From f1d6a50d3f022c0dc20e9010d55b0560a67ae3ba Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 22 Jul 2015 08:34:05 -0700 Subject: [PATCH] Add OpenOptions::exclusive It maps to O_EXCL on *nix and CREATE_NEW on Windows. --- src/libstd/fs.rs | 23 +++++++++++++++++++++++ src/libstd/sys/unix/fs.rs | 4 ++++ src/libstd/sys/windows/fs.rs | 13 ++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e5f2fcbae8394..b981312a7f648 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -473,6 +473,25 @@ impl OpenOptions { self.0.create(create); self } + /// Sets the option for exclusive creation mode. + /// + /// If both `OpenOptions::create` and this are set, the file will only + /// be successfully opened if it does not already exist on the filesystem. + /// If this is set but `OpenOptions::create` is not, the result is + /// unspecified. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().create(true).exclusive(true).open("foo.txt"); + /// ``` + #[unstable(feature = "open_options_exclusive", reason = "recently added")] + pub fn exclusive(&mut self, exclusive: bool) -> &mut OpenOptions { + self.0.exclusive(exclusive); self + } + /// Opens a file at `path` with the options specified by `self`. /// /// # Errors @@ -2044,6 +2063,10 @@ mod tests { check!(f.write("bar".as_bytes())); } assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + + check!(c(&rw).create(true).exclusive(true).open(&tmpdir.join("i"))); + assert!(tmpdir.join("i").exists()); + error!(c(&rw).create(true).exclusive(true).open(&tmpdir.join("i")), "exists"); } #[test] diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0c99a30f107d0..6c8b22d456ad0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -240,6 +240,10 @@ impl OpenOptions { self.flag(libc::O_CREAT, create); } + pub fn exclusive(&mut self, exclusive: bool) { + self.flag(libc::O_EXCL, exclusive); + } + pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 4ce6d53cf125c..b5eaef2016754 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -61,6 +61,7 @@ pub struct OpenOptions { read: bool, write: bool, truncate: bool, + exclusive: bool, desired_access: Option, share_mode: Option, creation_disposition: Option, @@ -158,6 +159,7 @@ impl OpenOptions { pub fn append(&mut self, append: bool) { self.append = append; } pub fn create(&mut self, create: bool) { self.create = create; } pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } + pub fn exclusive(&mut self, exclusive: bool) { self.exclusive = exclusive; } pub fn creation_disposition(&mut self, val: u32) { self.creation_disposition = Some(val); } @@ -197,11 +199,12 @@ impl OpenOptions { fn get_creation_disposition(&self) -> libc::DWORD { self.creation_disposition.unwrap_or({ - match (self.create, self.truncate) { - (true, true) => libc::CREATE_ALWAYS, - (true, false) => libc::OPEN_ALWAYS, - (false, false) => libc::OPEN_EXISTING, - (false, true) => { + match (self.create, self.truncate, self.exclusive) { + (true, true, false) => libc::CREATE_ALWAYS, + (true, false, false) => libc::OPEN_ALWAYS, + (true, _, true) => libc::CREATE_NEW, + (false, false, _) => libc::OPEN_EXISTING, + (false, true, _) => { if self.write && !self.append { libc::CREATE_ALWAYS } else {