From: Michihiro NAKAJIMA Date: Thu, 6 Jan 2011 11:18:29 +0000 (-0500) Subject: Properly reset working directory when a directory traversals object is X-Git-Tag: v3.0.0a~782 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dca389c9d31a87e550a377e7b4024c104f8ccb63;p=thirdparty%2Flibarchive.git Properly reset working directory when a directory traversals object is released even if it would be broken off. SVN-Revision: 2864 --- diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index 25afa6ac5..092d8ad75 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -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); } diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c index 81b48bcd8..ce5529eb9 100644 --- a/libarchive/archive_read_disk_windows.c +++ b/libarchive/archive_read_disk_windows.c @@ -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); } diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c index 6378e3459..791bf73c4 100644 --- a/libarchive/test/test_read_disk_directory_traversals.c +++ b/libarchive/test/test_read_disk_directory_traversals.c @@ -25,11 +25,18 @@ #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); }