Commit Diff


commit - b1f53f863b929b40c74bacac290784713457664d
commit + 93377578d3a22851253313461f9a4ff1900acdd5
blob - 87d939ce395b929e50c9e3257153b56b51c83716
blob + 3a641cf18f1e48d808261abc46eccd40b4ebb038
--- cvg/cvg.c
+++ cvg/cvg.c
@@ -9021,11 +9021,13 @@ static const struct got_error *
 cmd_info(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
+	struct got_repository *repo = NULL;
 	struct got_worktree *worktree = NULL;
 	char *cwd = NULL, *id_str = NULL;
 	struct got_pathlist_head paths;
 	char *uuidstr = NULL;
 	int ch, show_files = 0;
+	int *pack_fds = NULL;
 
 	TAILQ_INIT(&paths);
 
@@ -9058,6 +9060,15 @@ cmd_info(int argc, char *argv[])
 			error = wrap_not_worktree_error(error, "info", cwd);
 		goto done;
 	}
+
+	error = got_repo_pack_fds_open(&pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL,
+	    pack_fds);
+	if (error)
+		goto done;
 
 #ifndef PROFILE
 	/* Remove "wpath cpath proc exec sendfd" promises. */
@@ -9105,7 +9116,7 @@ cmd_info(int argc, char *argv[])
 			 */
 			pe->data = (void *)got_error(GOT_ERR_BAD_PATH);
 		}
-		error = got_worktree_path_info(worktree, &paths,
+		error = got_worktree_path_info(worktree, repo, &paths,
 		    print_path_info, &paths, check_cancelled, NULL);
 		if (error)
 			goto done;
@@ -9123,6 +9134,17 @@ cmd_info(int argc, char *argv[])
 done:
 	if (worktree)
 		got_worktree_close(worktree);
+	if (repo) {
+		const struct got_error *close_err = got_repo_close(repo);
+		if (error == NULL)
+			error = close_err;
+	}
+	if (pack_fds) {
+		const struct got_error *pack_err =
+		    got_repo_pack_fds_close(pack_fds);
+		if (error == NULL)
+			error = pack_err;
+	}
 	got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
 	free(cwd);
 	free(id_str);
blob - 997b1d0f9fb166dc969511ea80b23724dc8d9e6c
blob + 4ca1f1f4258c67ff27c56e47a3918d706f3589e6
--- got/got.c
+++ got/got.c
@@ -14608,10 +14608,12 @@ static const struct got_error *
 cmd_info(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
+	struct got_repository *repo = NULL;
 	struct got_worktree *worktree = NULL;
 	char *cwd = NULL, *id_str = NULL;
 	struct got_pathlist_head paths;
 	char *uuidstr = NULL;
+	int *pack_fds = NULL;
 	int ch, show_files = 0;
 
 	TAILQ_INIT(&paths);
@@ -14645,6 +14647,15 @@ cmd_info(int argc, char *argv[])
 			error = wrap_not_worktree_error(error, "info", cwd);
 		goto done;
 	}
+
+	error = got_repo_pack_fds_open(&pack_fds);
+	if (error != NULL)
+		goto done;
+
+	error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL,
+	    pack_fds);
+	if (error)
+		goto done;
 
 #ifndef PROFILE
 	/* Remove "wpath cpath proc exec sendfd" promises. */
@@ -14692,7 +14703,7 @@ cmd_info(int argc, char *argv[])
 			 */
 			pe->data = (void *)got_error(GOT_ERR_BAD_PATH);
 		}
