diff options
Diffstat (limited to 'libarchive/archive_read_disk_posix.c')
-rw-r--r-- | libarchive/archive_read_disk_posix.c | 96 |
1 files changed, 75 insertions, 21 deletions
diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index 698600e..a13dbbf 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -105,6 +105,9 @@ __FBSDID("$FreeBSD$"); #ifndef O_BINARY #define O_BINARY 0 #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif /*- * This is a new directory-walking system that addresses a number @@ -361,6 +364,7 @@ static int setup_sparse(struct archive_read_disk *, struct archive_entry *); static int close_and_restore_time(int fd, struct tree *, struct restore_time *); static int open_on_current_dir(struct tree *, const char *, int); +static int tree_dup(int); static struct archive_vtable * @@ -717,7 +721,7 @@ _archive_read_data_block(struct archive *_a, const void **buff, * Open the current file. */ if (t->entry_fd < 0) { - int flags = O_RDONLY | O_BINARY; + int flags = O_RDONLY | O_BINARY | O_CLOEXEC; /* * Eliminate or reduce cache effects if we can. @@ -740,6 +744,7 @@ _archive_read_data_block(struct archive *_a, const void **buff, #endif t->entry_fd = open_on_current_dir(t, tree_current_access_path(t), flags); + __archive_ensure_cloexec_flag(t->entry_fd); #if defined(O_NOATIME) /* * When we did open the file with O_NOATIME flag, @@ -984,10 +989,12 @@ next_entry(struct archive_read_disk *a, struct tree *t, #elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { - unsigned long stflags; + int stflags; t->entry_fd = open_on_current_dir(t, - tree_current_access_path(t), O_RDONLY | O_NONBLOCK); + tree_current_access_path(t), + O_RDONLY | O_NONBLOCK | O_CLOEXEC); + __archive_ensure_cloexec_flag(t->entry_fd); if (t->entry_fd >= 0) { r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS, &stflags); @@ -1359,15 +1366,17 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) fid = t->max_filesystem_id++; if (t->max_filesystem_id > t->allocated_filesytem) { size_t s; + void *p; s = t->max_filesystem_id * 2; - t->filesystem_table = realloc(t->filesystem_table, - s * sizeof(*t->filesystem_table)); - if (t->filesystem_table == NULL) { + p = realloc(t->filesystem_table, + s * sizeof(*t->filesystem_table)); + if (p == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate tar data"); return (ARCHIVE_FATAL); } + t->filesystem_table = (struct filesystem *)p; t->allocated_filesytem = s; } t->current_filesystem_id = fid; @@ -1482,7 +1491,8 @@ setup_current_filesystem(struct archive_read_disk *a) * where current is. */ int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY); + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); if (fd < 0) { archive_set_error(&a->archive, errno, "openat failed"); @@ -1660,7 +1670,8 @@ setup_current_filesystem(struct archive_read_disk *a) * where current is. */ int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY); + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); if (fd < 0) { archive_set_error(&a->archive, errno, "openat failed"); @@ -1768,7 +1779,8 @@ setup_current_filesystem(struct archive_read_disk *a) * where current is. */ int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY); + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); if (fd < 0) { archive_set_error(&a->archive, errno, "openat failed"); @@ -1889,7 +1901,8 @@ static int close_and_restore_time(int fd, struct tree *t, struct restore_time *rt) { #ifndef HAVE_UTIMES - (void)a; /* UNUSED */ + (void)t; /* UNUSED */ + (void)rt; /* UNUSED */ return (close(fd)); #else #if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) @@ -1952,6 +1965,28 @@ open_on_current_dir(struct tree *t, const char *path, int flags) #endif } +static int +tree_dup(int fd) +{ + int new_fd; +#ifdef F_DUPFD_CLOEXEC + static volatile int can_dupfd_cloexec = 1; + + if (can_dupfd_cloexec) { + new_fd = fcntl(fd, F_DUPFD_CLOEXEC); + if (new_fd != -1) + return (new_fd); + /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, + * but it cannot be used. So we have to try dup(). */ + /* We won't try F_DUPFD_CLOEXEC. */ + can_dupfd_cloexec = 0; + } +#endif /* F_DUPFD_CLOEXEC */ + new_fd = dup(fd); + __archive_ensure_cloexec_flag(new_fd); + return (new_fd); +} + /* * Add a directory path to the current stack. */ @@ -2052,8 +2087,9 @@ tree_reopen(struct tree *t, const char *path, int restore_time) tree_push(t, path, 0, 0, 0, NULL); t->stack->flags = needsFirstVisit; t->maxOpenCount = t->openCount = 1; - t->initial_dir_fd = open(".", O_RDONLY); - t->working_dir_fd = dup(t->initial_dir_fd); + t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(t->initial_dir_fd); + t->working_dir_fd = tree_dup(t->initial_dir_fd); return (t); } @@ -2063,11 +2099,12 @@ tree_descent(struct tree *t) int flag, new_fd, r = 0; t->dirname_length = archive_strlen(&t->path); - flag = O_RDONLY; + flag = O_RDONLY | O_CLOEXEC; #if defined(O_DIRECTORY) flag |= O_DIRECTORY; #endif new_fd = open_on_current_dir(t, t->stack->name.s, flag); + __archive_ensure_cloexec_flag(new_fd); if (new_fd < 0) { t->tree_errno = errno; r = TREE_ERROR_DIR; @@ -2101,8 +2138,10 @@ tree_ascend(struct tree *t) prev_dir_fd = t->working_dir_fd; if (te->flags & isDirLink) new_fd = te->symlink_parent_fd; - else - new_fd = open_on_current_dir(t, "..", O_RDONLY); + else { + new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(new_fd); + } if (new_fd < 0) { t->tree_errno = errno; r = TREE_ERROR_FATAL; @@ -2265,11 +2304,16 @@ tree_dir_next_posix(struct tree *t) #endif #if defined(HAVE_FDOPENDIR) - if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) { -#else - if (tree_enter_working_dir(t) != 0 || - (t->d = opendir(".")) == NULL) { + t->d = fdopendir(tree_dup(t->working_dir_fd)); +#else /* HAVE_FDOPENDIR */ + if (tree_enter_working_dir(t) == 0) { + t->d = opendir("."); +#if HAVE_DIRFD || defined(dirfd) + __archive_ensure_cloexec_flag(dirfd(t->d)); #endif + } +#endif /* HAVE_FDOPENDIR */ + if (t->d == NULL) { r = tree_ascend(t); /* Undo "chdir" */ tree_pop(t); t->tree_errno = errno; @@ -2296,11 +2340,21 @@ tree_dir_next_posix(struct tree *t) #endif /* HAVE_READDIR_R */ } for (;;) { + errno = 0; #if defined(HAVE_READDIR_R) r = readdir_r(t->d, t->dirent, &t->de); +#ifdef _AIX + /* Note: According to the man page, return value 9 indicates + * that the readdir_r was not successful and the error code + * is set to the global errno variable. And then if the end + * of directory entries was reached, the return value is 9 + * and the third parameter is set to NULL and errno is + * unchanged. */ + if (r == 9) + r = errno; +#endif /* _AIX */ if (r != 0 || t->de == NULL) { #else - errno = 0; t->de = readdir(t->d); if (t->de == NULL) { r = errno; @@ -2391,7 +2445,7 @@ tree_current_is_dir(struct tree *t) return 1; /* Not a dir; might be a link to a dir. */ /* If it's not a link, then it's not a link to a dir. */ - if (!S_ISLNK(tree_current_lstat(t)->st_mode)) + if (!S_ISLNK(st->st_mode)) return 0; /* * It's a link, but we don't know what it's a link to, |