Skip to content

Commit 7fe67f8

Browse files
committed
add dirfd implementations
1 parent 07d246f commit 7fe67f8

File tree

13 files changed

+1924
-95
lines changed

13 files changed

+1924
-95
lines changed

library/std/src/fs.rs

Lines changed: 502 additions & 0 deletions
Large diffs are not rendered by default.

library/std/src/fs/tests.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rand::RngCore;
22

3+
use super::Dir;
34
#[cfg(any(
45
windows,
56
target_os = "freebsd",
@@ -17,7 +18,7 @@ use crate::char::MAX_LEN_UTF8;
1718
target_vendor = "apple",
1819
))]
1920
use crate::fs::TryLockError;
20-
use crate::fs::{self, File, FileTimes, OpenOptions};
21+
use crate::fs::{self, File, FileTimes, OpenOptions, create_dir, exists};
2122
use crate::io::prelude::*;
2223
use crate::io::{BorrowedBuf, ErrorKind, SeekFrom};
2324
use crate::mem::MaybeUninit;
@@ -2110,3 +2111,119 @@ fn test_open_options_invalid_combinations() {
21102111
assert_eq!(err.kind(), ErrorKind::InvalidInput);
21112112
assert_eq!(err.to_string(), "must specify at least one of read, write, or append access");
21122113
}
2114+
2115+
#[test]
2116+
fn test_dir_smoke_test() {
2117+
let tmpdir = tmpdir();
2118+
let dir = Dir::new(tmpdir.path());
2119+
println!("{dir:?}");
2120+
check!(dir);
2121+
}
2122+
2123+
#[test]
2124+
fn test_dir_read_file() {
2125+
let tmpdir = tmpdir();
2126+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2127+
check!(f.write(b"bar"));
2128+
check!(f.flush());
2129+
drop(f);
2130+
let dir = check!(Dir::new(tmpdir.path()));
2131+
let mut f = check!(dir.open("foo.txt"));
2132+
let mut buf = [0u8; 3];
2133+
check!(f.read_exact(&mut buf));
2134+
assert_eq!(b"bar", &buf);
2135+
}
2136+
2137+
#[test]
2138+
fn test_dir_write_file() {
2139+
let tmpdir = tmpdir();
2140+
let dir = check!(Dir::new(tmpdir.path()));
2141+
let mut f = check!(dir.open_with("foo.txt", &OpenOptions::new().write(true).create(true)));
2142+
check!(f.write(b"bar"));
2143+
check!(f.flush());
2144+
drop(f);
2145+
let mut f = check!(File::open(tmpdir.join("foo.txt")));
2146+
let mut buf = [0u8; 3];
2147+
check!(f.read_exact(&mut buf));
2148+
assert_eq!(b"bar", &buf);
2149+
}
2150+
2151+
#[test]
2152+
fn test_dir_remove_file() {
2153+
let tmpdir = tmpdir();
2154+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2155+
check!(f.write(b"bar"));
2156+
check!(f.flush());
2157+
drop(f);
2158+
let dir = check!(Dir::new(tmpdir.path()));
2159+
check!(dir.remove_file("foo.txt"));
2160+
assert!(!matches!(exists(tmpdir.join("foo.txt")), Ok(true)));
2161+
}
2162+
2163+
#[test]
2164+
fn test_dir_remove_dir() {
2165+
let tmpdir = tmpdir();
2166+
check!(create_dir(tmpdir.join("foo")));
2167+
let dir = check!(Dir::new(tmpdir.path()));
2168+
check!(dir.remove_dir("foo"));
2169+
assert!(!matches!(exists(tmpdir.join("foo")), Ok(true)));
2170+
}
2171+
2172+
#[test]
2173+
fn test_dir_rename_file() {
2174+
let tmpdir = tmpdir();
2175+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2176+
check!(f.write(b"bar"));
2177+
check!(f.flush());
2178+
drop(f);
2179+
let dir = check!(Dir::new(tmpdir.path()));
2180+
check!(dir.rename("foo.txt", &dir, "baz.txt"));
2181+
let mut f = check!(File::open(tmpdir.join("baz.txt")));
2182+
let mut buf = [0u8; 3];
2183+
check!(f.read_exact(&mut buf));
2184+
assert_eq!(b"bar", &buf);
2185+
}
2186+
2187+
#[test]
2188+
fn test_dir_create_dir() {
2189+
let tmpdir = tmpdir();
2190+
let dir = check!(Dir::new(tmpdir.path()));
2191+
check!(dir.create_dir("foo"));
2192+
check!(Dir::new(tmpdir.join("foo")));
2193+
}
2194+
2195+
#[test]
2196+
fn test_dir_open_dir() {
2197+
let tmpdir = tmpdir();
2198+
let dir1 = check!(Dir::new(tmpdir.path()));
2199+
check!(dir1.create_dir("foo"));
2200+
let dir2 = check!(Dir::new(tmpdir.path().join("foo")));
2201+
let mut f = check!(dir2.open_with("bar.txt", &OpenOptions::new().create(true).write(true)));
2202+
check!(f.write(b"baz"));
2203+
check!(f.flush());
2204+
drop(f);
2205+
let dir3 = check!(dir1.open_dir("foo"));
2206+
let mut f = check!(dir3.open("bar.txt"));
2207+
let mut buf = [0u8; 3];
2208+
check!(f.read_exact(&mut buf));
2209+
assert_eq!(b"baz", &buf);
2210+
}
2211+
2212+
#[test]
2213+
fn test_dir_symlink() {
2214+
let tmpdir = tmpdir();
2215+
if !got_symlink_permission(&tmpdir) {
2216+
return;
2217+
};
2218+
2219+
let dir = check!(Dir::new(tmpdir.path()));
2220+
let mut f = check!(dir.open_with("foo.txt", &OpenOptions::new().write(true).create(true)));
2221+
check!(f.write(b"quux"));
2222+
check!(f.flush());
2223+
drop(f);
2224+
check!(dir.symlink("foo.txt", "bar.txt"));
2225+
let mut f = check!(dir.open("bar.txt"));
2226+
let mut buf = [0u8; 4];
2227+
check!(f.read_exact(&mut buf));
2228+
assert_eq!(b"quux", &buf);
2229+
}

