mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Add FileIoErr::AlreadyExists + some Windows fixes
This commit is contained in:
parent
f6016c1009
commit
2fe1604652
2 changed files with 51 additions and 12 deletions
|
@ -1,11 +1,11 @@
|
||||||
use crate::native_path::NativePath;
|
use crate::native_path::NativePath;
|
||||||
use core::{ffi::CStr, fmt, mem::MaybeUninit};
|
use core::{fmt, mem::MaybeUninit};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use widestring::U16CString;
|
use widestring::U16CStr;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use core::ffi::{c_char, c_int};
|
use core::ffi::{c_char, c_int, CStr};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
|
@ -96,6 +96,14 @@ pub enum FileIoErr {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
/// ERROR_ACCESS_DENIED: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
/// ERROR_ACCESS_DENIED: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||||
AccessDenied = 5,
|
AccessDenied = 5,
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
/// EEXIST: https://www.man7.org/linux/man-pages/man3/errno.3.html
|
||||||
|
AlreadyExists = 17,
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
/// ERROR_FILE_EXISTS: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||||
|
AlreadyExists = 80,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FileIoErr {
|
impl fmt::Debug for FileIoErr {
|
||||||
|
@ -106,6 +114,7 @@ impl fmt::Debug for FileIoErr {
|
||||||
FileIoErr::AccessDenied => write!(f, "AccessDenied ({})", *self as i32),
|
FileIoErr::AccessDenied => write!(f, "AccessDenied ({})", *self as i32),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
FileIoErr::AccessDenied => write!(f, "AccessDenied ({})", *self as i32),
|
FileIoErr::AccessDenied => write!(f, "AccessDenied ({})", *self as i32),
|
||||||
|
FileIoErr::AlreadyExists => write!(f, "AlreadyExists ({})", *self as i32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,16 +135,16 @@ impl FileIoErr {
|
||||||
fn __errno_location() -> *mut FileIoErr;
|
fn __errno_location() -> *mut FileIoErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { errno = *__errno_location() }
|
unsafe { *__errno_location() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn most_recent() -> FileIoErr {
|
fn most_recent() -> FileIoErr {
|
||||||
extern "system" {
|
extern "system" {
|
||||||
fn GetLastError() -> u32;
|
fn GetLastError() -> FileIoErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { FileIoErr(GetLastError()) }
|
unsafe { GetLastError() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,9 +191,13 @@ impl File {
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
impl File {
|
impl File {
|
||||||
|
const GENERIC_READ: u32 = 0x80000000;
|
||||||
const GENERIC_WRITE: u32 = 0x40000000;
|
const GENERIC_WRITE: u32 = 0x40000000;
|
||||||
|
const FILE_SHARE_READ: u32 = 1;
|
||||||
|
const FILE_SHARE_WRITE: u32 = 2;
|
||||||
|
const CREATE_NEW: u32 = 1;
|
||||||
const CREATE_ALWAYS: u32 = 2;
|
const CREATE_ALWAYS: u32 = 2;
|
||||||
const FILE_SHARE_WRITE: u32 = 0x00000002;
|
const OPEN_EXISTING: u32 = 3;
|
||||||
|
|
||||||
pub fn open(path: &NativePath) -> Result<Self, FileIoErr> {
|
pub fn open(path: &NativePath) -> Result<Self, FileIoErr> {
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
|
@ -202,7 +215,7 @@ impl File {
|
||||||
if handle != -1 {
|
if handle != -1 {
|
||||||
Ok(File { handle })
|
Ok(File { handle })
|
||||||
} else {
|
} else {
|
||||||
Err(FileIoErr::errno())
|
Err(FileIoErr::most_recent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +235,7 @@ impl File {
|
||||||
if handle != -1 {
|
if handle != -1 {
|
||||||
Ok(File { handle })
|
Ok(File { handle })
|
||||||
} else {
|
} else {
|
||||||
Err(FileIoErr::errno())
|
Err(FileIoErr::most_recent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,7 +464,7 @@ mod tests {
|
||||||
use core::ffi::CStr;
|
use core::ffi::CStr;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use widestring::U16CString;
|
use widestring::U16CStr;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn str_to_cstr(s: &str) -> &CStr {
|
fn str_to_cstr(s: &str) -> &CStr {
|
||||||
|
@ -556,4 +569,30 @@ mod tests {
|
||||||
"Data read from the file does not match data written to the file"
|
"Data read from the file does not match data written to the file"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_file_that_already_exists() {
|
||||||
|
let path = mock_path("roc_test_already_exists\0");
|
||||||
|
|
||||||
|
// Create the file for the first time
|
||||||
|
let file_result = File::create(path);
|
||||||
|
assert!(
|
||||||
|
file_result.is_ok(),
|
||||||
|
"Failed to create the file: roc_test_already_exists"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Attempt to create the same file again
|
||||||
|
let file_result = File::create(path);
|
||||||
|
assert_eq!(
|
||||||
|
file_result.map(|_| ()),
|
||||||
|
Err(FileIoErr::AlreadyExists),
|
||||||
|
"File should already exist: roc_test_already_exists"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the file now that we're done with it
|
||||||
|
assert!(
|
||||||
|
File::remove(path),
|
||||||
|
"Failed to remove the file: roc_test_already_exists"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,8 @@ impl<'a> From<&'a CStr> for &'a NativePath {
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
impl<'a> From<&'a U16CStr> for &'a NativePath {
|
impl<'a> From<&'a U16CStr> for &'a NativePath {
|
||||||
fn from(inner: &'a U16CStr) -> Self {
|
fn from(u16_c_str: &'a U16CStr) -> Self {
|
||||||
// Safety: Self is repr(transparent)
|
// Safety: Self is repr(transparent)
|
||||||
unsafe { mem::transmute(c_str) }
|
unsafe { mem::transmute(u16_c_str) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue