@@ -907,10 +907,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
907
907
return 1 ;
908
908
}
909
909
910
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
911
+ char * tmpbuf , int * plen , DWORD * ptag );
912
+
910
913
int mingw_lstat (const char * file_name , struct stat * buf )
911
914
{
912
915
WIN32_FILE_ATTRIBUTE_DATA fdata ;
913
- WIN32_FIND_DATAW findbuf = { 0 };
916
+ DWORD reparse_tag = 0 ;
917
+ int link_len = 0 ;
914
918
wchar_t wfilename [MAX_LONG_PATH ];
915
919
int wlen = xutftowcs_long_path (wfilename , file_name );
916
920
if (wlen < 0 )
@@ -925,28 +929,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
925
929
}
926
930
927
931
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
928
- /* for reparse points, use FindFirstFile to get the reparse tag */
932
+ /* for reparse points, get the link tag and length */
929
933
if (fdata .dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
930
- HANDLE handle = FindFirstFileW (wfilename , & findbuf );
931
- if (handle == INVALID_HANDLE_VALUE )
932
- goto error ;
933
- FindClose (handle );
934
+ char tmpbuf [MAX_LONG_PATH ];
935
+
936
+ if (readlink_1 (wfilename , FALSE, tmpbuf , & link_len ,
937
+ & reparse_tag ) < 0 )
938
+ return -1 ;
934
939
}
935
940
buf -> st_ino = 0 ;
936
941
buf -> st_gid = 0 ;
937
942
buf -> st_uid = 0 ;
938
943
buf -> st_nlink = 1 ;
939
944
buf -> st_mode = file_attr_to_st_mode (fdata .dwFileAttributes ,
940
- findbuf . dwReserved0 , file_name );
941
- buf -> st_size = S_ISLNK (buf -> st_mode ) ? MAX_LONG_PATH :
945
+ reparse_tag , file_name );
946
+ buf -> st_size = S_ISLNK (buf -> st_mode ) ? link_len :
942
947
fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
943
948
buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
944
949
filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
945
950
filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
946
951
filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
947
952
return 0 ;
948
953
}
949
- error :
954
+
950
955
switch (GetLastError ()) {
951
956
case ERROR_ACCESS_DENIED :
952
957
case ERROR_SHARING_VIOLATION :
@@ -2783,17 +2788,13 @@ typedef struct _REPARSE_DATA_BUFFER {
2783
2788
} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
2784
2789
#endif
2785
2790
2786
- int readlink (const char * path , char * buf , size_t bufsiz )
2791
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
2792
+ char * tmpbuf , int * plen , DWORD * ptag )
2787
2793
{
2788
2794
HANDLE handle ;
2789
- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2795
+ WCHAR * wbuf ;
2790
2796
REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
2791
2797
DWORD dummy ;
2792
- char tmpbuf [MAX_LONG_PATH ];
2793
- int len ;
2794
-
2795
- if (xutftowcs_long_path (wpath , path ) < 0 )
2796
- return -1 ;
2797
2798
2798
2799
/* read reparse point data */
2799
2800
handle = CreateFileW (wpath , 0 ,
@@ -2813,7 +2814,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2813
2814
CloseHandle (handle );
2814
2815
2815
2816
/* get target path for symlinks or mount points (aka 'junctions') */
2816
- switch (b -> ReparseTag ) {
2817
+ switch (( * ptag = b -> ReparseTag ) ) {
2817
2818
case IO_REPARSE_TAG_SYMLINK :
2818
2819
wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
2819
2820
+ b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -2827,19 +2828,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2827
2828
+ b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
2828
2829
break ;
2829
2830
default :
2830
- errno = EINVAL ;
2831
- return -1 ;
2831
+ if (fail_on_unknown_tag ) {
2832
+ errno = EINVAL ;
2833
+ return -1 ;
2834
+ } else {
2835
+ * plen = MAX_LONG_PATH ;
2836
+ return 0 ;
2837
+ }
2832
2838
}
2833
2839
2840
+ if ((* plen =
2841
+ xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2842
+ return -1 ;
2843
+ return 0 ;
2844
+ }
2845
+
2846
+ int readlink (const char * path , char * buf , size_t bufsiz )
2847
+ {
2848
+ WCHAR wpath [MAX_LONG_PATH ];
2849
+ char tmpbuf [MAX_LONG_PATH ];
2850
+ int len ;
2851
+ DWORD tag ;
2852
+
2853
+ if (xutftowcs_long_path (wpath , path ) < 0 )
2854
+ return -1 ;
2855
+
2856
+ if (readlink_1 (wpath , TRUE, tmpbuf , & len , & tag ) < 0 )
2857
+ return -1 ;
2858
+
2834
2859
/*
2835
2860
* Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
2836
2861
* cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
2837
2862
* condition. There is no conversion function that produces invalid UTF-8,
2838
2863
* so convert to a (hopefully large enough) temporary buffer, then memcpy
2839
2864
* the requested number of bytes (including '\0' for robustness).
2840
2865
*/
2841
- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2842
- return -1 ;
2843
2866
memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
2844
2867
return min (bufsiz , len );
2845
2868
}
0 commit comments