Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,10 @@ impl OpenOptions {
/// See also [`std::fs::write()`][self::write] for a simple function to
/// create a file with some given data.
///
/// # Errors
///
/// If `.create(true)` is set without `.write(true)` or `.append(true)`,
/// calling [`open`](Self::open) will fail with [`InvalidInput`](io::ErrorKind::InvalidInput) error.
/// # Examples
///
/// ```no_run
Expand Down Expand Up @@ -1685,7 +1689,8 @@ impl OpenOptions {
/// * [`AlreadyExists`]: `create_new` was specified and the file already
/// exists.
/// * [`InvalidInput`]: Invalid combinations of open options (truncate
/// without write access, no access mode set, etc.).
/// without write access, create without write or append access,
/// no access mode set, etc.).
///
/// The following errors don't match any existing [`io::ErrorKind`] at the moment:
/// * One of the directory components of the specified file path
Expand Down
56 changes: 41 additions & 15 deletions library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1265,12 +1265,7 @@ fn open_flavors() {
let mut ra = OO::new();
ra.read(true).append(true);

#[cfg(windows)]
let invalid_options = 87; // ERROR_INVALID_PARAMETER
#[cfg(all(unix, not(target_os = "vxworks")))]
let invalid_options = "Invalid argument";
#[cfg(target_os = "vxworks")]
let invalid_options = "invalid argument";
let invalid_options = "creating or truncating a file requires write or append access";

// Test various combinations of creation modes and access modes.
//
Expand All @@ -1293,10 +1288,10 @@ fn open_flavors() {
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);
error_contains!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
error_contains!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
error_contains!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
error_contains!(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
Expand All @@ -1308,21 +1303,21 @@ fn open_flavors() {

// append
check!(c(&a).create_new(true).open(&tmpdir.join("d")));
error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
error_contains!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
error_contains!(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")));

// read-append
check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
error_contains!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
error_contains!(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")));

// Test opening a file without setting an access mode
let mut blank = OO::new();
error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
error_contains!(blank.create(true).open(&tmpdir.join("f")), invalid_options);

// Test write works
check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
Expand Down Expand Up @@ -2084,3 +2079,34 @@ fn test_rename_junction() {
// Junction links are always absolute so we just check the file name is correct.
assert_eq!(fs::read_link(&dest).unwrap().file_name(), Some(not_exist.as_os_str()));
}

#[test]
fn test_open_options_invalid_combinations() {
use crate::fs::OpenOptions as OO;

let test_cases: &[(fn() -> OO, &str)] = &[
(|| OO::new().create(true).read(true).clone(), "create without write"),
(|| OO::new().create_new(true).read(true).clone(), "create_new without write"),
(|| OO::new().truncate(true).read(true).clone(), "truncate without write"),
(|| OO::new().truncate(true).append(true).clone(), "truncate with append"),
];

for (make_opts, desc) in test_cases {
let opts = make_opts();
let result = opts.open("nonexistent.txt");
assert!(result.is_err(), "{desc} should fail");
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput, "{desc} - wrong error kind");
assert_eq!(
err.to_string(),
"creating or truncating a file requires write or append access",
"{desc} - wrong error message"
);
}

let result = OO::new().open("nonexistent.txt");
assert!(result.is_err(), "no access mode should fail");
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
assert_eq!(err.to_string(), "must specify at least one of read, write, or append access");
}
26 changes: 23 additions & 3 deletions library/std/src/sys/fs/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,21 @@ impl OpenOptions {
(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)),
(false, false, false) => {
// If no access mode is set, check if any creation flags are set
// to provide a more descriptive error message
if self.create || self.create_new || self.truncate {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
))
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"must specify at least one of read, write, or append access",
))
}
}
}
}

Expand All @@ -1132,12 +1146,18 @@ impl OpenOptions {
(true, false) => {}
(false, false) => {
if self.truncate || self.create || self.create_new {
return Err(Error::from_raw_os_error(libc::EINVAL));
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
));
}
}
(_, true) => {
if self.truncate && !self.create_new {
return Err(Error::from_raw_os_error(libc::EINVAL));
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
));
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions library/std/src/sys/fs/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,19 @@ impl OpenOptions {
Ok(c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA))
}
(false, false, false, None) => {
Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32))
// If no access mode is set, check if any creation flags are set
// to provide a more descriptive error message
if self.create || self.create_new || self.truncate {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
))
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"must specify at least one of read, write, or append access",
))
}
}
}
}
Expand All @@ -268,12 +280,18 @@ impl OpenOptions {
(true, false) => {}
(false, false) => {
if self.truncate || self.create || self.create_new {
return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32));
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
));
}
}
(_, true) => {
if self.truncate && !self.create_new {
return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32));
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"creating or truncating a file requires write or append access",
));
}
}
}
Expand Down
24 changes: 18 additions & 6 deletions library/std/src/sys/process/windows/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::{Arg, make_command_line};
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;
use crate::os::windows::io::AsHandle;
use crate::process::{Command, Stdio};

#[test]
fn test_raw_args() {
Expand Down Expand Up @@ -29,19 +30,30 @@ fn test_thread_handle() {
use crate::os::windows::process::{ChildExt, CommandExt};
const CREATE_SUSPENDED: u32 = 0x00000004;

let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
let p = Command::new("whoami").stdout(Stdio::null()).creation_flags(CREATE_SUSPENDED).spawn();
assert!(p.is_ok());
let mut p = p.unwrap();

// Ensure the process is killed in the event something goes wrong.
struct DropGuard(crate::process::Child);
impl Drop for DropGuard {
fn drop(&mut self) {
let _ = self.0.kill();
}
}
let mut p = DropGuard(p.unwrap());
let p = &mut p.0;

unsafe extern "system" {
fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
unsafe fn ResumeThread(hHandle: BorrowedHandle<'_>) -> u32;
unsafe fn WaitForSingleObject(hHandle: BorrowedHandle<'_>, dwMilliseconds: u32) -> u32;
}
unsafe {
ResumeThread(p.main_thread_handle());
// Wait until the process exits or 1 minute passes.
// We don't bother checking the result here as that's done below using `try_wait`.
WaitForSingleObject(p.as_handle(), 1000 * 60);
}

crate::thread::sleep(crate::time::Duration::from_millis(100));

let res = p.try_wait();
assert!(res.is_ok());
assert!(res.unwrap().is_some());
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dependencies": {
"browser-ui-test": "^0.21.1",
"browser-ui-test": "^0.21.3",
"es-check": "^6.2.1",
"eslint": "^8.57.1",
"eslint-js": "github:eslint/js",
Expand Down
6 changes: 5 additions & 1 deletion src/bootstrap/src/utils/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ mod inner {
impl TracingGuard {
pub fn copy_to_dir(self, dir: &std::path::Path) {
drop(self.guard);
std::fs::rename(&self.chrome_tracing_path, dir.join("chrome-trace.json")).unwrap();
crate::utils::helpers::move_file(
&self.chrome_tracing_path,
dir.join("chrome-trace.json"),
)
.unwrap();
}
}

Expand Down
Loading