|
3 | 3 | #include <conio.h>
|
4 | 4 | #include <shlobj.h>
|
5 | 5 | #include <wchar.h>
|
| 6 | +#include <winioctl.h> |
6 | 7 | #include "../strbuf.h"
|
7 | 8 | #include "../run-command.h"
|
8 | 9 | #include "../cache.h"
|
@@ -2008,6 +2009,99 @@ int link(const char *oldpath, const char *newpath)
|
2008 | 2009 | return 0;
|
2009 | 2010 | }
|
2010 | 2011 |
|
| 2012 | +typedef struct _REPARSE_DATA_BUFFER { |
| 2013 | + DWORD ReparseTag; |
| 2014 | + WORD ReparseDataLength; |
| 2015 | + WORD Reserved; |
| 2016 | + _ANONYMOUS_UNION union { |
| 2017 | + struct { |
| 2018 | + WORD SubstituteNameOffset; |
| 2019 | + WORD SubstituteNameLength; |
| 2020 | + WORD PrintNameOffset; |
| 2021 | + WORD PrintNameLength; |
| 2022 | + ULONG Flags; |
| 2023 | + WCHAR PathBuffer[1]; |
| 2024 | + } SymbolicLinkReparseBuffer; |
| 2025 | + struct { |
| 2026 | + WORD SubstituteNameOffset; |
| 2027 | + WORD SubstituteNameLength; |
| 2028 | + WORD PrintNameOffset; |
| 2029 | + WORD PrintNameLength; |
| 2030 | + WCHAR PathBuffer[1]; |
| 2031 | + } MountPointReparseBuffer; |
| 2032 | + struct { |
| 2033 | + BYTE DataBuffer[1]; |
| 2034 | + } GenericReparseBuffer; |
| 2035 | + } DUMMYUNIONNAME; |
| 2036 | +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 2037 | + |
| 2038 | +int readlink(const char *path, char *buf, size_t bufsiz) |
| 2039 | +{ |
| 2040 | + HANDLE handle; |
| 2041 | + WCHAR wpath[MAX_LONG_PATH], *wbuf; |
| 2042 | + REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); |
| 2043 | + DWORD dummy; |
| 2044 | + char tmpbuf[MAX_LONG_PATH]; |
| 2045 | + int len; |
| 2046 | + |
| 2047 | + /* fail if symlinks are disabled */ |
| 2048 | + if (!has_symlinks) { |
| 2049 | + errno = ENOSYS; |
| 2050 | + return -1; |
| 2051 | + } |
| 2052 | + |
| 2053 | + if (xutftowcs_long_path(wpath, path) < 0) |
| 2054 | + return -1; |
| 2055 | + |
| 2056 | + /* read reparse point data */ |
| 2057 | + handle = CreateFileW(wpath, 0, |
| 2058 | + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
| 2059 | + OPEN_EXISTING, |
| 2060 | + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 2061 | + if (handle == INVALID_HANDLE_VALUE) { |
| 2062 | + errno = err_win_to_posix(GetLastError()); |
| 2063 | + return -1; |
| 2064 | + } |
| 2065 | + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, b, |
| 2066 | + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { |
| 2067 | + errno = err_win_to_posix(GetLastError()); |
| 2068 | + CloseHandle(handle); |
| 2069 | + return -1; |
| 2070 | + } |
| 2071 | + CloseHandle(handle); |
| 2072 | + |
| 2073 | + /* get target path for symlinks or mount points (aka 'junctions') */ |
| 2074 | + switch (b->ReparseTag) { |
| 2075 | + case IO_REPARSE_TAG_SYMLINK: |
| 2076 | + wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer) |
| 2077 | + + b->SymbolicLinkReparseBuffer.SubstituteNameOffset); |
| 2078 | + *(WCHAR*) (((char*) wbuf) |
| 2079 | + + b->SymbolicLinkReparseBuffer.SubstituteNameLength) = 0; |
| 2080 | + break; |
| 2081 | + case IO_REPARSE_TAG_MOUNT_POINT: |
| 2082 | + wbuf = (WCHAR*) (((char*) b->MountPointReparseBuffer.PathBuffer) |
| 2083 | + + b->MountPointReparseBuffer.SubstituteNameOffset); |
| 2084 | + *(WCHAR*) (((char*) wbuf) |
| 2085 | + + b->MountPointReparseBuffer.SubstituteNameLength) = 0; |
| 2086 | + break; |
| 2087 | + default: |
| 2088 | + errno = EINVAL; |
| 2089 | + return -1; |
| 2090 | + } |
| 2091 | + |
| 2092 | + /* |
| 2093 | + * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially |
| 2094 | + * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure |
| 2095 | + * condition. There is no conversion function that produces invalid UTF-8, |
| 2096 | + * so convert to a (hopefully large enough) temporary buffer, then memcpy |
| 2097 | + * the requested number of bytes (including '\0' for robustness). |
| 2098 | + */ |
| 2099 | + if ((len = xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_LONG_PATH)) < 0) |
| 2100 | + return -1; |
| 2101 | + memcpy(buf, tmpbuf, min(bufsiz, len + 1)); |
| 2102 | + return min(bufsiz, len); |
| 2103 | +} |
| 2104 | + |
2011 | 2105 | pid_t waitpid(pid_t pid, int *status, int options)
|
2012 | 2106 | {
|
2013 | 2107 | HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
|
0 commit comments