summaryrefslogtreecommitdiff
path: root/libarchive/archive_write_disk_windows.c
diff options
context:
space:
mode:
authorMartin Matuska <martin@matuska.org>2019-04-13 21:51:03 +0200
committerMartin Matuska <martin@matuska.org>2019-04-13 21:54:29 +0200
commitb17df5e194724f7e83fa028471f00db1a78f511a (patch)
tree7459ca085ab92ad808fd5fb333b536ab5539824e /libarchive/archive_write_disk_windows.c
parent40f72fed535be6a7236e91aef3aad641b71f9168 (diff)
downloadlibarchive-b17df5e194724f7e83fa028471f00db1a78f511a.tar.gz
Windows symlink bugfixes and improvements
Treat targets ending with /. and /.. as directory symlinks Explicitly test for file and directory symlinks Improve debug output on test failure Fix two memory allocations
Diffstat (limited to 'libarchive/archive_write_disk_windows.c')
-rw-r--r--libarchive/archive_write_disk_windows.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c
index 811e7772..b29389c1 100644
--- a/libarchive/archive_write_disk_windows.c
+++ b/libarchive/archive_write_disk_windows.c
@@ -558,8 +558,10 @@ la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)
set = 1;
f = la_GetFunctionKernel32("CreateHardLinkW");
}
- if (!f)
+ if (!f) {
+ errno = ENOTSUP;
return (0);
+ }
ret = (*f)(linkname, target, NULL);
if (!ret) {
/* Under windows 2000, it is necessary to remove
@@ -595,6 +597,7 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target) {
static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD);
static int set;
wchar_t *ttarget, *p;
+ int len;
DWORD attrs = 0;
DWORD flags = 0;
DWORD newflags = 0;
@@ -607,11 +610,16 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target) {
if (!f)
return (0);
+ len = wcslen(target);
+ if (len == 0) {
+ errno = EINVAL;
+ return(0);
+ }
/*
* When writing path targets, we need to translate slashes
* to backslashes
*/
- ttarget = malloc((wcslen(target) + 1) * sizeof(wchar_t));
+ ttarget = malloc((len + 1) * sizeof(wchar_t));
if (ttarget == NULL)
return(0);
@@ -628,23 +636,19 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target) {
*p = L'\0';
/*
- * If the target equals ".", ".." or ends with a backslash, it always
- * points to a directory. In this case we can safely set the directory
- * flag. All other symlinks are created as file symlinks.
+ * If the target equals ".", "..", ends with a backslash or a
+ * backslash followed by "." or ".." it always points to a directory.
+ * In this case we can safely set the directory flag.
+ * All other symlinks are created as file symlinks.
*/
- if (wcscmp(ttarget, L".") == 0 || wcscmp(ttarget, L"..") == 0 ||
- *(p - 1) == L'\\') {
+ if (*(p - 1) == L'\\' || (*(p - 1) == L'.' && (
+ len == 1 || *(p - 2) == L'\\' || ( *(p - 2) == L'.' && (
+ len == 2 || *(p - 3) == L'\\'))))) {
#if defined(SYMBOLIC_LINK_FLAG_DIRECTORY)
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
#else
flags |= 0x1;
#endif
- /* Now we remove trailing backslashes, if any */
- p--;
- while(*p == L'\\') {
- *p = L'\0';
- p--;
- }
}
#if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
@@ -1633,9 +1637,11 @@ create_filesystem_object(struct archive_write_disk *a)
#if HAVE_SYMLINK
return symlink(linkname, a->name) ? errno : 0;
#else
+ errno = 0;
r = la_CreateSymbolicLinkW((const wchar_t *)a->name, linkname);
if (r == 0) {
- la_dosmaperr(GetLastError());
+ if (errno == 0)
+ la_dosmaperr(GetLastError());
r = errno;
} else
r = 0;