summaryrefslogtreecommitdiff
path: root/archivers/libarchive/files/libarchive/archive_read_disk_posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'archivers/libarchive/files/libarchive/archive_read_disk_posix.c')
-rw-r--r--archivers/libarchive/files/libarchive/archive_read_disk_posix.c70
1 files changed, 66 insertions, 4 deletions
diff --git a/archivers/libarchive/files/libarchive/archive_read_disk_posix.c b/archivers/libarchive/files/libarchive/archive_read_disk_posix.c
index cdf7541238c..c4df6c9436b 100644
--- a/archivers/libarchive/files/libarchive/archive_read_disk_posix.c
+++ b/archivers/libarchive/files/libarchive/archive_read_disk_posix.c
@@ -856,7 +856,12 @@ next_entry(struct archive_read_disk *a, struct tree *t,
const struct stat *st; /* info to use for this entry */
const struct stat *lst;/* lstat() information */
const char *name;
- int descend, r;
+ int delayed, delayed_errno, descend, r;
+ struct archive_string delayed_str;
+
+ delayed = ARCHIVE_OK;
+ delayed_errno = 0;
+ archive_string_init(&delayed_str);
st = NULL;
lst = NULL;
@@ -885,14 +890,26 @@ next_entry(struct archive_read_disk *a, struct tree *t,
case TREE_REGULAR:
lst = tree_current_lstat(t);
if (lst == NULL) {
+ if (errno == ENOENT && t->depth > 0) {
+ delayed = ARCHIVE_WARN;
+ delayed_errno = errno;
+ if (delayed_str.length == 0) {
+ archive_string_sprintf(&delayed_str,
+ "%s", tree_current_path(t));
+ } else {
+ archive_string_sprintf(&delayed_str,
+ " %s", tree_current_path(t));
+ }
+ } else {
archive_set_error(&a->archive, errno,
"%s: Cannot stat",
tree_current_path(t));
tree_enter_initial_dir(t);
return (ARCHIVE_FAILED);
+ }
}
break;
- }
+ }
} while (lst == NULL);
#ifdef __APPLE__
@@ -1083,6 +1100,18 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_read_disk_entry_from_file(&(a->archive), entry,
t->entry_fd, st);
+ if (r == ARCHIVE_OK) {
+ r = delayed;
+ if (r != ARCHIVE_OK) {
+ archive_string_sprintf(&delayed_str, ": %s",
+ "File removed before we read it");
+ archive_set_error(&(a->archive), delayed_errno,
+ "%s", delayed_str.s);
+ }
+ }
+ if (!archive_string_empty(&delayed_str))
+ archive_string_free(&delayed_str);
+
return (r);
}
@@ -1266,10 +1295,23 @@ archive_read_disk_descend(struct archive *_a)
if (t->visit_type != TREE_REGULAR || !t->descend)
return (ARCHIVE_OK);
+ /*
+ * We must not treat the initial specified path as a physical dir,
+ * because if we do then we will try and ascend out of it by opening
+ * ".." which is (a) wrong and (b) causes spurious permissions errors
+ * if ".." is not readable by us. Instead, treat it as if it were a
+ * symlink. (This uses an extra fd, but it can only happen once at the
+ * top level of a traverse.) But we can't necessarily assume t->st is
+ * valid here (though t->lst is), which complicates the logic a
+ * little.
+ */
if (tree_current_is_physical_dir(t)) {
tree_push(t, t->basename, t->current_filesystem_id,
t->lst.st_dev, t->lst.st_ino, &t->restore_time);
- t->stack->flags |= isDir;
+ if (t->stack->parent->parent != NULL)
+ t->stack->flags |= isDir;
+ else
+ t->stack->flags |= isDirLink;
} else if (tree_current_is_dir(t)) {
tree_push(t, t->basename, t->current_filesystem_id,
t->st.st_dev, t->st.st_ino, &t->restore_time);
@@ -2122,6 +2164,17 @@ tree_open(const char *path, int symlink_mode, int restore_time)
static struct tree *
tree_reopen(struct tree *t, const char *path, int restore_time)
{
+#if defined(O_PATH)
+ /* Linux */
+ const int o_flag = O_PATH;
+#elif defined(O_SEARCH)
+ /* SunOS */
+ const int o_flag = O_SEARCH;
+#elif defined(O_EXEC)
+ /* FreeBSD */
+ const int o_flag = O_EXEC;
+#endif
+
t->flags = (restore_time != 0)?needsRestoreTimes:0;
t->flags |= onInitialDir;
t->visit_type = 0;
@@ -2143,6 +2196,15 @@ tree_reopen(struct tree *t, const char *path, int restore_time)
t->stack->flags = needsFirstVisit;
t->maxOpenCount = t->openCount = 1;
t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC);
+#if defined(O_PATH) || defined(O_SEARCH) || defined(O_EXEC)
+ /*
+ * Most likely reason to fail opening "." is that it's not readable,
+ * so try again for execute. The consequences of not opening this are
+ * unhelpful and unnecessary errors later.
+ */
+ if (t->initial_dir_fd < 0)
+ t->initial_dir_fd = open(".", o_flag | O_CLOEXEC);
+#endif
__archive_ensure_cloexec_flag(t->initial_dir_fd);
t->working_dir_fd = tree_dup(t->initial_dir_fd);
return (t);
@@ -2450,7 +2512,7 @@ tree_current_stat(struct tree *t)
#else
if (tree_enter_working_dir(t) != 0)
return NULL;
- if (stat(tree_current_access_path(t), &t->st) != 0)
+ if (la_stat(tree_current_access_path(t), &t->st) != 0)
#endif
return NULL;
t->flags |= hasStat;