]> git.ipfire.org Git - thirdparty/git.git/blobdiff - object-file.c
reftable: fix resource warning
[thirdparty/git.git] / object-file.c
index 112d9b4badcfdeb2667aea1f2ea07c3adb6ea8e7..8d5a5b8afbec0c61466a5485b8c8623442c89db0 100644 (file)
@@ -165,7 +165,6 @@ static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx)
        BUG("trying to finalize unknown hash");
 }
 
-
 const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
        {
                NULL,
@@ -184,8 +183,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
        },
        {
                "sha1",
-               /* "sha1", big-endian */
-               0x73686131,
+               GIT_SHA1_FORMAT_ID,
                GIT_SHA1_RAWSZ,
                GIT_SHA1_HEXSZ,
                GIT_SHA1_BLKSZ,
@@ -200,8 +198,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
        },
        {
                "sha256",
-               /* "s256", big-endian */
-               0x73323536,
+               GIT_SHA256_FORMAT_ID,
                GIT_SHA256_RAWSZ,
                GIT_SHA256_HEXSZ,
                GIT_SHA256_BLKSZ,
@@ -1016,9 +1013,11 @@ void *xmmap(void *start, size_t length,
  * the streaming interface and rehash it to do the same.
  */
 int check_object_signature(struct repository *r, const struct object_id *oid,
-                          void *map, unsigned long size, const char *type)
+                          void *map, unsigned long size, const char *type,
+                          struct object_id *real_oidp)
 {
-       struct object_id real_oid;
+       struct object_id tmp;
+       struct object_id *real_oid = real_oidp ? real_oidp : &tmp;
        enum object_type obj_type;
        struct git_istream *st;
        git_hash_ctx c;
@@ -1026,8 +1025,8 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
        int hdrlen;
 
        if (map) {
-               hash_object_file(r->hash_algo, map, size, type, &real_oid);
-               return !oideq(oid, &real_oid) ? -1 : 0;
+               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);
@@ -1052,9 +1051,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)
@@ -1187,11 +1186,14 @@ void *map_loose_object(struct repository *r,
        return map_loose_object_1(r, NULL, oid, size);
 }
 
-static int unpack_loose_short_header(git_zstream *stream,
-                                    unsigned char *map, unsigned long mapsize,
-                                    void *buffer, unsigned long bufsiz)
+enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
+                                                   unsigned char *map,
+                                                   unsigned long mapsize,
+                                                   void *buffer,
+                                                   unsigned long bufsiz,
+                                                   struct strbuf *header)
 {
-       int ret;
+       int status;
 
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
@@ -1202,43 +1204,24 @@ static int unpack_loose_short_header(git_zstream *stream,
 
        git_inflate_init(stream);
        obj_read_unlock();
-       ret = git_inflate(stream, 0);
+       status = git_inflate(stream, 0);
        obj_read_lock();
-
-       return ret;
-}
-
-int unpack_loose_header(git_zstream *stream,
-                       unsigned char *map, unsigned long mapsize,
-                       void *buffer, unsigned long bufsiz)
-{
-       int status = unpack_loose_short_header(stream, map, mapsize,
-                                              buffer, bufsiz);
-
-       if (status < Z_OK)
-               return status;
-
-       /* Make sure we have the terminating NUL */
-       if (!memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
-               return -1;
-       return 0;
-}
-
-static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map,
-                                        unsigned long mapsize, void *buffer,
-                                        unsigned long bufsiz, struct strbuf *header)
-{
-       int status;
-
-       status = unpack_loose_short_header(stream, map, mapsize, buffer, bufsiz);
        if (status < Z_OK)
-               return -1;
+               return ULHR_BAD;
 
        /*
         * Check if entire header is unpacked in the first iteration.
         */
        if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
-               return 0;
+               return ULHR_OK;
+
+       /*
+        * We have a header longer than MAX_HEADER_LEN. The "header"
+        * here is only non-NULL when we run "cat-file
+        * --allow-unknown-type".
+        */
+       if (!header)
+               return ULHR_TOO_LONG;
 
        /*
         * buffer[0..bufsiz] was not large enough.  Copy the partial
@@ -1259,7 +1242,7 @@ static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map
                stream->next_out = buffer;
                stream->avail_out = bufsiz;
        } while (status != Z_STREAM_END);
-       return -1;
+       return ULHR_TOO_LONG;
 }
 
 static void *unpack_loose_rest(git_zstream *stream,
@@ -1317,11 +1300,10 @@ static void *unpack_loose_rest(git_zstream *stream,
  * too permissive for what we want to check. So do an anal
  * object header parse by hand.
  */
-static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
-                                      unsigned int flags)
+int parse_loose_header(const char *hdr, struct object_info *oi)
 {
        const char *type_buf = hdr;
-       unsigned long size;
+       size_t size;
        int type, type_len = 0;
 
        /*
@@ -1340,15 +1322,6 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
        type = type_from_string_gently(type_buf, type_len, 1);
        if (oi->type_name)
                strbuf_add(oi->type_name, type_buf, type_len);
-       /*
-        * Set type to 0 if its an unknown object and
-        * we're obtaining the type using '--allow-unknown-type'
-        * option.
-        */
-       if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
-               type = 0;
-       else if (type < 0)
-               die(_("invalid object type"));
        if (oi->typep)
                *oi->typep = type;
 
@@ -1365,25 +1338,24 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
                        if (c > 9)
                                break;
                        hdr++;
-                       size = size * 10 + c;
+                       size = st_add(st_mult(size, 10), c);
                }
        }
 
        if (oi->sizep)
