@@ -958,10 +958,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
958958 return 1 ;
959959}
960960
961+ static int readlink_1 (const WCHAR * wpath , BOOL fail_on_unknown_tag ,
962+ char * tmpbuf , int * plen , DWORD * ptag );
963+
961964int mingw_lstat (const char * file_name , struct stat * buf )
962965{
963966 WIN32_FILE_ATTRIBUTE_DATA fdata ;
964- WIN32_FIND_DATAW findbuf = { 0 };
967+ DWORD reparse_tag = 0 ;
968+ int link_len = 0 ;
965969 wchar_t wfilename [MAX_LONG_PATH ];
966970 int wlen = xutftowcs_long_path (wfilename , file_name );
967971 if (wlen < 0 )
@@ -976,28 +980,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
976980 }
977981
978982 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 */
980984 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 ;
985990 }
986991 buf -> st_ino = 0 ;
987992 buf -> st_gid = 0 ;
988993 buf -> st_uid = 0 ;
989994 buf -> st_nlink = 1 ;
990995 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 :
993998 fdata .nFileSizeLow | (((off_t ) fdata .nFileSizeHigh ) << 32 );
994999 buf -> st_dev = buf -> st_rdev = 0 ; /* not used by Git */
9951000 filetime_to_timespec (& (fdata .ftLastAccessTime ), & (buf -> st_atim ));
9961001 filetime_to_timespec (& (fdata .ftLastWriteTime ), & (buf -> st_mtim ));
9971002 filetime_to_timespec (& (fdata .ftCreationTime ), & (buf -> st_ctim ));
9981003 return 0 ;
9991004 }
1000- error :
1005+
10011006 switch (GetLastError ()) {
10021007 case ERROR_ACCESS_DENIED :
10031008 case ERROR_SHARING_VIOLATION :
@@ -2923,17 +2928,13 @@ typedef struct _REPARSE_DATA_BUFFER {
29232928} REPARSE_DATA_BUFFER , * PREPARSE_DATA_BUFFER ;
29242929#endif
29252930
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 )
29272933{
29282934 HANDLE handle ;
2929- WCHAR wpath [ MAX_LONG_PATH ], * wbuf ;
2935+ WCHAR * wbuf ;
29302936 REPARSE_DATA_BUFFER * b = alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
29312937 DWORD dummy ;
2932- char tmpbuf [MAX_LONG_PATH ];
2933- int len ;
2934-
2935- if (xutftowcs_long_path (wpath , path ) < 0 )
2936- return -1 ;
29372938
29382939 /* read reparse point data */
29392940 handle = CreateFileW (wpath , 0 ,
@@ -2953,7 +2954,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
29532954 CloseHandle (handle );
29542955
29552956 /* get target path for symlinks or mount points (aka 'junctions') */
2956- switch (b -> ReparseTag ) {
2957+ switch (( * ptag = b -> ReparseTag ) ) {
29572958 case IO_REPARSE_TAG_SYMLINK :
29582959 wbuf = (WCHAR * ) (((char * ) b -> SymbolicLinkReparseBuffer .PathBuffer )
29592960 + b -> SymbolicLinkReparseBuffer .SubstituteNameOffset );
@@ -2967,19 +2968,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
29672968 + b -> MountPointReparseBuffer .SubstituteNameLength ) = 0 ;
29682969 break ;
29692970 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+ }
29722978 }
29732979
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+
29742999 /*
29753000 * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
29763001 * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
29773002 * condition. There is no conversion function that produces invalid UTF-8,
29783003 * so convert to a (hopefully large enough) temporary buffer, then memcpy
29793004 * the requested number of bytes (including '\0' for robustness).
29803005 */
2981- if ((len = xwcstoutf (tmpbuf , normalize_ntpath (wbuf ), MAX_LONG_PATH )) < 0 )
2982- return -1 ;
29833006 memcpy (buf , tmpbuf , min (bufsiz , len + 1 ));
29843007 return min (bufsiz , len );
29853008}
0 commit comments