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 | |
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.
-rw-r--r-- | Config.in | 10 | ||||
-rw-r--r-- | configs/mingw32_defconfig | 8 | ||||
-rw-r--r-- | configs/mingw64_defconfig | 8 | ||||
-rw-r--r-- | coreutils/ls.c | 2 | ||||
-rw-r--r-- | coreutils/stat.c | 4 | ||||
-rw-r--r-- | include/mingw.h | 4 | ||||
-rw-r--r-- | win32/mingw.c | 65 |
7 files changed, 92 insertions, 9 deletions
@@ -473,6 +473,16 @@ config FEATURE_IDENTIFY_OWNER | |||
473 | Try to determine if files belong to the current user. If they don't | 473 | Try to determine if files belong to the current user. If they don't |
474 | they're listed as belonging to root. | 474 | they're listed as belonging to root. |
475 | 475 | ||
476 | config FEATURE_READLINK2 | ||
477 | bool "Read the contents of symbolic links (1.1 kb)" | ||
478 | default y | ||
479 | depends on PLATFORM_MINGW32 | ||
480 | help | ||
481 | Implement the readlink(2) system call to allow applets to read | ||
482 | the contents of symbolic links. With this feature ls and stat | ||
483 | can display the target of symbolic links and it makes sense to | ||
484 | enable the readlink applet. | ||
485 | |||
476 | comment 'Build Options' | 486 | comment 'Build Options' |
477 | 487 | ||
478 | config STATIC | 488 | config STATIC |
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index c30ffa1b5..a29cc164a 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.31.0.git | 3 | # Busybox version: 1.31.0.git |
4 | # Fri Mar 1 08:50:17 2019 | 4 | # Wed Mar 6 09:32:59 2019 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -50,6 +50,7 @@ CONFIG_FEATURE_ICON_ALL=y | |||
50 | CONFIG_FEATURE_EURO=y | 50 | CONFIG_FEATURE_EURO=y |
51 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 51 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
52 | CONFIG_FEATURE_IDENTIFY_OWNER=y | 52 | CONFIG_FEATURE_IDENTIFY_OWNER=y |
53 | CONFIG_FEATURE_READLINK2=y | ||
53 | 54 | ||
54 | # | 55 | # |
55 | # Build Options | 56 | # Build Options |
@@ -295,8 +296,8 @@ CONFIG_PASTE=y | |||
295 | CONFIG_PRINTENV=y | 296 | CONFIG_PRINTENV=y |
296 | CONFIG_PRINTF=y | 297 | CONFIG_PRINTF=y |
297 | CONFIG_PWD=y | 298 | CONFIG_PWD=y |
298 | # CONFIG_READLINK is not set | 299 | CONFIG_READLINK=y |
299 | # CONFIG_FEATURE_READLINK_FOLLOW is not set | 300 | CONFIG_FEATURE_READLINK_FOLLOW=y |
300 | CONFIG_REALPATH=y | 301 | CONFIG_REALPATH=y |
301 | CONFIG_RM=y | 302 | CONFIG_RM=y |
302 | CONFIG_RMDIR=y | 303 | CONFIG_RMDIR=y |
@@ -1113,6 +1114,7 @@ CONFIG_ASH_HELP=y | |||
1113 | CONFIG_ASH_GETOPTS=y | 1114 | CONFIG_ASH_GETOPTS=y |
1114 | CONFIG_ASH_CMDCMD=y | 1115 | CONFIG_ASH_CMDCMD=y |
1115 | CONFIG_ASH_NOCONSOLE=y | 1116 | CONFIG_ASH_NOCONSOLE=y |
1117 | CONFIG_ASH_NOCASEGLOB=y | ||
1116 | # CONFIG_CTTYHACK is not set | 1118 | # CONFIG_CTTYHACK is not set |
1117 | # CONFIG_HUSH is not set | 1119 | # CONFIG_HUSH is not set |
1118 | # CONFIG_HUSH_BASH_COMPAT is not set | 1120 | # CONFIG_HUSH_BASH_COMPAT is not set |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 46cb6941f..3d6102f0a 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.31.0.git | 3 | # Busybox version: 1.31.0.git |
4 | # Fri Mar 1 08:50:17 2019 | 4 | # Wed Mar 6 09:32:59 2019 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -50,6 +50,7 @@ CONFIG_FEATURE_ICON_ALL=y | |||
50 | CONFIG_FEATURE_EURO=y | 50 | CONFIG_FEATURE_EURO=y |
51 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 51 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
52 | CONFIG_FEATURE_IDENTIFY_OWNER=y | 52 | CONFIG_FEATURE_IDENTIFY_OWNER=y |
53 | CONFIG_FEATURE_READLINK2=y | ||
53 | 54 | ||
54 | # | 55 | # |
55 | # Build Options | 56 | # Build Options |
@@ -295,8 +296,8 @@ CONFIG_PASTE=y | |||
295 | CONFIG_PRINTENV=y | 296 | CONFIG_PRINTENV=y |
296 | CONFIG_PRINTF=y | 297 | CONFIG_PRINTF=y |
297 | CONFIG_PWD=y | 298 | CONFIG_PWD=y |
298 | # CONFIG_READLINK is not set | 299 | CONFIG_READLINK=y |
299 | # CONFIG_FEATURE_READLINK_FOLLOW is not set | 300 | CONFIG_FEATURE_READLINK_FOLLOW=y |
300 | CONFIG_REALPATH=y | 301 | CONFIG_REALPATH=y |
301 | CONFIG_RM=y | 302 | CONFIG_RM=y |
302 | CONFIG_RMDIR=y | 303 | CONFIG_RMDIR=y |
@@ -1113,6 +1114,7 @@ CONFIG_ASH_HELP=y | |||
1113 | CONFIG_ASH_GETOPTS=y | 1114 | CONFIG_ASH_GETOPTS=y |
1114 | CONFIG_ASH_CMDCMD=y | 1115 | CONFIG_ASH_CMDCMD=y |
1115 | CONFIG_ASH_NOCONSOLE=y | 1116 | CONFIG_ASH_NOCONSOLE=y |
1117 | CONFIG_ASH_NOCASEGLOB=y | ||
1116 | # CONFIG_CTTYHACK is not set | 1118 | # CONFIG_CTTYHACK is not set |
1117 | # CONFIG_HUSH is not set | 1119 | # CONFIG_HUSH is not set |
1118 | # CONFIG_HUSH_BASH_COMPAT is not set | 1120 | # CONFIG_HUSH_BASH_COMPAT is not set |
diff --git a/coreutils/ls.c b/coreutils/ls.c index c5402de30..6be3eb291 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -492,7 +492,7 @@ static NOINLINE unsigned display_single(const struct dnode *dn) | |||
492 | /* Do readlink early, so that if it fails, error message | 492 | /* Do readlink early, so that if it fails, error message |
493 | * does not appear *inside* the "ls -l" line */ | 493 | * does not appear *inside* the "ls -l" line */ |
494 | lpath = NULL; | 494 | lpath = NULL; |
495 | #if !ENABLE_PLATFORM_MINGW32 | 495 | #if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_READLINK2 |
496 | if (opt & OPT_l) | 496 | if (opt & OPT_l) |
497 | if (S_ISLNK(dn->dn_mode)) | 497 | if (S_ISLNK(dn->dn_mode)) |
498 | lpath = xmalloc_readlink_or_warn(dn->fullname); | 498 | lpath = xmalloc_readlink_or_warn(dn->fullname); |
diff --git a/coreutils/stat.c b/coreutils/stat.c index 32bc5e2d3..cf13af0b6 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c | |||
@@ -317,7 +317,7 @@ static void FAST_FUNC print_stat(char *pformat, const char m, | |||
317 | printfs(pformat, filename); | 317 | printfs(pformat, filename); |
318 | } else if (m == 'N') { | 318 | } else if (m == 'N') { |
319 | strcatc(pformat, 's'); | 319 | strcatc(pformat, 's'); |
320 | #if !ENABLE_PLATFORM_MINGW32 | 320 | #if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_READLINK2 |
321 | if (S_ISLNK(statbuf->st_mode)) { | 321 | if (S_ISLNK(statbuf->st_mode)) { |
322 | char *linkname = xmalloc_readlink_or_warn(filename); | 322 | char *linkname = xmalloc_readlink_or_warn(filename); |
323 | if (linkname == NULL) | 323 | if (linkname == NULL) |
@@ -712,7 +712,7 @@ static bool do_stat(const char *filename, const char *format) | |||
712 | gw_ent = getgrgid(statbuf.st_gid); | 712 | gw_ent = getgrgid(statbuf.st_gid); |
713 | pw_ent = getpwuid(statbuf.st_uid); | 713 | pw_ent = getpwuid(statbuf.st_uid); |
714 | 714 | ||
715 | #if !ENABLE_PLATFORM_MINGW32 | 715 | #if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_READLINK2 |
716 | if (S_ISLNK(statbuf.st_mode)) | 716 | if (S_ISLNK(statbuf.st_mode)) |
717 | linkname = xmalloc_readlink_or_warn(filename); | 717 | linkname = xmalloc_readlink_or_warn(filename); |
718 | if (linkname) { | 718 | if (linkname) { |
diff --git a/include/mingw.h b/include/mingw.h index 188d4eecf..b5324e49b 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -407,7 +407,11 @@ int mingw_xopen(const char *filename, int oflags); | |||
407 | ssize_t mingw_read(int fd, void *buf, size_t count); | 407 | ssize_t mingw_read(int fd, void *buf, size_t count); |
408 | int mingw_close(int fd); | 408 | int mingw_close(int fd); |
409 | int pipe(int filedes[2]); | 409 | int pipe(int filedes[2]); |
410 | #if ENABLE_FEATURE_READLINK2 | ||
411 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); | ||
412 | #else | ||
410 | NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM); | 413 | NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM); |
414 | #endif | ||
411 | NOIMPL(setgid,gid_t gid UNUSED_PARAM); | 415 | NOIMPL(setgid,gid_t gid UNUSED_PARAM); |
412 | NOIMPL(setegid,gid_t gid UNUSED_PARAM); | 416 | NOIMPL(setegid,gid_t gid UNUSED_PARAM); |
413 | NOIMPL(setsid,void); | 417 | NOIMPL(setsid,void); |
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; |