@@ -971,10 +971,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
971
971
return 1 ;
972
972
}
973
973
974
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
975
+ char * tmpbuf , int * plen , DWORD * ptag );
976
+
974
977
int mingw_lstat (const char * file_name , struct stat * buf )
975
978
{
976
979
WIN32_FILE_ATTRIBUTE_DATA fdata ;
977
- WIN32_FIND_DATAW findbuf = { 0 };
980
+ DWORD reparse_tag = 0 ;
981
+ int link_len = 0 ;
978
982
wchar_t wfilename [MAX_LONG_PATH ];
979
983
int wlen = xutftowcs_long_path (wfilename , file_name );
980
984
if (wlen < 0 )
@@ -989,28 +993,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
989
993
}
990
994
991
995
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
992
- /* for reparse points, use FindFirstFile to get the reparse tag */
996
+ /* for reparse points, get the link tag and length */
993
997
if (fdata .dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
994
- HANDLE handle = FindFirstFileW (wfilename , & findbuf );
995
- if (handle == INVALID_HANDLE_VALUE )
996
- goto error ;
997
- FindClose (handle );
998
+ char tmpbuf [MAX_LONG_PATH ];
999
+
1000
+ if (readlink_1 (wfilename , FALSE, tmpbuf , & link_len ,
1001
+ & reparse_tag ) < 0 )
1002
+ return -1 ;
998
1003
}
999
1004
buf -> st_ino = 0 ;
1000
1005
buf -> st_gid = 0 ;
1001
1006
buf -> st_uid = 0 ;
1002
1007
buf -> st_nlink = 1 ;
1003
1008
buf -> st_mode = file_attr_to_st_mode (fdata .dwFileAttributes ,
1004
- findbuf . dwReserved0 , file_name );
1005
- buf -> st_size = S_ISLNK (buf -> st_mode ) ? MAX_LONG_PATH :
1009
+ reparse_tag , file_name );
1010
+ buf -> st_size = S_ISLNK (buf -> st_mode ) ? link_len :
1006
1011
fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
1007
1012
buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
1008
1013
filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
1009
1014
filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
1010
1015
filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
1011
1016
return 0 ;
1012
1017
}
1013
- error :
1018
+
1014
1019
switch (GetLastError ()) {
1015
1020
case ERROR_ACCESS_DENIED :
1016
1021
case ERROR_SHARING_VIOLATION :
@@ -2971,17 +2976,13 @@ typedef struct _REPARSE_DATA_BUFFER {
2971
2976
} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
2972
2977
#endif
2973
2978
2974
- int readlink (const char * path , char * buf , size_t bufsiz )
2979
+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
2980
+ char * tmpbuf , int * plen , DWORD * ptag )
2975
2981
{
2976
2982
HANDLE handle ;
2977
- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2983
+ WCHAR * wbuf ;
2978
2984
REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
2979
2985
DWORD dummy ;
2980
- char tmpbuf [MAX_LONG_PATH ];
2981
- int len ;
2982
-
2983
- if (xutftowcs_long_path (wpath , path ) < 0 )
2984
- return -1 ;
2985
2986
2986
2987
/* read reparse point data */
2987
2988
handle = CreateFileW (wpath , 0 ,
@@ -3001,7 +3002,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
3001
3002
CloseHandle (handle );
3002
3003
3003
3004
/* get target path for symlinks or mount points (aka 'junctions') */
3004
- switch (b -> ReparseTag ) {
3005
+ switch (( * ptag = b -> ReparseTag ) ) {
3005
3006
case IO_REPARSE_TAG_SYMLINK :
3006
3007
wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
3007
3008
+ b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -3015,19 +3016,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
3015
3016
+ b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
3016
3017
break ;
3017
3018
default :
3018
- errno = EINVAL ;
3019
- return -1 ;
3019
+ if (fail_on_unknown_tag ) {
3020
+ errno = EINVAL ;
3021
+ return -1 ;
3022
+ } else {
3023
+ * plen = MAX_LONG_PATH ;
3024
+ return 0 ;
3025
+ }
3020
3026
}
3021
3027
3028
+ if ((* plen =
3029
+ xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
3030
+ return -1 ;
3031
+ return 0 ;
3032
+ }
3033
+
3034
+ int readlink (const char * path , char * buf , size_t bufsiz )
3035
+ {
3036
+ WCHAR wpath [MAX_LONG_PATH ];
3037
+ char tmpbuf [MAX_LONG_PATH ];
3038
+ int len ;
3039
+ DWORD tag ;
3040
+
3041
+ if (xutftowcs_long_path (wpath , path ) < 0 )
3042
+ return -1 ;
3043
+
3044
+ if (readlink_1 (wpath , TRUE, tmpbuf , & len , & tag ) < 0 )
3045
+ return -1 ;
3046
+
3022
3047
/*
3023
3048
* Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
3024
3049
* cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
3025
3050
* condition. There is no conversion function that produces invalid UTF-8,
3026
3051
* so convert to a (hopefully large enough) temporary buffer, then memcpy
3027
3052
* the requested number of bytes (including '\0' for robustness).
3028
3053
*/
3029
- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
3030
- return -1 ;
3031
3054
memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
3032
3055
return min (bufsiz , len );
3033
3056
}
0 commit comments