@@ -920,10 +920,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
920
920
return 1 ;
921
921
}
922
922
923
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
924
+ char * tmpbuf , int * plen , DWORD * ptag );
925
+
923
926
int mingw_lstat (const char * file_name , struct stat * buf )
924
927
{
925
928
WIN32_FILE_ATTRIBUTE_DATA fdata ;
926
- WIN32_FIND_DATAW findbuf = { 0 };
929
+ DWORD reparse_tag = 0 ;
930
+ int link_len = 0 ;
927
931
wchar_t wfilename [MAX_LONG_PATH ];
928
932
int wlen = xutftowcs_long_path (wfilename , file_name );
929
933
if (wlen < 0 )
@@ -938,28 +942,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
938
942
}
939
943
940
944
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
941
- /* for reparse points, use FindFirstFile to get the reparse tag */
945
+ /* for reparse points, get the link tag and length */
942
946
if (fdata .dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
943
- HANDLE handle = FindFirstFileW (wfilename , & findbuf );
944
- if (handle == INVALID_HANDLE_VALUE )
945
- goto error ;
946
- FindClose (handle );
947
+ char tmpbuf [MAX_LONG_PATH ];
948
+
949
+ if (readlink_1 (wfilename , FALSE, tmpbuf , & link_len ,
950
+ & reparse_tag ) < 0 )
951
+ return -1 ;
947
952
}
948
953
buf -> st_ino = 0 ;
949
954
buf -> st_gid = 0 ;
950
955
buf -> st_uid = 0 ;
951
956
buf -> st_nlink = 1 ;
952
957
buf -> st_mode = file_attr_to_st_mode (fdata .dwFileAttributes ,
953
- findbuf . dwReserved0 , file_name );
954
- buf -> st_size = S_ISLNK (buf -> st_mode ) ? MAX_LONG_PATH :
958
+ reparse_tag , file_name );
959
+ buf -> st_size = S_ISLNK (buf -> st_mode ) ? link_len :
955
960
fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
956
961
buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
957
962
filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
958
963
filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
959
964
filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
960
965
return 0 ;
961
966
}
962
- error :
967
+
963
968
switch (GetLastError ()) {
964
969
case ERROR_ACCESS_DENIED :
965
970
case ERROR_SHARING_VIOLATION :
@@ -2831,17 +2836,13 @@ typedef struct _REPARSE_DATA_BUFFER {
2831
2836
} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
2832
2837
#endif
2833
2838
2834
- int readlink (const char * path , char * buf , size_t bufsiz )
2839
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
2840
+ char * tmpbuf , int * plen , DWORD * ptag )
2835
2841
{
2836
2842
HANDLE handle ;
2837
- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2843
+ WCHAR * wbuf ;
2838
2844
REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
2839
2845
DWORD dummy ;
2840
- char tmpbuf [MAX_LONG_PATH ];
2841
- int len ;
2842
-
2843
- if (xutftowcs_long_path (wpath , path ) < 0 )
2844
- return -1 ;
2845
2846
2846
2847
/* read reparse point data */
2847
2848
handle = CreateFileW (wpath , 0 ,
@@ -2861,7 +2862,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2861
2862
CloseHandle (handle );
2862
2863
2863
2864
/* get target path for symlinks or mount points (aka 'junctions') */
2864
- switch (b -> ReparseTag ) {
2865
+ switch (( * ptag = b -> ReparseTag ) ) {
2865
2866
case IO_REPARSE_TAG_SYMLINK :
2866
2867
wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
2867
2868
+ b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -2875,19 +2876,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2875
2876
+ b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
2876
2877
break ;
2877
2878
default :
2878
- errno = EINVAL ;
2879
- return -1 ;
2879
+ if (fail_on_unknown_tag ) {
2880
+ errno = EINVAL ;
2881
+ return -1 ;
2882
+ } else {
2883
+ * plen = MAX_LONG_PATH ;
2884
+ return 0 ;
2885
+ }
2880
2886
}
2881
2887
2888
+ if ((* plen =
2889
+ xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2890
+ return -1 ;
2891
+ return 0 ;
2892
+ }
2893
+
2894
+ int readlink (const char * path , char * buf , size_t bufsiz )
2895
+ {
2896
+ WCHAR wpath [MAX_LONG_PATH ];
2897
+ char tmpbuf [MAX_LONG_PATH ];
2898
+ int len ;
2899
+ DWORD tag ;
2900
+
2901
+ if (xutftowcs_long_path (wpath , path ) < 0 )
2902
+ return -1 ;
2903
+
2904
+ if (readlink_1 (wpath , TRUE, tmpbuf , & len , & tag ) < 0 )
2905
+ return -1 ;
2906
+
2882
2907
/*
2883
2908
* Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
2884
2909
* cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
2885
2910
* condition. There is no conversion function that produces invalid UTF-8,
2886
2911
* so convert to a (hopefully large enough) temporary buffer, then memcpy
2887
2912
* the requested number of bytes (including '\0' for robustness).
2888
2913
*/
2889
- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2890
- return -1 ;
2891
2914
memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
2892
2915
return min (bufsiz , len );
2893
2916
}
0 commit comments