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,
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);