]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
archive_write_disk_posix: Report correct error
authorDag-Erling Smørgrav <des@des.dev>
Fri, 6 Feb 2026 00:54:50 +0000 (01:54 +0100)
committerDag-Erling Smørgrav <des@des.dev>
Mon, 2 Mar 2026 08:27:00 +0000 (09:27 +0100)
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.

libarchive/archive_write_disk_posix.c

index d1f043d244374b2d390b28d993c53b3270b8ec52..7e4dba3c43577bc364f88c30ec421db33d93089d 100644 (file)
@@ -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__ */
-