/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.27.1/src/sys/stat.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] |
2 | | pub use libc::c_uint; |
3 | | #[cfg(any( |
4 | | target_os = "netbsd", |
5 | | target_os = "freebsd", |
6 | | target_os = "dragonfly" |
7 | | ))] |
8 | | pub use libc::c_ulong; |
9 | | pub use libc::stat as FileStat; |
10 | | pub use libc::{dev_t, mode_t}; |
11 | | |
12 | | #[cfg(not(target_os = "redox"))] |
13 | | use crate::fcntl::{at_rawfd, AtFlags}; |
14 | | use crate::sys::time::{TimeSpec, TimeVal}; |
15 | | use crate::{errno::Errno, NixPath, Result}; |
16 | | use std::mem; |
17 | | use std::os::unix::io::RawFd; |
18 | | |
19 | | libc_bitflags!( |
20 | | /// "File type" flags for `mknod` and related functions. |
21 | | pub struct SFlag: mode_t { |
22 | | S_IFIFO; |
23 | | S_IFCHR; |
24 | | S_IFDIR; |
25 | | S_IFBLK; |
26 | | S_IFREG; |
27 | | S_IFLNK; |
28 | | S_IFSOCK; |
29 | | S_IFMT; |
30 | | } |
31 | | ); |
32 | | |
33 | | libc_bitflags! { |
34 | | /// "File mode / permissions" flags. |
35 | | pub struct Mode: mode_t { |
36 | | /// Read, write and execute for owner. |
37 | | S_IRWXU; |
38 | | /// Read for owner. |
39 | | S_IRUSR; |
40 | | /// Write for owner. |
41 | | S_IWUSR; |
42 | | /// Execute for owner. |
43 | | S_IXUSR; |
44 | | /// Read write and execute for group. |
45 | | S_IRWXG; |
46 | | /// Read fr group. |
47 | | S_IRGRP; |
48 | | /// Write for group. |
49 | | S_IWGRP; |
50 | | /// Execute for group. |
51 | | S_IXGRP; |
52 | | /// Read, write and execute for other. |
53 | | S_IRWXO; |
54 | | /// Read for other. |
55 | | S_IROTH; |
56 | | /// Write for other. |
57 | | S_IWOTH; |
58 | | /// Execute for other. |
59 | | S_IXOTH; |
60 | | /// Set user id on execution. |
61 | | S_ISUID as mode_t; |
62 | | /// Set group id on execution. |
63 | | S_ISGID as mode_t; |
64 | | S_ISVTX as mode_t; |
65 | | } |
66 | | } |
67 | | |
68 | | #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] |
69 | | pub type type_of_file_flag = c_uint; |
70 | | #[cfg(any( |
71 | | target_os = "netbsd", |
72 | | target_os = "freebsd", |
73 | | target_os = "dragonfly" |
74 | | ))] |
75 | | pub type type_of_file_flag = c_ulong; |
76 | | |
77 | | #[cfg(any( |
78 | | target_os = "openbsd", |
79 | | target_os = "netbsd", |
80 | | target_os = "freebsd", |
81 | | target_os = "dragonfly", |
82 | | target_os = "macos", |
83 | | target_os = "ios" |
84 | | ))] |
85 | | libc_bitflags! { |
86 | | /// File flags. |
87 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
88 | | pub struct FileFlag: type_of_file_flag { |
89 | | /// The file may only be appended to. |
90 | | SF_APPEND; |
91 | | /// The file has been archived. |
92 | | SF_ARCHIVED; |
93 | | #[cfg(any(target_os = "dragonfly"))] |
94 | | SF_CACHE; |
95 | | /// The file may not be changed. |
96 | | SF_IMMUTABLE; |
97 | | /// Indicates a WAPBL journal file. |
98 | | #[cfg(any(target_os = "netbsd"))] |
99 | | SF_LOG; |
100 | | /// Do not retain history for file |
101 | | #[cfg(any(target_os = "dragonfly"))] |
102 | | SF_NOHISTORY; |
103 | | /// The file may not be renamed or deleted. |
104 | | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
105 | | SF_NOUNLINK; |
106 | | /// Mask of superuser changeable flags |
107 | | SF_SETTABLE; |
108 | | /// Snapshot is invalid. |
109 | | #[cfg(any(target_os = "netbsd"))] |
110 | | SF_SNAPINVAL; |
111 | | /// The file is a snapshot file. |
112 | | #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] |
113 | | SF_SNAPSHOT; |
114 | | #[cfg(any(target_os = "dragonfly"))] |
115 | | SF_XLINK; |
116 | | /// The file may only be appended to. |
117 | | UF_APPEND; |
118 | | /// The file needs to be archived. |
119 | | #[cfg(any(target_os = "freebsd"))] |
120 | | UF_ARCHIVE; |
121 | | #[cfg(any(target_os = "dragonfly"))] |
122 | | UF_CACHE; |
123 | | /// File is compressed at the file system level. |
124 | | #[cfg(any(target_os = "macos", target_os = "ios"))] |
125 | | UF_COMPRESSED; |
126 | | /// The file may be hidden from directory listings at the application's |
127 | | /// discretion. |
128 | | #[cfg(any( |
129 | | target_os = "freebsd", |
130 | | target_os = "macos", |
131 | | target_os = "ios", |
132 | | ))] |
133 | | UF_HIDDEN; |
134 | | /// The file may not be changed. |
135 | | UF_IMMUTABLE; |
136 | | /// Do not dump the file. |
137 | | UF_NODUMP; |
138 | | #[cfg(any(target_os = "dragonfly"))] |
139 | | UF_NOHISTORY; |
140 | | /// The file may not be renamed or deleted. |
141 | | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
142 | | UF_NOUNLINK; |
143 | | /// The file is offline, or has the Windows and CIFS |
144 | | /// `FILE_ATTRIBUTE_OFFLINE` attribute. |
145 | | #[cfg(any(target_os = "freebsd"))] |
146 | | UF_OFFLINE; |
147 | | /// The directory is opaque when viewed through a union stack. |
148 | | UF_OPAQUE; |
149 | | /// The file is read only, and may not be written or appended. |
150 | | #[cfg(any(target_os = "freebsd"))] |
151 | | UF_READONLY; |
152 | | /// The file contains a Windows reparse point. |
153 | | #[cfg(any(target_os = "freebsd"))] |
154 | | UF_REPARSE; |
155 | | /// Mask of owner changeable flags. |
156 | | UF_SETTABLE; |
157 | | /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. |
158 | | #[cfg(any(target_os = "freebsd"))] |
159 | | UF_SPARSE; |
160 | | /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` |
161 | | /// attribute. |
162 | | #[cfg(any(target_os = "freebsd"))] |
163 | | UF_SYSTEM; |
164 | | /// File renames and deletes are tracked. |
165 | | #[cfg(any(target_os = "macos", target_os = "ios"))] |
166 | | UF_TRACKED; |
167 | | #[cfg(any(target_os = "dragonfly"))] |
168 | | UF_XLINK; |
169 | | } |
170 | | } |
171 | | |
172 | | /// Create a special or ordinary file, by pathname. |
173 | 0 | pub fn mknod<P: ?Sized + NixPath>( |
174 | 0 | path: &P, |
175 | 0 | kind: SFlag, |
176 | 0 | perm: Mode, |
177 | 0 | dev: dev_t, |
178 | 0 | ) -> Result<()> { |
179 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
180 | 0 | libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev) |
181 | 0 | })?; |
182 | | |
183 | 0 | Errno::result(res).map(drop) |
184 | 0 | } |
185 | | |
186 | | /// Create a special or ordinary file, relative to a given directory. |
187 | | #[cfg(not(any( |
188 | | target_os = "ios", |
189 | | target_os = "macos", |
190 | | target_os = "redox", |
191 | | target_os = "haiku" |
192 | | )))] |
193 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
194 | 0 | pub fn mknodat<P: ?Sized + NixPath>( |
195 | 0 | dirfd: RawFd, |
196 | 0 | path: &P, |
197 | 0 | kind: SFlag, |
198 | 0 | perm: Mode, |
199 | 0 | dev: dev_t, |
200 | 0 | ) -> Result<()> { |
201 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
202 | 0 | libc::mknodat( |
203 | 0 | dirfd, |
204 | 0 | cstr.as_ptr(), |
205 | 0 | kind.bits() | perm.bits() as mode_t, |
206 | 0 | dev, |
207 | 0 | ) |
208 | 0 | })?; |
209 | | |
210 | 0 | Errno::result(res).map(drop) |
211 | 0 | } |
212 | | |
213 | | #[cfg(target_os = "linux")] |
214 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
215 | 0 | pub const fn major(dev: dev_t) -> u64 { |
216 | 0 | ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) |
217 | 0 | } |
218 | | |
219 | | #[cfg(target_os = "linux")] |
220 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
221 | 0 | pub const fn minor(dev: dev_t) -> u64 { |
222 | 0 | ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) |
223 | 0 | } |
224 | | |
225 | | #[cfg(target_os = "linux")] |
226 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
227 | 0 | pub const fn makedev(major: u64, minor: u64) -> dev_t { |
228 | 0 | ((major & 0xffff_f000) << 32) |
229 | 0 | | ((major & 0x0000_0fff) << 8) |
230 | 0 | | ((minor & 0xffff_ff00) << 12) |
231 | 0 | | (minor & 0x0000_00ff) |
232 | 0 | } |
233 | | |
234 | 0 | pub fn umask(mode: Mode) -> Mode { |
235 | 0 | let prev = unsafe { libc::umask(mode.bits() as mode_t) }; |
236 | 0 | Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") |
237 | 0 | } |
238 | | |
239 | 0 | pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { |
240 | 0 | let mut dst = mem::MaybeUninit::uninit(); |
241 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
242 | 0 | libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) |
243 | 0 | })?; |
244 | | |
245 | 0 | Errno::result(res)?; |
246 | | |
247 | 0 | Ok(unsafe { dst.assume_init() }) |
248 | 0 | } |
249 | | |
250 | 0 | pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { |
251 | 0 | let mut dst = mem::MaybeUninit::uninit(); |
252 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
253 | 0 | libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) |
254 | 0 | })?; |
255 | | |
256 | 0 | Errno::result(res)?; |
257 | | |
258 | 0 | Ok(unsafe { dst.assume_init() }) |
259 | 0 | } |
260 | | |
261 | 0 | pub fn fstat(fd: RawFd) -> Result<FileStat> { |
262 | 0 | let mut dst = mem::MaybeUninit::uninit(); |
263 | 0 | let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; |
264 | 0 |
|
265 | 0 | Errno::result(res)?; |
266 | | |
267 | 0 | Ok(unsafe { dst.assume_init() }) |
268 | 0 | } |
269 | | |
270 | | #[cfg(not(target_os = "redox"))] |
271 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
272 | 0 | pub fn fstatat<P: ?Sized + NixPath>( |
273 | 0 | dirfd: RawFd, |
274 | 0 | pathname: &P, |
275 | 0 | f: AtFlags, |
276 | 0 | ) -> Result<FileStat> { |
277 | 0 | let mut dst = mem::MaybeUninit::uninit(); |
278 | 0 | let res = pathname.with_nix_path(|cstr| unsafe { |
279 | 0 | libc::fstatat( |
280 | 0 | dirfd, |
281 | 0 | cstr.as_ptr(), |
282 | 0 | dst.as_mut_ptr(), |
283 | 0 | f.bits() as libc::c_int, |
284 | 0 | ) |
285 | 0 | })?; |
286 | | |
287 | 0 | Errno::result(res)?; |
288 | | |
289 | 0 | Ok(unsafe { dst.assume_init() }) |
290 | 0 | } |
291 | | |
292 | | /// Change the file permission bits of the file specified by a file descriptor. |
293 | | /// |
294 | | /// # References |
295 | | /// |
296 | | /// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). |
297 | 0 | pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { |
298 | 0 | let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; |
299 | 0 |
|
300 | 0 | Errno::result(res).map(drop) |
301 | 0 | } |
302 | | |
303 | | /// Flags for `fchmodat` function. |
304 | | #[derive(Clone, Copy, Debug)] |
305 | | pub enum FchmodatFlags { |
306 | | FollowSymlink, |
307 | | NoFollowSymlink, |
308 | | } |
309 | | |
310 | | /// Change the file permission bits. |
311 | | /// |
312 | | /// The file to be changed is determined relative to the directory associated |
313 | | /// with the file descriptor `dirfd` or the current working directory |
314 | | /// if `dirfd` is `None`. |
315 | | /// |
316 | | /// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, |
317 | | /// then the mode of the symbolic link is changed. |
318 | | /// |
319 | | /// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to |
320 | | /// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented |
321 | | /// in the `nix` crate. |
322 | | /// |
323 | | /// # References |
324 | | /// |
325 | | /// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). |
326 | | #[cfg(not(target_os = "redox"))] |
327 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
328 | 0 | pub fn fchmodat<P: ?Sized + NixPath>( |
329 | 0 | dirfd: Option<RawFd>, |
330 | 0 | path: &P, |
331 | 0 | mode: Mode, |
332 | 0 | flag: FchmodatFlags, |
333 | 0 | ) -> Result<()> { |
334 | 0 | let atflag = match flag { |
335 | 0 | FchmodatFlags::FollowSymlink => AtFlags::empty(), |
336 | 0 | FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, |
337 | | }; |
338 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
339 | 0 | libc::fchmodat( |
340 | 0 | at_rawfd(dirfd), |
341 | 0 | cstr.as_ptr(), |
342 | 0 | mode.bits() as mode_t, |
343 | 0 | atflag.bits() as libc::c_int, |
344 | 0 | ) |
345 | 0 | })?; |
346 | | |
347 | 0 | Errno::result(res).map(drop) |
348 | 0 | } |
349 | | |
350 | | /// Change the access and modification times of a file. |
351 | | /// |
352 | | /// `utimes(path, times)` is identical to |
353 | | /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former |
354 | | /// is a deprecated API so prefer using the latter if the platforms you care |
355 | | /// about support it. |
356 | | /// |
357 | | /// # References |
358 | | /// |
359 | | /// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). |
360 | 0 | pub fn utimes<P: ?Sized + NixPath>( |
361 | 0 | path: &P, |
362 | 0 | atime: &TimeVal, |
363 | 0 | mtime: &TimeVal, |
364 | 0 | ) -> Result<()> { |
365 | 0 | let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; |
366 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
367 | 0 | libc::utimes(cstr.as_ptr(), ×[0]) |
368 | 0 | })?; |
369 | | |
370 | 0 | Errno::result(res).map(drop) |
371 | 0 | } |
372 | | |
373 | | /// Change the access and modification times of a file without following symlinks. |
374 | | /// |
375 | | /// `lutimes(path, times)` is identical to |
376 | | /// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former |
377 | | /// is a deprecated API so prefer using the latter if the platforms you care |
378 | | /// about support it. |
379 | | /// |
380 | | /// # References |
381 | | /// |
382 | | /// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). |
383 | | #[cfg(any( |
384 | | target_os = "linux", |
385 | | target_os = "haiku", |
386 | | target_os = "ios", |
387 | | target_os = "macos", |
388 | | target_os = "freebsd", |
389 | | target_os = "netbsd" |
390 | | ))] |
391 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
392 | 0 | pub fn lutimes<P: ?Sized + NixPath>( |
393 | 0 | path: &P, |
394 | 0 | atime: &TimeVal, |
395 | 0 | mtime: &TimeVal, |
396 | 0 | ) -> Result<()> { |
397 | 0 | let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; |
398 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
399 | 0 | libc::lutimes(cstr.as_ptr(), ×[0]) |
400 | 0 | })?; |
401 | | |
402 | 0 | Errno::result(res).map(drop) |
403 | 0 | } |
404 | | |
405 | | /// Change the access and modification times of the file specified by a file descriptor. |
406 | | /// |
407 | | /// # References |
408 | | /// |
409 | | /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). |
410 | | #[inline] |
411 | 0 | pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { |
412 | 0 | let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; |
413 | 0 | let res = unsafe { libc::futimens(fd, ×[0]) }; |
414 | 0 |
|
415 | 0 | Errno::result(res).map(drop) |
416 | 0 | } |
417 | | |
418 | | /// Flags for `utimensat` function. |
419 | | // TODO: replace with fcntl::AtFlags |
420 | | #[derive(Clone, Copy, Debug)] |
421 | | pub enum UtimensatFlags { |
422 | | FollowSymlink, |
423 | | NoFollowSymlink, |
424 | | } |
425 | | |
426 | | /// Change the access and modification times of a file. |
427 | | /// |
428 | | /// The file to be changed is determined relative to the directory associated |
429 | | /// with the file descriptor `dirfd` or the current working directory |
430 | | /// if `dirfd` is `None`. |
431 | | /// |
432 | | /// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, |
433 | | /// then the mode of the symbolic link is changed. |
434 | | /// |
435 | | /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to |
436 | | /// `utimes(path, times)`. The latter is a deprecated API so prefer using the |
437 | | /// former if the platforms you care about support it. |
438 | | /// |
439 | | /// # References |
440 | | /// |
441 | | /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). |
442 | | #[cfg(not(target_os = "redox"))] |
443 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
444 | 0 | pub fn utimensat<P: ?Sized + NixPath>( |
445 | 0 | dirfd: Option<RawFd>, |
446 | 0 | path: &P, |
447 | 0 | atime: &TimeSpec, |
448 | 0 | mtime: &TimeSpec, |
449 | 0 | flag: UtimensatFlags, |
450 | 0 | ) -> Result<()> { |
451 | 0 | let atflag = match flag { |
452 | 0 | UtimensatFlags::FollowSymlink => AtFlags::empty(), |
453 | 0 | UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, |
454 | | }; |
455 | 0 | let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; |
456 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
457 | 0 | libc::utimensat( |
458 | 0 | at_rawfd(dirfd), |
459 | 0 | cstr.as_ptr(), |
460 | 0 | ×[0], |
461 | 0 | atflag.bits() as libc::c_int, |
462 | 0 | ) |
463 | 0 | })?; |
464 | | |
465 | 0 | Errno::result(res).map(drop) |
466 | 0 | } |
467 | | |
468 | | #[cfg(not(target_os = "redox"))] |
469 | | #[cfg_attr(docsrs, doc(cfg(all())))] |
470 | 0 | pub fn mkdirat<P: ?Sized + NixPath>( |
471 | 0 | fd: RawFd, |
472 | 0 | path: &P, |
473 | 0 | mode: Mode, |
474 | 0 | ) -> Result<()> { |
475 | 0 | let res = path.with_nix_path(|cstr| unsafe { |
476 | 0 | libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) |
477 | 0 | })?; |
478 | | |
479 | 0 | Errno::result(res).map(drop) |
480 | 0 | } |