mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-28 10:28:56 +00:00
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.
This commit is contained in:
parent
3b2a423c3f
commit
c52736fa52
@ -281,6 +281,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
|
||||
*
|
||||
|
@ -51,18 +51,6 @@ GIT_BEGIN_DECL
|
||||
// TODO Ignored files not handled yet
|
||||
#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.
|
||||
*
|
||||
|
54
src/odb.c
54
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];
|
||||
|
90
src/status.c
90
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");
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user