-               *oi->sizep = size;
+               *oi->sizep = cast_size_t_to_ulong(size);
 
        /*
         * The length must be followed by a zero byte
         */
-       return *hdr ? -1 : type;
-}
-
-int parse_loose_header(const char *hdr, unsigned long *sizep)
-{
-       struct object_info oi = OBJECT_INFO_INIT;
+       if (*hdr)
+               return -1;
 
-       oi.sizep = sizep;
-       return parse_loose_header_extended(hdr, &oi, 0);
+       /*
+        * The format is valid, but the type may still be bogus. The
+        * Caller needs to check its oi->typep.
+        */
+       return 0;
 }
 
 static int loose_object_info(struct repository *r,
@@ -1397,6 +1369,8 @@ static int loose_object_info(struct repository *r,
        char hdr[MAX_HEADER_LEN];
        struct strbuf hdrbuf = STRBUF_INIT;
        unsigned long size_scratch;
+       enum object_type type_scratch;
+       int allow_unknown = flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
 
        if (oi->delta_base_oid)
                oidclr(oi->delta_base_oid);
@@ -1427,43 +1401,48 @@ static int loose_object_info(struct repository *r,
 
        if (!oi->sizep)
                oi->sizep = &size_scratch;
+       if (!oi->typep)
+               oi->typep = &type_scratch;
 
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
-       if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
-               if (unpack_loose_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
-                       status = error(_("unable to unpack %s header with --allow-unknown-type"),
-                                      oid_to_hex(oid));
-       } else if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+
+       switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
+                                   allow_unknown ? &hdrbuf : NULL)) {
+       case ULHR_OK:
+               if (parse_loose_header(hdrbuf.len ? hdrbuf.buf : hdr, oi) < 0)
+                       status = error(_("unable to parse %s header"), oid_to_hex(oid));
+               else if (!allow_unknown && *oi->typep < 0)
+                       die(_("invalid object type"));
+
+               if (!oi->contentp)
+                       break;
+               *oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
+               if (*oi->contentp)
+                       goto cleanup;
+
+               status = -1;
+               break;
+       case ULHR_BAD:
                status = error(_("unable to unpack %s header"),
                               oid_to_hex(oid));
-       if (status < 0)
-               ; /* Do nothing */
-       else if (hdrbuf.len) {
-               if ((status = parse_loose_header_extended(hdrbuf.buf, oi, flags)) < 0)
-                       status = error(_("unable to parse %s header with --allow-unknown-type"),
-                                      oid_to_hex(oid));
-       } else if ((status = parse_loose_header_extended(hdr, oi, flags)) < 0)
-               status = error(_("unable to parse %s header"), oid_to_hex(oid));
-
-       if (status >= 0 && oi->contentp) {
-               *oi->contentp = unpack_loose_rest(&stream, hdr,
-                                                 *oi->sizep, oid);
-               if (!*oi->contentp) {
-                       git_inflate_end(&stream);
-                       status = -1;
-               }
-       } else
-               git_inflate_end(&stream);
+               break;
+       case ULHR_TOO_LONG:
+               status = error(_("header for %s too long, exceeds %d bytes"),
+                              oid_to_hex(oid), MAX_HEADER_LEN);
+               break;
+       }
 
+       git_inflate_end(&stream);
+cleanup:
        munmap(map, mapsize);
-       if (status && oi->typep)
-               *oi->typep = status;
        if (oi->sizep == &size_scratch)
                oi->sizep = NULL;
        strbuf_release(&hdrbuf);
+       if (oi->typep == &type_scratch)
+               oi->typep = NULL;
        oi->whence = OI_LOOSE;
-       return (status < 0) ? status : 0;
+       return status;
 }
 
 int obj_read_use_lock = 0;
