diff options
Diffstat (limited to 'archivers/libarchive/files/libarchive/archive_read_disk_posix.c')
-rw-r--r-- | archivers/libarchive/files/libarchive/archive_read_disk_posix.c | 70 |
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; |