diff options
author | Ron Yorston <rmy@pobox.com> | 2019-03-06 10:05:06 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-03-06 10:05:06 +0000 |
commit | 5c5197df8668ba58ec7799ccc418d124a6c6a49e (patch) | |
tree | b2cf42a770934c7adba484b5abe5e5e04e76fbff /win32 | |
parent | 8ebe81483b8759c36c9aa5015044d8e3d2c50fd5 (diff) | |
download | busybox-w32-5c5197df8668ba58ec7799ccc418d124a6c6a49e.tar.gz busybox-w32-5c5197df8668ba58ec7799ccc418d124a6c6a49e.tar.bz2 busybox-w32-5c5197df8668ba58ec7799ccc418d124a6c6a49e.zip |
win32: implement readlink(2)
Provide an implementation of readlink(2) based on code from Git
for Windows. This version only supports symbolic links, not
mount points, as the latter seem to work well enough as-is.
With this change the ls and stat applets can display the targets
of symbolic links. The readlink applet has been enabled in the
default configuration.
Diffstat (limited to 'win32')
-rw-r--r-- | win32/mingw.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/win32/mingw.c b/win32/mingw.c index dda2e9a60..c42dbed97 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -4,6 +4,9 @@ | |||
4 | #if ENABLE_FEATURE_IDENTIFY_OWNER | 4 | #if ENABLE_FEATURE_IDENTIFY_OWNER |
5 | #include <aclapi.h> | 5 | #include <aclapi.h> |
6 | #endif | 6 | #endif |
7 | #if ENABLE_FEATURE_READLINK2 | ||
8 | #include <ntdef.h> | ||
9 | #endif | ||
7 | 10 | ||
8 | #if defined(__MINGW64_VERSION_MAJOR) | 11 | #if defined(__MINGW64_VERSION_MAJOR) |
9 | #if ENABLE_GLOBBING | 12 | #if ENABLE_GLOBBING |
@@ -1060,6 +1063,68 @@ char *realpath(const char *path, char *resolved_path) | |||
1060 | return NULL; | 1063 | return NULL; |
1061 | } | 1064 | } |
1062 | 1065 | ||
1066 | #if ENABLE_FEATURE_READLINK2 | ||
1067 | static wchar_t *normalize_ntpath(wchar_t *wbuf) | ||
1068 | { | ||
1069 | int i; | ||
1070 | /* fix absolute path prefixes */ | ||
1071 | if (wbuf[0] == '\\') { | ||
1072 | /* strip NT namespace prefixes */ | ||
1073 | if (!wcsncmp(wbuf, L"\\??\\", 4) || | ||
1074 | !wcsncmp(wbuf, L"\\\\?\\", 4)) | ||
1075 | wbuf += 4; | ||
1076 | else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12)) | ||
1077 | wbuf += 12; | ||
1078 | /* replace remaining '...UNC\' with '\\' */ | ||
1079 | if (!wcsnicmp(wbuf, L"UNC\\", 4)) { | ||
1080 | wbuf += 2; | ||
1081 | *wbuf = '\\'; | ||
1082 | } | ||
1083 | } | ||
1084 | /* convert backslashes to slashes */ | ||
1085 | for (i = 0; wbuf[i]; i++) | ||
1086 | if (wbuf[i] == '\\') | ||
1087 | wbuf[i] = '/'; | ||
1088 | return wbuf; | ||
1089 | } | ||
1090 | |||
1091 | #define SRPB rptr->SymbolicLinkReparseBuffer | ||
1092 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) | ||
1093 | { | ||
1094 | HANDLE h; | ||
1095 | |||
1096 | h = CreateFile(pathname, 0, 0, NULL, OPEN_EXISTING, | ||
1097 | FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); | ||
1098 | if (h != INVALID_HANDLE_VALUE) { | ||
1099 | DWORD nbytes; | ||
1100 | BYTE rbuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; | ||
1101 | PREPARSE_DATA_BUFFER rptr = (PREPARSE_DATA_BUFFER)rbuf; | ||
1102 | BOOL status; | ||
1103 | |||
1104 | status = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, | ||
1105 | rptr, sizeof(rbuf), &nbytes, NULL); | ||
1106 | CloseHandle(h); | ||
1107 | |||
1108 | if (status && rptr->ReparseTag == IO_REPARSE_TAG_SYMLINK) { | ||
1109 | size_t len = SRPB.SubstituteNameLength/sizeof(WCHAR); | ||
1110 | WCHAR *name = SRPB.PathBuffer + | ||
1111 | SRPB.SubstituteNameOffset/sizeof(WCHAR); | ||
1112 | |||
1113 | name[len] = 0; | ||
1114 | name = normalize_ntpath(name); | ||
1115 | len = wcslen(name); | ||
1116 | if (len > bufsiz) | ||
1117 | len = bufsiz; | ||
1118 | if (WideCharToMultiByte(CP_ACP, 0, name, len, buf, bufsiz, 0, 0)) { | ||
1119 | return len; | ||
1120 | } | ||
1121 | } | ||
1122 | } | ||
1123 | errno = err_win_to_posix(); | ||
1124 | return -1; | ||
1125 | } | ||
1126 | #endif | ||
1127 | |||
1063 | const char *get_busybox_exec_path(void) | 1128 | const char *get_busybox_exec_path(void) |
1064 | { | 1129 | { |
1065 | static char *path = NULL; | 1130 | static char *path = NULL; |