summaryrefslogtreecommitdiffstats
path: root/libarchive/archive_read_disk_posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'libarchive/archive_read_disk_posix.c')
-rw-r--r--libarchive/archive_read_disk_posix.c96
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,
OpenPOWER on IntegriCloud