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