summaryrefslogtreecommitdiff
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
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
-rw-r--r--cpio/test/test_basic.c2
-rw-r--r--cpio/test/test_gcpio_compat.c2
-rw-r--r--cpio/test/test_option_L_upper.c4
-rw-r--r--libarchive/archive_write_disk_windows.c34
-rw-r--r--libarchive/test/test_read_extract.c2
-rw-r--r--libarchive/test/test_write_disk_symlink.c129
-rw-r--r--tar/test/test_basic.c2
-rw-r--r--tar/test/test_copy.c2
-rw-r--r--tar/test/test_option_H_upper.c26
-rw-r--r--tar/test/test_option_L_upper.c18
-rw-r--r--tar/test/test_option_U_upper.c6
-rw-r--r--tar/test/test_option_s.c16
-rw-r--r--tar/test/test_strip_components.c4
-rw-r--r--tar/test/test_symlink_dir.c4
-rw-r--r--test_utils/test_common.h6
-rw-r--r--test_utils/test_main.c82
16 files changed, 261 insertions, 78 deletions
diff --git a/cpio/test/test_basic.c b/cpio/test/test_basic.c
index 855793fb..a8fedf89 100644
--- a/cpio/test/test_basic.c
+++ b/cpio/test/test_basic.c
@@ -46,7 +46,7 @@ verify_files(const char *msg)
/* Symlink */
if (canSymlink())
- assertIsSymlink("symlink", "file");
+ assertIsSymlink("symlink", "file", 0);
/* Another file with 1 link and different permissions. */
failure(msg);
diff --git a/cpio/test/test_gcpio_compat.c b/cpio/test/test_gcpio_compat.c
index 461e427c..9bb98899 100644
--- a/cpio/test/test_gcpio_compat.c
+++ b/cpio/test/test_gcpio_compat.c
@@ -71,7 +71,7 @@ unpack_test(const char *from, const char *options, const char *se)
/* Symlink */
if (canSymlink())
- assertIsSymlink("symlink", "file");
+ assertIsSymlink("symlink", "file", 0);
/* dir */
assertIsDir("dir", 0775);
diff --git a/cpio/test/test_option_L_upper.c b/cpio/test/test_option_L_upper.c
index bf3a9c43..cab41b61 100644
--- a/cpio/test/test_option_L_upper.c
+++ b/cpio/test/test_option_L_upper.c
@@ -63,7 +63,7 @@ DEFINE_TEST(test_option_L_upper)
assertTextFileContents("1 block\n", "copy.err");
failure("Regular -p without -L should preserve symlinks.");
- assertIsSymlink("copy/symlink", NULL);
+ assertIsSymlink("copy/symlink", NULL, 0);
r = systemf(CAT " filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog);
assertEqualInt(r, 0);
@@ -86,7 +86,7 @@ DEFINE_TEST(test_option_L_upper)
assertTextFileContents("1 block\n", "unpack.err");
assertChdir("..");
- assertIsSymlink("unpack/symlink", NULL);
+ assertIsSymlink("unpack/symlink", NULL, 0);
r = systemf(CAT " filelist | %s -oL >archive-L.out 2>archive-L.err", testprog);
failure("Error invoking %s -oL", testprog);
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;
diff --git a/libarchive/test/test_read_extract.c b/libarchive/test/test_read_extract.c
index c537e4f9..cd06096e 100644
--- a/libarchive/test/test_read_extract.c
+++ b/libarchive/test/test_read_extract.c
@@ -161,7 +161,7 @@ DEFINE_TEST(test_read_extract)
assertIsDir("dir4/b", 0755);
assertIsDir("dir4/c", 0711);
if (canSymlink())
- assertIsSymlink("symlink", "file");
+ assertIsSymlink("symlink", "file", 0);
free(buff);
free(file_buff);
diff --git a/libarchive/test/test_write_disk_symlink.c b/libarchive/test/test_write_disk_symlink.c
index 13089c78..43796a45 100644
--- a/libarchive/test/test_write_disk_symlink.c
+++ b/libarchive/test/test_write_disk_symlink.c
@@ -99,6 +99,116 @@ DEFINE_TEST(test_write_disk_symlink)
assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
archive_entry_free(ae);
+ /* Symbolic link: dot -> . */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, ".");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: dotdot -> .. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dotdot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "..");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: slash -> / */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "slash");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "/");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: sldot -> /. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "sldot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "/.");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: sldotdot -> /.. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "sldotdot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "/..");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Dir: d1 */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "d1");
+ archive_entry_set_mode(ae, AE_IFDIR | 0777);
+ archive_entry_unset_size(ae);
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: d1nosl -> d1 */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "d1nosl");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "d1");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: d1slash -> d1/ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "d1slash");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "d1/");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: d1sldot -> d1/. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "d1sldot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "d1/.");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+ /* Symbolic link: d1slddot -> d1/.. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "d1slddot");
+ archive_entry_set_mode(ae, AE_IFLNK | 0642);
+ archive_entry_unset_size(ae);
+ archive_entry_copy_symlink(ae, "d1/..");
+ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
+ if (r >= ARCHIVE_WARN)
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ archive_entry_free(ae);
+
+
assertEqualInt(ARCHIVE_OK, archive_write_free(ad));
/* Test the entries on disk. */
@@ -107,11 +217,26 @@ DEFINE_TEST(test_write_disk_symlink)
assertIsReg("link1a", -1);
assertFileSize("link1a", sizeof(data));
assertFileNLinks("link1a", 1);
- assertIsSymlink("link1b", "link1a");
+ assertIsSymlink("link1b", "link1a", 0);
/* Test #2: Should produce identical results to test #1 */
assertIsReg("link2a", -1);
assertFileSize("link2a", sizeof(data));
assertFileNLinks("link2a", 1);
- assertIsSymlink("link2b", "link2a");
+ assertIsSymlink("link2b", "link2a", 0);
+
+ /* Test #3: Special symlinks */
+ assertIsSymlink("dot", ".", 1);
+ assertIsSymlink("dotdot", "..", 1);
+ assertIsSymlink("slash", "/", 1);
+ assertIsSymlink("sldot", "/.", 1);
+ assertIsSymlink("sldotdot", "/..", 1);
+
+ /* Test #4: Directory symlink mixed with . and .. */
+ assertIsDir("d1", -1);
+ /* On Windows, d1nosl should be a file symlink */
+ assertIsSymlink("d1nosl", "d1", 0);
+ assertIsSymlink("d1slash", "d1/", 1);
+ assertIsSymlink("d1sldot", "d1/.", 1);
+ assertIsSymlink("d1slddot", "d1/..", 1);
}
diff --git a/tar/test/test_basic.c b/tar/test/test_basic.c
index 91282cde..9bb966a0 100644
--- a/tar/test/test_basic.c
+++ b/tar/test/test_basic.c
@@ -78,7 +78,7 @@ verify_files(const char *target)
/* Symlink */
if (canSymlink())
- assertIsSymlink("symlink", "file");
+ assertIsSymlink("symlink", "file", 0);
/* dir */
failure("%s", target);
diff --git a/tar/test/test_copy.c b/tar/test/test_copy.c
index 1e59e192..b828666b 100644
--- a/tar/test/test_copy.c
+++ b/tar/test/test_copy.c
@@ -222,7 +222,7 @@ verify_tree(size_t limit)
sprintf(name1, "s/%s", filenames[i]);
sprintf(name2, "../f/%s", filenames[i]);
if (strlen(name2) <= limit)
- assertIsSymlink(name1, name2);
+ assertIsSymlink(name1, name2, 0);
}
/* Verify dir "d/abcdef...". */
diff --git a/tar/test/test_option_H_upper.c b/tar/test/test_option_H_upper.c
index 7c201ce2..2c2ad33c 100644
--- a/tar/test/test_option_H_upper.c
+++ b/tar/test/test_option_H_upper.c
@@ -55,11 +55,11 @@ DEFINE_TEST(test_option_H_upper)
assertChdir("test1");
assertEqualInt(0,
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
- assertIsSymlink("ld1", "d1");
- assertIsSymlink("d1/link1", "file1");
- assertIsSymlink("d1/linkX", "fileX");
- assertIsSymlink("link2", "d1/file2");
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("ld1", "d1", 1);
+ assertIsSymlink("d1/link1", "file1", 0);
+ assertIsSymlink("d1/linkX", "fileX", 0);
+ assertIsSymlink("link2", "d1/file2", 0);
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
/* Test 2: With -H, no symlink on command line. */
@@ -69,11 +69,11 @@ DEFINE_TEST(test_option_H_upper)
assertChdir("test2");
assertEqualInt(0,
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
- assertIsSymlink("ld1", "d1");
- assertIsSymlink("d1/link1", "file1");
- assertIsSymlink("d1/linkX", "fileX");
- assertIsSymlink("link2", "d1/file2");
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("ld1", "d1", 1);
+ assertIsSymlink("d1/link1", "file1", 0);
+ assertIsSymlink("d1/linkX", "fileX", 0);
+ assertIsSymlink("link2", "d1/file2", 0);
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
/* Test 3: With -H, some symlinks on command line. */
@@ -84,9 +84,9 @@ DEFINE_TEST(test_option_H_upper)
assertEqualInt(0,
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
assertIsDir("ld1", umasked(0755));
- assertIsSymlink("d1/linkX", "fileX");
- assertIsSymlink("d1/link1", "file1");
+ assertIsSymlink("d1/linkX", "fileX", 0);
+ assertIsSymlink("d1/link1", "file1", 0);
assertIsReg("link2", umasked(0644));
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
}
diff --git a/tar/test/test_option_L_upper.c b/tar/test/test_option_L_upper.c
index 83f69d08..5697b0f2 100644
--- a/tar/test/test_option_L_upper.c
+++ b/tar/test/test_option_L_upper.c
@@ -55,11 +55,11 @@ DEFINE_TEST(test_option_L_upper)
assertChdir("test1");
assertEqualInt(0,
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
- assertIsSymlink("ld1", "d1");
- assertIsSymlink("d1/link1", "file1");
- assertIsSymlink("d1/linkX", "fileX");
- assertIsSymlink("link2", "d1/file2");
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("ld1", "d1", 1);
+ assertIsSymlink("d1/link1", "file1", 0);
+ assertIsSymlink("d1/linkX", "fileX", 0);
+ assertIsSymlink("link2", "d1/file2", 0);
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
/* Test 2: With -L, no symlink on command line. */
@@ -71,9 +71,9 @@ DEFINE_TEST(test_option_L_upper)
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
assertIsDir("ld1", umasked(0755));
assertIsReg("d1/link1", umasked(0644));
- assertIsSymlink("d1/linkX", "fileX");
+ assertIsSymlink("d1/linkX", "fileX", 0);
assertIsReg("link2", umasked(0644));
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
/* Test 3: With -L, some symlinks on command line. */
@@ -85,8 +85,8 @@ DEFINE_TEST(test_option_L_upper)
systemf("%s -xf archive.tar >c.out 2>c.err", testprog));
assertIsDir("ld1", umasked(0755));
assertIsReg("d1/link1", umasked(0644));
- assertIsSymlink("d1/linkX", "fileX");
+ assertIsSymlink("d1/linkX", "fileX", 0);
assertIsReg("link2", umasked(0644));
- assertIsSymlink("linkY", "d1/fileY");
+ assertIsSymlink("linkY", "d1/fileY", 0);
assertChdir("..");
}
diff --git a/tar/test/test_option_U_upper.c b/tar/test/test_option_U_upper.c
index 83205486..d864e13c 100644
--- a/tar/test/test_option_U_upper.c
+++ b/tar/test/test_option_U_upper.c
@@ -82,7 +82,7 @@ DEFINE_TEST(test_option_U_upper)
assertMakeSymlink("d1", "realDir", 1);
r = systemf("%s -xf ../archive.tar d1/file1 >test.out 2>test.err", testprog);
assert(r != 0);
- assertIsSymlink("d1", "realDir");
+ assertIsSymlink("d1", "realDir", 1);
assertFileNotExists("d1/file1");
assertEmptyFile("test.out");
assertNonEmptyFile("test.err");
@@ -108,7 +108,7 @@ DEFINE_TEST(test_option_U_upper)
assertMakeSymlink("d1", "realDir", 1);
assertEqualInt(0,
systemf("%s -xPf ../archive.tar d1/file1 >test.out 2>test.err", testprog));
- assertIsSymlink("d1", "realDir");
+ assertIsSymlink("d1", "realDir", 1);
assertFileContents("d1/file1", 8, "d1/file1");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
@@ -121,7 +121,7 @@ DEFINE_TEST(test_option_U_upper)
assertMakeSymlink("d1", "realDir", 1);
assertEqualInt(0,
systemf("%s -xPUf ../archive.tar d1/file1 >test.out 2>test.err", testprog));
- assertIsSymlink("d1", "realDir");
+ assertIsSymlink("d1", "realDir", 1);
assertFileContents("d1/file1", 8, "d1/file1");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
diff --git a/tar/test/test_option_s.c b/tar/test/test_option_s.c
index a0896606..09c72ee7 100644
--- a/tar/test/test_option_s.c
+++ b/tar/test/test_option_s.c
@@ -109,14 +109,14 @@ DEFINE_TEST(test_option_s)
testprog, testprog);
assertFileContents("realfile", 8, "test6a/in/d2/realfile");
assertFileContents("realfile", 8, "test6a/in/d2/symlink");
- assertIsSymlink("test6a/in/d2/symlink", "realfile");
+ assertIsSymlink("test6a/in/d2/symlink", "realfile", 0);
/* At creation time. */
assertMakeDir("test6b", 0755);
systemf("%s -cf - -s /d1/d2/ in/d1 | %s -xf - -C test6b",
testprog, testprog);
assertFileContents("realfile", 8, "test6b/in/d2/realfile");
assertFileContents("realfile", 8, "test6b/in/d2/symlink");
- assertIsSymlink("test6b/in/d2/symlink", "realfile");
+ assertIsSymlink("test6b/in/d2/symlink", "realfile", 0);
}
/*
@@ -129,14 +129,14 @@ DEFINE_TEST(test_option_s)
testprog, testprog);
assertFileContents("realfile", 8, "test7a/in/d1/realfile-renamed");
assertFileContents("realfile", 8, "test7a/in/d1/symlink");
- assertIsSymlink("test7a/in/d1/symlink", "realfile-renamed");
+ assertIsSymlink("test7a/in/d1/symlink", "realfile-renamed", 0);
/* At creation. */
assertMakeDir("test7b", 0755);
systemf("%s -cf - -s /realfile/realfile-renamed/ in/d1 | %s -xf - -C test7b",
testprog, testprog);
assertFileContents("realfile", 8, "test7b/in/d1/realfile-renamed");
assertFileContents("realfile", 8, "test7b/in/d1/symlink");
- assertIsSymlink("test7b/in/d1/symlink", "realfile-renamed");
+ assertIsSymlink("test7b/in/d1/symlink", "realfile-renamed", 0);
}
/*
@@ -192,7 +192,7 @@ DEFINE_TEST(test_option_s)
assertFileContents("realfile", 8, "test10a/in/d1/foo");
assertFileContents("foo", 3, "test10a/in/d1/realfile");
assertFileContents("foo", 3, "test10a/in/d1/symlink");
- assertIsSymlink("test10a/in/d1/symlink", "realfile");
+ assertIsSymlink("test10a/in/d1/symlink", "realfile", 0);
/* At creation. */
assertMakeDir("test10b", 0755);
systemf("%s -cf - -s /realfile/foo/S -s /foo/realfile/ in/d1 | %s -xf - -C test10b",
@@ -200,7 +200,7 @@ DEFINE_TEST(test_option_s)
assertFileContents("realfile", 8, "test10b/in/d1/foo");
assertFileContents("foo", 3, "test10b/in/d1/realfile");
assertFileContents("foo", 3, "test10b/in/d1/symlink");
- assertIsSymlink("test10b/in/d1/symlink", "realfile");
+ assertIsSymlink("test10b/in/d1/symlink", "realfile", 0);
}
/*
@@ -214,7 +214,7 @@ DEFINE_TEST(test_option_s)
assertFileContents("foo", 3, "test11a/in/d1/foo");
assertFileContents("realfile", 8, "test11a/in/d1/realfile");
assertFileContents("foo", 3, "test11a/in/d1/symlink");
- assertIsSymlink("test11a/in/d1/symlink", "foo");
+ assertIsSymlink("test11a/in/d1/symlink", "foo", 0);
/* At creation. */
assertMakeDir("test11b", 0755);
systemf("%s -cf - -s /realfile/foo/R in/d1 | %s -xf - -C test11b",
@@ -222,7 +222,7 @@ DEFINE_TEST(test_option_s)
assertFileContents("foo", 3, "test11b/in/d1/foo");
assertFileContents("realfile", 8, "test11b/in/d1/realfile");
assertFileContents("foo", 3, "test11b/in/d1/symlink");
- assertIsSymlink("test11b/in/d1/symlink", "foo");
+ assertIsSymlink("test11b/in/d1/symlink", "foo", 0);
}
/*
diff --git a/tar/test/test_strip_components.c b/tar/test/test_strip_components.c
index caf45a3e..090fb0db 100644
--- a/tar/test/test_strip_components.c
+++ b/tar/test/test_strip_components.c
@@ -65,7 +65,7 @@ DEFINE_TEST(test_strip_components)
/* If platform supports symlinks, target/s2 is a broken symlink. */
/* If platform does not support symlink, target/s2 doesn't exist. */
if (canSymlink())
- assertIsSymlink("target/s2", "d2/f1");
+ assertIsSymlink("target/s2", "d2/f1", 0);
else
assertFileNotExists("target/s2");
failure("d0/d1/d2 should be extracted");
@@ -123,7 +123,7 @@ DEFINE_TEST(test_strip_components)
/* If platform supports symlinks, target/s2 is included. */
if (canSymlink()) {
failure("d0/d1/s2 is a symlink to something included in archive");
- assertIsSymlink("target2/s2", "d2/f1");
+ assertIsSymlink("target2/s2", "d2/f1", 0);
}
failure("d0/d1/d2 should be archived");
assertIsDir("target2/d2", -1);
diff --git a/tar/test/test_symlink_dir.c b/tar/test/test_symlink_dir.c
index 485ab32f..5836647c 100644
--- a/tar/test/test_symlink_dir.c
+++ b/tar/test/test_symlink_dir.c
@@ -132,8 +132,8 @@ DEFINE_TEST(test_symlink_dir)
/* dest2/dir and dest2/dir4 symlinks should be followed */
if (canSymlink()) {
- assertIsSymlink("dest2/dir", "real_dir");
- assertIsSymlink("dest2/dir4", "real_dir");
+ assertIsSymlink("dest2/dir", "real_dir", 1);
+ assertIsSymlink("dest2/dir4", "real_dir", 1);
assertIsDir("dest2/real_dir", -1);
}
diff --git a/test_utils/test_common.h b/test_utils/test_common.h
index 154a6964..7538d8cb 100644
--- a/test_utils/test_common.h
+++ b/test_utils/test_common.h
@@ -220,8 +220,8 @@
assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
#define assertIsReg(pathname, mode) \
assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents) \
- assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
+#define assertIsSymlink(pathname, contents, isdir) \
+ assertion_is_symlink(__FILE__, __LINE__, pathname, contents, isdir)
/* Create a directory, report error if it fails. */
#define assertMakeDir(dirname, mode) \
assertion_make_dir(__FILE__, __LINE__, dirname, mode)
@@ -289,7 +289,7 @@ int assertion_is_dir(const char *, int, const char *, int);
int assertion_is_hardlink(const char *, int, const char *, const char *);
int assertion_is_not_hardlink(const char *, int, const char *, const char *);
int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
+int assertion_is_symlink(const char *, int, const char *, const char *, int);
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 *);
diff --git a/test_utils/test_main.c b/test_utils/test_main.c
index cd4c772b..d9f3b19f 100644
--- a/test_utils/test_main.c
+++ b/test_utils/test_main.c
@@ -217,7 +217,7 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
DWORD attrs;
static int set;
- int ret, tmpflags;
+ int ret, tmpflags, llen, tlen;
int flags = 0;
char *src, *tgt, *p;
if (!set) {
@@ -227,10 +227,16 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
if (f == NULL)
return (0);
- tgt = malloc(strlen(target) + 1);
+ tlen = strlen(target);
+ llen = strlen(linkname);
+
+ if (tlen == 0 || llen == 0)
+ return (0);
+
+ tgt = malloc((tlen + 1) * sizeof(char));
if (tgt == NULL)
return (0);
- src = malloc(strlen(linkname) + 1);
+ src = malloc((llen + 1) * sizeof(char));
if (src == NULL) {
free(tgt);
return (0);
@@ -262,8 +268,8 @@ my_CreateSymbolicLinkA(const char *linkname, const char *target,
*p = '\0';
/*
- * If the target equals ".", ".." or ends with a slash, it always
- * points to a directory. In this case we can set the directory flag.
+ * Each test has to specify if a file or a directory symlink
+ * should be created.
*/
if (targetIsDir) {
#if defined(SYMBOLIC_LINK_FLAG_DIRECTORY)
@@ -1705,23 +1711,30 @@ assertion_is_reg(const char *file, int line, const char *pathname, int mode)
return (1);
}
-/* Check whether 'pathname' is a symbolic link. If 'contents' is
- * non-NULL, verify that the symlink has those contents. */
+/*
+ * Check whether 'pathname' is a symbolic link. If 'contents' is
+ * non-NULL, verify that the symlink has those contents.
+ *
+ * On platforms with directory symlinks, set isdir to 0 to test for a file
+ * symlink and to 1 to test for a directory symlink. On other platforms
+ * the variable is ignored.
+ */
static int
is_symlink(const char *file, int line,
- const char *pathname, const char *contents)
+ const char *pathname, const char *contents, int isdir)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
HANDLE h;
DWORD inbytes;
REPARSE_DATA_BUFFER *buf;
+ BY_HANDLE_FILE_INFORMATION st;
size_t len, len2;
wchar_t *linknamew, *contentsw;
const char *p;
char *s, *pn;
int ret = 0;
BYTE *indata;
- DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |
+ static DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OPEN_REPARSE_POINT;
/* Replace slashes with backslashes in pathname */
@@ -1741,8 +1754,39 @@ is_symlink(const char *file, int line,
h = CreateFileA(pn, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
flag, NULL);
free(pn);
- if (h == INVALID_HANDLE_VALUE)
+ if (h == INVALID_HANDLE_VALUE) {
+ failure_start(file, line, "Can't access %s\n", pathname);
+ failure_finish(NULL);
return (0);
+ }
+ ret = GetFileInformationByHandle(h, &st);
+ if (ret == 0) {
+ failure_start(file, line,
+ "Can't stat: %s", pathname);
+ failure_finish(NULL);
+ } else if ((st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+ failure_start(file, line,
+ "Not a symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (isdir && ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
+ failure_start(file, line,
+ "Not a directory symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (!isdir &&
+ ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
+ failure_start(file, line,
+ "Not a file symlink: %s", pathname);
+ failure_finish(NULL);
+ ret = 0;
+ }
+ if (ret == 0) {
+ CloseHandle(h);
+ return (0);
+ }
indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata,
@@ -1750,6 +1794,9 @@ is_symlink(const char *file, int line,
CloseHandle(h);
if (ret == 0) {
free(indata);
+ failure_start(file, line,
+ "Could not retrieve symlink target: %s", pathname);
+ failure_finish(NULL);
return (0);
}
@@ -1757,7 +1804,9 @@ is_symlink(const char *file, int line,
if (buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
free(indata);
/* File is not a symbolic link */
- errno = EINVAL;
+ failure_start(file, line,
+ "Not a symlink: %s", pathname);
+ failure_finish(NULL);
return (0);
}
@@ -1801,6 +1850,7 @@ is_symlink(const char *file, int line,
ssize_t linklen;
int r;
+ (void)isdir; /* UNUSED */
assertion_count(file, line);
r = lstat(pathname, &st);
if (r != 0) {
@@ -1829,9 +1879,9 @@ is_symlink(const char *file, int line,
/* Assert that path is a symlink that (optionally) contains contents. */
int
assertion_is_symlink(const char *file, int line,
- const char *path, const char *contents)
+ const char *path, const char *contents, int isdir)
{
- if (is_symlink(file, line, path, contents))
+ if (is_symlink(file, line, path, contents, isdir))
return (1);
if (contents)
failure_start(file, line, "File %s is not a symlink to %s",
@@ -2405,10 +2455,12 @@ canSymlink(void)
* use the Win32 CreateSymbolicLink() function. */
#if defined(_WIN32) && !defined(__CYGWIN__)
value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
- && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
+ && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0",
+ 0);
#elif HAVE_SYMLINK
value = (0 == symlink("canSymlink.0", "canSymlink.1"))
- && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
+ && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0",
+ 0);
#endif
return (value);
}