File tree Expand file tree Collapse file tree 3 files changed +30
-2
lines changed
library/std/src/sys/windows Expand file tree Collapse file tree 3 files changed +30
-2
lines changed Original file line number Diff line number Diff line change @@ -83,6 +83,7 @@ pub const CSTR_GREATER_THAN: c_int = 3;
8383pub const FILE_ATTRIBUTE_READONLY : DWORD = 0x1 ;
8484pub const FILE_ATTRIBUTE_DIRECTORY : DWORD = 0x10 ;
8585pub const FILE_ATTRIBUTE_REPARSE_POINT : DWORD = 0x400 ;
86+ pub const INVALID_FILE_ATTRIBUTES : DWORD = DWORD :: MAX ;
8687
8788pub const FILE_SHARE_DELETE : DWORD = 0x4 ;
8889pub const FILE_SHARE_READ : DWORD = 0x1 ;
@@ -1075,6 +1076,7 @@ extern "system" {
10751076 lpBuffer : LPWSTR ,
10761077 lpFilePart : * mut LPWSTR ,
10771078 ) -> DWORD ;
1079+ pub fn GetFileAttributesW ( lpFileName : LPCWSTR ) -> DWORD ;
10781080}
10791081
10801082#[ link( name = "ws2_32" ) ]
Original file line number Diff line number Diff line change @@ -394,7 +394,7 @@ fn resolve_exe<'a>(
394394
395395 // Append `.exe` if not already there.
396396 path = path:: append_suffix ( path, EXE_SUFFIX . as_ref ( ) ) ;
397- if path . try_exists ( ) . unwrap_or ( false ) {
397+ if program_exists ( & path ) {
398398 return Ok ( path) ;
399399 } else {
400400 // It's ok to use `set_extension` here because the intent is to
@@ -415,7 +415,7 @@ fn resolve_exe<'a>(
415415 if !has_extension {
416416 path. set_extension ( EXE_EXTENSION ) ;
417417 }
418- if let Ok ( true ) = path. try_exists ( ) { Some ( path) } else { None }
418+ if program_exists ( & path) { Some ( path) } else { None }
419419 } ) ;
420420 if let Some ( path) = result {
421421 return Ok ( path) ;
@@ -485,6 +485,21 @@ where
485485 None
486486}
487487
488+ /// Check if a file exists without following symlinks.
489+ fn program_exists ( path : & Path ) -> bool {
490+ unsafe {
491+ to_u16s ( path)
492+ . map ( |path| {
493+ // Getting attributes using `GetFileAttributesW` does not follow symlinks
494+ // and it will almost always be successful if the link exists.
495+ // There are some exceptions for special system files (e.g. the pagefile)
496+ // but these are not executable.
497+ c:: GetFileAttributesW ( path. as_ptr ( ) ) != c:: INVALID_FILE_ATTRIBUTES
498+ } )
499+ . unwrap_or ( false )
500+ }
501+ }
502+
488503impl Stdio {
489504 fn to_handle ( & self , stdio_id : c:: DWORD , pipe : & mut Option < AnonPipe > ) -> io:: Result < Handle > {
490505 match * self {
Original file line number Diff line number Diff line change @@ -135,6 +135,8 @@ fn windows_env_unicode_case() {
135135fn windows_exe_resolver ( ) {
136136 use super :: resolve_exe;
137137 use crate :: io;
138+ use crate :: sys:: fs:: symlink;
139+ use crate :: sys_common:: io:: test:: tmpdir;
138140
139141 let env_paths = || env:: var_os ( "PATH" ) ;
140142
@@ -178,4 +180,13 @@ fn windows_exe_resolver() {
178180 // The application's directory is also searched.
179181 let current_exe = env:: current_exe ( ) . unwrap ( ) ;
180182 assert ! ( resolve_exe( current_exe. file_name( ) . unwrap( ) . as_ref( ) , empty_paths, None ) . is_ok( ) ) ;
183+
184+ // Create a temporary path and add a broken symlink.
185+ let temp = tmpdir ( ) ;
186+ let mut exe_path = temp. path ( ) . to_owned ( ) ;
187+ exe_path. push ( "exists.exe" ) ;
188+ symlink ( "<DOES NOT EXIST>" . as_ref ( ) , & exe_path) . unwrap ( ) ;
189+
190+ // A broken symlink should still be resolved.
191+ assert ! ( resolve_exe( OsStr :: new( "exists.exe" ) , empty_paths, Some ( temp. path( ) . as_ref( ) ) ) . is_ok( ) ) ;
181192}
You can’t perform that action at this time.
0 commit comments