diff options
author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2021-02-26 23:51:15 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-03-01 09:23:43 +0000 |
commit | 7d0e7ba3c7029a5d744e04c8318d234de5ebedcf (patch) | |
tree | c13f465d49ba84d88080db54c5eedbc94a0676b1 | |
parent | b2ea5c74c8e2a26f9d9e8978d41a2368693e5ff7 (diff) | |
download | busybox-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.c | 11 |
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)) { |