summaryrefslogtreecommitdiff
path: root/pack-write.c
diff options
context:
space:
mode:
Diffstat (limited to 'pack-write.c')
-rw-r--r--pack-write.c184
1 files changed, 160 insertions, 24 deletions
diff --git a/pack-write.c b/pack-write.c
index e9bb3fd949..a5846f3a34 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -75,9 +75,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
index_name = strbuf_detach(&tmp_file, NULL);
} else {
unlink(index_name);
- fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
- if (fd < 0)
- die_errno("unable to create '%s'", index_name);
+ fd = xopen(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
}
f = hashfd(fd, index_name);
}
@@ -167,6 +165,128 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
return index_name;
}
+static int pack_order_cmp(const void *va, const void *vb, void *ctx)
+{
+ struct pack_idx_entry **objects = ctx;
+
+ off_t oa = objects[*(uint32_t*)va]->offset;
+ off_t ob = objects[*(uint32_t*)vb]->offset;
+
+ if (oa < ob)
+ return -1;
+ if (oa > ob)
+ return 1;
+ return 0;
+}
+
+static void write_rev_header(struct hashfile *f)
+{
+ uint32_t oid_version;
+ switch (hash_algo_by_ptr(the_hash_algo)) {
+ case GIT_HASH_SHA1:
+ oid_version = 1;
+ break;
+ case GIT_HASH_SHA256:
+ oid_version = 2;
+ break;
+ default:
+ die("write_rev_header: unknown hash version");
+ }
+
+ hashwrite_be32(f, RIDX_SIGNATURE);
+ hashwrite_be32(f, RIDX_VERSION);
+ hashwrite_be32(f, oid_version);
+}
+
+static void write_rev_index_positions(struct hashfile *f,
+ uint32_t *pack_order,
+ uint32_t nr_objects)
+{
+ uint32_t i;
+ for (i = 0; i < nr_objects; i++)
+ hashwrite_be32(f, pack_order[i]);
+}
+
+static void write_rev_trailer(struct hashfile *f, const unsigned char *hash)
+{
+ hashwrite(f, hash, the_hash_algo->rawsz);
+}
+
+const char *write_rev_file(const char *rev_name,
+ struct pack_idx_entry **objects,
+ uint32_t nr_objects,
+ const unsigned char *hash,
+ unsigned flags)
+{
+ uint32_t *pack_order;
+ uint32_t i;
+ const char *ret;
+
+ if (!(flags & WRITE_REV) && !(flags & WRITE_REV_VERIFY))
+ return NULL;
+
+ ALLOC_ARRAY(pack_order, nr_objects);
+ for (i = 0; i < nr_objects; i++)
+ pack_order[i] = i;
+ QSORT_S(pack_order, nr_objects, pack_order_cmp, objects);
+
+ ret = write_rev_file_order(rev_name, pack_order, nr_objects, hash,
+ flags);
+
+ free(pack_order);
+
+ return ret;
+}
+
+const char *write_rev_file_order(const char *rev_name,
+ uint32_t *pack_order,
+ uint32_t nr_objects,
+ const unsigned char *hash,
+ unsigned flags)
+{
+ struct hashfile *f;
+ int fd;
+
+ if ((flags & WRITE_REV) && (flags & WRITE_REV_VERIFY))
+ die(_("cannot both write and verify reverse index"));
+
+ if (flags & WRITE_REV) {
+ if (!rev_name) {
+ struct strbuf tmp_file = STRBUF_INIT;
+ fd = odb_mkstemp(&tmp_file, "pack/tmp_rev_XXXXXX");
+ rev_name = strbuf_detach(&tmp_file, NULL);
+ } else {
+ unlink(rev_name);
+ fd = xopen(rev_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ }
+ f = hashfd(fd, rev_name);
+ } else if (flags & WRITE_REV_VERIFY) {
+ struct stat statbuf;
+ if (stat(rev_name, &statbuf)) {
+ if (errno == ENOENT) {
+ /* .rev files are optional */
+ return NULL;
+ } else
+ die_errno(_("could not stat: %s"), rev_name);
+ }
+ f = hashfd_check(rev_name);
+ } else
+ return NULL;
+
+ write_rev_header(f);
+
+ write_rev_index_positions(f, pack_order, nr_objects);
+ write_rev_trailer(f, hash);
+
+ if (rev_name && adjust_shared_perm(rev_name) < 0)
+ die(_("failed to make %s readable"), rev_name);
+
+ finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_CLOSE |
+ ((flags & WRITE_IDX_VERIFY) ? 0 : CSUM_FSYNC));
+
+ return rev_name;
+}
+
off_t write_pack_header(struct hashfile *f, uint32_t nr_entries)
{
struct pack_header hdr;
@@ -273,7 +393,7 @@ void fixup_pack_header_footer(int pack_fd,
fsync_or_die(pack_fd, pack_name);
}
-char *index_pack_lockfile(int ip_out)
+char *index_pack_lockfile(int ip_out, int *is_well_formed)
{
char packname[GIT_MAX_HEXSZ + 6];
const int len = the_hash_algo->hexsz + 6;
@@ -287,11 +407,17 @@ char *index_pack_lockfile(int ip_out)
*/
if (read_in_full(ip_out, packname, len) == len && packname[len-1] == '\n') {
const char *name;
+
+ if (is_well_formed)
+ *is_well_formed = 1;
packname[len-1] = 0;
if (skip_prefix(packname, "keep\t", &name))
return xstrfmt("%s/pack/pack-%s.keep",
get_object_directory(), name);
+ return NULL;
}
+ if (is_well_formed)
+ *is_well_formed = 0;
return NULL;
}
@@ -335,38 +461,48 @@ struct hashfile *create_tmp_packfile(char **pack_tmp_name)
return hashfd(fd, *pack_tmp_name);
}
-void finish_tmp_packfile(struct strbuf *name_buffer,
+static void rename_tmp_packfile(struct strbuf *name_prefix, const char *source,
+ const char *ext)
+{
+ size_t name_prefix_len = name_prefix->len;
+
+ strbuf_addstr(name_prefix, ext);
+ if (rename(source, name_prefix->buf))
+ die_errno("unable to rename temporary file to '%s'",
+ name_prefix->buf);
+ strbuf_setlen(name_prefix, name_prefix_len);
+}
+
+void rename_tmp_packfile_idx(struct strbuf *name_buffer,
+ char **idx_tmp_name)
+{
+ rename_tmp_packfile(name_buffer, *idx_tmp_name, "idx");
+}
+
+void stage_tmp_packfiles(struct strbuf *name_buffer,
const char *pack_tmp_name,
struct pack_idx_entry **written_list,
uint32_t nr_written,
struct pack_idx_option *pack_idx_opts,
- unsigned char hash[])
+ unsigned char hash[],
+ char **idx_tmp_name)
{
- const char *idx_tmp_name;
- int basename_len = name_buffer->len;
+ const char *rev_tmp_name = NULL;
if (adjust_shared_perm(pack_tmp_name))
die_errno("unable to make temporary pack file readable");
- idx_tmp_name = write_idx_file(NULL, written_list, nr_written,
- pack_idx_opts, hash);
- if (adjust_shared_perm(idx_tmp_name))
+ *idx_tmp_name = (char *)write_idx_file(NULL, written_list, nr_written,
+ pack_idx_opts, hash);
+ if (adjust_shared_perm(*idx_tmp_name))
die_errno("unable to make temporary index file readable");
- strbuf_addf(name_buffer, "%s.pack", hash_to_hex(hash));
-
- if (rename(pack_tmp_name, name_buffer->buf))
- die_errno("unable to rename temporary pack file");
-
- strbuf_setlen(name_buffer, basename_len);
-
- strbuf_addf(name_buffer, "%s.idx", hash_to_hex(hash));
- if (rename(idx_tmp_name, name_buffer->buf))
- die_errno("unable to rename temporary index file");
-
- strbuf_setlen(name_buffer, basename_len);
+ rev_tmp_name = write_rev_file(NULL, written_list, nr_written, hash,
+ pack_idx_opts->flags);
- free((void *)idx_tmp_name);
+ rename_tmp_packfile(name_buffer, pack_tmp_name, "pack");
+ if (rev_tmp_name)
+ rename_tmp_packfile(name_buffer, rev_tmp_name, "rev");
}
void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought)