From: Michihiro NAKAJIMA Date: Wed, 19 Jan 2011 14:48:24 +0000 (-0500) Subject: Try to eliminate fchdir() operation as much as we can in the directory X-Git-Tag: v3.0.0a~736 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8848af5f4b004de31831f9ec55b93fa7bfeaffc1;p=thirdparty%2Flibarchive.git Try to eliminate fchdir() operation as much as we can in the directory traversals, which is a new API for the read disk object. SVN-Revision: 2926 --- diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index 3fcca7108..fc0e1e43b 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -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);