aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2021-02-26 23:51:15 +0100
committerRon Yorston <rmy@pobox.com>2021-03-01 09:23:43 +0000
commit7d0e7ba3c7029a5d744e04c8318d234de5ebedcf (patch)
treec13f465d49ba84d88080db54c5eedbc94a0676b1
parentb2ea5c74c8e2a26f9d9e8978d41a2368693e5ff7 (diff)
downloadbusybox-w32-7d0e7ba3c7029a5d744e04c8318d234de5ebedcf.tar.gz
busybox-w32-7d0e7ba3c7029a5d744e04c8318d234de5ebedcf.tar.bz2
busybox-w32-7d0e7ba3c7029a5d744e04c8318d234de5ebedcf.zip
win32(symlink): fix logic to determine the type of the symlink
On Windows, there are file symlinks and directory symlinks. When trying to `opendir()` a symlink marked as `file`, it will fail. Even if the target is a directory. Because it's the wrong symlink type. To address this, our `symlink()` function calls `stat(target, ...)` to see whether the target exists and is a directory. The problem is that this `target` can be a relative path, and the link path can _also_ be a relative path. Example: `symlink("dir", "uh/oh")`. In this example, the target might say `dir`, but it is relative to `uh/oh`, i.e. we need to `stat("uh/dir", ...)`. This is necessary to pass the `cp` tests because they first create such a directory symlink and then try to copy it while dereferencing symlinks, i.e. calling `opendir()` on the symlink. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
-rw-r--r--win32/mingw.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/win32/mingw.c b/win32/mingw.c
index c9b72ae98..2e9a53393 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -1076,13 +1076,22 @@ int symlink(const char *target, const char *linkpath)
1076 DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; 1076 DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
1077 struct stat st; 1077 struct stat st;
1078 DECLARE_PROC_ADDR(BOOL, CreateSymbolicLinkA, LPCSTR, LPCSTR, DWORD); 1078 DECLARE_PROC_ADDR(BOOL, CreateSymbolicLinkA, LPCSTR, LPCSTR, DWORD);
1079 char *relative = NULL;
1079 1080
1080 if (!INIT_PROC_ADDR(kernel32.dll, CreateSymbolicLinkA)) { 1081 if (!INIT_PROC_ADDR(kernel32.dll, CreateSymbolicLinkA)) {
1081 return -1; 1082 return -1;
1082 } 1083 }
1083 1084
1084 if (stat(target, &st) != -1 && S_ISDIR(st.st_mode)) 1085 if (!is_absolute_path(target) && has_path(linkpath)) {
1086 /* make target's path relative to current directory */
1087 const char *name = bb_get_last_path_component_nostrip(linkpath);
1088 relative = xasprintf("%.*s%s",
1089 (int)(name - linkpath), linkpath, target);
1090 }
1091
1092 if (stat(relative ?: target, &st) != -1 && S_ISDIR(st.st_mode))
1085 flag |= SYMBOLIC_LINK_FLAG_DIRECTORY; 1093 flag |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1094 free(relative);
1086 1095
1087 retry: 1096 retry:
1088 if (!CreateSymbolicLinkA(linkpath, target, flag)) { 1097 if (!CreateSymbolicLinkA(linkpath, target, flag)) {