Commit c52736fa5226141754918cabf55c22be9c2aee1b

Vicent Marti 2011-07-09T15:05:14

status: Cleanup The `hashfile` function has been moved to ODB, next to `git_odb_hash`. Global state has been removed from the dirent call in `status.c`, because global state is killing the rainforest and causing global warming.

diff --git a/include/git2/odb.h b/include/git2/odb.h
index ef16e1e..d0c3690 100644
--- a/include/git2/odb.h
+++ b/include/git2/odb.h
@@ -282,6 +282,19 @@ GIT_EXTERN(int) git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const
 GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type);
 
 /**
+ * Read a file from disk and fill a git_oid with the object id
+ * that the file would have if it were written to the Object
+ * Database as an object of the given type. Similar functionality
+ * to git.git's `git hash-object` without the `-w` flag.
+ *
+ * @param out oid structure the result is written into.
+ * @param path file to read and determine object id for
+ * @param type the type of the object that will be hashed
+ * @return GIT_SUCCESS if valid; error code otherwise
+ */
+GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_otype type);
+
+/**
  * Close an ODB object
  *
  * This method must always be called once a `git_odb_object` is no
diff --git a/include/git2/status.h b/include/git2/status.h
index b8d4734..7946cc1 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -52,18 +52,6 @@ GIT_BEGIN_DECL
 #define GIT_STATUS_IGNORED        (1 << 6)
 
 /**
- * Read a file from disk and fill a git_oid with the object id
- * that the file would have if it were written to the Object
- * Database as a loose blob. Similar functionality to git.git's
- * `git hash-object` without the `-w` flag.
- *
- * @param out oid structure the result is written into.
- * @param path file to read and determine object id for
- * @return GIT_SUCCESS if valid; error code otherwise
- */
-GIT_EXTERN(int) git_status_hashfile(git_oid *out, const char *path);
-
-/**
  * Gather file statuses and run a callback for each one.
  *
  * The callback is passed the path of the file, the status and the data pointer
diff --git a/src/odb.c b/src/odb.c
index caa4e1b..52546e7 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -46,10 +46,10 @@ typedef struct
 	int is_alternate;
 } backend_internal;
 
-static int format_object_header(char *hdr, size_t n, git_rawobj *obj)
+static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
 {
-	const char *type_str = git_object_type2string(obj->type);
-	int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj->len);
+	const char *type_str = git_object_type2string(obj_type);
+	int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
 
 	assert(len > 0);             /* otherwise snprintf() is broken  */
 	assert(((size_t) len) < n);  /* otherwise the caller is broken! */
@@ -72,7 +72,7 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob
 	if (!obj->data && obj->len != 0)
 		return git__throw(GIT_ERROR, "Failed to hash object. No data given");
 
-	if ((hdrlen = format_object_header(hdr, n, obj)) < 0)
+	if ((hdrlen = format_object_header(hdr, n, obj->len, obj->type)) < 0)
 		return git__rethrow(hdrlen, "Failed to hash object");
 
 	*len = hdrlen;
@@ -134,6 +134,52 @@ void git_odb_object_close(git_odb_object *object)
 	git_cached_obj_decref((git_cached_obj *)object, &free_odb_object);
 }
 
