]> git.ipfire.org Git - thirdparty/git.git/blobdiff - object-file.c
Merge branch 'ns/batch-fsync'
[thirdparty/git.git] / object-file.c
index a696f5ec69a8825f94a28ef475c75dd6d4428b54..2a1f3386f6a970d943fc306a870864db04039599 100644 (file)
@@ -274,10 +274,11 @@ static struct cached_object {
 static int cached_object_nr, cached_object_alloc;
 
 static struct cached_object empty_tree = {
-       { EMPTY_TREE_SHA1_BIN_LITERAL },
-       OBJ_TREE,
-       "",
-       0
+       .oid = {
+               .hash = EMPTY_TREE_SHA1_BIN_LITERAL,
+       },
+       .type = OBJ_TREE,
+       .buf = "",
 };
 
 static struct cached_object *find_cached_object(const struct object_id *oid)
@@ -1049,35 +1050,50 @@ void *xmmap(void *start, size_t length,
        return ret;
 }
 
-/*
- * With an in-core object data in "map", rehash it to make sure the
- * object name actually matches "oid" to detect object corruption.
- * With "map" == NULL, try reading the object named with "oid" using
- * the streaming interface and rehash it to do the same.
- */
+static int format_object_header_literally(char *str, size_t size,
+                                         const char *type, size_t objsize)
+{
+       return xsnprintf(str, size, "%s %"PRIuMAX, type, (uintmax_t)objsize) + 1;
+}
+
+int format_object_header(char *str, size_t size, enum object_type type,
+                        size_t objsize)
+{
+       const char *name = type_name(type);
+
+       if (!name)
+               BUG("could not get a type name for 'enum object_type' value %d", type);
+
+       return format_object_header_literally(str, size, name, objsize);
+}
+
 int check_object_signature(struct repository *r, const struct object_id *oid,
-                          void *map, unsigned long size, const char *type,
-                          struct object_id *real_oidp)
+                          void *buf, unsigned long size,
+                          enum object_type type)
 {
-       struct object_id tmp;
-       struct object_id *real_oid = real_oidp ? real_oidp : &tmp;
+       struct object_id real_oid;
+
+       hash_object_file(r->hash_algo, buf, size, type, &real_oid);
+
+       return !oideq(oid, &real_oid) ? -1 : 0;
+}
+
+int stream_object_signature(struct repository *r, const struct object_id *oid)
+{
+       struct object_id real_oid;
+       unsigned long size;
        enum object_type obj_type;
        struct git_istream *st;
        git_hash_ctx c;
        char hdr[MAX_HEADER_LEN];
        int hdrlen;
 
-       if (map) {
-               hash_object_file(r->hash_algo, map, size, type, real_oid);
-               return !oideq(oid, real_oid) ? -1 : 0;
-       }
-
        st = open_istream(r, oid, &obj_type, &size, NULL);
        if (!st)
                return -1;
 
        /* Generate the header */
-       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1;
+       hdrlen = format_object_header(hdr, sizeof(hdr), obj_type, size);
 
        /* Sha1.. */
        r->hash_algo->init_fn(&c);
@@ -1094,9 +1110,9 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
                        break;
                r->hash_algo->update_fn(&c, buf, readlen);
        }
-       r->hash_algo->final_oid_fn(real_oid, &c);
+       r->hash_algo->final_oid_fn(&real_oid, &c);
        close_istream(st);
-       return !oideq(oid, real_oid) ? -1 : 0;
+       return !oideq(oid, &real_oid) ? -1 : 0;
 }
 
 int git_open_cloexec(const char *name, int flags)
