Skip to content

Commit ca0fcaf

Browse files
Auto merge of #139514 - Qelxiros:120426-dirfd, r=<try>
dirfd: preliminary unix and windows implementations Tracking issue: #120426 As per [this comment](#120426 (comment)), this issue needs someone to start work on an implementation, so I've implemented a couple functions for UNIX. There's a lot more work to be done here (most of the feature), so I'd love some guidance on what needs fixing in this PR and any notes on how to proceed. Thanks! try-job: `x86_64-msvc*` try-job: `test-various*` try-job: `dist-various*`
2 parents 111e9bc + 3deaa18 commit ca0fcaf

File tree

11 files changed

+1712
-94
lines changed

11 files changed

+1712
-94
lines changed

library/std/src/fs.rs

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

library/std/src/fs/tests.rs

Lines changed: 92 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};
2122
use crate::io::prelude::*;
2223
use crate::io::{BorrowedBuf, ErrorKind, SeekFrom};
2324
use crate::mem::MaybeUninit;
@@ -2084,3 +2085,93 @@ fn test_rename_junction() {
20842085
// Junction links are always absolute so we just check the file name is correct.
20852086
assert_eq!(fs::read_link(&dest).unwrap().file_name(), Some(not_exist.as_os_str()));
20862087
}
2088+
2089+
#[test]
2090+
fn test_dir_smoke_test() {
2091+
let tmpdir = tmpdir();
2092+
check!(Dir::new(tmpdir.path()));
2093+
}
2094+
2095+
#[test]
2096+
fn test_dir_read_file() {
2097+
let tmpdir = tmpdir();
2098+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2099+
check!(f.write(b"bar"));
2100+
check!(f.flush());
2101+
drop(f);
2102+
let dir = check!(Dir::new(tmpdir.path()));
2103+
let mut f = check!(dir.open("foo.txt"));
2104+
let mut buf = [0u8; 3];
2105+
check!(f.read_exact(&mut buf));
2106+
assert_eq!(b"bar", &buf);
2107+
}
2108+
2109+
#[test]
2110+
fn test_dir_write_file() {
2111+
let tmpdir = tmpdir();
2112+
let dir = check!(Dir::new(tmpdir.path()));
2113+
let mut f = check!(dir.open_with("foo.txt", &OpenOptions::new().write(true).create(true)));
2114+
check!(f.write(b"bar"));
2115+
check!(f.flush());
2116+
drop(f);
2117+
let mut f = check!(File::open(tmpdir.join("foo.txt")));
2118+
let mut buf = [0u8; 3];
2119+
check!(f.read_exact(&mut buf));
2120+
assert_eq!(b"bar", &buf);
2121+
}
2122+
2123+
#[test]
2124+
fn test_dir_remove_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+
check!(dir.remove_file("foo.txt"));
2132+
let result = File::open(tmpdir.join("foo.txt"));
2133+
#[cfg(all(unix, not(target_os = "vxworks")))]
2134+
error!(result, "No such file or directory");
2135+
#[cfg(target_os = "vxworks")]
2136+
error!(result, "no such file or directory");
2137+
#[cfg(windows)]
2138+
error!(result, 2); // ERROR_FILE_NOT_FOUND
2139+
}
2140+
2141+
#[test]
2142+
fn test_dir_remove_dir() {
2143+
let tmpdir = tmpdir();
2144+
check!(create_dir(tmpdir.join("foo")));
2145+
let dir = check!(Dir::new(tmpdir.path()));
2146+
check!(dir.remove_dir("foo"));
2147+
let result = Dir::new(tmpdir.join("foo"));
2148+
#[cfg(all(unix, not(target_os = "vxworks")))]
2149+
error!(result, "No such file or directory");
2150+
#[cfg(target_os = "vxworks")]
2151+
error!(result, "no such file or directory");
2152+
#[cfg(windows)]
2153+
error!(result, 2); // ERROR_FILE_NOT_FOUND
2154+
}
2155+
2156+
#[test]
2157+
fn test_dir_rename_file() {
2158+
let tmpdir = tmpdir();
2159+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2160+
check!(f.write(b"bar"));
2161+
check!(f.flush());
2162+
drop(f);
2163+
let dir = check!(Dir::new(tmpdir.path()));
2164+
check!(dir.rename("foo.txt", &dir, "baz.txt"));
2165+
let mut f = check!(File::open(tmpdir.join("baz.txt")));
2166+
let mut buf = [0u8; 3];
2167+
check!(f.read_exact(&mut buf));
2168+
assert_eq!(b"bar", &buf);
2169+
}
2170+
2171+
#[test]
2172+
fn test_dir_create_dir() {
2173+
let tmpdir = tmpdir();
2174+
let dir = check!(Dir::new(tmpdir.path()));
2175+
check!(dir.create_dir("foo"));
2176+
check!(Dir::new(tmpdir.join("foo")));
2177+
}

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

