@@ -865,10 +865,37 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
865865}
866866
867867fn get_path ( f : & File ) -> io:: Result < PathBuf > {
868+ get_path_with_flags ( f, c:: VOLUME_NAME_DOS ) . or_else ( |error| {
869+ if error. raw_os_error ( ) == Some ( c:: ERROR_INVALID_FUNCTION as i32 ) {
870+ // This should normally be unreachable. See comment below.
871+ get_path_fallback ( f)
872+ } else {
873+ Err ( error)
874+ }
875+ } )
876+ }
877+
878+ // Unfortunately some third party filesystem drivers don't implement the
879+ // volume manager interface that the kernel requires. This breaks a number of
880+ // things, including resolving the win32 path from a file handle.
881+ //
882+ // To workaround these broken drivers, this function instead gets the NT kernel
883+ // path (which is always available) and then uses the magic win32 prefix
884+ // `\\?\GLOBALROOT` so that the NT path can be used in win32 code.
885+ //
886+ // A downside to this is that it produces weird paths that users may find
887+ // strange.
888+ fn get_path_fallback ( f : & File ) -> io:: Result < PathBuf > {
889+ get_path_with_flags ( f, c:: VOLUME_NAME_NT ) . map ( |nt_path| {
890+ let mut win32_path: OsString = r"\\?\GLOBALROOT" . into ( ) ;
891+ win32_path. push ( nt_path) ;
892+ win32_path. into ( )
893+ } )
894+ }
895+
896+ fn get_path_with_flags ( f : & File , flags : u32 ) -> io:: Result < PathBuf > {
868897 super :: fill_utf16_buf (
869- |buf, sz| unsafe {
870- c:: GetFinalPathNameByHandleW ( f. handle . as_raw_handle ( ) , buf, sz, c:: VOLUME_NAME_DOS )
871- } ,
898+ |buf, sz| unsafe { c:: GetFinalPathNameByHandleW ( f. handle . as_raw_handle ( ) , buf, sz, flags) } ,
872899 |buf| PathBuf :: from ( OsString :: from_wide ( buf) ) ,
873900 )
874901}
0 commit comments