Commit Diff


commit - d69bcdf7cbe646a8ad22a81f8665f3bd2e39e189
commit + e09a504cc5b72ff4eca5d539b6fb50c8d01d0036
blob - a4975d670ed06aa6ed6696642cd7e23b2e0a0ee9
blob + 63ce30e7bcc45b4859409015ccaceab0666be898
--- got/got.c
+++ got/got.c
@@ -560,8 +560,8 @@ cmd_checkout(int argc, char *argv[])
 
 	if (commit_id_str) {
 		struct got_object_id *commit_id;
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_str);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_str, repo);
 		if (error != NULL)
 			goto done;
 		error = check_linear_ancestry(commit_id,
@@ -741,8 +741,8 @@ cmd_update(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 	} else {
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_str);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_str, repo);
 		if (error != NULL)
 			goto done;
 	}
@@ -1190,8 +1190,8 @@ cmd_log(int argc, char *argv[])
 				goto done;
 		}
 		if (commit == NULL) {
-			error = got_object_resolve_id_str(&id, repo,
-			    start_commit);
+			error = got_repo_match_object_id_prefix(&id,
+			    start_commit, repo);
 			if (error != NULL)
 				return error;
 		}
@@ -1429,7 +1429,7 @@ cmd_diff(int argc, char *argv[])
 		goto done;
 	}
 
-	error = got_object_resolve_id_str(&id1, repo, id_str1);
+	error = got_repo_match_object_id_prefix(&id1, id_str1, repo);
 	if (error) {
 		struct got_reference *ref;
 		if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
@@ -1454,7 +1454,7 @@ cmd_diff(int argc, char *argv[])
 		}
 	}
 
-	error = got_object_resolve_id_str(&id2, repo, id_str2);
+	error = got_repo_match_object_id_prefix(&id2, id_str2, repo);
 	if (error) {
 		struct got_reference *ref;
 		if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
@@ -1642,8 +1642,8 @@ cmd_blame(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 	} else {
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_str);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_str, repo);
 		if (error != NULL)
 			goto done;
 	}
@@ -1874,8 +1874,8 @@ cmd_tree(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 	} else {
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_str);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_str, repo);
 		if (error != NULL)
 			goto done;
 	}
@@ -2034,7 +2034,7 @@ add_ref(struct got_repository *repo, const char *refna
 	struct got_object_id *id;
 	struct got_reference *ref = NULL;
 
-	err = got_object_resolve_id_str(&id, repo, target);
+	err = got_repo_match_object_id_prefix(&id, target, repo);
 	if (err) {
 		struct got_reference *target_ref;
 
@@ -2996,7 +2996,7 @@ cmd_cherrypick(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_object_resolve_id_str(&commit_id, repo, argv[0]);
+	error = got_repo_match_object_id_prefix(&commit_id, argv[0], repo);
 	if (error != NULL) {
 		struct got_reference *ref;
 		if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
@@ -3105,7 +3105,7 @@ cmd_backout(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_object_resolve_id_str(&commit_id, repo, argv[0]);
+	error = got_repo_match_object_id_prefix(&commit_id, argv[0], repo);
 	if (error != NULL) {
 		struct got_reference *ref;
 		if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
blob - c05ac929d21262fe260f6843312f25459fc4a06d
blob + 83b7c99d663d7a35621aa740a8b3f4da13281612
--- include/got_error.h
+++ include/got_error.h
@@ -28,7 +28,7 @@
 #define GOT_ERR_BAD_OBJ_HDR	10
 #define GOT_ERR_OBJ_TYPE	11
 #define GOT_ERR_BAD_OBJ_DATA	12
-/* 13 is currently free for re-use */
+#define GOT_ERR_AMBIGUOUS_ID	13
 #define GOT_ERR_BAD_PACKIDX	14
 #define GOT_ERR_PACKIDX_CSUM	15
 #define GOT_ERR_BAD_PACKFILE	16
@@ -115,7 +115,7 @@ static const struct got_error {
 	{ GOT_ERR_BAD_OBJ_HDR,	"bad object header" },
 	{ GOT_ERR_OBJ_TYPE,	"wrong type of object" },
 	{ GOT_ERR_BAD_OBJ_DATA,	"bad object data" },
-	{ 13,			"unused error code" },
+	{ GOT_ERR_AMBIGUOUS_ID, "ambiguous object ID" },
 	{ GOT_ERR_BAD_PACKIDX,	"bad pack index file" },
 	{ GOT_ERR_PACKIDX_CSUM, "pack index file checksum error" },
 	{ GOT_ERR_BAD_PACKFILE,	"bad pack file" },
blob - 0b61b49e3ed0680170a01636840b554aac156059
blob + 69c2e095c3af4282d19b75475fcff80fe12aeef5
--- include/got_repository.h
+++ include/got_repository.h
@@ -57,3 +57,7 @@ const struct got_error *got_repo_map_path(char **, str
 
 /* Create a new repository in an empty directory at a specified path. */
 const struct got_error *got_repo_init(const char *);
+
+/* Attempt to find a unique object ID for a given ID string prefix. */
+const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **,
+    const char *, struct got_repository *);
blob - 449f4a66c5e45ada327bc786016b0b7788668394
blob + 241a9411ba3a191b9ceafd49e0fec3cd038b2049
--- lib/diff.c
+++ lib/diff.c
@@ -24,8 +24,8 @@
 #include <sha1.h>
 #include <zlib.h>
 
-#include "got_repository.h"
 #include "got_object.h"
+#include "got_repository.h"
 #include "got_error.h"
 #include "got_diff.h"
 #include "got_opentemp.h"
blob - 34beeb2b7345dac2a513a297aab77a4a94811563
blob + 7af741d237c7cd84aca6789c32dc4cdf3bb5237a
--- lib/got_lib_pack.h
+++ lib/got_lib_pack.h
@@ -161,6 +161,10 @@ const struct got_error *got_packidx_open(struct got_pa
     const char *, int);
 const struct got_error* got_packidx_close(struct got_packidx *);
 int got_packidx_get_object_idx(struct got_packidx *, struct got_object_id *);
+typedef const struct got_error *(*got_packidx_for_each_id_cb)(void *,
+    struct got_object_id *);
+const struct got_error *got_packidx_for_each_id(struct got_packidx *,
+    got_packidx_for_each_id_cb cb, void *);
 
 const struct got_error *got_packfile_open_object(struct got_object **,
     struct got_pack *, struct got_packidx *, int, struct got_object_id *);
blob - 691ab915f783045757051241faacca38bd22898f
blob + 60a273ea713af45d42943ac3274ba6081c775576
--- lib/object.c
+++ lib/object.c
@@ -1596,4 +1596,3 @@ done:
 	}
 	return err;
 }
-
blob - 9f38ab305851d89c4ee68b2ae45ad8935d7a6d87
blob + 269e6fa733cf1a2955a5e341a8d46504352492c9
--- lib/pack.c
+++ lib/pack.c
@@ -444,6 +444,27 @@ got_packidx_get_object_idx(struct got_packidx *packidx
 }
 
 const struct got_error *
+got_packidx_for_each_id(struct got_packidx *packidx,
+    got_packidx_for_each_id_cb cb, void *cb_arg)
+{
+	const struct got_error *err = NULL;
+	uint32_t nobj = betoh32(packidx->hdr.fanout_table[0xff]);
+	struct got_packidx_object_id *oid;
+	struct got_object_id id;
+	int i;
+
+	for (i = 0; i < nobj; i++) {
+		oid = &packidx->hdr.sorted_ids[i];
+		memcpy(&id, oid->sha1, SHA1_DIGEST_LENGTH);
+		err = cb(cb_arg, &id);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+const struct got_error *
 got_pack_stop_privsep_child(struct got_pack *pack)
 {
 	const struct got_error *err = NULL;
blob - 34d0da428d84d9053008e21e8223ac41ed646d33
blob + f4cf79809502ced018e0ec153ae2240982059eb5
--- lib/repository.c
+++ lib/repository.c
@@ -21,6 +21,7 @@
 #include <sys/mman.h>
 #include <sys/syslimits.h>
 
+#include <ctype.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <dirent.h>
@@ -48,6 +49,7 @@
 #include "got_lib_pack.h"
 #include "got_lib_privsep.h"
 #include "got_lib_worktree.h"
+#include "got_lib_sha1.h"
 #include "got_lib_object_cache.h"
 #include "got_lib_repository.h"
 
@@ -874,4 +876,220 @@ got_repo_init(const char *repo_path)
 		return err;
 
 	return NULL;
+}
+
+struct match_packidx_id_args {
+	const char *id_str_prefix;
+	struct got_object_id *unique_id;
+};
+
+static const struct got_error *
+match_packidx_id(void *arg, struct got_object_id *id)
+{
+	const struct got_error *err;
+	struct match_packidx_id_args *a = arg;
+	char *id_str;
+
+	err = got_object_id_str(&id_str, id);
+	if (err)
+		return err;
+
+	if (strncmp(a->id_str_prefix, id_str, strlen(a->id_str_prefix)) == 0) {
+		if (a->unique_id == NULL) {
+			a->unique_id = got_object_id_dup(id);
+			if (a->unique_id == NULL)
+				err = got_error_from_errno("got_object_id_dup");
+		}
+	}
+
+	free(id_str);
+	return err;
+}
+
+static const struct got_error *
+match_packed_object_id_prefix(struct got_object_id **unique_id,
+    struct got_repository *repo, const char *id_str_prefix)
+{
+	const struct got_error *err = NULL;
+	struct match_packidx_id_args args;
+	char *path_packdir;
+	DIR *packdir;
+	struct dirent *dent;
+	char *path_packidx;
+
+	*unique_id = NULL;
+
+	path_packdir = got_repo_get_path_objects_pack(repo);
+	if (path_packdir == NULL)
+		return got_error_from_errno("got_repo_get_path_objects_pack");
+
+	packdir = opendir(path_packdir);
+	if (packdir == NULL) {
+		err = got_error_from_errno2("opendir", path_packdir);
+		goto done;
+	}
+
+	while ((dent = readdir(packdir)) != NULL) {
+		struct got_packidx *packidx;
+		const struct got_error *cb_err;
+
+		if (!is_packidx_filename(dent->d_name, dent->d_namlen))
+			continue;
+
+		if (asprintf(&path_packidx, "%s/%s", path_packdir,
+		    dent->d_name) == -1) {
+			err = got_error_from_errno("asprintf");
+			goto done;
+		}
+
+		err = got_packidx_open(&packidx, path_packidx, 0);
+		free(path_packidx);
+		if (err)
+			goto done;
+
+		args.id_str_prefix = id_str_prefix;
+		args.unique_id = NULL;
+		cb_err = got_packidx_for_each_id(packidx, match_packidx_id,
+		    &args);
+		err = got_packidx_close(packidx);
+		if (err)
+			break;
+		if (cb_err) {
+			err = cb_err;
+			break;
+		}
+
+		if (args.unique_id) {
+			if (*unique_id == NULL)
+				*unique_id = args.unique_id;
+			else {
+				err = got_error(GOT_ERR_AMBIGUOUS_ID);
+				break;
+			}
+		}
+	}
+done:
+	free(path_packdir);
+	if (packdir && closedir(packdir) != 0 && err == NULL)
+		err = got_error_from_errno("closedir");
+	if (err) {
+		free(*unique_id);
+		*unique_id = NULL;
+	}
+	return err;
+}
+
+static const struct got_error *
+match_object_id(struct got_object_id **unique_id, const char *path_objects,
+    const char *object_dir, const char *id_str_prefix,
+    struct got_repository *repo)
+{
+	const struct got_error *err = NULL;
+	char *path;
+	DIR *dir = NULL;
+	struct dirent *dent;
+	struct got_object_id id;
+	int i;
+
+	for (i = 0; i < strlen(id_str_prefix); i++) {
+		if (isxdigit((unsigned char)id_str_prefix[i]))
+			continue;
+		return got_error(GOT_ERR_BAD_OBJ_ID_STR);
+	}
+
+	/* Search pack index. */
+	err = match_packed_object_id_prefix(unique_id, repo, id_str_prefix);
+	if (err)
+		return err;
+
+	/* Search on-disk directories. */
+	if (asprintf(&path, "%s/%s", path_objects, object_dir) == -1) {
+		err = got_error_from_errno("asprintf");
+		goto done;
+	}
+
+	dir = opendir(path);
+	if (dir == NULL) {
+		err = got_error_from_errno2("opendir", path);
+		goto done;
+	}
+	while ((dent = readdir(dir)) != NULL) {
+		char *id_str;
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+
+		if (asprintf(&id_str, "%s%s", object_dir, dent->d_name) == -1) {
+			err = got_error_from_errno("asprintf");
+			goto done;
+		}
+
+		if (!got_parse_sha1_digest(id.sha1, id_str))
+			continue;
+
+		if (strncmp(id_str_prefix, id_str,
+		    strlen(id_str_prefix)) != 0) {
+			free(id_str);
+			continue;
+		}
+
+		if (*unique_id == NULL) {
+			*unique_id = got_object_id_dup(&id);
+			if (*unique_id == NULL) {
+				err = got_error_from_errno("got_object_id_dup");
+				free(id_str);
+				goto done;
+			}
+		} else {
+			err = got_error(GOT_ERR_AMBIGUOUS_ID);
+			free(id_str);
+			goto done;
+		}
+	}
+
+	if (err == NULL && *unique_id == NULL)
+		err = got_error(GOT_ERR_NO_OBJ);
+done:
+	if (err) {
+		free(*unique_id);
+		*unique_id = NULL;
+	}
+	if (dir && closedir(dir) != 0 && err == NULL)
+		err = got_error_from_errno("closedir");
+	free(path);
+	return err;
 }
+
+const struct got_error *
+got_repo_match_object_id_prefix(struct got_object_id **id, const char *id_str_prefix,
+    struct got_repository *repo)
+{
+	const struct got_error *err = NULL;
+	char *path_objects = got_repo_get_path_objects(repo);
+	char *object_dir = NULL;
+	size_t len;
+
+	len = strlen(id_str_prefix);
+	if (len >= 2) {
+		object_dir = strndup(id_str_prefix, 2);
+		if (object_dir == NULL)
+			return got_error_from_errno("strdup");
+		err = match_object_id(id, path_objects, object_dir,
+		    id_str_prefix, repo);
+	} else if (len == 1) {
+		int i;
+		for (i = 0; i < 0xf; i++) {
+			if (asprintf(&object_dir, "%s%.1x", id_str_prefix, i)
+			    == -1)
+				return got_error_from_errno("asprintf");
+			err = match_object_id(id, path_objects, object_dir,
+			    id_str_prefix, repo);
+			if (err)
+				break;
+		}
+	} else
+		return got_error(GOT_ERR_BAD_OBJ_ID_STR);
+
+	free(object_dir);
+	return err;
+}
blob - fc0bb7562d2d4c401739ecf6172c5813f1448b59
blob + 79ae802838b0dee98d1c9dcf060003faa4c58629
--- tog/tog.c
+++ tog/tog.c
@@ -2221,8 +2221,8 @@ cmd_log(int argc, char *argv[])
 		    got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD,
 		    repo);
 	else
-		error = got_object_resolve_id_str(&start_id, repo,
-		    start_commit);
+		error = got_repo_match_object_id_prefix(&start_id,
+		    start_commit, repo);
 	if (error != NULL)
 		goto done;
 
@@ -2830,11 +2830,11 @@ cmd_diff(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_object_resolve_id_str(&id1, repo, id_str1);
+	error = got_repo_match_object_id_prefix(&id1, id_str1, repo);
 	if (error)
 		goto done;
 
-	error = got_object_resolve_id_str(&id2, repo, id_str2);
+	error = got_repo_match_object_id_prefix(&id2, id_str2, repo);
 	if (error)
 		goto done;
 
@@ -3684,8 +3684,8 @@ cmd_blame(int argc, char *argv[])
 		error = got_ref_resolve(&commit_id, repo, head_ref);
 		got_ref_close(head_ref);
 	} else {
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_str);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_str, repo);
 	}
 	if (error != NULL)
 		goto done;
@@ -4411,8 +4411,8 @@ cmd_tree(int argc, char *argv[])
 	if (commit_id_arg == NULL)
 		error = get_head_commit_id(&commit_id, GOT_REF_HEAD, repo);
 	else
-		error = got_object_resolve_id_str(&commit_id, repo,
-		    commit_id_arg);
+		error = got_repo_match_object_id_prefix(&commit_id,
+		    commit_id_arg, repo);
 	if (error != NULL)
 		goto done;