rustix/fs/
abs.rs

1//! POSIX-style filesystem functions which operate on bare paths.
2
3use crate::fd::OwnedFd;
4#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
5use crate::fs::Access;
6#[cfg(not(any(
7    solarish,
8    target_os = "espidf",
9    target_os = "haiku",
10    target_os = "netbsd",
11    target_os = "nto",
12    target_os = "redox",
13    target_os = "vita",
14    target_os = "wasi",
15)))]
16use crate::fs::StatFs;
17#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
18use crate::fs::StatVfs;
19use crate::fs::{Mode, OFlags, Stat};
20#[cfg(not(target_os = "wasi"))]
21use crate::ugid::{Gid, Uid};
22use crate::{backend, io, path};
23#[cfg(feature = "alloc")]
24use {
25    crate::ffi::{CStr, CString},
26    crate::path::SMALL_PATH_BUFFER_SIZE,
27    alloc::vec::Vec,
28};
29
30/// `open(path, oflags, mode)`—Opens a file.
31///
32/// POSIX guarantees that `open` will use the lowest unused file descriptor,
33/// however it is not safe in general to rely on this, as file descriptors may
34/// be unexpectedly allocated on other threads or in libraries.
35///
36/// The `Mode` argument is only significant when creating a file.
37///
38/// # References
39///  - [POSIX]
40///  - [Linux]
41///
42/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/open.html
43/// [Linux]: https://man7.org/linux/man-pages/man2/open.2.html
44#[inline]
45pub fn open<P: path::Arg>(path: P, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
46    path.into_with_c_str(|path| backend::fs::syscalls::open(path, flags, mode))
47}
48
49/// `chmod(path, mode)`—Sets file or directory permissions.
50///
51/// # References
52///  - [POSIX]
53///  - [Linux]
54///
55/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/chmod.html
56/// [Linux]: https://man7.org/linux/man-pages/man2/chmod.2.html
57#[cfg(not(target_os = "wasi"))]
58#[inline]
59pub fn chmod<P: path::Arg>(path: P, mode: Mode) -> io::Result<()> {
60    path.into_with_c_str(|path| backend::fs::syscalls::chmod(path, mode))
61}
62
63/// `stat(path)`—Queries metadata for a file or directory.
64///
65/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
66/// interpret the `st_mode` field.
67///
68/// # References
69///  - [POSIX]
70///  - [Linux]
71///
72/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stat.html
73/// [Linux]: https://man7.org/linux/man-pages/man2/stat.2.html
74/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode
75/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
76#[inline]
77pub fn stat<P: path::Arg>(path: P) -> io::Result<Stat> {
78    path.into_with_c_str(backend::fs::syscalls::stat)
79}
80
81/// `lstat(path)`—Queries metadata for a file or directory, without following
82/// symlinks.
83///
84/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
85/// interpret the `st_mode` field.
86///
87/// # References
88///  - [POSIX]
89///  - [Linux]
90///
91/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/lstat.html
92/// [Linux]: https://man7.org/linux/man-pages/man2/lstat.2.html
93/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode
94/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
95#[inline]
96pub fn lstat<P: path::Arg>(path: P) -> io::Result<Stat> {
97    path.into_with_c_str(backend::fs::syscalls::lstat)
98}
99
100/// `readlink(path)`—Reads the contents of a symlink.
101///
102/// If `reuse` is non-empty, reuse its buffer to store the result if possible.
103///
104/// # References
105///  - [POSIX]
106///  - [Linux]
107///
108/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlink.html
109/// [Linux]: https://man7.org/linux/man-pages/man2/readlink.2.html
110#[cfg(feature = "alloc")]
111#[inline]
112pub fn readlink<P: path::Arg, B: Into<Vec<u8>>>(path: P, reuse: B) -> io::Result<CString> {
113    path.into_with_c_str(|path| _readlink(path, reuse.into()))
114}
115
116#[cfg(feature = "alloc")]
117fn _readlink(path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> {
118    // This code would benefit from having a better way to read into
119    // uninitialized memory, but that requires `unsafe`.
120    buffer.clear();
121    buffer.reserve(SMALL_PATH_BUFFER_SIZE);
122    buffer.resize(buffer.capacity(), 0_u8);
123
124    loop {
125        let nread = backend::fs::syscalls::readlink(path, &mut buffer)?;
126
127        let nread = nread as usize;
128        assert!(nread <= buffer.len());
129        if nread < buffer.len() {
130            buffer.resize(nread, 0_u8);
131            return Ok(CString::new(buffer).unwrap());
132        }
133        // Use `Vec` reallocation strategy to grow capacity exponentially.
134        buffer.reserve(1);
135        buffer.resize(buffer.capacity(), 0_u8);
136    }
137}
138
139/// `rename(old_path, new_path)`—Renames a file or directory.
140///
141/// # References
142///  - [POSIX]
143///  - [Linux]
144///
145/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/rename.html
146/// [Linux]: https://man7.org/linux/man-pages/man2/rename.2.html
147#[inline]
148pub fn rename<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
149    old_path.into_with_c_str(|old_path| {
150        new_path.into_with_c_str(|new_path| backend::fs::syscalls::rename(old_path, new_path))
151    })
152}
153
154/// `unlink(path)`—Unlinks a file.
155///
156/// # References
157///  - [POSIX]
158///  - [Linux]
159///
160/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlink.html
161/// [Linux]: https://man7.org/linux/man-pages/man2/unlink.2.html
162#[inline]
163pub fn unlink<P: path::Arg>(path: P) -> io::Result<()> {
164    path.into_with_c_str(backend::fs::syscalls::unlink)
165}
166
167/// `rmdir(path)`—Removes a directory.
168///
169/// # References
170///  - [POSIX]
171///  - [Linux]
172///
173/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/rmdir.html
174/// [Linux]: https://man7.org/linux/man-pages/man2/rmdir.2.html
175#[inline]
176pub fn rmdir<P: path::Arg>(path: P) -> io::Result<()> {
177    path.into_with_c_str(backend::fs::syscalls::rmdir)
178}
179
180/// `link(old_path, new_path)`—Creates a hard link.
181///
182/// POSIX leaves it implementation-defined whether `link` follows a symlink in
183/// `old_path`, or creates a new link to the symbolic link itself. On platforms
184/// which have it, [`linkat`] avoids this problem since it has an [`AtFlags`]
185/// parameter and the [`AtFlags::SYMLINK_FOLLOW`] flag determines whether
186/// symlinks should be followed.
187///
188/// # References
189///  - [POSIX]
190///  - [Linux]
191///
192/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/link.html
193/// [Linux]: https://man7.org/linux/man-pages/man2/link.2.html
194/// [`linkat`]: crate::fs::linkat
195/// [`AtFlags`]: crate::fs::AtFlags
196/// [`AtFlags::SYMLINK_FOLLOW`]: crate::fs::AtFlags::SYMLINK_FOLLOW
197#[inline]
198pub fn link<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
199    old_path.into_with_c_str(|old_path| {
200        new_path.into_with_c_str(|new_path| backend::fs::syscalls::link(old_path, new_path))
201    })
202}
203
204/// `symlink(old_path, new_path)`—Creates a symlink.
205///
206/// # References
207///  - [POSIX]
208///  - [Linux]
209///
210/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlink.html
211/// [Linux]: https://man7.org/linux/man-pages/man2/symlink.2.html
212#[inline]
213pub fn symlink<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
214    old_path.into_with_c_str(|old_path| {
215        new_path.into_with_c_str(|new_path| backend::fs::syscalls::symlink(old_path, new_path))
216    })
217}
218
219/// `mkdir(path, mode)`—Creates a directory.
220///
221/// # References
222///  - [POSIX]
223///  - [Linux]
224///
225/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html
226/// [Linux]: https://man7.org/linux/man-pages/man2/mkdir.2.html
227#[inline]
228pub fn mkdir<P: path::Arg>(path: P, mode: Mode) -> io::Result<()> {
229    path.into_with_c_str(|path| backend::fs::syscalls::mkdir(path, mode))
230}
231
232/// `access(path, access)`—Tests permissions for a file or directory.
233///
234/// # References
235///  - [POSIX]
236///  - [Linux]
237///
238/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/access.html
239/// [Linux]: https://man7.org/linux/man-pages/man2/access.2.html
240#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
241#[inline]
242pub fn access<P: path::Arg>(path: P, access: Access) -> io::Result<()> {
243    path.into_with_c_str(|path| backend::fs::syscalls::access(path, access))
244}
245
246/// `statfs`—Queries filesystem metadata.
247///
248/// Compared to [`statvfs`], this function often provides more information,
249/// though it's less portable.
250///
251/// # References
252///  - [Linux]
253///
254/// [Linux]: https://man7.org/linux/man-pages/man2/statfs.2.html
255#[cfg(not(any(
256    solarish,
257    target_os = "espidf",
258    target_os = "haiku",
259    target_os = "netbsd",
260    target_os = "nto",
261    target_os = "redox",
262    target_os = "vita",
263    target_os = "wasi",
264)))]
265#[inline]
266pub fn statfs<P: path::Arg>(path: P) -> io::Result<StatFs> {
267    path.into_with_c_str(backend::fs::syscalls::statfs)
268}
269
270/// `statvfs`—Queries filesystem metadata, POSIX version.
271///
272/// Compared to [`statfs`], this function often provides less information, but
273/// it is more portable. But even so, filesystems are very diverse and not all
274/// the fields are meaningful for every filesystem. And `f_fsid` doesn't seem
275/// to have a clear meaning anywhere.
276///
277/// # References
278///  - [POSIX]
279///  - [Linux]
280///
281/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/statvfs.html
282/// [Linux]: https://man7.org/linux/man-pages/man2/statvfs.2.html
283#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
284#[inline]
285pub fn statvfs<P: path::Arg>(path: P) -> io::Result<StatVfs> {
286    path.into_with_c_str(backend::fs::syscalls::statvfs)
287}
288
289/// `chown(path, owner, group)`—Sets open file or directory ownership.
290///
291/// # References
292///  - [POSIX]
293///  - [Linux]
294///
295/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/chown.html
296/// [Linux]: https://man7.org/linux/man-pages/man2/chown.2.html
297#[cfg(not(target_os = "wasi"))]
298#[inline]
299pub fn chown<P: path::Arg>(path: P, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
300    path.into_with_c_str(|path| backend::fs::syscalls::chown(path, owner, group))
301}