library/std/src/sys/fs/common.rs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#![allow(dead_code)] // not used on all platforms
22

3-
use crate::fs;
3+
use crate::fmt;
4+
use crate::fs::{self, create_dir, remove_dir, remove_file, rename};
45
use crate::io::{self, Error, ErrorKind};
5-
use crate::path::Path;
6+
use crate::path::{Path, PathBuf};
7+
use crate::sys::fs::{File, OpenOptions, symlink};
68
use crate::sys_common::ignore_notfound;
79

810
pub(crate) const NOT_FILE_ERROR: Error = io::const_error!(
@@ -58,3 +60,70 @@ pub fn exists(path: &Path) -> io::Result<bool> {
5860
Err(error) => Err(error),
5961
}
6062
}
63+
64+
pub struct Dir {
65+
path: PathBuf,
66+
}
67+
68+
impl Dir {
69+
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
70+
Ok(Self { path: path.as_ref().to_path_buf() })
71+
}
72+
73+
pub fn new_with<P: AsRef<Path>>(path: P, _opts: &OpenOptions) -> io::Result<Self> {
74+
Ok(Self { path: path.as_ref().to_path_buf() })
75+
}
76+
77+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
78+
Ok(Self { path: path.as_ref().to_path_buf() })
79+
}
80+
81+
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
82+
let mut opts = OpenOptions::new();
83+
opts.read(true);
84+
File::open(&self.path.join(path), &opts)
85+
}
86+
87+
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
88+
File::open(&self.path.join(path), opts)
89+
}
90+
91+
pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
92+
create_dir(self.path.join(path))
93+
}
94+
95+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
96+
Self::new(self.path.join(path))
97+
}
98+
99+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
100+
Self::new_with(self.path.join(path), opts)
101+
}
102+
103+
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
104+
remove_file(self.path.join(path))
105+
}
106+
107+
pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
108+
remove_dir(self.path.join(path))
109+
}
110+
111+
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(
112+
&self,
113+
from: P,
114+
to_dir: &Self,
115+
to: Q,
116+
) -> io::Result<()> {
117+
rename(self.path.join(from), to_dir.path.join(to))
118+
}
119+
120+
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q) -> io::Result<()> {
121+
symlink(original.as_ref(), link.as_ref())
122+
}
123+
}
124+
125+
impl fmt::Debug for Dir {
126+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127+
f.debug_struct("Dir").field("path", &self.path).finish()
128+
}
129+
}

