diff options
author | Ron Yorston <rmy@pobox.com> | 2021-02-12 14:11:01 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-02-12 14:11:01 +0000 |
commit | 7587b56c10a4d11fe434e3eaa51212113f09ec10 (patch) | |
tree | 219264f8c4079d13ab8c29d9d90f04b22e6470bc | |
parent | 1b61a02b5139a47e2e3ac8be5afca325d7b3cea7 (diff) | |
download | busybox-w32-7587b56c10a4d11fe434e3eaa51212113f09ec10.tar.gz busybox-w32-7587b56c10a4d11fe434e3eaa51212113f09ec10.tar.bz2 busybox-w32-7587b56c10a4d11fe434e3eaa51212113f09ec10.zip |
win32: implement symlink(2)
Provide an implementation of symlink(2).
Calls to symlink(2) will fail in default Windows installations unless
running with elevated privileges. Failure to create a symlink when
extracting files from an archive is therefore treated as a non-fatal
error.
There are two ways to permit the creation of symlinks:
- Edit security policy to give users the 'Create symbolic links'
privilege. Unfortunately this doesn't work for users who are an
Administrator.
- Enable developer mode, which is available in later versions of
Windows 10.
The ability to create symlinks is not available in Windows XP
or ReactOS.
-rw-r--r-- | archival/libarchive/unsafe_symlink_target.c | 30 | ||||
-rw-r--r-- | include/mingw.h | 2 | ||||
-rw-r--r-- | win32/mingw.c | 35 |
3 files changed, 55 insertions, 12 deletions
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c index b5f5a2670..8e4cd4380 100644 --- a/archival/libarchive/unsafe_symlink_target.c +++ b/archival/libarchive/unsafe_symlink_target.c | |||
@@ -5,12 +5,17 @@ | |||
5 | #include "libbb.h" | 5 | #include "libbb.h" |
6 | #include "bb_archive.h" | 6 | #include "bb_archive.h" |
7 | 7 | ||
8 | /* symlink may not be available for WIN32, just issue a warning */ | ||
9 | #if ENABLE_PLATFORM_MINGW32 | ||
10 | # undef bb_perror_msg_and_die | ||
11 | # define bb_perror_msg_and_die(...) bb_perror_msg(__VA_ARGS__) | ||
12 | #endif | ||
13 | |||
8 | void FAST_FUNC create_or_remember_link(llist_t **link_placeholders, | 14 | void FAST_FUNC create_or_remember_link(llist_t **link_placeholders, |
9 | const char *target, | 15 | const char *target, |
10 | const char *linkname, | 16 | const char *linkname, |
11 | int hard_link) | 17 | int hard_link) |
12 | { | 18 | { |
13 | #if !ENABLE_PLATFORM_MINGW32 | ||
14 | if (hard_link || target[0] == '/' || strstr(target, "..")) { | 19 | if (hard_link || target[0] == '/' || strstr(target, "..")) { |
15 | llist_add_to_end(link_placeholders, | 20 | llist_add_to_end(link_placeholders, |
16 | xasprintf("%c%s%c%s", hard_link, linkname, '\0', target) | 21 | xasprintf("%c%s%c%s", hard_link, linkname, '\0', target) |
@@ -23,16 +28,6 @@ void FAST_FUNC create_or_remember_link(llist_t **link_placeholders, | |||
23 | "sym", linkname, target | 28 | "sym", linkname, target |
24 | ); | 29 | ); |
25 | } | 30 | } |
26 | #else | ||
27 | if (hard_link) { | ||
28 | llist_add_to_end(link_placeholders, | ||
29 | xasprintf("%c%s%c%s", hard_link, linkname, '\0', target) | ||
30 | ); | ||
31 | return; | ||
32 | } | ||
33 | /* symlink isn't implemented for WIN32, just issue a warning */ | ||
34 | bb_perror_msg("can't create symlink '%s' to '%s'", linkname, target); | ||
35 | #endif | ||
36 | } | 31 | } |
37 | 32 | ||
38 | void FAST_FUNC create_links_from_list(llist_t *list) | 33 | void FAST_FUNC create_links_from_list(llist_t *list) |
@@ -42,11 +37,24 @@ void FAST_FUNC create_links_from_list(llist_t *list) | |||
42 | 37 | ||
43 | target = list->data + 1 + strlen(list->data + 1) + 1; | 38 | target = list->data + 1 + strlen(list->data + 1) + 1; |
44 | if ((*list->data ? link : symlink) (target, list->data + 1)) { | 39 | if ((*list->data ? link : symlink) (target, list->data + 1)) { |
40 | #if !ENABLE_PLATFORM_MINGW32 | ||
45 | /* shared message */ | 41 | /* shared message */ |
46 | bb_error_msg_and_die("can't create %slink '%s' to '%s'", | 42 | bb_error_msg_and_die("can't create %slink '%s' to '%s'", |
47 | *list->data ? "hard" : "sym", | 43 | *list->data ? "hard" : "sym", |
48 | list->data + 1, target | 44 | list->data + 1, target |
49 | ); | 45 | ); |
46 | #else | ||
47 | if (!*list->data) | ||
48 | bb_error_msg("can't create %slink '%s' to '%s'", | ||
49 | "sym", | ||
50 | list->data + 1, target | ||
51 | ); | ||
52 | else | ||
53 | bb_error_msg_and_die("can't create %slink '%s' to '%s'", | ||
54 | "hard", | ||
55 | list->data + 1, target | ||
56 | ); | ||
57 | #endif | ||
50 | } | 58 | } |
51 | list = list->link; | 59 | list = list->link; |
52 | } | 60 | } |
diff --git a/include/mingw.h b/include/mingw.h index 713205ef9..e2c02babf 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -440,7 +440,7 @@ NOIMPL(setsid,void); | |||
440 | NOIMPL(setuid,uid_t gid UNUSED_PARAM); | 440 | NOIMPL(setuid,uid_t gid UNUSED_PARAM); |
441 | NOIMPL(seteuid,uid_t gid UNUSED_PARAM); | 441 | NOIMPL(seteuid,uid_t gid UNUSED_PARAM); |
442 | unsigned int sleep(unsigned int seconds); | 442 | unsigned int sleep(unsigned int seconds); |
443 | NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM); | 443 | int symlink(const char *target, const char *linkpath); |
444 | static inline void sync(void) {} | 444 | static inline void sync(void) {} |
445 | long sysconf(int name); | 445 | long sysconf(int name); |
446 | IMPL(getpagesize,int,4096,void); | 446 | IMPL(getpagesize,int,4096,void); |
diff --git a/win32/mingw.c b/win32/mingw.c index 41dba9857..a6362333d 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -1063,6 +1063,41 @@ int link(const char *oldpath, const char *newpath) | |||
1063 | return 0; | 1063 | return 0; |
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY | ||
1067 | # define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1) | ||
1068 | #endif | ||
1069 | #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | ||
1070 | # define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2) | ||
1071 | #endif | ||
1072 | |||
1073 | int symlink(const char *target, const char *linkpath) | ||
1074 | { | ||
1075 | DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; | ||
1076 | struct stat st; | ||
1077 | DECLARE_PROC_ADDR(BOOL, CreateSymbolicLinkA, LPCSTR, LPCSTR, DWORD); | ||
1078 | |||
1079 | if (!INIT_PROC_ADDR(kernel32.dll, CreateSymbolicLinkA)) { | ||
1080 | return -1; | ||
1081 | } | ||
1082 | |||
1083 | if (stat(target, &st) != -1 && S_ISDIR(st.st_mode)) | ||
1084 | flag |= SYMBOLIC_LINK_FLAG_DIRECTORY; | ||
1085 | |||
1086 | retry: | ||
1087 | if (!CreateSymbolicLinkA(linkpath, target, flag)) { | ||
1088 | /* Old Windows versions see 'UNPRIVILEGED_CREATE' as an invalid | ||
1089 | * parameter. Retry without it. */ | ||
1090 | if ((flag & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) && | ||
1091 | GetLastError() == ERROR_INVALID_PARAMETER) { | ||
1092 | flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; | ||
1093 | goto retry; | ||
1094 | } | ||
1095 | errno = err_win_to_posix(); | ||
1096 | return -1; | ||
1097 | } | ||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1066 | static char *normalize_ntpathA(char *buf) | 1101 | static char *normalize_ntpathA(char *buf) |
1067 | { | 1102 | { |
1068 | /* fix absolute path prefixes */ | 1103 | /* fix absolute path prefixes */ |