File tree 3 files changed +30
-2
lines changed
library/std/src/sys/windows
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;
83
83
pub const FILE_ATTRIBUTE_READONLY : DWORD = 0x1 ;
84
84
pub const FILE_ATTRIBUTE_DIRECTORY : DWORD = 0x10 ;
85
85
pub const FILE_ATTRIBUTE_REPARSE_POINT : DWORD = 0x400 ;
86
+ pub const INVALID_FILE_ATTRIBUTES : DWORD = DWORD :: MAX ;
86
87
87
88
pub const FILE_SHARE_DELETE : DWORD = 0x4 ;
88
89
pub const FILE_SHARE_READ : DWORD = 0x1 ;
@@ -1075,6 +1076,7 @@ extern "system" {
1075
1076
lpBuffer : LPWSTR ,
1076
1077
lpFilePart : * mut LPWSTR ,
1077
1078
) -> DWORD ;
1079
+ pub fn GetFileAttributesW ( lpFileName : LPCWSTR ) -> DWORD ;
1078
1080
}
1079
1081
1080
1082
#[ link( name = "ws2_32" ) ]
Original file line number Diff line number Diff line change @@ -394,7 +394,7 @@ fn resolve_exe<'a>(
394
394
395
395
// Append `.exe` if not already there.
396
396
path = path:: append_suffix ( path, EXE_SUFFIX . as_ref ( ) ) ;
397
- if path . try_exists ( ) . unwrap_or ( false ) {
397
+ if program_exists ( & path ) {
398
398
return Ok ( path) ;
399
399
} else {
400
400
// It's ok to use `set_extension` here because the intent is to
@@ -415,7 +415,7 @@ fn resolve_exe<'a>(
415
415
if !has_extension {
416
416
path. set_extension ( EXE_EXTENSION ) ;
417
417
}
418
- if let Ok ( true ) = path. try_exists ( ) { Some ( path) } else { None }
418
+ if program_exists ( & path) { Some ( path) } else { None }
419
419
} ) ;
420
420
if let Some ( path) = result {
421
421
return Ok ( path) ;
@@ -485,6 +485,21 @@ where
485
485
None
486
486
}
487
487
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
+
488
503
impl Stdio {
489
504
fn to_handle ( & self , stdio_id : c:: DWORD , pipe : & mut Option < AnonPipe > ) -> io:: Result < Handle > {
490
505
match * self {
Original file line number Diff line number Diff line change @@ -135,6 +135,8 @@ fn windows_env_unicode_case() {
135
135
fn windows_exe_resolver ( ) {
136
136
use super :: resolve_exe;
137
137
use crate :: io;
138
+ use crate :: sys:: fs:: symlink;
139
+ use crate :: sys_common:: io:: test:: tmpdir;
138
140
139
141
let env_paths = || env:: var_os ( "PATH" ) ;
140
142
@@ -178,4 +180,13 @@ fn windows_exe_resolver() {
178
180
// The application's directory is also searched.
179
181
let current_exe = env:: current_exe ( ) . unwrap ( ) ;
180
182
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( ) ) ;
181
192
}
You can’t perform that action at this time.
0 commit comments