library/std/src/sys/fs/hermit.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ use crate::path::{Path, PathBuf};
1111
use crate::sync::Arc;
1212
use crate::sys::common::small_c_string::run_path_with_cstr;
1313
use crate::sys::fd::FileDesc;
14-
pub use crate::sys::fs::common::{copy, exists};
14+
pub use crate::sys::fs::common::{Dir, copy, exists};
15+
use crate::sys::fs::{remove_dir, remove_file};
1516
use crate::sys::time::SystemTime;
1617
use crate::sys::{cvt, unsupported, unsupported_err};
1718
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
1819
use crate::{fmt, mem};
1920

2021
#[derive(Debug)]
2122
pub struct File(FileDesc);
23+
2224
#[derive(Clone)]
2325
pub struct FileAttr {
2426
stat_val: stat_struct,
@@ -251,6 +253,32 @@ impl DirEntry {
251253
pub fn file_name_os_str(&self) -> &OsStr {
252254
self.name.as_os_str()
253255
}
256+
257+
pub fn open_file(&self) -> io::Result<File> {
258+
let mut opts = OpenOptions::new();
259+
opts.read(true);
260+
File::open(&self.path(), &opts)
261+
}
262+
263+
pub fn open_file_with(&self, opts: &OpenOptions) -> io::Result<File> {
264+
File::open(&self.path(), opts)
265+
}
266+
267+
pub fn open_dir(&self) -> io::Result<Dir> {
268+
Dir::new(self.path())
269+
}
270+
271+
pub fn open_dir_with(&self, opts: &OpenOptions) -> io::Result<Dir> {
272+
Dir::new_with(self.path(), opts)
273+
}
274+
275+
pub fn remove_file(&self) -> io::Result<()> {
276+
remove_file(&self.path())
277+
}
278+
279+
pub fn remove_dir(&self) -> io::Result<()> {
280+
remove_dir(&self.path())
281+
}
254282
}
255283

256284
impl OpenOptions {

library/std/src/sys/fs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
5353
}
5454

5555
pub use imp::{
56-
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
56+
Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
5757
ReadDir,
5858
};
5959

library/std/src/sys/fs/solid.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use crate::os::raw::{c_int, c_short};
99
use crate::os::solid::ffi::OsStrExt;
1010
use crate::path::{Path, PathBuf};
1111
use crate::sync::Arc;
12-
pub use crate::sys::fs::common::exists;
12+
pub use crate::sys::fs::common::{Dir, exists};
13+
use crate::sys::fs::{remove_dir, remove_file};
1314
use crate::sys::pal::{abi, error};
1415
use crate::sys::time::SystemTime;
1516
use crate::sys::{unsupported, unsupported_err};
@@ -219,6 +220,32 @@ impl DirEntry {
219220
_ => lstat(&self.path()).map(|m| m.file_type()),
220221
}
221222
}
223+
224+
pub fn open_file(&self) -> io::Result<File> {
225+
let mut opts = OpenOptions::new();
226+
opts.read(true);
227+
File::open(&self.path(), &opts)
228+
}
229+
230+
pub fn open_file_with(&self, opts: &OpenOptions) -> io::Result<File> {
231+
File::open(&self.path(), opts)
232+
}
233+
234+
pub fn open_dir(&self) -> io::Result<Dir> {
235+
Dir::new(self.path())
236+
}
237+
238+
pub fn open_dir_with(&self, opts: &OpenOptions) -> io::Result<Dir> {
239+
Dir::new_with(self.path(), opts)
240+
}
241+
242+
pub fn remove_file(&self) -> io::Result<()> {
243+
remove_file(&self.path())
244+
}
245+
246+
pub fn remove_dir(&self) -> io::Result<()> {
247+
remove_dir(&self.path())
248+
}
222249
}
223250

224251
impl OpenOptions {

0 commit comments

Comments
 (0)