summaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/libarchive/archive_write_disk_posix.c')
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_disk_posix.c63
1 files changed, 57 insertions, 6 deletions
diff --git a/src/libs/3rdparty/libarchive/archive_write_disk_posix.c b/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
index 7e32fca92..fcd733aff 100644
--- a/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
+++ b/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
@@ -360,7 +360,7 @@ static int la_mktemp(struct archive_write_disk *);
static void fsobj_error(int *, struct archive_string *, int, const char *,
const char *);
static int check_symlinks_fsobj(char *, int *, struct archive_string *,
- int);
+ int, int);
static int check_symlinks(struct archive_write_disk *);
static int create_filesystem_object(struct archive_write_disk *);
static struct fixup_entry *current_fixup(struct archive_write_disk *,
@@ -2263,7 +2263,7 @@ create_filesystem_object(struct archive_write_disk *a)
return (EPERM);
}
r = check_symlinks_fsobj(linkname_copy, &error_number,
- &error_string, a->flags);
+ &error_string, a->flags, 1);
if (r != ARCHIVE_OK) {
archive_set_error(&a->archive, error_number, "%s",
error_string.s);
@@ -2284,7 +2284,12 @@ create_filesystem_object(struct archive_write_disk *a)
*/
if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
unlink(a->name);
+#ifdef HAVE_LINKAT
+ r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,
+ 0) ? errno : 0;
+#else
r = link(linkname, a->name) ? errno : 0;
+#endif
/*
* New cpio and pax formats allow hardlink entries
* to carry data, so we may have to open the file
@@ -2456,6 +2461,7 @@ _archive_write_disk_close(struct archive *_a)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
struct fixup_entry *next, *p;
+ struct stat st;
int fd, ret;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -2473,6 +2479,20 @@ _archive_write_disk_close(struct archive *_a)
(TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) {
fd = open(p->name,
O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ /* If we cannot lstat, skip entry */
+ if (lstat(p->name, &st) != 0)
+ goto skip_fixup_entry;
+ /*
+ * If we deal with a symbolic link, mark
+ * it in the fixup mode to ensure no
+ * modifications are made to its target.
+ */
+ if (S_ISLNK(st.st_mode)) {
+ p->mode &= ~S_IFMT;
+ p->mode |= S_IFLNK;
+ }
+ }
}
if (p->fixup & TODO_TIMES) {
set_times(a, fd, p->mode, p->name,
@@ -2487,7 +2507,12 @@ _archive_write_disk_close(struct archive *_a)
fchmod(fd, p->mode);
else
#endif
- chmod(p->name, p->mode);
+#ifdef HAVE_LCHMOD
+ lchmod(p->name, p->mode);
+#else
+ if (!S_ISLNK(p->mode))
+ chmod(p->name, p->mode);
+#endif
}
if (p->fixup & TODO_ACLS)
archive_write_disk_set_acls(&a->archive, fd,
@@ -2498,6 +2523,7 @@ _archive_write_disk_close(struct archive *_a)
if (p->fixup & TODO_MAC_METADATA)
set_mac_metadata(a, p->name, p->mac_metadata,
p->mac_metadata_size);
+skip_fixup_entry:
next = p->next;
archive_acl_clear(&p->acl);
free(p->mac_metadata);
@@ -2638,6 +2664,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname)
fe->next = a->fixup_list;
a->fixup_list = fe;
fe->fixup = 0;
+ fe->mode = 0;
fe->name = strdup(pathname);
return (fe);
}
@@ -2675,7 +2702,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr,
*/
static int
check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
- int flags)
+ int flags, int checking_linkname)
{
#if !defined(HAVE_LSTAT) && \
!(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
@@ -2684,6 +2711,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
(void)error_number; /* UNUSED */
(void)error_string; /* UNUSED */
(void)flags; /* UNUSED */
+ (void)checking_linkname; /* UNUSED */
return (ARCHIVE_OK);
#else
int res = ARCHIVE_OK;
@@ -2805,6 +2833,28 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
head = tail + 1;
}
} else if (S_ISLNK(st.st_mode)) {
+ if (last && checking_linkname) {
+#ifdef HAVE_LINKAT
+ /*
+ * Hardlinks to symlinks are safe to write
+ * if linkat() is supported as it does not
+ * follow symlinks.
+ */
+ res = ARCHIVE_OK;
+#else
+ /*
+ * We return ARCHIVE_FAILED here as we are
+ * not able to safely write hardlinks
+ * to symlinks.
+ */
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, errno,
+ "Cannot write hardlink to symlink ",
+ path);
+ res = ARCHIVE_FAILED;
+#endif
+ break;
+ } else
if (last) {
/*
* Last element is symlink; remove it
@@ -2971,7 +3021,7 @@ check_symlinks(struct archive_write_disk *a)
int rc;
archive_string_init(&error_string);
rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
- a->flags);
+ a->flags, 0);
if (rc != ARCHIVE_OK) {
archive_set_error(&a->archive, error_number, "%s",
error_string.s);
@@ -3899,7 +3949,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
/* If we weren't given an fd, open it ourselves. */
if (myfd < 0) {
- myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
+ myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY |
+ O_CLOEXEC | O_NOFOLLOW);
__archive_ensure_cloexec_flag(myfd);
}
if (myfd < 0)