Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fb4e8d3

Browse files
committed
add windows implementation
1 parent bf718d8 commit fb4e8d3

File tree

1 file changed

+218
-4
lines changed

1 file changed

+218
-4
lines changed

‎library/std/src/sys/fs/windows.rs

Lines changed: 218 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::os::windows::io::{AsHandle, BorrowedHandle};
1010
use crate::os::windows::prelude::*;
1111
use crate::path::{Path, PathBuf};
1212
use crate::sync::Arc;
13+
use crate::sys::api::SetFileInformation;
1314
use crate::sys::handle::Handle;
1415
use crate::sys::pal::api::{self, WinError, set_file_information_by_handle};
1516
use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul};
@@ -26,6 +27,10 @@ pub struct File {
2627
handle: Handle,
2728
}
2829

30+
pub struct Dir {
31+
handle: Handle,
32+
}
33+
2934
#[derive(Clone)]
3035
pub struct FileAttr {
3136
attributes: u32,
@@ -846,6 +851,215 @@ impl File {
846851
}
847852
}
848853

854+
unsafe fn nt_create_file(
855+
access: u32,
856+
object_attributes: &c::OBJECT_ATTRIBUTES,
857+
share: u32,
858+
dir: bool,
859+
) -> Result<Handle, WinError> {
860+
let mut handle = ptr::null_mut();
861+
let mut io_status = c::IO_STATUS_BLOCK::PENDING;
862+
let disposition = match (access & c::GENERIC_READ > 0, access & c::GENERIC_WRITE > 0) {
863+
(true, true) => c::FILE_OPEN_IF,
864+
(true, false) => c::FILE_OPEN,
865+
(false, true) => c::FILE_CREATE,
866+
(false, false) => {
867+
return Err(WinError::new(c::ERROR_INVALID_PARAMETER));
868+
}
869+
};
870+
let status = unsafe {
871+
c::NtCreateFile(
872+
&mut handle,
873+
access,
874+
object_attributes,
875+
&mut io_status,
876+
ptr::null(),
877+
c::FILE_ATTRIBUTE_NORMAL,
878+
share,
879+
disposition,
880+
if dir { c::FILE_DIRECTORY_FILE } else { c::FILE_NON_DIRECTORY_FILE },
881+
ptr::null(),
882+
0,
883+
)
884+
};
885+
if c::nt_success(status) {
886+
// SAFETY: nt_success guarantees that handle is no longer null
887+
unsafe { Ok(Handle::from_raw_handle(handle)) }
888+
} else {
889+
let win_error = if status == c::STATUS_DELETE_PENDING {
890+
// We make a special exception for `STATUS_DELETE_PENDING` because
891+
// otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is
892+
// very unhelpful because that can also mean a permission error.
893+
WinError::DELETE_PENDING
894+
} else {
895+
WinError::new(unsafe { c::RtlNtStatusToDosError(status) })
896+
};
897+
Err(win_error)
898+
}
899+
}
900+
901+
fn run_path_with_wcstr<T, P: AsRef<Path>>(
902+
path: P,
903+
f: &dyn Fn(&WCStr) -> io::Result<T>,
904+
) -> io::Result<T> {
905+
let path = maybe_verbatim(path.as_ref())?;
906+
// SAFETY: maybe_verbatim returns null-terminated strings
907+
let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) };
908+
f(path)
909+
}
910+
911+
impl Dir {
912+
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
913+
let opts = OpenOptions::new();
914+
run_path_with_wcstr(path, &|path| Self::new_native(path, &opts))
915+
}
916+
917+
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
918+
run_path_with_wcstr(path, &|path| Self::new_native(path, &opts))
919+
}
920+
921+
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
922+
let mut opts = OpenOptions::new();
923+
opts.read(true);
924+
Ok(File { handle: run_path_with_wcstr(path, &|path| self.open_native(path, &opts))? })
925+
}
926+
927+
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
928+
Ok(File { handle: run_path_with_wcstr(path, &|path| self.open_native(path, &opts))? })
929+
}
930+
931+
pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
932+
run_path_with_wcstr(path, &|path| {
933+
self.create_dir_native(path, &OpenOptions::new()).map(|_| ())
934+
})
935+
}
936+
937+
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
938+
run_path_with_wcstr(path, &|path| self.remove_native(path, false))
939+
}
940+
941+
pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
942+
run_path_with_wcstr(path, &|path| self.remove_native(path, true))
943+
}
944+
945+
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(
946+
&self,
947+
from: P,
948+
to_dir: &Self,
949+
to: Q,
950+
) -> io::Result<()> {
951+
run_path_with_wcstr(from.as_ref(), &|from| run_path_with_wcstr(to.as_ref(), &|to| panic!()))
952+
}
953+
954+
fn new_native(path: &WCStr, opts: &OpenOptions) -> io::Result<Self> {
955+
let name = c::UNICODE_STRING {
956+
Length: path.count_bytes() as _,
957+
MaximumLength: path.count_bytes() as _,
958+
Buffer: path.as_ptr() as *mut _,
959+
};
960+
let object_attributes = c::OBJECT_ATTRIBUTES {
961+
Length: size_of::<c::OBJECT_ATTRIBUTES>() as _,
962+
RootDirectory: ptr::null_mut(),
963+
ObjectName: &name,
964+
Attributes: 0,
965+
SecurityDescriptor: ptr::null(),
966+
SecurityQualityOfService: ptr::null(),
967+
};
968+
let share = c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE;
969+
let handle =
970+
unsafe { nt_create_file(opts.get_access_mode()?, &object_attributes, share, true) }
971+
.io_result()?;
972+
Ok(Self { handle })
973+
}
974+
975+
fn open_native(&self, path: &WCStr, opts: &OpenOptions) -> io::Result<Handle> {
976+
let name = c::UNICODE_STRING {
977+
Length: path.count_bytes() as _,
978+
MaximumLength: path.count_bytes() as _,
979+
Buffer: path.as_ptr() as *mut _,
980+
};
981+
let object_attributes = c::OBJECT_ATTRIBUTES {
982+
Length: size_of::<c::OBJECT_ATTRIBUTES>() as _,
983+
RootDirectory: self.handle.as_raw_handle(),
984+
ObjectName: &name,
985+
Attributes: 0,
986+
SecurityDescriptor: ptr::null(),
987+
SecurityQualityOfService: ptr::null(),
988+
};
989+
let share = c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE;
990+
unsafe { nt_create_file(opts.get_access_mode()?, &object_attributes, share, false) }
991+
.io_result()
992+
}
993+
994+
fn create_dir_native(&self, path: &WCStr, opts: &OpenOptions) -> io::Result<Handle> {
995+
let name = c::UNICODE_STRING {
996+
Length: path.count_bytes() as _,
997+
MaximumLength: path.count_bytes() as _,
998+
Buffer: path.as_ptr() as *mut _,
999+
};
1000+
let object_attributes = c::OBJECT_ATTRIBUTES {
1001+
Length: size_of::<c::OBJECT_ATTRIBUTES>() as _,
1002+
RootDirectory: self.handle.as_raw_handle(),
1003+
ObjectName: &name,
1004+
Attributes: 0,
1005+
SecurityDescriptor: ptr::null(),
1006+
SecurityQualityOfService: ptr::null(),
1007+
};
1008+
let share = c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE;
1009+
unsafe { nt_create_file(opts.get_access_mode()?, &object_attributes, share, true) }
1010+
.io_result()
1011+
}
1012+
1013+
fn remove_native(&self, path: &WCStr, dir: bool) -> io::Result<()> {
1014+
let mut opts = OpenOptions::new();
1015+
opts.access_mode(c::GENERIC_WRITE);
1016+
let handle =
1017+
if dir { self.create_dir_native(path, &opts) } else { self.open_native(path, &opts) }?;
1018+
let info = c::FILE_DISPOSITION_INFO_EX { Flags: c::FILE_DISPOSITION_FLAG_DELETE };
1019+
let result = unsafe {
1020+
c::SetFileInformationByHandle(
1021+
handle.as_raw_handle(),
1022+
c::FileDispositionInfoEx,
1023+
(&info).as_ptr(),
1024+
size_of::<c::FILE_DISPOSITION_INFO_EX>() as _,
1025+
)
1026+
};
1027+
if result == 0 { Err(api::get_last_error()).io_result() } else { Ok(()) }
1028+
}
1029+
1030+
fn rename_native(&self, from: &WCStr, to_dir: &Self, to: &WCStr) -> io::Result<()> {
1031+
let mut opts = OpenOptions::new();
1032+
opts.access_mode(c::GENERIC_WRITE);
1033+
let handle = self.open_native(from, &opts)?;
1034+
let info = c::FILE_RENAME_INFO {
1035+
Anonymous: c::FILE_RENAME_INFO_0 { ReplaceIfExists: true },
1036+
RootDirectory: to_dir.handle.as_raw_handle(),
1037+
FileNameLength: to.count_bytes() as _,
1038+
FileName: [to.as_ptr() as u16],
1039+
};
1040+
let result = unsafe {
1041+
c::SetFileInformationByHandle(
1042+
handle.as_raw_handle(),
1043+
c::FileRenameInfo,
1044+
ptr::addr_of!(info) as _,
1045+
size_of::<c::FILE_RENAME_INFO>() as _,
1046+
)
1047+
};
1048+
if result == 0 { Err(api::get_last_error()).io_result() } else { Ok(()) }
1049+
}
1050+
}
1051+
1052+
impl fmt::Debug for Dir {
1053+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1054+
let mut b = f.debug_struct("Dir");
1055+
b.field("handle", &self.handle.as_raw_handle());
1056+
if let Ok(path) = get_path(self.handle.as_handle()) {
1057+
b.field("path", &path);
1058+
}
1059+
b.finish()
1060+
}
1061+
}
1062+
8491063
/// A buffer for holding directory entries.
8501064
struct DirBuff {
8511065
buffer: Box<Align8<[MaybeUninit<u8>; Self::BUFFER_SIZE]>>,
@@ -995,7 +1209,7 @@ impl fmt::Debug for File {
9951209
// FIXME(#24570): add more info here (e.g., mode)
9961210
let mut b = f.debug_struct("File");
9971211
b.field("handle", &self.handle.as_raw_handle());
998-
if let Ok(path) = get_path(self) {
1212+
if let Ok(path) = get_path(self.handle.as_handle()) {
9991213
b.field("path", &path);
10001214
}
10011215
b.finish()
@@ -1484,10 +1698,10 @@ pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> {
14841698
}
14851699
}
14861700

1487-
fn get_path(f: &File) -> io::Result<PathBuf> {
1701+
fn get_path(f: implAsRawHandle) -> io::Result<PathBuf> {
14881702
fill_utf16_buf(
14891703
|buf, sz| unsafe {
1490-
c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS)
1704+
c::GetFinalPathNameByHandleW(f.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS)
14911705
},
14921706
|buf| PathBuf::from(OsString::from_wide(buf)),
14931707
)
@@ -1500,7 +1714,7 @@ pub fn canonicalize(p: &WCStr) -> io::Result<PathBuf> {
15001714
// This flag is so we can open directories too
15011715
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
15021716
let f = File::open_native(p, &opts)?;
1503-
get_path(&f)
1717+
get_path(f.handle)
15041718
}
15051719

15061720
pub fn copy(from: &WCStr, to: &WCStr) -> io::Result<u64> {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /