]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Ignore sizes which do not fit into off_t 2688/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 27 Jun 2025 15:06:00 +0000 (17:06 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 27 Jun 2025 15:06:14 +0000 (17:06 +0200)
It is possible to handle entries and files with sizes which do not fit
into off_t of the current system (Windows always has 32 bit off_t and
32 bit systems without large file support also have 32 bit off_t).

Set sizes to 0 in such cases. The fstat system call would return -1 and
set errno to EOVERFLOW, but that's not how archive_entry_set_size acts.
It would simply ignore negative values and set the size to 0.

Actual callers of archive_entry_stat from foreign projects seem to not
even check for NULL return values, so let's try to handle such cases as
nice as possible.

Affects mtree's checkfs option as well (Windows only, 32 bit systems
would simply fail in fstat/stat).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_entry_stat.c
libarchive/archive_windows.c
libarchive/test/test_entry.c

index c4906838ed0febe3cc87a497ffadafc717765446..345d3d29b2f2ae4665ae574e13671a49ec3bc859 100644 (file)
@@ -38,6 +38,7 @@
 const struct stat *
 archive_entry_stat(struct archive_entry *entry)
 {
+       int64_t size;
        struct stat *st;
        if (entry->stat == NULL) {
                entry->stat = calloc(1, sizeof(*st));
@@ -74,7 +75,10 @@ archive_entry_stat(struct archive_entry *entry)
        st->st_ino = (ino_t)archive_entry_ino64(entry);
        st->st_nlink = archive_entry_nlink(entry);
        st->st_rdev = archive_entry_rdev(entry);
-       st->st_size = (off_t)archive_entry_size(entry);
+       size = archive_entry_size(entry);
+       st->st_size = (off_t)size;
+       if (st->st_size < 0 || (int64_t)st->st_size != size)
+               st->st_size = 0;
        st->st_mode = archive_entry_mode(entry);
 
        /*
index 0ccea0f818b90cd4edd185901131fc74223cad23..19180bba6102ec7249f9e7f35b969fe05b8ad941 100644 (file)
@@ -561,6 +561,8 @@ copy_stat(struct stat *st, struct ustat *us)
        st->st_mode = us->st_mode;
        st->st_nlink = us->st_nlink;
        st->st_size = (off_t)us->st_size;
+       if (st->st_size < 0 || (uint64_t)st->st_size != us->st_size)
+               st->st_size = 0;
        st->st_uid = us->st_uid;
        st->st_dev = us->st_dev;
        st->st_rdev = us->st_rdev;
index 9b21b83ecdfb84a3203304ff65d766b3898ccba8..cff9c5c86efcb67a001724b2372c0c6c05447474 100644 (file)
@@ -880,6 +880,17 @@ DEFINE_TEST(test_entry)
        if (pst == NULL)
                return;
        assertEqualInt(pst->st_uid, 22);
+
+       /* Check behavior with large sizes. */
+       archive_entry_set_size(e, INT64_MAX - 1);
+       assert((pst = archive_entry_stat(e)) != NULL);
+       if (pst == NULL)
+               return;
+       if (sizeof(pst->st_size) < sizeof(int64_t))
+               assertEqualInt(pst->st_size, 0);
+       else
+               assertEqualInt(pst->st_size, INT64_MAX - 1);
+
        /* We don't need to check high-res fields here. */
 
        /*