+int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
+{
+	int fd, hdr_len;
+	char hdr[64], buffer[2048];
+	git_off_t size;
+	git_hash_ctx *ctx;
+
+	if ((fd = p_open(path, O_RDONLY)) < 0)
+		return git__throw(GIT_ENOTFOUND, "Could not open '%s'", path);
+
+	if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
+		p_close(fd);
+		return git__throw(GIT_EOSERR, "'%s' appears to be corrupted", path);
+	}
+
+	hdr_len = format_object_header(hdr, sizeof(hdr), size, type);
+	if (hdr_len < 0)
+		return git__throw(GIT_ERROR, "Failed to format blob header. Length is out of bounds");
+
+	ctx = git_hash_new_ctx();
+
+	git_hash_update(ctx, hdr, hdr_len);
+
+	while (size > 0) {
+		ssize_t read_len;
+
+		read_len = read(fd, buffer, sizeof(buffer));
+
+		if (read_len < 0) {
+			p_close(fd);
+			git_hash_free_ctx(ctx);
+			return git__throw(GIT_EOSERR, "Can't read full file '%s'", path);
+		}
+
+		git_hash_update(ctx, buffer, read_len);
+		size -= read_len;
+	}
+
+	p_close(fd);
+
+	git_hash_final(out, ctx);
+	git_hash_free_ctx(ctx);
+
+	return GIT_SUCCESS;
+}
+
 int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type)
 {
 	char hdr[64];
diff --git a/src/status.c b/src/status.c
index 9f826e0..e25e100 100644
--- a/src/status.c
+++ b/src/status.c
@@ -31,54 +31,6 @@
 #include "tree.h"
 #include "git2/status.h"
 
-int git_status_hashfile(git_oid *out, const char *path)
-{
-	int fd, len;
-	char hdr[64], buffer[2048];
-	git_off_t size;
-	git_hash_ctx *ctx;
-
-	if ((fd = p_open(path, O_RDONLY)) < 0)
-		return git__throw(GIT_ENOTFOUND, "Could not open '%s'", path);
-
-	if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
-		p_close(fd);
-		return git__throw(GIT_EOSERR, "'%s' appears to be corrupted", path);
-	}
-
-	ctx = git_hash_new_ctx();
-
-	len = snprintf(hdr, sizeof(hdr), "blob %"PRIuZ, (size_t)size);
-	assert(len > 0);
-	assert(((size_t) len) < sizeof(hdr));
-	if (len < 0 || ((size_t) len) >= sizeof(hdr))
-		return git__throw(GIT_ERROR, "Failed to format blob header. Length is out of bounds");
-
-	git_hash_update(ctx, hdr, len+1);
-
-	while (size > 0) {
-		ssize_t read_len;
-
-		read_len = read(fd, buffer, sizeof(buffer));
-
-		if (read_len < 0) {
-			p_close(fd);
-			git_hash_free_ctx(ctx);
-			return git__throw(GIT_EOSERR, "Can't read full file '%s'", path);
-		}
-
-		git_hash_update(ctx, buffer, read_len);
-		size -= read_len;
-	}
-
-	p_close(fd);
-
-	git_hash_final(out, ctx);
-	git_hash_free_ctx(ctx);
-
-	return GIT_SUCCESS;
-}
-
 struct status_entry {
 	char path[GIT_PATH_MAX];
 
@@ -181,13 +133,21 @@ static void recurse_tree_entry(git_tree *tree, struct status_entry *e, const cha
 	git_tree_close(tree);
 }
 
-static int workdir_path_len;
+struct status_st {
+	union {
+		git_vector *vector;
+		struct status_entry *e;
+	} entry;
+
+	int workdir_path_len;
+};
+
 static int dirent_cb(void *state, char *full_path)
 {
 	int idx;
 	struct status_entry *e;
-	git_vector *entries = (git_vector *)state;
-	char *file_path = full_path + workdir_path_len;
+	struct status_st *st = (struct status_st *)state;
+	char *file_path = full_path + st->workdir_path_len;
 	struct stat filest;
 	git_oid oid;
 
@@ -197,8 +157,8 @@ static int dirent_cb(void *state, char *full_path)
 	if (git_futils_isdir(full_path) == GIT_SUCCESS)
 		return git_futils_direach(full_path, GIT_PATH_MAX, dirent_cb, state);
 
-	if ((idx = find_status_entry(entries, file_path)) != GIT_ENOTFOUND) {
-		e = (struct status_entry *)git_vector_get(entries, idx);
+	if ((idx = find_status_entry(st->entry.vector, file_path)) != GIT_ENOTFOUND) {
+		e = (struct status_entry *)git_vector_get(st->entry.vector, idx);
 
 		if (p_stat(full_path, &filest) < 0)
 			return git__throw(GIT_EOSERR, "Failed to read file %s", full_path);
@@ -208,10 +168,10 @@ static int dirent_cb(void *state, char *full_path)
 			return 0;
 		}
 	} else {
-		e = new_status_entry(entries, file_path);
+		e = new_status_entry(st->entry.vector, file_path);
 	}
 
-	git_status_hashfile(&oid, full_path);
+	git_odb_hashfile(&oid, full_path, GIT_OBJ_BLOB);
 	git_oid_cpy(&e->wt_oid, &oid);
 
 	return 0;
@@ -219,8 +179,10 @@ static int dirent_cb(void *state, char *full_path)
 
 static int single_dirent_cb(void *state, char *full_path)
 {
-	struct status_entry *e = *(struct status_entry **)(state);
-	char *file_path = full_path + workdir_path_len;
+	struct status_st *st = (struct status_st *)state;
+	struct status_entry *e = st->entry.e;
+
+	char *file_path = full_path + st->workdir_path_len;
 	struct stat filest;
 	git_oid oid;
 
@@ -239,7 +201,7 @@ static int single_dirent_cb(void *state, char *full_path)
 			return 1;
 		}
 
-		git_status_hashfile(&oid, full_path);
+		git_odb_hashfile(&oid, full_path, GIT_OBJ_BLOB);
 		git_oid_cpy(&e->wt_oid, &oid);
 		return 1;
 	}
@@ -289,6 +251,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
 	git_oid zero;
 	int error;
 	git_tree *tree;
+	struct status_st dirent_st;
 
 	git_reference *head_ref, *resolved_head_ref;
 	git_commit *head_commit;
@@ -314,9 +277,10 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
 	git_commit_tree(&tree, head_commit);
 	recurse_tree_entries(tree, &entries, "");
 
-	workdir_path_len = strlen(repo->path_workdir);
+	dirent_st.workdir_path_len = strlen(repo->path_workdir);
+	dirent_st.entry.vector = &entries;
 	strcpy(temp_path, repo->path_workdir);
-	git_futils_direach(temp_path, GIT_PATH_MAX, dirent_cb, &entries);
+	git_futils_direach(temp_path, GIT_PATH_MAX, dirent_cb, &dirent_st);
 
 	memset(&zero, 0x0, sizeof(git_oid));
 	for (i = 0; i < entries.length; ++i) {
@@ -352,6 +316,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
 	git_tree *tree;
 	git_reference *head_ref, *resolved_head_ref;
 	git_commit *head_commit;
+	struct status_st dirent_st;
 
 	assert(status_flags);
 
@@ -376,9 +341,10 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
 	recurse_tree_entry(tree, e, path);
 
 	// Find file in Workdir
-	workdir_path_len = strlen(repo->path_workdir);
+	dirent_st.workdir_path_len = strlen(repo->path_workdir);
+	dirent_st.entry.e = e;
 	strcpy(temp_path, repo->path_workdir);
-	git_futils_direach(temp_path, GIT_PATH_MAX, single_dirent_cb, &e);
+	git_futils_direach(temp_path, GIT_PATH_MAX, single_dirent_cb, &dirent_st);
 
 	if ((error = set_status_flags(e)) < GIT_SUCCESS)
 		return git__throw(error, "Nonexistent file");
diff --git a/tests/t18-status.c b/tests/t18-status.c
index a20d97b..3fdcce9 100644
--- a/tests/t18-status.c
+++ b/tests/t18-status.c
@@ -68,7 +68,7 @@ BEGIN_TEST(file0, "test retrieving OID from a file apart from the ODB")
 	must_pass(git_futils_exists(temp_path));
 
 	git_oid_fromstr(&expected_id, test_blob_oid);
-	must_pass(git_status_hashfile(&actual_id, temp_path));
+	must_pass(git_odb_hashfile(&actual_id, temp_path, GIT_OBJ_BLOB));
 
 	must_be_true(git_oid_cmp(&expected_id, &actual_id) == 0);