-		error = got_worktree_path_info(worktree, &paths,
+		error = got_worktree_path_info(worktree, repo, &paths,
 		    print_path_info, &paths, check_cancelled, NULL);
 		if (error)
 			goto done;
@@ -14710,6 +14721,17 @@ cmd_info(int argc, char *argv[])
 done:
 	if (worktree)
 		got_worktree_close(worktree);
+	if (repo) {
+		const struct got_error *close_err = got_repo_close(repo);
+		if (error == NULL)
+			error = close_err;
+	}
+	if (pack_fds) {
+		const struct got_error *pack_err =
+		    got_repo_pack_fds_close(pack_fds);
+		if (error == NULL)
+			error = pack_err;
+	}
 	got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
 	free(cwd);
 	free(id_str);
blob - d2b62724acbc48c141e49a60bd36765fe2c58cad
blob + 4ad750063163bd75fcdbccf958d5b7b7a72278fb
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -590,8 +590,9 @@ typedef const struct got_error *(*got_worktree_path_in
  * a path, and meta-data arguments (see got_worktree_path_info_cb).
  */
 const struct got_error *
-got_worktree_path_info(struct got_worktree *, struct got_pathlist_head *,
-    got_worktree_path_info_cb, void *, got_cancel_cb , void *);
+got_worktree_path_info(struct got_worktree *, struct got_repository *,
+    struct got_pathlist_head *, got_worktree_path_info_cb, void *,
+    got_cancel_cb , void *);
 
 /* References pointing at pre-rebase commit backups. */
 #define GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX "refs/got/backup/rebase"
@@ -604,7 +605,7 @@ got_worktree_path_info(struct got_worktree *, struct g
  */
 const struct got_error *
 got_worktree_patch_prepare(struct got_fileindex **, char **,
-    struct got_worktree *);
+    struct got_worktree *, struct got_repository *);
 
 /*
  * Lookup paths for the "old" and "new" file before patching and check their
blob - 6569d7c0ef6815b70f9e1c721beaac52ce94c62e
blob + 7562966e2249f48aa8b9d58a623a51a74c97c9bf
--- lib/fileindex.c
+++ lib/fileindex.c
@@ -52,6 +52,7 @@ struct got_fileindex {
 	struct got_fileindex_tree entries;
 	int nentries; /* Does not include entries marked for removal. */
 #define GOT_FILEIDX_MAX_ENTRIES INT32_MAX
+	enum got_hash_algorithm algo;
 };
 
 mode_t
@@ -87,8 +88,8 @@ got_fileindex_perms_to_st(struct got_fileindex_entry *
 
 const struct got_error *
 got_fileindex_entry_update(struct got_fileindex_entry *ie,
-    int wt_fd, const char *ondisk_path, uint8_t *blob_sha1,
-    uint8_t *commit_sha1, int update_timestamps)
+    int wt_fd, const char *ondisk_path, struct got_object_id *blob,
+    struct got_object_id *commit, int update_timestamps)
 {
 	struct stat sb;
 
@@ -125,14 +126,14 @@ got_fileindex_entry_update(struct got_fileindex_entry 
 		}
 	}
 
-	if (blob_sha1) {
-		memmove(ie->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH);
+	if (blob) {
+		memmove(&ie->blob, blob, sizeof(ie->blob));
 		ie->flags &= ~GOT_FILEIDX_F_NO_BLOB;
 	} else
 		ie->flags |= GOT_FILEIDX_F_NO_BLOB;
 
-	if (commit_sha1) {
-		memmove(ie->commit_sha1, commit_sha1, SHA1_DIGEST_LENGTH);
+	if (commit) {
+		memmove(&ie->commit, commit, sizeof(ie->commit));
 		ie->flags &= ~GOT_FILEIDX_F_NO_COMMIT;
 	} else
 		ie->flags |= GOT_FILEIDX_F_NO_COMMIT;
@@ -329,7 +330,7 @@ got_fileindex_for_each_entry_safe(struct got_fileindex
 }
 
 struct got_fileindex *
-got_fileindex_alloc(void)
+got_fileindex_alloc(enum got_hash_algorithm algo)
 {
 	struct got_fileindex *fileindex;
 
@@ -337,6 +338,7 @@ got_fileindex_alloc(void)
 	if (fileindex == NULL)
 		return NULL;
 
+	fileindex->algo = algo;
 	RB_INIT(&fileindex->entries);
 	return fileindex;
 }
@@ -422,6 +424,7 @@ write_fileindex_entry(struct got_hash *ctx, struct got
 	const struct got_error *err;
 	size_t n;
 	uint32_t stage;
+	size_t digest_len = got_hash_digest_length(ctx->algo);
 
 	err = write_fileindex_val64(ctx, ie->ctime_sec, outfile);
 	if (err)
@@ -450,14 +453,14 @@ write_fileindex_entry(struct got_hash *ctx, struct got
 	if (err)
 		return err;
 
-	got_hash_update(ctx, ie->blob_sha1, SHA1_DIGEST_LENGTH);
-	n = fwrite(ie->blob_sha1, 1, SHA1_DIGEST_LENGTH, outfile);
-	if (n != SHA1_DIGEST_LENGTH)
+	got_hash_update(ctx, ie->blob.hash, digest_len);
+	n = fwrite(ie->blob.hash, 1, digest_len, outfile);
+	if (n != digest_len)
 		return got_ferror(outfile, GOT_ERR_IO);
 
-	got_hash_update(ctx, ie->commit_sha1, SHA1_DIGEST_LENGTH);
-	n = fwrite(ie->commit_sha1, 1, SHA1_DIGEST_LENGTH, outfile);
-	if (n != SHA1_DIGEST_LENGTH)
+	got_hash_update(ctx, ie->commit.hash, digest_len);
+	n = fwrite(ie->commit.hash, 1, digest_len, outfile);
+	if (n != digest_len)
 		return got_ferror(outfile, GOT_ERR_IO);
 
 	err = write_fileindex_val32(ctx, ie->flags, outfile);
@@ -471,10 +474,10 @@ write_fileindex_entry(struct got_hash *ctx, struct got
 	stage = got_fileindex_entry_stage_get(ie);
 	if (stage == GOT_FILEIDX_STAGE_MODIFY ||
 	    stage == GOT_FILEIDX_STAGE_ADD) {
-		got_hash_update(ctx, ie->staged_blob_sha1, SHA1_DIGEST_LENGTH);
-		n = fwrite(ie->staged_blob_sha1, 1, SHA1_DIGEST_LENGTH,
+		got_hash_update(ctx, ie->staged_blob.hash, digest_len);
+		n = fwrite(ie->staged_blob.hash, 1, digest_len,
 		    outfile);
-		if (n != SHA1_DIGEST_LENGTH)
+		if (n != digest_len)
 			return got_ferror(outfile, GOT_ERR_IO);
 	}
 
@@ -488,18 +491,22 @@ got_fileindex_write(struct got_fileindex *fileindex, F
 	struct got_fileindex_hdr hdr;
 	struct got_hash ctx;
 	uint8_t hash[GOT_HASH_DIGEST_MAXLEN];
-	size_t n;
+	size_t n, digest_len = got_hash_digest_length(fileindex->algo);
 	struct got_fileindex_entry *ie, *tmp;
 
-	got_hash_init(&ctx, GOT_HASH_SHA1);
+	memset(hash, 0, sizeof(hash));
 
+	got_hash_init(&ctx, fileindex->algo);
+
 	hdr.signature = htobe32(GOT_FILE_INDEX_SIGNATURE);
 	hdr.version = htobe32(GOT_FILE_INDEX_VERSION);
 	hdr.nentries = htobe32(fileindex->nentries);
+	hdr.algo = htobe32(fileindex->algo);
 
 	got_hash_update(&ctx, &hdr.signature, sizeof(hdr.signature));
 	got_hash_update(&ctx, &hdr.version, sizeof(hdr.version));
 	got_hash_update(&ctx, &hdr.nentries, sizeof(hdr.nentries));
+	got_hash_update(&ctx, &hdr.algo, sizeof(hdr.algo));
 	n = fwrite(&hdr.signature, 1, sizeof(hdr.signature), outfile);
 	if (n != sizeof(hdr.signature))
 		return got_ferror(outfile, GOT_ERR_IO);
@@ -509,6 +516,9 @@ got_fileindex_write(struct got_fileindex *fileindex, F
 	n = fwrite(&hdr.nentries, 1, sizeof(hdr.nentries), outfile);
 	if (n != sizeof(hdr.nentries))
 		return got_ferror(outfile, GOT_ERR_IO);
+	n = fwrite(&hdr.algo, 1, sizeof(hdr.algo), outfile);
+	if (n != sizeof(hdr.nentries))
+		return got_ferror(outfile, GOT_ERR_IO);
 
 	RB_FOREACH_SAFE(ie, got_fileindex_tree, &fileindex->entries, tmp) {
 		ie->flags &= ~GOT_FILEIDX_F_NOT_FLUSHED;
@@ -524,8 +534,8 @@ got_fileindex_write(struct got_fileindex *fileindex, F
 	}
 
 	got_hash_final(&ctx, hash);
-	n = fwrite(hash, 1, SHA1_DIGEST_LENGTH, outfile);
-	if (n != SHA1_DIGEST_LENGTH)
+	n = fwrite(hash, 1, digest_len, outfile);
+	if (n != digest_len)
 		return got_ferror(outfile, GOT_ERR_IO);
 
 	if (fflush(outfile) != 0)
@@ -600,11 +610,11 @@ read_fileindex_path(char **path, struct got_hash *ctx,
 
 static const struct got_error *
 read_fileindex_entry(struct got_fileindex_entry **iep, struct got_hash *ctx,
-    FILE *infile, uint32_t version)
+    FILE *infile, uint32_t version, enum got_hash_algorithm algo)
 {
 	const struct got_error *err;
 	struct got_fileindex_entry *ie;
-	size_t n;
+	size_t n, digest_len = got_hash_digest_length(algo);
 
 	*iep = NULL;
 
@@ -639,19 +649,21 @@ read_fileindex_entry(struct got_fileindex_entry **iep,
 	if (err)
 		goto done;
 
-	n = fread(ie->blob_sha1, 1, SHA1_DIGEST_LENGTH, infile);
-	if (n != SHA1_DIGEST_LENGTH) {
+	ie->blob.algo = algo;
+	n = fread(ie->blob.hash, 1, digest_len, infile);
+	if (n != digest_len) {
 		err = got_ferror(infile, GOT_ERR_FILEIDX_BAD);
 		goto done;
 	}
-	got_hash_update(ctx, ie->blob_sha1, SHA1_DIGEST_LENGTH);
+	got_hash_update(ctx, ie->blob.hash, digest_len);
 
-	n = fread(ie->commit_sha1, 1, SHA1_DIGEST_LENGTH, infile);
-	if (n != SHA1_DIGEST_LENGTH) {
+	ie->commit.algo = algo;
+	n = fread(ie->commit.hash, 1, digest_len, infile);
+	if (n != digest_len) {
 		err = got_ferror(infile, GOT_ERR_FILEIDX_BAD);
 		goto done;
 	}
-	got_hash_update(ctx, ie->commit_sha1, SHA1_DIGEST_LENGTH);
+	got_hash_update(ctx, ie->commit.hash, digest_len);
 
 	err = read_fileindex_val32(&ie->flags, ctx, infile);
 	if (err)
@@ -665,14 +677,15 @@ read_fileindex_entry(struct got_fileindex_entry **iep,
 		uint32_t stage = got_fileindex_entry_stage_get(ie);
 		if (stage == GOT_FILEIDX_STAGE_MODIFY ||
 		    stage == GOT_FILEIDX_STAGE_ADD) {
-			n = fread(ie->staged_blob_sha1, 1, SHA1_DIGEST_LENGTH,
+			ie->staged_blob.algo = algo;
+			n = fread(ie->staged_blob.hash, 1, digest_len,
 			    infile);
-			if (n != SHA1_DIGEST_LENGTH) {
+			if (n != digest_len) {
 				err = got_ferror(infile, GOT_ERR_FILEIDX_BAD);
 				goto done;
 			}
-			got_hash_update(ctx, ie->staged_blob_sha1,
-			    SHA1_DIGEST_LENGTH);
+			got_hash_update(ctx, ie->staged_blob.hash,
+			    digest_len);
 		}
 	} else {
 		/* GOT_FILE_INDEX_VERSION 1 does not support staging. */
@@ -688,19 +701,20 @@ done:
 }
 
 const struct got_error *
-got_fileindex_read(struct got_fileindex *fileindex, FILE *infile)
+got_fileindex_read(struct got_fileindex *fileindex, FILE *infile,
+    enum got_hash_algorithm repo_algo)
 {
 	const struct got_error *err = NULL;
 	struct got_fileindex_hdr hdr;
 	struct got_hash ctx;
 	struct got_fileindex_entry *ie;
-	uint8_t sha1_expected[SHA1_DIGEST_LENGTH];
-	uint8_t sha1[SHA1_DIGEST_LENGTH];
-	size_t n;
+	enum got_hash_algorithm algo = repo_algo;
+	uint8_t hash_expected[GOT_HASH_DIGEST_MAXLEN];
+	uint8_t hash[GOT_HASH_DIGEST_MAXLEN];
+	size_t n, digest_len;
+	uint32_t version;
 	int i;
 
-	got_hash_init(&ctx, GOT_HASH_SHA1);
-
 	n = fread(&hdr.signature, 1, sizeof(hdr.signature), infile);
 	if (n != sizeof(hdr.signature)) {
 		if (n == 0) /* EOF */
@@ -718,11 +732,30 @@ got_fileindex_read(struct got_fileindex *fileindex, FI
 		if (n == 0) /* EOF */
 			return NULL;
 		return got_ferror(infile, GOT_ERR_FILEIDX_BAD);
+	}
+	version = be32toh(hdr.version);
+
+	if (version >= 3) {
+		n = fread(&hdr.algo, 1, sizeof(hdr.algo), infile);
+		if (n != sizeof(hdr.algo)) {
+			if (n == 0) /* EOF */
+				return NULL;
+			return got_ferror(infile, GOT_ERR_FILEIDX_BAD);
+		}
+		algo = be32toh(hdr.algo);
+		if (algo != repo_algo)
+			return got_error_fmt(GOT_ERR_OBJECT_FORMAT,
+			    "unknown object format");
 	}
 
+	digest_len = got_hash_digest_length(algo);
+
+	got_hash_init(&ctx, algo);
 	got_hash_update(&ctx, &hdr.signature, sizeof(hdr.signature));
 	got_hash_update(&ctx, &hdr.version, sizeof(hdr.version));
 	got_hash_update(&ctx, &hdr.nentries, sizeof(hdr.nentries));
+	if (version >= 3)
+		got_hash_update(&ctx, &hdr.algo, sizeof(hdr.algo));
 
 	hdr.signature = be32toh(hdr.signature);
 	hdr.version = be32toh(hdr.version);
@@ -733,8 +766,10 @@ got_fileindex_read(struct got_fileindex *fileindex, FI
 	if (hdr.version > GOT_FILE_INDEX_VERSION)
 		return got_error(GOT_ERR_FILEIDX_VER);
 
+	fileindex->algo = algo;
 	for (i = 0; i < hdr.nentries; i++) {
-		err = read_fileindex_entry(&ie, &ctx, infile, hdr.version);
+		err = read_fileindex_entry(&ie, &ctx, infile,
+		    hdr.version, algo);
 		if (err)
 			return err;
 		err = add_entry(fileindex, ie);
@@ -744,11 +779,11 @@ got_fileindex_read(struct got_fileindex *fileindex, FI
 		}
 	}
 
-	n = fread(sha1_expected, 1, sizeof(sha1_expected), infile);
-	if (n != sizeof(sha1_expected))
+	n = fread(hash_expected, 1, digest_len, infile);
+	if (n != digest_len)
 		return got_ferror(infile, GOT_ERR_FILEIDX_BAD);
-	got_hash_final(&ctx, sha1);
-	if (memcmp(sha1, sha1_expected, SHA1_DIGEST_LENGTH) != 0)
+	got_hash_final(&ctx, hash);
+	if (got_hash_cmp(algo, hash, hash_expected) != 0)
 		return got_error(GOT_ERR_FILEIDX_CSUM);
 
 	return NULL;
@@ -1240,27 +1275,21 @@ struct got_object_id *
 got_fileindex_entry_get_staged_blob_id(struct got_object_id *id,
     struct got_fileindex_entry *ie)
 {
-	memset(id, 0, sizeof(*id));
-	memcpy(id->hash, ie->staged_blob_sha1, sizeof(ie->staged_blob_sha1));
-	return id;
+	return memcpy(id, &ie->staged_blob, sizeof(*id));
 }
 
 struct got_object_id *
 got_fileindex_entry_get_blob_id(struct got_object_id *id,
     struct got_fileindex_entry *ie)
 {
-	memset(id, 0, sizeof(*id));
-	memcpy(id->hash, ie->blob_sha1, sizeof(ie->blob_sha1));
-	return id;
+	return memcpy(id, &ie->blob, sizeof(*id));
 }
 
 struct got_object_id *
 got_fileindex_entry_get_commit_id(struct got_object_id *id,
     struct got_fileindex_entry *ie)
 {
-	memset(id, 0, sizeof(*id));
-	memcpy(id->hash, ie->commit_sha1, sizeof(ie->commit_sha1));
-	return id;
+	return memcpy(id, &ie->commit, sizeof(*id));
 }
 
 RB_GENERATE(got_fileindex_tree, got_fileindex_entry, entry, got_fileindex_cmp);
blob - 7045733009e3c274bef6f25b589a001bff3de260
blob + 7c7b47e3dc574a93a12fc50b094d200ba5622572
--- lib/got_lib_fileindex.h
+++ lib/got_lib_fileindex.h
@@ -46,11 +46,17 @@ struct got_fileindex_entry {
 #define GOT_FILEIDX_MODE_PERMS		0xfff0
 #define GOT_FILEIDX_MODE_PERMS_SHIFT	4
 
-	/* SHA1 of corresponding blob in repository. */
-	uint8_t blob_sha1[SHA1_DIGEST_LENGTH];
+	/*
+	 * id of corresponding blob in repository.  only the actual
+	 * hash is written to the disk.
+	 */
+	struct got_object_id blob;
 
-	/* SHA1 of corresponding base commit in repository. */
-	uint8_t commit_sha1[SHA1_DIGEST_LENGTH];
+	/*
+	 * id of corresponding base commit in repository.  only the
+	 * actual hash is written to the disk.
+	 */
+	struct got_object_id commit;
 
 	uint32_t flags;
 
@@ -62,11 +68,12 @@ struct got_fileindex_entry {
 
 	/*
 	 * (since GOT_FILE_INDEX_VERSION 2)
-	 * SHA1 of staged blob in repository if stage equals either
+	 * Hash of staged blob in repository if stage equals either
 	 * GOT_FILEIDX_STAGE_MODIFY or GOT_FILEIDX_STAGE_ADD.
 	 * Otherwise, this field is not written to disk.
+	 * Only the actual hash is written to the disk.
 	 */
-	uint8_t staged_blob_sha1[SHA1_DIGEST_LENGTH];
+	struct got_object_id staged_blob;
 };
 
 /* Modifications explicitly staged for commit. */
@@ -97,10 +104,15 @@ struct got_fileindex_hdr {
 	uint32_t signature;	/* big-endian */
 #define GOT_FILE_INDEX_SIGNATURE	0x676f7449 /* 'g', 'o', 't', 'I' */
 	uint32_t version;	/* big-endian */
-#define GOT_FILE_INDEX_VERSION	2
+#define GOT_FILE_INDEX_VERSION	3
 	uint32_t nentries;	/* big-endian */
+	uint32_t algo;		/* big-endian -- since v3 */
 	/* list of concatenated fileindex entries */
-	uint8_t sha1[SHA1_DIGEST_LENGTH]; /* checksum of above on-disk data */
+	/*
+	 * checksum of above on-disk data, the actual length of the
+	 * hash depends on the algorithm.
+	 */
+	uint8_t hash[GOT_HASH_DIGEST_MAXLEN];
 };
 
 mode_t got_fileindex_entry_perms_get(struct got_fileindex_entry *);
@@ -108,13 +120,13 @@ uint16_t got_fileindex_perms_from_st(struct stat *);
 mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *);
 
 const struct got_error *got_fileindex_entry_update(struct got_fileindex_entry *,
-    int, const char *, uint8_t *, uint8_t *, int);
+    int, const char *, struct got_object_id *, struct got_object_id *, int);
 void got_fileindex_entry_mark_skipped(struct got_fileindex_entry *);
 const struct got_error *got_fileindex_entry_alloc(struct got_fileindex_entry **,
     const char *);
 void got_fileindex_entry_free(struct got_fileindex_entry *);
 
-struct got_fileindex *got_fileindex_alloc(void);
+struct got_fileindex *got_fileindex_alloc(enum got_hash_algorithm);
 void got_fileindex_free(struct got_fileindex *);
 const struct got_error *got_fileindex_write(struct got_fileindex *, FILE *);
 const struct got_error *got_fileindex_entry_add(struct got_fileindex *,
@@ -123,7 +135,8 @@ void got_fileindex_entry_remove(struct got_fileindex *
     struct got_fileindex_entry *);
 struct got_fileindex_entry *got_fileindex_entry_get(struct got_fileindex *,
     const char *, size_t);
-const struct got_error *got_fileindex_read(struct got_fileindex *, FILE *);
+const struct got_error *got_fileindex_read(struct got_fileindex *, FILE *,
+	enum got_hash_algorithm);
 typedef const struct got_error *(*got_fileindex_cb)(void *,
     struct got_fileindex_entry *);
 const struct got_error *got_fileindex_for_each_entry_safe(
blob - 996cc7dfcfa8663dbcb68d5e6d2239b32f6598d9
blob + b559a190d58cd65bb489e31cdd7a513cd617ad23
--- lib/patch.c
+++ lib/patch.c
@@ -1081,7 +1081,7 @@ got_patch(int fd, struct got_worktree *worktree, struc
 		goto done;
 
 	err = got_worktree_patch_prepare(&fileindex, &fileindex_path,
-	    worktree);
+	    worktree, repo);
 	if (err)
 		goto done;
 
blob - 395ef382fc3ffceef47e20c4f0ae221df51a3d05
blob + 5a8c2707368f5ed8e5e2003dcf066bb87f7e88c1
--- lib/worktree.c
+++ lib/worktree.c
@@ -1114,7 +1114,7 @@ create_fileindex_entry(struct got_fileindex_entry **ne
 		return err;
 
 	err = got_fileindex_entry_update(new_ie, wt_fd, path,
-	    blob_id->hash, base_commit_id->hash, update_timestamps);
+	    blob_id, base_commit_id, update_timestamps);
 	if (err)
 		goto done;
 
@@ -1897,7 +1897,7 @@ sync_timestamps(int wt_fd, const char *path, unsigned 
 {
 	if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb))
 		return got_fileindex_entry_update(ie, wt_fd, path,
-		    ie->blob_sha1, ie->commit_sha1, 1);
+		    &ie->blob, &ie->commit, 1);
 
 	return NULL;
 }
@@ -2000,8 +2000,8 @@ update_blob(struct got_worktree *worktree,
 		 * updating contents of this file.
 		 */
 		if (got_fileindex_entry_has_commit(ie) &&
-		    memcmp(ie->commit_sha1, worktree->base_commit_id->hash,
-		    SHA1_DIGEST_LENGTH) == 0) {
+		    got_object_id_cmp(&ie->commit,
+		    worktree->base_commit_id) == 0) {
 			/* Same commit. */
 			err = sync_timestamps(worktree->root_fd,
 			    path, status, ie, &sb);
@@ -2012,14 +2012,12 @@ update_blob(struct got_worktree *worktree,
 			goto done;
 		}
 		if (got_fileindex_entry_has_blob(ie) &&
-		    memcmp(ie->blob_sha1, te->id.hash,
-		    SHA1_DIGEST_LENGTH) == 0) {
+		    got_object_id_cmp(&ie->blob, &te->id) == 0) {
 			/* Different commit but the same blob. */
 			if (got_fileindex_entry_has_commit(ie)) {
 				/* Update the base commit ID of this file. */
-				memcpy(ie->commit_sha1,
-				    worktree->base_commit_id->hash,
-				    sizeof(ie->commit_sha1));
+				memcpy(&ie->commit, worktree->base_commit_id,
+				    sizeof(ie->commit));
 			}
 			err = sync_timestamps(worktree->root_fd,
 			    path, status, ie, &sb);
@@ -2057,9 +2055,10 @@ update_blob(struct got_worktree *worktree,
 				goto done;
 		}
 		if (got_fileindex_entry_has_commit(ie)) {
-			char id_str[SHA1_DIGEST_STRING_LENGTH];
-			if (got_sha1_digest_to_str(ie->commit_sha1, id_str,
-			    sizeof(id_str)) == NULL) {
+			char id_str[GOT_HASH_DIGEST_STRING_MAXLEN];
+
+			if (got_hash_digest_to_str(ie->commit.hash, id_str,
+			    sizeof(id_str), ie->commit.algo) == NULL) {
 				err = got_error_path(id_str,
 				    GOT_ERR_BAD_OBJ_ID_STR);
 				goto done;
@@ -2100,17 +2099,16 @@ update_blob(struct got_worktree *worktree,
 		 * unmodified files again.
 		 */
 		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
-		    blob->id.hash, worktree->base_commit_id->hash,
-		    update_timestamps);
+		    &blob->id, worktree->base_commit_id, update_timestamps);
 	} else if (status == GOT_STATUS_MODE_CHANGE) {
 		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
-		    blob->id.hash, worktree->base_commit_id->hash, 0);
+		    &blob->id, worktree->base_commit_id, 0);
 	} else if (status == GOT_STATUS_DELETE) {
 		err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
 		if (err)
 			goto done;
 		err = got_fileindex_entry_update(ie, worktree->root_fd, path,
-		    blob->id.hash, worktree->base_commit_id->hash, 0);
+		    &blob->id, worktree->base_commit_id, 0);
 		if (err)
 			goto done;
 	} else {
@@ -2134,8 +2132,8 @@ update_blob(struct got_worktree *worktree,
 
 		if (ie) {
 			err = got_fileindex_entry_update(ie,
-			    worktree->root_fd, path, blob->id.hash,
-			    worktree->base_commit_id->hash, 1);
+			    worktree->root_fd, path, &blob->id,
+			    worktree->base_commit_id, 1);
 		} else {
 			err = create_fileindex_entry(&ie, fileindex,
 			    worktree->base_commit_id, worktree->root_fd, path,
@@ -2511,13 +2509,13 @@ get_fileindex_path(char **fileindex_path, struct got_w
 
 static const struct got_error *
 open_fileindex(struct got_fileindex **fileindex, char **fileindex_path,
-    struct got_worktree *worktree)
+    struct got_worktree *worktree, enum got_hash_algorithm algo)
 {
 	const struct got_error *err = NULL;
 	FILE *index = NULL;
 
+	*fileindex = got_fileindex_alloc(algo);
 	*fileindex_path = NULL;
-	*fileindex = got_fileindex_alloc();
 	if (*fileindex == NULL)
 		return got_error_from_errno("got_fileindex_alloc");
 
@@ -2530,7 +2528,7 @@ open_fileindex(struct got_fileindex **fileindex, char 
 		if (errno != ENOENT)
 			err = got_error_from_errno2("fopen", *fileindex_path);
 	} else {
-		err = got_fileindex_read(*fileindex, index);
+		err = got_fileindex_read(*fileindex, index, algo);
 		if (fclose(index) == EOF && err == NULL)
 			err = got_error_from_errno("fclose");
 	}
@@ -2568,8 +2566,7 @@ bump_base_commit_id(void *arg, struct got_fileindex_en
 	if (got_fileindex_entry_was_skipped(ie))
 		return NULL;
 
-	if (memcmp(ie->commit_sha1, a->base_commit_id->hash,
-	    SHA1_DIGEST_LENGTH) == 0)
+	if (got_object_id_cmp(&ie->commit, a->base_commit_id) == 0)
 		return NULL;
 
 	if (a->progress_cb) {
@@ -2578,7 +2575,7 @@ bump_base_commit_id(void *arg, struct got_fileindex_en
 		if (err)
 			return err;
 	}
-	memcpy(ie->commit_sha1, a->base_commit_id->hash, SHA1_DIGEST_LENGTH);
+	memcpy(&ie->commit, a->base_commit_id, sizeof(ie->commit));
 	return NULL;
 }
 
@@ -2867,7 +2864,8 @@ got_worktree_checkout_files(struct got_worktree *workt
 	 * Checking out files is supposed to be an idempotent operation.
 	 * If the on-disk file index is incomplete we will try to complete it.
 	 */
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -2965,8 +2963,8 @@ add_file(struct got_worktree *worktree, struct got_fil
 	} else {
 		/* Re-adding a locally deleted file. */
 		err = got_fileindex_entry_update(ie,
-		    worktree->root_fd, path2, ie->blob_sha1,
-		    worktree->base_commit_id->hash, 0);
+		    worktree->root_fd, path2, &ie->blob,
+		    worktree->base_commit_id, 0);
 		if (err)
 			return err;
 	}
@@ -3319,8 +3317,7 @@ check_mixed_commits(void *arg, struct got_fileindex_en
 
 	/* Reject merges into a work tree with mixed base commits. */
 	if (got_fileindex_entry_has_commit(ie) &&
-	    memcmp(ie->commit_sha1, a->worktree->base_commit_id->hash,
-	    SHA1_DIGEST_LENGTH) != 0)
+	    got_object_id_cmp(&ie->commit, a->worktree->base_commit_id) != 0)
 		return got_error(GOT_ERR_MIXED_COMMITS);
 
 	return NULL;
@@ -3358,7 +3355,8 @@ got_worktree_get_state(char *state, struct got_reposit
 	cma.cancel_arg = cancel_arg;
 
 	if (got_object_id_cmp(base_id, head_id) == 0) {
-		err = open_fileindex(&fileindex, &fileindex_path, worktree);
+		err = open_fileindex(&fileindex, &fileindex_path, worktree,
+		    got_repo_get_object_format(repo));
 		if (err)
 			goto done;
 
@@ -3567,7 +3565,8 @@ got_worktree_merge_files(struct got_worktree *worktree
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -4226,7 +4225,8 @@ got_worktree_status(struct got_worktree *worktree,
 	struct got_fileindex *fileindex = NULL;
 	struct got_pathlist_entry *pe;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		return err;
 
@@ -4444,7 +4444,8 @@ got_worktree_schedule_add(struct got_worktree *worktre
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -4634,7 +4635,8 @@ got_worktree_schedule_delete(struct got_worktree *work
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -5308,8 +5310,7 @@ revert_file(void *arg, unsigned char status, unsigned 
 			    status == GOT_STATUS_MODE_CHANGE) {
 				err = got_fileindex_entry_update(ie,
 				    a->worktree->root_fd, relpath,
-				    blob->id.hash,
-				    a->worktree->base_commit_id->hash, 1);
+				    &blob->id, a->worktree->base_commit_id, 1);
 				if (err)
 					goto done;
 			}
@@ -5358,7 +5359,8 @@ got_worktree_revert(struct got_worktree *worktree,
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -6281,22 +6283,20 @@ update_fileindex_after_commit(struct got_worktree *wor
 
 				err = got_fileindex_entry_update(ie,
 				    worktree->root_fd, relpath,
-				    ct->staged_blob_id->hash,
-				    new_base_commit_id->hash,
+				    ct->staged_blob_id, new_base_commit_id,
 				    !have_staged_files);
 			} else
 				err = got_fileindex_entry_update(ie,
 				    worktree->root_fd, relpath,
-				    ct->blob_id->hash,
-				    new_base_commit_id->hash,
+				    ct->blob_id, new_base_commit_id,
 				    !have_staged_files);
 		} else {
 			err = got_fileindex_entry_alloc(&ie, pe->path);
 			if (err)
 				goto done;
 			err = got_fileindex_entry_update(ie,
-			    worktree->root_fd, relpath, ct->blob_id->hash,
-			    new_base_commit_id->hash, 1);
+			    worktree->root_fd, relpath, ct->blob_id,
+			    new_base_commit_id, 1);
 			if (err) {
 				got_fileindex_entry_free(ie);
 				goto done;
@@ -6608,7 +6608,8 @@ got_worktree_commit(struct got_object_id **new_commit_
 	if (err)
 		goto done;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -6747,8 +6748,7 @@ check_rebase_ok(void *arg, struct got_fileindex_entry 
 	char *ondisk_path;
 
 	/* Reject rebase of a work tree with mixed base commits. */
-	if (memcmp(ie->commit_sha1, a->worktree->base_commit_id->hash,
-	    SHA1_DIGEST_LENGTH))
+	if (got_object_id_cmp(&ie->commit, a->worktree->base_commit_id))
 		return got_error(GOT_ERR_MIXED_COMMITS);
 
 	if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path)
@@ -6791,7 +6791,8 @@ got_worktree_rebase_prepare(struct got_reference **new
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -6907,7 +6908,8 @@ got_worktree_rebase_continue(struct got_object_id **co
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -7881,7 +7883,8 @@ got_worktree_histedit_prepare(struct got_reference **t
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -8017,7 +8020,8 @@ got_worktree_histedit_continue(struct got_object_id **
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -8404,7 +8408,8 @@ got_worktree_integrate_prepare(struct got_fileindex **
 		goto done;
 	}
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -8788,7 +8793,8 @@ const struct got_error *got_worktree_merge_prepare(
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -8894,7 +8900,8 @@ got_worktree_merge_continue(char **branch_name,
 	if (err)
 		return err;
 
-	err = open_fileindex(fileindex, &fileindex_path, worktree);
+	err = open_fileindex(fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -9234,8 +9241,8 @@ stage_path(void *arg, unsigned char status,
 		    path_content ? path_content : ondisk_path, a->repo);
 		if (err)
 			break;
-		memcpy(ie->staged_blob_sha1, new_staged_blob_id->hash,
-		    SHA1_DIGEST_LENGTH);
+		memcpy(&ie->staged_blob, new_staged_blob_id,
+		    sizeof(ie->staged_blob));
 		if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
 			stage = GOT_FILEIDX_STAGE_ADD;
 		else
@@ -9287,8 +9294,7 @@ stage_path(void *arg, unsigned char status,
 		 * When staging the reverse of the staged diff,
 		 * implicitly unstage the file.
 		 */
-		if (memcmp(ie->staged_blob_sha1, ie->blob_sha1,
-		    sizeof(ie->blob_sha1)) == 0) {
+		if (got_object_id_cmp(&ie->staged_blob, &ie->blob) == 0) {
 			got_fileindex_entry_stage_set(ie,
 			    GOT_FILEIDX_STAGE_NONE);
 		}
@@ -9366,7 +9372,8 @@ got_worktree_stage(struct got_worktree *worktree,
 	err = got_ref_resolve(&head_commit_id, repo, head_ref);
 	if (err)
 		goto done;
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -9705,8 +9712,8 @@ unstage_hunks(struct got_object_id *staged_blob_id,
 		goto done;
 
 	if (new_staged_blob_id) {
-		memcpy(ie->staged_blob_sha1, new_staged_blob_id->hash,
-		    SHA1_DIGEST_LENGTH);
+		memcpy(&ie->staged_blob, new_staged_blob_id,
+		    sizeof(ie->staged_blob));
 	} else {
 		got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE);
 		got_fileindex_entry_staged_filetype_set(ie, 0);
@@ -9913,7 +9920,8 @@ got_worktree_unstage(struct got_worktree *worktree,
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -9996,6 +10004,7 @@ report_file_info(void *arg, struct got_fileindex_entry
 
 const struct got_error *
 got_worktree_path_info(struct got_worktree *worktree,
+    struct got_repository *repo,
     struct got_pathlist_head *paths,
     got_worktree_path_info_cb info_cb, void *info_arg,
     got_cancel_cb cancel_cb, void *cancel_arg)
@@ -10010,7 +10019,8 @@ got_worktree_path_info(struct got_worktree *worktree,
 	if (err)
 		return err;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;
 
@@ -10116,9 +10126,11 @@ patch_can_edit(const char *path, unsigned char status,
 
 const struct got_error *
 got_worktree_patch_prepare(struct got_fileindex **fileindex,
-    char **fileindex_path, struct got_worktree *worktree)
+    char **fileindex_path, struct got_worktree *worktree,
+    struct got_repository *repo)
 {
-	return open_fileindex(fileindex, fileindex_path, worktree);
+	return open_fileindex(fileindex, fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 }
 
 const struct got_error *
blob - 9f62eb12777b37eb17942878776e9cf4c9f62943
blob + 1352c465ed6129ef5409f556f1ab3c0bae6edcc1
--- lib/worktree_cvg.c
+++ lib/worktree_cvg.c
@@ -560,13 +560,13 @@ get_fileindex_path(char **fileindex_path, struct got_w
 
 static const struct got_error *
 open_fileindex(struct got_fileindex **fileindex, char **fileindex_path,
-    struct got_worktree *worktree)
+    struct got_worktree *worktree, enum got_hash_algorithm algo)
 {
 	const struct got_error *err = NULL;
 	FILE *index = NULL;
 
 	*fileindex_path = NULL;
-	*fileindex = got_fileindex_alloc();
+	*fileindex = got_fileindex_alloc(algo);
 	if (*fileindex == NULL)
 		return got_error_from_errno("got_fileindex_alloc");
 
@@ -579,7 +579,7 @@ open_fileindex(struct got_fileindex **fileindex, char 
 		if (errno != ENOENT)
 			err = got_error_from_errno2("fopen", *fileindex_path);
 	} else {
-		err = got_fileindex_read(*fileindex, index);
+		err = got_fileindex_read(*fileindex, index, algo);
 		if (fclose(index) == EOF && err == NULL)
 			err = got_error_from_errno("fclose");
 	}
@@ -2142,22 +2142,20 @@ update_fileindex_after_commit(struct got_worktree *wor
 
 				err = got_fileindex_entry_update(ie,
 				    worktree->root_fd, relpath,
-				    ct->staged_blob_id->hash,
-				    new_base_commit_id->hash,
+				    ct->staged_blob_id, new_base_commit_id,
 				    !have_staged_files);
 			} else
 				err = got_fileindex_entry_update(ie,
 				    worktree->root_fd, relpath,
-				    ct->blob_id->hash,
-				    new_base_commit_id->hash,
+				    ct->blob_id, new_base_commit_id,
 				    !have_staged_files);
 		} else {
 			err = got_fileindex_entry_alloc(&ie, pe->path);
 			if (err)
 				goto done;
 			err = got_fileindex_entry_update(ie,
-			    worktree->root_fd, relpath, ct->blob_id->hash,
-			    new_base_commit_id->hash, 1);
+			    worktree->root_fd, relpath, ct->blob_id,
+			    new_base_commit_id, 1);
 			if (err) {
 				got_fileindex_entry_free(ie);
 				goto done;
@@ -2966,7 +2964,8 @@ got_worktree_cvg_commit(struct got_object_id **new_com
 	if (err)
 		goto done;
 
-	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	err = open_fileindex(&fileindex, &fileindex_path, worktree,
+	    got_repo_get_object_format(repo));
 	if (err)
 		goto done;