-
Notifications
You must be signed in to change notification settings - Fork 13.7k
minimal dirfd implementation (1/4) #146341
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -153,6 +153,32 @@ pub enum TryLockError { | |||
WouldBlock, | ||||
} | ||||
|
||||
/// An object providing access to a directory on the filesystem. | ||||
/// | ||||
/// Directories are automatically closed when they go out of scope. Errors detected | ||||
/// on closing are ignored by the implementation of `Drop`. | ||||
/// | ||||
/// # Examples | ||||
/// | ||||
/// Opens a directory and then a file inside it. | ||||
/// | ||||
/// ```no_run | ||||
/// #![feature(dirfd)] | ||||
/// use std::{fs::Dir, io}; | ||||
/// | ||||
/// fn main() -> std::io::Result<()> { | ||||
/// let dir = Dir::open("foo")?; | ||||
/// let mut file = dir.open_file("bar.txt")?; | ||||
/// let contents = io::read_to_string(file)?; | ||||
/// assert_eq!(contents, "Hello, world!"); | ||||
/// Ok(()) | ||||
/// } | ||||
/// ``` | ||||
#[unstable(feature = "dirfd", issue = "120426")] | ||||
pub struct Dir { | ||||
inner: fs_imp::Dir, | ||||
} | ||||
|
||||
/// Metadata information about a file. | ||||
/// | ||||
/// This structure is returned from the [`metadata`] or | ||||
|
@@ -1474,6 +1500,85 @@ impl Seek for Arc<File> { | |||
} | ||||
} | ||||
|
||||
impl Dir { | ||||
/// Attempts to open a directory at `path` in read-only mode. | ||||
/// | ||||
/// # Errors | ||||
/// | ||||
/// This function will return an error if `path` does not point to an existing directory. | ||||
/// Other errors may also be returned according to [`OpenOptions::open`]. | ||||
/// | ||||
/// # Examples | ||||
/// | ||||
/// ```no_run | ||||
/// #![feature(dirfd)] | ||||
/// use std::{fs::Dir, io}; | ||||
/// | ||||
/// fn main() -> std::io::Result<()> { | ||||
/// let dir = Dir::open("foo")?; | ||||
/// let mut f = dir.open_file("bar.txt")?; | ||||
/// let contents = io::read_to_string(f)?; | ||||
/// assert_eq!(contents, "Hello, world!"); | ||||
/// Ok(()) | ||||
/// } | ||||
/// ``` | ||||
#[unstable(feature = "dirfd", issue = "120426")] | ||||
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> { | ||||
fs_imp::Dir::open(path).map(|inner| Self { inner }) | ||||
} | ||||
|
||||
/// | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
/// Attempts to open a file in read-only mode relative to this directory. | ||||
/// | ||||
/// # Errors | ||||
/// | ||||
/// This function will return an error if `path` does not point to an existing file. | ||||
/// Other errors may also be returned according to [`OpenOptions::open`]. | ||||
/// | ||||
/// # Examples | ||||
/// | ||||
/// ```no_run | ||||
/// #![feature(dirfd)] | ||||
/// use std::{fs::Dir, io}; | ||||
/// | ||||
/// fn main() -> std::io::Result<()> { | ||||
/// let dir = Dir::open("foo")?; | ||||
/// let mut f = dir.open_file("bar.txt")?; | ||||
/// let contents = io::read_to_string(f)?; | ||||
/// assert_eq!(contents, "Hello, world!"); | ||||
/// Ok(()) | ||||
/// } | ||||
/// ``` | ||||
#[unstable(feature = "dirfd", issue = "120426")] | ||||
pub fn open_file<P: AsRef<Path>>(&self, path: P) -> io::Result<File> { | ||||
self.inner.open_file(path).map(|f| File { inner: f }) | ||||
} | ||||
} | ||||
|
||||
impl AsInner<fs_imp::Dir> for Dir { | ||||
#[inline] | ||||
fn as_inner(&self) -> &fs_imp::Dir { | ||||
&self.inner | ||||
} | ||||
} | ||||
impl FromInner<fs_imp::Dir> for Dir { | ||||
fn from_inner(f: fs_imp::Dir) -> Dir { | ||||
Dir { inner: f } | ||||
} | ||||
} | ||||
impl IntoInner<fs_imp::Dir> for Dir { | ||||
fn into_inner(self) -> fs_imp::Dir { | ||||
self.inner | ||||
} | ||||
} | ||||
|
||||
#[unstable(feature = "dirfd", issue = "120426")] | ||||
impl fmt::Debug for Dir { | ||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
self.inner.fmt(f) | ||||
} | ||||
} | ||||
|
||||
impl OpenOptions { | ||||
/// Creates a blank new set of options ready for configuration. | ||||
/// | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
#![allow(dead_code)] // not used on all platforms | ||
|
||
use crate::fs; | ||
use crate::io::{self, Error, ErrorKind}; | ||
use crate::path::Path; | ||
use crate::path::{Path, PathBuf}; | ||
use crate::sys::fs::{File, OpenOptions}; | ||
use crate::sys_common::ignore_notfound; | ||
use crate::{fmt, fs}; | ||
|
||
pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( | ||
ErrorKind::InvalidInput, | ||
|
@@ -58,3 +59,25 @@ pub fn exists(path: &Path) -> io::Result<bool> { | |
Err(error) => Err(error), | ||
} | ||
} | ||
|
||
pub struct Dir { | ||
path: PathBuf, | ||
} | ||
Comment on lines
+63
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a doc about this being an absolute path, per #120426 and the previous comment. It would also be good to add a note that this fallback doesn't provide the TOCTOU safety. |
||
|
||
impl Dir { | ||
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> { | ||
Ok(Self { path: path.as_ref().to_path_buf() }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't act as expected if the user passes a relative path here then changes directories, it should store an absolute path. |
||
} | ||
|
||
pub fn open_file<P: AsRef<Path>>(&self, path: P) -> io::Result<File> { | ||
let mut opts = OpenOptions::new(); | ||
opts.read(true); | ||
File::open(&self.path.join(path), &opts) | ||
} | ||
} | ||
|
||
impl fmt::Debug for Dir { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("Dir").field("path", &self.path).finish() | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this just reexport from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs should also cover some of the API goals and platform-specific behavior (basically what #120426 covers)