mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-29 11:37:39 +00:00
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:
commit
292af75f8d
193
src/libstd/fs.rs
193
src/libstd/fs.rs
@ -375,7 +375,7 @@ impl<'a> Seek for &'a File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OpenOptions {
|
impl OpenOptions {
|
||||||
/// Creates a blank net set of options ready for configuration.
|
/// Creates a blank new set of options ready for configuration.
|
||||||
///
|
///
|
||||||
/// All options are initially set to `false`.
|
/// All options are initially set to `false`.
|
||||||
///
|
///
|
||||||
@ -384,7 +384,8 @@ impl OpenOptions {
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use std::fs::OpenOptions;
|
/// use std::fs::OpenOptions;
|
||||||
///
|
///
|
||||||
/// let file = OpenOptions::new().open("foo.txt");
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// let file = options.read(true).open("foo.txt");
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn new() -> OpenOptions {
|
pub fn new() -> OpenOptions {
|
||||||
@ -413,6 +414,9 @@ impl OpenOptions {
|
|||||||
/// This option, when true, will indicate that the file should be
|
/// This option, when true, will indicate that the file should be
|
||||||
/// `write`-able if opened.
|
/// `write`-able if opened.
|
||||||
///
|
///
|
||||||
|
/// If a file already exist, any write calls on the file will overwrite its
|
||||||
|
/// contents, without truncating it.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
@ -429,13 +433,30 @@ impl OpenOptions {
|
|||||||
///
|
///
|
||||||
/// This option, when true, means that writes will append to a file instead
|
/// This option, when true, means that writes will append to a file instead
|
||||||
/// of overwriting previous contents.
|
/// of overwriting previous contents.
|
||||||
|
/// Note that setting `.write(true).append(true)` has the same effect as
|
||||||
|
/// setting only `.append(true)`.
|
||||||
|
///
|
||||||
|
/// For most filesystems the operating system guarantees all writes are
|
||||||
|
/// atomic: no writes get mangled because another process writes at the same
|
||||||
|
/// time.
|
||||||
|
///
|
||||||
|
/// One maybe obvious note when using append-mode: make sure that all data
|
||||||
|
/// that belongs together, is written the the file in one operation. This
|
||||||
|
/// can be done by concatenating strings before passing them to `write()`,
|
||||||
|
/// or using a buffered writer (with a more than adequately sized buffer)
|
||||||
|
/// and calling `flush()` when the message is complete.
|
||||||
|
///
|
||||||
|
/// If a file is opened with both read and append access, beware that after
|
||||||
|
/// opening and after every write the position for reading may be set at the
|
||||||
|
/// end of the file. So before writing save the current position (using
|
||||||
|
/// `seek(SeekFrom::Current(0))`, and restore it before the next read.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use std::fs::OpenOptions;
|
/// use std::fs::OpenOptions;
|
||||||
///
|
///
|
||||||
/// let file = OpenOptions::new().write(true).append(true).open("foo.txt");
|
/// let file = OpenOptions::new().append(true).open("foo.txt");
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
|
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
|
||||||
@ -447,6 +468,8 @@ impl OpenOptions {
|
|||||||
/// If a file is successfully opened with this option set it will truncate
|
/// If a file is successfully opened with this option set it will truncate
|
||||||
/// the file to 0 length if it already exists.
|
/// the file to 0 length if it already exists.
|
||||||
///
|
///
|
||||||
|
/// The file must be opened with write access for truncate to work.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
@ -464,18 +487,54 @@ impl OpenOptions {
|
|||||||
/// This option indicates whether a new file will be created if the file
|
/// This option indicates whether a new file will be created if the file
|
||||||
/// does not yet already exist.
|
/// does not yet already exist.
|
||||||
///
|
///
|
||||||
|
/// The file must be opened with write or append access in order to create
|
||||||
|
/// a new file.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use std::fs::OpenOptions;
|
/// use std::fs::OpenOptions;
|
||||||
///
|
///
|
||||||
/// let file = OpenOptions::new().create(true).open("foo.txt");
|
/// let file = OpenOptions::new().write(true).create(true).open("foo.txt");
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
|
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
|
||||||
self.0.create(create); self
|
self.0.create(create); self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the option to always create a new file.
|
||||||
|
///
|
||||||
|
/// This option indicates whether a new file will be created.
|
||||||
|
/// No file is allowed to exist at the target location, also no (dangling)
|
||||||
|
/// symlink.
|
||||||
|
///
|
||||||
|
/// This option is usefull because it as atomic. Otherwise between checking
|
||||||
|
/// whether a file exists and creating a new one, the file may have been
|
||||||
|
/// created by another process (a TOCTOU race condition / attack).
|
||||||
|
///
|
||||||
|
/// If `.create_new(true)` is set, `.create()` and `.truncate()` are
|
||||||
|
/// ignored.
|
||||||
|
///
|
||||||
|
/// The file must be opened with write or append access in order to create
|
||||||
|
/// a new file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// #![feature(expand_open_options)]
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
///
|
||||||
|
/// let file = OpenOptions::new().write(true)
|
||||||
|
/// .create_new(true)
|
||||||
|
/// .open("foo.txt");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "expand_open_options",
|
||||||
|
reason = "recently added",
|
||||||
|
issue = "30014")]
|
||||||
|
pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
|
||||||
|
self.0.create_new(create_new); self
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens a file at `path` with the options specified by `self`.
|
/// Opens a file at `path` with the options specified by `self`.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@ -483,10 +542,13 @@ impl OpenOptions {
|
|||||||
/// This function will return an error under a number of different
|
/// This function will return an error under a number of different
|
||||||
/// circumstances, to include but not limited to:
|
/// circumstances, to include but not limited to:
|
||||||
///
|
///
|
||||||
/// * Opening a file that does not exist with read access.
|
/// * Opening a file that does not exist without setting `create` or
|
||||||
|
/// `create_new`.
|
||||||
/// * Attempting to open a file with access that the user lacks
|
/// * Attempting to open a file with access that the user lacks
|
||||||
/// permissions for
|
/// permissions for
|
||||||
/// * Filesystem-level errors (full disk, etc)
|
/// * Filesystem-level errors (full disk, etc)
|
||||||
|
/// * Invalid combinations of open options (truncate without write access,
|
||||||
|
/// no access mode set, etc)
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -2098,61 +2160,114 @@ mod tests {
|
|||||||
|
|
||||||
let mut r = OO::new(); r.read(true);
|
let mut r = OO::new(); r.read(true);
|
||||||
let mut w = OO::new(); w.write(true);
|
let mut w = OO::new(); w.write(true);
|
||||||
let mut rw = OO::new(); rw.write(true).read(true);
|
let mut rw = OO::new(); rw.read(true).write(true);
|
||||||
|
let mut a = OO::new(); a.append(true);
|
||||||
|
let mut ra = OO::new(); ra.read(true).append(true);
|
||||||
|
|
||||||
match r.open(&tmpdir.join("a")) {
|
let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
|
||||||
Ok(..) => panic!(), Err(..) => {}
|
else { "Invalid argument" };
|
||||||
}
|
|
||||||
|
|
||||||
// Perform each one twice to make sure that it succeeds the second time
|
// Test various combinations of creation modes and access modes.
|
||||||
// (where the file exists)
|
//
|
||||||
check!(c(&w).create(true).open(&tmpdir.join("b")));
|
// Allowed:
|
||||||
assert!(tmpdir.join("b").exists());
|
// creation mode | read | write | read-write | append | read-append |
|
||||||
check!(c(&w).create(true).open(&tmpdir.join("b")));
|
// :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
|
||||||
check!(w.open(&tmpdir.join("b")));
|
// not set (open existing) | X | X | X | X | X |
|
||||||
|
// create | | X | X | X | X |
|
||||||
|
// truncate | | X | X | | |
|
||||||
|
// create and truncate | | X | X | | |
|
||||||
|
// create_new | | X | X | X | X |
|
||||||
|
//
|
||||||
|
// tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
|
||||||
|
|
||||||
|
// write-only
|
||||||
|
check!(c(&w).create_new(true).open(&tmpdir.join("a")));
|
||||||
|
check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
|
||||||
|
check!(c(&w).truncate(true).open(&tmpdir.join("a")));
|
||||||
|
check!(c(&w).create(true).open(&tmpdir.join("a")));
|
||||||
|
check!(c(&w).open(&tmpdir.join("a")));
|
||||||
|
|
||||||
|
// read-only
|
||||||
|
error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
|
||||||
|
error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
|
||||||
|
error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
|
||||||
|
error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
|
||||||
|
check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
|
||||||
|
|
||||||
|
// read-write
|
||||||
|
check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
|
||||||
|
check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
|
||||||
|
check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
|
||||||
check!(c(&rw).create(true).open(&tmpdir.join("c")));
|
check!(c(&rw).create(true).open(&tmpdir.join("c")));
|
||||||
assert!(tmpdir.join("c").exists());
|
check!(c(&rw).open(&tmpdir.join("c")));
|
||||||
check!(c(&rw).create(true).open(&tmpdir.join("c")));
|
|
||||||
check!(rw.open(&tmpdir.join("c")));
|
|
||||||
|
|
||||||
check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
|
// append
|
||||||
assert!(tmpdir.join("d").exists());
|
check!(c(&a).create_new(true).open(&tmpdir.join("d")));
|
||||||
check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
|
error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
|
||||||
check!(c(&w).append(true).open(&tmpdir.join("d")));
|
error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
|
||||||
|
check!(c(&a).create(true).open(&tmpdir.join("d")));
|
||||||
|
check!(c(&a).open(&tmpdir.join("d")));
|
||||||
|
|
||||||
check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
|
// read-append
|
||||||
assert!(tmpdir.join("e").exists());
|
check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
|
||||||
check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
|
error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
|
||||||
check!(c(&rw).append(true).open(&tmpdir.join("e")));
|
error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
|
||||||
|
check!(c(&ra).create(true).open(&tmpdir.join("e")));
|
||||||
|
check!(c(&ra).open(&tmpdir.join("e")));
|
||||||
|
|
||||||
check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
|
// Test opening a file without setting an access mode
|
||||||
assert!(tmpdir.join("f").exists());
|
let mut blank = OO::new();
|
||||||
check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
|
error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
|
||||||
check!(c(&w).truncate(true).open(&tmpdir.join("f")));
|
|
||||||
|
|
||||||
check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
|
// Test write works
|
||||||
assert!(tmpdir.join("g").exists());
|
check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
|
||||||
check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
|
|
||||||
check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
|
|
||||||
|
|
||||||
check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
|
// Test write fails for read-only
|
||||||
check!(r.open(&tmpdir.join("h")));
|
check!(r.open(&tmpdir.join("h")));
|
||||||
{
|
{
|
||||||
let mut f = check!(r.open(&tmpdir.join("h")));
|
let mut f = check!(r.open(&tmpdir.join("h")));
|
||||||
assert!(f.write("wut".as_bytes()).is_err());
|
assert!(f.write("wut".as_bytes()).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test write overwrites
|
||||||
|
{
|
||||||
|
let mut f = check!(c(&w).open(&tmpdir.join("h")));
|
||||||
|
check!(f.write("baz".as_bytes()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut f = check!(c(&r).open(&tmpdir.join("h")));
|
||||||
|
let mut b = vec![0; 6];
|
||||||
|
check!(f.read(&mut b));
|
||||||
|
assert_eq!(b, "bazbar".as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test truncate works
|
||||||
|
{
|
||||||
|
let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
|
||||||
|
check!(f.write("foo".as_bytes()));
|
||||||
|
}
|
||||||
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
||||||
|
|
||||||
|
// Test append works
|
||||||
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
||||||
{
|
{
|
||||||
let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
|
let mut f = check!(c(&a).open(&tmpdir.join("h")));
|
||||||
check!(f.write("bar".as_bytes()));
|
check!(f.write("bar".as_bytes()));
|
||||||
}
|
}
|
||||||
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
|
||||||
|
|
||||||
|
// Test .append(true) equals .write(true).append(true)
|
||||||
{
|
{
|
||||||
let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
|
let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
|
||||||
check!(f.write("bar".as_bytes()));
|
check!(f.write("baz".as_bytes()));
|
||||||
}
|
}
|
||||||
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn _assert_send_sync() {
|
||||||
|
fn _assert_send_sync<T: Send + Sync>() {}
|
||||||
|
_assert_send_sync::<OpenOptions>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -118,8 +118,38 @@ pub trait OpenOptionsExt {
|
|||||||
///
|
///
|
||||||
/// If a new file is created as part of a `File::open_opts` call then this
|
/// 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.
|
/// 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")]
|
#[stable(feature = "fs_ext", since = "1.1.0")]
|
||||||
fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
|
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")]
|
#[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 {
|
fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
|
||||||
self.as_inner_mut().mode(mode); self
|
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
|
// 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
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +50,15 @@ pub struct DirEntry {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OpenOptions {
|
pub struct OpenOptions {
|
||||||
flags: c_int,
|
// generic
|
||||||
read: bool,
|
read: bool,
|
||||||
write: bool,
|
write: bool,
|
||||||
|
append: bool,
|
||||||
|
truncate: bool,
|
||||||
|
create: bool,
|
||||||
|
create_new: bool,
|
||||||
|
// system-specific
|
||||||
|
custom_flags: i32,
|
||||||
mode: mode_t,
|
mode: mode_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,44 +239,61 @@ impl DirEntry {
|
|||||||
impl OpenOptions {
|
impl OpenOptions {
|
||||||
pub fn new() -> OpenOptions {
|
pub fn new() -> OpenOptions {
|
||||||
OpenOptions {
|
OpenOptions {
|
||||||
flags: libc::O_CLOEXEC,
|
// generic
|
||||||
read: false,
|
read: false,
|
||||||
write: false,
|
write: false,
|
||||||
|
append: false,
|
||||||
|
truncate: false,
|
||||||
|
create: false,
|
||||||
|
create_new: false,
|
||||||
|
// system-specific
|
||||||
|
custom_flags: 0,
|
||||||
mode: 0o666,
|
mode: 0o666,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, read: bool) {
|
pub fn read(&mut self, read: bool) { self.read = read; }
|
||||||
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) {
|
pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
|
||||||
self.write = write;
|
pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn append(&mut self, append: bool) {
|
fn get_access_mode(&self) -> io::Result<c_int> {
|
||||||
self.flag(libc::O_APPEND, append);
|
match (self.read, self.write, self.append) {
|
||||||
}
|
(true, false, false) => Ok(libc::O_RDONLY),
|
||||||
|
(false, true, false) => Ok(libc::O_WRONLY),
|
||||||
pub fn truncate(&mut self, truncate: bool) {
|
(true, true, false) => Ok(libc::O_RDWR),
|
||||||
self.flag(libc::O_TRUNC, truncate);
|
(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)),
|
||||||
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_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 {
|
impl File {
|
||||||
@ -280,12 +303,10 @@ impl File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
||||||
let flags = opts.flags | match (opts.read, opts.write) {
|
let flags = libc::O_CLOEXEC |
|
||||||
(true, true) => libc::O_RDWR,
|
try!(opts.get_access_mode()) |
|
||||||
(false, true) => libc::O_WRONLY,
|
try!(opts.get_creation_mode()) |
|
||||||
(true, false) |
|
(opts.custom_flags as c_int & !libc::O_ACCMODE);
|
||||||
(false, false) => libc::O_RDONLY,
|
|
||||||
};
|
|
||||||
let fd = try!(cvt_r(|| unsafe {
|
let fd = try!(cvt_r(|| unsafe {
|
||||||
libc::open(path.as_ptr(), flags, opts.mode as c_int)
|
libc::open(path.as_ptr(), flags, opts.mode as c_int)
|
||||||
}));
|
}));
|
||||||
|
@ -93,16 +93,30 @@ pub const CREATE_NEW: DWORD = 1;
|
|||||||
pub const OPEN_ALWAYS: DWORD = 4;
|
pub const OPEN_ALWAYS: DWORD = 4;
|
||||||
pub const OPEN_EXISTING: DWORD = 3;
|
pub const OPEN_EXISTING: DWORD = 3;
|
||||||
pub const TRUNCATE_EXISTING: DWORD = 5;
|
pub const TRUNCATE_EXISTING: DWORD = 5;
|
||||||
pub const FILE_APPEND_DATA: DWORD = 0x00000004;
|
|
||||||
pub const FILE_READ_DATA: DWORD = 0x00000001;
|
pub const FILE_READ_DATA: DWORD = 0x00000001;
|
||||||
pub const FILE_WRITE_DATA: DWORD = 0x00000002;
|
pub const FILE_WRITE_DATA: DWORD = 0x00000002;
|
||||||
pub const STANDARD_RIGHTS_READ: DWORD = 0x20000;
|
pub const FILE_APPEND_DATA: DWORD = 0x00000004;
|
||||||
pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000;
|
|
||||||
pub const FILE_WRITE_EA: DWORD = 0x00000010;
|
|
||||||
pub const FILE_READ_EA: DWORD = 0x00000008;
|
pub const FILE_READ_EA: DWORD = 0x00000008;
|
||||||
pub const SYNCHRONIZE: DWORD = 0x00100000;
|
pub const FILE_WRITE_EA: DWORD = 0x00000010;
|
||||||
pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
|
pub const FILE_EXECUTE: DWORD = 0x00000020;
|
||||||
pub const FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
|
pub const FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
|
||||||
|
pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
|
||||||
|
|
||||||
|
pub const DELETE: DWORD = 0x00008000;
|
||||||
|
pub const READ_CONTROL: DWORD = 0x00020000;
|
||||||
|
pub const WRITE_DAC: DWORD = 0x00040000;
|
||||||
|
pub const WRITE_OWNER: DWORD = 0x00080000;
|
||||||
|
pub const SYNCHRONIZE: DWORD = 0x00100000;
|
||||||
|
|
||||||
|
pub const GENERIC_READ: DWORD = 0x80000000;
|
||||||
|
pub const GENERIC_WRITE: DWORD = 0x40000000;
|
||||||
|
pub const GENERIC_EXECUTE: DWORD = 0x20000000;
|
||||||
|
pub const GENERIC_ALL: DWORD = 0x10000000;
|
||||||
|
|
||||||
|
pub const STANDARD_RIGHTS_READ: DWORD = READ_CONTROL;
|
||||||
|
pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL;
|
||||||
|
pub const STANDARD_RIGHTS_EXECUTE: DWORD = READ_CONTROL;
|
||||||
pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA |
|
pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA |
|
||||||
FILE_READ_ATTRIBUTES |
|
FILE_READ_ATTRIBUTES |
|
||||||
FILE_READ_EA |
|
FILE_READ_EA |
|
||||||
@ -113,6 +127,14 @@ pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |
|
|||||||
FILE_APPEND_DATA |
|
FILE_APPEND_DATA |
|
||||||
SYNCHRONIZE;
|
SYNCHRONIZE;
|
||||||
|
|
||||||
|
pub const SECURITY_ANONYMOUS: DWORD = 0 << 16;
|
||||||
|
pub const SECURITY_IDENTIFICATION: DWORD = 1 << 16;
|
||||||
|
pub const SECURITY_IMPERSONATION: DWORD = 2 << 16;
|
||||||
|
pub const SECURITY_DELEGATION: DWORD = 3 << 16;
|
||||||
|
pub const SECURITY_CONTEXT_TRACKING: DWORD = 0x00040000;
|
||||||
|
pub const SECURITY_EFFECTIVE_ONLY: DWORD = 0x00080000;
|
||||||
|
pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
pub struct WIN32_FIND_DATAW {
|
pub struct WIN32_FIND_DATAW {
|
||||||
|
@ -25,45 +25,131 @@ use sys_common::{AsInnerMut, AsInner};
|
|||||||
pub trait OpenOptionsExt {
|
pub trait OpenOptionsExt {
|
||||||
/// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
|
/// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
|
||||||
/// with the specified value.
|
/// with the specified value.
|
||||||
fn desired_access(&mut self, access: u32) -> &mut Self;
|
|
||||||
|
|
||||||
/// Overrides the `dwCreationDisposition` argument to the call to
|
|
||||||
/// `CreateFile` with the specified value.
|
|
||||||
///
|
///
|
||||||
/// This will override any values of the standard `create` flags, for
|
/// This will override the `read`, `write`, and `append` flags on the
|
||||||
/// example.
|
/// `OpenOptions` structure. This method provides fine-grained control over
|
||||||
fn creation_disposition(&mut self, val: u32) -> &mut Self;
|
/// the permissions to read, write and append data, attributes (like hidden
|
||||||
|
/// and system) and extended attributes.
|
||||||
/// Overrides the `dwFlagsAndAttributes` argument to the call to
|
|
||||||
/// `CreateFile` with the specified value.
|
|
||||||
///
|
///
|
||||||
/// This will override any values of the standard flags on the
|
/// # Examples
|
||||||
/// `OpenOptions` structure.
|
///
|
||||||
fn flags_and_attributes(&mut self, val: u32) -> &mut Self;
|
/// ```no_run
|
||||||
|
/// #![feature(open_options_ext)]
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// // Open without read and write permission, for example if you only need
|
||||||
|
/// // to call `stat()` on the file
|
||||||
|
/// let file = OpenOptions::new().access_mode(0).open("foo.txt");
|
||||||
|
/// ```
|
||||||
|
fn access_mode(&mut self, access: u32) -> &mut Self;
|
||||||
|
|
||||||
/// Overrides the `dwShareMode` argument to the call to `CreateFile` with
|
/// Overrides the `dwShareMode` argument to the call to `CreateFile` with
|
||||||
/// the specified value.
|
/// the specified value.
|
||||||
///
|
///
|
||||||
/// This will override any values of the standard flags on the
|
/// By default `share_mode` is set to
|
||||||
/// `OpenOptions` structure.
|
/// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. Specifying
|
||||||
|
/// less permissions denies others to read from, write to and/or delete the
|
||||||
|
/// file while it is open.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// #![feature(open_options_ext)]
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// // Do not allow others to read or modify this file while we have it open
|
||||||
|
/// // for writing
|
||||||
|
/// let file = OpenOptions::new().write(true)
|
||||||
|
/// .share_mode(0)
|
||||||
|
/// .open("foo.txt");
|
||||||
|
/// ```
|
||||||
fn share_mode(&mut self, val: u32) -> &mut Self;
|
fn share_mode(&mut self, val: u32) -> &mut Self;
|
||||||
|
|
||||||
|
/// Sets extra flags for the `dwFileFlags` argument to the call to
|
||||||
|
/// `CreateFile2` (or combines it with `attributes` and `security_qos_flags`
|
||||||
|
/// to set the `dwFlagsAndAttributes` for `CreateFile`).
|
||||||
|
///
|
||||||
|
/// 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 winapi;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.create(true).write(true);
|
||||||
|
/// if cfg!(windows) {
|
||||||
|
/// options.custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE);
|
||||||
|
/// }
|
||||||
|
/// let file = options.open("foo.txt");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "expand_open_options",
|
||||||
|
reason = "recently added",
|
||||||
|
issue = "30014")]
|
||||||
|
fn custom_flags(&mut self, flags: u32) -> &mut Self;
|
||||||
|
|
||||||
|
/// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to
|
||||||
|
/// the specified value (or combines it with `custom_flags` and
|
||||||
|
/// `security_qos_flags` to set the `dwFlagsAndAttributes` for
|
||||||
|
/// `CreateFile`).
|
||||||
|
///
|
||||||
|
/// If a _new_ file is created because it does not yet exist and
|
||||||
|
///`.create(true)` or `.create_new(true)` are specified, the new file is
|
||||||
|
/// given the attributes declared with `.attributes()`.
|
||||||
|
///
|
||||||
|
/// If an _existing_ file is opened with `.create(true).truncate(true)`, its
|
||||||
|
/// existing attributes are preserved and combined with the ones declared
|
||||||
|
/// with `.attributes()`.
|
||||||
|
///
|
||||||
|
/// In all other cases the attributes get ignored.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// #![feature(open_options_ext)]
|
||||||
|
/// extern crate winapi;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// let file = OpenOptions::new().write(true).create(true)
|
||||||
|
/// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
|
||||||
|
/// .open("foo.txt");
|
||||||
|
/// ```
|
||||||
|
fn attributes(&mut self, val: u32) -> &mut Self;
|
||||||
|
|
||||||
|
/// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to
|
||||||
|
/// the specified value (or combines it with `custom_flags` and `attributes`
|
||||||
|
/// to set the `dwFlagsAndAttributes` for `CreateFile`).
|
||||||
|
fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "open_options_ext",
|
#[unstable(feature = "open_options_ext",
|
||||||
reason = "may require more thought/methods",
|
reason = "may require more thought/methods",
|
||||||
issue = "27720")]
|
issue = "27720")]
|
||||||
impl OpenOptionsExt for OpenOptions {
|
impl OpenOptionsExt for OpenOptions {
|
||||||
fn desired_access(&mut self, access: u32) -> &mut OpenOptions {
|
fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
|
||||||
self.as_inner_mut().desired_access(access); self
|
self.as_inner_mut().access_mode(access); self
|
||||||
}
|
}
|
||||||
fn creation_disposition(&mut self, access: u32) -> &mut OpenOptions {
|
|
||||||
self.as_inner_mut().creation_disposition(access); self
|
fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
|
||||||
|
self.as_inner_mut().share_mode(share); self
|
||||||
}
|
}
|
||||||
fn flags_and_attributes(&mut self, access: u32) -> &mut OpenOptions {
|
|
||||||
self.as_inner_mut().flags_and_attributes(access); self
|
fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
|
||||||
|
self.as_inner_mut().custom_flags(flags); self
|
||||||
}
|
}
|
||||||
fn share_mode(&mut self, access: u32) -> &mut OpenOptions {
|
|
||||||
self.as_inner_mut().share_mode(access); self
|
fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
|
||||||
|
self.as_inner_mut().attributes(attributes); self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
|
||||||
|
self.as_inner_mut().security_qos_flags(flags); self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,18 +54,22 @@ pub struct DirEntry {
|
|||||||
data: c::WIN32_FIND_DATAW,
|
data: c::WIN32_FIND_DATAW,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone)]
|
||||||
pub struct OpenOptions {
|
pub struct OpenOptions {
|
||||||
create: bool,
|
// generic
|
||||||
append: bool,
|
|
||||||
read: bool,
|
read: bool,
|
||||||
write: bool,
|
write: bool,
|
||||||
|
append: bool,
|
||||||
truncate: bool,
|
truncate: bool,
|
||||||
desired_access: Option<c::DWORD>,
|
create: bool,
|
||||||
share_mode: Option<c::DWORD>,
|
create_new: bool,
|
||||||
creation_disposition: Option<c::DWORD>,
|
// system-specific
|
||||||
flags_and_attributes: Option<c::DWORD>,
|
custom_flags: u32,
|
||||||
security_attributes: usize, // *mut T doesn't have a Default impl
|
access_mode: Option<c::DWORD>,
|
||||||
|
attributes: c::DWORD,
|
||||||
|
share_mode: c::DWORD,
|
||||||
|
security_qos_flags: c::DWORD,
|
||||||
|
security_attributes: usize, // FIXME: should be a reference
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
@ -151,68 +155,86 @@ impl DirEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OpenOptions {
|
impl OpenOptions {
|
||||||
pub fn new() -> OpenOptions { Default::default() }
|
pub fn new() -> OpenOptions {
|
||||||
|
OpenOptions {
|
||||||
|
// generic
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
append: false,
|
||||||
|
truncate: false,
|
||||||
|
create: false,
|
||||||
|
create_new: false,
|
||||||
|
// system-specific
|
||||||
|
custom_flags: 0,
|
||||||
|
access_mode: None,
|
||||||
|
share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
|
||||||
|
attributes: 0,
|
||||||
|
security_qos_flags: 0,
|
||||||
|
security_attributes: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 write(&mut self, write: bool) { self.write = write; }
|
||||||
pub fn append(&mut self, append: bool) { self.append = append; }
|
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 truncate(&mut self, truncate: bool) { self.truncate = truncate; }
|
||||||
pub fn creation_disposition(&mut self, val: u32) {
|
pub fn create(&mut self, create: bool) { self.create = create; }
|
||||||
self.creation_disposition = Some(val);
|
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
|
||||||
}
|
|
||||||
pub fn flags_and_attributes(&mut self, val: u32) {
|
pub fn custom_flags(&mut self, flags: u32) { self.custom_flags = flags; }
|
||||||
self.flags_and_attributes = Some(val);
|
pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); }
|
||||||
}
|
pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; }
|
||||||
pub fn desired_access(&mut self, val: u32) {
|
pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; }
|
||||||
self.desired_access = Some(val);
|
pub fn security_qos_flags(&mut self, flags: u32) { self.security_qos_flags = flags; }
|
||||||
}
|
|
||||||
pub fn share_mode(&mut self, val: u32) {
|
|
||||||
self.share_mode = Some(val);
|
|
||||||
}
|
|
||||||
pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
|
pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
|
||||||
self.security_attributes = attrs as usize;
|
self.security_attributes = attrs as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_desired_access(&self) -> c::DWORD {
|
fn get_access_mode(&self) -> io::Result<c::DWORD> {
|
||||||
self.desired_access.unwrap_or({
|
const ERROR_INVALID_PARAMETER: i32 = 87;
|
||||||
let mut base = if self.read {c::FILE_GENERIC_READ} else {0} |
|
|
||||||
if self.write {c::FILE_GENERIC_WRITE} else {0};
|
match (self.read, self.write, self.append, self.access_mode) {
|
||||||
if self.append {
|
(_, _, _, Some(mode)) => Ok(mode),
|
||||||
base &= !c::FILE_WRITE_DATA;
|
(true, false, false, None) => Ok(c::GENERIC_READ),
|
||||||
base |= c::FILE_APPEND_DATA;
|
(false, true, false, None) => Ok(c::GENERIC_WRITE),
|
||||||
}
|
(true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
|
||||||
base
|
(false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA),
|
||||||
})
|
(true, _, true, None) => Ok(c::GENERIC_READ |
|
||||||
|
(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)),
|
||||||
|
(false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_share_mode(&self) -> c::DWORD {
|
fn get_creation_mode(&self) -> io::Result<c::DWORD> {
|
||||||
// libuv has a good comment about this, but the basic idea is that
|
const ERROR_INVALID_PARAMETER: i32 = 87;
|
||||||
// we try to emulate unix semantics by enabling all sharing by
|
|
||||||
// allowing things such as deleting a file while it's still open.
|
|
||||||
self.share_mode.unwrap_or(c::FILE_SHARE_READ |
|
|
||||||
c::FILE_SHARE_WRITE |
|
|
||||||
c::FILE_SHARE_DELETE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_creation_disposition(&self) -> c::DWORD {
|
match (self.write, self.append) {
|
||||||
self.creation_disposition.unwrap_or({
|
(true, false) => {}
|
||||||
match (self.create, self.truncate) {
|
(false, false) =>
|
||||||
(true, true) => c::CREATE_ALWAYS,
|
if self.truncate || self.create || self.create_new {
|
||||||
(true, false) => c::OPEN_ALWAYS,
|
return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
|
||||||
(false, false) => c::OPEN_EXISTING,
|
},
|
||||||
(false, true) => {
|
(_, true) =>
|
||||||
if self.write && !self.append {
|
if self.truncate && !self.create_new {
|
||||||
c::CREATE_ALWAYS
|
return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
|
||||||
} else {
|
},
|
||||||
c::TRUNCATE_EXISTING
|
}
|
||||||
}
|
|
||||||
}
|
Ok(match (self.create, self.truncate, self.create_new) {
|
||||||
}
|
(false, false, false) => c::OPEN_EXISTING,
|
||||||
})
|
(true, false, false) => c::OPEN_ALWAYS,
|
||||||
|
(false, true, false) => c::TRUNCATE_EXISTING,
|
||||||
|
(true, true, false) => c::CREATE_ALWAYS,
|
||||||
|
(_, _, true) => c::CREATE_NEW,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_flags_and_attributes(&self) -> c::DWORD {
|
fn get_flags_and_attributes(&self) -> c::DWORD {
|
||||||
self.flags_and_attributes.unwrap_or(c::FILE_ATTRIBUTE_NORMAL)
|
self.custom_flags |
|
||||||
|
self.attributes |
|
||||||
|
self.security_qos_flags |
|
||||||
|
if self.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } |
|
||||||
|
if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,8 +243,8 @@ impl File {
|
|||||||
let mut opts = OpenOptions::new();
|
let mut opts = OpenOptions::new();
|
||||||
opts.read(!write);
|
opts.read(!write);
|
||||||
opts.write(write);
|
opts.write(write);
|
||||||
opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT |
|
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
|
||||||
c::FILE_FLAG_BACKUP_SEMANTICS);
|
c::FILE_FLAG_BACKUP_SEMANTICS);
|
||||||
File::open(path, &opts)
|
File::open(path, &opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,10 +252,10 @@ impl File {
|
|||||||
let path = try!(to_u16s(path));
|
let path = try!(to_u16s(path));
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
c::CreateFileW(path.as_ptr(),
|
c::CreateFileW(path.as_ptr(),
|
||||||
opts.get_desired_access(),
|
try!(opts.get_access_mode()),
|
||||||
opts.get_share_mode(),
|
opts.share_mode,
|
||||||
opts.security_attributes as *mut _,
|
opts.security_attributes as *mut _,
|
||||||
opts.get_creation_disposition(),
|
try!(opts.get_creation_mode()),
|
||||||
opts.get_flags_and_attributes(),
|
opts.get_flags_and_attributes(),
|
||||||
ptr::null_mut())
|
ptr::null_mut())
|
||||||
};
|
};
|
||||||
@ -533,7 +555,10 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
|
|||||||
// metadata information is.
|
// metadata information is.
|
||||||
if attr.is_reparse_point() {
|
if attr.is_reparse_point() {
|
||||||
let mut opts = OpenOptions::new();
|
let mut opts = OpenOptions::new();
|
||||||
opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
|
// No read or write permissions are necessary
|
||||||
|
opts.access_mode(0);
|
||||||
|
// This flag is so we can open directories too
|
||||||
|
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
|
||||||
let file = try!(File::open(p, &opts));
|
let file = try!(File::open(p, &opts));
|
||||||
file.file_attr()
|
file.file_attr()
|
||||||
} else {
|
} else {
|
||||||
@ -577,9 +602,10 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
|
|||||||
|
|
||||||
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
|
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
|
||||||
let mut opts = OpenOptions::new();
|
let mut opts = OpenOptions::new();
|
||||||
opts.read(true);
|
// No read or write permissions are necessary
|
||||||
|
opts.access_mode(0);
|
||||||
// This flag is so we can open directories too
|
// This flag is so we can open directories too
|
||||||
opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
|
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
|
||||||
let f = try!(File::open(p, &opts));
|
let f = try!(File::open(p, &opts));
|
||||||
get_path(&f)
|
get_path(&f)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user