@@ -958,10 +958,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
958
958
return 1 ;
959
959
}
960
960
961
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
962
+ char * tmpbuf , int * plen , DWORD * ptag );
963
+
961
964
int mingw_lstat (const char * file_name , struct stat * buf )
962
965
{
963
966
WIN32_FILE_ATTRIBUTE_DATA fdata ;
964
- WIN32_FIND_DATAW findbuf = { 0 };
967
+ DWORD reparse_tag = 0 ;
968
+ int link_len = 0 ;
965
969
wchar_t wfilename [MAX_LONG_PATH ];
966
970
int wlen = xutftowcs_long_path (wfilename , file_name );
967
971
if (wlen < 0 )
@@ -976,28 +980,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
976
980
}
977
981
978
982
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
979
- /* for reparse points, use FindFirstFile to get the reparse tag */
983
+ /* for reparse points, get the link tag and length */
980
984
if (fdata .dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
981
- HANDLE handle = FindFirstFileW (wfilename , & findbuf );
982
- if (handle == INVALID_HANDLE_VALUE )
983
- goto error ;
984
- FindClose (handle );
985
+ char tmpbuf [MAX_LONG_PATH ];
986
+
987
+ if (readlink_1 (wfilename , FALSE, tmpbuf , & link_len ,
988
+ & reparse_tag ) < 0 )
989
+ return -1 ;
985
990
}
986
991
buf -> st_ino = 0 ;
987
992
buf -> st_gid = 0 ;
988
993
buf -> st_uid = 0 ;
989
994
buf -> st_nlink = 1 ;
990
995
buf -> st_mode = file_attr_to_st_mode (fdata .dwFileAttributes ,
991
- findbuf . dwReserved0 , file_name );
992
- buf -> st_size = S_ISLNK (buf -> st_mode ) ? MAX_LONG_PATH :
996
+ reparse_tag , file_name );
997
+ buf -> st_size = S_ISLNK (buf -> st_mode ) ? link_len :
993
998
fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
994
999
buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
995
1000
filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
996
1001
filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
997
1002
filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
998
1003
return 0 ;
999
1004
}
1000
- error :
1005
+
1001
1006
switch (GetLastError ()) {
1002
1007
case ERROR_ACCESS_DENIED :
1003
1008
case ERROR_SHARING_VIOLATION :
@@ -2923,17 +2928,13 @@ typedef struct _REPARSE_DATA_BUFFER {
2923
2928
} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
2924
2929
#endif
2925
2930
2926
- int readlink (const char * path , char * buf , size_t bufsiz )
2931
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
2932
+ char * tmpbuf , int * plen , DWORD * ptag )
2927
2933
{
2928
2934
HANDLE handle ;
2929
- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2935
+ WCHAR * wbuf ;
2930
2936
REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
2931
2937
DWORD dummy ;
2932
- char tmpbuf [MAX_LONG_PATH ];
2933
- int len ;
2934
-
2935
- if (xutftowcs_long_path (wpath , path ) < 0 )
2936
- return -1 ;
2937
2938
2938
2939
/* read reparse point data */
2939
2940
handle = CreateFileW (wpath , 0 ,
@@ -2953,7 +2954,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2953
2954
CloseHandle (handle );
2954
2955
2955
2956
/* get target path for symlinks or mount points (aka 'junctions') */
2956
- switch (b -> ReparseTag ) {
2957
+ switch (( * ptag = b -> ReparseTag ) ) {
2957
2958
case IO_REPARSE_TAG_SYMLINK :
2958
2959
wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
2959
2960
+ b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -2967,19 +2968,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
2967
2968
+ b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
2968
2969
break ;
2969
2970
default :
2970
- errno = EINVAL ;
2971
- return -1 ;
2971
+ if (fail_on_unknown_tag ) {
2972
+ errno = EINVAL ;
2973
+ return -1 ;
2974
+ } else {
2975
+ * plen = MAX_LONG_PATH ;
2976
+ return 0 ;
2977
+ }
2972
2978
}
2973
2979
2980
+ if ((* plen =
2981
+ xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2982
+ return -1 ;
2983
+ return 0 ;
2984
+ }
2985
+
2986
+ int readlink (const char * path , char * buf , size_t bufsiz )
2987
+ {
2988
+ WCHAR wpath [MAX_LONG_PATH ];
2989
+ char tmpbuf [MAX_LONG_PATH ];
2990
+ int len ;
2991
+ DWORD tag ;
2992
+
2993
+ if (xutftowcs_long_path (wpath , path ) < 0 )
2994
+ return -1 ;
2995
+
2996
+ if (readlink_1 (wpath , TRUE, tmpbuf , & len , & tag ) < 0 )
2997
+ return -1 ;
2998
+
2974
2999
/*
2975
3000
* Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
2976
3001
* cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
2977
3002
* condition. There is no conversion function that produces invalid UTF-8,
2978
3003
* so convert to a (hopefully large enough) temporary buffer, then memcpy
2979
3004
* the requested number of bytes (including '\0' for robustness).
2980
3005
*/
2981
- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2982
- return -1 ;
2983
3006
memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
2984
3007
return min (bufsiz , len );
2985
3008
}
0 commit comments