Auto merge of #30872 - pitdicker:expand_open_options, r=alexcrichton
Tracking issue: #30014 This implements the RFC and makes a few other changes. I have added a few extra tests, and made the Windows and Unix code as similar as possible. Part of the RFC mentions the unstable OpenOptionsExt trait on Windows (see #27720). I have added a few extra methods to future-proof it for CreateFile2.
This commit is contained in:
@@ -118,8 +118,38 @@ pub trait OpenOptionsExt {
|
||||
///
|
||||
/// If a new file is created as part of a `File::open_opts` call then this
|
||||
/// specified `mode` will be used as the permission bits for the new file.
|
||||
/// If no `mode` is set, the default of `0o666` will be used.
|
||||
/// The operating system masks out bits with the systems `umask`, to produce
|
||||
/// the final permissions.
|
||||
#[stable(feature = "fs_ext", since = "1.1.0")]
|
||||
fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
|
||||
|
||||
/// Pass custom flags to the `flags` agument of `open`.
|
||||
///
|
||||
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
|
||||
/// ensure they do not interfere with the access mode set by Rusts options.
|
||||
///
|
||||
/// Custom flags can only set flags, not remove flags set by Rusts options.
|
||||
/// This options overwrites any previously set custom flags.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// extern crate libc;
|
||||
/// use std::fs::OpenOptions;
|
||||
/// use std::os::unix::fs::OpenOptionsExt;
|
||||
///
|
||||
/// let mut options = OpenOptions::new();
|
||||
/// options.write(true);
|
||||
/// if cfg!(unix) {
|
||||
/// options.custom_flags(libc::O_NOFOLLOW);
|
||||
/// }
|
||||
/// let file = options.open("foo.txt");
|
||||
/// ```
|
||||
#[unstable(feature = "expand_open_options",
|
||||
reason = "recently added",
|
||||
issue = "30014")]
|
||||
fn custom_flags(&mut self, flags: i32) -> &mut Self;
|
||||
}
|
||||
|
||||
#[stable(feature = "fs_ext", since = "1.1.0")]
|
||||
@@ -127,6 +157,10 @@ impl OpenOptionsExt for OpenOptions {
|
||||
fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
|
||||
self.as_inner_mut().mode(mode); self
|
||||
}
|
||||
|
||||
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
|
||||
self.as_inner_mut().custom_flags(flags); self
|
||||
}
|
||||
}
|
||||
|
||||
// Hm, why are there casts here to the returned type, shouldn't the types always
|
||||
@@ -281,4 +315,3 @@ impl DirBuilderExt for fs::DirBuilder {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,9 +50,15 @@ pub struct DirEntry {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OpenOptions {
|
||||
flags: c_int,
|
||||
// generic
|
||||
read: bool,
|
||||
write: bool,
|
||||
append: bool,
|
||||
truncate: bool,
|
||||
create: bool,
|
||||
create_new: bool,
|
||||
// system-specific
|
||||
custom_flags: i32,
|
||||
mode: mode_t,
|
||||
}
|
||||
|
||||
@@ -233,44 +239,61 @@ impl DirEntry {
|
||||
impl OpenOptions {
|
||||
pub fn new() -> OpenOptions {
|
||||
OpenOptions {
|
||||
flags: libc::O_CLOEXEC,
|
||||
// generic
|
||||
read: false,
|
||||
write: false,
|
||||
append: false,
|
||||
truncate: false,
|
||||
create: false,
|
||||
create_new: false,
|
||||
// system-specific
|
||||
custom_flags: 0,
|
||||
mode: 0o666,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&mut self, read: bool) {
|
||||
self.read = read;
|
||||
}
|
||||
pub fn read(&mut self, read: bool) { self.read = read; }
|
||||
pub fn write(&mut self, write: bool) { self.write = write; }
|
||||
pub fn append(&mut self, append: bool) { self.append = append; }
|
||||
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
|
||||
pub fn create(&mut self, create: bool) { self.create = create; }
|
||||
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
|
||||
|
||||
pub fn write(&mut self, write: bool) {
|
||||
self.write = write;
|
||||
}
|
||||
pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
|
||||
pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; }
|
||||
|
||||
pub fn append(&mut self, append: bool) {
|
||||
self.flag(libc::O_APPEND, append);
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, truncate: bool) {
|
||||
self.flag(libc::O_TRUNC, truncate);
|
||||
}
|
||||
|
||||
pub fn create(&mut self, create: bool) {
|
||||
self.flag(libc::O_CREAT, create);
|
||||
}
|
||||
|
||||
pub fn mode(&mut self, mode: raw::mode_t) {
|
||||
self.mode = mode as mode_t;
|
||||
}
|
||||
|
||||
fn flag(&mut self, bit: c_int, on: bool) {
|
||||
if on {
|
||||
self.flags |= bit;
|
||||
} else {
|
||||
self.flags &= !bit;
|
||||
fn get_access_mode(&self) -> io::Result<c_int> {
|
||||
match (self.read, self.write, self.append) {
|
||||
(true, false, false) => Ok(libc::O_RDONLY),
|
||||
(false, true, false) => Ok(libc::O_WRONLY),
|
||||
(true, true, false) => Ok(libc::O_RDWR),
|
||||
(false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
|
||||
(true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
|
||||
(false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_creation_mode(&self) -> io::Result<c_int> {
|
||||
match (self.write, self.append) {
|
||||
(true, false) => {}
|
||||
(false, false) =>
|
||||
if self.truncate || self.create || self.create_new {
|
||||
return Err(Error::from_raw_os_error(libc::EINVAL));
|
||||
},
|
||||
(_, true) =>
|
||||
if self.truncate && !self.create_new {
|
||||
return Err(Error::from_raw_os_error(libc::EINVAL));
|
||||
},
|
||||
}
|
||||
|
||||
Ok(match (self.create, self.truncate, self.create_new) {
|
||||
(false, false, false) => 0,
|
||||
(true, false, false) => libc::O_CREAT,
|
||||
(false, true, false) => libc::O_TRUNC,
|
||||
(true, true, false) => libc::O_CREAT | libc::O_TRUNC,
|
||||
(_, _, true) => libc::O_CREAT | libc::O_EXCL,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
@@ -280,12 +303,10 @@ impl File {
|
||||
}
|
||||
|
||||
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
||||
let flags = opts.flags | match (opts.read, opts.write) {
|
||||
(true, true) => libc::O_RDWR,
|
||||
(false, true) => libc::O_WRONLY,
|
||||
(true, false) |
|
||||
(false, false) => libc::O_RDONLY,
|
||||
};
|
||||
let flags = libc::O_CLOEXEC |
|
||||
try!(opts.get_access_mode()) |
|
||||
try!(opts.get_creation_mode()) |
|
||||
(opts.custom_flags as c_int & !libc::O_ACCMODE);
|
||||
let fd = try!(cvt_r(|| unsafe {
|
||||
libc::open(path.as_ptr(), flags, opts.mode as c_int)
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user