From 7f7c83316849b5d24b93ace5c69ad39f539d26b1 Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Wed, 3 Apr 2019 23:13:35 +0200 Subject: [PATCH] Fix various symlink bugs with Windows symlinks tests: extend assertMakeSymlink with targetIsDir --- cpio/test/test_basic.c | 2 +- cpio/test/test_format_newc.c | 2 +- cpio/test/test_option_L_upper.c | 2 +- cpio/test/test_option_c.c | 2 +- libarchive/archive_write_disk_windows.c | 57 +++++++++++++++---- .../test_read_disk_directory_traversals.c | 24 ++++---- tar/test/test_basic.c | 2 +- tar/test/test_copy.c | 2 +- tar/test/test_option_H_upper.c | 10 ++-- tar/test/test_option_L_upper.c | 10 ++-- tar/test/test_option_U_upper.c | 12 ++-- tar/test/test_option_s.c | 2 +- tar/test/test_strip_components.c | 4 +- tar/test/test_symlink_dir.c | 22 +++---- test_utils/test_common.h | 6 +- test_utils/test_main.c | 48 +++++++++++----- 16 files changed, 130 insertions(+), 77 deletions(-) diff --git a/cpio/test/test_basic.c b/cpio/test/test_basic.c index 6e45d1856..855793fbb 100644 --- a/cpio/test/test_basic.c +++ b/cpio/test/test_basic.c @@ -173,7 +173,7 @@ DEFINE_TEST(test_basic) /* Symlink to above file. */ if (canSymlink()) { - assertMakeSymlink("symlink", "file"); + assertMakeSymlink("symlink", "file", 0); fprintf(filelist, "symlink\n"); if (is_LargeInode("symlink")) { strncat(result, diff --git a/cpio/test/test_format_newc.c b/cpio/test/test_format_newc.c index 258640443..2c6694267 100644 --- a/cpio/test/test_format_newc.c +++ b/cpio/test/test_format_newc.c @@ -114,7 +114,7 @@ DEFINE_TEST(test_format_newc) /* "symlink" */ if (canSymlink()) { - assertMakeSymlink("symlink", "file1"); + assertMakeSymlink("symlink", "file1", 0); fprintf(list, "symlink\n"); } diff --git a/cpio/test/test_option_L_upper.c b/cpio/test/test_option_L_upper.c index 1774343f6..7fd10cefc 100644 --- a/cpio/test/test_option_L_upper.c +++ b/cpio/test/test_option_L_upper.c @@ -51,7 +51,7 @@ DEFINE_TEST(test_option_L_upper) fprintf(filelist, "file\n"); /* Symlink to above file. */ - assertMakeSymlink("symlink", "file"); + assertMakeSymlink("symlink", "file", 0); fprintf(filelist, "symlink\n"); fclose(filelist); diff --git a/cpio/test/test_option_c.c b/cpio/test/test_option_c.c index fa47b7e27..013caed56 100644 --- a/cpio/test/test_option_c.c +++ b/cpio/test/test_option_c.c @@ -85,7 +85,7 @@ DEFINE_TEST(test_option_c) /* "symlink" */ if (canSymlink()) { - assertMakeSymlink("symlink", "file"); + assertMakeSymlink("symlink", "file", 0); fprintf(filelist, "symlink\n"); } diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c index 1155c3135..811e7772c 100644 --- a/libarchive/archive_write_disk_windows.c +++ b/libarchive/archive_write_disk_windows.c @@ -1454,28 +1454,45 @@ restore_entry(struct archive_write_disk *a) en = create_filesystem_object(a); } else if (en == EEXIST) { mode_t st_mode; + mode_t lst_mode; + BY_HANDLE_FILE_INFORMATION lst; /* * We know something is in the way, but we don't know what; * we need to find out before we go any further. */ int r = 0; + int dirlnk = 0; + /* * The SECURE_SYMLINK logic has already removed a * symlink to a dir if the client wants that. So * follow the symlink if we're creating a dir. - */ - if (S_ISDIR(a->mode)) - r = file_information(a, a->name, &a->st, &st_mode, 0); - /* * If it's not a dir (or it's a broken symlink), * then don't follow it. + * + * Windows distinguishes file and directory symlinks. + * A file symlink may erroneously point to a directory + * and a directory symlink to a file. Windows does not follow + * such symlinks. We always need both source and target + * information. */ - if (r != 0 || !S_ISDIR(a->mode)) - r = file_information(a, a->name, &a->st, &st_mode, 1); + r = file_information(a, a->name, &lst, &lst_mode, 1); if (r != 0) { archive_set_error(&a->archive, errno, "Can't stat existing object"); return (ARCHIVE_FAILED); + } else if (S_ISLNK(lst_mode)) { + if (lst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dirlnk = 1; + /* In case of a symlink we need target information */ + r = file_information(a, a->name, &a->st, &st_mode, 0); + if (r != 0) { + a->st = lst; + st_mode = lst_mode; + } + } else { + a->st = lst; + st_mode = lst_mode; } /* @@ -1499,8 +1516,15 @@ restore_entry(struct archive_write_disk *a) } if (!S_ISDIR(st_mode)) { - /* A non-dir is in the way, unlink it. */ - if (disk_unlink(a->name) != 0) { + /* Edge case: a directory symlink pointing to a file */ + if (dirlnk) { + if (disk_rmdir(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't unlink directory symlink"); + return (ARCHIVE_FAILED); + } + } else if (disk_unlink(a->name) != 0) { + /* A non-dir is in the way, unlink it. */ archive_set_error(&a->archive, errno, "Can't unlink already-existing object"); return (ARCHIVE_FAILED); @@ -1927,6 +1951,9 @@ check_symlinks(struct archive_write_disk *a) p = a->path_safe.s; while ((*pn != '\0') && (*p == *pn)) ++p, ++pn; + /* Skip leading backslashes */ + while (*pn == '\\') + ++pn; c = pn[0]; /* Keep going until we've checked the entire name. */ while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) { @@ -1944,8 +1971,8 @@ check_symlinks(struct archive_write_disk *a) } else if (S_ISLNK(st_mode)) { if (c == '\0') { /* - * Last element is symlink; remove it - * so we can overwrite it with the + * Last element is a file or directory symlink. + * Remove it so we can overwrite it with the * item being extracted. */ if (st.dwFileAttributes & @@ -1978,7 +2005,13 @@ check_symlinks(struct archive_write_disk *a) return (0); } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { /* User asked us to remove problems. */ - if (disk_unlink(a->name) != 0) { + if (st.dwFileAttributes & + FILE_ATTRIBUTE_DIRECTORY) { + r = disk_rmdir(a->name); + } else { + r = disk_unlink(a->name); + } + if (r != 0) { archive_set_error(&a->archive, 0, "Cannot remove intervening " "symlink %ls", a->name); @@ -1994,6 +2027,8 @@ check_symlinks(struct archive_write_disk *a) return (ARCHIVE_FAILED); } } + pn[0] = c; + pn++; } pn[0] = c; /* We've checked and/or cleaned the whole path, so remember it. */ diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c index 82579b23c..1e41c3caa 100644 --- a/libarchive/test/test_read_disk_directory_traversals.c +++ b/libarchive/test/test_read_disk_directory_traversals.c @@ -570,13 +570,13 @@ test_symlink_hybrid(void) assertMakeDir("h", 0755); assertChdir("h"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1/"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); assert((ae = archive_entry_new()) != NULL); @@ -727,13 +727,13 @@ test_symlink_logical(void) assertMakeDir("l", 0755); assertChdir("l"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1/"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); /* Note: this test uses archive_read_next_header() @@ -961,8 +961,8 @@ test_symlink_logical_loop(void) assertMakeDir("d1/d2/d3", 0755); assertMakeDir("d2", 0755); assertMakeFile("d2/file1", 0644, "d2/file1"); - assertMakeSymlink("d1/d2/ld1", "../../d1/"); - assertMakeSymlink("d1/d2/ld2", "../../d2/"); + assertMakeSymlink("d1/d2/ld1", "../../d1", 1); + assertMakeSymlink("d1/d2/ld2", "../../d2", 1); assertChdir(".."); assert((ae = archive_entry_new()) != NULL); diff --git a/tar/test/test_basic.c b/tar/test/test_basic.c index 0008e1cfb..91282cde9 100644 --- a/tar/test/test_basic.c +++ b/tar/test/test_basic.c @@ -42,7 +42,7 @@ make_files(void) /* Symlink to above file. */ if (canSymlink()) - assertMakeSymlink("symlink", "file"); + assertMakeSymlink("symlink", "file", 0); /* Directory. */ assertMakeDir("dir", 0775); diff --git a/tar/test/test_copy.c b/tar/test/test_copy.c index e6e31f452..1e59e1929 100644 --- a/tar/test/test_copy.c +++ b/tar/test/test_copy.c @@ -176,7 +176,7 @@ create_tree(void) sprintf(buff, "s/%s", filenames[i]); sprintf(buff2, "../f/%s", filenames[i]); failure("buff=\"%s\" buff2=\"%s\"", buff, buff2); - assertMakeSymlink(buff, buff2); + assertMakeSymlink(buff, buff2, 0); } /* Create a dir named "d/abcdef...". */ buff[0] = 'd'; diff --git a/tar/test/test_option_H_upper.c b/tar/test/test_option_H_upper.c index adc294b55..7c201ce26 100644 --- a/tar/test/test_option_H_upper.c +++ b/tar/test/test_option_H_upper.c @@ -39,13 +39,13 @@ DEFINE_TEST(test_option_H_upper) assertMakeDir("in", 0755); assertChdir("in"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); /* Test 1: Without -H */ diff --git a/tar/test/test_option_L_upper.c b/tar/test/test_option_L_upper.c index f5a3c5ab4..83f69d085 100644 --- a/tar/test/test_option_L_upper.c +++ b/tar/test/test_option_L_upper.c @@ -39,13 +39,13 @@ DEFINE_TEST(test_option_L_upper) assertMakeDir("in", 0755); assertChdir("in"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); /* Test 1: Without -L */ diff --git a/tar/test/test_option_U_upper.c b/tar/test/test_option_U_upper.c index 2c43e002d..832054860 100644 --- a/tar/test/test_option_U_upper.c +++ b/tar/test/test_option_U_upper.c @@ -79,7 +79,7 @@ DEFINE_TEST(test_option_U_upper) assertMakeDir("test3", 0755); assertChdir("test3"); assertMakeDir("realDir", 0755); - assertMakeSymlink("d1", "realDir"); + assertMakeSymlink("d1", "realDir", 1); r = systemf("%s -xf ../archive.tar d1/file1 >test.out 2>test.err", testprog); assert(r != 0); assertIsSymlink("d1", "realDir"); @@ -92,7 +92,7 @@ DEFINE_TEST(test_option_U_upper) assertMakeDir("test4", 0755); assertChdir("test4"); assertMakeDir("realDir", 0755); - assertMakeSymlink("d1", "realDir"); + assertMakeSymlink("d1", "realDir", 1); assertEqualInt(0, systemf("%s -xUf ../archive.tar >test.out 2>test.err", testprog)); assertIsDir("d1", -1); @@ -105,7 +105,7 @@ DEFINE_TEST(test_option_U_upper) assertMakeDir("test5", 0755); assertChdir("test5"); assertMakeDir("realDir", 0755); - assertMakeSymlink("d1", "realDir"); + assertMakeSymlink("d1", "realDir", 1); assertEqualInt(0, systemf("%s -xPf ../archive.tar d1/file1 >test.out 2>test.err", testprog)); assertIsSymlink("d1", "realDir"); @@ -118,7 +118,7 @@ DEFINE_TEST(test_option_U_upper) assertMakeDir("test6", 0755); assertChdir("test6"); assertMakeDir("realDir", 0755); - assertMakeSymlink("d1", "realDir"); + assertMakeSymlink("d1", "realDir", 1); assertEqualInt(0, systemf("%s -xPUf ../archive.tar d1/file1 >test.out 2>test.err", testprog)); assertIsSymlink("d1", "realDir"); @@ -132,7 +132,7 @@ DEFINE_TEST(test_option_U_upper) assertChdir("test7"); assertMakeDir("d1", 0755); assertMakeFile("d1/realfile1", 0644, "realfile1"); - assertMakeSymlink("d1/file1", "d1/realfile1"); + assertMakeSymlink("d1/file1", "d1/realfile1", 0); assertEqualInt(0, systemf("%s -xf ../archive.tar d1/file1 >test.out 2>test.err", testprog)); assertIsReg("d1/file1", umasked(0644)); @@ -147,7 +147,7 @@ DEFINE_TEST(test_option_U_upper) assertChdir("test8"); assertMakeDir("d1", 0755); assertMakeFile("d1/realfile1", 0644, "realfile1"); - assertMakeSymlink("d1/file1", "d1/realfile1"); + assertMakeSymlink("d1/file1", "d1/realfile1", 0); assertEqualInt(0, systemf("%s -xPUf ../archive.tar d1/file1 >test.out 2>test.err", testprog)); assertIsReg("d1/file1", umasked(0644)); diff --git a/tar/test/test_option_s.c b/tar/test/test_option_s.c index ee8332f34..a08966068 100644 --- a/tar/test/test_option_s.c +++ b/tar/test/test_option_s.c @@ -36,7 +36,7 @@ DEFINE_TEST(test_option_s) assertMakeFile("in/d1/bar", 0644, "bar"); if (canSymlink()) { assertMakeFile("in/d1/realfile", 0644, "realfile"); - assertMakeSymlink("in/d1/symlink", "realfile"); + assertMakeSymlink("in/d1/symlink", "realfile", 0); } assertMakeFile("in/d1/hardlink1", 0644, "hardlinkedfile"); assertMakeHardlink("in/d1/hardlink2", "in/d1/hardlink1"); diff --git a/tar/test/test_strip_components.c b/tar/test/test_strip_components.c index d195af1b3..e1d71ddc5 100644 --- a/tar/test/test_strip_components.c +++ b/tar/test/test_strip_components.c @@ -36,8 +36,8 @@ DEFINE_TEST(test_strip_components) assertMakeHardlink("l1", "d1/d2/f1"); assertMakeHardlink("d1/l2", "d1/d2/f1"); if (canSymlink()) { - assertMakeSymlink("s1", "d1/d2/f1"); - assertMakeSymlink("d1/s2", "d2/f1"); + assertMakeSymlink("s1", "d1/d2/f1", 0); + assertMakeSymlink("d1/s2", "d2/f1", 0); } assertChdir(".."); diff --git a/tar/test/test_symlink_dir.c b/tar/test/test_symlink_dir.c index 852e00b37..485ab32f8 100644 --- a/tar/test/test_symlink_dir.c +++ b/tar/test/test_symlink_dir.c @@ -66,22 +66,22 @@ DEFINE_TEST(test_symlink_dir) /* "dir" is a symlink to an existing "dest1/real_dir" */ assertMakeDir("dest1/real_dir", 0755); if (canSymlink()) { - assertMakeSymlink("dest1/dir", "real_dir"); + assertMakeSymlink("dest1/dir", "real_dir", 1); /* "dir2" is a symlink to a non-existing "real_dir2" */ - assertMakeSymlink("dest1/dir2", "real_dir2"); + assertMakeSymlink("dest1/dir2", "real_dir2", 1); } else { skipping("Symlinks are not supported on this platform"); } /* "dir3" is a symlink to an existing "non_dir3" */ assertMakeFile("dest1/non_dir3", 0755, "abcdef"); if (canSymlink()) - assertMakeSymlink("dest1/dir3", "non_dir3"); + assertMakeSymlink("dest1/dir3", "non_dir3", 1); /* "file" is a symlink to existing "real_file" */ assertMakeFile("dest1/real_file", 0755, "abcdefg"); if (canSymlink()) { - assertMakeSymlink("dest1/file", "real_file"); + assertMakeSymlink("dest1/file", "real_file", 0); /* "file2" is a symlink to non-existing "real_file2" */ - assertMakeSymlink("dest1/file2", "real_file2"); + assertMakeSymlink("dest1/file2", "real_file2", 0); } assertEqualInt(0, systemf("%s -xf test.tar -C dest1", testprog)); @@ -108,26 +108,26 @@ DEFINE_TEST(test_symlink_dir) /* "dir" is a symlink to existing "real_dir" */ assertMakeDir("dest2/real_dir", 0755); if (canSymlink()) - assertMakeSymlink("dest2/dir", "real_dir"); + assertMakeSymlink("dest2/dir", "real_dir", 1); /* "dir2" is a symlink to a non-existing "real_dir2" */ if (canSymlink()) - assertMakeSymlink("dest2/dir2", "real_dir2"); + assertMakeSymlink("dest2/dir2", "real_dir2", 1); /* "dir3" is a symlink to an existing "non_dir3" */ assertMakeFile("dest2/non_dir3", 0755, "abcdefgh"); if (canSymlink()) - assertMakeSymlink("dest2/dir3", "non_dir3"); + assertMakeSymlink("dest2/dir3", "non_dir3", 1); /* "file" is a symlink to existing "real_file" */ assertMakeFile("dest2/real_file", 0755, "abcdefghi"); if (canSymlink()) - assertMakeSymlink("dest2/file", "real_file"); + assertMakeSymlink("dest2/file", "real_file", 0); /* "file2" is a symlink to non-existing "real_file2" */ if (canSymlink()) - assertMakeSymlink("dest2/file2", "real_file2"); + assertMakeSymlink("dest2/file2", "real_file2", 0); assertEqualInt(0, systemf("%s -xPf test.tar -C dest2", testprog)); /* "dir4" is a symlink to existing "real_dir" */ if (canSymlink()) - assertMakeSymlink("dest2/dir4", "real_dir"); + assertMakeSymlink("dest2/dir4", "real_dir", 1); assertEqualInt(0, systemf("%s -xPf test2.tar -C dest2", testprog)); /* dest2/dir and dest2/dir4 symlinks should be followed */ diff --git a/test_utils/test_common.h b/test_utils/test_common.h index 4ebfdb0cd..154a6964d 100644 --- a/test_utils/test_common.h +++ b/test_utils/test_common.h @@ -231,8 +231,8 @@ assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) #define assertMakeHardlink(newfile, oldfile) \ assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) -#define assertMakeSymlink(newfile, linkto) \ - assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertMakeSymlink(newfile, linkto, targetIsDir) \ + assertion_make_symlink(__FILE__, __LINE__, newfile, linkto, targetIsDir) #define assertSetNodump(path) \ assertion_set_nodump(__FILE__, __LINE__, path) #define assertUmask(mask) \ @@ -293,7 +293,7 @@ int assertion_is_symlink(const char *, int, const char *, const char *); int assertion_make_dir(const char *, int, const char *, int); int assertion_make_file(const char *, int, const char *, int, int, const void *); int assertion_make_hardlink(const char *, int, const char *newpath, const char *); -int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_make_symlink(const char *, int, const char *newpath, const char *, int); int assertion_non_empty_file(const char *, int, const char *); int assertion_set_nodump(const char *, int, const char *); int assertion_text_file_contents(const char *, int, const char *buff, const char *f); diff --git a/test_utils/test_main.c b/test_utils/test_main.c index 6f4dd3a1a..91effdf58 100644 --- a/test_utils/test_main.c +++ b/test_utils/test_main.c @@ -211,13 +211,15 @@ GetFunctionKernel32(const char *name) } static int -my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) +my_CreateSymbolicLinkA(const char *linkname, const char *target, + int targetIsDir) { static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); DWORD attrs; static int set; int ret, tmpflags; - char *tgt, *p; + int flags = 0; + char *src, *tgt, *p; if (!set) { set = 1; f = GetFunctionKernel32("CreateSymbolicLinkA"); @@ -228,10 +230,26 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) tgt = malloc(strlen(target) + 1); if (tgt == NULL) return (0); + src = malloc(strlen(linkname) + 1); + if (src == NULL) { + free(tgt); + return (0); + } /* * Translate slashes to backslashes */ + p = src; + while(*linkname != '\0') { + if (*linkname == '/') + *p = '\\'; + else + *p = *linkname; + linkname++; + p++; + } + *p = '\0'; + p = tgt; while(*target != '\0') { if (*target == '/') @@ -247,19 +265,12 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) * If the target equals ".", ".." or ends with a slash, it always * points to a directory. In this case we can set the directory flag. */ - if (strcmp(tgt, ".") == 0 || strcmp(tgt, "..") == 0 || - *(p - 1) == '\\') { + if (targetIsDir) { #if defined(SYMBOLIC_LINK_FLAG_DIRECTORY) flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; #else flags |= 0x1; #endif - /* Now we remove trailing backslashes */ - p--; - while(*p == '\\') { - *p = '\0'; - p--; - } } #if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) @@ -278,14 +289,15 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) DeleteFileA(linkname); } - ret = (*f)(linkname, tgt, tmpflags); + ret = (*f)(src, tgt, tmpflags); /* * Prior to Windows 10 the SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE * is not undestood */ if (!ret) - ret = (*f)(linkname, tgt, flags); + ret = (*f)(src, tgt, flags); + free(src); free(tgt); return (ret); } @@ -1928,20 +1940,26 @@ assertion_make_hardlink(const char *file, int line, return(0); } -/* Create a symlink and report any failures. */ +/* + * Create a symlink and report any failures. + * + * Windows symlinks need to know if the target is a directory. + */ int assertion_make_symlink(const char *file, int line, - const char *newpath, const char *linkto) + const char *newpath, const char *linkto, int targetIsDir) { #if defined(_WIN32) && !defined(__CYGWIN__) - int targetIsDir = 0; /* TODO: Fix this */ assertion_count(file, line); if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) return (1); #elif HAVE_SYMLINK + (void)targetIsDir; /* UNUSED */ assertion_count(file, line); if (0 == symlink(linkto, newpath)) return (1); +#else + (void)targetIsDir; /* UNUSED */ #endif failure_start(file, line, "Could not create symlink"); logprintf(" New link: %s\n", newpath); -- 2.47.2