Skip to main content

rustpython_host_env/
posix_unix_like.rs

1//! Common POSIX implementations across Unix-likes.
2
3use std::{io, path::Path};
4
5use rustix::{
6    fd::AsFd,
7    fs::{self, AtFlags},
8};
9
10pub use rustix::fs::RawMode;
11
12use crate::{crt_fd, fileutils::StatStruct};
13
14/// https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html
15pub fn make_dir(
16    dir_fd: Option<crt_fd::Borrowed<'_>>,
17    path: impl AsRef<Path>,
18    mode: fs::RawMode,
19) -> io::Result<()> {
20    let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
21    fs::mkdirat(dir_fd, path.as_ref(), mode.into()).map_err(Into::into)
22}
23
24/// https://pubs.opengroup.org/onlinepubs/9799919799/functions/rename.html
25pub fn rename(
26    from: impl AsRef<Path>,
27    from_fd: Option<crt_fd::Borrowed<'_>>,
28    to: impl AsRef<Path>,
29    to_fd: Option<crt_fd::Borrowed<'_>>,
30) -> io::Result<()> {
31    let from = from.as_ref();
32    let from_fd = from_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
33    let to = to.as_ref();
34    let to_fd = to_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
35    fs::renameat(from_fd, from, to_fd, to).map_err(Into::into)
36}
37
38/// https://docs.python.org/3/library/os.html#os.replace
39///
40/// Atomically replace `to` with `from`.
41/// POSIX's rename already atomically replaces targets, so this function just forwards to [`rename`].
42#[inline]
43pub fn replace(
44    from: impl AsRef<Path>,
45    from_fd: Option<crt_fd::Borrowed<'_>>,
46    to: impl AsRef<Path>,
47    to_fd: Option<crt_fd::Borrowed<'_>>,
48) -> io::Result<()> {
49    rename(from, from_fd, to, to_fd)
50}
51
52pub fn remove_dir_at(
53    dir_fd: Option<crt_fd::Borrowed<'_>>,
54    path: impl AsRef<Path>,
55) -> io::Result<()> {
56    let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
57    fs::unlinkat(dir_fd, path.as_ref(), AtFlags::REMOVEDIR).map_err(Into::into)
58}
59
60pub fn stat_path(
61    path: impl AsRef<Path>,
62    dir_fd: Option<crt_fd::Borrowed<'_>>,
63    follow_symlinks: bool,
64) -> io::Result<Option<StatStruct>> {
65    let flags = if follow_symlinks {
66        AtFlags::empty()
67    } else {
68        AtFlags::SYMLINK_NOFOLLOW
69    };
70    let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
71    fs::statat(dir_fd, path.as_ref(), flags)
72        .map(Option::Some)
73        .map_err(Into::into)
74}
75
76pub fn unlinkat(dir_fd: Option<crt_fd::Borrowed<'_>>, path: impl AsRef<Path>) -> io::Result<()> {
77    let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
78    fs::unlinkat(dir_fd, path.as_ref(), AtFlags::empty()).map_err(Into::into)
79}