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