aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-03-06 10:05:06 +0000
committerRon Yorston <rmy@pobox.com>2019-03-06 10:05:06 +0000
commit5c5197df8668ba58ec7799ccc418d124a6c6a49e (patch)
treeb2cf42a770934c7adba484b5abe5e5e04e76fbff /win32
parent8ebe81483b8759c36c9aa5015044d8e3d2c50fd5 (diff)
downloadbusybox-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.c65
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
1067static 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
1092ssize_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
1063const char *get_busybox_exec_path(void) 1128const char *get_busybox_exec_path(void)
1064{ 1129{
1065 static char *path = NULL; 1130 static char *path = NULL;