From: Dag-Erling Smørgrav Date: Fri, 6 Feb 2026 00:54:50 +0000 (+0100) Subject: archive_write_disk_posix: Report correct error X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8ae9e937b7f5c94736bf0afac32a1b2053db7809;p=thirdparty%2Flibarchive.git archive_write_disk_posix: Report correct error When create_dir() fails to create a directory, it immediately checks to see if the directory already exists, which can happen if it's been given something like foo/../foo. Unfortunately, this clobbers errno, which means that create_dir() always reports ENOENT, regardless of the actual error. Fix this by only performing this extra check if errno is EEXIST, then reset errno to either EEXIST or ENOTDIR depending on the outcome. --- diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index d1f043d24..7e4dba3c4 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -1975,7 +1975,7 @@ archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id) return (a->lookup_gid)(a->lookup_gid_data, name, id); return (id); } - + int64_t archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id) { @@ -2406,7 +2406,7 @@ create_filesystem_object(struct archive_write_disk *a) */ mode = final_mode & 0777 & ~a->user_umask; - /* + /* * Always create writable such that [f]setxattr() works if we're not * root. */ @@ -3024,7 +3024,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, /* * We are not the last element and we want to * follow symlinks if they are a directory. - * + * * This is needed to extract hardlinks over * symlinks. */ @@ -3435,7 +3435,7 @@ create_dir(struct archive_write_disk *a, char *path) le = new_fixup(a, path); if (le == NULL) return (ARCHIVE_FATAL); - le->fixup |=TODO_MODE_BASE; + le->fixup |= TODO_MODE_BASE; le->mode = mode_final; } return (ARCHIVE_OK); @@ -3447,8 +3447,17 @@ create_dir(struct archive_write_disk *a, char *path) * don't add it to the fixup list here, as it's already been * added. */ - if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) - return (ARCHIVE_OK); + if (errno == EEXIST) { + if (la_stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) + return (ARCHIVE_OK); + /* path exists but is not a directory */ + errno = ENOTDIR; + } else { + /* restore original errno */ + errno = EEXIST; + } + } archive_set_error(&a->archive, errno, "Failed to create dir '%s'", path); @@ -4767,4 +4776,3 @@ static void close_file_descriptor(struct archive_write_disk* a) #endif /* !_WIN32 || __CYGWIN__ */ -