Skip to content

Commit 6a2bf58

Browse files
dschoGit for Windows Build Agent
authored and
Git for Windows Build Agent
committed
Merge pull request #2637 from billziss-gh/master
mingw: lstat: compute correct size for symlinks
2 parents 0e9265c + 79f11dc commit 6a2bf58

File tree

1 file changed

+44
-21
lines changed

1 file changed

+44
-21
lines changed

compat/mingw.c

+44-21
Original file line numberDiff line numberDiff line change
@@ -971,10 +971,14 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
971971
return 1;
972972
}
973973

974+
static int readlink_1(const WCHAR *wpath, BOOL fail_on_unknown_tag,
975+
char *tmpbuf, int *plen, DWORD *ptag);
976+
974977
int mingw_lstat(const char *file_name, struct stat *buf)
975978
{
976979
WIN32_FILE_ATTRIBUTE_DATA fdata;
977-
WIN32_FIND_DATAW findbuf = { 0 };
980+
DWORD reparse_tag = 0;
981+
int link_len = 0;
978982
wchar_t wfilename[MAX_LONG_PATH];
979983
int wlen = xutftowcs_long_path(wfilename, file_name);
980984
if (wlen < 0)
@@ -989,28 +993,29 @@ int mingw_lstat(const char *file_name, struct stat *buf)
989993
}
990994

991995
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 */
993997
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;
9981003
}
9991004
buf->st_ino = 0;
10001005
buf->st_gid = 0;
10011006
buf->st_uid = 0;
10021007
buf->st_nlink = 1;
10031008
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 :
10061011
fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
10071012
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
10081013
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
10091014
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
10101015
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
10111016
return 0;
10121017
}
1013-
error:
1018+
10141019
switch (GetLastError()) {
10151020
case ERROR_ACCESS_DENIED:
10161021
case ERROR_SHARING_VIOLATION:
@@ -2971,17 +2976,13 @@ typedef struct _REPARSE_DATA_BUFFER {
29712976
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
29722977
#endif
29732978

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)
29752981
{
29762982
HANDLE handle;
2977-
WCHAR wpath[MAX_LONG_PATH], *wbuf;
2983+
WCHAR *wbuf;
29782984
REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
29792985
DWORD dummy;
2980-
char tmpbuf[MAX_LONG_PATH];
2981-
int len;
2982-
2983-
if (xutftowcs_long_path(wpath, path) < 0)
2984-
return -1;
29852986

29862987
/* read reparse point data */
29872988
handle = CreateFileW(wpath, 0,
@@ -3001,7 +3002,7 @@ int readlink(const char *path, char *buf, size_t bufsiz)
30013002
CloseHandle(handle);
30023003

30033004
/* get target path for symlinks or mount points (aka 'junctions') */
3004-
switch (b->ReparseTag) {
3005+
switch ((*ptag = b->ReparseTag)) {
30053006
case IO_REPARSE_TAG_SYMLINK:
30063007
wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer)
30073008
+ b->SymbolicLinkReparseBuffer.SubstituteNameOffset);
@@ -3015,19 +3016,41 @@ int readlink(const char *path, char *buf, size_t bufsiz)
30153016
+ b->MountPointReparseBuffer.SubstituteNameLength) = 0;
30163017
break;
30173018
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+
}
30203026
}
30213027

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+
30223047
/*
30233048
* Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially
30243049
* cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure
30253050
* condition. There is no conversion function that produces invalid UTF-8,
30263051
* so convert to a (hopefully large enough) temporary buffer, then memcpy
30273052
* the requested number of bytes (including '\0' for robustness).
30283053
*/
3029-
if ((len = xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_LONG_PATH)) < 0)
3030-
return -1;
30313054
memcpy(buf, tmpbuf, min(bufsiz, len + 1));
30323055
return min(bufsiz, len);
30333056
}

0 commit comments

Comments
 (0)