@@ -1546,7 +1525,14 @@ static int do_oid_object_info_extended(struct repository *r,
                                break;
                }
 
-               if (register_all_submodule_odb_as_alternates())
+               /*
+                * If r is the_repository, this might be an attempt at
+                * accessing a submodule object as if it were in the_repository
+                * (having called add_submodule_odb() on that submodule's ODB).
+                * If any such ODBs exist, register them and try again.
+                */
+               if (r == the_repository &&
+                   register_all_submodule_odb_as_alternates())
                        /* We added some alternates; retry */
                        continue;
 
@@ -1873,7 +1859,7 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
 
 static int write_loose_object(const struct object_id *oid, char *hdr,
                              int hdrlen, const void *buf, unsigned long len,
-                             time_t mtime)
+                             time_t mtime, unsigned flags)
 {
        int fd, ret;
        unsigned char compressed[4096];
@@ -1887,7 +1873,9 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
 
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
-               if (errno == EACCES)
+               if (flags & HASH_SILENT)
+                       return -1;
+               else if (errno == EACCES)
                        return error(_("insufficient permission for adding an object to repository database %s"), get_object_directory());
                else
                        return error_errno(_("unable to create temporary file"));
@@ -1937,7 +1925,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                struct utimbuf utb;
                utb.actime = mtime;
                utb.modtime = mtime;
-               if (utime(tmp_file.buf, &utb) < 0)
+               if (utime(tmp_file.buf, &utb) < 0 &&
+                   !(flags & HASH_SILENT))
                        warning_errno(_("failed utime() on %s"), tmp_file.buf);
        }
 
@@ -1962,8 +1951,9 @@ static int freshen_packed_object(const struct object_id *oid)
        return 1;
 }
 
-int write_object_file(const void *buf, unsigned long len, const char *type,
-                     struct object_id *oid)
+int write_object_file_flags(const void *buf, unsigned long len,
+                           const char *type, struct object_id *oid,
+                           unsigned flags)
 {
        char hdr[MAX_HEADER_LEN];
        int hdrlen = sizeof(hdr);
@@ -1975,7 +1965,7 @@ int write_object_file(const void *buf, unsigned long len, const char *type,
                                  &hdrlen);
        if (freshen_packed_object(oid) || freshen_loose_object(oid))
                return 0;
-       return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
+       return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
 }
 
 int hash_object_file_literally(const void *buf, unsigned long len,
@@ -1995,7 +1985,7 @@ int hash_object_file_literally(const void *buf, unsigned long len,
                goto cleanup;
        if (freshen_packed_object(oid) || freshen_loose_object(oid))
                goto cleanup;
-       status = write_loose_object(oid, header, hdrlen, buf, len, 0);
+       status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
 
 cleanup:
        free(header);
@@ -2017,7 +2007,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
        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;
-       ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
+       ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
        free(buf);
 
        return ret;
@@ -2524,17 +2514,16 @@ static int check_stream_oid(git_zstream *stream,
 
 int read_loose_object(const char *path,
                      const struct object_id *expected_oid,
-                     enum object_type *type,
-                     unsigned long *size,
-                     void **contents)
+                     struct object_id *real_oid,
+                     void **contents,
+                     struct object_info *oi)
 {
        int ret = -1;
        void *map = NULL;
        unsigned long mapsize;
        git_zstream stream;
        char hdr[MAX_HEADER_LEN];
-
-       *contents = NULL;
+       unsigned long *size = oi->sizep;
 
        map = map_loose_object_1(the_repository, path, NULL, &mapsize);
        if (!map) {
@@ -2542,19 +2531,19 @@ int read_loose_object(const char *path,
                goto out;
        }
 
-       if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
+       if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
+                               NULL) < 0) {
                error(_("unable to unpack header of %s"), path);
                goto out;
        }
 
-       *type = parse_loose_header(hdr, size);
-       if (*type < 0) {
+       if (parse_loose_header(hdr, oi) < 0) {
                error(_("unable to parse header of %s"), path);
                git_inflate_end(&stream);
                goto out;
        }
 
-       if (*type == OBJ_BLOB && *size > big_file_threshold) {
+       if (*oi->typep == OBJ_BLOB && *size > big_file_threshold) {
                if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
                        goto out;
        } else {
@@ -2566,12 +2555,8 @@ int read_loose_object(const char *path,
                }
                if (check_object_signature(the_repository, expected_oid,
                                           *contents, *size,
-                                          type_name(*type))) {
-                       error(_("hash mismatch for %s (expected %s)"), path,
-                             oid_to_hex(expected_oid));
-                       free(*contents);
+                                          oi->type_name->buf, real_oid))
                        goto out;
-               }
        }
 
        ret = 0; /* everything checks out */