@@ -865,10 +865,37 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
865
865
}
866
866
867
867
fn 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 > {
868
897
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) } ,
872
899
|buf| PathBuf :: from ( OsString :: from_wide ( buf) ) ,
873
900
)
874
901
}
0 commit comments