]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Properly reset working directory when a directory traversals object is
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 6 Jan 2011 11:18:29 +0000 (06:18 -0500)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 6 Jan 2011 11:18:29 +0000 (06:18 -0500)
released even if it would be broken off.

SVN-Revision: 2864

libarchive/archive_read_disk_posix.c
libarchive/archive_read_disk_windows.c
libarchive/test/test_read_disk_directory_traversals.c

index 25afa6ac5a41c0b3a5189140f38c20ccbc664ad0..092d8ad7531508e5218895085b67a7a6e510522d 100644 (file)
@@ -1444,25 +1444,34 @@ tree_current_path(struct tree *t)
 static void
 tree_close(struct tree *t)
 {
+       /* Close the handle of readdir(). */
+       if (t->d != INVALID_DIR_HANDLE) {
+               closedir(t->d);
+               t->d = INVALID_DIR_HANDLE;
+       }
        /* Release anything remaining in the stack. */
-       while (t->stack != NULL)
+       while (t->stack != NULL) {
+#ifdef HAVE_FCHDIR
+               /*
+                * If the current working directory have not returned to
+                * the initial directory where tree_open() was performed,
+                * we should return.
+                */
+               if (t->stack->next == NULL) {
+                       /* The last stack has the initial directory fd. */
+                       int s = fchdir(t->stack->symlink_parent_fd);
+                       (void)s; /* UNUSED */
+                       close(t->stack->symlink_parent_fd);
+               } else if (t->stack->flags & isDirLink)
+                       close(t->stack->symlink_parent_fd);
+#endif
                tree_pop(t);
+       }
        archive_string_free(&t->path);
 #if defined(HAVE_READDIR_R)
        free(t->dirent);
 #endif
        free(t->filesystem_table);
-       /* TODO: Ensure that premature close() resets cwd */
-#if 0
-#ifdef HAVE_FCHDIR
-       if (t->initialDirFd >= 0) {
-               int s = fchdir(t->initialDirFd);
-               (void)s; /* UNUSED */
-               close(t->initialDirFd);
-               t->initialDirFd = -1;
-       }
-#endif
-#endif
        free(t);
 }
 
index 81b48bcd84451b4fb9f913ea673641054d038586..ce5529eb93efff3a5dd621d3759cdecf4d9c9ca9 100644 (file)
@@ -1537,13 +1537,18 @@ tree_current_path(struct tree *t)
 static void
 tree_close(struct tree *t)
 {
+       /* Close the handle of FindFirstFileW */
+       if (t->d != INVALID_DIR_HANDLE) {
+               FindClose(t->d);
+               t->d = INVALID_DIR_HANDLE;
+               t->findData = NULL;
+       }
        /* Release anything remaining in the stack. */
        while (t->stack != NULL)
                tree_pop(t);
        archive_wstring_free(&t->path);
        archive_wstring_free(&t->full_path);
        free(t->filesystem_table);
-       /* TODO: Ensure that premature close() resets cwd */
        free(t);
 }
 
index 6378e3459dfe5e629d38c76df78f7f4e29c84258..791bf73c46a749b8f02cb0aae9b854538167ba54 100644 (file)
 #include "test.h"
 __FBSDID("$FreeBSD$");
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# if !defined(__BORLANDC__)
+#  define getcwd _getcwd
+# endif
+#endif
+
 DEFINE_TEST(test_read_disk_directory_traversals)
 {
        struct archive *a;
        struct archive_entry *ae;
        const void *p;
+       char *initial_cwd, *cwd;
        size_t size;
        int64_t offset;
        int file_count;
@@ -165,7 +172,6 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        /*
         * Test that call archive_read_disk_open with a regular file.
         */
-       assert((ae = archive_entry_new()) != NULL);
        assert((a = archive_read_disk_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/file1"));
 
@@ -191,7 +197,6 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        /*
         * Test for wildcard '*' or '?'
         */
-       assert((ae = archive_entry_new()) != NULL);
        assert((a = archive_read_disk_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/*1"));
 
@@ -232,5 +237,45 @@ DEFINE_TEST(test_read_disk_directory_traversals)
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
 #endif
 
+       /*
+        * We should be on the initial directory where we performed
+        * archive_read_disk_new() after we perfome archive_read_free()
+        *  even if we broke off the directory traversals.
+        */
+
+       /* Save current working directory. */
+       initial_cwd = getcwd(NULL, 0);
+
+       assert((a = archive_read_disk_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1"));
+
+       /* Step in a deep directory. */
+       while (file_count--) {
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_read_next_header2(a, ae));
+               if (strcmp(archive_entry_pathname(ae),
+                   "dir1/sub1/file1") == 0)
+                       /*
+                        * We are on an another directory at this time.
+                        */
+                       break;
+               if (archive_entry_filetype(ae) == AE_IFDIR) {
+                       /* Descend into the current object */
+                       assertEqualIntA(a, ARCHIVE_OK,
+                           archive_read_disk_descend(a));
+               }
+       }
+       /* Destroy the archive. */
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+       /* We should be on the initial working directory. */
+       failure(
+           "Current working directory does not return to the initial"
+           "directory");
+       cwd = getcwd(NULL, 0);
+       assertEqualString(initial_cwd, cwd);
+       free(initial_cwd);
+       free(cwd);
+
        archive_entry_free(ae);
 }