@@ -969,10 +969,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
969969 return 1 ;
970970}
971971
972+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
973+ char * tmpbuf , int * plen , DWORD * ptag );
974+
972975int mingw_lstat (const char * file_name , struct stat * buf )
973976{
974977 WIN32_FILE_ATTRIBUTE_DATA fdata ;
975- WIN32_FIND_DATAW findbuf = { 0 };
978+ DWORD reparse_tag = 0 ;
979+ int link_len = 0 ;
976980 wchar_t wfilename [MAX_LONG_PATH ];
977981 int wlen = xutftowcs_long_path (wfilename , file_name );
978982 if (wlen < 0 )
@@ -987,28 +991,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
987991 }
988992
989993 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 */
991995 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 ;
9961001 }
9971002 buf -> st_ino = 0 ;
9981003 buf -> st_gid = 0 ;
9991004 buf -> st_uid = 0 ;
10001005 buf -> st_nlink = 1 ;
10011006 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 :
10041009 fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
10051010 buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
10061011 filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
10071012 filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
10081013 filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
10091014 return 0 ;
10101015 }
1011- error :
1016+
10121017 switch (GetLastError ()) {
10131018 case ERROR_ACCESS_DENIED :
10141019 case ERROR_SHARING_VIOLATION :
@@ -2968,17 +2973,13 @@ typedef struct _REPARSE_DATA_BUFFER {
29682973} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
29692974#endif
29702975
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 )
29722978{
29732979 HANDLE handle ;
2974- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2980+ WCHAR * wbuf ;
29752981 REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
29762982 DWORD dummy ;
2977- char tmpbuf [MAX_LONG_PATH ];
2978- int len ;
2979-
2980- if (xutftowcs_long_path (wpath , path ) < 0 )
2981- return -1 ;
29822983
29832984 /* read reparse point data */
29842985 handle = CreateFileW (wpath , 0 ,
@@ -2998,7 +2999,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
29982999 CloseHandle (handle );
29993000
30003001 /* get target path for symlinks or mount points (aka 'junctions') */
3001- switch (b -> ReparseTag ) {
3002+ switch (( * ptag = b -> ReparseTag ) ) {
30023003 case IO_REPARSE_TAG_SYMLINK :
30033004 wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
30043005 + b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -3012,19 +3013,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
30123013 + b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
30133014 break ;
30143015 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+ }
30173023 }
30183024
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+
30193044 /*
30203045 * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
30213046 * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
30223047 * condition. There is no conversion function that produces invalid UTF-8,
30233048 * so convert to a (hopefully large enough) temporary buffer, then memcpy
30243049 * the requested number of bytes (including '\0' for robustness).
30253050 */
3026- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
3027- return -1 ;
30283051 memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
30293052 return min (bufsiz , len );
30303053}
0 commit comments