Commit c52736fa by Vicent Marti

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.
parent 3b2a423c
......@@ -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
......
......@@ -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
......
......@@ -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];
......
......@@ -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");
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment