@@ -1943,6 +1943,87 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
return fd;
}
+/**
+ * Common steps for loose object writers to start writing loose
+ * objects:
+ *
+ * - Create tmpfile for the loose object.
+ * - Setup zlib stream for compression.
+ * - Start to feed header to zlib stream.
+ *
+ * Returns a "fd", which should later be provided to
+ * end_loose_object_common().
+ */
+static int start_loose_object_common(struct strbuf *tmp_file,
+ const char *filename, unsigned flags,
+ git_zstream *stream,
+ unsigned char *buf, size_t buflen,
+ git_hash_ctx *c,
+ char *hdr, int hdrlen)
+{
+ int fd;
+
+ fd = create_tmpfile(tmp_file, filename);
+ if (fd < 0) {
+ 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"));
+ }
+
+ /* Setup zlib stream for compression */
+ git_deflate_init(stream, zlib_compression_level);
+ stream->next_out = buf;
+ stream->avail_out = buflen;
+ the_hash_algo->init_fn(c);
+
+ /* Start to feed header to zlib stream */
+ stream->next_in = (unsigned char *)hdr;
+ stream->avail_in = hdrlen;
+ while (git_deflate(stream, 0) == Z_OK)
+ ; /* nothing */
+ the_hash_algo->update_fn(c, hdr, hdrlen);
+
+ return fd;
+}
+
+/**
+ * Common steps for loose object writers to end writing loose objects:
+ *
+ * - End the compression of zlib stream.
+ * - Get the calculated oid to "parano_oid".
+ * - fsync() and close() the "fd"
+ */
+static void end_loose_object_common(int fd, int ret, git_hash_ctx *c,
+ git_zstream *stream,
+ struct object_id *parano_oid,
+ const struct object_id *expected_oid,
+ const char *die_msg1_fmt,
+ const char *die_msg2_fmt)
+{
+ if (ret != Z_STREAM_END)
+ die(_(die_msg1_fmt), ret, expected_oid);
+ ret = git_deflate_end_gently(stream);
+ if (ret != Z_OK)
+ die(_(die_msg2_fmt), ret, expected_oid);
+ the_hash_algo->final_oid_fn(parano_oid, c);
+
+ /*
+ * We already did a write_buffer() to the "fd", let's fsync()
+ * and close().
+ *
+ * We might still die() on a subsequent sanity check, but
+ * let's not add to that confusion by not flushing any
+ * outstanding writes to disk first.
+ */
+ close_loose_object(fd);
+}
+
static int write_loose_object(const struct object_id *oid, char *hdr,
int hdrlen, const void *buf, unsigned long len,
time_t mtime, unsigned flags)
@@ -1957,28 +2038,11 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
loose_object_path(the_repository, &filename, oid);
- fd = create_tmpfile(&tmp_file, filename.buf);
- if (fd < 0) {
- 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"));
- }
-
- /* Set it up */
- git_deflate_init(&stream, zlib_compression_level);
- stream.next_out = compressed;
- stream.avail_out = sizeof(compressed);
- the_hash_algo->init_fn(&c);
-
- /* First header.. */
- stream.next_in = (unsigned char *)hdr;
- stream.avail_in = hdrlen;
- while (git_deflate(&stream, 0) == Z_OK)
- ; /* nothing */
- the_hash_algo->update_fn(&c, hdr, hdrlen);
+ fd = start_loose_object_common(&tmp_file, filename.buf, flags,
+ &stream, compressed, sizeof(compressed),
+ &c, hdr, hdrlen);
+ if (fd < 0)
+ return -1;
/* Then the data itself.. */
stream.next_in = (void *)buf;
@@ -1993,24 +2057,9 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
stream.avail_out = sizeof(compressed);
} while (ret == Z_OK);
- if (ret != Z_STREAM_END)
- die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
- ret);
- ret = git_deflate_end_gently(&stream);
- if (ret != Z_OK)
- die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
- ret);
- the_hash_algo->final_oid_fn(¶no_oid, &c);
-
- /*
- * We already did a write_buffer() to the "fd", let's fsync()
- * and close().
- *
- * We might still die() on a subsequent sanity check, but
- * let's not add to that confusion by not flushing any
- * outstanding writes to disk first.
- */
- close_loose_object(fd);
+ end_loose_object_common(fd, ret, &c, &stream, ¶no_oid, oid,
+ N_("unable to deflate new object %s (%d)"),
+ N_("deflateEnd on object %s failed (%d)"));
if (!oideq(oid, ¶no_oid))
die(_("confused by unstable object source data for %s"),