aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--Config.in10
-rw-r--r--configs/mingw32_defconfig8
-rw-r--r--configs/mingw64_defconfig8
-rw-r--r--coreutils/ls.c2
-rw-r--r--coreutils/stat.c4
-rw-r--r--include/mingw.h4
-rw-r--r--win32/mingw.c65
7 files changed, 92 insertions, 9 deletions
diff --git a/Config.in b/Config.in
index 2b4b81515..100f6e491 100644
--- a/Config.in
+++ b/Config.in
@@ -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
476config 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
476comment 'Build Options' 486comment 'Build Options'
477 487
478config STATIC 488config 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#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_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
50CONFIG_FEATURE_EURO=y 50CONFIG_FEATURE_EURO=y
51CONFIG_FEATURE_EXTRA_FILE_DATA=y 51CONFIG_FEATURE_EXTRA_FILE_DATA=y
52CONFIG_FEATURE_IDENTIFY_OWNER=y 52CONFIG_FEATURE_IDENTIFY_OWNER=y
53CONFIG_FEATURE_READLINK2=y
53 54
54# 55#
55# Build Options 56# Build Options
@@ -295,8 +296,8 @@ CONFIG_PASTE=y
295CONFIG_PRINTENV=y 296CONFIG_PRINTENV=y
296CONFIG_PRINTF=y 297CONFIG_PRINTF=y
297CONFIG_PWD=y 298CONFIG_PWD=y
298# CONFIG_READLINK is not set 299CONFIG_READLINK=y
299# CONFIG_FEATURE_READLINK_FOLLOW is not set 300CONFIG_FEATURE_READLINK_FOLLOW=y
300CONFIG_REALPATH=y 301CONFIG_REALPATH=y
301CONFIG_RM=y 302CONFIG_RM=y
302CONFIG_RMDIR=y 303CONFIG_RMDIR=y
@@ -1113,6 +1114,7 @@ CONFIG_ASH_HELP=y
1113CONFIG_ASH_GETOPTS=y 1114CONFIG_ASH_GETOPTS=y
1114CONFIG_ASH_CMDCMD=y 1115CONFIG_ASH_CMDCMD=y
1115CONFIG_ASH_NOCONSOLE=y 1116CONFIG_ASH_NOCONSOLE=y
1117CONFIG_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#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_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
50CONFIG_FEATURE_EURO=y 50CONFIG_FEATURE_EURO=y
51CONFIG_FEATURE_EXTRA_FILE_DATA=y 51CONFIG_FEATURE_EXTRA_FILE_DATA=y
52CONFIG_FEATURE_IDENTIFY_OWNER=y 52CONFIG_FEATURE_IDENTIFY_OWNER=y
53CONFIG_FEATURE_READLINK2=y
53 54
54# 55#
55# Build Options 56# Build Options
@@ -295,8 +296,8 @@ CONFIG_PASTE=y
295CONFIG_PRINTENV=y 296CONFIG_PRINTENV=y
296CONFIG_PRINTF=y 297CONFIG_PRINTF=y
297CONFIG_PWD=y 298CONFIG_PWD=y
298# CONFIG_READLINK is not set 299CONFIG_READLINK=y
299# CONFIG_FEATURE_READLINK_FOLLOW is not set 300CONFIG_FEATURE_READLINK_FOLLOW=y
300CONFIG_REALPATH=y 301CONFIG_REALPATH=y
301CONFIG_RM=y 302CONFIG_RM=y
302CONFIG_RMDIR=y 303CONFIG_RMDIR=y
@@ -1113,6 +1114,7 @@ CONFIG_ASH_HELP=y
1113CONFIG_ASH_GETOPTS=y 1114CONFIG_ASH_GETOPTS=y
1114CONFIG_ASH_CMDCMD=y 1115CONFIG_ASH_CMDCMD=y
1115CONFIG_ASH_NOCONSOLE=y 1116CONFIG_ASH_NOCONSOLE=y
1117CONFIG_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);
407ssize_t mingw_read(int fd, void *buf, size_t count); 407ssize_t mingw_read(int fd, void *buf, size_t count);
408int mingw_close(int fd); 408int mingw_close(int fd);
409int pipe(int filedes[2]); 409int pipe(int filedes[2]);
410#if ENABLE_FEATURE_READLINK2
411ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
412#else
410NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM); 413NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM);
414#endif
411NOIMPL(setgid,gid_t gid UNUSED_PARAM); 415NOIMPL(setgid,gid_t gid UNUSED_PARAM);
412NOIMPL(setegid,gid_t gid UNUSED_PARAM); 416NOIMPL(setegid,gid_t gid UNUSED_PARAM);
413NOIMPL(setsid,void); 417NOIMPL(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
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;