]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Windows symlink bugfixes and improvements
authorMartin Matuska <martin@matuska.org>
Sat, 13 Apr 2019 19:51:03 +0000 (21:51 +0200)
committerMartin Matuska <martin@matuska.org>
Sat, 13 Apr 2019 19:54:29 +0000 (21:54 +0200)
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

16 files changed:
cpio/test/test_basic.c
cpio/test/test_gcpio_compat.c
cpio/test/test_option_L_upper.c
libarchive/archive_write_disk_windows.c
libarchive/test/test_read_extract.c
libarchive/test/test_write_disk_symlink.c
tar/test/test_basic.c
tar/test/test_copy.c
tar/test/test_option_H_upper.c
tar/test/test_option_L_upper.c
tar/test/test_option_U_upper.c
tar/test/test_option_s.c
tar/test/test_strip_components.c
tar/test/test_symlink_dir.c
test_utils/test_common.h
test_utils/test_main.c

index 855793fbb054d8e810212fb280059f72bff587c5..a8fedf89e9688f030e171483f5052bcccb54a833 100644 (file)
@@ -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);
index 461e427c2e88283ee9a10fe0f2df8a46e3dd19c8..9bb988990e4cb34861b63750b81f4f2fc1897812 100644 (file)
@@ -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);
index bf3a9c430c916bf0e8aae1b67827316caccd0756..cab41b61d749aa7b7b64d447382a0ab3407e1d2d 100644 (file)
@@ -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);
index 811e7772c3529d747d5cd91198b55ec01767bd8a..b29389c1b9556380fe9aff5a6c32fe0efd374833 100644 (file)
@@ -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;
index c537e4f936c47f2cf34599fbb848254832d3b91e..cd06096eff693a357d8be878bbdc77bb9c14222c 100644 (file)
@@ -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);
index 13089c78d8949bee089500250546cdb76ef4262b..43796a45d7030238820e2bbdf174caa07af177d0 100644 (file)
@@ -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);
 }
index 91282cde9a30de8a97bdf2c88ab0782dbd41cf67..9bb966a0cf866745ac88f6f0e3cc1202ba95527c 100644 (file)
@@ -78,7 +78,7 @@ verify_files(const char *target)
 
        /* Symlink */
        if (canSymlink())
-               assertIsSymlink("symlink", "file");
+               assertIsSymlink("symlink", "file", 0);
 
        /* dir */
        failure("%s", target);
index 1e59e1929fbc4d5c3d78376ab8565fe4ed2b9ea3..b828666b93fd62bacf5f344ac00513d090b0e471 100644 (file)
@@ -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...". */
index 7c201ce26270ffc905e71d20fe3ce4a4fe6e6ff0..2c2ad33ce75b7f10c5e908969be0c9b5ce06a9f0 100644 (file)
@@ -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("..");
 }
index 83f69d085bdd5678de07ddaacc02181eb024cc83..5697b0f293c224a345f7e9bed6a67b6f23478c8d 100644 (file)
@@ -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("..");
 }
index 832054860f17720e4b01154ace902741064a17e7..d864e13c4f6be15e0f22547ad8a4b429771ad56b 100644 (file)
@@ -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");
index a08966068b803422728b7a472dfdd0580b2f8eb8..09c72ee7d63d288be88685c9318ac4e4509bc923 100644 (file)
@@ -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);
        }
 
        /*
index caf45a3e144ddc8b9031a8becd01d62b03d17f5c..090fb0dbf913f3b4cf2b8d928b3bb201a8145957 100644 (file)
@@ -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);
index 485ab32f847162d944358da1a9fe8ad327c88c8f..5836647c1a23727bb800610a27d381718954d158 100644 (file)
@@ -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);
        }
 
index 154a6964d1bbd3f060315c37af4dc92cf5eab50a..7538d8cb7b5a24d3b9c27cd2245a264d035d9b27 100644 (file)
   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 *);
index cd4c772b8ed3413b6a0a31a39a5391296a49bc88..d9f3b19ffe9dfc5d5acb1d57da376485b1a9a306 100644 (file)
@@ -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);
 }