summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/odb.h13
-rw-r--r--include/git2/status.h12
-rw-r--r--src/odb.c54
-rw-r--r--src/status.c90
-rw-r--r--tests/t18-status.c2
5 files changed, 92 insertions, 79 deletions
diff --git a/include/git2/odb.h b/include/git2/odb.h
index ef16e1e42..d0c369055 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 b8d473447..7946cc1f3 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 caa4e1bef..52546e7c7 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 9f826e0bc..e25e100f5 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 a20d97b8f..3fdcce9c9 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);