|
1 | 1 | #include <nall/directory.hpp> |
| 2 | +#if defined(PLATFORM_WINDOWS) |
| 3 | + #include <winioctl.h> |
| 4 | + |
| 5 | + //normally defined in ntifs.h (WDK) |
| 6 | + typedef struct _REPARSE_DATA_BUFFER { |
| 7 | + unsigned long ReparseTag; |
| 8 | + unsigned short ReparseDataLength; |
| 9 | + unsigned short Reserved; |
| 10 | + union { |
| 11 | + struct { |
| 12 | + unsigned short SubstituteNameOffset; |
| 13 | + unsigned short SubstituteNameLength; |
| 14 | + unsigned short PrintNameOffset; |
| 15 | + unsigned short PrintNameLength; |
| 16 | + unsigned long Flags; |
| 17 | + wchar_t PathBuffer[1]; |
| 18 | + } SymbolicLinkReparseBuffer; |
| 19 | + struct { |
| 20 | + unsigned short SubstituteNameOffset; |
| 21 | + unsigned short SubstituteNameLength; |
| 22 | + unsigned short PrintNameOffset; |
| 23 | + unsigned short PrintNameLength; |
| 24 | + wchar_t PathBuffer[1]; |
| 25 | + } MountPointReparseBuffer; |
| 26 | + struct { |
| 27 | + unsigned char DataBuffer[1]; |
| 28 | + } GenericReparseBuffer; |
| 29 | + } DUMMYUNIONNAME; |
| 30 | + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 31 | +#endif |
2 | 32 |
|
3 | 33 | namespace nall { |
4 | 34 |
|
@@ -90,15 +120,31 @@ NALL_HEADER_INLINE auto directory::ufiles(const string& pathname, const string& |
90 | 120 | NALL_HEADER_INLINE auto directory::resolveSymLink(const string& pathname) -> string { |
91 | 121 | string result = pathname; |
92 | 122 | #if defined (PLATFORM_WINDOWS) |
93 | | - HANDLE hFile = CreateFile(utf16_t(result.data()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); |
| 123 | + HANDLE hFile = CreateFile(utf16_t(result.data()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 124 | + NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); |
94 | 125 | if(hFile != INVALID_HANDLE_VALUE) |
95 | 126 | { |
96 | | - wchar_t buffer[MAX_PATH]; |
97 | | - memset(buffer, 0, MAX_PATH * sizeof(wchar_t)); |
98 | | - if(GetFinalPathNameByHandle(hFile, buffer, MAX_PATH, 0) < MAX_PATH) { |
99 | | - result = (slice((const char*)utf8_t(buffer), 4, wcslen(buffer) - 4)).transform("\\", "/"); //remove "\\?\" prefix |
| 127 | + BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; |
| 128 | + memset(buffer, 0, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); |
| 129 | + if(DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, NULL, NULL)) { |
| 130 | + REPARSE_DATA_BUFFER* reparseData = (REPARSE_DATA_BUFFER*)buffer; |
| 131 | + u16 substituteNameOffset = 0, substituteNameLength = 0; |
| 132 | + wchar_t* pathBuffer = nullptr; |
| 133 | + if(reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { |
| 134 | + pathBuffer = reparseData->SymbolicLinkReparseBuffer.PathBuffer; |
| 135 | + substituteNameOffset = reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
| 136 | + substituteNameLength = reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
| 137 | + result = (slice((const char*)utf8_t(pathBuffer) + substituteNameOffset, 0, substituteNameLength)).transform("\\", "/"); |
| 138 | + if(result.beginsWith("/??/")) result = result.slice(4); |
| 139 | + } else if (reparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { |
| 140 | + pathBuffer = reparseData->MountPointReparseBuffer.PathBuffer; |
| 141 | + substituteNameOffset = reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); |
| 142 | + substituteNameLength = reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); |
| 143 | + result = (slice((const char*)utf8_t(pathBuffer) + substituteNameOffset, 0, substituteNameLength)).transform("\\", "/"); |
| 144 | + if(result.beginsWith("/??/")) result = result.slice(4); |
100 | 145 | } |
101 | | - CloseHandle(hFile); |
| 146 | + } |
| 147 | + CloseHandle(hFile); |
102 | 148 | } |
103 | 149 | #else |
104 | 150 | struct stat sb = {}; |
|
0 commit comments