]> git.ipfire.org Git - thirdparty/git.git/commitdiff
odb: introduce mtime fields for object info requests
authorPatrick Steinhardt <ps@pks.im>
Thu, 15 Jan 2026 11:04:40 +0000 (12:04 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Jan 2026 13:50:29 +0000 (05:50 -0800)
There are some use cases where we need to figure out the mtime for
objects. Most importantly, this is the case when we want to prune
unreachable objects. But getting at that data requires users to manually
derive the info either via the loose object's mtime, the packfiles'
mtime or via the ".mtimes" file.

Introduce a new `struct object_info::mtimep` pointer that allows callers
to request an object's mtime. This new field will be used in a
subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
object-file.c
odb.c
odb.h
packfile.c

index 65e730684b374fcfce7de2f712090deec7baf1a3..c0f896673b1d6d8eceae46af72ac58041963bb12 100644 (file)
@@ -409,6 +409,7 @@ static int read_object_info_from_path(struct odb_source *source,
        char hdr[MAX_HEADER_LEN];
        unsigned long size_scratch;
        enum object_type type_scratch;
+       struct stat st;
 
        /*
         * If we don't care about type or size, then we don't
@@ -421,7 +422,7 @@ static int read_object_info_from_path(struct odb_source *source,
        if (!oi || (!oi->typep && !oi->sizep && !oi->contentp)) {
                struct stat st;
 
-               if ((!oi || !oi->disk_sizep) && (flags & OBJECT_INFO_QUICK)) {
+               if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) {
                        ret = quick_has_loose(source->loose, oid) ? 0 : -1;
                        goto out;
                }
@@ -431,8 +432,12 @@ static int read_object_info_from_path(struct odb_source *source,
                        goto out;
                }
 
-               if (oi && oi->disk_sizep)
-                       *oi->disk_sizep = st.st_size;
+               if (oi) {
+                       if (oi->disk_sizep)
+                               *oi->disk_sizep = st.st_size;
+                       if (oi->mtimep)
+                               *oi->mtimep = st.st_mtime;
+               }
 
                ret = 0;
                goto out;
@@ -446,7 +451,21 @@ static int read_object_info_from_path(struct odb_source *source,
                goto out;
        }
 
-       map = map_fd(fd, path, &mapsize);
+       if (fstat(fd, &st)) {
+               close(fd);
+               ret = -1;
+               goto out;
+       }
+
+       mapsize = xsize_t(st.st_size);
+       if (!mapsize) {
+               close(fd);
+               ret = error(_("object file %s is empty"), path);
+               goto out;
+       }
+
+       map = xmmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+       close(fd);
        if (!map) {
                ret = -1;
                goto out;
@@ -454,6 +473,8 @@ static int read_object_info_from_path(struct odb_source *source,
 
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
+       if (oi->mtimep)
+               *oi->mtimep = st.st_mtime;
 
        stream_to_end = &stream;
 
diff --git a/odb.c b/odb.c
index 65f0447aa5eb204fc4deb7040dd76a5f2102caa5..67decd39087f74d23776d763f0987a7da97cdbe4 100644 (file)
--- a/odb.c
+++ b/odb.c
@@ -702,6 +702,8 @@ static int do_oid_object_info_extended(struct object_database *odb,
                                oidclr(oi->delta_base_oid, odb->repo->hash_algo);
                        if (oi->contentp)
                                *oi->contentp = xmemdupz(co->buf, co->size);
+                       if (oi->mtimep)
+                               *oi->mtimep = 0;
                        oi->whence = OI_CACHED;
                }
                return 0;
diff --git a/odb.h b/odb.h
index 8f6d95aee54f98e7c7c6f13dff20e853cbbfa5df..9e22f79172e96faab4f23b21dd1b9a53213bcb40 100644 (file)
--- a/odb.h
+++ b/odb.h
@@ -317,6 +317,7 @@ struct object_info {
        off_t *disk_sizep;
        struct object_id *delta_base_oid;
        void **contentp;
+       time_t *mtimep;
 
        /* Response */
        enum {
index 4f84bc19d9fb6acf99ed52c9da76dbf029f8e60f..c96ec21f866e713b0a24f1971c6e21e01b6f2442 100644 (file)
@@ -1578,13 +1578,14 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
        hashmap_add(&delta_base_cache, &ent->ent);
 }
 
-int packed_object_info(struct packed_git *p,
-                      off_t obj_offset, struct object_info *oi)
+static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
+                                            uint32_t *maybe_index_pos, struct object_info *oi)
 {
        struct pack_window *w_curs = NULL;
        unsigned long size;
        off_t curpos = obj_offset;
        enum object_type type = OBJ_NONE;
+       uint32_t pack_pos;
        int ret;
 
        /*
@@ -1619,16 +1620,34 @@ int packed_object_info(struct packed_git *p,
                }
        }
 
-       if (oi->disk_sizep) {
-               uint32_t pos;
-               if (offset_to_pack_pos(p, obj_offset, &pos) < 0) {
+       if (oi->disk_sizep || (oi->mtimep && p->is_cruft)) {
+               if (offset_to_pack_pos(p, obj_offset, &pack_pos) < 0) {
                        error("could not find object at offset %"PRIuMAX" "
                              "in pack %s", (uintmax_t)obj_offset, p->pack_name);
                        ret = -1;
                        goto out;
                }
+       }
+
+       if (oi->disk_sizep)
+               *oi->disk_sizep = pack_pos_to_offset(p, pack_pos + 1) - obj_offset;
+
+       if (oi->mtimep) {
+               if (p->is_cruft) {
+                       uint32_t index_pos;
+
+                       if (load_pack_mtimes(p) < 0)
+                               die(_("could not load cruft pack .mtimes"));
+
+                       if (maybe_index_pos)
+                               index_pos = *maybe_index_pos;
+                       else
+                               index_pos = pack_pos_to_index(p, pack_pos);
 
-               *oi->disk_sizep = pack_pos_to_offset(p, pos + 1) - obj_offset;
+                       *oi->mtimep = nth_packed_mtime(p, index_pos);
+               } else {
+                       *oi->mtimep = p->mtime;
+               }
        }
 
        if (oi->typep) {
@@ -1681,6 +1700,12 @@ out:
        return ret;
 }
 
+int packed_object_info(struct packed_git *p, off_t obj_offset,
+                      struct object_info *oi)
+{
+       return packed_object_info_with_index_pos(p, obj_offset, NULL, oi);
+}
+
 static void *unpack_compressed_entry(struct packed_git *p,
                                    struct pack_window **w_curs,
                                    off_t curpos,
@@ -2377,7 +2402,8 @@ static int packfile_store_for_each_object_wrapper(const struct object_id *oid,
        if (data->oi) {
                off_t offset = nth_packed_object_offset(pack, index_pos);
 
-               if (packed_object_info(pack, offset, data->oi) < 0) {
+               if (packed_object_info_with_index_pos(pack, offset,
+                                                     &index_pos, data->oi) < 0) {
                        mark_bad_packed_object(pack, oid);
                        return -1;
                }