|
6 | 6 | #include <sddl.h>
|
7 | 7 | #include <conio.h>
|
8 | 8 | #include <wchar.h>
|
| 9 | +#include <winioctl.h> |
9 | 10 | #include "../strbuf.h"
|
10 | 11 | #include "../run-command.h"
|
11 | 12 | #include "../abspath.h"
|
@@ -2754,6 +2755,103 @@ int link(const char *oldpath, const char *newpath)
|
2754 | 2755 | return 0;
|
2755 | 2756 | }
|
2756 | 2757 |
|
| 2758 | +#ifndef _WINNT_H |
| 2759 | +/* |
| 2760 | + * The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in |
| 2761 | + * ntifs.h) and in MSYS1's winnt.h (which defines _WINNT_H). So define |
| 2762 | + * it ourselves if we are on MSYS2 (whose winnt.h defines _WINNT_). |
| 2763 | + */ |
| 2764 | +typedef struct _REPARSE_DATA_BUFFER { |
| 2765 | + DWORD ReparseTag; |
| 2766 | + WORD ReparseDataLength; |
| 2767 | + WORD Reserved; |
| 2768 | +#ifndef _MSC_VER |
| 2769 | + _ANONYMOUS_UNION |
| 2770 | +#endif |
| 2771 | + union { |
| 2772 | + struct { |
| 2773 | + WORD SubstituteNameOffset; |
| 2774 | + WORD SubstituteNameLength; |
| 2775 | + WORD PrintNameOffset; |
| 2776 | + WORD PrintNameLength; |
| 2777 | + ULONG Flags; |
| 2778 | + WCHAR PathBuffer[1]; |
| 2779 | + } SymbolicLinkReparseBuffer; |
| 2780 | + struct { |
| 2781 | + WORD SubstituteNameOffset; |
| 2782 | + WORD SubstituteNameLength; |
| 2783 | + WORD PrintNameOffset; |
| 2784 | + WORD PrintNameLength; |
| 2785 | + WCHAR PathBuffer[1]; |
| 2786 | + } MountPointReparseBuffer; |
| 2787 | + struct { |
| 2788 | + BYTE DataBuffer[1]; |
| 2789 | + } GenericReparseBuffer; |
| 2790 | + } DUMMYUNIONNAME; |
| 2791 | +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 2792 | +#endif |
| 2793 | + |
| 2794 | +int readlink(const char *path, char *buf, size_t bufsiz) |
| 2795 | +{ |
| 2796 | + HANDLE handle; |
| 2797 | + WCHAR wpath[MAX_LONG_PATH], *wbuf; |
| 2798 | + REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); |
| 2799 | + DWORD dummy; |
| 2800 | + char tmpbuf[MAX_LONG_PATH]; |
| 2801 | + int len; |
| 2802 | + |
| 2803 | + if (xutftowcs_long_path(wpath, path) < 0) |
| 2804 | + return -1; |
| 2805 | + |
| 2806 | + /* read reparse point data */ |
| 2807 | + handle = CreateFileW(wpath, 0, |
| 2808 | + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
| 2809 | + OPEN_EXISTING, |
| 2810 | + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 2811 | + if (handle == INVALID_HANDLE_VALUE) { |
| 2812 | + errno = err_win_to_posix(GetLastError()); |
| 2813 | + return -1; |
| 2814 | + } |
| 2815 | + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, b, |
| 2816 | + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { |
| 2817 | + errno = err_win_to_posix(GetLastError()); |
| 2818 | + CloseHandle(handle); |
| 2819 | + return -1; |
| 2820 | + } |
| 2821 | + CloseHandle(handle); |
| 2822 | + |
| 2823 | + /* get target path for symlinks or mount points (aka 'junctions') */ |
| 2824 | + switch (b->ReparseTag) { |
| 2825 | + case IO_REPARSE_TAG_SYMLINK: |
| 2826 | + wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer) |
| 2827 | + + b->SymbolicLinkReparseBuffer.SubstituteNameOffset); |
| 2828 | + *(WCHAR*) (((char*) wbuf) |
| 2829 | + + b->SymbolicLinkReparseBuffer.SubstituteNameLength) = 0; |
| 2830 | + break; |
| 2831 | + case IO_REPARSE_TAG_MOUNT_POINT: |
| 2832 | + wbuf = (WCHAR*) (((char*) b->MountPointReparseBuffer.PathBuffer) |
| 2833 | + + b->MountPointReparseBuffer.SubstituteNameOffset); |
| 2834 | + *(WCHAR*) (((char*) wbuf) |
| 2835 | + + b->MountPointReparseBuffer.SubstituteNameLength) = 0; |
| 2836 | + break; |
| 2837 | + default: |
| 2838 | + errno = EINVAL; |
| 2839 | + return -1; |
| 2840 | + } |
| 2841 | + |
| 2842 | + /* |
| 2843 | + * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially |
| 2844 | + * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure |
| 2845 | + * condition. There is no conversion function that produces invalid UTF-8, |
| 2846 | + * so convert to a (hopefully large enough) temporary buffer, then memcpy |
| 2847 | + * the requested number of bytes (including '\0' for robustness). |
| 2848 | + */ |
| 2849 | + if ((len = xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_LONG_PATH)) < 0) |
| 2850 | + return -1; |
| 2851 | + memcpy(buf, tmpbuf, min(bufsiz, len + 1)); |
| 2852 | + return min(bufsiz, len); |
| 2853 | +} |
| 2854 | + |
2757 | 2855 | pid_t waitpid(pid_t pid, int *status, int options)
|
2758 | 2856 | {
|
2759 | 2857 | HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
|
0 commit comments