21
#define SECURITY_WIN32
22
#include <sspi.h>
23
#include <wchar.h>
24
+#include <winioctl.h>
25
#include <winternl.h>
26
27
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056)
918
return 1;
919
}
920
921
+#ifndef _WINNT_H
922
+/*
923
+ * The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in
924
+ * ntifs.h) and in MSYS1's winnt.h (which defines _WINNT_H). So define
925
+ * it ourselves if we are on MSYS2 (whose winnt.h defines _WINNT_).
926
+ */
927
+typedef struct _REPARSE_DATA_BUFFER {
928
+ DWORD ReparseTag;
929
+ WORD ReparseDataLength;
930
+ WORD Reserved;
931
+#ifndef _MSC_VER
932
+ _ANONYMOUS_UNION
933
+#endif
934
+ union {
935
+ struct {
936
+ WORD SubstituteNameOffset;
937
+ WORD SubstituteNameLength;
938
+ WORD PrintNameOffset;
939
+ WORD PrintNameLength;
940
+ ULONG Flags;
941
+ WCHAR PathBuffer[1];
942
+ } SymbolicLinkReparseBuffer;
943
+ struct {
944
+ WORD SubstituteNameOffset;
945
+ WORD SubstituteNameLength;
946
+ WORD PrintNameOffset;
947
+ WORD PrintNameLength;
948
+ WCHAR PathBuffer[1];
949
+ } MountPointReparseBuffer;
950
+ struct {
951
+ BYTE DataBuffer[1];
952
+ } GenericReparseBuffer;
953
+ } DUMMYUNIONNAME;
954
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
955
+#endif
956
+
957
+static int read_reparse_point(const WCHAR *wpath, BOOL fail_on_unknown_tag,
958
+ char *tmpbuf, int *plen, DWORD *ptag)
959
+{
960
+ HANDLE handle;
961
+ WCHAR *wbuf;
962
+ REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
963
+ DWORD dummy;
964
+
965
+ /* read reparse point data */
966
+ handle = CreateFileW(wpath, 0,
967
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
968
+ OPEN_EXISTING,
969
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
970
+ if (handle == INVALID_HANDLE_VALUE) {
971
+ errno = err_win_to_posix(GetLastError());
972
+ return -1;
973
+ }
974
+ if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, b,
975
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) {
976
+ errno = err_win_to_posix(GetLastError());
977
+ CloseHandle(handle);
978
+ return -1;
979
+ }
980
+ CloseHandle(handle);
981
+
982
+ /* get target path for symlinks or mount points (aka 'junctions') */
983
+ switch ((*ptag = b->ReparseTag)) {
984
+ case IO_REPARSE_TAG_SYMLINK:
985
+ wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer)
986
+ + b->SymbolicLinkReparseBuffer.SubstituteNameOffset);
987
+ *(WCHAR*) (((char*) wbuf)
988
+ + b->SymbolicLinkReparseBuffer.SubstituteNameLength) = 0;
989
+ break;
990
+ case IO_REPARSE_TAG_MOUNT_POINT:
991
+ wbuf = (WCHAR*) (((char*) b->MountPointReparseBuffer.PathBuffer)
992
+ + b->MountPointReparseBuffer.SubstituteNameOffset);
993
+ *(WCHAR*) (((char*) wbuf)
994
+ + b->MountPointReparseBuffer.SubstituteNameLength) = 0;
995
+ break;
996
+ default:
997
+ if (fail_on_unknown_tag) {
998
+ errno = EINVAL;
999
+ return -1;
1000
+ } else {
1001
+ *plen = MAX_PATH;
1002
+ return 0;
1003
+ }
1004
+ }
1005
+
1006
+ if ((*plen =
1007
+ xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_PATH)) < 0)
1008
+ return -1;
1009
+ return 0;
1010
+}
1011
+
1012
int mingw_lstat(const char *file_name, struct stat *buf)
1013
{
1014
WIN32_FILE_ATTRIBUTE_DATA fdata;
923
- WIN32_FIND_DATAW findbuf = { 0 };
1015
+ DWORD reparse_tag = 0;
1016
+ int link_len = 0;
1017
wchar_t wfilename[MAX_PATH];
1018
int wlen = xutftowcs_path(wfilename, file_name);
1019
if (wlen < 0)
1028
}
1029
1030
if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
938
- /* for reparse points, use FindFirstFile to get the reparse tag */
1031
+ /* for reparse points, get the link tag and length */
1032
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
940
- HANDLE handle = FindFirstFileW(wfilename, &findbuf);
941
- if (handle == INVALID_HANDLE_VALUE)
942
- goto error;
943
- FindClose(handle);
1033
+ char tmpbuf[MAX_PATH];
1034
+
1035
+ if (read_reparse_point(wfilename, FALSE, tmpbuf,
1036
+ &link_len, &reparse_tag) < 0)
1037
+ return -1;
1038
}
1039
buf->st_ino = 0;
1040
buf->st_gid = 0;
1041
buf->st_uid = 0;
1042
buf->st_nlink = 1;
1043
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes,
950
- findbuf.dwReserved0);
951
- buf->st_size = fdata.nFileSizeLow |
952
- (((off_t)fdata.nFileSizeHigh)<<32);
1044
+ reparse_tag);
1045
+ buf->st_size = S_ISLNK(buf->st_mode) ? link_len :
1046
+ fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
1047
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
1048
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
1049
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
1050
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
1051
return 0;
1052
}
959
-error:
1053
+
1054
switch (GetLastError()) {
1055
case ERROR_ACCESS_DENIED:
1056
case ERROR_SHARING_VIOLATION: