| 
7 | 7 | #include <sddl.h>  | 
8 | 8 | #include <conio.h>  | 
9 | 9 | #include <wchar.h>  | 
 | 10 | +#include <winioctl.h>  | 
10 | 11 | #include "../strbuf.h"  | 
11 | 12 | #include "../run-command.h"  | 
12 | 13 | #include "../abspath.h"  | 
@@ -2977,6 +2978,103 @@ int link(const char *oldpath, const char *newpath)  | 
2977 | 2978 | 	return 0;  | 
2978 | 2979 | }  | 
2979 | 2980 | 
 
  | 
 | 2981 | +#ifndef _WINNT_H  | 
 | 2982 | +/*  | 
 | 2983 | + * The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in  | 
 | 2984 | + * ntifs.h) and in MSYS1's winnt.h (which defines _WINNT_H). So define  | 
 | 2985 | + * it ourselves if we are on MSYS2 (whose winnt.h defines _WINNT_).  | 
 | 2986 | + */  | 
 | 2987 | +typedef struct _REPARSE_DATA_BUFFER {  | 
 | 2988 | +	DWORD  ReparseTag;  | 
 | 2989 | +	WORD   ReparseDataLength;  | 
 | 2990 | +	WORD   Reserved;  | 
 | 2991 | +#ifndef _MSC_VER  | 
 | 2992 | +	_ANONYMOUS_UNION  | 
 | 2993 | +#endif  | 
 | 2994 | +	union {  | 
 | 2995 | +		struct {  | 
 | 2996 | +			WORD   SubstituteNameOffset;  | 
 | 2997 | +			WORD   SubstituteNameLength;  | 
 | 2998 | +			WORD   PrintNameOffset;  | 
 | 2999 | +			WORD   PrintNameLength;  | 
 | 3000 | +			ULONG  Flags;  | 
 | 3001 | +			WCHAR PathBuffer[1];  | 
 | 3002 | +		} SymbolicLinkReparseBuffer;  | 
 | 3003 | +		struct {  | 
 | 3004 | +			WORD   SubstituteNameOffset;  | 
 | 3005 | +			WORD   SubstituteNameLength;  | 
 | 3006 | +			WORD   PrintNameOffset;  | 
 | 3007 | +			WORD   PrintNameLength;  | 
 | 3008 | +			WCHAR PathBuffer[1];  | 
 | 3009 | +		} MountPointReparseBuffer;  | 
 | 3010 | +		struct {  | 
 | 3011 | +			BYTE   DataBuffer[1];  | 
 | 3012 | +		} GenericReparseBuffer;  | 
 | 3013 | +	} DUMMYUNIONNAME;  | 
 | 3014 | +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;  | 
 | 3015 | +#endif  | 
 | 3016 | + | 
 | 3017 | +int readlink(const char *path, char *buf, size_t bufsiz)  | 
 | 3018 | +{  | 
 | 3019 | +	HANDLE handle;  | 
 | 3020 | +	WCHAR wpath[MAX_LONG_PATH], *wbuf;  | 
 | 3021 | +	REPARSE_DATA_BUFFER *b = alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);  | 
 | 3022 | +	DWORD dummy;  | 
 | 3023 | +	char tmpbuf[MAX_LONG_PATH];  | 
 | 3024 | +	int len;  | 
 | 3025 | + | 
 | 3026 | +	if (xutftowcs_long_path(wpath, path) < 0)  | 
 | 3027 | +		return -1;  | 
 | 3028 | + | 
 | 3029 | +	/* read reparse point data */  | 
 | 3030 | +	handle = CreateFileW(wpath, 0,  | 
 | 3031 | +			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,  | 
 | 3032 | +			OPEN_EXISTING,  | 
 | 3033 | +			FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);  | 
 | 3034 | +	if (handle == INVALID_HANDLE_VALUE) {  | 
 | 3035 | +		errno = err_win_to_posix(GetLastError());  | 
 | 3036 | +		return -1;  | 
 | 3037 | +	}  | 
 | 3038 | +	if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, b,  | 
 | 3039 | +			MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) {  | 
 | 3040 | +		errno = err_win_to_posix(GetLastError());  | 
 | 3041 | +		CloseHandle(handle);  | 
 | 3042 | +		return -1;  | 
 | 3043 | +	}  | 
 | 3044 | +	CloseHandle(handle);  | 
 | 3045 | + | 
 | 3046 | +	/* get target path for symlinks or mount points (aka 'junctions') */  | 
 | 3047 | +	switch (b->ReparseTag) {  | 
 | 3048 | +	case IO_REPARSE_TAG_SYMLINK:  | 
 | 3049 | +		wbuf = (WCHAR*) (((char*) b->SymbolicLinkReparseBuffer.PathBuffer)  | 
 | 3050 | +				+ b->SymbolicLinkReparseBuffer.SubstituteNameOffset);  | 
 | 3051 | +		*(WCHAR*) (((char*) wbuf)  | 
 | 3052 | +				+ b->SymbolicLinkReparseBuffer.SubstituteNameLength) = 0;  | 
 | 3053 | +		break;  | 
 | 3054 | +	case IO_REPARSE_TAG_MOUNT_POINT:  | 
 | 3055 | +		wbuf = (WCHAR*) (((char*) b->MountPointReparseBuffer.PathBuffer)  | 
 | 3056 | +				+ b->MountPointReparseBuffer.SubstituteNameOffset);  | 
 | 3057 | +		*(WCHAR*) (((char*) wbuf)  | 
 | 3058 | +				+ b->MountPointReparseBuffer.SubstituteNameLength) = 0;  | 
 | 3059 | +		break;  | 
 | 3060 | +	default:  | 
 | 3061 | +		errno = EINVAL;  | 
 | 3062 | +		return -1;  | 
 | 3063 | +	}  | 
 | 3064 | + | 
 | 3065 | +	/*  | 
 | 3066 | +	 * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially  | 
 | 3067 | +	 * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure  | 
 | 3068 | +	 * condition. There is no conversion function that produces invalid UTF-8,  | 
 | 3069 | +	 * so convert to a (hopefully large enough) temporary buffer, then memcpy  | 
 | 3070 | +	 * the requested number of bytes (including '\0' for robustness).  | 
 | 3071 | +	 */  | 
 | 3072 | +	if ((len = xwcstoutf(tmpbuf, normalize_ntpath(wbuf), MAX_LONG_PATH)) < 0)  | 
 | 3073 | +		return -1;  | 
 | 3074 | +	memcpy(buf, tmpbuf, min(bufsiz, len + 1));  | 
 | 3075 | +	return min(bufsiz, len);  | 
 | 3076 | +}  | 
 | 3077 | + | 
2980 | 3078 | pid_t waitpid(pid_t pid, int *status, int options)  | 
2981 | 3079 | {  | 
2982 | 3080 | 	HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,  | 
 | 
0 commit comments