1 pub use libc::{dev_t, mode_t};
2 pub use libc::stat as FileStat;
3 
4 use {Result, NixPath};
5 use errno::Errno;
6 use fcntl::{AtFlags, at_rawfd};
7 use libc;
8 use std::mem;
9 use std::os::unix::io::RawFd;
10 use sys::time::{TimeSpec, TimeVal};
11 
12 libc_bitflags!(
13     pub struct SFlag: mode_t {
14         S_IFIFO;
15         S_IFCHR;
16         S_IFDIR;
17         S_IFBLK;
18         S_IFREG;
19         S_IFLNK;
20         S_IFSOCK;
21         S_IFMT;
22     }
23 );
24 
25 libc_bitflags! {
26     pub struct Mode: mode_t {
27         S_IRWXU;
28         S_IRUSR;
29         S_IWUSR;
30         S_IXUSR;
31         S_IRWXG;
32         S_IRGRP;
33         S_IWGRP;
34         S_IXGRP;
35         S_IRWXO;
36         S_IROTH;
37         S_IWOTH;
38         S_IXOTH;
39         S_ISUID as mode_t;
40         S_ISGID as mode_t;
41         S_ISVTX as mode_t;
42     }
43 }
44 
mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()>45 pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
46     let res = path.with_nix_path(|cstr| {
47         unsafe {
48             libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
49         }
50     })?;
51 
52     Errno::result(res).map(drop)
53 }
54 
55 #[cfg(target_os = "linux")]
major(dev: dev_t) -> u6456 pub fn major(dev: dev_t) -> u64 {
57     ((dev >> 32) & 0xffff_f000) |
58     ((dev >>  8) & 0x0000_0fff)
59 }
60 
61 #[cfg(target_os = "linux")]
minor(dev: dev_t) -> u6462 pub fn minor(dev: dev_t) -> u64 {
63     ((dev >> 12) & 0xffff_ff00) |
64     ((dev      ) & 0x0000_00ff)
65 }
66 
67 #[cfg(target_os = "linux")]
makedev(major: u64, minor: u64) -> dev_t68 pub fn makedev(major: u64, minor: u64) -> dev_t {
69     ((major & 0xffff_f000) << 32) |
70     ((major & 0x0000_0fff) <<  8) |
71     ((minor & 0xffff_ff00) << 12) |
72      (minor & 0x0000_00ff)
73 }
74 
umask(mode: Mode) -> Mode75 pub fn umask(mode: Mode) -> Mode {
76     let prev = unsafe { libc::umask(mode.bits() as mode_t) };
77     Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
78 }
79 
stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat>80 pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
81     let mut dst = mem::MaybeUninit::uninit();
82     let res = path.with_nix_path(|cstr| {
83         unsafe {
84             libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
85         }
86     })?;
87 
88     Errno::result(res)?;
89 
90     Ok(unsafe{dst.assume_init()})
91 }
92 
lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat>93 pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
94     let mut dst = mem::MaybeUninit::uninit();
95     let res = path.with_nix_path(|cstr| {
96         unsafe {
97             libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
98         }
99     })?;
100 
101     Errno::result(res)?;
102 
103     Ok(unsafe{dst.assume_init()})
104 }
105 
fstat(fd: RawFd) -> Result<FileStat>106 pub fn fstat(fd: RawFd) -> Result<FileStat> {
107     let mut dst = mem::MaybeUninit::uninit();
108     let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
109 
110     Errno::result(res)?;
111 
112     Ok(unsafe{dst.assume_init()})
113 }
114 
fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat>115 pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
116     let mut dst = mem::MaybeUninit::uninit();
117     let res = pathname.with_nix_path(|cstr| {
118         unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
119     })?;
120 
121     Errno::result(res)?;
122 
123     Ok(unsafe{dst.assume_init()})
124 }
125 
126 /// Change the file permission bits of the file specified by a file descriptor.
127 ///
128 /// # References
129 ///
130 /// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html).
fchmod(fd: RawFd, mode: Mode) -> Result<()>131 pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
132     let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
133 
134     Errno::result(res).map(drop)
135 }
136 
137 /// Flags for `fchmodat` function.
138 #[derive(Clone, Copy, Debug)]
139 pub enum FchmodatFlags {
140     FollowSymlink,
141     NoFollowSymlink,
142 }
143 
144 /// Change the file permission bits.
145 ///
146 /// The file to be changed is determined relative to the directory associated
147 /// with the file descriptor `dirfd` or the current working directory
148 /// if `dirfd` is `None`.
149 ///
150 /// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
151 /// then the mode of the symbolic link is changed.
152 ///
153 /// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
154 /// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
155 /// in the `nix` crate.
156 ///
157 /// # References
158 ///
159 /// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
fchmodat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, mode: Mode, flag: FchmodatFlags, ) -> Result<()>160 pub fn fchmodat<P: ?Sized + NixPath>(
161     dirfd: Option<RawFd>,
162     path: &P,
163     mode: Mode,
164     flag: FchmodatFlags,
165 ) -> Result<()> {
166     let atflag =
167         match flag {
168             FchmodatFlags::FollowSymlink => AtFlags::empty(),
169             FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
170         };
171     let res = path.with_nix_path(|cstr| unsafe {
172         libc::fchmodat(
173             at_rawfd(dirfd),
174             cstr.as_ptr(),
175             mode.bits() as mode_t,
176             atflag.bits() as libc::c_int,
177         )
178     })?;
179 
180     Errno::result(res).map(drop)
181 }
182 
183 /// Change the access and modification times of a file.
184 ///
185 /// `utimes(path, times)` is identical to
186 /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
187 /// is a deprecated API so prefer using the latter if the platforms you care
188 /// about support it.
189 ///
190 /// # References
191 ///
192 /// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html).
utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()>193 pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
194     let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
195     let res = path.with_nix_path(|cstr| unsafe {
196         libc::utimes(cstr.as_ptr(), &times[0])
197     })?;
198 
199     Errno::result(res).map(drop)
200 }
201 
202 /// Change the access and modification times of a file without following symlinks.
203 ///
204 /// `lutimes(path, times)` is identical to
205 /// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
206 /// is a deprecated API so prefer using the latter if the platforms you care
207 /// about support it.
208 ///
209 /// # References
210 ///
211 /// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
212 #[cfg(any(target_os = "linux",
213           target_os = "haiku",
214           target_os = "ios",
215           target_os = "macos",
216           target_os = "freebsd",
217           target_os = "netbsd"))]
lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()>218 pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
219     let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
220     let res = path.with_nix_path(|cstr| unsafe {
221         libc::lutimes(cstr.as_ptr(), &times[0])
222     })?;
223 
224     Errno::result(res).map(drop)
225 }
226 
227 /// Change the access and modification times of the file specified by a file descriptor.
228 ///
229 /// # References
230 ///
231 /// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
232 #[inline]
futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()>233 pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
234     let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
235     let res = unsafe { libc::futimens(fd, &times[0]) };
236 
237     Errno::result(res).map(drop)
238 }
239 
240 /// Flags for `utimensat` function.
241 #[derive(Clone, Copy, Debug)]
242 pub enum UtimensatFlags {
243     FollowSymlink,
244     NoFollowSymlink,
245 }
246 
247 /// Change the access and modification times of a file.
248 ///
249 /// The file to be changed is determined relative to the directory associated
250 /// with the file descriptor `dirfd` or the current working directory
251 /// if `dirfd` is `None`.
252 ///
253 /// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
254 /// then the mode of the symbolic link is changed.
255 ///
256 /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
257 /// `utimes(path, times)`. The latter is a deprecated API so prefer using the
258 /// former if the platforms you care about support it.
259 ///
260 /// # References
261 ///
262 /// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
utimensat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, atime: &TimeSpec, mtime: &TimeSpec, flag: UtimensatFlags ) -> Result<()>263 pub fn utimensat<P: ?Sized + NixPath>(
264     dirfd: Option<RawFd>,
265     path: &P,
266     atime: &TimeSpec,
267     mtime: &TimeSpec,
268     flag: UtimensatFlags
269 ) -> Result<()> {
270     let atflag =
271         match flag {
272             UtimensatFlags::FollowSymlink => AtFlags::empty(),
273             UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
274         };
275     let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
276     let res = path.with_nix_path(|cstr| unsafe {
277         libc::utimensat(
278             at_rawfd(dirfd),
279             cstr.as_ptr(),
280             &times[0],
281             atflag.bits() as libc::c_int,
282         )
283     })?;
284 
285     Errno::result(res).map(drop)
286 }
287 
mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()>288 pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
289     let res = path.with_nix_path(|cstr| {
290         unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
291     })?;
292 
293     Errno::result(res).map(drop)
294 }
295