@@ -1662,7 +1678,7 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
 {
        struct cached_object *co;
 
-       hash_object_file(the_hash_algo, buf, len, type_name(type), oid);
+       hash_object_file(the_hash_algo, buf, len, type, oid);
        if (has_object_file_with_flags(oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
            find_cached_object(oid))
                return 0;
@@ -1712,7 +1728,7 @@ void *read_object_file_extended(struct repository *r,
                die(_("loose object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), path);
 
-       if ((p = has_packed_and_bad(r, repl)) != NULL)
+       if ((p = has_packed_and_bad(r, repl)))
                die(_("packed object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), p->pack_name);
        obj_read_unlock();
@@ -1722,16 +1738,15 @@ void *read_object_file_extended(struct repository *r,
 
 void *read_object_with_reference(struct repository *r,
                                 const struct object_id *oid,
-                                const char *required_type_name,
+                                enum object_type required_type,
                                 unsigned long *size,
                                 struct object_id *actual_oid_return)
 {
-       enum object_type type, required_type;
+       enum object_type type;
        void *buffer;
        unsigned long isize;
        struct object_id actual_oid;
 
-       required_type = type_from_string(required_type_name);
        oidcpy(&actual_oid, oid);
        while (1) {
                int ref_length = -1;
@@ -1769,21 +1784,40 @@ void *read_object_with_reference(struct repository *r,
        }
 }
 
+static void hash_object_body(const struct git_hash_algo *algo, git_hash_ctx *c,
+                            const void *buf, unsigned long len,
+                            struct object_id *oid,
+                            char *hdr, int *hdrlen)
+{
+       algo->init_fn(c);
+       algo->update_fn(c, hdr, *hdrlen);
+       algo->update_fn(c, buf, len);
+       algo->final_oid_fn(oid, c);
+}
+
 static void write_object_file_prepare(const struct git_hash_algo *algo,
                                      const void *buf, unsigned long len,
-                                     const char *type, struct object_id *oid,
+                                     enum object_type type, struct object_id *oid,
                                      char *hdr, int *hdrlen)
 {
        git_hash_ctx c;
 
        /* Generate the header */
-       *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1;
+       *hdrlen = format_object_header(hdr, *hdrlen, type, len);
 
        /* Sha1.. */
-       algo->init_fn(&c);
-       algo->update_fn(&c, hdr, *hdrlen);
-       algo->update_fn(&c, buf, len);
-       algo->final_oid_fn(oid, &c);
+       hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
+}
+
+static void write_object_file_prepare_literally(const struct git_hash_algo *algo,
+                                     const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     char *hdr, int *hdrlen)
+{
+       git_hash_ctx c;
+
+       *hdrlen = format_object_header_literally(hdr, *hdrlen, type, len);
+       hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
 }
 
 /*
@@ -1836,29 +1870,36 @@ static int write_buffer(int fd, const void *buf, size_t len)
        return 0;
 }
 
-int hash_object_file(const struct git_hash_algo *algo, const void *buf,
-                    unsigned long len, const char *type,
-                    struct object_id *oid)
+static void hash_object_file_literally(const struct git_hash_algo *algo,
+                                      const void *buf, unsigned long len,
+                                      const char *type, struct object_id *oid)
 {
        char hdr[MAX_HEADER_LEN];
        int hdrlen = sizeof(hdr);
-       write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
-       return 0;
+
+       write_object_file_prepare_literally(algo, buf, len, type, oid, hdr, &hdrlen);
+}
+
+void hash_object_file(const struct git_hash_algo *algo, const void *buf,
+                     unsigned long len, enum object_type type,
+                     struct object_id *oid)
+{
+       hash_object_file_literally(algo, buf, len, type_name(type), oid);
 }
 
 /* Finalize a file on disk, and close it. */
-static void close_loose_object(int fd)
+static void close_loose_object(int fd, const char *filename)
 {
        if (the_repository->objects->odb->will_destroy)
                goto out;
 
        if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
-               fsync_loose_object_bulk_checkin(fd, "loose object file");
+               fsync_loose_object_bulk_checkin(fd, filename);
        else if (fsync_object_files > 0)
-               fsync_or_die(fd, "loose object file");
+               fsync_or_die(fd, filename);
        else
                fsync_component_or_die(FSYNC_COMPONENT_LOOSE_OBJECT, fd,
-                                      "loose object file");
+                                      filename);
 
 out:
        if (close(fd) != 0)
@@ -1975,7 +2016,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
 
-       close_loose_object(fd);
+       close_loose_object(fd, tmp_file.buf);
 
        if (mtime) {
                struct utimbuf utb;
@@ -2008,7 +2049,7 @@ static int freshen_packed_object(const struct object_id *oid)
 }
 
 int write_object_file_flags(const void *buf, unsigned long len,
-                           const char *type, struct object_id *oid,
+                           enum object_type type, struct object_id *oid,
                            unsigned flags)
 {
        char hdr[MAX_HEADER_LEN];
@@ -2024,9 +2065,9 @@ int write_object_file_flags(const void *buf, unsigned long len,
        return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
 }
 
-int hash_object_file_literally(const void *buf, unsigned long len,
-                              const char *type, struct object_id *oid,
-                              unsigned flags)
+int write_object_file_literally(const void *buf, unsigned long len,
+                               const char *type, struct object_id *oid,
+                               unsigned flags)
 {
        char *header;
        int hdrlen, status = 0;
@@ -2034,8 +2075,8 @@ int hash_object_file_literally(const void *buf, unsigned long len,
        /* type string, SP, %lu of the length plus NUL must fit this */
        hdrlen = strlen(type) + MAX_HEADER_LEN;
        header = xmalloc(hdrlen);
-       write_object_file_prepare(the_hash_algo, buf, len, type, oid, header,
-                                 &hdrlen);
+       write_object_file_prepare_literally(the_hash_algo, buf, len, type,
+                                           oid, header, &hdrlen);
 
        if (!(flags & HASH_WRITE_OBJECT))
                goto cleanup;
@@ -2062,7 +2103,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
        buf = read_object(the_repository, oid, &type, &len);
        if (!buf)
                return error(_("cannot read object for %s"), oid_to_hex(oid));
-       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
+       hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
        ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
        free(buf);
 
@@ -2128,7 +2169,8 @@ static int index_mem(struct index_state *istate,
                     enum object_type type,
                     const char *path, unsigned flags)
 {
-       int ret, re_allocated = 0;
+       int ret = 0;
+       int re_allocated = 0;
        int write_object = flags & HASH_WRITE_OBJECT;
 
        if (!type)
@@ -2155,10 +2197,9 @@ static int index_mem(struct index_state *istate,
        }
 
        if (write_object)
-               ret = write_object_file(buf, size, type_name(type), oid);
+               ret = write_object_file(buf, size, type, oid);
        else
-               ret = hash_object_file(the_hash_algo, buf, size,
-                                      type_name(type), oid);
+               hash_object_file(the_hash_algo, buf, size, type, oid);
        if (re_allocated)
                free(buf);
        return ret;
@@ -2170,7 +2211,7 @@ static int index_stream_convert_blob(struct index_state *istate,
                                     const char *path,
                                     unsigned flags)
 {
-       int ret;
+       int ret = 0;
        const int write_object = flags & HASH_WRITE_OBJECT;
        struct strbuf sbuf = STRBUF_INIT;
 
@@ -2181,11 +2222,11 @@ static int index_stream_convert_blob(struct index_state *istate,
                                 get_conv_flags(flags));
 
        if (write_object)
-               ret = write_object_file(sbuf.buf, sbuf.len, type_name(OBJ_BLOB),
+               ret = write_object_file(sbuf.buf, sbuf.len, OBJ_BLOB,
                                        oid);
        else
-               ret = hash_object_file(the_hash_algo, sbuf.buf, sbuf.len,
-                                      type_name(OBJ_BLOB), oid);
+               hash_object_file(the_hash_algo, sbuf.buf, sbuf.len, OBJ_BLOB,
+                                oid);
        strbuf_release(&sbuf);
        return ret;
 }
@@ -2304,8 +2345,8 @@ int index_path(struct index_state *istate, struct object_id *oid,
                        return error_errno("readlink(\"%s\")", path);
                if (!(flags & HASH_WRITE_OBJECT))
                        hash_object_file(the_hash_algo, sb.buf, sb.len,
-                                        blob_type, oid);
-               else if (write_object_file(sb.buf, sb.len, blob_type, oid))
+                                        OBJ_BLOB, oid);
+               else if (write_object_file(sb.buf, sb.len, OBJ_BLOB, oid))
                        rc = error(_("%s: failed to insert into database"), path);
                strbuf_release(&sb);
                break;
@@ -2587,8 +2628,12 @@ int read_loose_object(const char *path,
                goto out;
        }
 
-       if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
-                               NULL) < 0) {
+       switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
+                                   NULL)) {
+       case ULHR_OK:
+               break;
+       case ULHR_BAD:
+       case ULHR_TOO_LONG:
                error(_("unable to unpack header of %s"), path);
                goto out;
        }
@@ -2609,9 +2654,10 @@ int read_loose_object(const char *path,
                        git_inflate_end(&stream);
                        goto out;
                }
-               if (check_object_signature(the_repository, expected_oid,
+               hash_object_file_literally(the_repository->hash_algo,
                                           *contents, *size,
-                                          oi->type_name->buf, real_oid))
+                                          oi->type_name->buf, real_oid);
+               if (!oideq(expected_oid, real_oid))
                        goto out;
        }