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);
}
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);
}
#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;
/*
* 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"));
/*
* 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"));
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);
}