Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

dirfd: preliminary unix and windows implementations #139514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Qelxiros wants to merge 1 commit into rust-lang:master
base: master
Choose a base branch
Loading
from Qelxiros:120426-dirfd
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
502 changes: 502 additions & 0 deletions library/std/src/fs.rs
View file Open in desktop

Large diffs are not rendered by default.

119 changes: 118 additions & 1 deletion library/std/src/fs/tests.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rand::RngCore;

use super::Dir;
#[cfg(any(
windows,
target_os = "freebsd",
Expand All @@ -17,7 +18,7 @@ use crate::char::MAX_LEN_UTF8;
target_vendor = "apple",
))]
use crate::fs::TryLockError;
use crate::fs::{self, File, FileTimes, OpenOptions};
use crate::fs::{self, File, FileTimes, OpenOptions, create_dir, exists};
use crate::io::prelude::*;
use crate::io::{BorrowedBuf, ErrorKind, SeekFrom};
use crate::mem::MaybeUninit;
Expand Down Expand Up @@ -2110,3 +2111,119 @@ fn test_open_options_invalid_combinations() {
assert_eq!(err.kind(), ErrorKind::InvalidInput);
assert_eq!(err.to_string(), "must specify at least one of read, write, or append access");
}

#[test]
fn test_dir_smoke_test() {
let tmpdir = tmpdir();
let dir = Dir::new(tmpdir.path());
println!("{dir:?}");
check!(dir);
}

#[test]
fn test_dir_read_file() {
let tmpdir = tmpdir();
let mut f = check!(File::create(tmpdir.join("foo.txt")));
check!(f.write(b"bar"));
check!(f.flush());
drop(f);
let dir = check!(Dir::new(tmpdir.path()));
let mut f = check!(dir.open("foo.txt"));
let mut buf = [0u8; 3];
check!(f.read_exact(&mut buf));
assert_eq!(b"bar", &buf);
}

#[test]
fn test_dir_write_file() {
let tmpdir = tmpdir();
let dir = check!(Dir::new(tmpdir.path()));
let mut f = check!(dir.open_with("foo.txt", &OpenOptions::new().write(true).create(true)));
check!(f.write(b"bar"));
check!(f.flush());
drop(f);
let mut f = check!(File::open(tmpdir.join("foo.txt")));
let mut buf = [0u8; 3];
check!(f.read_exact(&mut buf));
assert_eq!(b"bar", &buf);
}

#[test]
fn test_dir_remove_file() {
let tmpdir = tmpdir();
let mut f = check!(File::create(tmpdir.join("foo.txt")));
check!(f.write(b"bar"));
check!(f.flush());
drop(f);
let dir = check!(Dir::new(tmpdir.path()));
check!(dir.remove_file("foo.txt"));
assert!(!matches!(exists(tmpdir.join("foo.txt")), Ok(true)));
}

#[test]
fn test_dir_remove_dir() {
let tmpdir = tmpdir();
check!(create_dir(tmpdir.join("foo")));
let dir = check!(Dir::new(tmpdir.path()));
check!(dir.remove_dir("foo"));
assert!(!matches!(exists(tmpdir.join("foo")), Ok(true)));
}

#[test]
fn test_dir_rename_file() {
let tmpdir = tmpdir();
let mut f = check!(File::create(tmpdir.join("foo.txt")));
check!(f.write(b"bar"));
check!(f.flush());
drop(f);
let dir = check!(Dir::new(tmpdir.path()));
check!(dir.rename("foo.txt", &dir, "baz.txt"));
let mut f = check!(File::open(tmpdir.join("baz.txt")));
let mut buf = [0u8; 3];
check!(f.read_exact(&mut buf));
assert_eq!(b"bar", &buf);
}

#[test]
fn test_dir_create_dir() {
let tmpdir = tmpdir();
let dir = check!(Dir::new(tmpdir.path()));
check!(dir.create_dir("foo"));
check!(Dir::new(tmpdir.join("foo")));
}

#[test]
fn test_dir_open_dir() {
let tmpdir = tmpdir();
let dir1 = check!(Dir::new(tmpdir.path()));
check!(dir1.create_dir("foo"));
let dir2 = check!(Dir::new(tmpdir.path().join("foo")));
let mut f = check!(dir2.open_with("bar.txt", &OpenOptions::new().create(true).write(true)));
check!(f.write(b"baz"));
check!(f.flush());
drop(f);
let dir3 = check!(dir1.open_dir("foo"));
let mut f = check!(dir3.open("bar.txt"));
let mut buf = [0u8; 3];
check!(f.read_exact(&mut buf));
assert_eq!(b"baz", &buf);
}

#[test]
fn test_dir_symlink() {
let tmpdir = tmpdir();
if !got_symlink_permission(&tmpdir) {
return;
};

let dir = check!(Dir::new(tmpdir.path()));
let mut f = check!(dir.open_with("foo.txt", &OpenOptions::new().write(true).create(true)));
check!(f.write(b"quux"));
check!(f.flush());
drop(f);
check!(dir.symlink("foo.txt", "bar.txt"));
let mut f = check!(dir.open("bar.txt"));
let mut buf = [0u8; 4];
check!(f.read_exact(&mut buf));
assert_eq!(b"quux", &buf);
}
73 changes: 71 additions & 2 deletions library/std/src/sys/fs/common.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#![allow(dead_code)] // not used on all platforms

