From ba4e4fc13f3b08025030c97797873c7e8c0f3c3a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 27 Apr 2015 17:29:35 -0700 Subject: [PATCH] std: Implement fs::DirBuilder This is the last remaining portion of #24796 --- src/libstd/fs.rs | 62 ++++++++++++++++++++++++++++++++--- src/libstd/sys/unix/ext/fs.rs | 16 +++++++++ src/libstd/sys/unix/fs2.rs | 24 ++++++++++---- src/libstd/sys/windows/fs2.rs | 20 +++++++---- 4 files changed, 105 insertions(+), 17 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index b47c0c696bffa..2b15a4ff83ed1 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -152,6 +152,15 @@ pub struct Permissions(fs_imp::FilePermissions); #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct FileType(fs_imp::FileType); +/// A builder used to create directories in various manners. +/// +/// This builder also supports platform-specific options. +#[unstable(feature = "dir_builder", reason = "recently added API")] +pub struct DirBuilder { + inner: fs_imp::DirBuilder, + recursive: bool, +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -997,7 +1006,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir>(path: P) -> io::Result<()> { - fs_imp::mkdir(path.as_ref()) + DirBuilder::new().create(path.as_ref()) } /// Recursively create a directory and all of its parent components if they @@ -1022,10 +1031,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir_all>(path: P) -> io::Result<()> { - let path = path.as_ref(); - if path == Path::new("") || path.is_dir() { return Ok(()) } - if let Some(p) = path.parent() { try!(create_dir_all(p)) } - create_dir(path) + DirBuilder::new().recursive(true).create(path.as_ref()) } /// Removes an existing, empty directory. @@ -1286,6 +1292,52 @@ pub fn set_permissions>(path: P, perm: Permissions) -> io::Result fs_imp::set_perm(path.as_ref(), perm.0) } +impl DirBuilder { + /// Creates a new set of options with default mode/security settings for all + /// platforms and also non-recursive. + pub fn new() -> DirBuilder { + DirBuilder { + inner: fs_imp::DirBuilder::new(), + recursive: false, + } + } + + /// Indicate that directories create should be created recursively, creating + /// all parent directories if they do not exist with the same security and + /// permissions settings. + /// + /// This option defaults to `false` + pub fn recursive(&mut self, recursive: bool) -> &mut Self { + self.recursive = recursive; + self + } + + /// Create the specified directory with the options configured in this + /// builder. + pub fn create>(&self, path: P) -> io::Result<()> { + let path = path.as_ref(); + if self.recursive { + self.create_dir_all(path) + } else { + self.inner.mkdir(path) + } + } + + fn create_dir_all(&self, path: &Path) -> io::Result<()> { + if path == Path::new("") || path.is_dir() { return Ok(()) } + if let Some(p) = path.parent() { + try!(self.create_dir_all(p)) + } + self.inner.mkdir(path) + } +} + +impl AsInnerMut for DirBuilder { + fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder { + &mut self.inner + } +} + #[cfg(test)] mod tests { #![allow(deprecated)] //rand diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index ad6a856d5bcca..2e4ed38e50fe7 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -189,3 +189,19 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { sys::fs2::symlink(src.as_ref(), dst.as_ref()) } + +#[unstable(feature = "dir_builder", reason = "recently added API")] +/// An extension trait for `fs::DirBuilder` for unix-specific options. +pub trait DirBuilderExt { + /// Sets the mode to create new directories with. This option defaults to + /// 0o777. + fn mode(&mut self, mode: raw::mode_t) -> &mut Self; +} + +impl DirBuilderExt for fs::DirBuilder { + fn mode(&mut self, mode: raw::mode_t) -> &mut fs::DirBuilder { + self.as_inner_mut().set_mode(mode); + self + } +} + diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index 678d8065ce7b8..350161c751cb8 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -61,6 +61,8 @@ pub struct FilePermissions { mode: mode_t } #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct FileType { mode: mode_t } +pub struct DirBuilder { mode: mode_t } + impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { @@ -342,6 +344,22 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } } +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { mode: 0o777 } + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = try!(cstr(p)); + try!(cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })); + Ok(()) + } + + pub fn set_mode(&mut self, mode: mode_t) { + self.mode = mode; + } +} + fn cstr(path: &Path) -> io::Result { path.as_os_str().to_cstring().ok_or( io::Error::new(io::ErrorKind::InvalidInput, "path contained a null")) @@ -401,12 +419,6 @@ impl fmt::Debug for File { } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = try!(cstr(p)); - try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) })); - Ok(()) -} - pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); let p = try!(cstr(p)); diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index 2c81c34d3a4a6..d6b1b804adefd 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -70,6 +70,8 @@ pub struct OpenOptions { #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { attrs: libc::DWORD } +pub struct DirBuilder; + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { @@ -425,12 +427,18 @@ impl FileType { pub fn is_symlink(&self) -> bool { *self == FileType::Symlink } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = to_utf16(p); - try!(cvt(unsafe { - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - })); - Ok(()) +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { mode: 0o777 } + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = to_utf16(p); + try!(cvt(unsafe { + libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) + })); + Ok(()) + } } pub fn readdir(p: &Path) -> io::Result {