|
2 | 2 | #include "win32.h"
|
3 | 3 | #include <conio.h>
|
4 | 4 | #include <wchar.h>
|
| 5 | +#include <winioctl.h> |
5 | 6 | #include "../strbuf.h"
|
6 | 7 | #include "../run-command.h"
|
7 | 8 | #include "../cache.h"
|
@@ -2171,6 +2172,106 @@ int link(const char *oldpath, const char *newpath)
|
2171 | 2172 | return 0;
|
2172 | 2173 | }
|
2173 | 2174 |
|
| 2175 | +#ifndef _WINNT_H |
| 2176 | +/* |
| 2177 | + * The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in |
| 2178 | + * ntifs.h) and in MSYS1's winnt.h (which defines _WINNT_H). So define |
| 2179 | + * it ourselves if we are on MSYS2 (whose winnt.h defines _WINNT_). |
| 2180 | + */ |
| 2181 | +typedef struct _REPARSE_DATA_BUFFER { |
| 2182 | + DWORD ReparseTag; |
| 2183 | + WORD ReparseDataLength; |
| 2184 | + WORD Reserved; |
| 2185 | + _ANONYMOUS_UNION union { |
| 2186 | + struct { |
| 2187 | + WORD SubstituteNameOffset; |
| 2188 | + WORD SubstituteNameLength; |
| 2189 | + WORD PrintNameOffset; |
| 2190 | + WORD PrintNameLength; |
| 2191 | + ULONG Flags; |
| 2192 | + WCHAR PathBuffer[1]; |
| 2193 | + } SymbolicLinkReparseBuffer; |
| 2194 | + struct { |
| 2195 | + WORD SubstituteNameOffset; |
| 2196 | + WORD SubstituteNameLength; |
| 2197 | + WORD PrintNameOffset; |
| 2198 | + WORD PrintNameLength; |
| 2199 | + WCHAR PathBuffer[1]; |
| 2200 | + } MountPointReparseBuffer; |
| 2201 | + struct { |
| 2202 | + BYTE DataBuffer[1]; |
| 2203 | + } GenericReparseBuffer; |
| 2204 | + } DUMMYUNIONNAME; |
| 2205 | +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 2206 | +#endif |
| 2207 | + |
| 2208 | +int readlink(const char *path, char *buf, size_t bufsiz) |
| 2209 | +{ |
| 2210 | + HANDLE handle; |
| 2211 | + WCHAR wpath[MAX_LONG_PATH], *wbuf; |
| 2212 | + REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); |
| 2213 | + DWORD dummy; |
| 2214 | + char tmpbuf[MAX_LONG_PATH]; |
| 2215 | + int len; |
| 2216 | + |
| 2217 | + /* fail if symlinks are disabled */ |
| 2218 | + if (!has_symlinks) { |
| 2219 | + errno = ENOSYS; |
| 2220 | + return -1; |
| 2221 | + } |
| 2222 | + |
| 2223 | + if (xutftowcs_long_path(wpath, path) < 0) |
| 2224 | + return -1; |
| 2225 | + |
| 2226 | + /* read reparse point data */ |
| 2227 | + handle = CreateFileW(wpath, 0, |
| 2228 | + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
| 2229 | + OPEN_EXISTING, |
| 2230 | + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 2231 | + if (handle == INVALID_HANDLE_VALUE) { |
| 2232 | + errno = err_win_to_posix(GetLastError()); |
| 2233 | + return -1; |
| 2234 | + } |
| 2235 | + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, b, |
| 2236 | + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { |
| 2237 | + errno = err_win_to_posix(GetLastError()); |
| 2238 | + CloseHandle(handle); |
| 2239 | + return -1; |
| 2240 | + } |
| 2241 | + CloseHandle(handle); |
| 2242 | + |
| 2243 | + /* get target path for symlinks or mount points (aka 'junctions') */ |
| 2244 | + switch (b->ReparseTag) { |
| 2245 | + case IO_REPARSE_TAG_SYMLINK: |
| 2246 | + wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer) |
| 2247 | + + b->SymbolicLinkReparseBuffer.SubstituteNameOffset); |
| 2248 | + *(WCHAR*) (((char*) wbuf) |
| 2249 | + + b->SymbolicLinkReparseBuffer.SubstituteNameLength) = 0; |
| 2250 | + break; |
| 2251 | + case IO_REPARSE_TAG_MOUNT_POINT: |
| 2252 | + wbuf = (WCHAR*) (((char*) b->MountPointReparseBuffer.PathBuffer) |
| 2253 | + + b->MountPointReparseBuffer.SubstituteNameOffset); |
| 2254 | + *(WCHAR*) (((char*) wbuf) |
| 2255 | + + b->MountPointReparseBuffer.SubstituteNameLength) = 0; |
| 2256 | + break; |
| 2257 | + default: |
| 2258 | + errno = EINVAL; |
| 2259 | + return -1; |
| 2260 | + } |
| 2261 | + |
| 2262 | + /* |
| 2263 | + * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially |
| 2264 | + * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure |
| 2265 | + * condition. There is no conversion function that produces invalid UTF-8, |
| 2266 | + * so convert to a (hopefully large enough) temporary buffer, then memcpy |
| 2267 | + * the requested number of bytes (including '\0' for robustness). |
| 2268 | + */ |
| 2269 | + if ((len = xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_LONG_PATH)) < 0) |
| 2270 | + return -1; |
| 2271 | + memcpy(buf, tmpbuf, min(bufsiz, len + 1)); |
| 2272 | + return min(bufsiz, len); |
| 2273 | +} |
| 2274 | + |
2174 | 2275 | pid_t waitpid(pid_t pid, int *status, int options)
|
2175 | 2276 | {
|
2176 | 2277 | HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
|
0 commit comments