use crate::fs;
use crate::fmt;
use crate::fs::{self, create_dir, remove_dir, remove_file, rename};
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;
use crate::path::{Path, PathBuf};
use crate::sys::fs::{File, OpenOptions, symlink};
use crate::sys_common::ignore_notfound;

pub(crate) const NOT_FILE_ERROR: Error = io::const_error!(
Expand Down Expand Up @@ -58,3 +60,70 @@ pub fn exists(path: &Path) -> io::Result<bool> {
Err(error) => Err(error),
}
}

pub struct Dir {
path: PathBuf,
}

impl Dir {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Ok(Self { path: path.as_ref().to_path_buf() })
}

pub fn new_with<P: AsRef<Path>>(path: P, _opts: &OpenOptions) -> io::Result<Self> {
Ok(Self { path: path.as_ref().to_path_buf() })
}

pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Ok(Self { path: path.as_ref().to_path_buf() })
}

pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
let mut opts = OpenOptions::new();
opts.read(true);
File::open(&self.path.join(path), &opts)
}

pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
File::open(&self.path.join(path), opts)
}

pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
create_dir(self.path.join(path))
}

pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
Self::new(self.path.join(path))
}

pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
Self::new_with(self.path.join(path), opts)
}

pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
remove_file(self.path.join(path))
}

pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
remove_dir(self.path.join(path))
}

pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(
&self,
from: P,
to_dir: &Self,
to: Q,
) -> io::Result<()> {
rename(self.path.join(from), to_dir.path.join(to))
}

pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q) -> io::Result<()> {
symlink(original.as_ref(), link.as_ref())
}
}

impl fmt::Debug for Dir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Dir").field("path", &self.path).finish()
}
}
30 changes: 29 additions & 1 deletion library/std/src/sys/fs/hermit.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ use crate::path::{Path, PathBuf};
use crate::sync::Arc;
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::fd::FileDesc;
pub use crate::sys::fs::common::{copy, exists};
pub use crate::sys::fs::common::{Dir, copy, exists};
use crate::sys::fs::{remove_dir, remove_file};
use crate::sys::time::SystemTime;
use crate::sys::{cvt, unsupported, unsupported_err};
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::{fmt, mem};

#[derive(Debug)]
pub struct File(FileDesc);

#[derive(Clone)]
pub struct FileAttr {
stat_val: stat_struct,
Expand Down Expand Up @@ -251,6 +253,32 @@ impl DirEntry {
pub fn file_name_os_str(&self) -> &OsStr {
self.name.as_os_str()
}

pub fn open_file(&self) -> io::Result<File> {
let mut opts = OpenOptions::new();
opts.read(true);
File::open(&self.path(), &opts)
}

pub fn open_file_with(&self, opts: &OpenOptions) -> io::Result<File> {
File::open(&self.path(), opts)
}

pub fn open_dir(&self) -> io::Result<Dir> {
Dir::new(self.path())
}

pub fn open_dir_with(&self, opts: &OpenOptions) -> io::Result<Dir> {
Dir::new_with(self.path(), opts)
}

pub fn remove_file(&self) -> io::Result<()> {
remove_file(&self.path())
}

pub fn remove_dir(&self) -> io::Result<()> {
remove_dir(&self.path())
}
}

impl OpenOptions {
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/fs/mod.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
}

pub use imp::{
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
ReadDir,
};

Expand Down
29 changes: 28 additions & 1 deletion library/std/src/sys/fs/solid.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::os::raw::{c_int, c_short};
use crate::os::solid::ffi::OsStrExt;
use crate::path::{Path, PathBuf};
use crate::sync::Arc;
pub use crate::sys::fs::common::exists;
pub use crate::sys::fs::common::{Dir, exists};
use crate::sys::fs::{remove_dir, remove_file};
use crate::sys::pal::{abi, error};
use crate::sys::time::SystemTime;
use crate::sys::{unsupported, unsupported_err};
Expand Down Expand Up @@ -219,6 +220,32 @@ impl DirEntry {
_ => lstat(&self.path()).map(|m| m.file_type()),
}
}

pub fn open_file(&self) -> io::Result<File> {
let mut opts = OpenOptions::new();
opts.read(true);
File::open(&self.path(), &opts)
}

pub fn open_file_with(&self, opts: &OpenOptions) -> io::Result<File> {
File::open(&self.path(), opts)
}

pub fn open_dir(&self) -> io::Result<Dir> {
Dir::new(self.path())
}

pub fn open_dir_with(&self, opts: &OpenOptions) -> io::Result<Dir> {
Dir::new_with(self.path(), opts)
}

pub fn remove_file(&self) -> io::Result<()> {
remove_file(&self.path())
}

pub fn remove_dir(&self) -> io::Result<()> {
remove_dir(&self.path())
}
}

impl OpenOptions {
Expand Down
Loading
Loading

AltStyle によって変換されたページ (->オリジナル) /