]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Try to eliminate fchdir() operation as much as we can in the directory
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 19 Jan 2011 14:48:24 +0000 (09:48 -0500)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 19 Jan 2011 14:48:24 +0000 (09:48 -0500)
traversals, which is a new API for the read disk object.

SVN-Revision: 2926

libarchive/archive_read_disk_posix.c

index 3fcca7108e5661e328a6d6fe96d51c7371ecf87a..fc0e1e43b7d993bcde82a54f7c0c1dc708551ec6 100644 (file)
@@ -773,7 +773,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
        struct tree *t;
        const struct stat *st; /* info to use for this entry */
        const struct stat *lst;/* lstat() information */
-       int descend, r;
+       int descend, fd = -1, r;
 
        archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
            ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
@@ -869,13 +869,35 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
        archive_entry_copy_stat(entry, st);
 
 #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-       /* Restore working directory. */
-       tree_enter_working_dir(t);
-#endif
+       /*
+        * Open the current file to freely gather its metadata anywhere in
+        * working directory.
+        * Note: A symbolic link file cannot be opened with O_NOFOLLOW.
+        */
+       if (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)
+               fd = openat(tree_current_dir_fd(t), tree_current_access_path(t),
+                   (a->follow_symlinks)? O_RDONLY | O_NONBLOCK
+                                       : O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
+       /* Restore working directory if openat() operation failed or
+        * the file is a symbolic link. */
+       if (fd < 0)
+               tree_enter_working_dir(t);
 
+       /* The current direcotry fd is needed at
+        * archive_read_disk_entry_from_file() function to read link data
+        * with readlinkat(). */
        a->entry_wd_fd = tree_current_dir_fd(t);
-       /* Populate the archive_entry with metadata from the disk. */
-       r = archive_read_disk_entry_from_file(&(a->archive), entry, -1, st);
+#endif
+
+       /*
+        * Populate the archive_entry with metadata from the disk.
+        */
+       r = archive_read_disk_entry_from_file(&(a->archive), entry, fd, st);
+
+       /* Close the file descriptor used for reding the current file
+        * metadata at archive_read_disk_entry_from_file(). */
+       if (fd >= 0)
+               close(fd);
 
        /* Return to the initial directory. */
        tree_enter_initial_dir(t);