Lines changed: 67 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};
68
use crate::sys_common::ignore_notfound;
79

810
pub(crate) const NOT_FILE_ERROR: Error = io::const_error!(
@@ -58,3 +60,66 @@ 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+
121+
impl fmt::Debug for Dir {
122+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123+
f.debug_struct("Dir").field("path", &self.path).finish()
124+
}
125+
}

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
@@ -47,7 +47,7 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
4747
}
4848

4949
pub use imp::{
50-
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
50+
Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
5151
ReadDir,
5252
};
5353

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 {

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub struct FileAttr {
2020
size: u64,
2121
}
2222

23+
pub struct Dir(!);
24+
2325
pub struct ReadDir(!);
2426

2527
pub struct DirEntry(!);
@@ -115,6 +117,63 @@ impl FileType {
115117
}
116118
}
117119

120+
impl Dir {
121+
pub fn new<P: AsRef<Path>>(_path: P) -> io::Result<Self> {
122+
unsupported()
123+
}
124+
125+
pub fn new_with<P: AsRef<Path>>(_path: P, _opts: &OpenOptions) -> io::Result<Self> {
126+
unsupported()
127+
}
128+
129+
pub fn new_for_traversal<P: AsRef<Path>>(_path: P) -> io::Result<Self> {
130+
unsupported()
131+
}
132+
133+
pub fn open<P: AsRef<Path>>(&self, _path: P) -> io::Result<File> {
134+
self.0
135+
}
136+
137+
pub fn open_with<P: AsRef<Path>>(&self, _path: P, _opts: &OpenOptions) -> io::Result<File> {
138+
self.0
139+
}
140+
141+
pub fn create_dir<P: AsRef<Path>>(&self, _path: P) -> io::Result<()> {
142+
self.0
143+
}
144+
145+
pub fn open_dir<P: AsRef<Path>>(&self, _path: P) -> io::Result<Self> {
146+
self.0
147+
}
148+
149+
pub fn open_dir_with<P: AsRef<Path>>(&self, _path: P, _opts: &OpenOptions) -> io::Result<Self> {
150+
self.0
151+
}
152+
153+
pub fn remove_file<P: AsRef<Path>>(&self, _path: P) -> io::Result<()> {
154+
self.0
155+
}
156+
157+
pub fn remove_dir<P: AsRef<Path>>(&self, _path: P) -> io::Result<()> {
158+
self.0
159+
}
160+
161+
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(
162+
&self,
163+
_from: P,
164+
_to_dir: &Self,
165+
_to: Q,
166+
) -> io::Result<()> {
167+
self.0
168+
}
169+
}
170+
171+
impl fmt::Debug for Dir {
172+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
173+
self.0
174+
}
175+
}
176+
118177
impl fmt::Debug for ReadDir {
119178
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
120179
self.0
@@ -145,6 +204,30 @@ impl DirEntry {
145204
pub fn file_type(&self) -> io::Result<FileType> {
146205
self.0
147206
}
207+
208+
pub fn open_file(&self) -> io::Result<File> {
209+
self.0
210+
}
211+
212+
pub fn open_file_with(&self, _opts: &OpenOptions) -> io::Result<File> {
213+
self.0
214+
}
215+
216+
pub fn open_dir(&self) -> io::Result<Dir> {
217+
self.0
218+
}
219+
220+
pub fn open_dir_with(&self, _opts: &OpenOptions) -> io::Result<Dir> {
221+
self.0
222+
}
223+
224+
pub fn remove_file(&self) -> io::Result<()> {
225+
self.0
226+
}
227+
228+
pub fn remove_dir(&self) -> io::Result<()> {
229+
self.0
230+
}
148231
}
149232

150233
impl OpenOptions {

0 commit comments

Comments
 (0)