@@ -12,7 +12,7 @@ use crate::sync::Arc;
1212use crate :: sys:: handle:: Handle ;
1313use crate :: sys:: pal:: api:: { self , WinError , set_file_information_by_handle} ;
1414use crate :: sys:: pal:: { IoResult , fill_utf16_buf, to_u16s, truncate_utf16_at_nul} ;
15- use crate :: sys:: path:: maybe_verbatim;
15+ use crate :: sys:: path:: { WCStr , maybe_verbatim} ;
1616use crate :: sys:: time:: SystemTime ;
1717use crate :: sys:: { Align8 , c, cvt} ;
1818use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
@@ -298,10 +298,12 @@ impl OpenOptions {
298298impl File {
299299 pub fn open ( path : & Path , opts : & OpenOptions ) -> io:: Result < File > {
300300 let path = maybe_verbatim ( path) ?;
301+ // SAFETY: maybe_verbatim returns null-terminated strings
302+ let path = unsafe { WCStr :: from_wchars_with_null_unchecked ( & path) } ;
301303 Self :: open_native ( & path, opts)
302304 }
303305
304- fn open_native ( path : & [ u16 ] , opts : & OpenOptions ) -> io:: Result < File > {
306+ fn open_native ( path : & WCStr , opts : & OpenOptions ) -> io:: Result < File > {
305307 let creation = opts. get_creation_mode ( ) ?;
306308 let handle = unsafe {
307309 c:: CreateFileW (
@@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
12121214 }
12131215}
12141216
1215- pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
1216- let p_u16s = maybe_verbatim ( p) ?;
1217- if unsafe { c:: DeleteFileW ( p_u16s. as_ptr ( ) ) } == 0 {
1217+ pub fn unlink ( path : & WCStr ) -> io:: Result < ( ) > {
1218+ if unsafe { c:: DeleteFileW ( path. as_ptr ( ) ) } == 0 {
12181219 let err = api:: get_last_error ( ) ;
12191220 // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove
12201221 // the file while ignoring the readonly attribute.
@@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
12231224 let mut opts = OpenOptions :: new ( ) ;
12241225 opts. access_mode ( c:: DELETE ) ;
12251226 opts. custom_flags ( c:: FILE_FLAG_OPEN_REPARSE_POINT ) ;
1226- if let Ok ( f) = File :: open_native ( & p_u16s , & opts) {
1227+ if let Ok ( f) = File :: open_native ( & path , & opts) {
12271228 if f. posix_delete ( ) . is_ok ( ) {
12281229 return Ok ( ( ) ) ;
12291230 }
@@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
12361237 }
12371238}
12381239
1239- pub fn rename ( old : & Path , new : & Path ) -> io:: Result < ( ) > {
1240- let old = maybe_verbatim ( old) ?;
1241- let new = maybe_verbatim ( new) ?;
1242-
1240+ pub fn rename ( old : & WCStr , new : & WCStr ) -> io:: Result < ( ) > {
12431241 if unsafe { c:: MoveFileExW ( old. as_ptr ( ) , new. as_ptr ( ) , c:: MOVEFILE_REPLACE_EXISTING ) } == 0 {
12441242 let err = api:: get_last_error ( ) ;
12451243 // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
@@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
12531251
12541252 // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
12551253 // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
1256- let Ok ( new_len_without_nul_in_bytes) : Result < u32 , _ > = ( ( new. len ( ) - 1 ) * 2 ) . try_into ( )
1254+ let Ok ( new_len_without_nul_in_bytes) : Result < u32 , _ > =
1255+ ( ( new. count_bytes ( ) - 1 ) * 2 ) . try_into ( )
12571256 else {
12581257 return Err ( err) . io_result ( ) ;
12591258 } ;
@@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
12821281
12831282 new. as_ptr ( ) . copy_to_nonoverlapping (
12841283 ( & raw mut ( * file_rename_info) . FileName ) . cast :: < u16 > ( ) ,
1285- new. len ( ) ,
1284+ new. count_bytes ( ) ,
12861285 ) ;
12871286 }
12881287
@@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
13091308 Ok ( ( ) )
13101309}
13111310
1312- pub fn rmdir ( p : & Path ) -> io:: Result < ( ) > {
1313- let p = maybe_verbatim ( p) ?;
1311+ pub fn rmdir ( p : & WCStr ) -> io:: Result < ( ) > {
13141312 cvt ( unsafe { c:: RemoveDirectoryW ( p. as_ptr ( ) ) } ) ?;
13151313 Ok ( ( ) )
13161314}
13171315
1318- pub fn remove_dir_all ( path : & Path ) -> io:: Result < ( ) > {
1316+ pub fn remove_dir_all ( path : & WCStr ) -> io:: Result < ( ) > {
13191317 // Open a file or directory without following symlinks.
13201318 let mut opts = OpenOptions :: new ( ) ;
13211319 opts. access_mode ( c:: FILE_LIST_DIRECTORY ) ;
13221320 // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
13231321 // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
13241322 opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS | c:: FILE_FLAG_OPEN_REPARSE_POINT ) ;
1325- let file = File :: open ( path, & opts) ?;
1323+ let file = File :: open_native ( path, & opts) ?;
13261324
13271325 // Test if the file is not a directory or a symlink to a directory.
13281326 if ( file. basic_info ( ) ?. FileAttributes & c:: FILE_ATTRIBUTE_DIRECTORY ) == 0 {
@@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
13331331 remove_dir_all_iterative ( file) . io_result ( )
13341332}
13351333
1336- pub fn readlink ( path : & Path ) -> io:: Result < PathBuf > {
1334+ pub fn readlink ( path : & WCStr ) -> io:: Result < PathBuf > {
13371335 // Open the link with no access mode, instead of generic read.
13381336 // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
13391337 // this is needed for a common case.
13401338 let mut opts = OpenOptions :: new ( ) ;
13411339 opts. access_mode ( 0 ) ;
13421340 opts. custom_flags ( c:: FILE_FLAG_OPEN_REPARSE_POINT | c:: FILE_FLAG_BACKUP_SEMANTICS ) ;
1343- let file = File :: open ( path, & opts) ?;
1341+ let file = File :: open_native ( & path, & opts) ?;
13441342 file. readlink ( )
13451343}
13461344
@@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()>
13781376}
13791377
13801378#[ cfg( not( target_vendor = "uwp" ) ) ]
1381- pub fn link ( original : & Path , link : & Path ) -> io:: Result < ( ) > {
1382- let original = maybe_verbatim ( original) ?;
1383- let link = maybe_verbatim ( link) ?;
1379+ pub fn link ( original : & WCStr , link : & WCStr ) -> io:: Result < ( ) > {
13841380 cvt ( unsafe { c:: CreateHardLinkW ( link. as_ptr ( ) , original. as_ptr ( ) , ptr:: null_mut ( ) ) } ) ?;
13851381 Ok ( ( ) )
13861382}
13871383
13881384#[ cfg( target_vendor = "uwp" ) ]
1389- pub fn link ( _original : & Path , _link : & Path ) -> io:: Result < ( ) > {
1385+ pub fn link ( _original : & WCStr , _link : & WCStr ) -> io:: Result < ( ) > {
13901386 return Err ( io:: const_error!( io:: ErrorKind :: Unsupported , "hard link are not supported on UWP" ) ) ;
13911387}
13921388
1393- pub fn stat ( path : & Path ) -> io:: Result < FileAttr > {
1389+ pub fn stat ( path : & WCStr ) -> io:: Result < FileAttr > {
13941390 match metadata ( path, ReparsePoint :: Follow ) {
13951391 Err ( err) if err. raw_os_error ( ) == Some ( c:: ERROR_CANT_ACCESS_FILE as i32 ) => {
13961392 if let Ok ( attrs) = lstat ( path) {
@@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result<FileAttr> {
14041400 }
14051401}
14061402
1407- pub fn lstat ( path : & Path ) -> io:: Result < FileAttr > {
1403+ pub fn lstat ( path : & WCStr ) -> io:: Result < FileAttr > {
14081404 metadata ( path, ReparsePoint :: Open )
14091405}
14101406
@@ -1420,7 +1416,7 @@ impl ReparsePoint {
14201416 }
14211417}
14221418
1423- fn metadata ( path : & Path , reparse : ReparsePoint ) -> io:: Result < FileAttr > {
1419+ fn metadata ( path : & WCStr , reparse : ReparsePoint ) -> io:: Result < FileAttr > {
14241420 let mut opts = OpenOptions :: new ( ) ;
14251421 // No read or write permissions are necessary
14261422 opts. access_mode ( 0 ) ;
@@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
14291425 // Attempt to open the file normally.
14301426 // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`.
14311427 // If the fallback fails for any reason we return the original error.
1432- match File :: open ( path, & opts) {
1428+ match File :: open_native ( & path, & opts) {
14331429 Ok ( file) => file. file_attr ( ) ,
14341430 Err ( e)
14351431 if [ Some ( c:: ERROR_SHARING_VIOLATION as _ ) , Some ( c:: ERROR_ACCESS_DENIED as _ ) ]
@@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
14421438 // However, there are special system files, such as
14431439 // `C:\hiberfil.sys`, that are locked in a way that denies even that.
14441440 unsafe {
1445- let path = maybe_verbatim ( path) ?;
1446-
14471441 // `FindFirstFileExW` accepts wildcard file names.
14481442 // Fortunately wildcards are not valid file names and
14491443 // `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
@@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
14821476 }
14831477}
14841478
1485- pub fn set_perm ( p : & Path , perm : FilePermissions ) -> io:: Result < ( ) > {
1486- let p = maybe_verbatim ( p) ?;
1479+ pub fn set_perm ( p : & WCStr , perm : FilePermissions ) -> io:: Result < ( ) > {
14871480 unsafe {
14881481 cvt ( c:: SetFileAttributesW ( p. as_ptr ( ) , perm. attrs ) ) ?;
14891482 Ok ( ( ) )
@@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
14991492 )
15001493}
15011494
1502- pub fn canonicalize ( p : & Path ) -> io:: Result < PathBuf > {
1495+ pub fn canonicalize ( p : & WCStr ) -> io:: Result < PathBuf > {
15031496 let mut opts = OpenOptions :: new ( ) ;
15041497 // No read or write permissions are necessary
15051498 opts. access_mode ( 0 ) ;
15061499 // This flag is so we can open directories too
15071500 opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS ) ;
1508- let f = File :: open ( p, & opts) ?;
1501+ let f = File :: open_native ( p, & opts) ?;
15091502 get_path ( & f)
15101503}
15111504
1512- pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
1505+ pub fn copy ( from : & WCStr , to : & WCStr ) -> io:: Result < u64 > {
15131506 unsafe extern "system" fn callback (
15141507 _TotalFileSize : i64 ,
15151508 _TotalBytesTransferred : i64 ,
@@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
15281521 c:: PROGRESS_CONTINUE
15291522 }
15301523 }
1531- let pfrom = maybe_verbatim ( from) ?;
1532- let pto = maybe_verbatim ( to) ?;
15331524 let mut size = 0i64 ;
15341525 cvt ( unsafe {
15351526 c:: CopyFileExW (
1536- pfrom . as_ptr ( ) ,
1537- pto . as_ptr ( ) ,
1527+ from . as_ptr ( ) ,
1528+ to . as_ptr ( ) ,
15381529 Some ( callback) ,
15391530 ( & raw mut size) as * mut _ ,
15401531 ptr:: null_mut ( ) ,
@@ -1624,14 +1615,14 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
16241615}
16251616
16261617// Try to see if a file exists but, unlike `exists`, report I/O errors.
1627- pub fn exists ( path : & Path ) -> io:: Result < bool > {
1618+ pub fn exists ( path : & WCStr ) -> io:: Result < bool > {
16281619 // Open the file to ensure any symlinks are followed to their target.
16291620 let mut opts = OpenOptions :: new ( ) ;
16301621 // No read, write, etc access rights are needed.
16311622 opts. access_mode ( 0 ) ;
16321623 // Backup semantics enables opening directories as well as files.
16331624 opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS ) ;
1634- match File :: open ( path, & opts) {
1625+ match File :: open_native ( path, & opts) {
16351626 Err ( e) => match e. kind ( ) {
16361627 // The file definitely does not exist
16371628 io:: ErrorKind :: NotFound => Ok ( false ) ,
0 commit comments