From 33127043b3ef8dd8dd695ba3613eaa104a80a56b Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Fri, 14 Oct 2011 14:18:02 -0700 Subject: fileops/posix: replace usage of "int mode" with "mode_t mode" Note: Functions exported from fileops take const mode_t, while the underlying POSIX wrappers take mode_t. --- src/fileops.c | 10 +++++----- src/fileops.h | 8 ++++---- src/posix.c | 2 +- src/posix.h | 2 +- src/repository.c | 2 +- src/win32/posix.h | 8 ++++---- src/win32/posix_w32.c | 8 ++++---- tests/t10-refs.c | 2 +- tests/t12-repo.c | 6 +++--- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index 203cce0a4..da9c55f14 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -33,7 +33,7 @@ int git_futils_mv_atomic(const char *from, const char *to) int git_futils_mkpath2file(const char *file_path) { - const int mode = 0755; /* or 0777 ? */ + const mode_t mode = 0755; /* or 0777 ? */ int error = GIT_SUCCESS; char target_folder_path[GIT_PATH_MAX]; @@ -67,7 +67,7 @@ int git_futils_mktmp(char *path_out, const char *filename) return fd; } -int git_futils_creat_withpath(const char *path, int mode) +int git_futils_creat_withpath(const char *path, const mode_t mode) { if (git_futils_mkpath2file(path) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to create file %s", path); @@ -75,13 +75,13 @@ int git_futils_creat_withpath(const char *path, int mode) return p_creat(path, mode); } -int git_futils_creat_locked(const char *path, int mode) +int git_futils_creat_locked(const char *path, const mode_t mode) { int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode); return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create locked file. Could not open %s", path); } -int git_futils_creat_locked_withpath(const char *path, int mode) +int git_futils_creat_locked_withpath(const char *path, const mode_t mode) { if (git_futils_mkpath2file(path) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to create locked file %s", path); @@ -289,7 +289,7 @@ int git_futils_direach( return GIT_SUCCESS; } -int git_futils_mkdir_r(const char *path, int mode) +int git_futils_mkdir_r(const char *path, const mode_t mode) { int error, root_path_offset; char *pp, *sp; diff --git a/src/fileops.h b/src/fileops.h index 5b69199d2..176888895 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -48,18 +48,18 @@ extern int git_futils_exists(const char *path); * Create and open a file, while also * creating all the folders in its path */ -extern int git_futils_creat_withpath(const char *path, int mode); +extern int git_futils_creat_withpath(const char *path, const mode_t mode); /** * Create an open a process-locked file */ -extern int git_futils_creat_locked(const char *path, int mode); +extern int git_futils_creat_locked(const char *path, const mode_t mode); /** * Create an open a process-locked file, while * also creating all the folders in its path */ -extern int git_futils_creat_locked_withpath(const char *path, int mode); +extern int git_futils_creat_locked_withpath(const char *path, const mode_t mode); /** * Check if the given path points to a directory @@ -74,7 +74,7 @@ extern int git_futils_isfile(const char *path); /** * Create a path recursively */ -extern int git_futils_mkdir_r(const char *path, int mode); +extern int git_futils_mkdir_r(const char *path, const mode_t mode); /** * Create all the folders required to contain diff --git a/src/posix.c b/src/posix.c index 1b85b053d..7cd0749b6 100644 --- a/src/posix.c +++ b/src/posix.c @@ -17,7 +17,7 @@ int p_open(const char *path, int flags) return open(path, flags | O_BINARY); } -int p_creat(const char *path, int mode) +int p_creat(const char *path, mode_t mode) { return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); } diff --git a/src/posix.h b/src/posix.h index 59bec2794..389578d5b 100644 --- a/src/posix.h +++ b/src/posix.h @@ -42,7 +42,7 @@ extern int p_write(git_file fd, const void *buf, size_t cnt); #define p_close(fd) close(fd) extern int p_open(const char *path, int flags); -extern int p_creat(const char *path, int mode); +extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); #ifndef GIT_WIN32 diff --git a/src/repository.c b/src/repository.c index 328bc0d57..36642e5ae 100644 --- a/src/repository.c +++ b/src/repository.c @@ -609,7 +609,7 @@ static int repo_init_createhead(git_repository *repo) static int repo_init_structure(const char *git_dir, int is_bare) { - const int mode = 0755; /* or 0777 ? */ + const mode_t mode = 0755; /* or 0777 ? */ int error; char temp_path[GIT_PATH_MAX]; diff --git a/src/win32/posix.h b/src/win32/posix.h index 442717e42..c0af62b1f 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -19,7 +19,7 @@ GIT_INLINE(int) p_link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new)) return -1; } -GIT_INLINE(int) p_mkdir(const char *path, int GIT_UNUSED(mode)) +GIT_INLINE(int) p_mkdir(const char *path, mode_t GIT_UNUSED(mode)) { wchar_t* buf = conv_utf8_to_utf16(path); int ret = _wmkdir(buf); @@ -41,12 +41,12 @@ extern int p_mkstemp(char *tmp_path); extern int p_setenv(const char* name, const char* value, int overwrite); extern int p_stat(const char* path, struct stat* buf); extern int p_chdir(const char* path); -extern int p_chmod(const char* path, int mode); +extern int p_chmod(const char* path, mode_t mode); extern int p_rmdir(const char* path); -extern int p_access(const char* path, int mode); +extern int p_access(const char* path, mode_t mode); extern int p_fsync(int fd); extern int p_open(const char *path, int flags); -extern int p_creat(const char *path, int mode); +extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); #endif diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index cc17cc71f..bbc496f16 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -230,7 +230,7 @@ int p_open(const char *path, int flags) return fd; } -int p_creat(const char *path, int mode) +int p_creat(const char *path, mode_t mode) { int fd; wchar_t* buf = conv_utf8_to_utf16(path); @@ -268,7 +268,7 @@ int p_chdir(const char* path) return ret; } -int p_chmod(const char* path, int mode) +int p_chmod(const char* path, mode_t mode) { wchar_t* buf = conv_utf8_to_utf16(path); int ret = _wchmod(buf, mode); @@ -355,7 +355,7 @@ int p_snprintf(char *buffer, size_t count, const char *format, ...) return r; } -extern int p_creat(const char *path, int mode); +extern int p_creat(const char *path, mode_t mode); int p_mkstemp(char *tmp_path) { @@ -378,7 +378,7 @@ int p_setenv(const char* name, const char* value, int overwrite) return (SetEnvironmentVariableA(name, value) == 0 ? GIT_EOSERR : GIT_SUCCESS); } -int p_access(const char* path, int mode) +int p_access(const char* path, mode_t mode) { wchar_t *buf = conv_utf8_to_utf16(path); int ret; diff --git a/tests/t10-refs.c b/tests/t10-refs.c index c7bfe4eea..aa6735a30 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -431,7 +431,7 @@ END_TEST BEGIN_TEST(pack0, "create a packfile for an empty folder") git_repository *repo; char temp_path[GIT_PATH_MAX]; - const int mode = 0755; /* or 0777 ? */ + const mode_t mode = 0755; /* or 0777 ? */ must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); diff --git a/tests/t12-repo.c b/tests/t12-repo.c index de921f9ca..6884188a3 100644 --- a/tests/t12-repo.c +++ b/tests/t12-repo.c @@ -173,7 +173,7 @@ END_TEST BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory") char path_repository[GIT_PATH_MAX]; char current_workdir[GIT_PATH_MAX]; - const int mode = 0755; /* or 0777 ? */ + const mode_t mode = 0755; /* or 0777 ? */ git_repository* repo; must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); @@ -232,7 +232,7 @@ BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of t char current_workdir[GIT_PATH_MAX]; char path_repository[GIT_PATH_MAX]; - const int mode = 0755; /* or 0777 ? */ + const mode_t mode = 0755; /* or 0777 ? */ git_repository* repo; /* Setup the repository to open */ @@ -384,7 +384,7 @@ BEGIN_TEST(discover0, "test discover") char repository_path[GIT_PATH_MAX]; char sub_repository_path[GIT_PATH_MAX]; char found_path[GIT_PATH_MAX]; - int mode = 0755; + mode_t mode = 0755; git_futils_mkdir_r(DISCOVER_FOLDER, mode); must_pass(append_ceiling_dir(ceiling_dirs, TEMP_REPO_FOLDER)); -- cgit v1.2.1 From ce8cd006ce3adcd012a38401b8a7555ba3307b3f Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Wed, 7 Sep 2011 15:32:44 -0700 Subject: fileops/repository: create (most) directories with 0777 permissions To further match how Git behaves, this change makes most of the directories libgit2 creates in a git repo have a file mode of 0777. Specifically: - Intermediate directories created with git_futils_mkpath2file() have 0777 permissions. This affects odb_loose, reflog, and refs. - The top level folder for bare repos is created with 0777 permissions. - The top level folder for non-bare repos is created with 0755 permissions. - /objects/info/, /objects/pack/, /refs/heads/, and /refs/tags/ are created with 0777 permissions. Additionally, the following changes have been made: - fileops functions that create intermediate directories have grown a new dirmode parameter. The only exception to this is filebuf's lock_file(), which unconditionally creates intermediate directories with 0777 permissions when GIT_FILEBUF_FORCE is set. - The test runner now sets the umask to 0 before running any tests. This ensurses all file mode checks are consistent across systems. - t09-tree.c now does a directory permissions check. I've avoided adding this check to other tests that might reuse existing directories from the prefabricated test repos. Because they're checked into the repo, they have 0755 permissions. - Other assorted directories created by tests have 0777 permissions. --- src/filebuf.c | 3 ++- src/fileops.c | 15 +++++++-------- src/fileops.h | 8 ++++---- src/odb.h | 3 +++ src/odb_loose.c | 4 ++-- src/posix.h | 1 + src/reflog.c | 2 +- src/reflog.h | 1 + src/refs.h | 1 + src/repository.c | 11 +++++------ src/repository.h | 4 +++- tests-clay/core/dirent.c | 4 ++-- tests-clay/core/rmdir.c | 12 ++++++------ tests/t00-core.c | 18 +++++++++--------- tests/t03-objwrite.c | 2 +- tests/t06-index.c | 2 +- tests/t09-tree.c | 3 +++ tests/t10-refs.c | 3 +-- tests/t12-repo.c | 8 ++++---- tests/test_helpers.c | 42 ++++++++++++++++++++++++++++++++++++++---- tests/test_helpers.h | 4 ++++ tests/test_main.c | 4 ++++ 22 files changed, 103 insertions(+), 52 deletions(-) diff --git a/src/filebuf.c b/src/filebuf.c index 1a98e3f43..e6167d014 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -23,7 +23,8 @@ static int lock_file(git_filebuf *file, int flags) /* create path to the file buffer is required */ if (flags & GIT_FILEBUF_FORCE) { - file->fd = git_futils_creat_locked_withpath(file->path_lock, 0644); + /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ + file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, 0644); } else { file->fd = git_futils_creat_locked(file->path_lock, 0644); } diff --git a/src/fileops.c b/src/fileops.c index da9c55f14..ff36b007e 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -31,9 +31,8 @@ int git_futils_mv_atomic(const char *from, const char *to) #endif } -int git_futils_mkpath2file(const char *file_path) +int git_futils_mkpath2file(const char *file_path, const mode_t mode) { - const mode_t mode = 0755; /* or 0777 ? */ int error = GIT_SUCCESS; char target_folder_path[GIT_PATH_MAX]; @@ -67,9 +66,9 @@ int git_futils_mktmp(char *path_out, const char *filename) return fd; } -int git_futils_creat_withpath(const char *path, const mode_t mode) +int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode) { - if (git_futils_mkpath2file(path) < GIT_SUCCESS) + if (git_futils_mkpath2file(path, dirmode) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to create file %s", path); return p_creat(path, mode); @@ -81,9 +80,9 @@ int git_futils_creat_locked(const char *path, const mode_t mode) return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create locked file. Could not open %s", path); } -int git_futils_creat_locked_withpath(const char *path, const mode_t mode) +int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode) { - if (git_futils_mkpath2file(path) < GIT_SUCCESS) + if (git_futils_mkpath2file(path, dirmode) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to create locked file %s", path); return git_futils_creat_locked(path, mode); @@ -212,9 +211,9 @@ void git_futils_freebuffer(git_fbuffer *obj) } -int git_futils_mv_withpath(const char *from, const char *to) +int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) { - if (git_futils_mkpath2file(to) < GIT_SUCCESS) + if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS) return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */ return git_futils_mv_atomic(from, to); /* The callee already takes care of setting the correct error message. */ diff --git a/src/fileops.h b/src/fileops.h index 176888895..56c4770cb 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -48,7 +48,7 @@ extern int git_futils_exists(const char *path); * Create and open a file, while also * creating all the folders in its path */ -extern int git_futils_creat_withpath(const char *path, const mode_t mode); +extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode); /** * Create an open a process-locked file @@ -59,7 +59,7 @@ extern int git_futils_creat_locked(const char *path, const mode_t mode); * Create an open a process-locked file, while * also creating all the folders in its path */ -extern int git_futils_creat_locked_withpath(const char *path, const mode_t mode); +extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode); /** * Check if the given path points to a directory @@ -80,7 +80,7 @@ extern int git_futils_mkdir_r(const char *path, const mode_t mode); * Create all the folders required to contain * the full path of a file */ -extern int git_futils_mkpath2file(const char *path); +extern int git_futils_mkpath2file(const char *path, const mode_t mode); extern int git_futils_rmdir_r(const char *path, int force); @@ -98,7 +98,7 @@ extern int git_futils_mv_atomic(const char *from, const char *to); * Move a file on the filesystem, create the * destination path if it doesn't exist */ -extern int git_futils_mv_withpath(const char *from, const char *to); +extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode); /** diff --git a/src/odb.h b/src/odb.h index 4e850916b..7c8c9f9e2 100644 --- a/src/odb.h +++ b/src/odb.h @@ -14,6 +14,9 @@ #include "vector.h" #include "cache.h" +#define GIT_OBJECTS_DIR "objects/" +#define GIT_OBJECT_DIR_MODE 0777 + /* DO NOT EXPORT */ typedef struct { void *data; /**< Raw, decompressed object data. */ diff --git a/src/odb_loose.c b/src/odb_loose.c index 80f0aa9e7..a3013d3dd 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -666,7 +666,7 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) return GIT_ENOMEM; - if ((error = git_futils_mkpath2file(final_path)) < GIT_SUCCESS) + if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write loose backend"); stream->finished = 1; @@ -787,7 +787,7 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v if ((error = object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) < GIT_SUCCESS) goto cleanup; - if ((error = git_futils_mkpath2file(final_path)) < GIT_SUCCESS) + if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS) goto cleanup; return git_filebuf_commit_at(&fbuf, final_path); diff --git a/src/posix.h b/src/posix.h index 389578d5b..55cd35a38 100644 --- a/src/posix.h +++ b/src/posix.h @@ -40,6 +40,7 @@ extern int p_write(git_file fd, const void *buf, size_t cnt); #define p_fstat(f,b) fstat(f, b) #define p_lseek(f,n,w) lseek(f, n, w) #define p_close(fd) close(fd) +#define p_umask(m) umask(m) extern int p_open(const char *path, int flags); extern int p_creat(const char *path, mode_t mode); diff --git a/src/reflog.c b/src/reflog.c index 594963c03..6cdb35304 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -226,7 +226,7 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old, git_path_join_n(log_path, 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name); if (git_futils_exists(log_path)) { - if ((error = git_futils_mkpath2file(log_path)) < GIT_SUCCESS) + if ((error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write reflog. Cannot create reflog directory"); } else if (git_futils_isfile(log_path)) { return git__throw(GIT_ERROR, "Failed to write reflog. `%s` is directory", log_path); diff --git a/src/reflog.h b/src/reflog.h index 093874e51..16e9a94ec 100644 --- a/src/reflog.h +++ b/src/reflog.h @@ -12,6 +12,7 @@ #include "vector.h" #define GIT_REFLOG_DIR "logs/" +#define GIT_REFLOG_DIR_MODE 0777 #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17) diff --git a/src/refs.h b/src/refs.h index c4b0b0e39..f802cfe4a 100644 --- a/src/refs.h +++ b/src/refs.h @@ -16,6 +16,7 @@ #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" #define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/" +#define GIT_REFS_DIR_MODE 0777 #define GIT_RENAMED_REF_FILE GIT_REFS_DIR "RENAMED-REF" diff --git a/src/repository.c b/src/repository.c index 36642e5ae..d583cad6a 100644 --- a/src/repository.c +++ b/src/repository.c @@ -609,12 +609,11 @@ static int repo_init_createhead(git_repository *repo) static int repo_init_structure(const char *git_dir, int is_bare) { - const mode_t mode = 0755; /* or 0777 ? */ int error; char temp_path[GIT_PATH_MAX]; - if (git_futils_mkdir_r(git_dir, mode)) + if (git_futils_mkdir_r(git_dir, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE)) return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir"); /* Hides the ".git" directory */ @@ -628,25 +627,25 @@ static int repo_init_structure(const char *git_dir, int is_bare) /* Creates the '/objects/info/' directory */ git_path_join(temp_path, git_dir, GIT_OBJECTS_INFO_DIR); - error = git_futils_mkdir_r(temp_path, mode); + error = git_futils_mkdir_r(temp_path, GIT_OBJECT_DIR_MODE); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to initialize repository structure"); /* Creates the '/objects/pack/' directory */ git_path_join(temp_path, git_dir, GIT_OBJECTS_PACK_DIR); - error = p_mkdir(temp_path, mode); + error = p_mkdir(temp_path, GIT_OBJECT_DIR_MODE); if (error < GIT_SUCCESS) return git__throw(error, "Unable to create `%s` folder", temp_path); /* Creates the '/refs/heads/' directory */ git_path_join(temp_path, git_dir, GIT_REFS_HEADS_DIR); - error = git_futils_mkdir_r(temp_path, mode); + error = git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to initialize repository structure"); /* Creates the '/refs/tags/' directory */ git_path_join(temp_path, git_dir, GIT_REFS_TAGS_DIR); - error = p_mkdir(temp_path, mode); + error = p_mkdir(temp_path, GIT_REFS_DIR_MODE); if (error < GIT_SUCCESS) return git__throw(error, "Unable to create `%s` folder", temp_path); diff --git a/src/repository.h b/src/repository.h index 99217e5a4..a12dd9da0 100644 --- a/src/repository.h +++ b/src/repository.h @@ -18,10 +18,12 @@ #include "cache.h" #include "refs.h" #include "buffer.h" +#include "odb.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" -#define GIT_OBJECTS_DIR "objects/" +#define GIT_DIR_MODE 0755 +#define GIT_BARE_DIR_MODE 0777 #define GIT_INDEX_FILE "index" struct git_object { diff --git a/tests-clay/core/dirent.c b/tests-clay/core/dirent.c index 73f571595..898b1227b 100644 --- a/tests-clay/core/dirent.c +++ b/tests-clay/core/dirent.c @@ -20,12 +20,12 @@ static void setup(walk_data *d) { name_data *n; - cl_must_pass(p_mkdir(top_dir, 0755)); + cl_must_pass(p_mkdir(top_dir, 0777)); cl_must_pass(p_chdir(top_dir)); if (strcmp(d->sub, ".") != 0) - cl_must_pass(p_mkdir(d->sub, 0755)); + cl_must_pass(p_mkdir(d->sub, 0777)); strcpy(path_buffer, d->sub); state_loc = d; diff --git a/tests-clay/core/rmdir.c b/tests-clay/core/rmdir.c index aa21c6a3d..03baecf23 100644 --- a/tests-clay/core/rmdir.c +++ b/tests-clay/core/rmdir.c @@ -7,22 +7,22 @@ void test_core_rmdir__initialize(void) { char path[GIT_PATH_MAX]; - cl_must_pass(p_mkdir(empty_tmp_dir, 0755)); + cl_must_pass(p_mkdir(empty_tmp_dir, 0777)); git_path_join(path, empty_tmp_dir, "/one"); - cl_must_pass(p_mkdir(path, 0755)); + cl_must_pass(p_mkdir(path, 0777)); git_path_join(path, empty_tmp_dir, "/one/two_one"); - cl_must_pass(p_mkdir(path, 0755)); + cl_must_pass(p_mkdir(path, 0777)); git_path_join(path, empty_tmp_dir, "/one/two_two"); - cl_must_pass(p_mkdir(path, 0755)); + cl_must_pass(p_mkdir(path, 0777)); git_path_join(path, empty_tmp_dir, "/one/two_two/three"); - cl_must_pass(p_mkdir(path, 0755)); + cl_must_pass(p_mkdir(path, 0777)); git_path_join(path, empty_tmp_dir, "/two"); - cl_must_pass(p_mkdir(path, 0755)); + cl_must_pass(p_mkdir(path, 0777)); } /* make sure empty dir can be deleted recusively */ diff --git a/tests/t00-core.c b/tests/t00-core.c index 703504bf8..185681562 100644 --- a/tests/t00-core.c +++ b/tests/t00-core.c @@ -250,14 +250,14 @@ static int setup(walk_data *d) { name_data *n; - if (p_mkdir(top_dir, 0755) < 0) + if (p_mkdir(top_dir, 0777) < 0) return error("can't mkdir(\"%s\")", top_dir); if (p_chdir(top_dir) < 0) return error("can't chdir(\"%s\")", top_dir); if (strcmp(d->sub, ".") != 0) - if (p_mkdir(d->sub, 0755) < 0) + if (p_mkdir(d->sub, 0777) < 0) return error("can't mkdir(\"%s\")", d->sub); strcpy(path_buffer, d->sub); @@ -510,27 +510,27 @@ static int setup_empty_tmp_dir(void) { char path[GIT_PATH_MAX]; - if (p_mkdir(empty_tmp_dir, 0755)) + if (p_mkdir(empty_tmp_dir, 0777)) return -1; git_path_join(path, empty_tmp_dir, "/one"); - if (p_mkdir(path, 0755)) + if (p_mkdir(path, 0777)) return -1; git_path_join(path, empty_tmp_dir, "/one/two_one"); - if (p_mkdir(path, 0755)) + if (p_mkdir(path, 0777)) return -1; git_path_join(path, empty_tmp_dir, "/one/two_two"); - if (p_mkdir(path, 0755)) + if (p_mkdir(path, 0777)) return -1; git_path_join(path, empty_tmp_dir, "/one/two_two/three"); - if (p_mkdir(path, 0755)) + if (p_mkdir(path, 0777)) return -1; git_path_join(path, empty_tmp_dir, "/two"); - if (p_mkdir(path, 0755)) + if (p_mkdir(path, 0777)) return -1; return 0; @@ -547,7 +547,7 @@ BEGIN_TEST(rmdir1, "make sure non-empty dir cannot be deleted recusively") must_pass(setup_empty_tmp_dir()); git_path_join(file, empty_tmp_dir, "/two/file.txt"); - fd = p_creat(file, 0755); + fd = p_creat(file, 0777); must_pass(fd); must_pass(p_close(fd)); must_fail(git_futils_rmdir_r(empty_tmp_dir, 0)); diff --git a/tests/t03-objwrite.c b/tests/t03-objwrite.c index 31f611a5c..7563d0e3a 100644 --- a/tests/t03-objwrite.c +++ b/tests/t03-objwrite.c @@ -31,7 +31,7 @@ static char *odb_dir = "test-objects"; static int make_odb_dir(void) { - if (p_mkdir(odb_dir, 0755) < 0) { + if (p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE) < 0) { int err = errno; fprintf(stderr, "can't make directory \"%s\"", odb_dir); if (err == EEXIST) diff --git a/tests/t06-index.c b/tests/t06-index.c index 621e742b3..dde98abaf 100644 --- a/tests/t06-index.c +++ b/tests/t06-index.c @@ -176,7 +176,7 @@ BEGIN_TEST(add0, "add a new file to the index") must_pass(git_index_entrycount(index) == 0); /* Create a new file in the working directory */ - must_pass(git_futils_mkpath2file(TEMP_REPO_FOLDER "myrepo/test.txt")); + must_pass(git_futils_mkpath2file(TEMP_REPO_FOLDER "myrepo/test.txt", 0777)); must_pass(git_filebuf_open(&file, TEMP_REPO_FOLDER "myrepo/test.txt", 0)); must_pass(git_filebuf_write(&file, "hey there\n", 10)); must_pass(git_filebuf_commit(&file)); diff --git a/tests/t09-tree.c b/tests/t09-tree.c index 3af06ea67..1f2fe3f02 100644 --- a/tests/t09-tree.c +++ b/tests/t09-tree.c @@ -200,6 +200,9 @@ BEGIN_TEST(write3, "write a hierarchical tree from a memory") // check data is correct must_pass(git_tree_lookup(&tree, repo, &id_hiearar)); must_be_true(2 == git_tree_entrycount(tree)); +#ifndef GIT_WIN32 + must_be_true((loose_object_dir_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_DIR_MODE); +#endif git_tree_close(tree); close_temp_repo(repo); diff --git a/tests/t10-refs.c b/tests/t10-refs.c index aa6735a30..4cb31d5e7 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -431,12 +431,11 @@ END_TEST BEGIN_TEST(pack0, "create a packfile for an empty folder") git_repository *repo; char temp_path[GIT_PATH_MAX]; - const mode_t mode = 0755; /* or 0777 ? */ must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); git_path_join_n(temp_path, 3, repo->path_repository, GIT_REFS_HEADS_DIR, "empty_dir"); - must_pass(git_futils_mkdir_r(temp_path, mode)); + must_pass(git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE)); must_pass(git_reference_packall(repo)); diff --git a/tests/t12-repo.c b/tests/t12-repo.c index 6884188a3..c07150c9c 100644 --- a/tests/t12-repo.c +++ b/tests/t12-repo.c @@ -173,7 +173,7 @@ END_TEST BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory") char path_repository[GIT_PATH_MAX]; char current_workdir[GIT_PATH_MAX]; - const mode_t mode = 0755; /* or 0777 ? */ + const mode_t mode = 0777; git_repository* repo; must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); @@ -232,7 +232,7 @@ BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of t char current_workdir[GIT_PATH_MAX]; char path_repository[GIT_PATH_MAX]; - const mode_t mode = 0755; /* or 0777 ? */ + const mode_t mode = 0777; git_repository* repo; /* Setup the repository to open */ @@ -351,7 +351,7 @@ static int write_file(const char *path, const char *content) return error; } - file = git_futils_creat_withpath(path, 0644); + file = git_futils_creat_withpath(path, 0777, 0644); if (file < GIT_SUCCESS) return file; @@ -384,7 +384,7 @@ BEGIN_TEST(discover0, "test discover") char repository_path[GIT_PATH_MAX]; char sub_repository_path[GIT_PATH_MAX]; char found_path[GIT_PATH_MAX]; - mode_t mode = 0755; + const mode_t mode = 0777; git_futils_mkdir_r(DISCOVER_FOLDER, mode); must_pass(append_ceiling_dir(ceiling_dirs, TEMP_REPO_FOLDER)); diff --git a/tests/test_helpers.c b/tests/test_helpers.c index 0900430e1..7074e4822 100644 --- a/tests/test_helpers.c +++ b/tests/test_helpers.c @@ -42,7 +42,7 @@ int write_object_data(char *file, void *data, size_t len) int write_object_files(const char *odb_dir, object_data *d) { - if (p_mkdir(odb_dir, 0755) < 0) { + if (p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE) < 0) { int err = errno; fprintf(stderr, "can't make directory \"%s\"", odb_dir); if (err == EEXIST) @@ -51,7 +51,7 @@ int write_object_files(const char *odb_dir, object_data *d) return -1; } - if ((p_mkdir(d->dir, 0755) < 0) && (errno != EEXIST)) { + if ((p_mkdir(d->dir, GIT_OBJECT_DIR_MODE) < 0) && (errno != EEXIST)) { fprintf(stderr, "can't make object directory \"%s\"\n", d->dir); return -1; } @@ -82,7 +82,7 @@ int remove_object_files(const char *odb_dir, object_data *d) return 0; } -int remove_loose_object(const char *repository_folder, git_object *object) +void locate_loose_object(const char *repository_folder, git_object *object, char **out, char **out_folder) { static const char *objects_folder = "objects/"; @@ -104,6 +104,40 @@ int remove_loose_object(const char *repository_folder, git_object *object) ptr += GIT_OID_HEXSZ + 1; *ptr = 0; + *out = full_path; + + if (out_folder) + *out_folder = top_folder; +} + +int loose_object_dir_mode(const char *repository_folder, git_object *object) +{ + char *object_path; + size_t pos; + struct stat st; + + locate_loose_object(repository_folder, object, &object_path, NULL); + + pos = strlen(object_path); + while (pos--) { + if (object_path[pos] == '/') { + object_path[pos] = 0; + break; + } + } + + assert(p_stat(object_path, &st) == 0); + free(object_path); + + return st.st_mode; +} + +int remove_loose_object(const char *repository_folder, git_object *object) +{ + char *full_path, *top_folder; + + locate_loose_object(repository_folder, object, &full_path, &top_folder); + if (p_unlink(full_path) < 0) { fprintf(stderr, "can't delete object file \"%s\"\n", full_path); return -1; @@ -141,7 +175,7 @@ int copy_file(const char *src, const char *dst) if (git_futils_readbuffer(&source_buf, src) < GIT_SUCCESS) return GIT_ENOTFOUND; - dst_fd = git_futils_creat_withpath(dst, 0644); + dst_fd = git_futils_creat_withpath(dst, 0777, 0644); if (dst_fd < 0) goto cleanup; diff --git a/tests/test_helpers.h b/tests/test_helpers.h index 53361b7b1..2e5194d7c 100644 --- a/tests/test_helpers.h +++ b/tests/test_helpers.h @@ -63,6 +63,10 @@ extern int remove_object_files(const char *odb_dir, object_data *d); extern int cmp_objects(git_rawobj *o, object_data *d); +extern void locate_loose_object(const char *odb_dir, git_object *object, char **out, char **out_folder); + +extern int loose_object_dir_mode(const char *odb_dir, git_object *object); + extern int remove_loose_object(const char *odb_dir, git_object *object); extern int cmp_files(const char *a, const char *b); diff --git a/tests/test_main.c b/tests/test_main.c index c9f8da3a4..9961ffd6b 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -26,6 +26,8 @@ #include #include +#include "posix.h" + #include "test_lib.h" #include "test_helpers.h" @@ -81,6 +83,8 @@ main(int GIT_UNUSED(argc), char *GIT_UNUSED(argv[])) GIT_UNUSED_ARG(argc); GIT_UNUSED_ARG(argv); + p_umask(0); + failures = 0; for (i = 0; i < GIT_SUITE_COUNT; ++i) -- cgit v1.2.1 From 01ad7b3a9ec8f5e465f94c2704e1e96b84f941c7 Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Tue, 6 Sep 2011 15:48:45 -0700 Subject: *: correct and codify various file permissions The following files now have 0444 permissions: - loose objects - pack indexes - pack files - packs downloaded by fetch - packs downloaded by the HTTP transport And the following files now have 0666 permissions: - config files - repository indexes - reflogs - refs This brings libgit2 more in line with Git. Note that git_filebuf_commit() and git_filebuf_commit_at() have both gained a new mode parameter. The latter change fixes an important issue where filebufs created with GIT_FILEBUF_TEMPORARY received 0600 permissions (due to mkstemp(3) usage). Now we chmod() the file before renaming it into place. Tests have been added to confirm that new commit, tag, and tree objects are created with the right permissions. I don't have access to Windows, so for now I've guarded the tests with "#ifndef GIT_WIN32". --- src/config.h | 1 + src/config_file.c | 2 +- src/fetch.c | 3 ++- src/filebuf.c | 17 ++++++++++++----- src/filebuf.h | 4 ++-- src/index.c | 2 +- src/index.h | 3 +++ src/indexer.c | 2 +- src/odb.h | 1 + src/odb_loose.c | 4 ++-- src/pack.h | 2 ++ src/reflog.c | 2 +- src/reflog.h | 1 + src/refs.c | 5 +++-- src/refs.h | 1 + src/repository.h | 1 - src/transports/http.c | 3 ++- tests-clay/core/dirent.c | 2 +- tests-clay/core/filebuf.c | 6 +++--- tests-clay/core/rmdir.c | 2 +- tests-clay/status/single.c | 2 +- tests/t00-core.c | 8 ++++---- tests/t04-commit.c | 4 ++++ tests/t06-index.c | 2 +- tests/t08-tag.c | 3 +++ tests/t09-tree.c | 1 + tests/t12-repo.c | 2 +- tests/t15-config.c | 2 +- tests/t18-status.c | 4 ++-- tests/test_helpers.c | 14 +++++++++++++- tests/test_helpers.h | 1 + 31 files changed, 73 insertions(+), 34 deletions(-) diff --git a/src/config.h b/src/config.h index 7749a9c1a..43574a586 100644 --- a/src/config.h +++ b/src/config.h @@ -14,6 +14,7 @@ #define GIT_CONFIG_FILENAME ".gitconfig" #define GIT_CONFIG_FILENAME_INREPO "config" +#define GIT_CONFIG_FILE_MODE 0666 struct git_config { git_vector files; diff --git a/src/config_file.c b/src/config_file.c index a85ae1578..855574d7e 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1034,7 +1034,7 @@ static int config_write(diskfile_backend *cfg, cvar_t *var) if (error < GIT_SUCCESS) git_filebuf_cleanup(&file); else - error = git_filebuf_commit(&file); + error = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE); git_futils_freebuffer(&cfg->reader.buffer); return error; diff --git a/src/fetch.c b/src/fetch.c index ac7282819..af7dbaffd 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -14,6 +14,7 @@ #include "transport.h" #include "remote.h" #include "refspec.h" +#include "pack.h" #include "fetch.h" #include "netops.h" @@ -181,7 +182,7 @@ int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_s } /* A bit dodgy, but we need to keep the pack at the temporary path */ - error = git_filebuf_commit_at(&file, file.path_lock); + error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE); cleanup: if (error < GIT_SUCCESS) git_filebuf_cleanup(&file); diff --git a/src/filebuf.c b/src/filebuf.c index e6167d014..a86d25b5a 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -10,6 +10,8 @@ #include "filebuf.h" #include "fileops.h" +#define GIT_LOCK_FILE_MODE 0644 + static const size_t WRITE_BUFFER_SIZE = (4096 * 2); static int lock_file(git_filebuf *file, int flags) @@ -24,9 +26,9 @@ static int lock_file(git_filebuf *file, int flags) /* create path to the file buffer is required */ if (flags & GIT_FILEBUF_FORCE) { /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ - file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, 0644); + file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, GIT_LOCK_FILE_MODE); } else { - file->fd = git_futils_creat_locked(file->path_lock, 0644); + file->fd = git_futils_creat_locked(file->path_lock, GIT_LOCK_FILE_MODE); } if (file->fd < 0) @@ -247,17 +249,17 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file) return GIT_SUCCESS; } -int git_filebuf_commit_at(git_filebuf *file, const char *path) +int git_filebuf_commit_at(git_filebuf *file, const char *path, mode_t mode) { free(file->path_original); file->path_original = git__strdup(path); if (file->path_original == NULL) return GIT_ENOMEM; - return git_filebuf_commit(file); + return git_filebuf_commit(file, mode); } -int git_filebuf_commit(git_filebuf *file) +int git_filebuf_commit(git_filebuf *file, mode_t mode) { int error; @@ -271,6 +273,11 @@ int git_filebuf_commit(git_filebuf *file) p_close(file->fd); file->fd = -1; + if (p_chmod(file->path_lock, mode)) { + error = git__throw(GIT_EOSERR, "Failed to chmod locked file before committing"); + goto cleanup; + } + error = git_futils_mv_atomic(file->path_lock, file->path_original); cleanup: diff --git a/src/filebuf.h b/src/filebuf.h index 525ca3c81..d08505e8d 100644 --- a/src/filebuf.h +++ b/src/filebuf.h @@ -49,8 +49,8 @@ int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len); int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3); int git_filebuf_open(git_filebuf *lock, const char *path, int flags); -int git_filebuf_commit(git_filebuf *lock); -int git_filebuf_commit_at(git_filebuf *lock, const char *path); +int git_filebuf_commit(git_filebuf *lock, mode_t mode); +int git_filebuf_commit_at(git_filebuf *lock, const char *path, mode_t mode); void git_filebuf_cleanup(git_filebuf *lock); int git_filebuf_hash(git_oid *oid, git_filebuf *file); diff --git a/src/index.c b/src/index.c index 7bf5daf2c..2655aefa9 100644 --- a/src/index.c +++ b/src/index.c @@ -262,7 +262,7 @@ int git_index_write(git_index *index) return git__rethrow(error, "Failed to write index"); } - if ((error = git_filebuf_commit(&file)) < GIT_SUCCESS) + if ((error = git_filebuf_commit(&file, GIT_INDEX_FILE_MODE)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write index"); if (p_stat(index->index_file_path, &indexst) == 0) { diff --git a/src/index.h b/src/index.h index e912770b7..a1cd3403e 100644 --- a/src/index.h +++ b/src/index.h @@ -14,6 +14,9 @@ #include "git2/odb.h" #include "git2/index.h" +#define GIT_INDEX_FILE "index" +#define GIT_INDEX_FILE_MODE 0666 + struct git_index { git_repository *repository; char *index_file_path; diff --git a/src/indexer.c b/src/indexer.c index d5f605fdb..6be4f4a7e 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -272,7 +272,7 @@ int git_indexer_write(git_indexer *idx) /* Figure out what the final name should be */ index_path(filename, idx); /* Commit file */ - error = git_filebuf_commit_at(&idx->file, filename); + error = git_filebuf_commit_at(&idx->file, filename, GIT_PACK_FILE_MODE); cleanup: git_mwindow_free_all(&idx->pack->mwf); diff --git a/src/odb.h b/src/odb.h index 7c8c9f9e2..833739e99 100644 --- a/src/odb.h +++ b/src/odb.h @@ -16,6 +16,7 @@ #define GIT_OBJECTS_DIR "objects/" #define GIT_OBJECT_DIR_MODE 0777 +#define GIT_OBJECT_FILE_MODE 0444 /* DO NOT EXPORT */ typedef struct { diff --git a/src/odb_loose.c b/src/odb_loose.c index a3013d3dd..dc9897288 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -670,7 +670,7 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) return git__rethrow(error, "Failed to write loose backend"); stream->finished = 1; - return git_filebuf_commit_at(&stream->fbuf, final_path); + return git_filebuf_commit_at(&stream->fbuf, final_path, GIT_OBJECT_FILE_MODE); } static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len) @@ -790,7 +790,7 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS) goto cleanup; - return git_filebuf_commit_at(&fbuf, final_path); + return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE); cleanup: git_filebuf_cleanup(&fbuf); diff --git a/src/pack.h b/src/pack.h index 0fddd9dc8..aecf580e9 100644 --- a/src/pack.h +++ b/src/pack.h @@ -15,6 +15,8 @@ #include "mwindow.h" #include "odb.h" +#define GIT_PACK_FILE_MODE 0444 + #define PACK_SIGNATURE 0x5041434b /* "PACK" */ #define PACK_VERSION 2 #define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3)) diff --git a/src/reflog.c b/src/reflog.c index 6cdb35304..303c2b494 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -71,7 +71,7 @@ static int reflog_write(const char *log_path, const char *oid_old, } git_filebuf_write(&fbuf, log.ptr, log.size); - error = git_filebuf_commit(&fbuf); + error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE); git_buf_free(&log); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write reflog"); diff --git a/src/reflog.h b/src/reflog.h index 16e9a94ec..44b063700 100644 --- a/src/reflog.h +++ b/src/reflog.h @@ -13,6 +13,7 @@ #define GIT_REFLOG_DIR "logs/" #define GIT_REFLOG_DIR_MODE 0777 +#define GIT_REFLOG_FILE_MODE 0666 #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17) diff --git a/src/refs.c b/src/refs.c index fcf771b5e..b34067f00 100644 --- a/src/refs.c +++ b/src/refs.c @@ -9,6 +9,7 @@ #include "hash.h" #include "repository.h" #include "fileops.h" +#include "pack.h" #include #include @@ -357,7 +358,7 @@ static int loose_write(git_reference *ref) goto unlock; } - error = git_filebuf_commit(&file); + error = git_filebuf_commit(&file, GIT_REFS_FILE_MODE); if (p_stat(ref_path, &st) == GIT_SUCCESS) ref->mtime = st.st_mtime; @@ -870,7 +871,7 @@ cleanup: /* if we've written all the references properly, we can commit * the packfile to make the changes effective */ if (error == GIT_SUCCESS) { - error = git_filebuf_commit(&pack_file); + error = git_filebuf_commit(&pack_file, GIT_PACK_FILE_MODE); /* when and only when the packfile has been properly written, * we can go ahead and remove the loose refs */ diff --git a/src/refs.h b/src/refs.h index f802cfe4a..33c1e6983 100644 --- a/src/refs.h +++ b/src/refs.h @@ -17,6 +17,7 @@ #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" #define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/" #define GIT_REFS_DIR_MODE 0777 +#define GIT_REFS_FILE_MODE 0666 #define GIT_RENAMED_REF_FILE GIT_REFS_DIR "RENAMED-REF" diff --git a/src/repository.h b/src/repository.h index a12dd9da0..0c17958fd 100644 --- a/src/repository.h +++ b/src/repository.h @@ -24,7 +24,6 @@ #define GIT_DIR DOT_GIT "/" #define GIT_DIR_MODE 0755 #define GIT_BARE_DIR_MODE 0777 -#define GIT_INDEX_FILE "index" struct git_object { git_cached_obj cached; diff --git a/src/transports/http.c b/src/transports/http.c index 680354bae..c324bb4ab 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -15,6 +15,7 @@ #include "buffer.h" #include "pkt.h" #include "refs.h" +#include "pack.h" #include "fetch.h" #include "filebuf.h" #include "repository.h" @@ -702,7 +703,7 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito } /* A bit dodgy, but we need to keep the pack at the temporary path */ - error = git_filebuf_commit_at(&file, file.path_lock); + error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE); cleanup: if (error < GIT_SUCCESS) diff --git a/tests-clay/core/dirent.c b/tests-clay/core/dirent.c index 898b1227b..105e8d8f0 100644 --- a/tests-clay/core/dirent.c +++ b/tests-clay/core/dirent.c @@ -31,7 +31,7 @@ static void setup(walk_data *d) state_loc = d; for (n = d->names; n->name; n++) { - git_file fd = p_creat(n->name, 0600); + git_file fd = p_creat(n->name, 0666); cl_assert(fd >= 0); p_close(fd); n->count = 0; diff --git a/tests-clay/core/filebuf.c b/tests-clay/core/filebuf.c index e00e20497..e1ecb2798 100644 --- a/tests-clay/core/filebuf.c +++ b/tests-clay/core/filebuf.c @@ -27,14 +27,14 @@ void test_core_filebuf__1(void) int fd; char test[] = "test"; - fd = p_creat(test, 0644); + fd = p_creat(test, 0666); cl_must_pass(fd); cl_must_pass(p_write(fd, "libgit2 rocks\n", 14)); cl_must_pass(p_close(fd)); cl_git_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND)); cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); - cl_git_pass(git_filebuf_commit(&file)); + cl_git_pass(git_filebuf_commit(&file, 0666)); cl_must_pass(p_unlink(test)); } @@ -51,7 +51,7 @@ void test_core_filebuf__2(void) cl_git_pass(git_filebuf_open(&file, test, 0)); cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf))); - cl_git_pass(git_filebuf_commit(&file)); + cl_git_pass(git_filebuf_commit(&file, 0666)); cl_must_pass(p_unlink(test)); } diff --git a/tests-clay/core/rmdir.c b/tests-clay/core/rmdir.c index 03baecf23..20cc8f5f0 100644 --- a/tests-clay/core/rmdir.c +++ b/tests-clay/core/rmdir.c @@ -39,7 +39,7 @@ void test_core_rmdir__fail_to_delete_non_empty_dir(void) git_path_join(file, empty_tmp_dir, "/two/file.txt"); - fd = p_creat(file, 0755); + fd = p_creat(file, 0666); cl_assert(fd >= 0); cl_must_pass(p_close(fd)); diff --git a/tests-clay/status/single.c b/tests-clay/status/single.c index ea1c77fa0..4fd6e6ff4 100644 --- a/tests-clay/status/single.c +++ b/tests-clay/status/single.c @@ -10,7 +10,7 @@ cleanup__remove_file(void *_file) static void file_create(const char *filename, const char *content) { - int fd = p_creat(filename, 0644); + int fd = p_creat(filename, 0666); cl_assert(fd >= 0); cl_must_pass(p_write(fd, content, strlen(content))); cl_must_pass(p_close(fd)); diff --git a/tests/t00-core.c b/tests/t00-core.c index 185681562..dbc80670f 100644 --- a/tests/t00-core.c +++ b/tests/t00-core.c @@ -264,7 +264,7 @@ static int setup(walk_data *d) state_loc = d; for (n = d->names; n->name; n++) { - git_file fd = p_creat(n->name, 0600); + git_file fd = p_creat(n->name, 0666); if (fd < 0) return GIT_ERROR; p_close(fd); @@ -479,14 +479,14 @@ BEGIN_TEST(filebuf1, "make sure GIT_FILEBUF_APPEND works as expected") int fd; char test[] = "test"; - fd = p_creat(test, 0644); + fd = p_creat(test, 0666); must_pass(fd); must_pass(p_write(fd, "libgit2 rocks\n", 14)); must_pass(p_close(fd)); must_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND)); must_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); - must_pass(git_filebuf_commit(&file)); + must_pass(git_filebuf_commit(&file, 0666)); must_pass(p_unlink(test)); END_TEST @@ -499,7 +499,7 @@ BEGIN_TEST(filebuf2, "make sure git_filebuf_write writes large buffer correctly" memset(buf, 0xfe, sizeof(buf)); must_pass(git_filebuf_open(&file, test, 0)); must_pass(git_filebuf_write(&file, buf, sizeof(buf))); - must_pass(git_filebuf_commit(&file)); + must_pass(git_filebuf_commit(&file, 0666)); must_pass(p_unlink(test)); END_TEST diff --git a/tests/t04-commit.c b/tests/t04-commit.c index 3fb4d370c..4abbf01c2 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -690,6 +690,10 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk") must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0); +#ifndef GIT_WIN32 + must_be_true((loose_object_mode(REPOSITORY_FOLDER, (git_object *)commit) & 0777) == GIT_OBJECT_FILE_MODE); +#endif + must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); git_commit_close(commit); diff --git a/tests/t06-index.c b/tests/t06-index.c index dde98abaf..44562d004 100644 --- a/tests/t06-index.c +++ b/tests/t06-index.c @@ -179,7 +179,7 @@ BEGIN_TEST(add0, "add a new file to the index") must_pass(git_futils_mkpath2file(TEMP_REPO_FOLDER "myrepo/test.txt", 0777)); must_pass(git_filebuf_open(&file, TEMP_REPO_FOLDER "myrepo/test.txt", 0)); must_pass(git_filebuf_write(&file, "hey there\n", 10)); - must_pass(git_filebuf_commit(&file)); + must_pass(git_filebuf_commit(&file, 0666)); /* Store the expected hash of the file/blob * This has been generated by executing the following diff --git a/tests/t08-tag.c b/tests/t08-tag.c index 216fb9dfc..85ef9225e 100644 --- a/tests/t08-tag.c +++ b/tests/t08-tag.c @@ -189,6 +189,9 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-tag")); must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0); must_pass(git_reference_delete(ref_tag)); +#ifndef GIT_WIN32 + must_be_true((loose_object_mode(REPOSITORY_FOLDER, (git_object *)tag) & 0777) == GIT_OBJECT_FILE_MODE); +#endif must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag)); diff --git a/tests/t09-tree.c b/tests/t09-tree.c index 1f2fe3f02..2341a1ca4 100644 --- a/tests/t09-tree.c +++ b/tests/t09-tree.c @@ -202,6 +202,7 @@ BEGIN_TEST(write3, "write a hierarchical tree from a memory") must_be_true(2 == git_tree_entrycount(tree)); #ifndef GIT_WIN32 must_be_true((loose_object_dir_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_DIR_MODE); + must_be_true((loose_object_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_FILE_MODE); #endif git_tree_close(tree); diff --git a/tests/t12-repo.c b/tests/t12-repo.c index c07150c9c..6197cdd00 100644 --- a/tests/t12-repo.c +++ b/tests/t12-repo.c @@ -351,7 +351,7 @@ static int write_file(const char *path, const char *content) return error; } - file = git_futils_creat_withpath(path, 0777, 0644); + file = git_futils_creat_withpath(path, 0777, 0666); if (file < GIT_SUCCESS) return file; diff --git a/tests/t15-config.c b/tests/t15-config.c index c4cb590f5..a97f82067 100644 --- a/tests/t15-config.c +++ b/tests/t15-config.c @@ -319,7 +319,7 @@ BEGIN_TEST(config16, "add a variable in a new section") /* As the section wasn't removed, owerwrite the file */ must_pass(git_filebuf_open(&buf, CONFIG_BASE "/config10", 0)); must_pass(git_filebuf_write(&buf, "[empty]\n", strlen("[empty]\n"))); - must_pass(git_filebuf_commit(&buf)); + must_pass(git_filebuf_commit(&buf, 0666)); END_TEST BEGIN_TEST(config17, "prefixes aren't broken") diff --git a/tests/t18-status.c b/tests/t18-status.c index bd205a438..d836fb9a9 100644 --- a/tests/t18-status.c +++ b/tests/t18-status.c @@ -37,7 +37,7 @@ static int file_create(const char *filename, const char *content) { int fd; - fd = p_creat(filename, 0644); + fd = p_creat(filename, 0666); if (fd == 0) return GIT_ERROR; if (p_write(fd, content, strlen(content)) != 0) @@ -400,7 +400,7 @@ BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty rep must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt")); git_path_join(file_path, TEMP_REPO_FOLDER, filename); - fd = p_creat(file_path, 0644); + fd = p_creat(file_path, 0666); must_pass(fd); must_pass(p_write(fd, "new_file\n", 9)); must_pass(p_close(fd)); diff --git a/tests/test_helpers.c b/tests/test_helpers.c index 7074e4822..7bba2e1d2 100644 --- a/tests/test_helpers.c +++ b/tests/test_helpers.c @@ -110,6 +110,18 @@ void locate_loose_object(const char *repository_folder, git_object *object, char *out_folder = top_folder; } +int loose_object_mode(const char *repository_folder, git_object *object) +{ + char *object_path; + struct stat st; + + locate_loose_object(repository_folder, object, &object_path, NULL); + assert(p_stat(object_path, &st) == 0); + free(object_path); + + return st.st_mode; +} + int loose_object_dir_mode(const char *repository_folder, git_object *object) { char *object_path; @@ -175,7 +187,7 @@ int copy_file(const char *src, const char *dst) if (git_futils_readbuffer(&source_buf, src) < GIT_SUCCESS) return GIT_ENOTFOUND; - dst_fd = git_futils_creat_withpath(dst, 0777, 0644); + dst_fd = git_futils_creat_withpath(dst, 0777, 0666); if (dst_fd < 0) goto cleanup; diff --git a/tests/test_helpers.h b/tests/test_helpers.h index 2e5194d7c..16a3a2ced 100644 --- a/tests/test_helpers.h +++ b/tests/test_helpers.h @@ -65,6 +65,7 @@ extern int cmp_objects(git_rawobj *o, object_data *d); extern void locate_loose_object(const char *odb_dir, git_object *object, char **out, char **out_folder); +extern int loose_object_mode(const char *odb_dir, git_object *object); extern int loose_object_dir_mode(const char *odb_dir, git_object *object); extern int remove_loose_object(const char *odb_dir, git_object *object); -- cgit v1.2.1 From 9ff46db9111ba77bd4c209f1014028a6bfc60c4a Mon Sep 17 00:00:00 2001 From: schu Date: Wed, 19 Oct 2011 13:48:51 +0200 Subject: tests-clay: move t01-rawobj.c to clay Signed-off-by: schu --- tests-clay/clay.h | 52 ++++-- tests-clay/clay_main.c | 198 +++++++++++++++------- tests-clay/object/raw/chars.c | 52 ++++++ tests-clay/object/raw/compare.c | 124 ++++++++++++++ tests-clay/object/raw/convert.c | 75 +++++++++ tests-clay/object/raw/data.h | 323 ++++++++++++++++++++++++++++++++++++ tests-clay/object/raw/fromstr.c | 30 ++++ tests-clay/object/raw/hash.c | 162 ++++++++++++++++++ tests-clay/object/raw/short.c | 94 +++++++++++ tests-clay/object/raw/size.c | 13 ++ tests-clay/object/raw/type2string.c | 54 ++++++ 11 files changed, 1106 insertions(+), 71 deletions(-) create mode 100644 tests-clay/object/raw/chars.c create mode 100644 tests-clay/object/raw/compare.c create mode 100644 tests-clay/object/raw/convert.c create mode 100644 tests-clay/object/raw/data.h create mode 100644 tests-clay/object/raw/fromstr.c create mode 100644 tests-clay/object/raw/hash.c create mode 100644 tests-clay/object/raw/short.c create mode 100644 tests-clay/object/raw/size.c create mode 100644 tests-clay/object/raw/type2string.c diff --git a/tests-clay/clay.h b/tests-clay/clay.h index bc4267b66..cbdf1381d 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -57,6 +57,17 @@ void cl_fixture_cleanup(const char *fixture_name); /** * Test method declarations */ +extern void test_status_single__hash_single_file(void); +extern void test_status_worktree__initialize(void); +extern void test_status_worktree__cleanup(void); +extern void test_status_worktree__whole_repository(void); +extern void test_status_worktree__empty_repository(void); +extern void test_network_remotes__initialize(void); +extern void test_network_remotes__cleanup(void); +extern void test_network_remotes__parsing(void); +extern void test_network_remotes__refspec_parsing(void); +extern void test_network_remotes__fnmatch(void); +extern void test_network_remotes__transform(void); extern void test_core_dirent__dont_traverse_dot(void); extern void test_core_dirent__traverse_subfolder(void); extern void test_core_dirent__traverse_slash_terminated_folder(void); @@ -82,21 +93,40 @@ extern void test_core_strtol__int64(void); extern void test_core_vector__0(void); extern void test_core_vector__1(void); extern void test_core_vector__2(void); -extern void test_network_remotes__initialize(void); -extern void test_network_remotes__cleanup(void); -extern void test_network_remotes__parsing(void); -extern void test_network_remotes__refspec_parsing(void); -extern void test_network_remotes__fnmatch(void); -extern void test_network_remotes__transform(void); extern void test_object_tree_frompath__initialize(void); extern void test_object_tree_frompath__cleanup(void); extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void); extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void); extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void); -extern void test_status_single__hash_single_file(void); -extern void test_status_worktree__initialize(void); -extern void test_status_worktree__cleanup(void); -extern void test_status_worktree__whole_repository(void); -extern void test_status_worktree__empty_repository(void); +extern void test_object_raw_chars__find_invalid_chars_in_oid(void); +extern void test_object_raw_chars__build_valid_oid_from_raw_bytes(void); +extern void test_object_raw_compare__succeed_on_copy_oid(void); +extern void test_object_raw_compare__succeed_on_oid_comparison_lesser(void); +extern void test_object_raw_compare__succeed_on_oid_comparison_equal(void); +extern void test_object_raw_compare__succeed_on_oid_comparison_greater(void); +extern void test_object_raw_compare__compare_fmt_oids(void); +extern void test_object_raw_compare__compare_allocfmt_oids(void); +extern void test_object_raw_compare__compare_pathfmt_oids(void); +extern void test_object_raw_convert__succeed_on_oid_to_string_conversion(void); +extern void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void); +extern void test_object_raw_fromstr__fail_on_invalid_oid_string(void); +extern void test_object_raw_fromstr__succeed_on_valid_oid_string(void); +extern void test_object_raw_hash__hash_by_blocks(void); +extern void test_object_raw_hash__hash_buffer_in_single_call(void); +extern void test_object_raw_hash__hash_vector(void); +extern void test_object_raw_hash__hash_junk_data(void); +extern void test_object_raw_hash__hash_commit_object(void); +extern void test_object_raw_hash__hash_tree_object(void); +extern void test_object_raw_hash__hash_tag_object(void); +extern void test_object_raw_hash__hash_zero_length_object(void); +extern void test_object_raw_hash__hash_one_byte_object(void); +extern void test_object_raw_hash__hash_two_byte_object(void); +extern void test_object_raw_hash__hash_multi_byte_object(void); +extern void test_object_raw_short__oid_shortener_no_duplicates(void); +extern void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void); +extern void test_object_raw_size__validate_oid_size(void); +extern void test_object_raw_type2string__convert_type_to_string(void); +extern void test_object_raw_type2string__convert_string_to_type(void); +extern void test_object_raw_type2string__check_type_is_loose(void); #endif diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index da90872ce..2f3cee39c 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -660,123 +660,201 @@ cl_fs_cleanup(void) static const struct clay_func _all_callbacks[] = { - {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 0}, - {"traverse_subfolder", &test_core_dirent__traverse_subfolder, 0}, - {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 0}, - {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 0}, - {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 0}, - {"0", &test_core_filebuf__0, 1}, - {"1", &test_core_filebuf__1, 1}, - {"2", &test_core_filebuf__2, 1}, - {"streq", &test_core_oid__streq, 2}, - {"0", &test_core_path__0, 3}, - {"1", &test_core_path__1, 3}, - {"2", &test_core_path__2, 3}, - {"5", &test_core_path__5, 3}, - {"6", &test_core_path__6, 3}, - {"delete_recursive", &test_core_rmdir__delete_recursive, 4}, - {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 4}, - {"0", &test_core_string__0, 5}, - {"1", &test_core_string__1, 5}, - {"int32", &test_core_strtol__int32, 6}, - {"int64", &test_core_strtol__int64, 6}, - {"0", &test_core_vector__0, 7}, - {"1", &test_core_vector__1, 7}, - {"2", &test_core_vector__2, 7}, - {"parsing", &test_network_remotes__parsing, 8}, - {"refspec_parsing", &test_network_remotes__refspec_parsing, 8}, - {"fnmatch", &test_network_remotes__fnmatch, 8}, - {"transform", &test_network_remotes__transform, 8}, - {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry, 9}, - {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment, 9}, - {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path, 9}, - {"hash_single_file", &test_status_single__hash_single_file, 10}, - {"whole_repository", &test_status_worktree__whole_repository, 11}, - {"empty_repository", &test_status_worktree__empty_repository, 11} + {"hash_single_file", &test_status_single__hash_single_file, 0}, + {"whole_repository", &test_status_worktree__whole_repository, 1}, + {"empty_repository", &test_status_worktree__empty_repository, 1}, + {"parsing", &test_network_remotes__parsing, 2}, + {"refspec_parsing", &test_network_remotes__refspec_parsing, 2}, + {"fnmatch", &test_network_remotes__fnmatch, 2}, + {"transform", &test_network_remotes__transform, 2}, + {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 3}, + {"traverse_subfolder", &test_core_dirent__traverse_subfolder, 3}, + {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 3}, + {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 3}, + {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 3}, + {"0", &test_core_filebuf__0, 4}, + {"1", &test_core_filebuf__1, 4}, + {"2", &test_core_filebuf__2, 4}, + {"streq", &test_core_oid__streq, 5}, + {"0", &test_core_path__0, 6}, + {"1", &test_core_path__1, 6}, + {"2", &test_core_path__2, 6}, + {"5", &test_core_path__5, 6}, + {"6", &test_core_path__6, 6}, + {"delete_recursive", &test_core_rmdir__delete_recursive, 7}, + {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 7}, + {"0", &test_core_string__0, 8}, + {"1", &test_core_string__1, 8}, + {"int32", &test_core_strtol__int32, 9}, + {"int64", &test_core_strtol__int64, 9}, + {"0", &test_core_vector__0, 10}, + {"1", &test_core_vector__1, 10}, + {"2", &test_core_vector__2, 10}, + {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry, 11}, + {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment, 11}, + {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path, 11}, + {"find_invalid_chars_in_oid", &test_object_raw_chars__find_invalid_chars_in_oid, 12}, + {"build_valid_oid_from_raw_bytes", &test_object_raw_chars__build_valid_oid_from_raw_bytes, 12}, + {"succeed_on_copy_oid", &test_object_raw_compare__succeed_on_copy_oid, 13}, + {"succeed_on_oid_comparison_lesser", &test_object_raw_compare__succeed_on_oid_comparison_lesser, 13}, + {"succeed_on_oid_comparison_equal", &test_object_raw_compare__succeed_on_oid_comparison_equal, 13}, + {"succeed_on_oid_comparison_greater", &test_object_raw_compare__succeed_on_oid_comparison_greater, 13}, + {"compare_fmt_oids", &test_object_raw_compare__compare_fmt_oids, 13}, + {"compare_allocfmt_oids", &test_object_raw_compare__compare_allocfmt_oids, 13}, + {"compare_pathfmt_oids", &test_object_raw_compare__compare_pathfmt_oids, 13}, + {"succeed_on_oid_to_string_conversion", &test_object_raw_convert__succeed_on_oid_to_string_conversion, 14}, + {"succeed_on_oid_to_string_conversion_big", &test_object_raw_convert__succeed_on_oid_to_string_conversion_big, 14}, + {"fail_on_invalid_oid_string", &test_object_raw_fromstr__fail_on_invalid_oid_string, 15}, + {"succeed_on_valid_oid_string", &test_object_raw_fromstr__succeed_on_valid_oid_string, 15}, + {"hash_by_blocks", &test_object_raw_hash__hash_by_blocks, 16}, + {"hash_buffer_in_single_call", &test_object_raw_hash__hash_buffer_in_single_call, 16}, + {"hash_vector", &test_object_raw_hash__hash_vector, 16}, + {"hash_junk_data", &test_object_raw_hash__hash_junk_data, 16}, + {"hash_commit_object", &test_object_raw_hash__hash_commit_object, 16}, + {"hash_tree_object", &test_object_raw_hash__hash_tree_object, 16}, + {"hash_tag_object", &test_object_raw_hash__hash_tag_object, 16}, + {"hash_zero_length_object", &test_object_raw_hash__hash_zero_length_object, 16}, + {"hash_one_byte_object", &test_object_raw_hash__hash_one_byte_object, 16}, + {"hash_two_byte_object", &test_object_raw_hash__hash_two_byte_object, 16}, + {"hash_multi_byte_object", &test_object_raw_hash__hash_multi_byte_object, 16}, + {"oid_shortener_no_duplicates", &test_object_raw_short__oid_shortener_no_duplicates, 17}, + {"oid_shortener_stresstest_git_oid_shorten", &test_object_raw_short__oid_shortener_stresstest_git_oid_shorten, 17}, + {"validate_oid_size", &test_object_raw_size__validate_oid_size, 18}, + {"convert_type_to_string", &test_object_raw_type2string__convert_type_to_string, 19}, + {"convert_string_to_type", &test_object_raw_type2string__convert_string_to_type, 19}, + {"check_type_is_loose", &test_object_raw_type2string__check_type_is_loose, 19} }; static const struct clay_suite _all_suites[] = { { + "status::single", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[0], 1 + }, + { + "status::worktree", + {"initialize", &test_status_worktree__initialize, 1}, + {"cleanup", &test_status_worktree__cleanup, 1}, + &_all_callbacks[1], 2 + }, + { + "network::remotes", + {"initialize", &test_network_remotes__initialize, 2}, + {"cleanup", &test_network_remotes__cleanup, 2}, + &_all_callbacks[3], 4 + }, + { "core::dirent", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[0], 5 + &_all_callbacks[7], 5 }, { "core::filebuf", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[5], 3 + &_all_callbacks[12], 3 }, { "core::oid", - {"initialize", &test_core_oid__initialize, 2}, + {"initialize", &test_core_oid__initialize, 5}, {NULL, NULL, 0}, - &_all_callbacks[8], 1 + &_all_callbacks[15], 1 }, { "core::path", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[9], 5 + &_all_callbacks[16], 5 }, { "core::rmdir", - {"initialize", &test_core_rmdir__initialize, 4}, + {"initialize", &test_core_rmdir__initialize, 7}, {NULL, NULL, 0}, - &_all_callbacks[14], 2 + &_all_callbacks[21], 2 }, { "core::string", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[16], 2 + &_all_callbacks[23], 2 }, { "core::strtol", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[18], 2 + &_all_callbacks[25], 2 }, { "core::vector", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[20], 3 + &_all_callbacks[27], 3 }, { - "network::remotes", - {"initialize", &test_network_remotes__initialize, 8}, - {"cleanup", &test_network_remotes__cleanup, 8}, - &_all_callbacks[23], 4 + "object::tree::frompath", + {"initialize", &test_object_tree_frompath__initialize, 11}, + {"cleanup", &test_object_tree_frompath__cleanup, 11}, + &_all_callbacks[30], 3 }, { - "object::tree::frompath", - {"initialize", &test_object_tree_frompath__initialize, 9}, - {"cleanup", &test_object_tree_frompath__cleanup, 9}, - &_all_callbacks[27], 3 + "object::raw::chars", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[33], 2 }, { - "status::single", + "object::raw::compare", {NULL, NULL, 0}, {NULL, NULL, 0}, - &_all_callbacks[30], 1 + &_all_callbacks[35], 7 }, { - "status::worktree", - {"initialize", &test_status_worktree__initialize, 11}, - {"cleanup", &test_status_worktree__cleanup, 11}, - &_all_callbacks[31], 2 + "object::raw::convert", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[42], 2 + }, + { + "object::raw::fromstr", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[44], 2 + }, + { + "object::raw::hash", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[46], 11 + }, + { + "object::raw::short", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[57], 2 + }, + { + "object::raw::size", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[59], 1 + }, + { + "object::raw::type2string", + {NULL, NULL, 0}, + {NULL, NULL, 0}, + &_all_callbacks[60], 3 } }; -static const char _suites_str[] = "core::dirent, core::filebuf, core::oid, core::path, core::rmdir, core::string, core::strtol, core::vector, network::remotes, object::tree::frompath, status::single, status::worktree"; +static const char _suites_str[] = "status::single, status::worktree, network::remotes, core::dirent, core::filebuf, core::oid, core::path, core::rmdir, core::string, core::strtol, core::vector, object::tree::frompath, object::raw::chars, object::raw::compare, object::raw::convert, object::raw::fromstr, object::raw::hash, object::raw::short, object::raw::size, object::raw::type2string"; int _MAIN_CC main(int argc, char *argv[]) { return clay_test( argc, argv, _suites_str, - _all_callbacks, 33, - _all_suites, 12 + _all_callbacks, 63, + _all_suites, 20 ); } diff --git a/tests-clay/object/raw/chars.c b/tests-clay/object/raw/chars.c new file mode 100644 index 000000000..eba352b40 --- /dev/null +++ b/tests-clay/object/raw/chars.c @@ -0,0 +1,52 @@ + +#include "clay_libgit2.h" + +#include "odb.h" + +static int from_hex(unsigned int i) +{ + if (i >= '0' && i <= '9') + return i - '0'; + if (i >= 'a' && i <= 'f') + return 10 + (i - 'a'); + if (i >= 'A' && i <= 'F') + return 10 + (i - 'A'); + return -1; +} + +void test_object_raw_chars__find_invalid_chars_in_oid(void) +{ + git_oid out; + unsigned char exp[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + char in[41] = "16a67770b7d8d72317c4b775213c23a8bd74f5e0"; + unsigned int i; + + for (i = 0; i < 256; i++) { + in[38] = (char)i; + if (from_hex(i) >= 0) { + exp[19] = (unsigned char)(from_hex(i) << 4); + cl_git_pass(git_oid_fromstr(&out, in)); + cl_assert(memcmp(out.id, exp, sizeof(out.id)) == 0); + } else { + cl_git_fail(git_oid_fromstr(&out, in)); + } + } +} + +void test_object_raw_chars__build_valid_oid_from_raw_bytes(void) +{ + git_oid out; + unsigned char exp[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + git_oid_fromraw(&out, exp); + cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); +} diff --git a/tests-clay/object/raw/compare.c b/tests-clay/object/raw/compare.c new file mode 100644 index 000000000..45e5331be --- /dev/null +++ b/tests-clay/object/raw/compare.c @@ -0,0 +1,124 @@ + +#include "clay_libgit2.h" + +#include "odb.h" + +void test_object_raw_compare__succeed_on_copy_oid(void) +{ + git_oid a, b; + unsigned char exp[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + memset(&b, 0, sizeof(b)); + git_oid_fromraw(&a, exp); + git_oid_cpy(&b, &a); + cl_git_pass(memcmp(a.id, exp, sizeof(a.id))); +} + +void test_object_raw_compare__succeed_on_oid_comparison_lesser(void) +{ + git_oid a, b; + unsigned char a_in[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + unsigned char b_in[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xf0, + }; + git_oid_fromraw(&a, a_in); + git_oid_fromraw(&b, b_in); + cl_assert(git_oid_cmp(&a, &b) < 0); +} + +void test_object_raw_compare__succeed_on_oid_comparison_equal(void) +{ + git_oid a, b; + unsigned char a_in[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + git_oid_fromraw(&a, a_in); + git_oid_fromraw(&b, a_in); + cl_assert(git_oid_cmp(&a, &b) == 0); +} + +void test_object_raw_compare__succeed_on_oid_comparison_greater(void) +{ + git_oid a, b; + unsigned char a_in[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + unsigned char b_in[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xd0, + }; + git_oid_fromraw(&a, a_in); + git_oid_fromraw(&b, b_in); + cl_assert(git_oid_cmp(&a, &b) > 0); +} + +void test_object_raw_compare__compare_fmt_oids(void) +{ + const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; + git_oid in; + char out[GIT_OID_HEXSZ + 1]; + + cl_git_pass(git_oid_fromstr(&in, exp)); + + /* Format doesn't touch the last byte */ + out[GIT_OID_HEXSZ] = 'Z'; + git_oid_fmt(out, &in); + cl_assert(out[GIT_OID_HEXSZ] == 'Z'); + + /* Format produced the right result */ + out[GIT_OID_HEXSZ] = '\0'; + cl_assert(strcmp(exp, out) == 0); +} + +void test_object_raw_compare__compare_allocfmt_oids(void) +{ + const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; + git_oid in; + char *out; + + cl_git_pass(git_oid_fromstr(&in, exp)); + + out = git_oid_allocfmt(&in); + cl_assert(out); + cl_assert(strcmp(exp, out) == 0); + free(out); +} + +void test_object_raw_compare__compare_pathfmt_oids(void) +{ + const char *exp1 = "16a0123456789abcdef4b775213c23a8bd74f5e0"; + const char *exp2 = "16/a0123456789abcdef4b775213c23a8bd74f5e0"; + git_oid in; + char out[GIT_OID_HEXSZ + 2]; + + cl_git_pass(git_oid_fromstr(&in, exp1)); + + /* Format doesn't touch the last byte */ + out[GIT_OID_HEXSZ + 1] = 'Z'; + git_oid_pathfmt(out, &in); + cl_assert(out[GIT_OID_HEXSZ + 1] == 'Z'); + + /* Format produced the right result */ + out[GIT_OID_HEXSZ + 1] = '\0'; + cl_assert(strcmp(exp2, out) == 0); +} diff --git a/tests-clay/object/raw/convert.c b/tests-clay/object/raw/convert.c new file mode 100644 index 000000000..f69f5f924 --- /dev/null +++ b/tests-clay/object/raw/convert.c @@ -0,0 +1,75 @@ + +#include "clay_libgit2.h" + +#include "odb.h" + +void test_object_raw_convert__succeed_on_oid_to_string_conversion(void) +{ + const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; + git_oid in; + char out[GIT_OID_HEXSZ + 1]; + char *str; + int i; + + cl_git_pass(git_oid_fromstr(&in, exp)); + + /* NULL buffer pointer, returns static empty string */ + str = git_oid_to_string(NULL, sizeof(out), &in); + cl_assert(str && *str == '\0' && str != out); + + /* zero buffer size, returns static empty string */ + str = git_oid_to_string(out, 0, &in); + cl_assert(str && *str == '\0' && str != out); + + /* NULL oid pointer, returns static empty string */ + str = git_oid_to_string(out, sizeof(out), NULL); + cl_assert(str && *str == '\0' && str != out); + + /* n == 1, returns out as an empty string */ + str = git_oid_to_string(out, 1, &in); + cl_assert(str && *str == '\0' && str == out); + + for (i = 1; i < GIT_OID_HEXSZ; i++) { + out[i+1] = 'Z'; + str = git_oid_to_string(out, i+1, &in); + /* returns out containing c-string */ + cl_assert(str && str == out); + /* must be '\0' terminated */ + cl_assert(*(str+i) == '\0'); + /* must not touch bytes past end of string */ + cl_assert(*(str+(i+1)) == 'Z'); + /* i == n-1 charaters of string */ + cl_git_pass(strncmp(exp, out, i)); + } + + /* returns out as hex formatted c-string */ + str = git_oid_to_string(out, sizeof(out), &in); + cl_assert(str && str == out && *(str+GIT_OID_HEXSZ) == '\0'); + cl_assert(strcmp(exp, out) == 0); +} + +void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void) +{ + const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; + git_oid in; + char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */ + char *str; + + cl_git_pass(git_oid_fromstr(&in, exp)); + + /* place some tail material */ + big[GIT_OID_HEXSZ+0] = 'W'; /* should be '\0' afterwards */ + big[GIT_OID_HEXSZ+1] = 'X'; /* should remain untouched */ + big[GIT_OID_HEXSZ+2] = 'Y'; /* ditto */ + big[GIT_OID_HEXSZ+3] = 'Z'; /* ditto */ + + /* returns big as hex formatted c-string */ + str = git_oid_to_string(big, sizeof(big), &in); + cl_assert(str && str == big && *(str+GIT_OID_HEXSZ) == '\0'); + cl_assert(strcmp(exp, big) == 0); + + /* check tail material is untouched */ + cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+1) == 'X'); + cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+2) == 'Y'); + cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+3) == 'Z'); +} diff --git a/tests-clay/object/raw/data.h b/tests-clay/object/raw/data.h new file mode 100644 index 000000000..cf23819f1 --- /dev/null +++ b/tests-clay/object/raw/data.h @@ -0,0 +1,323 @@ + +/* + * Raw data + */ +static unsigned char commit_data[] = { + 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66, + 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35, + 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38, + 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32, + 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33, + 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55, + 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, + 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, + 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20, + 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, + 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, + 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, + 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65, + 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68, + 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, + 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d, + 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20, + 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x3e, 0x0a, +}; + + +static unsigned char tree_data[] = { + 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f, + 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79, + 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b, + 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31, + 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f, + 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86, + 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8, + 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31, + 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77, + 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b, + 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd, + 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30, + 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72, + 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, + 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a, + 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91, +}; + +static unsigned char tag_data[] = { + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33, + 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66, + 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66, + 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39, + 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32, + 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a, + 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20, + 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74, + 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20, + 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, + 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, + 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, + 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30, + 0x2e, 0x30, 0x2e, 0x31, 0x0a, +}; + +/* + * Dummy data + */ +static unsigned char zero_data[] = { + 0x00, +}; + +static unsigned char one_data[] = { + 0x0a, +}; + +static unsigned char two_data[] = { + 0x61, 0x0a, +}; + +static unsigned char some_data[] = { + 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, + 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, + 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, + 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, + 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, + 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a, + 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, + 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, + 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, + 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, + 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, + 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65, + 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e, + 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, + 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20, + 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, + 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a, + 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65, + 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, + 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, + 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, + 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e, + 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65, + 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20, + 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62, + 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, + 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c, + 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, + 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74, + 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48, + 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20, + 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59, + 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, + 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69, + 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61, + 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20, + 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, + 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, + 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54, + 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52, + 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, + 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, + 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20, + 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a, + 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f, + 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61, + 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, + 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, + 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, + 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47, + 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, + 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, + 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20, + 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e, + 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c, + 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46, + 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a, + 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c, + 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31, + 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20, + 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f, + 0x0a, +}; + +/* + * SHA1 Hashes + */ +static char *commit_id = "3d7f8a6af076c8c3f20071a8935cdbe8228594d1"; +static char *tree_id = "dff2da90b254e1beb889d1f1f1288be1803782df"; +static char *tag_id = "09d373e1dfdc16b129ceec6dd649739911541e05"; +static char *zero_id = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"; +static char *one_id = "8b137891791fe96927ad78e64b0aad7bded08bdc"; +static char *two_id = "78981922613b2afb6025042ff6bd878ac1994e85"; +static char *some_id = "fd8430bc864cfcd5f10e5590f8a447e01b942bfe"; + +/* + * In-memory objects + */ +static git_rawobj tree_obj = { + tree_data, + sizeof(tree_data), + GIT_OBJ_TREE +}; + +static git_rawobj tag_obj = { + tag_data, + sizeof(tag_data), + GIT_OBJ_TAG +}; + +static git_rawobj zero_obj = { + zero_data, + 0, + GIT_OBJ_BLOB +}; + +static git_rawobj one_obj = { + one_data, + sizeof(one_data), + GIT_OBJ_BLOB +}; + +static git_rawobj two_obj = { + two_data, + sizeof(two_data), + GIT_OBJ_BLOB +}; + +static git_rawobj commit_obj = { + commit_data, + sizeof(commit_data), + GIT_OBJ_COMMIT +}; + +static git_rawobj some_obj = { + some_data, + sizeof(some_data), + GIT_OBJ_BLOB +}; + +static git_rawobj junk_obj = { + NULL, + 0, + GIT_OBJ_BAD +}; diff --git a/tests-clay/object/raw/fromstr.c b/tests-clay/object/raw/fromstr.c new file mode 100644 index 000000000..6d732d4eb --- /dev/null +++ b/tests-clay/object/raw/fromstr.c @@ -0,0 +1,30 @@ + +#include "clay_libgit2.h" + +#include "odb.h" + +void test_object_raw_fromstr__fail_on_invalid_oid_string(void) +{ + git_oid out; + cl_git_fail(git_oid_fromstr(&out, "")); + cl_git_fail(git_oid_fromstr(&out, "moo")); + cl_git_fail(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez")); +} + +void test_object_raw_fromstr__succeed_on_valid_oid_string(void) +{ + git_oid out; + unsigned char exp[] = { + 0x16, 0xa6, 0x77, 0x70, 0xb7, + 0xd8, 0xd7, 0x23, 0x17, 0xc4, + 0xb7, 0x75, 0x21, 0x3c, 0x23, + 0xa8, 0xbd, 0x74, 0xf5, 0xe0, + }; + + cl_git_pass(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5e0")); + cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); + + cl_git_pass(git_oid_fromstr(&out, "16A67770B7D8D72317C4b775213C23A8BD74F5E0")); + cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); + +} diff --git a/tests-clay/object/raw/hash.c b/tests-clay/object/raw/hash.c new file mode 100644 index 000000000..9974ed6ef --- /dev/null +++ b/tests-clay/object/raw/hash.c @@ -0,0 +1,162 @@ + +#include "clay_libgit2.h" + +#include "odb.h" +#include "hash.h" + +#include "data.h" + +static int hash_object(git_oid *oid, git_rawobj *obj) +{ + return git_odb_hash(oid, obj->data, obj->len, obj->type); +} + +static char *hello_id = "22596363b3de40b06f981fb85d82312e8c0ed511"; +static char *hello_text = "hello world\n"; + +static char *bye_id = "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"; +static char *bye_text = "bye world\n"; + +void test_object_raw_hash__hash_by_blocks(void) +{ + git_hash_ctx *ctx; + git_oid id1, id2; + + cl_assert((ctx = git_hash_new_ctx()) != NULL); + + /* should already be init'd */ + git_hash_update(ctx, hello_text, strlen(hello_text)); + git_hash_final(&id2, ctx); + cl_git_pass(git_oid_fromstr(&id1, hello_id)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); + + /* reinit should permit reuse */ + git_hash_init(ctx); + git_hash_update(ctx, bye_text, strlen(bye_text)); + git_hash_final(&id2, ctx); + cl_git_pass(git_oid_fromstr(&id1, bye_id)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); + + git_hash_free_ctx(ctx); +} + +void test_object_raw_hash__hash_buffer_in_single_call(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, hello_id)); + git_hash_buf(&id2, hello_text, strlen(hello_text)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_vector(void) +{ + git_oid id1, id2; + git_buf_vec vec[2]; + + cl_git_pass(git_oid_fromstr(&id1, hello_id)); + + vec[0].data = hello_text; + vec[0].len = 4; + vec[1].data = hello_text+4; + vec[1].len = strlen(hello_text)-4; + + git_hash_vec(&id2, vec, 2); + + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_junk_data(void) +{ + git_oid id, id_zero; + + cl_git_pass(git_oid_fromstr(&id_zero, zero_id)); + + /* invalid types: */ + junk_obj.data = some_data; + cl_git_fail(hash_object(&id, &junk_obj)); + + junk_obj.type = GIT_OBJ__EXT1; + cl_git_fail(hash_object(&id, &junk_obj)); + + junk_obj.type = GIT_OBJ__EXT2; + cl_git_fail(hash_object(&id, &junk_obj)); + + junk_obj.type = GIT_OBJ_OFS_DELTA; + cl_git_fail(hash_object(&id, &junk_obj)); + + junk_obj.type = GIT_OBJ_REF_DELTA; + cl_git_fail(hash_object(&id, &junk_obj)); + + /* data can be NULL only if len is zero: */ + junk_obj.type = GIT_OBJ_BLOB; + junk_obj.data = NULL; + cl_git_pass(hash_object(&id, &junk_obj)); + cl_assert(git_oid_cmp(&id, &id_zero) == 0); + + junk_obj.len = 1; + cl_git_fail(hash_object(&id, &junk_obj)); +} + +void test_object_raw_hash__hash_commit_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, commit_id)); + cl_git_pass(hash_object(&id2, &commit_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_tree_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, tree_id)); + cl_git_pass(hash_object(&id2, &tree_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_tag_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, tag_id)); + cl_git_pass(hash_object(&id2, &tag_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_zero_length_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, zero_id)); + cl_git_pass(hash_object(&id2, &zero_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_one_byte_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, one_id)); + cl_git_pass(hash_object(&id2, &one_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_two_byte_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, two_id)); + cl_git_pass(hash_object(&id2, &two_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} + +void test_object_raw_hash__hash_multi_byte_object(void) +{ + git_oid id1, id2; + + cl_git_pass(git_oid_fromstr(&id1, some_id)); + cl_git_pass(hash_object(&id2, &some_obj)); + cl_assert(git_oid_cmp(&id1, &id2) == 0); +} diff --git a/tests-clay/object/raw/short.c b/tests-clay/object/raw/short.c new file mode 100644 index 000000000..46e4fba2c --- /dev/null +++ b/tests-clay/object/raw/short.c @@ -0,0 +1,94 @@ + +#include "clay_libgit2.h" + +#include "odb.h" +#include "hash.h" + +void test_object_raw_short__oid_shortener_no_duplicates(void) +{ + git_oid_shorten *os; + int min_len; + + os = git_oid_shorten_new(0); + cl_assert(os != NULL); + + git_oid_shorten_add(os, "22596363b3de40b06f981fb85d82312e8c0ed511"); + git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"); + git_oid_shorten_add(os, "16a0123456789abcdef4b775213c23a8bd74f5e0"); + min_len = git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"); + + cl_assert(min_len == GIT_OID_HEXSZ + 1); + + git_oid_shorten_free(os); +} + +void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void) +{ +#define MAX_OIDS 1000 + + git_oid_shorten *os; + char *oids[MAX_OIDS]; + char number_buffer[16]; + git_oid oid; + size_t i, j; + + int min_len = 0, found_collision; + + os = git_oid_shorten_new(0); + cl_assert(os != NULL); + + /* + * Insert in the shortener 1000 unique SHA1 ids + */ + for (i = 0; i < MAX_OIDS; ++i) { + char *oid_text; + + sprintf(number_buffer, "%u", (unsigned int)i); + git_hash_buf(&oid, number_buffer, strlen(number_buffer)); + + oid_text = git__malloc(GIT_OID_HEXSZ + 1); + git_oid_fmt(oid_text, &oid); + oid_text[GIT_OID_HEXSZ] = 0; + + min_len = git_oid_shorten_add(os, oid_text); + cl_assert(min_len >= 0); + + oids[i] = oid_text; + } + + /* + * Compare the first `min_char - 1` characters of each + * SHA1 OID. If the minimizer worked, we should find at + * least one collision + */ + found_collision = 0; + for (i = 0; i < MAX_OIDS; ++i) { + for (j = 0; j < MAX_OIDS; ++j) { + if (i != j && memcmp(oids[i], oids[j], min_len - 1) == 0) + found_collision = 1; + } + } + cl_assert(found_collision == 1); + + /* + * Compare the first `min_char` characters of each + * SHA1 OID. If the minimizer worked, every single preffix + * should be unique. + */ + found_collision = 0; + for (i = 0; i < MAX_OIDS; ++i) { + for (j = 0; j < MAX_OIDS; ++j) { + if (i != j && memcmp(oids[i], oids[j], min_len) == 0) + found_collision = 1; + } + } + cl_assert(found_collision == 0); + + /* cleanup */ + for (i = 0; i < MAX_OIDS; ++i) + free(oids[i]); + + git_oid_shorten_free(os); + +#undef MAX_OIDS +} diff --git a/tests-clay/object/raw/size.c b/tests-clay/object/raw/size.c new file mode 100644 index 000000000..44c5b6cd1 --- /dev/null +++ b/tests-clay/object/raw/size.c @@ -0,0 +1,13 @@ + +#include "clay_libgit2.h" + +#include "odb.h" + +void test_object_raw_size__validate_oid_size(void) +{ + git_oid out; + cl_assert(20 == GIT_OID_RAWSZ); + cl_assert(40 == GIT_OID_HEXSZ); + cl_assert(sizeof(out) == GIT_OID_RAWSZ); + cl_assert(sizeof(out.id) == GIT_OID_RAWSZ); +} diff --git a/tests-clay/object/raw/type2string.c b/tests-clay/object/raw/type2string.c new file mode 100644 index 000000000..109bc1112 --- /dev/null +++ b/tests-clay/object/raw/type2string.c @@ -0,0 +1,54 @@ + +#include "clay_libgit2.h" + +#include "odb.h" +#include "hash.h" + +void test_object_raw_type2string__convert_type_to_string(void) +{ + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_BAD), "")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ__EXT1), "")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_COMMIT), "commit")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_TREE), "tree")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_BLOB), "blob")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_TAG), "tag")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ__EXT2), "")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_OFS_DELTA), "OFS_DELTA")); + cl_assert(!strcmp(git_object_type2string(GIT_OBJ_REF_DELTA), "REF_DELTA")); + + cl_assert(!strcmp(git_object_type2string(-2), "")); + cl_assert(!strcmp(git_object_type2string(8), "")); + cl_assert(!strcmp(git_object_type2string(1234), "")); +} + +void test_object_raw_type2string__convert_string_to_type(void) +{ + cl_assert(git_object_string2type(NULL) == GIT_OBJ_BAD); + cl_assert(git_object_string2type("") == GIT_OBJ_BAD); + cl_assert(git_object_string2type("commit") == GIT_OBJ_COMMIT); + cl_assert(git_object_string2type("tree") == GIT_OBJ_TREE); + cl_assert(git_object_string2type("blob") == GIT_OBJ_BLOB); + cl_assert(git_object_string2type("tag") == GIT_OBJ_TAG); + cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJ_OFS_DELTA); + cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJ_REF_DELTA); + + cl_assert(git_object_string2type("CoMmIt") == GIT_OBJ_BAD); + cl_assert(git_object_string2type("hohoho") == GIT_OBJ_BAD); +} + +void test_object_raw_type2string__check_type_is_loose(void) +{ + cl_assert(git_object_typeisloose(GIT_OBJ_BAD) == 0); + cl_assert(git_object_typeisloose(GIT_OBJ__EXT1) == 0); + cl_assert(git_object_typeisloose(GIT_OBJ_COMMIT) == 1); + cl_assert(git_object_typeisloose(GIT_OBJ_TREE) == 1); + cl_assert(git_object_typeisloose(GIT_OBJ_BLOB) == 1); + cl_assert(git_object_typeisloose(GIT_OBJ_TAG) == 1); + cl_assert(git_object_typeisloose(GIT_OBJ__EXT2) == 0); + cl_assert(git_object_typeisloose(GIT_OBJ_OFS_DELTA) == 0); + cl_assert(git_object_typeisloose(GIT_OBJ_REF_DELTA) == 0); + + cl_assert(git_object_typeisloose(-2) == 0); + cl_assert(git_object_typeisloose(8) == 0); + cl_assert(git_object_typeisloose(1234) == 0); +} -- cgit v1.2.1 From 11d51ca63184b760e2537bbe08c5ca4c63bd4854 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 26 Oct 2011 16:43:55 -0700 Subject: windows: Add support for non-UTF codepages Our previous assumption that all paths in Windows are encoded in UTF-8 is rather weak, specially when considering that Git is encoding-agnostic. These set of functions allow the user to change the library's active codepage globally, so it is possible to access paths and files on all international versions of Windows. Note that the default encoding here is UTF-8 because we assume that 99% of all Git repositories will be in UTF-8. Also, if you use non-ascii characters in paths, anywhere, please burn on a fire. --- include/git2/windows.h | 59 +++++++++++++++++++++++++++++++++ src/config.c | 2 +- src/win32/dir.c | 9 +++--- src/win32/posix.h | 4 +-- src/win32/posix_w32.c | 24 +++++++------- src/win32/utf-conv.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/win32/utf-conv.h | 17 ++++++++++ src/win32/utf8-conv.c | 68 -------------------------------------- src/win32/utf8-conv.h | 17 ---------- 9 files changed, 184 insertions(+), 104 deletions(-) create mode 100644 include/git2/windows.h create mode 100644 src/win32/utf-conv.c create mode 100644 src/win32/utf-conv.h delete mode 100644 src/win32/utf8-conv.c delete mode 100644 src/win32/utf8-conv.h diff --git a/include/git2/windows.h b/include/git2/windows.h new file mode 100644 index 000000000..6a2e9e2cd --- /dev/null +++ b/include/git2/windows.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_windows_h__ +#define INCLUDE_git_windows_h__ + +#include "common.h" + +/** + * @file git2/windows.h + * @brief Windows-specific functions + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Set the active codepage for Windows syscalls + * + * All syscalls performed by the library will assume + * this codepage when converting paths and strings + * to use by the Windows kernel. + * + * The default value of UTF-8 will work automatically + * with most Git repositories created on Unix systems. + * + * This settings needs only be changed when working + * with repositories that contain paths in specific, + * non-UTF codepages. + * + * A full list of all available codepage identifiers may + * be found at: + * + * http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx + * + * @param codepage numeric codepage identifier + */ +GIT_EXTERN(void) gitwin_set_codepage(unsigned int codepage); + +/** + * Return the active codepage for Windows syscalls + * + * @return numeric codepage identifier + */ +GIT_EXTERN(unsigned int) gitwin_get_codepage(void); + +/** + * Set the active Windows codepage to UTF-8 (this is + * the default value) + */ +GIT_EXTERN(void) gitwin_set_utf8(void); + +/** @} */ +GIT_END_DECL +#endif + diff --git a/src/config.c b/src/config.c index f53afa145..ad6f88575 100644 --- a/src/config.c +++ b/src/config.c @@ -370,7 +370,7 @@ static int win32_find_system(char *system_config_path) return GIT_ENOTFOUND; } - apphome_utf8 = conv_utf16_to_utf8(apphome_utf16); + apphome_utf8 = gitwin_from_utf16(apphome_utf16); free(apphome_utf16); if (strlen(apphome_utf8) >= GIT_PATH_MAX) { diff --git a/src/win32/dir.c b/src/win32/dir.c index ab50318e3..fea74b4eb 100644 --- a/src/win32/dir.c +++ b/src/win32/dir.c @@ -6,7 +6,8 @@ */ #define GIT__WIN32_NO_WRAP_DIR #include "dir.h" -#include "utf8-conv.h" +#include "utf-conv.h" +#include "git2/windows.h" static int init_filter(char *filter, size_t n, const char *dir) { @@ -43,7 +44,7 @@ git__DIR *git__opendir(const char *dir) } strcpy(new->dir, dir); - filter_w = conv_utf8_to_utf16(filter); + filter_w = gitwin_to_utf16(filter); new->h = FindFirstFileW(filter_w, &new->f); free(filter_w); @@ -73,7 +74,7 @@ struct git__dirent *git__readdir(git__DIR *d) return NULL; d->entry.d_ino = 0; - WideCharToMultiByte(CP_UTF8, 0, d->f.cFileName, -1, d->entry.d_name, GIT_PATH_MAX, NULL, NULL); + WideCharToMultiByte(gitwin_get_codepage(), 0, d->f.cFileName, -1, d->entry.d_name, GIT_PATH_MAX, NULL, NULL); return &d->entry; } @@ -90,7 +91,7 @@ void git__rewinddir(git__DIR *d) d->first = 0; if (init_filter(filter, sizeof(filter), d->dir)) { - filter_w = conv_utf8_to_utf16(filter); + filter_w = gitwin_to_utf16(filter); d->h = FindFirstFileW(filter_w, &d->f); free(filter_w); diff --git a/src/win32/posix.h b/src/win32/posix.h index 442717e42..3774e7883 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -9,7 +9,7 @@ #include "common.h" #include "fnmatch.h" -#include "utf8-conv.h" +#include "utf-conv.h" GIT_INLINE(int) p_link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new)) { @@ -21,7 +21,7 @@ GIT_INLINE(int) p_link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new)) GIT_INLINE(int) p_mkdir(const char *path, int GIT_UNUSED(mode)) { - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); int ret = _wmkdir(buf); GIT_UNUSED_ARG(mode) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index cc17cc71f..a05aafcca 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -6,7 +6,7 @@ */ #include "posix.h" #include "path.h" -#include "utf8-conv.h" +#include "utf-conv.h" #include #include #include @@ -17,7 +17,7 @@ int p_unlink(const char *path) int ret = 0; wchar_t* buf; - buf = conv_utf8_to_utf16(path); + buf = gitwin_to_utf16(path); _wchmod(buf, 0666); ret = _wunlink(buf); free(buf); @@ -59,7 +59,7 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft) static int do_lstat(const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; - wchar_t* fbuf = conv_utf8_to_utf16(file_name); + wchar_t* fbuf = gitwin_to_utf16(file_name); if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { int fMode = S_IREAD; @@ -161,7 +161,7 @@ int p_readlink(const char *link, char *target, size_t target_len) "'GetFinalPathNameByHandleW' is not available in this platform"); } - link_w = conv_utf8_to_utf16(link); + link_w = gitwin_to_utf16(link); hFile = CreateFileW(link_w, // file to open GENERIC_READ, // open for reading @@ -223,7 +223,7 @@ int p_readlink(const char *link, char *target, size_t target_len) int p_open(const char *path, int flags) { int fd; - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); fd = _wopen(buf, flags | _O_BINARY); free(buf); @@ -233,7 +233,7 @@ int p_open(const char *path, int flags) int p_creat(const char *path, int mode) { int fd; - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode); free(buf); @@ -261,7 +261,7 @@ int p_stat(const char* path, struct stat* buf) int p_chdir(const char* path) { - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); int ret = _wchdir(buf); free(buf); @@ -270,7 +270,7 @@ int p_chdir(const char* path) int p_chmod(const char* path, int mode) { - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); int ret = _wchmod(buf, mode); free(buf); @@ -279,7 +279,7 @@ int p_chmod(const char* path, int mode) int p_rmdir(const char* path) { - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); int ret = _wrmdir(buf); free(buf); @@ -289,7 +289,7 @@ int p_rmdir(const char* path) int p_hide_directory__w32(const char *path) { int error; - wchar_t* buf = conv_utf8_to_utf16(path); + wchar_t* buf = gitwin_to_utf16(path); error = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0 ? GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */ @@ -305,7 +305,7 @@ int p_hide_directory__w32(const char *path) char *p_realpath(const char *orig_path, char *buffer) { int ret, alloc = 0; - wchar_t* orig_path_w = conv_utf8_to_utf16(orig_path); + wchar_t* orig_path_w = gitwin_to_utf16(orig_path); wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t)); if (buffer == NULL) { @@ -380,7 +380,7 @@ int p_setenv(const char* name, const char* value, int overwrite) int p_access(const char* path, int mode) { - wchar_t *buf = conv_utf8_to_utf16(path); + wchar_t *buf = gitwin_to_utf16(path); int ret; ret = _waccess(buf, mode); diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c new file mode 100644 index 000000000..cb607839e --- /dev/null +++ b/src/win32/utf-conv.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "utf-conv.h" + +/* + * Default codepage value + */ +static int _active_codepage = CP_UTF8; + +void gitwin_set_codepage(unsigned int codepage) +{ + _active_codepage = codepage; +} + +unsigned int gitwin_get_codepage(void) +{ + return _active_codepage; +} + +void gitwin_set_utf8(void) +{ + _active_codepage = CP_UTF8; +} + +wchar_t* gitwin_to_utf16(const char* str) +{ + wchar_t* ret; + int cb; + + if (!str) { + return NULL; + } + + cb = strlen(str) * sizeof(wchar_t); + if (cb == 0) { + ret = (wchar_t*)git__malloc(sizeof(wchar_t)); + ret[0] = 0; + return ret; + } + + /* Add space for null terminator */ + cb += sizeof(wchar_t); + + ret = (wchar_t*)git__malloc(cb); + + if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) { + free(ret); + ret = NULL; + } + + return ret; +} + +char* gitwin_from_utf16(const wchar_t* str) +{ + char* ret; + int cb; + + if (!str) { + return NULL; + } + + cb = wcslen(str) * sizeof(char); + if (cb == 0) { + ret = (char*)git__malloc(sizeof(char)); + ret[0] = 0; + return ret; + } + + /* Add space for null terminator */ + cb += sizeof(char); + + ret = (char*)git__malloc(cb); + + if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) { + free(ret); + ret = NULL; + } + + return ret; + +} diff --git a/src/win32/utf-conv.h b/src/win32/utf-conv.h new file mode 100644 index 000000000..da03e3385 --- /dev/null +++ b/src/win32/utf-conv.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include + +#ifndef INCLUDE_git_utfconv_h__ +#define INCLUDE_git_utfconv_h__ + +wchar_t* gitwin_to_utf16(const char* str); +char* gitwin_from_utf16(const wchar_t* str); + +#endif + diff --git a/src/win32/utf8-conv.c b/src/win32/utf8-conv.c deleted file mode 100644 index dec6f8e79..000000000 --- a/src/win32/utf8-conv.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2009-2011 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" -#include "utf8-conv.h" - -wchar_t* conv_utf8_to_utf16(const char* str) -{ - wchar_t* ret; - int cb; - - if (!str) { - return NULL; - } - - cb = strlen(str) * sizeof(wchar_t); - if (cb == 0) { - ret = (wchar_t*)git__malloc(sizeof(wchar_t)); - ret[0] = 0; - return ret; - } - - /* Add space for null terminator */ - cb += sizeof(wchar_t); - - ret = (wchar_t*)git__malloc(cb); - - if (MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, cb) == 0) { - free(ret); - ret = NULL; - } - - return ret; -} - -char* conv_utf16_to_utf8(const wchar_t* str) -{ - char* ret; - int cb; - - if (!str) { - return NULL; - } - - cb = wcslen(str) * sizeof(char); - if (cb == 0) { - ret = (char*)git__malloc(sizeof(char)); - ret[0] = 0; - return ret; - } - - /* Add space for null terminator */ - cb += sizeof(char); - - ret = (char*)git__malloc(cb); - - if (WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, cb, NULL, NULL) == 0) { - free(ret); - ret = NULL; - } - - return ret; - -} diff --git a/src/win32/utf8-conv.h b/src/win32/utf8-conv.h deleted file mode 100644 index 1967ac3a1..000000000 --- a/src/win32/utf8-conv.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2009-2011 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include - -#ifndef INCLUDE_git_utf8conv_h__ -#define INCLUDE_git_utf8conv_h__ - -wchar_t* conv_utf8_to_utf16(const char* str); -char* conv_utf16_to_utf8(const wchar_t* str); - -#endif - -- cgit v1.2.1 From 9f861826be17d1f3d4e34df1f4b2d4bd9aaec3b0 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Thu, 27 Oct 2011 16:45:44 +0200 Subject: Fixed crash in config parser when empty value is encountered. Example: key1 = value1 key2 = In this config the value will be a bad pointer which config object will attempt to free() causing a crash. --- src/config_file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/config_file.c b/src/config_file.c index a85ae1578..3540aae0a 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1158,19 +1158,25 @@ static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_val while (isspace(value_start[0])) value_start++; - if (value_start[0] == '\0') + if (value_start[0] == '\0') { + *var_value = NULL; goto out; + } if (is_multiline_var(value_start)) { error = parse_multiline_variable(cfg, value_start, var_value); - if (error < GIT_SUCCESS) + if (error != GIT_SUCCESS) + { + *var_value = NULL; free(*var_name); + } goto out; } tmp = strdup(value_start); if (tmp == NULL) { free(*var_name); + *var_value = NULL; error = GIT_ENOMEM; goto out; } -- cgit v1.2.1 From 899cb7a876a13f0031484db799a84b613c690c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 22 Oct 2011 11:36:18 +0200 Subject: status: remove git_index_entry_bypos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is already implemented (better) as git_index_get. Change the only caller to use that function. Signed-off-by: Carlos Martín Nieto --- src/status.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/status.c b/src/status.c index 1deade9a5..62b3fcb7f 100644 --- a/src/status.c +++ b/src/status.c @@ -337,17 +337,6 @@ static const git_tree_entry *git_tree_entry_bypos(git_tree *tree, unsigned int i return git_vector_get(&tree->entries, idx); } -/* - * Convenience method to enumerate the index. This method is not supposed to be exposed - * as part of the index API because it precludes that the index will not be altered - * while the enumeration is being processed. Which wouldn't be very API friendly :) - */ -static const git_index_entry *git_index_entry_bypos(git_index *index, unsigned int idx) -{ - assert(index); - return git_vector_get(&index->entries, idx); -} - /* Greatly inspired from JGit IndexTreeWalker */ /* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */ @@ -371,7 +360,7 @@ static int dirent_cb(void *state, char *a) while (1) { m = git_tree_entry_bypos(st->tree, st->tree_position); - entry = git_index_entry_bypos(st->index, st->index_position); + entry = git_index_get(st->index, st->index_position); if ((m == NULL) && (a == NULL) && (entry == NULL)) return GIT_SUCCESS; -- cgit v1.2.1 From c2892d61acfe4ec1544a87e2455bb086bee96516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 22 Oct 2011 11:46:22 +0200 Subject: status: remove git_tree_entry_bypos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only caller has been changed to treat a NULL tree as a special case and use the existing git_tree_entry_byindex. Signed-off-by: Carlos Martín Nieto --- src/status.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/status.c b/src/status.c index 62b3fcb7f..7449335c2 100644 --- a/src/status.c +++ b/src/status.c @@ -324,19 +324,6 @@ static int compare(const char *left, const char *right) return strcmp(left, right); } -/* - * Convenience method to enumerate a tree. Contrarily to the git_tree_entry_byindex() - * method, it allows the tree to be enumerated to be NULL. In this case, every returned - * tree entry will be NULL as well. - */ -static const git_tree_entry *git_tree_entry_bypos(git_tree *tree, unsigned int idx) -{ - if (tree == NULL) - return NULL; - - return git_vector_get(&tree->entries, idx); -} - /* Greatly inspired from JGit IndexTreeWalker */ /* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */ @@ -359,7 +346,11 @@ static int dirent_cb(void *state, char *a) a_name = (path_type != GIT_STATUS_PATH_NULL) ? a + st->workdir_path_len : NULL; while (1) { - m = git_tree_entry_bypos(st->tree, st->tree_position); + if (st->tree == NULL) + m = NULL; + else + m = git_tree_entry_byindex(st->tree, st->tree_position); + entry = git_index_get(st->index, st->index_position); if ((m == NULL) && (a == NULL) && (entry == NULL)) -- cgit v1.2.1 From 68a26dfa7c61b6421d7a32176e83b36420b7201b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 22 Oct 2011 12:33:49 +0200 Subject: status: reorder retrieve_head_tree error checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Martín Nieto --- src/status.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/status.c b/src/status.c index 7449335c2..bda4ec59a 100644 --- a/src/status.c +++ b/src/status.c @@ -142,16 +142,14 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo) *tree_out = NULL; error = git_repository_head(&resolved_head_ref, repo); - if (error != GIT_SUCCESS && error != GIT_ENOTFOUND) - return git__rethrow(error, "HEAD can't be resolved"); - /* * We assume that a situation where HEAD exists but can not be resolved is valid. * A new repository fits this description for instance. */ - if (error == GIT_ENOTFOUND) return GIT_SUCCESS; + if (error < GIT_SUCCESS) + return git__rethrow(error, "HEAD can't be resolved"); if ((error = git_commit_lookup(&head_commit, repo, git_reference_oid(resolved_head_ref))) < GIT_SUCCESS) return git__rethrow(error, "The tip of HEAD can't be retrieved"); -- cgit v1.2.1 From 1ca715e07a3d99b8a79ac606f7ddb81a10709a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 22 Oct 2011 12:36:30 +0200 Subject: status: move GIT_STATUS_PATH_* into an enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Their actual values have no meaning, so pack them in an enum. Signed-off-by: Carlos Martín Nieto --- src/status.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/status.c b/src/status.c index bda4ec59a..c53c4acc9 100644 --- a/src/status.c +++ b/src/status.c @@ -166,17 +166,19 @@ exit: return error; } -#define GIT_STATUS_PATH_NULL -2 -#define GIT_STATUS_PATH_IGNORE -1 -#define GIT_STATUS_PATH_FILE 0 -#define GIT_STATUS_PATH_FOLDER 1 +enum path_type { + GIT_STATUS_PATH_NULL, + GIT_STATUS_PATH_IGNORE, + GIT_STATUS_PATH_FILE, + GIT_STATUS_PATH_FOLDER, +}; static int dirent_cb(void *state, char *full_path); static int alphasorted_futils_direach( char *path, size_t path_sz, int (*fn)(void *, char *), void *arg); -static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, int path_type) +static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, enum path_type path_type) { git_object *subtree = NULL; git_tree *pushed_tree = NULL; @@ -240,7 +242,7 @@ static int determine_status(struct status_st *st, const git_index_entry *index_entry, char *full_path, const char *status_path, - int path_type) + enum path_type path_type) { struct status_entry *e; int error = GIT_SUCCESS; @@ -329,7 +331,7 @@ static int dirent_cb(void *state, char *a) { const git_tree_entry *m; const git_index_entry *entry; - int path_type; + enum path_type path_type; int cmpma, cmpmi, cmpai, error; const char *pm, *pa, *pi; const char *m_name, *i_name, *a_name; -- cgit v1.2.1 From da37654d04617b4dacce6e7a4796007d2854624d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 27 Oct 2011 22:33:31 -0700 Subject: tree: Add traversal in post-order --- include/git2/tree.h | 30 ++++++++++++++++++++++++++++ src/tree.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/include/git2/tree.h b/include/git2/tree.h index 8d638f723..68d82351a 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -282,6 +282,36 @@ GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_tr * entry, GIT_EINVALIDPATH or an error code */ GIT_EXTERN(int) git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path); + +/** Callback for the tree traversal method */ +typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry); + +/** Tree traversal modes */ +enum git_treewalk_mode { + GIT_TREEWALK_PRE = 0, /* Pre-order */ + GIT_TREEWALK_POST = 1, /* Post-order */ +}; + +/** + * Traverse the entries in a tree and its subtrees in + * post or pre order + * + * The entries will be traversed in the specified order, + * children subtrees will be automatically loaded as required, + * and the `callback` will be called once per entry with + * the current (relative) root for the entry and the entry + * data itself. + * + * If the callback returns a negative value, the passed entry + * will be skiped on the traversal. + * + * @param tree The tree to walk + * @param callback Function to call on each tree entry + * @param mode Traversal mode (pre or post-order) + * @return GIT_SUCCESS or an error code + */ +GIT_EXTERN(int) git_tree_walk(git_tree *walk, git_treewalk_cb callback, int mode); + /** @} */ GIT_END_DECL #endif diff --git a/src/tree.c b/src/tree.c index 00aefc295..77034fa43 100644 --- a/src/tree.c +++ b/src/tree.c @@ -15,6 +15,8 @@ #define MAX_FILEMODE 0777777 #define MAX_FILEMODE_BYTES 6 +#define ENTRY_IS_TREE(e) ((e)->attr & 040000) + static int valid_attributes(const int attributes) { return attributes >= 0 && attributes <= MAX_FILEMODE; @@ -31,8 +33,8 @@ static int entry_sort_cmp(const void *a, const void *b) const git_tree_entry *entry_b = (const git_tree_entry *)(b); return git_futils_cmp_path( - entry_a->filename, entry_a->filename_len, entry_a->attr & 040000, - entry_b->filename, entry_b->filename_len, entry_b->attr & 040000); + entry_a->filename, entry_a->filename_len, ENTRY_IS_TREE(entry_a), + entry_b->filename, entry_b->filename_len, ENTRY_IS_TREE(entry_b)); } @@ -654,3 +656,53 @@ int git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeent strcpy(buffer, treeentry_path); return tree_frompath(parent_out, root, buffer, 0); } + +static int tree_walk_post(git_tree *tree, git_treewalk_cb callback, char *root, size_t root_len) +{ + int error; + unsigned int i; + + for (i = 0; i < tree->entries.length; ++i) { + git_tree_entry *entry = tree->entries.contents[i]; + + root[root_len] = '\0'; + + if (callback(root, entry) < 0) + continue; + + if (ENTRY_IS_TREE(entry)) { + git_tree *subtree; + + if ((error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid)) < 0) + return error; + + strcpy(root + root_len, entry->filename); + root[root_len + entry->filename_len] = '/'; + + tree_walk_post(subtree, callback, root, root_len + entry->filename_len + 1); + + git_tree_close(subtree); + } + } + + return GIT_SUCCESS; +} + +int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode) +{ + char root_path[GIT_PATH_MAX]; + + root_path[0] = '\0'; + switch (mode) { + case GIT_TREEWALK_POST: + return tree_walk_post(tree, callback, root_path, 0); + + case GIT_TREEWALK_PRE: + return git__throw(GIT_ENOTIMPLEMENTED, + "Preorder tree walking is still not implemented"); + + default: + return git__throw(GIT_EINVALIDARGS, + "Invalid walking mode for tree walk"); + } +} -- cgit v1.2.1 From 3286c408eccb18c525ca123383f3ebf5097441bc Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 28 Oct 2011 14:51:13 -0700 Subject: global: Properly use `git__` memory wrappers Ensure that all memory related functions (malloc, calloc, strdup, free, etc) are using their respective `git__` wrappers. --- examples/network/fetch.c | 2 +- include/git2/oid.h | 2 +- src/blob.c | 2 +- src/buffer.c | 2 +- src/cache.c | 2 +- src/commit.c | 10 +++---- src/config.c | 16 +++++------ src/config_file.c | 64 ++++++++++++++++++++--------------------- src/delta-apply.c | 2 +- src/errors.c | 4 +-- src/filebuf.c | 14 ++++----- src/fileops.c | 6 ++-- src/hash.c | 2 +- src/hashtable.c | 10 +++---- src/index.c | 24 ++++++++-------- src/indexer.c | 10 +++---- src/mwindow.c | 6 ++-- src/netops.c | 2 +- src/object.c | 2 +- src/odb.c | 22 +++++++------- src/odb_loose.c | 16 +++++------ src/odb_pack.c | 10 +++---- src/oid.c | 8 +++--- src/pack.c | 20 ++++++------- src/path.c | 4 +-- src/pkt.c | 6 ++-- src/pqueue.c | 6 ++-- src/reflog.c | 26 ++++++++--------- src/refs.c | 16 +++++------ src/refspec.c | 2 +- src/remote.c | 20 ++++++------- src/repository.c | 14 ++++----- src/revwalk.c | 14 ++++----- src/signature.c | 6 ++-- src/status.c | 10 +++---- src/tag.c | 10 +++---- src/transports/git.c | 18 ++++++------ src/transports/http.c | 20 ++++++------- src/transports/local.c | 14 ++++----- src/tree-cache.c | 4 +-- src/tree.c | 16 +++++------ src/tsort.c | 4 +-- src/util.c | 4 +-- src/util.h | 2 ++ src/vector.c | 4 +-- src/win32/dir.c | 14 ++++----- src/win32/posix.h | 2 +- src/win32/posix_w32.c | 44 ++++++++++++++-------------- src/win32/utf-conv.c | 4 +-- tests-clay/core/path.c | 4 +-- tests-clay/core/vector.c | 4 +-- tests-clay/object/raw/compare.c | 2 +- tests-clay/object/raw/short.c | 2 +- tests/t00-core.c | 8 +++--- tests/t01-rawobj.c | 4 +-- tests/t04-commit.c | 6 ++-- tests/t07-hashtable.c | 6 ++-- tests/test_helpers.c | 2 +- 58 files changed, 291 insertions(+), 289 deletions(-) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index dd732f22e..35fc3eae4 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -119,7 +119,7 @@ int fetch(git_repository *repo, int argc, char **argv) if (error < GIT_SUCCESS) return error; - free(packname); + git__free(packname); git_indexer_free(idx); git_remote_free(remote); diff --git a/include/git2/oid.h b/include/git2/oid.h index b9824b887..9cebda931 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -100,7 +100,7 @@ GIT_EXTERN(void) git_oid_pathfmt(char *str, const git_oid *oid); * * @param oid the oid structure to format * @return the c-string; NULL if memory is exhausted. Caller must - * deallocate the string with free(). + * deallocate the string with git__free(). */ GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *oid); diff --git a/src/blob.c b/src/blob.c index 42564ab50..f13a5be15 100644 --- a/src/blob.c +++ b/src/blob.c @@ -27,7 +27,7 @@ size_t git_blob_rawsize(git_blob *blob) void git_blob__free(git_blob *blob) { git_odb_object_close(blob->odb_object); - free(blob); + git__free(blob); } int git_blob__parse(git_blob *blob, git_odb_object *odb_obj) diff --git a/src/buffer.c b/src/buffer.c index 0eeeecf2f..1fb848e46 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -97,7 +97,7 @@ const char *git_buf_cstr(git_buf *buf) void git_buf_free(git_buf *buf) { - free(buf->ptr); + git__free(buf->ptr); } void git_buf_clear(git_buf *buf) diff --git a/src/cache.c b/src/cache.c index 79f3eaea2..6ba4d212c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -53,7 +53,7 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->nodes[i].lock); } - free(cache->nodes); + git__free(cache->nodes); } void *git_cache_get(git_cache *cache, const git_oid *oid) diff --git a/src/commit.c b/src/commit.c index ced457ecc..b9eb3650f 100644 --- a/src/commit.c +++ b/src/commit.c @@ -32,7 +32,7 @@ static void clear_parents(git_commit *commit) for (i = 0; i < commit->parent_oids.length; ++i) { git_oid *parent = git_vector_get(&commit->parent_oids, i); - free(parent); + git__free(parent); } git_vector_clear(&commit->parent_oids); @@ -46,9 +46,9 @@ void git_commit__free(git_commit *commit) git_signature_free(commit->author); git_signature_free(commit->committer); - free(commit->message); - free(commit->message_encoding); - free(commit); + git__free(commit->message); + git__free(commit->message_encoding); + git__free(commit); } const git_oid *git_commit_id(git_commit *c) @@ -84,7 +84,7 @@ int git_commit_create_v( message_encoding, message, tree, parent_count, parents); - free((void *)parents); + git__free((void *)parents); return error; } diff --git a/src/config.c b/src/config.c index ad6f88575..4e48ff7f4 100644 --- a/src/config.c +++ b/src/config.c @@ -35,11 +35,11 @@ void git_config_free(git_config *cfg) internal = git_vector_get(&cfg->files, i); file = internal->file; file->free(file); - free(internal); + git__free(internal); } git_vector_free(&cfg->files); - free(cfg); + git__free(cfg); } static int config_backend_cmp(const void *a, const void *b) @@ -61,7 +61,7 @@ int git_config_new(git_config **out) memset(cfg, 0x0, sizeof(git_config)); if (git_vector_init(&cfg->files, 3, config_backend_cmp) < 0) { - free(cfg); + git__free(cfg); return GIT_ENOMEM; } @@ -125,7 +125,7 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority) internal->priority = priority; if (git_vector_insert(&cfg->files, internal) < 0) { - free(internal); + git__free(internal); return GIT_ENOMEM; } @@ -366,20 +366,20 @@ static int win32_find_system(char *system_config_path) return git__throw(GIT_ERROR, "Failed to expand environment strings"); if (_waccess(apphome_utf16, F_OK) < 0) { - free(apphome_utf16); + git__free(apphome_utf16); return GIT_ENOTFOUND; } apphome_utf8 = gitwin_from_utf16(apphome_utf16); - free(apphome_utf16); + git__free(apphome_utf16); if (strlen(apphome_utf8) >= GIT_PATH_MAX) { - free(apphome_utf8); + git__free(apphome_utf8); return git__throw(GIT_ESHORTBUFFER, "Path is too long"); } strcpy(system_config_path, apphome_utf8); - free(apphome_utf8); + git__free(apphome_utf8); return GIT_SUCCESS; } #endif diff --git a/src/config_file.c b/src/config_file.c index 3540aae0a..3cf1bb2e2 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -90,10 +90,10 @@ static void cvar_free(cvar_t *var) if (var == NULL) return; - free(var->section); - free(var->name); - free(var->value); - free(var); + git__free(var->section); + git__free(var->name); + git__free(var->value); + git__free(var); } static void cvar_list_free(cvar_t_list *list) @@ -188,7 +188,7 @@ static int cvar_normalize_name(cvar_t *var, char **output) if (section_sp == NULL) { ret = p_snprintf(name, len + 1, "%s.%s", var->section, var->name); if (ret < 0) { - free(name); + git__free(name); return git__throw(GIT_EOSERR, "Failed to normalize name. OS err: %s", strerror(errno)); } @@ -281,10 +281,10 @@ static void backend_free(git_config_file *_backend) if (backend == NULL) return; - free(backend->file_path); + git__free(backend->file_path); cvar_list_free(&backend->var_list); - free(backend); + git__free(backend); } static int file_foreach(git_config_file *backend, int (*fn)(const char *, const char *, void *), void *data) @@ -301,7 +301,7 @@ static int file_foreach(git_config_file *backend, int (*fn)(const char *, const return ret; ret = fn(normalized, var->value, data); - free(normalized); + git__free(normalized); if (ret) break; } @@ -326,7 +326,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value) if (tmp == NULL && value != NULL) return GIT_ENOMEM; - free(existing->value); + git__free(existing->value); existing->value = tmp; return config_write(b, existing); @@ -411,7 +411,7 @@ int git_config_file__ondisk(git_config_file **out, const char *path) backend->file_path = git__strdup(path); if (backend->file_path == NULL) { - free(backend); + git__free(backend); return GIT_ENOMEM; } @@ -653,13 +653,13 @@ static int parse_section_header(diskfile_backend *cfg, char **section_out) /* find the end of the variable's name */ name_end = strchr(line, ']'); if (name_end == NULL) { - free(line); + git__free(line); return git__throw(GIT_EOBJCORRUPTED, "Failed to parse header. Can't find header name end"); } name = (char *)git__malloc((size_t)(name_end - line) + 1); if (name == NULL) { - free(line); + git__free(line); return GIT_ENOMEM; } @@ -679,8 +679,8 @@ static int parse_section_header(diskfile_backend *cfg, char **section_out) if (isspace(c)){ name[name_length] = '\0'; error = parse_section_header_ext(line, name, section_out); - free(line); - free(name); + git__free(line); + git__free(name); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse header"); } @@ -699,14 +699,14 @@ static int parse_section_header(diskfile_backend *cfg, char **section_out) } name[name_length] = 0; - free(line); + git__free(line); git__strtolower(name); *section_out = name; return GIT_SUCCESS; error: - free(line); - free(name); + git__free(line); + git__free(name); return error; } @@ -810,7 +810,7 @@ static int config_parse(diskfile_backend *cfg_file) break; case '[': /* section header, new section begins */ - free(current_section); + git__free(current_section); current_section = NULL; error = parse_section_header(cfg_file, ¤t_section); break; @@ -826,7 +826,7 @@ static int config_parse(diskfile_backend *cfg_file) if (error < GIT_SUCCESS) break; - var = malloc(sizeof(cvar_t)); + var = git__malloc(sizeof(cvar_t)); if (var == NULL) { error = GIT_ENOMEM; break; @@ -837,7 +837,7 @@ static int config_parse(diskfile_backend *cfg_file) var->section = git__strdup(current_section); if (var->section == NULL) { error = GIT_ENOMEM; - free(var); + git__free(var); break; } @@ -851,7 +851,7 @@ static int config_parse(diskfile_backend *cfg_file) } } - free(current_section); + git__free(current_section); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse config"); } @@ -915,7 +915,7 @@ static int config_write(diskfile_backend *cfg, cvar_t *var) */ pre_end = post_start = cfg->reader.read_ptr; if (current_section) - free(current_section); + git__free(current_section); error = parse_section_header(cfg, ¤t_section); if (error < GIT_SUCCESS) break; @@ -953,8 +953,8 @@ static int config_write(diskfile_backend *cfg, cvar_t *var) if ((error = parse_variable(cfg, &var_name, &var_value)) == GIT_SUCCESS) cmp = strcasecmp(var->name, var_name); - free(var_name); - free(var_value); + git__free(var_name); + git__free(var_value); if (cmp != 0) break; @@ -1029,7 +1029,7 @@ static int config_write(diskfile_backend *cfg, cvar_t *var) git__rethrow(error, "Failed to write new section"); cleanup: - free(current_section); + git__free(current_section); if (error < GIT_SUCCESS) git_filebuf_cleanup(&file); @@ -1093,7 +1093,7 @@ static int parse_multiline_variable(diskfile_backend *cfg, const char *first, ch ret = p_snprintf(buf, len, "%s %s", first, line); if (ret < 0) { error = git__throw(GIT_EOSERR, "Failed to parse multiline var. Failed to put together two lines. OS err: %s", strerror(errno)); - free(buf); + git__free(buf); goto out; } @@ -1105,14 +1105,14 @@ static int parse_multiline_variable(diskfile_backend *cfg, const char *first, ch if (is_multiline_var(buf)) { char *final_val; error = parse_multiline_variable(cfg, buf, &final_val); - free(buf); + git__free(buf); buf = final_val; } *out = buf; out: - free(line); + git__free(line); return error; } @@ -1168,14 +1168,14 @@ static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_val if (error != GIT_SUCCESS) { *var_value = NULL; - free(*var_name); + git__free(*var_name); } goto out; } - tmp = strdup(value_start); + tmp = git__strdup(value_start); if (tmp == NULL) { - free(*var_name); + git__free(*var_name); *var_value = NULL; error = GIT_ENOMEM; goto out; @@ -1188,6 +1188,6 @@ static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_val } out: - free(line); + git__free(line); return error; } diff --git a/src/delta-apply.c b/src/delta-apply.c index e1fb15b9b..3e40bf8cf 100644 --- a/src/delta-apply.c +++ b/src/delta-apply.c @@ -109,7 +109,7 @@ int git__delta_apply( return GIT_SUCCESS; fail: - free(out->data); + git__free(out->data); out->data = NULL; return git__throw(GIT_ERROR, "Failed to apply delta"); } diff --git a/src/errors.c b/src/errors.c index 60d774636..18afff3b5 100644 --- a/src/errors.c +++ b/src/errors.c @@ -70,9 +70,9 @@ void git___rethrow(const char *msg, ...) vsnprintf(new_error, sizeof(new_error), msg, va); va_end(va); - old_error = strdup(g_last_error); + old_error = git__strdup(g_last_error); snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error); - free(old_error); + git__free(old_error); } void git___throw(const char *msg, ...) diff --git a/src/filebuf.c b/src/filebuf.c index 1a98e3f43..3f57d295d 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -63,13 +63,13 @@ void git_filebuf_cleanup(git_filebuf *file) if (file->digest) git_hash_free_ctx(file->digest); - free(file->buffer); - free(file->z_buf); + git__free(file->buffer); + git__free(file->z_buf); deflateEnd(&file->zs); - free(file->path_original); - free(file->path_lock); + git__free(file->path_original); + git__free(file->path_lock); } GIT_INLINE(int) flush_buffer(git_filebuf *file) @@ -248,7 +248,7 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file) int git_filebuf_commit_at(git_filebuf *file, const char *path) { - free(file->path_original); + git__free(file->path_original); file->path_original = git__strdup(path); if (file->path_original == NULL) return GIT_ENOMEM; @@ -368,12 +368,12 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...) va_end(arglist); if (len < 0) { - free(tmp_buffer); + git__free(tmp_buffer); return git__throw(GIT_EOSERR, "Failed to format string"); } error = git_filebuf_write(file, tmp_buffer, len); - free(tmp_buffer); + git__free(tmp_buffer); return error; } diff --git a/src/fileops.c b/src/fileops.c index 203cce0a4..c8de8d83d 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -181,7 +181,7 @@ int git_futils_readbuffer_updated(git_fbuffer *obj, const char *path, time_t *mt if (p_read(fd, buff, len) < 0) { p_close(fd); - free(buff); + git__free(buff); return git__throw(GIT_ERROR, "Failed to read file `%s`", path); } buff[len] = '\0'; @@ -207,7 +207,7 @@ int git_futils_readbuffer(git_fbuffer *obj, const char *path) void git_futils_freebuffer(git_fbuffer *obj) { assert(obj); - free(obj->data); + git__free(obj->data); obj->data = NULL; } @@ -326,7 +326,7 @@ int git_futils_mkdir_r(const char *path, int mode) error = GIT_SUCCESS; } - free(path_copy); + git__free(path_copy); if (error < GIT_SUCCESS) return git__throw(error, "Failed to recursively create `%s` tree structure", path); diff --git a/src/hash.c b/src/hash.c index ff85ca957..56063cc0b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -32,7 +32,7 @@ git_hash_ctx *git_hash_new_ctx(void) void git_hash_free_ctx(git_hash_ctx *ctx) { - free(ctx); + git__free(ctx); } void git_hash_init(git_hash_ctx *ctx) diff --git a/src/hashtable.c b/src/hashtable.c index 1382eabaa..15d173992 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -39,17 +39,17 @@ static int resize_to(git_hashtable *self, size_t new_size) self->is_resizing = 0; else { new_size *= 2; - free(self->nodes); + git__free(self->nodes); } } while(self->is_resizing); - free(old_nodes); + git__free(old_nodes); return GIT_SUCCESS; } static int set_size(git_hashtable *self, size_t new_size) { - self->nodes = realloc(self->nodes, new_size * sizeof(git_hashtable_node)); + self->nodes = git__realloc(self->nodes, new_size * sizeof(git_hashtable_node)); if (self->nodes == NULL) return GIT_ENOMEM; @@ -156,8 +156,8 @@ void git_hashtable_free(git_hashtable *self) { assert(self); - free(self->nodes); - free(self); + git__free(self->nodes); + git__free(self); } diff --git a/src/index.c b/src/index.c index 7bf5daf2c..9ace9515f 100644 --- a/src/index.c +++ b/src/index.c @@ -138,7 +138,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const index->index_file_path = git__strdup(index_path); if (index->index_file_path == NULL) { - free(index); + git__free(index); return GIT_ENOMEM; } @@ -179,8 +179,8 @@ void git_index_free(git_index *index) git_vector_free(&index->entries); git_vector_free(&index->unmerged); - free(index->index_file_path); - free(index); + git__free(index->index_file_path); + git__free(index); } void git_index_clear(git_index *index) @@ -192,15 +192,15 @@ void git_index_clear(git_index *index) for (i = 0; i < index->entries.length; ++i) { git_index_entry *e; e = git_vector_get(&index->entries, i); - free(e->path); - free(e); + git__free(e->path); + git__free(e); } for (i = 0; i < index->unmerged.length; ++i) { git_index_entry_unmerged *e; e = git_vector_get(&index->unmerged, i); - free(e->path); - free(e); + git__free(e->path); + git__free(e); } git_vector_clear(&index->entries); @@ -334,7 +334,7 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT); entry->path = git__strdup(rel_path); if (entry->path == NULL) { - free(entry); + git__free(entry); return GIT_ENOMEM; } @@ -364,8 +364,8 @@ static void index_entry_free(git_index_entry *entry) { if (!entry) return; - free(entry->path); - free(entry); + git__free(entry->path); + git__free(entry); } static int index_insert(git_index *index, git_index_entry *entry, int replace) @@ -416,8 +416,8 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) /* exists, replace it */ entry_array = (git_index_entry **) index->entries.contents; - free(entry_array[position]->path); - free(entry_array[position]); + git__free(entry_array[position]->path); + git__free(entry_array[position]); entry_array[position] = entry; return GIT_SUCCESS; diff --git a/src/indexer.c b/src/indexer.c index d5f605fdb..a09353ab7 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -367,7 +367,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) idx->fanout[i]++; } - free(obj.data); + git__free(obj.data); stats->processed = ++processed; } @@ -390,12 +390,12 @@ void git_indexer_free(git_indexer *idx) p_close(idx->pack->mwf.fd); git_vector_foreach(&idx->objects, i, e) - free(e); + git__free(e); git_vector_free(&idx->objects); git_vector_foreach(&idx->pack->cache, i, pe) - free(pe); + git__free(pe); git_vector_free(&idx->pack->cache); - free(idx->pack); - free(idx); + git__free(idx->pack); + git__free(idx); } diff --git a/src/mwindow.c b/src/mwindow.c index e53477e98..126268fd9 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -69,7 +69,7 @@ void git_mwindow_free_all(git_mwindow_file *mwf) git_futils_mmap_free(&w->window_map); mwf->windows = w->next; - free(w); + git__free(w); } } @@ -139,7 +139,7 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf) else *list = lru_w->next; - free(lru_w); + git__free(lru_w); ctl.open_windows--; return GIT_SUCCESS; @@ -191,7 +191,7 @@ static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t siz return w; cleanup: - free(w); + git__free(w); return NULL; } diff --git a/src/netops.c b/src/netops.c index dad296a94..73375d725 100644 --- a/src/netops.c +++ b/src/netops.c @@ -190,7 +190,7 @@ int gitno_extract_host_and_port(char **host, char **port, const char *url, const delim = colon == NULL ? slash : colon; *host = git__strndup(url, delim - url); if (*host == NULL) { - free(*port); + git__free(*port); error = GIT_ENOMEM; } diff --git a/src/object.c b/src/object.c index edc2d80fa..c84e94b05 100644 --- a/src/object.c +++ b/src/object.c @@ -213,7 +213,7 @@ void git_object__free(void *_obj) break; default: - free(object); + git__free(object); break; } } diff --git a/src/odb.c b/src/odb.c index 60789cf70..69fdba009 100644 --- a/src/odb.c +++ b/src/odb.c @@ -83,8 +83,8 @@ static void free_odb_object(void *o) git_odb_object *object = (git_odb_object *)o; if (object != NULL) { - free(object->raw.data); - free(object); + git__free(object->raw.data); + git__free(object); } } @@ -205,8 +205,8 @@ static void fake_wstream__free(git_odb_stream *_stream) { fake_wstream *stream = (fake_wstream *)_stream; - free(stream->buffer); - free(stream); + git__free(stream->buffer); + git__free(stream); } static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, size_t size, git_otype type) @@ -221,7 +221,7 @@ static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend stream->type = type; stream->buffer = git__malloc(size); if (stream->buffer == NULL) { - free(stream); + git__free(stream); return GIT_ENOMEM; } @@ -265,12 +265,12 @@ int git_odb_new(git_odb **out) error = git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object); if (error < GIT_SUCCESS) { - free(db); + git__free(db); return git__rethrow(error, "Failed to create object database"); } if ((error = git_vector_init(&db->backends, 4, backend_sort_cmp)) < GIT_SUCCESS) { - free(db); + git__free(db); return git__rethrow(error, "Failed to create object database"); } @@ -296,7 +296,7 @@ static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int prio internal->is_alternate = is_alternate; if (git_vector_insert(&odb->backends, internal) < 0) { - free(internal); + git__free(internal); return GIT_ENOMEM; } @@ -421,14 +421,14 @@ void git_odb_close(git_odb *db) git_odb_backend *backend = internal->backend; if (backend->free) backend->free(backend); - else free(backend); + else git__free(backend); - free(internal); + git__free(internal); } git_vector_free(&db->backends); git_cache_free(&db->cache); - free(db); + git__free(db); } int git_odb_exists(git_odb *db, const git_oid *id) diff --git a/src/odb_loose.c b/src/odb_loose.c index dbfe18b43..538fbc909 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -277,7 +277,7 @@ static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) else { set_stream_output(s, buf + used, hdr->size - used); if (finish_inflate(s)) { - free(buf); + git__free(buf); return NULL; } } @@ -317,7 +317,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_fbuffer *obj) in = ((unsigned char *)obj->data) + used; len = obj->len - used; if (inflate_buffer(in, len, buf, hdr.size)) { - free(buf); + git__free(buf); return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer"); } buf[hdr.size] = '\0'; @@ -686,7 +686,7 @@ static void loose_backend__stream_free(git_odb_stream *_stream) if (!stream->finished) git_filebuf_cleanup(&stream->fbuf); - free(stream); + git__free(stream); } static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type) @@ -739,14 +739,14 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); if (error < GIT_SUCCESS) { - free(stream); + git__free(stream); return git__rethrow(error, "Failed to create loose backend stream"); } error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen); if (error < GIT_SUCCESS) { git_filebuf_cleanup(&stream->fbuf); - free(stream); + git__free(stream); return git__rethrow(error, "Failed to create loose backend stream"); } @@ -803,8 +803,8 @@ static void loose_backend__free(git_odb_backend *_backend) assert(_backend); backend = (loose_backend *)_backend; - free(backend->objects_dir); - free(backend); + git__free(backend->objects_dir); + git__free(backend); } int git_odb_backend_loose( @@ -821,7 +821,7 @@ int git_odb_backend_loose( backend->objects_dir = git__strdup(objects_dir); if (backend->objects_dir == NULL) { - free(backend); + git__free(backend); return GIT_ENOMEM; } diff --git a/src/odb_pack.c b/src/odb_pack.c index a8f854236..800e7b0da 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -231,7 +231,7 @@ static int packfile_load__cb(void *_data, char *path) return git__rethrow(error, "Failed to load packfile"); if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) { - free(pack); + git__free(pack); return GIT_ENOMEM; } @@ -445,8 +445,8 @@ static void pack_backend__free(git_odb_backend *_backend) } git_vector_free(&backend->packs); - free(backend->pack_folder); - free(backend); + git__free(backend->pack_folder); + git__free(backend); } int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) @@ -459,7 +459,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) return GIT_ENOMEM; if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) { - free(backend); + git__free(backend); return GIT_ENOMEM; } @@ -469,7 +469,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->pack_folder_mtime = 0; if (backend->pack_folder == NULL) { - free(backend); + git__free(backend); return GIT_ENOMEM; } } diff --git a/src/oid.c b/src/oid.c index bbf19ea20..4b3080430 100644 --- a/src/oid.c +++ b/src/oid.c @@ -223,7 +223,7 @@ struct git_oid_shorten { static int resize_trie(git_oid_shorten *self, size_t new_size) { - self->nodes = realloc(self->nodes, new_size * sizeof(trie_node)); + self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node)); if (self->nodes == NULL) return GIT_ENOMEM; @@ -270,7 +270,7 @@ git_oid_shorten *git_oid_shorten_new(size_t min_length) memset(os, 0x0, sizeof(git_oid_shorten)); if (resize_trie(os, 16) < GIT_SUCCESS) { - free(os); + git__free(os); return NULL; } @@ -282,8 +282,8 @@ git_oid_shorten *git_oid_shorten_new(size_t min_length) void git_oid_shorten_free(git_oid_shorten *os) { - free(os->nodes); - free(os); + git__free(os->nodes); + git__free(os); } diff --git a/src/pack.c b/src/pack.c index 2516bea93..429bb5e0f 100644 --- a/src/pack.c +++ b/src/pack.c @@ -181,7 +181,7 @@ static int pack_index_open(struct git_pack_file *p) strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx"); error = pack_index_check(idx_name, p); - free(idx_name); + git__free(idx_name); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to open index"); } @@ -297,7 +297,7 @@ static int packfile_unpack_delta( error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type); if (error < GIT_SUCCESS) { - free(base.data); + git__free(base.data); return git__rethrow(error, "Corrupted delta"); } @@ -306,8 +306,8 @@ static int packfile_unpack_delta( base.data, base.len, delta.data, delta.len); - free(base.data); - free(delta.data); + git__free(base.data); + git__free(delta.data); /* TODO: we might want to cache this shit. eventually */ //add_delta_base_cache(p, base_offset, base, base_size, *type); @@ -390,7 +390,7 @@ int packfile_unpack_compressed( st = inflateInit(&stream); if (st != Z_OK) { - free(buffer); + git__free(buffer); return git__throw(GIT_EZLIB, "Error in zlib"); } @@ -408,7 +408,7 @@ int packfile_unpack_compressed( inflateEnd(&stream); if ((st != Z_STREAM_END) || stream.total_out != size) { - free(buffer); + git__free(buffer); return git__throw(GIT_EZLIB, "Error in zlib"); } @@ -504,8 +504,8 @@ void packfile_free(struct git_pack_file *p) pack_index_free(p); - free(p->bad_object_sha1); - free(p); + git__free(p->bad_object_sha1); + git__free(p); } static int packfile_open(struct git_pack_file *p) @@ -598,7 +598,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) */ path_len -= strlen(".idx"); if (path_len < 1) { - free(p); + git__free(p); return git__throw(GIT_ENOTFOUND, "Failed to check packfile. Wrong path name"); } @@ -610,7 +610,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) strcpy(p->pack_name + path_len, ".pack"); if (p_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) { - free(p); + git__free(p); return git__throw(GIT_ENOTFOUND, "Failed to check packfile. File not found"); } diff --git a/src/path.c b/src/path.c index 2c6b76dd0..a8851dfdc 100644 --- a/src/path.c +++ b/src/path.c @@ -144,7 +144,7 @@ char *git_path_dirname(const char *path) return NULL; if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) { - free(dname); + git__free(dname); return NULL; } @@ -162,7 +162,7 @@ char *git_path_basename(const char *path) return NULL; if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) { - free(bname); + git__free(bname); return NULL; } diff --git a/src/pkt.c b/src/pkt.c index 9471df2d5..ff8c56eb2 100644 --- a/src/pkt.c +++ b/src/pkt.c @@ -149,7 +149,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) out: if (error < GIT_SUCCESS) - free(pkt); + git__free(pkt); else *out = (git_pkt *)pkt; @@ -260,10 +260,10 @@ void git_pkt_free(git_pkt *pkt) { if(pkt->type == GIT_PKT_REF) { git_pkt_ref *p = (git_pkt_ref *) pkt; - free(p->head.name); + git__free(p->head.name); } - free(pkt); + git__free(pkt); } int git_pkt_buffer_flush(git_buf *buf) diff --git a/src/pqueue.c b/src/pqueue.c index b5ddab835..80713fbba 100644 --- a/src/pqueue.c +++ b/src/pqueue.c @@ -17,7 +17,7 @@ int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri) assert(q); /* Need to allocate n+1 elements since element 0 isn't used. */ - if ((q->d = malloc((n + 1) * sizeof(void *))) == NULL) + if ((q->d = git__malloc((n + 1) * sizeof(void *))) == NULL) return GIT_ENOMEM; q->size = 1; @@ -30,7 +30,7 @@ int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri) void git_pqueue_free(git_pqueue *q) { - free(q->d); + git__free(q->d); q->d = NULL; } @@ -102,7 +102,7 @@ int git_pqueue_insert(git_pqueue *q, void *d) /* allocate more memory if necessary */ if (q->size >= q->avail) { newsize = q->size + q->step; - if ((tmp = realloc(q->d, sizeof(void *) * newsize)) == NULL) + if ((tmp = git__realloc(q->d, sizeof(void *) * newsize)) == NULL) return GIT_ENOMEM; q->d = tmp; diff --git a/src/reflog.c b/src/reflog.c index 594963c03..a7e1f9259 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -25,8 +25,8 @@ static int reflog_init(git_reflog **reflog, git_reference *ref) log->ref_name = git__strdup(ref->name); if (git_vector_init(&log->entries, 0, NULL) < 0) { - free(log->ref_name); - free(log); + git__free(log->ref_name); + git__free(log); return GIT_ENOMEM; } @@ -86,8 +86,8 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) #define seek_forward(_increase) { \ if (_increase >= buf_size) { \ if (entry->committer) \ - free(entry->committer); \ - free(entry); \ + git__free(entry->committer); \ + git__free(entry); \ return git__throw(GIT_ERROR, "Failed to seek forward. Buffer size exceeded"); \ } \ buf += _increase; \ @@ -101,13 +101,13 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) entry->committer = NULL; if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < GIT_SUCCESS) { - free(entry); + git__free(entry); return GIT_ERROR; } seek_forward(GIT_OID_HEXSZ + 1); if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < GIT_SUCCESS) { - free(entry); + git__free(entry); return GIT_ERROR; } seek_forward(GIT_OID_HEXSZ + 1); @@ -120,13 +120,13 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) entry->committer = git__malloc(sizeof(git_signature)); if (entry->committer == NULL) { - free(entry); + git__free(entry); return GIT_ENOMEM; } if ((error = git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf)) < GIT_SUCCESS) { - free(entry->committer); - free(entry); + git__free(entry->committer); + git__free(entry); return git__rethrow(error, "Failed to parse reflog. Could not parse signature"); } @@ -164,13 +164,13 @@ void git_reflog_free(git_reflog *reflog) git_signature_free(entry->committer); - free(entry->msg); - free(entry); + git__free(entry->msg); + git__free(entry); } git_vector_free(&reflog->entries); - free(reflog->ref_name); - free(reflog); + git__free(reflog->ref_name); + git__free(reflog); } int git_reflog_read(git_reflog **reflog, git_reference *ref) diff --git a/src/refs.c b/src/refs.c index fcf771b5e..f21ca69de 100644 --- a/src/refs.c +++ b/src/refs.c @@ -77,12 +77,12 @@ static void reference_free(git_reference *reference) return; if (reference->name) - free(reference->name); + git__free(reference->name); if (reference->type == GIT_REF_SYMBOLIC) - free(((reference_symbolic *)reference)->target); + git__free(((reference_symbolic *)reference)->target); - free(reference); + git__free(reference); } static int reference_create( @@ -212,7 +212,7 @@ static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content) refname_start += header_len; - free(ref_sym->target); + git__free(ref_sym->target); ref_sym->target = git__strdup(refname_start); if (ref_sym->target == NULL) return GIT_ENOMEM; @@ -1203,7 +1203,7 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id) ref_old->ref.name = git__strdup(ref->name); if (ref_old->ref.name == NULL) { - free(ref_old); + git__free(ref_old); return GIT_ENOMEM; } } @@ -1252,7 +1252,7 @@ int git_reference_set_target(git_reference *ref, const char *target) ref_sym = (reference_symbolic *)ref; - free(ref_sym->target); + git__free(ref_sym->target); ref_sym->target = git__strdup(target); if (ref_sym->target == NULL) return GIT_ENOMEM; @@ -1381,7 +1381,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) goto rollback; } - free(ref->name); + git__free(ref->name); ref->name = new_ref->name; /* @@ -1408,7 +1408,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) goto rollback; cleanup: - free(old_name); + git__free(old_name); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference"); rollback: diff --git a/src/refspec.c b/src/refspec.c index ed4b5e6b8..e60e8f5b5 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -32,7 +32,7 @@ int git_refspec_parse(git_refspec *refspec, const char *str) refspec->dst = git__strdup(delim + 1); if (refspec->dst == NULL) { - free(refspec->src); + git__free(refspec->src); refspec->src = NULL; return GIT_ENOMEM; } diff --git a/src/remote.c b/src/remote.c index a557a4930..3ff08a21e 100644 --- a/src/remote.c +++ b/src/remote.c @@ -36,7 +36,7 @@ static int refspec_parse(git_refspec *refspec, const char *str) refspec->dst = git__strdup(delim + 1); if (refspec->dst == NULL) { - free(refspec->src); + git__free(refspec->src); refspec->src = NULL; return GIT_ENOMEM; } @@ -68,7 +68,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url) remote->repo = repo; remote->url = git__strdup(url); if (remote->url == NULL) { - free(remote); + git__free(remote); return GIT_ENOMEM; } @@ -150,7 +150,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) *out = remote; cleanup: - free(buf); + git__free(buf); if (error < GIT_SUCCESS) git_remote_free(remote); @@ -260,17 +260,17 @@ void git_remote_free(git_remote *remote) if (remote == NULL) return; - free(remote->fetch.src); - free(remote->fetch.dst); - free(remote->push.src); - free(remote->push.dst); - free(remote->url); - free(remote->name); + git__free(remote->fetch.src); + git__free(remote->fetch.dst); + git__free(remote->push.src); + git__free(remote->push.dst); + git__free(remote->url); + git__free(remote->name); if (remote->transport != NULL) { if (remote->transport->connected) remote->transport->close(remote->transport); remote->transport->free(remote->transport); } - free(remote); + git__free(remote); } diff --git a/src/repository.c b/src/repository.c index 328bc0d57..33a3f270b 100644 --- a/src/repository.c +++ b/src/repository.c @@ -168,12 +168,12 @@ static git_repository *repository_alloc(void) error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free); if (error < GIT_SUCCESS) { - free(repo); + git__free(repo); return NULL; } if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) { - free(repo); + git__free(repo); return NULL; } @@ -467,13 +467,13 @@ static int read_gitfile(char *path_out, const char *file_path, const char *base_ static void git_repository__free_dirs(git_repository *repo) { - free(repo->path_workdir); + git__free(repo->path_workdir); repo->path_workdir = NULL; - free(repo->path_index); + git__free(repo->path_index); repo->path_index = NULL; - free(repo->path_repository); + git__free(repo->path_repository); repo->path_repository = NULL; - free(repo->path_odb); + git__free(repo->path_odb); repo->path_odb = NULL; } @@ -489,7 +489,7 @@ void git_repository_free(git_repository *repo) if (repo->db != NULL) git_odb_close(repo->db); - free(repo); + git__free(repo); } int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs) diff --git a/src/revwalk.c b/src/revwalk.c index 2d70d40e9..7e31650ff 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -68,7 +68,7 @@ static void commit_list_free(commit_list **list_p) while (list) { commit_list *temp = list; list = temp->next; - free(temp); + git__free(temp); } *list_p = NULL; @@ -81,7 +81,7 @@ static commit_object *commit_list_pop(commit_list **stack) if (top) { *stack = top->next; - free(top); + git__free(top); } return item; } @@ -156,7 +156,7 @@ static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid) git_oid_cpy(&commit->oid, oid); if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) { - free(commit); + git__free(commit); return NULL; } @@ -442,7 +442,7 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) (git_hash_keyeq_ptr)git_oid_cmp); if (walk->commits == NULL) { - free(walk); + git__free(walk); return GIT_ENOMEM; } @@ -475,17 +475,17 @@ void git_revwalk_free(git_revwalk *walk) * make sure it's being free'd */ GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, { if (commit->out_degree > PARENTS_PER_COMMIT) - free(commit->parents); + git__free(commit->parents); }); git_hashtable_free(walk->commits); git_pqueue_free(&walk->iterator_time); for (i = 0; i < walk->memory_alloc.length; ++i) - free(git_vector_get(&walk->memory_alloc, i)); + git__free(git_vector_get(&walk->memory_alloc, i)); git_vector_free(&walk->memory_alloc); - free(walk); + git__free(walk); } git_repository *git_revwalk_repository(git_revwalk *walk) diff --git a/src/signature.c b/src/signature.c index 388e8d9c9..832d6439c 100644 --- a/src/signature.c +++ b/src/signature.c @@ -15,9 +15,9 @@ void git_signature_free(git_signature *sig) if (sig == NULL) return; - free(sig->name); - free(sig->email); - free(sig); + git__free(sig->name); + git__free(sig->email); + git__free(sig); } static const char *skip_leading_spaces(const char *buffer, const char *buffer_end) diff --git a/src/status.c b/src/status.c index c53c4acc9..1fc3794ea 100644 --- a/src/status.c +++ b/src/status.c @@ -229,7 +229,7 @@ static int store_if_changed(struct status_st *st, struct status_entry *e) return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path); if (e->status_flags == GIT_STATUS_CURRENT) { - free(e); + git__free(e); return GIT_SUCCESS; } @@ -446,7 +446,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig error = git__rethrow(error, "Failed to determine statuses. User callback failed"); } - free(e); + git__free(e); } exit: @@ -550,7 +550,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char exit: git_tree_close(tree); - free(e); + git__free(e); return error; } @@ -606,7 +606,7 @@ static int alphasorted_dirent_cb(void *state, char *full_path) return GIT_ENOMEM; if (git_vector_insert(entry_names, entry) < GIT_SUCCESS) { - free(entry); + git__free(entry); return GIT_ENOMEM; } @@ -639,7 +639,7 @@ static int alphasorted_futils_direach( error = fn(arg, entry->path); } - free(entry); + git__free(entry); } git_vector_free(&entry_names); diff --git a/src/tag.c b/src/tag.c index ba75104ef..0bdca93bb 100644 --- a/src/tag.c +++ b/src/tag.c @@ -16,9 +16,9 @@ void git_tag__free(git_tag *tag) { git_signature_free(tag->tagger); - free(tag->message); - free(tag->tag_name); - free(tag); + git__free(tag->message); + git__free(tag->tag_name); + git__free(tag); } const git_oid *git_tag_id(git_tag *c) @@ -341,8 +341,8 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu error = git_reference_set_oid(new_ref, oid); git_signature_free(tag.tagger); - free(tag.tag_name); - free(tag.message); + git__free(tag.tag_name); + git__free(tag.message); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); } diff --git a/src/transports/git.c b/src/transports/git.c index 489807851..c2014529b 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -109,8 +109,8 @@ static int do_connect(transport_git *t, const char *url) error = send_request(s, NULL, url); t->socket = s; - free(host); - free(port); + git__free(host); + git__free(port); if (error < GIT_SUCCESS && s > 0) close(s); @@ -357,11 +357,11 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g gitno_consume(buf, line_end); if (pkt->type == GIT_PKT_ACK) { - free(pkt); + git__free(pkt); error = GIT_SUCCESS; goto done; } else if (pkt->type == GIT_PKT_NAK) { - free(pkt); + git__free(pkt); break; } else { error = git__throw(GIT_ERROR, "Got unexpected pkt type"); @@ -424,12 +424,12 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor return error; if (pkt->type == GIT_PKT_PACK) { - free(pkt); + git__free(pkt); return git_fetch__download_pack(out, buf->data, buf->offset, t->socket, repo); } /* For now we don't care about anything */ - free(pkt); + git__free(pkt); gitno_consume(buf, line_end); } @@ -475,9 +475,9 @@ static void git_free(git_transport *transport) } git_vector_free(refs); - free(t->heads); - free(t->parent.url); - free(t); + git__free(t->heads); + git__free(t->parent.url); + git__free(t); } int git_transport_git(git_transport **out) diff --git a/src/transports/http.c b/src/transports/http.c index 680354bae..a1a73cb00 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -389,18 +389,18 @@ static int on_body_parse_response(http_parser *parser, const char *str, size_t l git_buf_consume(buf, line_end); if (pkt->type == GIT_PKT_PACK) { - free(pkt); + git__free(pkt); t->pack_ready = 1; return 0; } if (pkt->type == GIT_PKT_NAK) { - free(pkt); + git__free(pkt); return 0; } if (pkt->type != GIT_PKT_ACK) { - free(pkt); + git__free(pkt); continue; } @@ -749,13 +749,13 @@ static void http_free(git_transport *transport) } git_vector_free(common); git_buf_free(&t->buf); - free(t->heads); - free(t->content_type); - free(t->host); - free(t->port); - free(t->service); - free(t->parent.url); - free(t); + git__free(t->heads); + git__free(t->content_type); + git__free(t->host); + git__free(t->port); + git__free(t->service); + git__free(t->parent.url); + git__free(t); } int git_transport_http(git_transport **out) diff --git a/src/transports/local.c b/src/transports/local.c index 3f47e9b89..e09680478 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -113,8 +113,8 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) out: git_object_close(obj); if (error < GIT_SUCCESS) { - free(head->name); - free(head); + git__free(head->name); + git__free(head); } return error; } @@ -190,16 +190,16 @@ static void local_free(git_transport *transport) if (t->refs != NULL) { git_vector_foreach (vec, i, h) { - free(h->name); - free(h); + git__free(h->name); + git__free(h); } git_vector_free(vec); - free(vec); + git__free(vec); } git_repository_free(t->repo); - free(t->parent.url); - free(t); + git__free(t->parent.url); + git__free(t); } /************** diff --git a/src/tree-cache.c b/src/tree-cache.c index 5a3257520..ea8b7bfb7 100644 --- a/src/tree-cache.c +++ b/src/tree-cache.c @@ -196,6 +196,6 @@ void git_tree_cache_free(git_tree_cache *tree) for (i = 0; i < tree->children_count; ++i) git_tree_cache_free(tree->children[i]); - free(tree->children); - free(tree); + git__free(tree->children); + git__free(tree); } diff --git a/src/tree.c b/src/tree.c index 77034fa43..6efedcff5 100644 --- a/src/tree.c +++ b/src/tree.c @@ -130,12 +130,12 @@ void git_tree__free(git_tree *tree) git_tree_entry *e; e = git_vector_get(&tree->entries, i); - free(e->filename); - free(e); + git__free(e->filename); + git__free(e); } git_vector_free(&tree->entries); - free(tree); + git__free(tree); } const git_oid *git_tree_id(git_tree *c) @@ -378,7 +378,7 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig last_comp = subdir; } error = append_entry(bld, last_comp, &sub_oid, S_IFDIR); - free(subdir); + git__free(subdir); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Failed to insert dir"); goto cleanup; @@ -441,7 +441,7 @@ int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) source_entries = source->entries.length; if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < GIT_SUCCESS) { - free(bld); + git__free(bld); return GIT_ENOMEM; } @@ -596,8 +596,8 @@ void git_treebuilder_clear(git_treebuilder *bld) for (i = 0; i < bld->entries.length; ++i) { git_tree_entry *e = bld->entries.contents[i]; - free(e->filename); - free(e); + git__free(e->filename); + git__free(e); } git_vector_clear(&bld->entries); @@ -607,7 +607,7 @@ void git_treebuilder_free(git_treebuilder *bld) { git_treebuilder_clear(bld); git_vector_free(&bld->entries); - free(bld); + git__free(bld); } static int tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path, int offset) diff --git a/src/tsort.c b/src/tsort.c index 5dd99cc6e..df230b59d 100644 --- a/src/tsort.c +++ b/src/tsort.c @@ -178,7 +178,7 @@ static int check_invariant(struct tsort_run *stack, int stack_curr) static int resize(struct tsort_store *store, size_t new_size) { if (store->alloc < new_size) { - void **tempstore = realloc(store->storage, new_size * sizeof(void *)); + void **tempstore = git__realloc(store->storage, new_size * sizeof(void *)); /** * Do not propagate on OOM; this will abort the sort and @@ -319,7 +319,7 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr, stack_curr--; \ } \ if (store->storage != NULL) {\ - free(store->storage);\ + git__free(store->storage);\ store->storage = NULL;\ }\ return;\ diff --git a/src/util.c b/src/util.c index c81ed2d3a..b3af7ffd8 100644 --- a/src/util.c +++ b/src/util.c @@ -26,9 +26,9 @@ void git_strarray_free(git_strarray *array) { size_t i; for (i = 0; i < array->count; ++i) - free(array->strings[i]); + git__free(array->strings[i]); - free(array->strings); + git__free(array->strings); } int git__fnmatch(const char *pattern, const char *name, int flags) diff --git a/src/util.h b/src/util.h index 4de91b494..fbf9012a3 100644 --- a/src/util.h +++ b/src/util.h @@ -72,6 +72,8 @@ GIT_INLINE(void *) git__realloc(void *ptr, size_t size) return new_ptr; } +#define git__free(ptr) free(ptr) + extern int git__prefixcmp(const char *str, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); diff --git a/src/vector.c b/src/vector.c index 8b20bb8ef..123aae8e6 100644 --- a/src/vector.c +++ b/src/vector.c @@ -18,7 +18,7 @@ static int resize_vector(git_vector *v) if (v->_alloc_size < minimum_size) v->_alloc_size = minimum_size; - v->contents = realloc(v->contents, v->_alloc_size * sizeof(void *)); + v->contents = git__realloc(v->contents, v->_alloc_size * sizeof(void *)); if (v->contents == NULL) return GIT_ENOMEM; @@ -29,7 +29,7 @@ static int resize_vector(git_vector *v) void git_vector_free(git_vector *v) { assert(v); - free(v->contents); + git__free(v->contents); } int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp) diff --git a/src/win32/dir.c b/src/win32/dir.c index fea74b4eb..01aaaaad3 100644 --- a/src/win32/dir.c +++ b/src/win32/dir.c @@ -39,18 +39,18 @@ git__DIR *git__opendir(const char *dir) new->dir = git__malloc(strlen(dir)+1); if (!new->dir) { - free(new); + git__free(new); return NULL; } strcpy(new->dir, dir); filter_w = gitwin_to_utf16(filter); new->h = FindFirstFileW(filter_w, &new->f); - free(filter_w); + git__free(filter_w); if (new->h == INVALID_HANDLE_VALUE) { - free(new->dir); - free(new); + git__free(new->dir); + git__free(new); return NULL; } new->first = 1; @@ -93,7 +93,7 @@ void git__rewinddir(git__DIR *d) if (init_filter(filter, sizeof(filter), d->dir)) { filter_w = gitwin_to_utf16(filter); d->h = FindFirstFileW(filter_w, &d->f); - free(filter_w); + git__free(filter_w); if (d->h != INVALID_HANDLE_VALUE) d->first = 1; @@ -107,8 +107,8 @@ int git__closedir(git__DIR *d) if (d->h != INVALID_HANDLE_VALUE) FindClose(d->h); if (d->dir) - free(d->dir); - free(d); + git__free(d->dir); + git__free(d); } return 0; } diff --git a/src/win32/posix.h b/src/win32/posix.h index 3774e7883..5dcdb5f85 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -26,7 +26,7 @@ GIT_INLINE(int) p_mkdir(const char *path, int GIT_UNUSED(mode)) GIT_UNUSED_ARG(mode) - free(buf); + git__free(buf); return ret; } diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index a05aafcca..ed7450a94 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -20,7 +20,7 @@ int p_unlink(const char *path) buf = gitwin_to_utf16(path); _wchmod(buf, 0666); ret = _wunlink(buf); - free(buf); + git__free(buf); return ret; } @@ -86,11 +86,11 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - free(fbuf); + git__free(fbuf); return GIT_SUCCESS; } - free(fbuf); + git__free(fbuf); switch (GetLastError()) { case ERROR_ACCESS_DENIED: @@ -171,7 +171,7 @@ int p_readlink(const char *link, char *target, size_t target_len) FILE_FLAG_BACKUP_SEMANTICS, // normal file NULL); // no attr. template - free(link_w); + git__free(link_w); if (hFile == INVALID_HANDLE_VALUE) return GIT_EOSERR; @@ -184,17 +184,17 @@ int p_readlink(const char *link, char *target, size_t target_len) dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0); if (dwRet >= target_len) { - free(target_w); + git__free(target_w); CloseHandle(hFile); return GIT_ENOMEM; } if (!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, target_len * sizeof(char), NULL, NULL)) { - free(target_w); + git__free(target_w); return GIT_EOSERR; } - free(target_w); + git__free(target_w); CloseHandle(hFile); if (dwRet > 4) { @@ -226,7 +226,7 @@ int p_open(const char *path, int flags) wchar_t* buf = gitwin_to_utf16(path); fd = _wopen(buf, flags | _O_BINARY); - free(buf); + git__free(buf); return fd; } @@ -236,7 +236,7 @@ int p_creat(const char *path, int mode) wchar_t* buf = gitwin_to_utf16(path); fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode); - free(buf); + git__free(buf); return fd; } @@ -246,11 +246,11 @@ int p_getcwd(char *buffer_out, size_t size) _wgetcwd(buf, (int)size); if (!WideCharToMultiByte(CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL)) { - free(buf); + git__free(buf); return GIT_EOSERR; } - free(buf); + git__free(buf); return GIT_SUCCESS; } @@ -264,7 +264,7 @@ int p_chdir(const char* path) wchar_t* buf = gitwin_to_utf16(path); int ret = _wchdir(buf); - free(buf); + git__free(buf); return ret; } @@ -273,7 +273,7 @@ int p_chmod(const char* path, int mode) wchar_t* buf = gitwin_to_utf16(path); int ret = _wchmod(buf, mode); - free(buf); + git__free(buf); return ret; } @@ -282,7 +282,7 @@ int p_rmdir(const char* path) wchar_t* buf = gitwin_to_utf16(path); int ret = _wrmdir(buf); - free(buf); + git__free(buf); return ret; } @@ -294,7 +294,7 @@ int p_hide_directory__w32(const char *path) error = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0 ? GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */ - free(buf); + git__free(buf); if (error < GIT_SUCCESS) error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path); @@ -314,21 +314,21 @@ char *p_realpath(const char *orig_path, char *buffer) } ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL); - free(orig_path_w); + git__free(orig_path_w); if (!ret || ret > GIT_PATH_MAX) { - free(buffer_w); - if (alloc) free(buffer); + git__free(buffer_w); + if (alloc) git__free(buffer); return NULL; } if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) { - free(buffer_w); - if (alloc) free(buffer); + git__free(buffer_w); + if (alloc) git__free(buffer); } - free(buffer_w); + git__free(buffer_w); git_path_mkposix(buffer); return buffer; } @@ -384,7 +384,7 @@ int p_access(const char* path, int mode) int ret; ret = _waccess(buf, mode); - free(buf); + git__free(buf); return ret; } diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index cb607839e..b41c78f92 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -50,7 +50,7 @@ wchar_t* gitwin_to_utf16(const char* str) ret = (wchar_t*)git__malloc(cb); if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) { - free(ret); + git__free(ret); ret = NULL; } @@ -79,7 +79,7 @@ char* gitwin_from_utf16(const wchar_t* str) ret = (char*)git__malloc(cb); if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) { - free(ret); + git__free(ret); ret = NULL; } diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c index db8f33d21..c394c7285 100644 --- a/tests-clay/core/path.c +++ b/tests-clay/core/path.c @@ -11,7 +11,7 @@ check_dirname(const char *A, const char *B) cl_assert((dir2 = git_path_dirname(A)) != NULL); cl_assert(strcmp(dir2, B) == 0); - free(dir2); + git__free(dir2); } static void @@ -24,7 +24,7 @@ check_basename(const char *A, const char *B) cl_assert((base2 = git_path_basename(A)) != NULL); cl_assert(strcmp(base2, B) == 0); - free(base2); + git__free(base2); } static void diff --git a/tests-clay/core/vector.c b/tests-clay/core/vector.c index 44e6d873d..b8a853c60 100644 --- a/tests-clay/core/vector.c +++ b/tests-clay/core/vector.c @@ -59,8 +59,8 @@ void test_core_vector__2(void) git_vector_free(&x); - free(ptrs[0]); - free(ptrs[1]); + git__free(ptrs[0]); + git__free(ptrs[1]); } diff --git a/tests-clay/object/raw/compare.c b/tests-clay/object/raw/compare.c index 45e5331be..94b196945 100644 --- a/tests-clay/object/raw/compare.c +++ b/tests-clay/object/raw/compare.c @@ -101,7 +101,7 @@ void test_object_raw_compare__compare_allocfmt_oids(void) out = git_oid_allocfmt(&in); cl_assert(out); cl_assert(strcmp(exp, out) == 0); - free(out); + git__free(out); } void test_object_raw_compare__compare_pathfmt_oids(void) diff --git a/tests-clay/object/raw/short.c b/tests-clay/object/raw/short.c index 46e4fba2c..996f3f7b4 100644 --- a/tests-clay/object/raw/short.c +++ b/tests-clay/object/raw/short.c @@ -86,7 +86,7 @@ void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void) /* cleanup */ for (i = 0; i < MAX_OIDS; ++i) - free(oids[i]); + git__free(oids[i]); git_oid_shorten_free(os); diff --git a/tests/t00-core.c b/tests/t00-core.c index 703504bf8..f93444d57 100644 --- a/tests/t00-core.c +++ b/tests/t00-core.c @@ -99,8 +99,8 @@ BEGIN_TEST(vector2, "remove duplicates") must_be_true(x.length == 2); git_vector_free(&x); - free(ptrs[0]); - free(ptrs[1]); + git__free(ptrs[0]); + git__free(ptrs[1]); END_TEST @@ -112,7 +112,7 @@ BEGIN_TEST(path0, "get the dirname of a path") must_be_true(strcmp(dir, B) == 0); \ must_be_true((dir2 = git_path_dirname(A)) != NULL); \ must_be_true(strcmp(dir2, B) == 0); \ - free(dir2); \ + git__free(dir2); \ } DIRNAME_TEST(NULL, "."); @@ -141,7 +141,7 @@ BEGIN_TEST(path1, "get the base name of a path") must_be_true(strcmp(base, B) == 0); \ must_be_true((base2 = git_path_basename(A)) != NULL); \ must_be_true(strcmp(base2, B) == 0); \ - free(base2); \ + git__free(base2); \ } BASENAME_TEST(NULL, "."); diff --git a/tests/t01-rawobj.c b/tests/t01-rawobj.c index 255208532..8b05f3394 100644 --- a/tests/t01-rawobj.c +++ b/tests/t01-rawobj.c @@ -217,7 +217,7 @@ BEGIN_TEST(oid12, "compare oids (allocate + format)") out = git_oid_allocfmt(&in); must_be_true(out); must_be_true(strcmp(exp, out) == 0); - free(out); + git__free(out); END_TEST BEGIN_TEST(oid13, "compare oids (path format)") @@ -390,7 +390,7 @@ BEGIN_TEST(oid17, "stress test for the git_oid_shorten object") /* cleanup */ for (i = 0; i < MAX_OIDS; ++i) - free(oids[i]); + git__free(oids[i]); git_oid_shorten_free(os); diff --git a/tests/t04-commit.c b/tests/t04-commit.c index 3fb4d370c..303b8f7cb 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -162,7 +162,7 @@ BEGIN_TEST(parse1, "parse the signature line in a commit") must_be_true(strcmp(_email, person.email) == 0);\ must_be_true(_time == person.when.time);\ must_be_true(_offset == person.when.offset);\ - free(person.name); free(person.email);\ + git__free(person.name); git__free(person.email);\ } #define TEST_SIGNATURE_FAIL(_string, _header) { \ @@ -170,7 +170,7 @@ BEGIN_TEST(parse1, "parse the signature line in a commit") size_t len = strlen(_string);\ git_signature person = {NULL, NULL, {0, 0}}; \ must_fail(git_signature__parse(&person, &ptr, ptr + len, _header, '\n'));\ - free(person.name); free(person.email);\ + git__free(person.name); git__free(person.email);\ } TEST_SIGNATURE_PASS( @@ -759,7 +759,7 @@ BEGIN_TEST(root0, "create a root commit") must_pass(git_reference_set_target(head, head_old)); must_pass(git_reference_delete(branch)); must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); - free(head_old); + git__free(head_old); git_commit_close(commit); git_repository_free(repo); END_TEST diff --git a/tests/t07-hashtable.c b/tests/t07-hashtable.c index c0e852259..41d52af19 100644 --- a/tests/t07-hashtable.c +++ b/tests/t07-hashtable.c @@ -103,7 +103,7 @@ BEGIN_TEST(table1, "fill the hashtable with random entries") } git_hashtable_free(table); - free(objects); + git__free(objects); END_TEST @@ -145,7 +145,7 @@ BEGIN_TEST(table2, "make sure the table resizes automatically") } git_hashtable_free(table); - free(objects); + git__free(objects); END_TEST @@ -179,7 +179,7 @@ BEGIN_TEST(tableit0, "iterate through all the contents of the table") must_be_true(objects[i].visited); git_hashtable_free(table); - free(objects); + git__free(objects); END_TEST diff --git a/tests/test_helpers.c b/tests/test_helpers.c index cb95607e1..d1d7c9ebd 100644 --- a/tests/test_helpers.c +++ b/tests/test_helpers.c @@ -116,7 +116,7 @@ int remove_loose_object(const char *repository_folder, git_object *object) return -1; } - free(full_path); + git__free(full_path); return GIT_SUCCESS; } -- cgit v1.2.1 From d1db74bf57999ac336fddadf2f9ee7c24961268f Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 29 Oct 2011 17:40:04 +0200 Subject: status: Prevent segfaulting when determining the status of a repository Fixes #465 --- src/status.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/status.c b/src/status.c index 1fc3794ea..a3d6ee897 100644 --- a/src/status.c +++ b/src/status.c @@ -183,26 +183,28 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry git_object *subtree = NULL; git_tree *pushed_tree = NULL; int error, pushed_tree_position = 0; - git_otype tree_entry_type; - - tree_entry_type = git_tree_entry_type(tree_entry); - - switch (tree_entry_type) { - case GIT_OBJ_TREE: - error = git_tree_entry_2object(&subtree, ((git_object *)(st->tree))->repo, tree_entry); - pushed_tree = st->tree; - pushed_tree_position = st->tree_position; - st->tree = (git_tree *)subtree; - st->tree_position = 0; - st->head_tree_relative_path_len += 1 + tree_entry->filename_len; /* path + '/' + name */ - break; - - case GIT_OBJ_BLOB: - /* No op */ - break; - - default: - error = git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type"); /* TODO: How should we deal with submodules? */ + git_otype tree_entry_type = GIT_OBJ_BAD; + + if (tree_entry != NULL) { + tree_entry_type = git_tree_entry_type(tree_entry); + + switch (tree_entry_type) { + case GIT_OBJ_TREE: + error = git_tree_entry_2object(&subtree, ((git_object *)(st->tree))->repo, tree_entry); + pushed_tree = st->tree; + pushed_tree_position = st->tree_position; + st->tree = (git_tree *)subtree; + st->tree_position = 0; + st->head_tree_relative_path_len += 1 + tree_entry->filename_len; /* path + '/' + name */ + break; + + case GIT_OBJ_BLOB: + /* No op */ + break; + + default: + error = git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type"); /* TODO: How should we deal with submodules? */ + } } if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) -- cgit v1.2.1 From a1bd78ea29caa05cf44e57f525d5b11fd9e2dc3a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 29 Oct 2011 21:29:31 +0200 Subject: status: Add a file in the test repository to cover the correct sorting of entries when the working folder is being read In this case, "subdir.txt" should be listed before the "subdir" directory. --- tests/resources/status/.gitted/COMMIT_EDITMSG | 2 +- tests/resources/status/.gitted/ORIG_HEAD | 2 +- tests/resources/status/.gitted/index | Bin 1080 -> 1160 bytes tests/resources/status/.gitted/logs/HEAD | 1 + tests/resources/status/.gitted/logs/refs/heads/master | 1 + .../objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f | 2 ++ .../objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 | Bin 0 -> 331 bytes .../objects/e8/ee89e15bbe9b20137715232387b3de5b28972e | Bin 0 -> 38 bytes tests/resources/status/.gitted/refs/heads/master | 2 +- tests/resources/status/subdir.txt | 2 ++ 10 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f create mode 100644 tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 create mode 100644 tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e create mode 100644 tests/resources/status/subdir.txt diff --git a/tests/resources/status/.gitted/COMMIT_EDITMSG b/tests/resources/status/.gitted/COMMIT_EDITMSG index ff887ba13..1a25cd4a6 100644 --- a/tests/resources/status/.gitted/COMMIT_EDITMSG +++ b/tests/resources/status/.gitted/COMMIT_EDITMSG @@ -1 +1 @@ -add subdir +Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker diff --git a/tests/resources/status/.gitted/ORIG_HEAD b/tests/resources/status/.gitted/ORIG_HEAD index c2805f422..b46871fd6 100644 --- a/tests/resources/status/.gitted/ORIG_HEAD +++ b/tests/resources/status/.gitted/ORIG_HEAD @@ -1 +1 @@ -0017bd4ab1ec30440b17bae1680cff124ab5f1f6 +735b6a258cd196a8f7c9428419b02c1dca93fd75 diff --git a/tests/resources/status/.gitted/index b/tests/resources/status/.gitted/index index 5c4b18841..d793791c9 100644 Binary files a/tests/resources/status/.gitted/index and b/tests/resources/status/.gitted/index differ diff --git a/tests/resources/status/.gitted/logs/HEAD b/tests/resources/status/.gitted/logs/HEAD index e876bd80b..7b95b3cf1 100644 --- a/tests/resources/status/.gitted/logs/HEAD +++ b/tests/resources/status/.gitted/logs/HEAD @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny 1308050070 -0400 commit (initial): initial 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny 1308954538 -0400 commit: add subdir +735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken 1319911544 +0200 commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker diff --git a/tests/resources/status/.gitted/logs/refs/heads/master b/tests/resources/status/.gitted/logs/refs/heads/master index e876bd80b..7b95b3cf1 100644 --- a/tests/resources/status/.gitted/logs/refs/heads/master +++ b/tests/resources/status/.gitted/logs/refs/heads/master @@ -1,2 +1,3 @@ 0000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny 1308050070 -0400 commit (initial): initial 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny 1308954538 -0400 commit: add subdir +735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken 1319911544 +0200 commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker diff --git a/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f b/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f new file mode 100644 index 000000000..f7dddc4ff --- /dev/null +++ b/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f @@ -0,0 +1,2 @@ +xMnÄ …»Î)¬ÙVšò† ªö(Ì€BDˆ¢Þ¾LÐöûüžž«¥¤RÈ·Þˆ@êà,Î9Ž‹òÜÌœtàìæ•ðNj6f`žM6Z;h©ì …ZÜÐÞp Ú™Y,37¯/Ü;42x­&ÀægêìÏŸüÕÛ‰ùImú|½jñ \ No newline at end of file diff --git a/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 b/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 new file mode 100644 index 000000000..b75481b51 Binary files /dev/null and b/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 differ diff --git a/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e b/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e new file mode 100644 index 000000000..cfc2413d5 Binary files /dev/null and b/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e differ diff --git a/tests/resources/status/.gitted/refs/heads/master b/tests/resources/status/.gitted/refs/heads/master index b46871fd6..3e2e2a07a 100644 --- a/tests/resources/status/.gitted/refs/heads/master +++ b/tests/resources/status/.gitted/refs/heads/master @@ -1 +1 @@ -735b6a258cd196a8f7c9428419b02c1dca93fd75 +26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f diff --git a/tests/resources/status/subdir.txt b/tests/resources/status/subdir.txt new file mode 100644 index 000000000..e8ee89e15 --- /dev/null +++ b/tests/resources/status/subdir.txt @@ -0,0 +1,2 @@ +Is it a bird? +Is it a plane? -- cgit v1.2.1 From e3baa3ccf3b606517b3819913228c030854b8d77 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 29 Oct 2011 17:45:01 +0200 Subject: status: Fix a sorting issue in the treewalker This ensures that entries from the working directory are retrieved according to the following rules: - The file "subdir" should appear before the file "subdir.txt" - The folder "subdir" should appear after the file "subdir.txt" --- src/status.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/status.c b/src/status.c index a3d6ee897..d50199d9a 100644 --- a/src/status.c +++ b/src/status.c @@ -291,7 +291,7 @@ static int path_type_from(char *full_path, int is_dir) if (!is_dir) return GIT_STATUS_PATH_FILE; - if (!git__suffixcmp(full_path, "/" DOT_GIT)) + if (!git__suffixcmp(full_path, "/" DOT_GIT "/")) return GIT_STATUS_PATH_IGNORE; return GIT_STATUS_PATH_FOLDER; @@ -360,7 +360,13 @@ static int dirent_cb(void *state, char *a) if (m != NULL) { st->head_tree_relative_path[st->head_tree_relative_path_len] = '\0'; - git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename); + + /* When the tree entry is a folder, append a forward slash to its name */ + if (git_tree_entry_type(m) == GIT_OBJ_TREE) + git_path_join_n(st->head_tree_relative_path, 3, st->head_tree_relative_path, m->filename, ""); + else + git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename); + m_name = st->head_tree_relative_path; } else m_name = NULL; @@ -378,7 +384,7 @@ static int dirent_cb(void *state, char *a) if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS) return git__rethrow(error, "An error occured while determining the status of '%s'", a); - if (pa != NULL) + if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER)) return GIT_SUCCESS; } } @@ -571,19 +577,32 @@ struct alphasorted_dirent_info { static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const char *path) { - int is_dir; + int is_dir, size; struct alphasorted_dirent_info *di; is_dir = git_futils_isdir(path) == GIT_SUCCESS ? 1 : 0; + size = sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 2; - di = git__malloc(sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 1); + di = git__malloc(size); if (di == NULL) return NULL; - memset(di, 0x0, sizeof(*di)); + memset(di, 0x0, size); strcpy(di->path, path); - di->is_dir = is_dir; + + if (is_dir) { + di->is_dir = 1; + + /* + * Append a forward slash to the name to force folders + * to be ordered in a similar way than in a tree + * + * The file "subdir" should appear before the file "subdir.txt" + * The folder "subdir" should appear after the file "subdir.txt" + */ + di->path[strlen(path)] = '/'; + } return di; } -- cgit v1.2.1 From ec9079443c874fe1711acefb22b3fc606484c786 Mon Sep 17 00:00:00 2001 From: schu Date: Sun, 30 Oct 2011 13:48:00 +0100 Subject: test_helpers: do not rely on assert The functions loose_object_mode and loose_object_dir_mode call stat inside an assert statement which isn't evaluated when compiling in Release mode (NDEBUG) and leads to failing tests. Replace it. Signed-off-by: schu --- tests/test_helpers.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_helpers.c b/tests/test_helpers.c index 47a0b1b11..31e38bf6a 100644 --- a/tests/test_helpers.c +++ b/tests/test_helpers.c @@ -116,7 +116,8 @@ int loose_object_mode(const char *repository_folder, git_object *object) struct stat st; locate_loose_object(repository_folder, object, &object_path, NULL); - assert(p_stat(object_path, &st) == 0); + if (p_stat(object_path, &st) < 0) + return 0; free(object_path); return st.st_mode; @@ -138,7 +139,8 @@ int loose_object_dir_mode(const char *repository_folder, git_object *object) } } - assert(p_stat(object_path, &st) == 0); + if (p_stat(object_path, &st) < 0) + return 0; free(object_path); return st.st_mode; -- cgit v1.2.1 From 54ccc71786cf5a0fee69e7ec173e62abd4a12af5 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Sat, 5 Nov 2011 18:01:32 -0500 Subject: examples/general.c: update for recent API renaming of git_config_get_int git_config_get_int --> git_config_get_int32 --- examples/general.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/general.c b/examples/general.c index 9bfbc4083..8b58fa6ff 100644 --- a/examples/general.c +++ b/examples/general.c @@ -430,14 +430,14 @@ int main (int argc, char** argv) printf("\n*Config Listing*\n"); const char *email; - int j; + int32_t j; git_config *cfg; // Open a config object so we can read global values from it. git_config_open_ondisk(&cfg, "~/.gitconfig"); - git_config_get_int(cfg, "help.autocorrect", &j); + git_config_get_int32(cfg, "help.autocorrect", &j); printf("Autocorrect: %d\n", j); git_config_get_string(cfg, "user.email", &email); -- cgit v1.2.1 From a46ec45746f965f2895098e058979225d92d66e5 Mon Sep 17 00:00:00 2001 From: schu Date: Wed, 10 Aug 2011 16:19:42 +0200 Subject: refs: split internal and external references Currently libgit2 shares pointers to its internal reference cache with the user. This leads to several problems like invalidation of reference pointers when reordering the cache or manipulation of the cache from user side. Give each user its own git_reference instead of leaking the internal representation (struct reference). Add the following new API functions: * git_reference_free * git_reference_is_packed Signed-off-by: schu --- include/git2/refs.h | 31 ++-- src/commit.c | 5 +- src/refs.c | 424 +++++++++++++++++++++++++++++++++++++--------------- src/refs.h | 2 - tests/t10-refs.c | 72 ++++----- 5 files changed, 360 insertions(+), 174 deletions(-) diff --git a/include/git2/refs.h b/include/git2/refs.h index c319bfb3d..773ae445c 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -23,8 +23,7 @@ GIT_BEGIN_DECL /** * Lookup a reference by its name in a repository. * - * The generated reference is owned by the repository and - * should not be freed by the user. + * The generated reference must be freed by the user. * * @param reference_out pointer to the looked-up reference * @param repo the repository to look up the reference @@ -39,8 +38,7 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_reposito * The reference will be created in the repository and written * to the disk. * - * This reference is owned by the repository and shall not - * be free'd by the user. + * The generated reference must be freed by the user. * * If `force` is true and there already exists a reference * with the same name, it will be overwritten. @@ -60,8 +58,7 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos * The reference will be created in the repository and written * to the disk. * - * This reference is owned by the repository and shall not - * be free'd by the user. + * The generated reference must be freed by the user. * * If `force` is true and there already exists a reference * with the same name, it will be overwritten. @@ -173,7 +170,9 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); * The new name will be checked for validity and may be * modified into a normalized form. * - * The refernece will be immediately renamed in-memory + * The given git_reference will be updated. + * + * The reference will be immediately renamed in-memory * and on disk. * */ @@ -200,9 +199,6 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref); * Once the `packed-refs` file has been written properly, * the loose references will be removed from disk. * - * WARNING: calling this method may invalidate any existing - * references previously loaded on the cache. - * * @param repo Repository where the loose refs will be packed * @return GIT_SUCCESS or an error code */ @@ -253,6 +249,21 @@ GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, */ GIT_EXTERN(int) git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload); +/** + * Check if a reference is packed + * + * @param ref git_reference + * @return 0 in case it's not packed; 1 otherwise + */ +GIT_EXTERN(int) git_reference_is_packed(git_reference *ref); + +/** + * Free the given reference + * + * @param ref git_reference + */ +GIT_EXTERN(void) git_reference_free(git_reference *ref); + /** @} */ GIT_END_DECL #endif diff --git a/src/commit.c b/src/commit.c index b9eb3650f..1010fdc56 100644 --- a/src/commit.c +++ b/src/commit.c @@ -137,12 +137,13 @@ int git_commit_create( if (error == GIT_SUCCESS && update_ref != NULL) { git_reference *head; + git_reference *target; error = git_reference_lookup(&head, repo, update_ref); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to create commit"); - error = git_reference_resolve(&head, head); + error = git_reference_resolve(&target, head); if (error < GIT_SUCCESS) { if (error != GIT_ENOTFOUND) return git__rethrow(error, "Failed to create commit"); @@ -156,7 +157,7 @@ int git_commit_create( return git_reference_create_oid(&head, repo, git_reference_target(head), oid, 1); } - error = git_reference_set_oid(head, oid); + error = git_reference_set_oid(target, oid); } if (error < GIT_SUCCESS) diff --git a/src/refs.c b/src/refs.c index 679d7bbcc..1c33f73b2 100644 --- a/src/refs.c +++ b/src/refs.c @@ -17,13 +17,20 @@ #define MAX_NESTING_LEVEL 5 typedef struct { - git_reference ref; + git_repository *owner; + char *name; + unsigned int type; + time_t mtime; +} reference; + +typedef struct { + reference ref; git_oid oid; git_oid peel_target; } reference_oid; typedef struct { - git_reference ref; + reference ref; char *target; } reference_symbolic; @@ -40,16 +47,21 @@ static uint32_t reftable_hash(const void *key, int hash_id) return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]); } -static void reference_free(git_reference *reference); -static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type); +static void reference_free(reference *reference); +static int reference_create(reference **ref_out, git_repository *repo, const char *name, git_rtype type); static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated); +static int reference_set_target(reference *ref, const char *target); +static int reference_set_oid(reference *ref, const git_oid *oid); + +static int reference_delete(reference *ref); + /* loose refs */ -static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content); -static int loose_parse_oid(git_reference *ref, git_fbuffer *file_content); -static int loose_lookup(git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic); -static int loose_write(git_reference *ref); -static int loose_update(git_reference *ref); +static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content); +static int loose_parse_oid(reference *ref, git_fbuffer *file_content); +static int loose_lookup(reference **ref_out, git_repository *repo, const char *name, int skip_symbolic); +static int loose_write(reference *ref); +static int loose_update(reference *ref); /* packed refs */ static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end); @@ -64,15 +76,19 @@ static int packed_write(git_repository *repo); /* internal helpers */ static int reference_available(git_repository *repo, const char *ref, const char *old_ref); +static int reference_lookup(reference **out, git_repository *repo, const char *name); /* name normalization */ static int check_valid_ref_char(char ch); static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref); -/***************************************** - * Internal methods - Constructor/destructor - *****************************************/ -static void reference_free(git_reference *reference) +/* reference transition */ +static git_reference * reference_create_external(reference *ref); +static reference * reference_get_internal(git_reference *ref); + + + +static void reference_free(reference *reference) { if (reference == NULL) return; @@ -87,14 +103,14 @@ static void reference_free(git_reference *reference) } static int reference_create( - git_reference **ref_out, + reference **ref_out, git_repository *repo, const char *name, git_rtype type) { char normalized[GIT_REFNAME_MAX]; int error = GIT_SUCCESS, size; - git_reference *reference = NULL; + reference *reference = NULL; assert(ref_out && repo && name); @@ -145,13 +161,38 @@ static int reference_read(git_fbuffer *file_content, time_t *mtime, const char * return git_futils_readbuffer_updated(file_content, path, mtime, updated); } +static git_reference * reference_create_external(reference *ref) +{ + size_t size = sizeof(git_reference); + git_reference *out; + + out = git__malloc(size); + if (out == NULL) + return NULL; + + memset(out, 0x0, size); + + out->owner = ref->owner; + + out->name = git__strdup(ref->name); + if (out->name == NULL) { + git__free(out); + return NULL; + } + + return out; +} + +static reference * reference_get_internal(git_reference *ref) +{ + reference *out = NULL; + reference_lookup(&out, ref->owner, ref->name); + return out; +} -/***************************************** - * Internal methods - Loose references - *****************************************/ -static int loose_update(git_reference *ref) +static int loose_update(reference *ref) { int error, updated; git_fbuffer ref_file = GIT_FBUFFER_INIT; @@ -159,6 +200,7 @@ static int loose_update(git_reference *ref) if (ref->type & GIT_REF_PACKED) return packed_load(ref->owner); + /* error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name); if (error < GIT_SUCCESS) goto cleanup; @@ -181,7 +223,6 @@ static int loose_update(git_reference *ref) error = git__throw(GIT_EOBJCORRUPTED, "Invalid reference type (%d) for loose reference", ref->type); - cleanup: git_futils_freebuffer(&ref_file); if (error != GIT_SUCCESS) { @@ -192,7 +233,7 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to update loose reference"); } -static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content) +static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content) { const unsigned int header_len = strlen(GIT_SYMREF); const char *refname_start; @@ -231,7 +272,7 @@ static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content) return GIT_SUCCESS; } -static int loose_parse_oid(git_reference *ref, git_fbuffer *file_content) +static int loose_parse_oid(reference *ref, git_fbuffer *file_content) { int error; reference_oid *ref_oid; @@ -279,14 +320,14 @@ static git_rtype loose_guess_rtype(const char *full_path) } static int loose_lookup( - git_reference **ref_out, + reference **ref_out, git_repository *repo, const char *name, int skip_symbolic) { int error = GIT_SUCCESS; git_fbuffer ref_file = GIT_FBUFFER_INIT; - git_reference *ref = NULL; + reference *ref = NULL; time_t ref_time = 0; *ref_out = NULL; @@ -326,7 +367,7 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to lookup loose reference"); } -static int loose_write(git_reference *ref) +static int loose_write(reference *ref) { git_filebuf file; char ref_path[GIT_PATH_MAX]; @@ -370,15 +411,6 @@ unlock: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write loose reference"); } - - - - - -/***************************************** - * Internal methods - Packed references - *****************************************/ - static int packed_parse_peel( reference_oid *tag_ref, const char **buffer_out, @@ -458,7 +490,7 @@ static int packed_parse_oid( if (refname[refname_len - 1] == '\r') refname[refname_len - 1] = 0; - error = reference_create(&_ref, repo, refname, GIT_REF_OID); + error = reference_create((reference **)&_ref, repo, refname, GIT_REF_OID); if (error < GIT_SUCCESS) goto cleanup; @@ -473,7 +505,7 @@ static int packed_parse_oid( return GIT_SUCCESS; cleanup: - reference_free((git_reference *)ref); + reference_free((reference *)ref); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse OID of packed reference"); } @@ -550,7 +582,7 @@ static int packed_load(git_repository *repo) error = git_hashtable_insert(ref_cache->packfile, ref->ref.name, ref); if (error < GIT_SUCCESS) { - reference_free((git_reference *)ref); + reference_free((reference *)ref); goto cleanup; } } @@ -566,8 +598,6 @@ cleanup: } - - struct dirent_list_data { git_repository *repo; size_t repo_path_len; @@ -601,8 +631,8 @@ static int _dirent_loose_listall(void *_data, char *full_path) static int _dirent_loose_load(void *data, char *full_path) { git_repository *repository = (git_repository *)data; - git_reference *reference; void *old_ref = NULL; + reference *ref; char *file_path; int error; @@ -610,17 +640,17 @@ static int _dirent_loose_load(void *data, char *full_path) return git_futils_direach(full_path, GIT_PATH_MAX, _dirent_loose_load, repository); file_path = full_path + strlen(repository->path_repository); - error = loose_lookup(&reference, repository, file_path, 1); - if (error == GIT_SUCCESS && reference != NULL) { - reference->type |= GIT_REF_PACKED; + error = loose_lookup(&ref, repository, file_path, 1); + if (error == GIT_SUCCESS && ref != NULL) { + ref->type |= GIT_REF_PACKED; - if (git_hashtable_insert2(repository->references.packfile, reference->name, reference, &old_ref) < GIT_SUCCESS) { - reference_free(reference); + if (git_hashtable_insert2(repository->references.packfile, ref->name, ref, &old_ref) < GIT_SUCCESS) { + reference_free(ref); return GIT_ENOMEM; } if (old_ref != NULL) - reference_free((git_reference *)old_ref); + reference_free((reference *)old_ref); } return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to load loose dirent"); @@ -644,7 +674,7 @@ static int packed_loadloose(git_repository *repository) /* Remove any loose references from the cache */ { const void *GIT_UNUSED(_unused); - git_reference *reference; + reference *reference; GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference, reference_free(reference); @@ -767,16 +797,16 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list) unsigned int i; char full_path[GIT_PATH_MAX]; int error = GIT_SUCCESS; - git_reference *reference; + reference *r; for (i = 0; i < packing_list->length; ++i) { - git_reference *ref = git_vector_get(packing_list, i); + reference *ref = git_vector_get(packing_list, i); /* Ensure the packed reference doesn't exist * in a (more up-to-date?) state as a loose reference */ - reference = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name); - if (reference != NULL) + r = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name); + if (r != NULL) continue; git_path_join(full_path, repo->path_repository, ref->name); @@ -801,8 +831,8 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list) static int packed_sort(const void *a, const void *b) { - const git_reference *ref_a = (const git_reference *)a; - const git_reference *ref_b = (const git_reference *)b; + const reference *ref_a = (const reference *)a; + const reference *ref_b = (const reference *)b; return strcmp(ref_a->name, ref_b->name); } @@ -828,7 +858,7 @@ static int packed_write(git_repository *repo) /* Load all the packfile into a vector */ { - git_reference *reference; + reference *reference; const void *GIT_UNUSED(_unused); GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference, @@ -935,14 +965,7 @@ static int reference_available(git_repository *repo, const char *ref, const char return error == GIT_SUCCESS ? GIT_SUCCESS : git__throw(GIT_EEXISTS, "Reference name `%s` conflicts with existing reference", ref); } -/***************************************** - * External Library API - *****************************************/ - -/** - * Constructors - */ -int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) +int reference_lookup(reference **ref_out, git_repository *repo, const char *name) { int error; char normalized_name[GIT_REFNAME_MAX]; @@ -990,10 +1013,30 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch return git__throw(GIT_ENOTFOUND, "Failed to lookup reference. Reference doesn't exist"); } +int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) +{ + int error; + reference *ref; + + assert(ref_out && repo && name); + + *ref_out = NULL; + + error = reference_lookup(&ref, repo, name); + if (error < GIT_SUCCESS) + return error; + + *ref_out = reference_create_external(ref); + if (*ref_out == NULL) + return GIT_ENOMEM; + + return GIT_SUCCESS; +} + /** * Getters */ -git_rtype git_reference_type(git_reference *ref) +static git_rtype ref_type(reference *ref) { assert(ref); @@ -1006,6 +1049,43 @@ git_rtype git_reference_type(git_reference *ref) return GIT_REF_INVALID; } +git_rtype git_reference_type(git_reference *ref_in) +{ + reference *ref; + + assert(ref_in); + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return GIT_REF_INVALID; + + return ref_type(ref); +} + +int git_reference_is_packed(git_reference *ref_in) +{ + reference *ref; + + assert(ref_in); + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return GIT_REF_INVALID; + + return !!(ref->type & GIT_REF_PACKED); +} + +void git_reference_free(git_reference *ref) +{ + if (ref == NULL) + return; + + if (ref->name) + git__free(ref->name); + + git__free(ref); +} + const char *git_reference_name(git_reference *ref) { assert(ref); @@ -1018,7 +1098,7 @@ git_repository *git_reference_owner(git_reference *ref) return ref->owner; } -const git_oid *git_reference_oid(git_reference *ref) +static const git_oid *ref_oid(reference *ref) { assert(ref); @@ -1031,7 +1111,20 @@ const git_oid *git_reference_oid(git_reference *ref) return &((reference_oid *)ref)->oid; } -const char *git_reference_target(git_reference *ref) +const git_oid *git_reference_oid(git_reference *ref_in) +{ + reference *ref; + + assert(ref_in); + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return NULL; + + return ref_oid(ref); +} + +static const char *ref_target(reference *ref) { assert(ref); @@ -1044,14 +1137,27 @@ const char *git_reference_target(git_reference *ref) return ((reference_symbolic *)ref)->target; } -int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) +const char *git_reference_target(git_reference *ref_in) +{ + reference *ref; + + assert(ref_in); + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return NULL; + + return ref_target(ref); +} + +static int reference_create_symbolic(reference **ref_out, git_repository *repo, const char *name, const char *target, int force) { char normalized[GIT_REFNAME_MAX]; int error = GIT_SUCCESS, updated = 0; - git_reference *ref = NULL; + reference *ref = NULL; void *old_ref = NULL; - if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) + if (reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) return git__throw(GIT_EEXISTS, "Failed to create symbolic reference. Reference already exists"); /* @@ -1076,7 +1182,7 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, goto cleanup; /* set the target; this will write the reference on disk */ - error = git_reference_set_target(ref, normalized); + error = reference_set_target(ref, normalized); if (error < GIT_SUCCESS) goto cleanup; @@ -1090,7 +1196,7 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, goto cleanup; if (old_ref != NULL) - reference_free((git_reference *)old_ref); + reference_free((reference *)old_ref); } *ref_out = ref; @@ -1102,13 +1208,29 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference"); } -int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) +int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) +{ + int error; + reference *ref; + + error = reference_create_symbolic(&ref, repo, name, target, force); + if (error < GIT_SUCCESS) + return error; + + *ref_out = reference_create_external(ref); + if (*ref_out == NULL) + return GIT_ENOMEM; + + return GIT_SUCCESS; +} + +static int reference_create_oid(reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) { int error = GIT_SUCCESS, updated = 0; - git_reference *ref = NULL; + reference *ref = NULL; void *old_ref = NULL; - if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) + if(reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) return git__throw(GIT_EEXISTS, "Failed to create reference OID. Reference already exists"); if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS) @@ -1131,7 +1253,7 @@ int git_reference_create_oid(git_reference **ref_out, git_repository *repo, cons } /* set the oid; this will write the reference on disk */ - error = git_reference_set_oid(ref, id); + error = reference_set_oid(ref, id); if (error < GIT_SUCCESS) goto cleanup; @@ -1141,7 +1263,7 @@ int git_reference_create_oid(git_reference **ref_out, git_repository *repo, cons goto cleanup; if (old_ref != NULL) - reference_free((git_reference *)old_ref); + reference_free((reference *)old_ref); } *ref_out = ref; @@ -1153,9 +1275,21 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID"); } -/** - * Setters - */ +int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) +{ + int error; + reference *ref; + + error = reference_create_oid(&ref, repo, name, id, force); + if (error < GIT_SUCCESS) + return error; + + *ref_out = reference_create_external(ref); + if (*ref_out == NULL) + return GIT_ENOMEM; + + return GIT_SUCCESS; +} /* * Change the OID target of a reference. @@ -1177,7 +1311,7 @@ cleanup: * 4. Write the original to the loose cache * 5. Replace the original with the copy (old reference) in the packfile cache */ -int git_reference_set_oid(git_reference *ref, const git_oid *id) +int reference_set_oid(reference *ref, const git_oid *id) { reference_oid *ref_oid; reference_oid *ref_old = NULL; @@ -1233,10 +1367,21 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id) return GIT_SUCCESS; cleanup: - reference_free((git_reference *)ref_old); + reference_free((reference *)ref_old); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to set OID target of reference"); } +int git_reference_set_oid(git_reference *ref_in, const git_oid *target) +{ + reference *ref; + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); + + return reference_set_oid(ref, target); +} + /* * Change the target of a symbolic reference. * @@ -1244,7 +1389,7 @@ cleanup: * a pack. We just change the target in memory * and overwrite the file on disk. */ -int git_reference_set_target(git_reference *ref, const char *target) +int reference_set_target(reference *ref, const char *target) { reference_symbolic *ref_sym; @@ -1261,11 +1406,18 @@ int git_reference_set_target(git_reference *ref, const char *target) return loose_write(ref); } -/** - * Other - */ +int git_reference_set_target(git_reference *ref_in, const char *target) +{ + reference *ref; + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); -int git_reference_rename(git_reference *ref, const char *new_name, int force) + return reference_set_target(ref, target); +} + +int git_reference_rename(git_reference *ref_in, const char *new_name, int force) { int error; char *old_name = NULL; @@ -1276,9 +1428,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) const char *target_ref = NULL; const char *head_target = NULL; const git_oid *target_oid = NULL; - git_reference *new_ref = NULL, *head = NULL; + reference *ref = NULL, *new_ref = NULL, *head = NULL; - assert(ref); + assert(ref_in); + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); error = normalize_name(normalized, sizeof(normalized), new_name, ref->type & GIT_REF_OID); if (error < GIT_SUCCESS) @@ -1286,12 +1442,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) new_name = normalized; - error = git_reference_lookup(&new_ref, ref->owner, new_name); + error = reference_lookup(&new_ref, ref->owner, new_name); if (error == GIT_SUCCESS) { if (!force) return git__throw(GIT_EEXISTS, "Failed to rename reference. Reference already exists"); - error = git_reference_delete(new_ref); + error = reference_delete(new_ref); } if (error < GIT_SUCCESS) { @@ -1314,10 +1470,10 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) old_name = git__strdup(ref->name); if (ref->type & GIT_REF_SYMBOLIC) { - if ((target_ref = git_reference_target(ref)) == NULL) + if ((target_ref = ref_target(ref)) == NULL) goto cleanup; } else { - if ((target_oid = git_reference_oid(ref)) == NULL) + if ((target_oid = ref_oid(ref)) == NULL) goto cleanup; } @@ -1375,22 +1531,18 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) * Finally we can create the new reference. */ if (ref->type & GIT_REF_SYMBOLIC) { - if ((error = git_reference_create_symbolic(&new_ref, ref->owner, new_name, target_ref, 0)) < GIT_SUCCESS) + if ((error = reference_create_symbolic(&new_ref, ref->owner, new_name, target_ref, 0)) < GIT_SUCCESS) goto rollback; } else { - if ((error = git_reference_create_oid(&new_ref, ref->owner, new_name, target_oid, 0)) < GIT_SUCCESS) + if ((error = reference_create_oid(&new_ref, ref->owner, new_name, target_oid, 0)) < GIT_SUCCESS) goto rollback; } - git__free(ref->name); - ref->name = new_ref->name; - /* - * No need in new_ref anymore. We created it to fix the change on disk. - * TODO: Refactoring required. + * Change the name of the reference given by the user. */ - new_ref->name = NULL; - reference_free(new_ref); + git__free(ref_in->name); + ref_in->name = git__strdup(new_ref->name); if ((error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref)) < GIT_SUCCESS) goto rollback; @@ -1399,13 +1551,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) * Check if we have to update HEAD. */ - if ((error = git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE)) < GIT_SUCCESS) + if ((error = reference_lookup(&head, new_ref->owner, GIT_HEAD_FILE)) < GIT_SUCCESS) goto cleanup; - head_target = git_reference_target(head); + head_target = ref_target(head); if (head_target && !strcmp(head_target, old_name)) - if ((error = git_reference_create_symbolic(&head, ref->owner, "HEAD", ref->name, 1)) < GIT_SUCCESS) + if ((error = reference_create_symbolic(&head, new_ref->owner, "HEAD", new_ref->name, 1)) < GIT_SUCCESS) goto rollback; cleanup: @@ -1417,11 +1569,11 @@ rollback: * Try to create the old reference again. */ if (ref->type & GIT_REF_SYMBOLIC) - error = git_reference_create_symbolic(&new_ref, ref->owner, old_name, target_ref, 0); + error = reference_create_symbolic(&new_ref, ref->owner, old_name, target_ref, 0); else - error = git_reference_create_oid(&new_ref, ref->owner, old_name, target_oid, 0); + error = reference_create_oid(&new_ref, ref->owner, old_name, target_oid, 0); - ref->name = old_name; + ref_in->name = old_name; return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference. Failed to rollback"); } @@ -1441,10 +1593,10 @@ rollback: * * This obviously invalidates the `ref` pointer. */ -int git_reference_delete(git_reference *ref) +int reference_delete(reference *ref) { int error; - git_reference *reference; + reference *reference; assert(ref); @@ -1468,9 +1620,9 @@ int git_reference_delete(git_reference *ref) /* When deleting a loose reference, we have to ensure that an older * packed version of it doesn't exist */ - if (!git_reference_lookup(&reference, ref->owner, ref->name)) { + if (!reference_lookup(&reference, ref->owner, ref->name)) { assert((reference->type & GIT_REF_PACKED) != 0); - error = git_reference_delete(reference); + error = reference_delete(reference); } } @@ -1479,7 +1631,20 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to delete reference"); } -int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) +int git_reference_delete(git_reference *ref_in) +{ + reference *ref; + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return git__throw(GIT_ENOTFOUND, "Failed to delete reference. Reference `%s` doesn't exist", ref_in->name); + + git_reference_free(ref_in); + + return reference_delete(ref); +} + +static int reference_resolve(reference **resolved_ref, reference *ref) { git_repository *repo; int error, i; @@ -1501,13 +1666,35 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) return GIT_SUCCESS; ref_sym = (reference_symbolic *)ref; - if ((error = git_reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS) + if ((error = reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS) return error; } return git__throw(GIT_ENOMEM, "Failed to resolve reference. Reference is too nested"); } +int git_reference_resolve(git_reference **resolved_ref, git_reference *ref_in) +{ + int error; + reference *ref = NULL, *out = NULL; + + *resolved_ref = NULL; + + ref = reference_get_internal(ref_in); + if (ref == NULL) + return git__throw(GIT_ENOTFOUND, "Failed to resolve reference. Reference `%s` doesn't exist", ref_in->name); + + error = reference_resolve(&out, ref); + if (error < GIT_SUCCESS) + return error; + + *resolved_ref = reference_create_external(out); + if (*resolved_ref == NULL) + return GIT_ENOMEM; + + return GIT_SUCCESS; +} + int git_reference_packall(git_repository *repo) { int error; @@ -1588,12 +1775,6 @@ int git_reference_listall(git_strarray *array, git_repository *repo, unsigned in return GIT_SUCCESS; } - - - -/***************************************** - * Init/free (repository API) - *****************************************/ int git_repository__refcache_init(git_refcache *refs) { assert(refs); @@ -1612,7 +1793,7 @@ int git_repository__refcache_init(git_refcache *refs) void git_repository__refcache_free(git_refcache *refs) { - git_reference *reference; + reference *reference; const void *GIT_UNUSED(_unused); assert(refs); @@ -1632,11 +1813,6 @@ void git_repository__refcache_free(git_refcache *refs) } } - - -/***************************************** - * Name normalization - *****************************************/ static int check_valid_ref_char(char ch) { if ((unsigned) ch <= ' ') diff --git a/src/refs.h b/src/refs.h index 33c1e6983..db0f5c4df 100644 --- a/src/refs.h +++ b/src/refs.h @@ -35,8 +35,6 @@ struct git_reference { git_repository *owner; char *name; - unsigned int type; - time_t mtime; }; typedef struct { diff --git a/tests/t10-refs.c b/tests/t10-refs.c index 4cb31d5e7..cfedff0a5 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -42,8 +42,8 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); - must_be_true(reference->type & GIT_REF_OID); - must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(reference) & GIT_REF_OID); + must_be_true(git_reference_is_packed(reference) == 0); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); @@ -81,12 +81,12 @@ BEGIN_TEST(readsym0, "lookup a symbolic reference") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE)); - must_be_true(reference->type & GIT_REF_SYMBOLIC); - must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(reference) & GIT_REF_SYMBOLIC); + must_be_true(git_reference_is_packed(reference) == 0); must_be_true(strcmp(reference->name, GIT_HEAD_FILE) == 0); must_pass(git_reference_resolve(&resolved_ref, reference)); - must_be_true(resolved_ref->type == GIT_REF_OID); + must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID); must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); must_be_true(object != NULL); @@ -108,12 +108,12 @@ BEGIN_TEST(readsym1, "lookup a nested symbolic reference") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name)); - must_be_true(reference->type & GIT_REF_SYMBOLIC); - must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(reference) & GIT_REF_SYMBOLIC); + must_be_true(git_reference_is_packed(reference) == 0); must_be_true(strcmp(reference->name, head_tracker_sym_ref_name) == 0); must_pass(git_reference_resolve(&resolved_ref, reference)); - must_be_true(resolved_ref->type == GIT_REF_OID); + must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID); must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); must_be_true(object != NULL); @@ -173,8 +173,8 @@ BEGIN_TEST(readpacked0, "lookup a packed reference") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, packed_head_name)); - must_be_true(reference->type & GIT_REF_OID); - must_be_true((reference->type & GIT_REF_PACKED) != 0); + must_be_true(git_reference_type(reference) & GIT_REF_OID); + must_be_true(git_reference_is_packed(reference)); must_be_true(strcmp(reference->name, packed_head_name) == 0); must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); @@ -192,8 +192,8 @@ BEGIN_TEST(readpacked1, "assure that a loose reference is looked up before a pac must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, packed_head_name)); must_pass(git_reference_lookup(&reference, repo, packed_test_head_name)); - must_be_true(reference->type & GIT_REF_OID); - must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(reference) & GIT_REF_OID); + must_be_true(git_reference_is_packed(reference) == 0); must_be_true(strcmp(reference->name, packed_test_head_name) == 0); git_repository_free(repo); @@ -219,13 +219,13 @@ BEGIN_TEST(create0, "create a new symbolic reference") /* Ensure the reference can be looked-up... */ must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker)); - must_be_true(looked_up_ref->type & GIT_REF_SYMBOLIC); - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0); /* ...peeled.. */ must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); - must_be_true(resolved_ref->type == GIT_REF_OID); + must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID); /* ...and that it points to the current master tip */ must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); @@ -283,8 +283,8 @@ BEGIN_TEST(create2, "create a new OID reference") /* Ensure the reference can be looked-up... */ must_pass(git_reference_lookup(&looked_up_ref, repo, new_head)); - must_be_true(looked_up_ref->type & GIT_REF_OID); - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_type(looked_up_ref) & GIT_REF_OID); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); must_be_true(strcmp(looked_up_ref->name, new_head) == 0); /* ...and that it points to the current master tip */ @@ -359,14 +359,14 @@ BEGIN_TEST(overwrite1, "Overwrite an existing object id reference") must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); /* Create it */ must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0)); must_pass(git_reference_lookup(&ref, repo, ref_test_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); /* Ensure we can't overwrite unless we force it */ @@ -388,7 +388,7 @@ BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symboli must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0)); @@ -411,7 +411,7 @@ BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); /* Create the symbolic ref */ @@ -451,7 +451,7 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") /* Ensure a known loose ref can be looked up */ must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); - must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(reference) == 0); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); /* @@ -467,7 +467,7 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") /* Ensure the known ref can still be looked up but is now packed */ must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); - must_be_true((reference->type & GIT_REF_PACKED) != 0); + must_be_true(git_reference_is_packed(reference)); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); /* Ensure the known ref has been removed from the loose folder structure */ @@ -493,7 +493,7 @@ BEGIN_TEST(rename0, "rename a loose reference") must_pass(git_reference_lookup(&looked_up_ref, repo, loose_tag_ref_name)); /* ... which is indeed loose */ - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); /* Now that the reference is renamed... */ must_pass(git_reference_rename(looked_up_ref, new_name, 0)); @@ -507,8 +507,8 @@ BEGIN_TEST(rename0, "rename a loose reference") must_be_true(!strcmp(another_looked_up_ref->name, new_name)); /* .. the ref is still loose... */ - must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(another_looked_up_ref) == 0); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); /* ...and the ref can be found in the file system */ git_path_join(temp_path, repo->path_repository, new_name); @@ -533,7 +533,7 @@ BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); /* .. and it's packed */ - must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0); + must_be_true(git_reference_is_packed(looked_up_ref) != 0); /* Now that the reference is renamed... */ must_pass(git_reference_rename(looked_up_ref, brand_new_name, 0)); @@ -547,8 +547,8 @@ BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") must_be_true(!strcmp(another_looked_up_ref->name, brand_new_name)); /* .. the ref is no longer packed... */ - must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(another_looked_up_ref) == 0); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); /* ...and the ref now happily lives in the file system */ git_path_join(temp_path, repo->path_repository, brand_new_name); @@ -573,13 +573,13 @@ BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); /* Ensure it's loose */ - must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(another_looked_up_ref) == 0); /* Lookup the reference to rename */ must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); /* Ensure it's packed */ - must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0); + must_be_true(git_reference_is_packed(looked_up_ref) != 0); /* Now that the reference is renamed... */ must_pass(git_reference_rename(looked_up_ref, brand_new_name, 0)); @@ -588,7 +588,7 @@ BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); /* Ensure it's loose */ - must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(another_looked_up_ref) == 0); /* Ensure the other ref still exists on the file system */ must_pass(git_futils_exists(temp_path)); @@ -699,7 +699,7 @@ BEGIN_TEST(rename7, "can not overwrite name of existing reference") must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); @@ -729,7 +729,7 @@ BEGIN_TEST(rename8, "can be renamed to a new name prefixed with the old name") must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); @@ -758,7 +758,7 @@ BEGIN_TEST(rename9, "can move a reference to a upper reference hierarchy") must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&ref, repo, ref_master_name)); - must_be_true(ref->type & GIT_REF_OID); + must_be_true(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_oid(ref)); @@ -794,7 +794,7 @@ BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name)); /* Ensure it's the loose version that has been found */ - must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(git_reference_is_packed(looked_up_ref) == 0); /* Now that the reference is deleted... */ must_pass(git_reference_delete(looked_up_ref)); -- cgit v1.2.1 From 4fd89fa0392967fabb905c7f4001cd4834f11dbd Mon Sep 17 00:00:00 2001 From: schu Date: Tue, 26 Jul 2011 11:17:32 +0200 Subject: refs: add test case checking "immutable" references Signed-off-by: schu --- tests/t10-refs.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/t10-refs.c b/tests/t10-refs.c index cfedff0a5..298aaa07f 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -808,6 +808,37 @@ BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove close_temp_repo(repo); END_TEST +BEGIN_TEST(delete1, "can delete a just packed reference") + git_reference *ref; + git_repository *repo; + git_oid id; + const char *new_ref = "refs/heads/new_ref"; + + git_oid_fromstr(&id, current_master_tip); + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Create and write the new object id reference */ + must_pass(git_reference_create_oid(&ref, repo, new_ref, &id, 0)); + + /* Lookup the reference */ + must_pass(git_reference_lookup(&ref, repo, new_ref)); + + /* Ensure it's a loose reference */ + must_be_true(git_reference_is_packed(ref) == 0); + + /* Pack all existing references */ + must_pass(git_reference_packall(repo)); + + /* Ensure it's a packed reference */ + must_be_true(git_reference_is_packed(ref) == 1); + + /* This should pass */ + must_pass(git_reference_delete(ref)); + + close_temp_repo(repo); +END_TEST + static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname) { int error = GIT_SUCCESS; @@ -1172,6 +1203,7 @@ BEGIN_SUITE(refs) ADD_TEST(rename9); ADD_TEST(delete0); + ADD_TEST(delete1); ADD_TEST(list0); ADD_TEST(list1); -- cgit v1.2.1 From 75abd2b92452782a9e6cee6ed5041339bd00c5bf Mon Sep 17 00:00:00 2001 From: schu Date: Thu, 11 Aug 2011 19:38:13 +0200 Subject: Free all used references in the source tree Since references are not owned by the repository anymore we have to free them manually now. Signed-off-by: schu --- src/commit.c | 15 ++++++++-- src/reflog.c | 6 +++- src/repository.c | 42 +++++++++++++++++++++------ src/tag.c | 24 +++++++++++++--- src/transports/local.c | 7 +++-- tests/t04-commit.c | 2 ++ tests/t08-tag.c | 6 +++- tests/t10-refs.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/t12-repo.c | 4 +++ 9 files changed, 165 insertions(+), 18 deletions(-) diff --git a/src/commit.c b/src/commit.c index 1010fdc56..83bc9fc4c 100644 --- a/src/commit.c +++ b/src/commit.c @@ -145,8 +145,10 @@ int git_commit_create( error = git_reference_resolve(&target, head); if (error < GIT_SUCCESS) { - if (error != GIT_ENOTFOUND) + if (error != GIT_ENOTFOUND) { + git_reference_free(head); return git__rethrow(error, "Failed to create commit"); + } /* * The target of the reference was not found. This can happen * just after a repository has been initialized (the master @@ -154,10 +156,19 @@ int git_commit_create( * point to) or after an orphan checkout, so if the target * branch doesn't exist yet, create it and return. */ - return git_reference_create_oid(&head, repo, git_reference_target(head), oid, 1); + error = git_reference_create_oid(&target, repo, git_reference_target(head), oid, 1); + + git_reference_free(head); + if (error == GIT_SUCCESS) + git_reference_free(target); + + return error; } error = git_reference_set_oid(target, oid); + + git_reference_free(head); + git_reference_free(target); } if (error < GIT_SUCCESS) diff --git a/src/reflog.c b/src/reflog.c index 5fc357a0f..81e171acf 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -218,8 +218,12 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old, return git__rethrow(error, "Failed to write reflog. Cannot resolve reference `%s`", ref->name); oid = git_reference_oid(r); - if (oid == NULL) + if (oid == NULL) { + git_reference_free(r); return git__throw(GIT_ERROR, "Failed to write reflog. Cannot resolve reference `%s`", r->name); + } + + git_reference_free(r); git_oid_to_string(new, GIT_OID_HEXSZ+1, oid); diff --git a/src/repository.c b/src/repository.c index 849e1a9cf..6c75aa190 100644 --- a/src/repository.c +++ b/src/repository.c @@ -603,8 +603,14 @@ static int repo_init_reinit(const char *repository_path, int is_bare) static int repo_init_createhead(git_repository *repo) { + int error; git_reference *head_reference; - return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0); + + error = git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0); + + git_reference_free(head_reference); + + return error; } static int repo_init_structure(const char *git_dir, int is_bare) @@ -715,10 +721,15 @@ int git_repository_head_detached(git_repository *repo) if (error < GIT_SUCCESS) return error; - if (git_reference_type(ref) == GIT_REF_SYMBOLIC) + if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { + git_reference_free(ref); return 0; + } error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref)); + + git_reference_free(ref); + if (error < GIT_SUCCESS) return error; @@ -730,7 +741,7 @@ int git_repository_head_detached(git_repository *repo) int git_repository_head(git_reference **head_out, git_repository *repo) { - git_reference *ref; + git_reference *ref, *resolved_ref; int error; *head_out = NULL; @@ -739,11 +750,15 @@ int git_repository_head(git_reference **head_out, git_repository *repo) if (error < GIT_SUCCESS) return git__rethrow(GIT_ENOTAREPO, "Failed to locate the HEAD"); - error = git_reference_resolve(&ref, ref); - if (error < GIT_SUCCESS) + error = git_reference_resolve(&resolved_ref, ref); + if (error < GIT_SUCCESS) { + git_reference_free(ref); return git__rethrow(error, "Failed to resolve the HEAD"); + } - *head_out = ref; + git_reference_free(ref); + + *head_out = resolved_ref; return GIT_SUCCESS; } @@ -754,6 +769,9 @@ int git_repository_head_orphan(git_repository *repo) error = git_repository_head(&ref, repo); + if (error == GIT_SUCCESS) + git_reference_free(ref); + return error == GIT_ENOTFOUND ? 1 : error; } @@ -766,13 +784,21 @@ int git_repository_is_empty(git_repository *repo) if (error < GIT_SUCCESS) return git__throw(error, "Corrupted repository. HEAD does not exist"); - if (git_reference_type(head) != GIT_REF_SYMBOLIC) + if (git_reference_type(head) != GIT_REF_SYMBOLIC) { + git_reference_free(head); return 0; + } - if (strcmp(git_reference_target(head), "refs/heads/master") != 0) + if (strcmp(git_reference_target(head), "refs/heads/master") != 0) { + git_reference_free(head); return 0; + } error = git_reference_resolve(&branch, head); + + git_reference_free(head); + git_reference_free(branch); + return error == GIT_ENOTFOUND ? 1 : error; } diff --git a/src/tag.c b/src/tag.c index 0bdca93bb..7372e68c7 100644 --- a/src/tag.c +++ b/src/tag.c @@ -153,6 +153,8 @@ static int retrieve_tag_reference(git_reference **tag_reference_out, char *ref_n git_reference *tag_ref; int error; + *tag_reference_out = NULL; + git_path_join(ref_name_out, GIT_REFS_TAGS_DIR, tag_name); error = git_reference_lookup(&tag_ref, repo, ref_name_out); if (error < GIT_SUCCESS) @@ -224,6 +226,7 @@ static int git_tag_create__internal( break; default: + git_reference_free(new_ref); return git__rethrow(error, "Failed to create tag"); } @@ -232,6 +235,7 @@ static int git_tag_create__internal( if (new_ref != NULL) { if (!allow_ref_overwrite) { git_oid_cpy(oid, git_reference_oid(new_ref)); + git_reference_free(new_ref); return git__throw(GIT_EEXISTS, "Tag already exists"); } else { should_update_ref = 1; @@ -239,8 +243,10 @@ static int git_tag_create__internal( } if (create_tag_annotation) { - if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) + if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) { + git_reference_free(new_ref); return error; + } } else git_oid_cpy(oid, git_object_id(target)); @@ -249,6 +255,8 @@ static int git_tag_create__internal( else error = git_reference_set_oid(new_ref, oid); + git_reference_free(new_ref); + return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); } @@ -281,7 +289,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu git_odb_stream *stream; git_odb_object *target_obj; - git_reference *new_ref; + git_reference *new_ref = NULL; char ref_name[GIT_REFNAME_MAX]; assert(oid && buffer); @@ -309,6 +317,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu break; default: + git_reference_free(new_ref); return git__rethrow(error, "Failed to create tag"); } @@ -317,6 +326,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu if (new_ref != NULL) { if (!allow_ref_overwrite) { git_oid_cpy(oid, git_reference_oid(new_ref)); + git_reference_free(new_ref); return git__throw(GIT_EEXISTS, "Tag already exists"); } else { should_update_ref = 1; @@ -324,22 +334,28 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu } /* write the buffer */ - if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) + if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) { + git_reference_free(new_ref); return git__rethrow(error, "Failed to create tag"); + } stream->write(stream, buffer, strlen(buffer)); error = stream->finalize_write(oid, stream); stream->free(stream); - if (error < GIT_SUCCESS) + if (error < GIT_SUCCESS) { + git_reference_free(new_ref); return git__rethrow(error, "Failed to create tag"); + } if (!should_update_ref) error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0); else error = git_reference_set_oid(new_ref, oid); + git_reference_free(new_ref); + git_signature_free(tag.tagger); git__free(tag.tag_name); git__free(tag.message); diff --git a/src/transports/local.c b/src/transports/local.c index e09680478..058ed7e79 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -54,7 +54,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) { const char peeled[] = "^{}"; git_remote_head *head; - git_reference *ref; + git_reference *ref, *resolved_ref; git_object *obj = NULL; int error = GIT_SUCCESS, peel_len, ret; @@ -72,7 +72,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) if (error < GIT_SUCCESS) goto out; - error = git_reference_resolve(&ref, ref); + error = git_reference_resolve(&resolved_ref, ref); if (error < GIT_SUCCESS) goto out; @@ -111,6 +111,9 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) goto out; out: + git_reference_free(ref); + git_reference_free(resolved_ref); + git_object_close(obj); if (error < GIT_SUCCESS) { git__free(head->name); diff --git a/tests/t04-commit.c b/tests/t04-commit.c index 681b3fbd1..d0bb1b583 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -766,6 +766,8 @@ BEGIN_TEST(root0, "create a root commit") git__free(head_old); git_commit_close(commit); git_repository_free(repo); + + git_reference_free(head); END_TEST BEGIN_SUITE(commit) diff --git a/tests/t08-tag.c b/tests/t08-tag.c index 85ef9225e..44efb584d 100644 --- a/tests/t08-tag.c +++ b/tests/t08-tag.c @@ -197,7 +197,6 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") git_tag_close(tag); git_repository_free(repo); - END_TEST BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag") @@ -266,6 +265,7 @@ BEGIN_TEST(write3, "Replace an already existing tag") close_temp_repo(repo); + git_reference_free(ref_tag); END_TEST BEGIN_TEST(write4, "write a lightweight tag to the repository and read it again") @@ -296,6 +296,8 @@ BEGIN_TEST(write4, "write a lightweight tag to the repository and read it again" must_pass(git_tag_delete(repo, "light-tag")); git_repository_free(repo); + + git_reference_free(ref_tag); END_TEST BEGIN_TEST(write5, "Attempt to write a lightweight tag bearing the same name than an already existing tag") @@ -334,6 +336,8 @@ BEGIN_TEST(delete0, "Delete an already existing tag") must_fail(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b")); close_temp_repo(repo); + + git_reference_free(ref_tag); END_TEST BEGIN_SUITE(tag) diff --git a/tests/t10-refs.c b/tests/t10-refs.c index 298aaa07f..12632b02b 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -56,6 +56,8 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") git_object_close(object); git_repository_free(repo); + + git_reference_free(reference); END_TEST BEGIN_TEST(readtag1, "lookup a loose tag reference that doesn't exist") @@ -66,6 +68,8 @@ BEGIN_TEST(readtag1, "lookup a loose tag reference that doesn't exist") must_fail(git_reference_lookup(&reference, repo, non_existing_tag_ref_name)); git_repository_free(repo); + + git_reference_free(reference); END_TEST static const char *head_tracker_sym_ref_name = "head-tracker"; @@ -97,6 +101,9 @@ BEGIN_TEST(readsym0, "lookup a symbolic reference") git_object_close(object); git_repository_free(repo); + + git_reference_free(reference); + git_reference_free(resolved_ref); END_TEST BEGIN_TEST(readsym1, "lookup a nested symbolic reference") @@ -124,6 +131,9 @@ BEGIN_TEST(readsym1, "lookup a nested symbolic reference") git_object_close(object); git_repository_free(repo); + + git_reference_free(reference); + git_reference_free(resolved_ref); END_TEST BEGIN_TEST(readsym2, "lookup the HEAD and resolve the master branch") @@ -145,6 +155,10 @@ BEGIN_TEST(readsym2, "lookup the HEAD and resolve the master branch") must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); git_repository_free(repo); + + git_reference_free(reference); + git_reference_free(resolved_ref); + git_reference_free(comp_base_ref); END_TEST BEGIN_TEST(readsym3, "lookup the master branch and then the HEAD") @@ -160,6 +174,10 @@ BEGIN_TEST(readsym3, "lookup the master branch and then the HEAD") must_pass(git_oid_cmp(git_reference_oid(master_ref), git_reference_oid(resolved_ref))); git_repository_free(repo); + + git_reference_free(reference); + git_reference_free(resolved_ref); + git_reference_free(master_ref); END_TEST static const char *packed_head_name = "refs/heads/packed"; @@ -183,6 +201,8 @@ BEGIN_TEST(readpacked0, "lookup a packed reference") git_object_close(object); git_repository_free(repo); + + git_reference_free(reference); END_TEST BEGIN_TEST(readpacked1, "assure that a loose reference is looked up before a packed reference") @@ -197,6 +217,8 @@ BEGIN_TEST(readpacked1, "assure that a loose reference is looked up before a pac must_be_true(strcmp(reference->name, packed_test_head_name) == 0); git_repository_free(repo); + + git_reference_free(reference); END_TEST BEGIN_TEST(create0, "create a new symbolic reference") @@ -240,6 +262,10 @@ BEGIN_TEST(create0, "create a new symbolic reference") must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); close_temp_repo(repo2); + + git_reference_free(new_reference); + git_reference_free(looked_up_ref); + git_reference_free(resolved_ref); END_TEST BEGIN_TEST(create1, "create a deep symbolic reference") @@ -261,6 +287,10 @@ BEGIN_TEST(create1, "create a deep symbolic reference") must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); close_temp_repo(repo); + + git_reference_free(new_reference); + git_reference_free(looked_up_ref); + git_reference_free(resolved_ref); END_TEST BEGIN_TEST(create2, "create a new OID reference") @@ -299,6 +329,9 @@ BEGIN_TEST(create2, "create a new OID reference") must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); close_temp_repo(repo2); + + git_reference_free(new_reference); + git_reference_free(looked_up_ref); END_TEST BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id") @@ -349,6 +382,9 @@ BEGIN_TEST(overwrite0, "Overwrite an existing symbolic reference") must_be_true(!strcmp(git_reference_target(ref), ref_master_name)); close_temp_repo(repo); + + git_reference_free(ref); + git_reference_free(branch_ref); END_TEST BEGIN_TEST(overwrite1, "Overwrite an existing object id reference") @@ -378,6 +414,8 @@ BEGIN_TEST(overwrite1, "Overwrite an existing object id reference") must_be_true(!git_oid_cmp(&id, git_reference_oid(ref))); close_temp_repo(repo); + + git_reference_free(ref); END_TEST BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symbolic one") @@ -401,6 +439,8 @@ BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symboli must_be_true(!strcmp(git_reference_target(ref), ref_master_name)); close_temp_repo(repo); + + git_reference_free(ref); END_TEST BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object id one") @@ -426,6 +466,8 @@ BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object must_be_true(!git_oid_cmp(git_reference_oid(ref), &id)); close_temp_repo(repo); + + git_reference_free(ref); END_TEST BEGIN_TEST(pack0, "create a packfile for an empty folder") @@ -475,6 +517,8 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") must_pass(!git_futils_exists(temp_path)); close_temp_repo(repo); + + git_reference_free(reference); END_TEST BEGIN_TEST(rename0, "rename a loose reference") @@ -515,6 +559,9 @@ BEGIN_TEST(rename0, "rename a loose reference") must_pass(git_futils_exists(temp_path)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); + git_reference_free(another_looked_up_ref); END_TEST BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") @@ -555,6 +602,9 @@ BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") must_pass(git_futils_exists(temp_path)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); + git_reference_free(another_looked_up_ref); END_TEST BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference which happens to be in both loose and pack state") @@ -594,6 +644,9 @@ BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference must_pass(git_futils_exists(temp_path)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); + git_reference_free(another_looked_up_ref); END_TEST BEGIN_TEST(rename3, "can not rename a reference with the name of an existing reference") @@ -613,6 +666,8 @@ BEGIN_TEST(rename3, "can not rename a reference with the name of an existing ref must_be_true(!strcmp(looked_up_ref->name, packed_head_name)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); END_TEST BEGIN_TEST(rename4, "can not rename a reference with an invalid name") @@ -635,6 +690,8 @@ BEGIN_TEST(rename4, "can not rename a reference with an invalid name") must_be_true(!strcmp(looked_up_ref->name, packed_test_head_name)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); END_TEST BEGIN_TEST(rename5, "can force-rename a packed reference with the name of an existing loose and packed reference") @@ -660,6 +717,8 @@ BEGIN_TEST(rename5, "can force-rename a packed reference with the name of an exi must_fail(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); close_temp_repo(repo); + + git_reference_free(looked_up_ref); END_TEST BEGIN_TEST(rename6, "can force-rename a loose reference with the name of an existing loose reference") @@ -685,6 +744,8 @@ BEGIN_TEST(rename6, "can force-rename a loose reference with the name of an exis must_fail(git_reference_lookup(&looked_up_ref, repo, "refs/heads/br2")); close_temp_repo(repo); + + git_reference_free(looked_up_ref); END_TEST static const char *ref_one_name = "refs/heads/one/branch"; @@ -717,6 +778,11 @@ BEGIN_TEST(rename7, "can not overwrite name of existing reference") must_fail(git_reference_lookup(&ref_one_new, repo, ref_one_name_new)); close_temp_repo(repo); + + git_reference_free(ref); + git_reference_free(ref_one); + git_reference_free(ref_one_new); + git_reference_free(ref_two); END_TEST static const char *ref_two_name_new = "refs/heads/two/two"; @@ -748,6 +814,10 @@ BEGIN_TEST(rename8, "can be renamed to a new name prefixed with the old name") must_fail(git_reference_lookup(&looked_up_ref, repo, ref_two_name)); close_temp_repo(repo); + + git_reference_free(ref); + git_reference_free(ref_two); + git_reference_free(looked_up_ref); END_TEST BEGIN_TEST(rename9, "can move a reference to a upper reference hierarchy") @@ -806,6 +876,8 @@ BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove must_pass(!git_futils_exists(temp_path)); close_temp_repo(repo); + + git_reference_free(another_looked_up_ref); END_TEST BEGIN_TEST(delete1, "can delete a just packed reference") @@ -1132,6 +1204,9 @@ BEGIN_TEST(reflog0, "write a reflog for a given reference and ensure it can be r git_signature_free(committer); git_reflog_free(reflog); close_temp_repo(repo2); + + git_reference_free(ref); + git_reference_free(lookedup_ref); END_TEST BEGIN_TEST(reflog1, "avoid writing an obviously wrong reflog") @@ -1160,6 +1235,8 @@ BEGIN_TEST(reflog1, "avoid writing an obviously wrong reflog") git_signature_free(committer); close_temp_repo(repo); + + git_reference_free(ref); END_TEST BEGIN_SUITE(refs) diff --git a/tests/t12-repo.c b/tests/t12-repo.c index 6197cdd00..47dc852f3 100644 --- a/tests/t12-repo.c +++ b/tests/t12-repo.c @@ -286,6 +286,8 @@ BEGIN_TEST(detached0, "test if HEAD is detached") must_be_true(git_repository_head_detached(repo) == 0); git_repository_free(repo); + + git_reference_free(ref); END_TEST BEGIN_TEST(orphan0, "test if HEAD is orphan") @@ -305,6 +307,8 @@ BEGIN_TEST(orphan0, "test if HEAD is orphan") must_be_true(git_repository_head_orphan(repo) == 0); git_repository_free(repo); + + git_reference_free(ref); END_TEST #define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git" -- cgit v1.2.1 From 549bbd1342499c2659388a483f1a266dfcedab85 Mon Sep 17 00:00:00 2001 From: schu Date: Sat, 13 Aug 2011 18:14:39 +0200 Subject: git_reference_rename: cleanup reference renaming git_reference_rename() didn't properly cleanup old references given by the user to not break some ugly old tests. Since references don't point to libgit's internal cache anymore we can cleanup git_reference_rename() to be somewhat less messy. Signed-off-by: schu --- src/refs.c | 72 ++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/src/refs.c b/src/refs.c index 1c33f73b2..43fea2230 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1420,15 +1420,12 @@ int git_reference_set_target(git_reference *ref_in, const char *target) int git_reference_rename(git_reference *ref_in, const char *new_name, int force) { int error; - char *old_name = NULL; char aux_path[GIT_PATH_MAX]; char normalized[GIT_REFNAME_MAX]; - const char *target_ref = NULL; const char *head_target = NULL; - const git_oid *target_oid = NULL; - reference *ref = NULL, *new_ref = NULL, *head = NULL; + reference *ref = NULL, *new_ref = NULL, *head = NULL, *tmp_ref = NULL; assert(ref_in); @@ -1467,36 +1464,32 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) * the new reference, e.g. when renaming foo/bar -> foo. */ - old_name = git__strdup(ref->name); + if (ref->type & GIT_REF_SYMBOLIC) + tmp_ref = git__malloc(sizeof(reference_symbolic)); + else + tmp_ref = git__malloc(sizeof(reference_oid)); - if (ref->type & GIT_REF_SYMBOLIC) { - if ((target_ref = ref_target(ref)) == NULL) - goto cleanup; - } else { - if ((target_oid = ref_oid(ref)) == NULL) - goto cleanup; - } + if (tmp_ref == NULL) + return GIT_ENOMEM; + + tmp_ref->name = git__strdup(ref->name); + tmp_ref->type = ref->type; + tmp_ref->owner = ref->owner; + + if (ref->type & GIT_REF_SYMBOLIC) + ((reference_symbolic *)tmp_ref)->target = git__strdup(((reference_symbolic *)ref)->target); + else + ((reference_oid *)tmp_ref)->oid = ((reference_oid *)ref)->oid; /* * Now delete the old ref and remove an possibly existing directory * named `new_name`. */ - if (ref->type & GIT_REF_PACKED) { - ref->type &= ~GIT_REF_PACKED; - - git_hashtable_remove(ref->owner->references.packfile, old_name); - if ((error = packed_write(ref->owner)) < GIT_SUCCESS) - goto rollback; - } else { - git_path_join(aux_path, ref->owner->path_repository, old_name); - if ((error = p_unlink(aux_path)) < GIT_SUCCESS) - goto cleanup; - - git_hashtable_remove(ref->owner->references.loose_cache, old_name); - } + if ((error = reference_delete(ref)) < GIT_SUCCESS) + goto cleanup; - git_path_join(aux_path, ref->owner->path_repository, new_name); + git_path_join(aux_path, tmp_ref->owner->path_repository, new_name); if (git_futils_exists(aux_path) == GIT_SUCCESS) { if (git_futils_isdir(aux_path) == GIT_SUCCESS) { if ((error = git_futils_rmdir_r(aux_path, 0)) < GIT_SUCCESS) @@ -1521,7 +1514,7 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) * */ - git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", old_name); + git_path_join_n(aux_path, 3, tmp_ref->owner->path_repository, "logs", tmp_ref->name); if (git_futils_isfile(aux_path) == GIT_SUCCESS) { if ((error = p_unlink(aux_path)) < GIT_SUCCESS) goto rollback; @@ -1530,11 +1523,11 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) /* * Finally we can create the new reference. */ - if (ref->type & GIT_REF_SYMBOLIC) { - if ((error = reference_create_symbolic(&new_ref, ref->owner, new_name, target_ref, 0)) < GIT_SUCCESS) + if (tmp_ref->type & GIT_REF_SYMBOLIC) { + if ((error = reference_create_symbolic(&new_ref, tmp_ref->owner, new_name, ((reference_symbolic *)tmp_ref)->target, 0)) < GIT_SUCCESS) goto rollback; } else { - if ((error = reference_create_oid(&new_ref, ref->owner, new_name, target_oid, 0)) < GIT_SUCCESS) + if ((error = reference_create_oid(&new_ref, tmp_ref->owner, new_name, &((reference_oid *)tmp_ref)->oid, 0)) < GIT_SUCCESS) goto rollback; } @@ -1544,7 +1537,7 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) git__free(ref_in->name); ref_in->name = git__strdup(new_ref->name); - if ((error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref)) < GIT_SUCCESS) + if ((error = git_hashtable_insert(new_ref->owner->references.loose_cache, new_ref->name, new_ref)) < GIT_SUCCESS) goto rollback; /* @@ -1556,12 +1549,12 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) head_target = ref_target(head); - if (head_target && !strcmp(head_target, old_name)) + if (head_target && !strcmp(head_target, tmp_ref->name)) if ((error = reference_create_symbolic(&head, new_ref->owner, "HEAD", new_ref->name, 1)) < GIT_SUCCESS) goto rollback; cleanup: - git__free(old_name); + reference_free(tmp_ref); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference"); rollback: @@ -1569,13 +1562,18 @@ rollback: * Try to create the old reference again. */ if (ref->type & GIT_REF_SYMBOLIC) - error = reference_create_symbolic(&new_ref, ref->owner, old_name, target_ref, 0); + error = reference_create_symbolic(&new_ref, tmp_ref->owner, tmp_ref->name, ((reference_symbolic *)tmp_ref)->target, 0); else - error = reference_create_oid(&new_ref, ref->owner, old_name, target_oid, 0); + error = reference_create_oid(&new_ref, ref->owner, tmp_ref->name, &((reference_oid *)tmp_ref)->oid, 0); + + git__free(ref_in->name); + ref_in->name = git__strdup(tmp_ref->name); - ref_in->name = old_name; + reference_free(tmp_ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference. Failed to rollback"); + return error == GIT_SUCCESS ? + git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") : + git__rethrow(error, "Failed to rename reference. Failed to rollback"); } /* -- cgit v1.2.1 From d4a0b124d00c70933d7c6ac9065c401cc2d70b2e Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 30 Oct 2011 21:58:33 -0700 Subject: refs: Partial rewrite for read-only refs This new version of the references code is significantly faster and hopefully easier to read. External API stays the same. A new method `git_reference_reload()` has been added to force updating a memory reference from disk. In-memory references are no longer updated automagically -- this was killing us. If a reference is deleted externally and the user doesn't reload the memory object, nothing critical happens: any functions using that reference should fail gracefully (e.g. deletion, renaming, and so on). All generated references from the API are read only and must be free'd by the user. There is no reference counting and no traces of generated references are kept in the library. There is no longer an internal representation for references. There is only one reference struct `git_reference`, and symbolic/oid targets are stored inside an union. Packfile references are stored using an optimized struct with flex array for reference names. This should significantly reduce the memory cost of loading the packfile from disk. --- include/git2/refs.h | 43 +- src/refs.c | 1454 ++++++++++++++++++++++----------------------------- src/refs.h | 10 +- src/repository.c | 7 +- tests/t10-refs.c | 14 +- 5 files changed, 671 insertions(+), 857 deletions(-) diff --git a/include/git2/refs.h b/include/git2/refs.h index 773ae445c..82c5d8881 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -116,8 +116,13 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref); * Thie method iteratively peels a symbolic reference * until it resolves to a direct reference to an OID. * + * The peeled reference is returned in the `resolved_ref` + * argument, and must be freed manually once it's no longer + * needed. + * * If a direct reference is passed as an argument, - * that reference is returned immediately + * a copy of that reference is returned. This copy must + * be manually freed too. * * @param resolved_ref Pointer to the peeled reference * @param ref The reference @@ -170,11 +175,19 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); * The new name will be checked for validity and may be * modified into a normalized form. * - * The given git_reference will be updated. + * The given git_reference will be updated in place. * * The reference will be immediately renamed in-memory * and on disk. * + * If the `force` flag is not enabled, and there's already + * a reference with the given name, the renaming will fail. + * + * @param ref The reference to rename + * @param new_name The new name for the reference + * @param force Overwrite an existing reference + * @return GIT_SUCCESS or an error code + * */ GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name, int force); @@ -186,6 +199,8 @@ GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name, i * The reference will be immediately removed on disk and from * memory. The given reference pointer will no longer be valid. * + * @param ref The reference to remove + * @return GIT_SUCCESS or an error code */ GIT_EXTERN(int) git_reference_delete(git_reference *ref); @@ -250,13 +265,33 @@ GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, GIT_EXTERN(int) git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload); /** - * Check if a reference is packed + * Check if a reference has been loaded from a packfile * - * @param ref git_reference + * @param ref A git reference * @return 0 in case it's not packed; 1 otherwise */ GIT_EXTERN(int) git_reference_is_packed(git_reference *ref); +/** + * Reload a reference from disk + * + * Reference pointers may become outdated if the Git + * repository is accessed simultaneously by other clients + * whilt the library is open. + * + * This method forces a reload of the reference from disk, + * to ensure that the provided information is still + * reliable. + * + * If the reload fails (e.g. the reference no longer exists + * on disk, or has become corrupted), an error code will be + * returned and the reference pointer will be invalidated. + * + * @param ref The reference to reload + * @return GIT_SUCCESS on success, or an error code + */ +GIT_EXTERN(int) git_reference_reload(git_reference *ref); + /** * Free the given reference * diff --git a/src/refs.c b/src/refs.c index 43fea2230..563406660 100644 --- a/src/refs.c +++ b/src/refs.c @@ -16,23 +16,17 @@ #define MAX_NESTING_LEVEL 5 -typedef struct { - git_repository *owner; - char *name; - unsigned int type; - time_t mtime; -} reference; - -typedef struct { - reference ref; - git_oid oid; - git_oid peel_target; -} reference_oid; +enum { + GIT_PACKREF_HAS_PEEL = 1, + GIT_PACKREF_WAS_LOOSE = 2 +}; -typedef struct { - reference ref; - char *target; -} reference_symbolic; +struct packref { + git_oid oid; + git_oid peel; + char flags; + char name[GIT_FLEX_ARRAY]; +}; static const int default_table_size = 32; @@ -47,106 +41,83 @@ static uint32_t reftable_hash(const void *key, int hash_id) return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]); } -static void reference_free(reference *reference); -static int reference_create(reference **ref_out, git_repository *repo, const char *name, git_rtype type); -static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated); - -static int reference_set_target(reference *ref, const char *target); -static int reference_set_oid(reference *ref, const git_oid *oid); - -static int reference_delete(reference *ref); +static int reference_read( + git_fbuffer *file_content, + time_t *mtime, + const char *repo_path, + const char *ref_name, + int *updated); /* loose refs */ -static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content); -static int loose_parse_oid(reference *ref, git_fbuffer *file_content); -static int loose_lookup(reference **ref_out, git_repository *repo, const char *name, int skip_symbolic); -static int loose_write(reference *ref); -static int loose_update(reference *ref); +static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content); +static int loose_parse_oid(git_oid *ref, git_fbuffer *file_content); +static int loose_lookup(git_reference *ref); +static int loose_lookup_to_packfile(struct packref **ref_out, + git_repository *repo, const char *name); +static int loose_write(git_reference *ref); /* packed refs */ -static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end); -static int packed_parse_oid(reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end); +static int packed_parse_peel(struct packref *tag_ref, + const char **buffer_out, const char *buffer_end); +static int packed_parse_oid(struct packref **ref_out, + const char **buffer_out, const char *buffer_end); static int packed_load(git_repository *repo); static int packed_loadloose(git_repository *repository); -static int packed_write_ref(reference_oid *ref, git_filebuf *file); -static int packed_find_peel(reference_oid *ref); +static int packed_write_ref(struct packref *ref, git_filebuf *file); +static int packed_find_peel(git_repository *repo, struct packref *ref); static int packed_remove_loose(git_repository *repo, git_vector *packing_list); static int packed_sort(const void *a, const void *b); +static int packed_lookup(git_reference *ref); static int packed_write(git_repository *repo); /* internal helpers */ -static int reference_available(git_repository *repo, const char *ref, const char *old_ref); -static int reference_lookup(reference **out, git_repository *repo, const char *name); +static int reference_available(git_repository *repo, + const char *ref, const char *old_ref); +static int reference_delete(git_reference *ref); +static int reference_lookup(git_reference *ref); /* name normalization */ -static int check_valid_ref_char(char ch); -static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref); - -/* reference transition */ -static git_reference * reference_create_external(reference *ref); -static reference * reference_get_internal(git_reference *ref); - +static int normalize_name(char *buffer_out, size_t out_size, + const char *name, int is_oid_ref); -static void reference_free(reference *reference) +void git_reference_free(git_reference *reference) { if (reference == NULL) return; - if (reference->name) - git__free(reference->name); + git__free(reference->name); - if (reference->type == GIT_REF_SYMBOLIC) - git__free(((reference_symbolic *)reference)->target); + if (reference->flags & GIT_REF_SYMBOLIC) + git__free(reference->target.symbolic); git__free(reference); } static int reference_create( - reference **ref_out, + git_reference **ref_out, git_repository *repo, - const char *name, - git_rtype type) + const char *name) { - char normalized[GIT_REFNAME_MAX]; - int error = GIT_SUCCESS, size; - reference *reference = NULL; + git_reference *reference = NULL; assert(ref_out && repo && name); - if (type == GIT_REF_SYMBOLIC) - size = sizeof(reference_symbolic); - else if (type == GIT_REF_OID) - size = sizeof(reference_oid); - else - return git__throw(GIT_EINVALIDARGS, - "Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier"); - - reference = git__malloc(size); + reference = git__malloc(sizeof(git_reference)); if (reference == NULL) return GIT_ENOMEM; - memset(reference, 0x0, size); + memset(reference, 0x0, sizeof(git_reference)); reference->owner = repo; - reference->type = type; - - error = normalize_name(normalized, sizeof(normalized), name, (type & GIT_REF_OID)); - if (error < GIT_SUCCESS) - goto cleanup; - reference->name = git__strdup(normalized); + reference->name = git__strdup(name); if (reference->name == NULL) { - error = GIT_ENOMEM; - goto cleanup; + free(reference); + return GIT_ENOMEM; } *ref_out = reference; - - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference"); - -cleanup: - reference_free(reference); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference"); + return GIT_SUCCESS; } static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated) @@ -161,87 +132,13 @@ static int reference_read(git_fbuffer *file_content, time_t *mtime, const char * return git_futils_readbuffer_updated(file_content, path, mtime, updated); } -static git_reference * reference_create_external(reference *ref) -{ - size_t size = sizeof(git_reference); - git_reference *out; - - out = git__malloc(size); - if (out == NULL) - return NULL; - - memset(out, 0x0, size); - - out->owner = ref->owner; - - out->name = git__strdup(ref->name); - if (out->name == NULL) { - git__free(out); - return NULL; - } - - return out; -} - -static reference * reference_get_internal(git_reference *ref) -{ - reference *out = NULL; - - reference_lookup(&out, ref->owner, ref->name); - - return out; -} - -static int loose_update(reference *ref) -{ - int error, updated; - git_fbuffer ref_file = GIT_FBUFFER_INIT; - - if (ref->type & GIT_REF_PACKED) - return packed_load(ref->owner); - - -/* error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name); - if (error < GIT_SUCCESS) - goto cleanup; - - if (ref_time == ref->mtime) - return GIT_SUCCESS; -*/ - error = reference_read(&ref_file, &ref->mtime, ref->owner->path_repository, ref->name, &updated); - if (error < GIT_SUCCESS) - goto cleanup; - - if (!updated) - goto cleanup; - - if (ref->type == GIT_REF_SYMBOLIC) - error = loose_parse_symbolic(ref, &ref_file); - else if (ref->type == GIT_REF_OID) - error = loose_parse_oid(ref, &ref_file); - else - error = git__throw(GIT_EOBJCORRUPTED, - "Invalid reference type (%d) for loose reference", ref->type); - -cleanup: - git_futils_freebuffer(&ref_file); - if (error != GIT_SUCCESS) { - reference_free(ref); - git_hashtable_remove(ref->owner->references.loose_cache, ref->name); - } - - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to update loose reference"); -} - -static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content) +static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content) { const unsigned int header_len = strlen(GIT_SYMREF); const char *refname_start; char *eol; - reference_symbolic *ref_sym; refname_start = (const char *)file_content->data; - ref_sym = (reference_symbolic *)ref; if (file_content->len < (header_len + 1)) return git__throw(GIT_EOBJCORRUPTED, @@ -254,13 +151,12 @@ static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content) refname_start += header_len; - git__free(ref_sym->target); - ref_sym->target = git__strdup(refname_start); - if (ref_sym->target == NULL) + ref->target.symbolic = git__strdup(refname_start); + if (ref->target.symbolic == NULL) return GIT_ENOMEM; /* remove newline at the end of file */ - eol = strchr(ref_sym->target, '\n'); + eol = strchr(ref->target.symbolic, '\n'); if (eol == NULL) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse loose reference. Missing EOL"); @@ -272,21 +168,19 @@ static int loose_parse_symbolic(reference *ref, git_fbuffer *file_content) return GIT_SUCCESS; } -static int loose_parse_oid(reference *ref, git_fbuffer *file_content) +static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content) { int error; - reference_oid *ref_oid; char *buffer; buffer = (char *)file_content->data; - ref_oid = (reference_oid *)ref; /* File format: 40 chars (OID) + newline */ if (file_content->len < GIT_OID_HEXSZ + 1) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse loose reference. Reference too short"); - if ((error = git_oid_fromstr(&ref_oid->oid, buffer)) < GIT_SUCCESS) + if ((error = git_oid_fromstr(oid, buffer)) < GIT_SUCCESS) return git__rethrow(GIT_EOBJCORRUPTED, "Failed to parse loose reference."); buffer = buffer + GIT_OID_HEXSZ; @@ -300,7 +194,6 @@ static int loose_parse_oid(reference *ref, git_fbuffer *file_content) return GIT_SUCCESS; } - static git_rtype loose_guess_rtype(const char *full_path) { git_fbuffer ref_file = GIT_FBUFFER_INIT; @@ -319,55 +212,78 @@ static git_rtype loose_guess_rtype(const char *full_path) return type; } -static int loose_lookup( - reference **ref_out, +static int loose_lookup(git_reference *ref) +{ + int error = GIT_SUCCESS, updated; + git_fbuffer ref_file = GIT_FBUFFER_INIT; + + if (reference_read(&ref_file, &ref->mtime, + ref->owner->path_repository, ref->name, &updated) < GIT_SUCCESS) + return git__throw(GIT_ENOTFOUND, "Failed to lookup loose reference"); + + if (!updated) + return GIT_SUCCESS; + + if (ref->flags & GIT_REF_SYMBOLIC) + free(ref->target.symbolic); + + ref->flags = 0; + + if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) { + ref->flags |= GIT_REF_SYMBOLIC; + error = loose_parse_symbolic(ref, &ref_file); + } else { + ref->flags |= GIT_REF_OID; + error = loose_parse_oid(&ref->target.oid, &ref_file); + } + + git_futils_freebuffer(&ref_file); + + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to lookup loose reference"); + + return GIT_SUCCESS; +} + +static int loose_lookup_to_packfile( + struct packref **ref_out, git_repository *repo, - const char *name, - int skip_symbolic) + const char *name) { int error = GIT_SUCCESS; git_fbuffer ref_file = GIT_FBUFFER_INIT; - reference *ref = NULL; - time_t ref_time = 0; + struct packref *ref = NULL; + size_t name_len; *ref_out = NULL; - error = reference_read(&ref_file, &ref_time, repo->path_repository, name, NULL); + error = reference_read(&ref_file, NULL, repo->path_repository, name, NULL); if (error < GIT_SUCCESS) goto cleanup; - if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) { - if (skip_symbolic) - return GIT_SUCCESS; - - error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC); - if (error < GIT_SUCCESS) - goto cleanup; - - error = loose_parse_symbolic(ref, &ref_file); - } else { - error = reference_create(&ref, repo, name, GIT_REF_OID); - if (error < GIT_SUCCESS) - goto cleanup; + name_len = strlen(name); + ref = git__malloc(sizeof(struct packref) + name_len + 1); - error = loose_parse_oid(ref, &ref_file); - } + memcpy(ref->name, name, name_len); + ref->name[name_len] = 0; + error = loose_parse_oid(&ref->oid, &ref_file); if (error < GIT_SUCCESS) goto cleanup; - ref->mtime = ref_time; + ref->flags = GIT_PACKREF_WAS_LOOSE; + *ref_out = ref; git_futils_freebuffer(&ref_file); return GIT_SUCCESS; cleanup: git_futils_freebuffer(&ref_file); - reference_free(ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to lookup loose reference"); + free(ref); + return git__rethrow(error, "Failed to lookup loose reference"); } -static int loose_write(reference *ref) +static int loose_write(git_reference *ref) { git_filebuf file; char ref_path[GIT_PATH_MAX]; @@ -379,40 +295,36 @@ static int loose_write(reference *ref) if ((error = git_filebuf_open(&file, ref_path, GIT_FILEBUF_FORCE)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write loose reference"); - if (ref->type & GIT_REF_OID) { - reference_oid *ref_oid = (reference_oid *)ref; + if (ref->flags & GIT_REF_OID) { char oid[GIT_OID_HEXSZ + 1]; - memset(oid, 0x0, sizeof(oid)); + git_oid_fmt(oid, &ref->target.oid); + oid[GIT_OID_HEXSZ] = '\0'; - git_oid_fmt(oid, &ref_oid->oid); error = git_filebuf_printf(&file, "%s\n", oid); if (error < GIT_SUCCESS) goto unlock; - } else if (ref->type & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */ - reference_symbolic *ref_sym = (reference_symbolic *)ref; - - error = git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref_sym->target); + } else if (ref->flags & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */ + error = git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic); } else { - error = git__throw(GIT_EOBJCORRUPTED, "Failed to write reference. Invalid reference type"); + error = git__throw(GIT_EOBJCORRUPTED, + "Failed to write reference. Invalid reference type"); goto unlock; } - error = git_filebuf_commit(&file, GIT_REFS_FILE_MODE); - if (p_stat(ref_path, &st) == GIT_SUCCESS) ref->mtime = st.st_mtime; - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write loose reference"); + return git_filebuf_commit(&file, GIT_REFS_FILE_MODE); unlock: git_filebuf_cleanup(&file); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write loose reference"); + return git__rethrow(error, "Failed to write loose reference"); } static int packed_parse_peel( - reference_oid *tag_ref, + struct packref *tag_ref, const char **buffer_out, const char *buffer_end) { @@ -422,47 +334,48 @@ static int packed_parse_peel( /* Ensure it's not the first entry of the file */ if (tag_ref == NULL) - return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Reference is the first entry of the file"); + return git__throw(GIT_EPACKEDREFSCORRUPTED, + "Failed to parse packed reference. " + "Reference is the first entry of the file"); /* Ensure reference is a tag */ - if (git__prefixcmp(tag_ref->ref.name, GIT_REFS_TAGS_DIR) != 0) - return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Reference is not a tag"); + if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0) + return git__throw(GIT_EPACKEDREFSCORRUPTED, + "Failed to parse packed reference. Reference is not a tag"); if (buffer + GIT_OID_HEXSZ >= buffer_end) - return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Buffer too small"); + return git__throw(GIT_EPACKEDREFSCORRUPTED, + "Failed to parse packed reference. Buffer too small"); /* Is this a valid object id? */ - if (git_oid_fromstr(&tag_ref->peel_target, buffer) < GIT_SUCCESS) - return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Not a valid object ID"); + if (git_oid_fromstr(&tag_ref->peel, buffer) < GIT_SUCCESS) + return git__throw(GIT_EPACKEDREFSCORRUPTED, + "Failed to parse packed reference. Not a valid object ID"); buffer = buffer + GIT_OID_HEXSZ; if (*buffer == '\r') buffer++; if (*buffer != '\n') - return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Buffer not terminated correctly"); + return git__throw(GIT_EPACKEDREFSCORRUPTED, + "Failed to parse packed reference. Buffer not terminated correctly"); *buffer_out = buffer + 1; - tag_ref->ref.type |= GIT_REF_HAS_PEEL; - return GIT_SUCCESS; } static int packed_parse_oid( - reference_oid **ref_out, - git_repository *repo, + struct packref **ref_out, const char **buffer_out, const char *buffer_end) { - git_reference *_ref = NULL; - reference_oid *ref = NULL; + struct packref *ref = NULL; const char *buffer = *buffer_out; const char *refname_begin, *refname_end; int error = GIT_SUCCESS; - int refname_len; - char refname[GIT_REFNAME_MAX]; + size_t refname_len; git_oid id; refname_begin = (buffer + GIT_OID_HEXSZ + 1); @@ -482,22 +395,19 @@ static int packed_parse_oid( goto cleanup; } - refname_len = refname_end - refname_begin; + if (refname_end[-1] == '\r') + refname_end--; - memcpy(refname, refname_begin, refname_len); - refname[refname_len] = 0; - - if (refname[refname_len - 1] == '\r') - refname[refname_len - 1] = 0; + refname_len = refname_end - refname_begin; - error = reference_create((reference **)&_ref, repo, refname, GIT_REF_OID); - if (error < GIT_SUCCESS) - goto cleanup; + ref = git__malloc(sizeof(struct packref) + refname_len + 1); - ref = (reference_oid *)_ref; + memcpy(ref->name, refname_begin, refname_len); + ref->name[refname_len] = 0; git_oid_cpy(&ref->oid, &id); - ref->ref.type |= GIT_REF_PACKED; + + ref->flags = 0; *ref_out = ref; *buffer_out = refname_end + 1; @@ -505,8 +415,8 @@ static int packed_parse_oid( return GIT_SUCCESS; cleanup: - reference_free((reference *)ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse OID of packed reference"); + free(ref); + return git__rethrow(error, "Failed to parse OID of packed reference"); } static int packed_load(git_repository *repo) @@ -521,7 +431,7 @@ static int packed_load(git_repository *repo) ref_cache->packfile = git_hashtable_alloc( default_table_size, reftable_hash, - (git_hash_keyeq_ptr)(&git__strcmp_cb)); + (git_hash_keyeq_ptr)&git__strcmp_cb); if (ref_cache->packfile == NULL) { error = GIT_ENOMEM; @@ -530,7 +440,7 @@ static int packed_load(git_repository *repo) } error = reference_read(&packfile, &ref_cache->packfile_time, - repo->path_repository, GIT_PACKEDREFS_FILE, &updated); + repo->path_repository, GIT_PACKEDREFS_FILE, &updated); /* * If we couldn't find the file, we need to clear the table and @@ -568,9 +478,9 @@ static int packed_load(git_repository *repo) } while (buffer_start < buffer_end) { - reference_oid *ref = NULL; + struct packref *ref = NULL; - error = packed_parse_oid(&ref, repo, &buffer_start, buffer_end); + error = packed_parse_oid(&ref, &buffer_start, buffer_end); if (error < GIT_SUCCESS) goto cleanup; @@ -580,9 +490,9 @@ static int packed_load(git_repository *repo) goto cleanup; } - error = git_hashtable_insert(ref_cache->packfile, ref->ref.name, ref); + error = git_hashtable_insert(ref_cache->packfile, ref->name, ref); if (error < GIT_SUCCESS) { - reference_free((reference *)ref); + free(ref); goto cleanup; } } @@ -594,7 +504,7 @@ cleanup: git_hashtable_free(ref_cache->packfile); ref_cache->packfile = NULL; git_futils_freebuffer(&packfile); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to load packed references"); + return git__rethrow(error, "Failed to load packed references"); } @@ -613,7 +523,8 @@ static int _dirent_loose_listall(void *_data, char *full_path) char *file_path = full_path + data->repo_path_len; if (git_futils_isdir(full_path) == GIT_SUCCESS) - return git_futils_direach(full_path, GIT_PATH_MAX, _dirent_loose_listall, _data); + return git_futils_direach(full_path, GIT_PATH_MAX, + _dirent_loose_listall, _data); /* do not add twice a reference that exists already in the packfile */ if ((data->list_flags & GIT_REF_PACKED) != 0 && @@ -632,28 +543,34 @@ static int _dirent_loose_load(void *data, char *full_path) { git_repository *repository = (git_repository *)data; void *old_ref = NULL; - reference *ref; + struct packref *ref; char *file_path; int error; if (git_futils_isdir(full_path) == GIT_SUCCESS) - return git_futils_direach(full_path, GIT_PATH_MAX, _dirent_loose_load, repository); + return git_futils_direach( + full_path, GIT_PATH_MAX, + _dirent_loose_load, repository); file_path = full_path + strlen(repository->path_repository); - error = loose_lookup(&ref, repository, file_path, 1); - if (error == GIT_SUCCESS && ref != NULL) { - ref->type |= GIT_REF_PACKED; + error = loose_lookup_to_packfile(&ref, repository, file_path); + + if (error == GIT_SUCCESS) { - if (git_hashtable_insert2(repository->references.packfile, ref->name, ref, &old_ref) < GIT_SUCCESS) { - reference_free(ref); + if (git_hashtable_insert2( + repository->references.packfile, + ref->name, ref, &old_ref) < GIT_SUCCESS) { + free(ref); return GIT_ENOMEM; } if (old_ref != NULL) - reference_free((reference *)old_ref); + free(old_ref); } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to load loose dirent"); + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to load loose references into packfile"); } /* @@ -671,30 +588,20 @@ static int packed_loadloose(git_repository *repository) git_path_join(refs_path, repository->path_repository, GIT_REFS_DIR); - /* Remove any loose references from the cache */ - { - const void *GIT_UNUSED(_unused); - reference *reference; - - GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference, - reference_free(reference); - ); - } - - git_hashtable_clear(repository->references.loose_cache); - /* * Load all the loose files from disk into the Packfile table. * This will overwrite any old packed entries with their * updated loose versions */ - return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_load, repository); + return git_futils_direach( + refs_path, GIT_PATH_MAX, + _dirent_loose_load, repository); } /* * Write a single reference into a packfile */ -static int packed_write_ref(reference_oid *ref, git_filebuf *file) +static int packed_write_ref(struct packref *ref, git_filebuf *file) { int error; char oid[GIT_OID_HEXSZ + 1]; @@ -712,17 +619,19 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file) * This obviously only applies to tags. * The required peels have already been loaded into `ref->peel_target`. */ - if (ref->ref.type & GIT_REF_HAS_PEEL) { + if (ref->flags & GIT_PACKREF_HAS_PEEL) { char peel[GIT_OID_HEXSZ + 1]; - git_oid_fmt(peel, &ref->peel_target); + git_oid_fmt(peel, &ref->peel); peel[GIT_OID_HEXSZ] = 0; - error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->ref.name, peel); + error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel); } else { - error = git_filebuf_printf(file, "%s %s\n", oid, ref->ref.name); + error = git_filebuf_printf(file, "%s %s\n", oid, ref->name); } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write packed reference"); + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to write packed reference"); } /* @@ -733,25 +642,25 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file) * cache on the packfile the OID of the object to * which that 'big tag' is pointing to. */ -static int packed_find_peel(reference_oid *ref) +static int packed_find_peel(git_repository *repo, struct packref *ref) { git_object *object; int error; - if (ref->ref.type & GIT_REF_HAS_PEEL) + if (ref->flags & GIT_PACKREF_HAS_PEEL) return GIT_SUCCESS; /* * Only applies to tags, i.e. references * in the /refs/tags folder */ - if (git__prefixcmp(ref->ref.name, GIT_REFS_TAGS_DIR) != 0) + if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0) return GIT_SUCCESS; /* * Find the tagged object in the repository */ - error = git_object_lookup(&object, ref->ref.owner, &ref->oid, GIT_OBJ_ANY); + error = git_object_lookup(&object, repo, &ref->oid, GIT_OBJ_ANY); if (error < GIT_SUCCESS) return git__throw(GIT_EOBJCORRUPTED, "Failed to find packed reference"); @@ -766,8 +675,8 @@ static int packed_find_peel(reference_oid *ref) /* * Find the object pointed at by this tag */ - git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); - ref->ref.type |= GIT_REF_HAS_PEEL; + git_oid_cpy(&ref->peel, git_tag_target_oid(tag)); + ref->flags |= GIT_PACKREF_HAS_PEEL; /* * The reference has now cached the resolved OID, and is @@ -777,7 +686,6 @@ static int packed_find_peel(reference_oid *ref) } git_object_close(object); - return GIT_SUCCESS; } @@ -797,16 +705,11 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list) unsigned int i; char full_path[GIT_PATH_MAX]; int error = GIT_SUCCESS; - reference *r; for (i = 0; i < packing_list->length; ++i) { - reference *ref = git_vector_get(packing_list, i); + struct packref *ref = git_vector_get(packing_list, i); - /* Ensure the packed reference doesn't exist - * in a (more up-to-date?) state as a loose reference - */ - r = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name); - if (r != NULL) + if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0) continue; git_path_join(full_path, repo->path_repository, ref->name); @@ -820,19 +723,18 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list) * but we should keep going and remove as many as possible. * After we've removed as many files as possible, we return * the error code anyway. - * - * TODO: mark this with a very special error code? - * GIT_EFAILTORMLOOSE */ } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to remove loose packed reference"); + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to remove loose packed reference"); } static int packed_sort(const void *a, const void *b) { - const reference *ref_a = (const reference *)a; - const reference *ref_b = (const reference *)b; + const struct packref *ref_a = (const struct packref *)a; + const struct packref *ref_b = (const struct packref *)b; return strcmp(ref_a->name, ref_b->name); } @@ -853,16 +755,18 @@ static int packed_write(git_repository *repo) assert(repo && repo->references.packfile); total_refs = repo->references.packfile->key_count; - if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS) + if ((error = + git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write packed reference"); /* Load all the packfile into a vector */ { - reference *reference; + struct packref *reference; const void *GIT_UNUSED(_unused); GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference, - git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */ + /* cannot fail: vector already has the right size */ + git_vector_insert(&packing_list, reference); ); } @@ -877,22 +781,19 @@ static int packed_write(git_repository *repo) /* Packfiles have a header... apparently * This is in fact not required, but we might as well print it * just for kicks */ - if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) + if ((error = + git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write packed reference"); for (i = 0; i < packing_list.length; ++i) { - reference_oid *ref = (reference_oid *)git_vector_get(&packing_list, i); - - /* only direct references go to the packfile; otherwise - * this is a disaster */ - assert(ref->ref.type & GIT_REF_OID); + struct packref *ref = (struct packref *)git_vector_get(&packing_list, i); - if ((error = packed_find_peel(ref)) < GIT_SUCCESS) { - error = git__throw(GIT_EOBJCORRUPTED, "A reference cannot be peeled"); + if ((error = packed_find_peel(repo, ref)) < GIT_SUCCESS) { + error = git__throw(GIT_EOBJCORRUPTED, + "A reference cannot be peeled"); goto cleanup; } - if ((error = packed_write_ref(ref, &pack_file)) < GIT_SUCCESS) goto cleanup; } @@ -918,20 +819,22 @@ cleanup: git_vector_free(&packing_list); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write packed reference"); + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to write packed reference"); } static int _reference_available_cb(const char *ref, void *data) { const char *new, *old; - git_vector *refs; + const char **refs; assert(ref && data); - refs = (git_vector *)data; + refs = (const char **)data; - new = (const char *)git_vector_get(refs, 0); - old = (const char *)git_vector_get(refs, 1); + new = (const char *)refs[0]; + old = (const char *)refs[1]; if (!old || strcmp(old, ref)) { int reflen = strlen(ref); @@ -947,439 +850,375 @@ static int _reference_available_cb(const char *ref, void *data) return GIT_SUCCESS; } -static int reference_available(git_repository *repo, const char *ref, const char* old_ref) +static int reference_available( + git_repository *repo, + const char *ref, + const char* old_ref) { - int error; - git_vector refs; - - if (git_vector_init(&refs, 2, NULL) < GIT_SUCCESS) - return GIT_ENOMEM; + const char *refs[2]; - git_vector_insert(&refs, (void *)ref); - git_vector_insert(&refs, (void *)old_ref); + refs[0] = ref; + refs[1] = old_ref; - error = git_reference_foreach(repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&refs); - - git_vector_free(&refs); + if (git_reference_foreach(repo, GIT_REF_LISTALL, + _reference_available_cb, (void *)refs) < 0) { + return git__throw(GIT_EEXISTS, + "Reference name `%s` conflicts with existing reference", ref); + } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__throw(GIT_EEXISTS, "Reference name `%s` conflicts with existing reference", ref); + return GIT_SUCCESS; } -int reference_lookup(reference **ref_out, git_repository *repo, const char *name) +static int reference_exists(int *exists, git_repository *repo, const char *ref_name) { int error; - char normalized_name[GIT_REFNAME_MAX]; - - assert(ref_out && repo && name); - - *ref_out = NULL; + char ref_path[GIT_PATH_MAX]; - error = normalize_name(normalized_name, sizeof(normalized_name), name, 0); + error = packed_load(repo); if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to lookup reference"); + return git__rethrow(error, "Cannot resolve if a reference exists"); - /* First, check has been previously loaded and cached */ - *ref_out = git_hashtable_lookup(repo->references.loose_cache, normalized_name); - if (*ref_out != NULL) - return loose_update(*ref_out); + git_path_join(ref_path, repo->path_repository, ref_name); - /* Then check if there is a loose file for that reference.*/ - error = loose_lookup(ref_out, repo, normalized_name, 0); + if (git_futils_isfile(ref_path) == GIT_SUCCESS || + git_hashtable_lookup(repo->references.packfile, ref_path) != NULL) { + *exists = 1; + } else { + *exists = 0; + } - /* If the file exists, we store it on the cache */ - if (error == GIT_SUCCESS) - return git_hashtable_insert(repo->references.loose_cache, (*ref_out)->name, (*ref_out)); + return GIT_SUCCESS; +} - /* The loose lookup has failed, but not because the reference wasn't found; - * probably the loose reference is corrupted. this is bad. */ - if (error != GIT_ENOTFOUND) - return git__rethrow(error, "Failed to lookup reference"); +static int packed_lookup(git_reference *ref) +{ + int error; + struct packref *pack_ref = NULL; - /* - * If we cannot find a loose reference, we look into the packfile - * Load the packfile first if it hasn't been loaded - */ - /* load all the packed references */ - error = packed_load(repo); + error = packed_load(ref->owner); if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to lookup reference"); + return git__rethrow(error, + "Failed to lookup reference from packfile"); - /* Look up on the packfile */ - *ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name); - if (*ref_out != NULL) + if (ref->flags & GIT_REF_PACKED && + ref->mtime == ref->owner->references.packfile_time) return GIT_SUCCESS; - /* The reference doesn't exist anywhere */ - return git__throw(GIT_ENOTFOUND, "Failed to lookup reference. Reference doesn't exist"); + if (ref->flags & GIT_REF_SYMBOLIC) + free(ref->target.symbolic); + + /* Look up on the packfile */ + pack_ref = git_hashtable_lookup(ref->owner->references.packfile, ref->name); + if (pack_ref == NULL) + return git__throw(GIT_ENOTFOUND, + "Failed to lookup reference from packfile"); + + ref->flags = GIT_REF_OID | GIT_REF_PACKED; + ref->mtime = ref->owner->references.packfile_time; + git_oid_cpy(&ref->target.oid, &pack_ref->oid); + + return GIT_SUCCESS; } -int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) +static int reference_lookup(git_reference *ref) { - int error; - reference *ref; + int error_loose, error_packed; - assert(ref_out && repo && name); + error_loose = loose_lookup(ref); + if (error_loose == GIT_SUCCESS) + return GIT_SUCCESS; - *ref_out = NULL; + error_packed = packed_lookup(ref); + if (error_packed == GIT_SUCCESS) + return GIT_SUCCESS; - error = reference_lookup(&ref, repo, name); - if (error < GIT_SUCCESS) - return error; + git_reference_free(ref); - *ref_out = reference_create_external(ref); - if (*ref_out == NULL) - return GIT_ENOMEM; + if (error_loose != GIT_ENOTFOUND) + return git__rethrow(error_loose, "Failed to lookup reference"); - return GIT_SUCCESS; + if (error_packed != GIT_ENOTFOUND) + return git__rethrow(error_packed, "Failed to lookup reference"); + + return git__throw(GIT_ENOTFOUND, "Reference not found"); } -/** - * Getters +/* + * Delete a reference. + * This is an internal method; the reference is removed + * from disk or the packfile, but the pointer is not freed */ -static git_rtype ref_type(reference *ref) +static int reference_delete(git_reference *ref) { + int error; + assert(ref); - if (ref->type & GIT_REF_OID) - return GIT_REF_OID; + /* If the reference is packed, this is an expensive operation. + * We need to reload the packfile, remove the reference from the + * packing list, and repack */ + if (ref->flags & GIT_REF_PACKED) { + /* load the existing packfile */ + if ((error = packed_load(ref->owner)) < GIT_SUCCESS) + return git__rethrow(error, "Failed to delete reference"); - if (ref->type & GIT_REF_SYMBOLIC) - return GIT_REF_SYMBOLIC; + if (git_hashtable_remove(ref->owner->references.packfile, + ref->name) < GIT_SUCCESS) + return git__throw(GIT_ENOTFOUND, "Reference not found"); - return GIT_REF_INVALID; -} + error = packed_write(ref->owner); -git_rtype git_reference_type(git_reference *ref_in) -{ - reference *ref; + /* If the reference is loose, we can just remove the reference + * from the filesystem */ + } else { + char full_path[GIT_PATH_MAX]; + git_reference *ref_in_pack; - assert(ref_in); + git_path_join(full_path, ref->owner->path_repository, ref->name); - ref = reference_get_internal(ref_in); - if (ref == NULL) - return GIT_REF_INVALID; + error = p_unlink(full_path); + if (error < GIT_SUCCESS) + goto cleanup; - return ref_type(ref); + /* When deleting a loose reference, we have to ensure that an older + * packed version of it doesn't exist */ + if (git_reference_lookup(&ref_in_pack, ref->owner, + ref->name) == GIT_SUCCESS) { + assert((ref_in_pack->flags & GIT_REF_PACKED) != 0); + error = git_reference_delete(ref_in_pack); + } + } + +cleanup: + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to delete reference"); } -int git_reference_is_packed(git_reference *ref_in) +int git_reference_delete(git_reference *ref) { - reference *ref; - - assert(ref_in); - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return GIT_REF_INVALID; + int error = reference_delete(ref); + if (error < GIT_SUCCESS) + return error; - return !!(ref->type & GIT_REF_PACKED); + git_reference_free(ref); + return GIT_SUCCESS; } -void git_reference_free(git_reference *ref) + +int git_reference_lookup(git_reference **ref_out, + git_repository *repo, const char *name) { - if (ref == NULL) - return; + int error; + char normalized_name[GIT_REFNAME_MAX]; + git_reference *ref = NULL; + + assert(ref_out && repo && name); + + *ref_out = NULL; - if (ref->name) - git__free(ref->name); + error = normalize_name(normalized_name, sizeof(normalized_name), name, 0); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to lookup reference"); - git__free(ref); + error = reference_create(&ref, repo, normalized_name); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to lookup reference"); + + error = reference_lookup(ref); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to lookup reference"); + + *ref_out = ref; + return GIT_SUCCESS; } -const char *git_reference_name(git_reference *ref) +/** + * Getters + */ +git_rtype git_reference_type(git_reference *ref) { assert(ref); - return ref->name; + + if (ref->flags & GIT_REF_OID) + return GIT_REF_OID; + + if (ref->flags & GIT_REF_SYMBOLIC) + return GIT_REF_SYMBOLIC; + + return GIT_REF_INVALID; } -git_repository *git_reference_owner(git_reference *ref) +int git_reference_is_packed(git_reference *ref) { assert(ref); - return ref->owner; + return !!(ref->flags & GIT_REF_PACKED); } -static const git_oid *ref_oid(reference *ref) +const char *git_reference_name(git_reference *ref) { assert(ref); - - if ((ref->type & GIT_REF_OID) == 0) - return NULL; - - if (loose_update(ref) < GIT_SUCCESS) - return NULL; - - return &((reference_oid *)ref)->oid; + return ref->name; } -const git_oid *git_reference_oid(git_reference *ref_in) +git_repository *git_reference_owner(git_reference *ref) { - reference *ref; - - assert(ref_in); - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return NULL; - - return ref_oid(ref); + assert(ref); + return ref->owner; } -static const char *ref_target(reference *ref) +const git_oid *git_reference_oid(git_reference *ref) { assert(ref); - if ((ref->type & GIT_REF_SYMBOLIC) == 0) + if ((ref->flags & GIT_REF_OID) == 0) return NULL; - if (loose_update(ref) < GIT_SUCCESS) - return NULL; - - return ((reference_symbolic *)ref)->target; + return &ref->target.oid; } -const char *git_reference_target(git_reference *ref_in) +const char *git_reference_target(git_reference *ref) { - reference *ref; - - assert(ref_in); + assert(ref); - ref = reference_get_internal(ref_in); - if (ref == NULL) + if ((ref->flags & GIT_REF_SYMBOLIC) == 0) return NULL; - return ref_target(ref); + return ref->target.symbolic; } -static int reference_create_symbolic(reference **ref_out, git_repository *repo, const char *name, const char *target, int force) +int git_reference_create_symbolic( + git_reference **ref_out, + git_repository *repo, + const char *name, + const char *target, + int force) { char normalized[GIT_REFNAME_MAX]; - int error = GIT_SUCCESS, updated = 0; - reference *ref = NULL; - void *old_ref = NULL; + int ref_exists, error = GIT_SUCCESS; + git_reference *ref = NULL; - if (reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) - return git__throw(GIT_EEXISTS, "Failed to create symbolic reference. Reference already exists"); + error = normalize_name(normalized, sizeof(normalized), name, 0); + if (error < GIT_SUCCESS) + goto cleanup; - /* - * If they old ref was of the same type, then we can just update - * it (once we've checked that the target is valid). Otherwise we - * need a new reference because we can't make a symbolic ref out - * of an oid one. - * If if didn't exist, then we need to create a new one anyway. - */ - if (ref && ref->type & GIT_REF_SYMBOLIC){ - updated = 1; - } else { - ref = NULL; - error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC); - if (error < GIT_SUCCESS) - goto cleanup; - } + if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS)) + return git__rethrow(error, "Failed to create symbolic reference"); - /* The target can aither be the name of an object id reference or the name of another symbolic reference */ - error = normalize_name(normalized, sizeof(normalized), target, 0); + if (ref_exists && !force) + return git__throw(GIT_EEXISTS, + "Failed to create symbolic reference. Reference already exists"); + + error = reference_create(&ref, repo, normalized); if (error < GIT_SUCCESS) goto cleanup; - /* set the target; this will write the reference on disk */ - error = reference_set_target(ref, normalized); + ref->flags |= GIT_REF_SYMBOLIC; + + /* set the target; this will normalize the name automatically + * and write the reference on disk */ + error = git_reference_set_target(ref, target); if (error < GIT_SUCCESS) goto cleanup; - /* - * If we didn't update the ref, then we need to insert or replace - * it in the loose cache. If we replaced a ref, free it. - */ - if (!updated){ - error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, &old_ref); - if (error < GIT_SUCCESS) - goto cleanup; - - if (old_ref != NULL) - reference_free((reference *)old_ref); + if (ref_out == NULL) { + git_reference_free(ref); + } else { + *ref_out = ref; } - *ref_out = ref; - - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference"); + return GIT_SUCCESS; cleanup: - reference_free(ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference"); + git_reference_free(ref); + return git__rethrow(error, "Failed to create symbolic reference"); } -int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) +int git_reference_create_oid( + git_reference **ref_out, + git_repository *repo, + const char *name, + const git_oid *id, + int force) { - int error; - reference *ref; + int error = GIT_SUCCESS, ref_exists; + git_reference *ref = NULL; + char normalized[GIT_REFNAME_MAX]; - error = reference_create_symbolic(&ref, repo, name, target, force); + error = normalize_name(normalized, sizeof(normalized), name, 1); if (error < GIT_SUCCESS) - return error; - - *ref_out = reference_create_external(ref); - if (*ref_out == NULL) - return GIT_ENOMEM; - - return GIT_SUCCESS; -} + goto cleanup; -static int reference_create_oid(reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) -{ - int error = GIT_SUCCESS, updated = 0; - reference *ref = NULL; - void *old_ref = NULL; + if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS)) + return git__rethrow(error, "Failed to create OID reference"); - if(reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) - return git__throw(GIT_EEXISTS, "Failed to create reference OID. Reference already exists"); + if (ref_exists && !force) + return git__throw(GIT_EEXISTS, + "Failed to create OID reference. Reference already exists"); if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS) return git__rethrow(error, "Failed to create reference"); - /* - * If they old ref was of the same type, then we can just update - * it (once we've checked that the target is valid). Otherwise we - * need a new reference because we can't make a symbolic ref out - * of an oid one. - * If if didn't exist, then we need to create a new one anyway. - */ - if (ref && ref-> type & GIT_REF_OID){ - updated = 1; - } else { - ref = NULL; - error = reference_create(&ref, repo, name, GIT_REF_OID); - if (error < GIT_SUCCESS) - goto cleanup; - } + error = reference_create(&ref, repo, name); + if (error < GIT_SUCCESS) + goto cleanup; + + ref->flags |= GIT_REF_OID; /* set the oid; this will write the reference on disk */ - error = reference_set_oid(ref, id); + error = git_reference_set_oid(ref, id); if (error < GIT_SUCCESS) goto cleanup; - if(!updated){ - error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, &old_ref); - if (error < GIT_SUCCESS) - goto cleanup; - - if (old_ref != NULL) - reference_free((reference *)old_ref); + if (ref_out == NULL) { + git_reference_free(ref); + } else { + *ref_out = ref; } - *ref_out = ref; - - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID"); + return GIT_SUCCESS; cleanup: - reference_free(ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID"); -} - -int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) -{ - int error; - reference *ref; - - error = reference_create_oid(&ref, repo, name, id, force); - if (error < GIT_SUCCESS) - return error; - - *ref_out = reference_create_external(ref); - if (*ref_out == NULL) - return GIT_ENOMEM; - - return GIT_SUCCESS; + git_reference_free(ref); + return git__rethrow(error, "Failed to create reference OID"); } /* * Change the OID target of a reference. * - * For loose references, just change the oid in memory - * and overwrite the file in disk. - * - * For packed files, this is not pretty: - * For performance reasons, we write the new reference - * loose on disk (it replaces the old on the packfile), - * but we cannot invalidate the pointer to the reference, - * and most importantly, the `packfile` object must stay - * consistent with the representation of the packfile - * on disk. This is what we need to: + * For both loose and packed references, just change + * the oid in memory and (over)write the file in disk. * - * 1. Copy the reference - * 2. Change the oid on the original - * 3. Write the original to disk - * 4. Write the original to the loose cache - * 5. Replace the original with the copy (old reference) in the packfile cache + * We do not repack packed references because of performance + * reasons. */ -int reference_set_oid(reference *ref, const git_oid *id) +int git_reference_set_oid(git_reference *ref, const git_oid *id) { - reference_oid *ref_oid; - reference_oid *ref_old = NULL; int error = GIT_SUCCESS; - if ((ref->type & GIT_REF_OID) == 0) - return git__throw(GIT_EINVALIDREFSTATE, "Failed to set OID target of reference. Not an OID reference"); - - ref_oid = (reference_oid *)ref; + if ((ref->flags & GIT_REF_OID) == 0) + return git__throw(GIT_EINVALIDREFSTATE, + "Failed to set OID target of reference. Not an OID reference"); assert(ref->owner); /* Don't let the user create references to OIDs that * don't exist in the ODB */ if (!git_odb_exists(git_repository_database(ref->owner), id)) - return git__throw(GIT_ENOTFOUND, "Failed to set OID target of reference. OID doesn't exist in ODB"); - - /* duplicate the reference; - * this copy will stay on the packfile cache */ - if (ref->type & GIT_REF_PACKED) { - ref_old = git__malloc(sizeof(reference_oid)); - if (ref_old == NULL) - return GIT_ENOMEM; - - ref_old->ref.name = git__strdup(ref->name); - if (ref_old->ref.name == NULL) { - git__free(ref_old); - return GIT_ENOMEM; - } - } + return git__throw(GIT_ENOTFOUND, + "Failed to set OID target of reference. OID doesn't exist in ODB"); - git_oid_cpy(&ref_oid->oid, id); - ref->type &= ~GIT_REF_HAS_PEEL; + /* Update the OID value on `ref` */ + git_oid_cpy(&ref->target.oid, id); error = loose_write(ref); if (error < GIT_SUCCESS) goto cleanup; - if (ref->type & GIT_REF_PACKED) { - /* insert the original on the loose cache */ - error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref); - if (error < GIT_SUCCESS) - goto cleanup; - - ref->type &= ~GIT_REF_PACKED; - - /* replace the original in the packfile with the copy */ - error = git_hashtable_insert(ref->owner->references.packfile, ref_old->ref.name, ref_old); - if (error < GIT_SUCCESS) - goto cleanup; - } - return GIT_SUCCESS; cleanup: - reference_free((reference *)ref_old); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to set OID target of reference"); -} - -int git_reference_set_oid(git_reference *ref_in, const git_oid *target) -{ - reference *ref; - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); - - return reference_set_oid(ref, target); + return git__rethrow(error, "Failed to set OID target of reference"); } /* @@ -1389,35 +1228,29 @@ int git_reference_set_oid(git_reference *ref_in, const git_oid *target) * a pack. We just change the target in memory * and overwrite the file on disk. */ -int reference_set_target(reference *ref, const char *target) +int git_reference_set_target(git_reference *ref, const char *target) { - reference_symbolic *ref_sym; + int error; + char normalized[GIT_REFNAME_MAX]; - if ((ref->type & GIT_REF_SYMBOLIC) == 0) - return git__throw(GIT_EINVALIDREFSTATE, "Failed to set reference target. Not a symbolic reference"); + if ((ref->flags & GIT_REF_SYMBOLIC) == 0) + return git__throw(GIT_EINVALIDREFSTATE, + "Failed to set reference target. Not a symbolic reference"); - ref_sym = (reference_symbolic *)ref; + error = normalize_name(normalized, sizeof(normalized), target, 0); + if (error < GIT_SUCCESS) + return git__rethrow(error, + "Failed to set reference target. Invalid target name"); - git__free(ref_sym->target); - ref_sym->target = git__strdup(target); - if (ref_sym->target == NULL) + git__free(ref->target.symbolic); + ref->target.symbolic = git__strdup(normalized); + if (ref->target.symbolic == NULL) return GIT_ENOMEM; return loose_write(ref); } -int git_reference_set_target(git_reference *ref_in, const char *target) -{ - reference *ref; - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); - - return reference_set_target(ref, target); -} - -int git_reference_rename(git_reference *ref_in, const char *new_name, int force) +int git_reference_rename(git_reference *ref, const char *new_name, int force) { int error; @@ -1425,71 +1258,59 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) char normalized[GIT_REFNAME_MAX]; const char *head_target = NULL; - reference *ref = NULL, *new_ref = NULL, *head = NULL, *tmp_ref = NULL; + git_reference *existing_ref = NULL, *head = NULL; - assert(ref_in); + error = normalize_name(normalized, sizeof(normalized), + new_name, ref->flags & GIT_REF_OID); - ref = reference_get_internal(ref_in); - if (ref == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to rename reference. Reference `%s` doesn't exist", ref->name); - - error = normalize_name(normalized, sizeof(normalized), new_name, ref->type & GIT_REF_OID); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to rename reference. Invalid name"); new_name = normalized; - error = reference_lookup(&new_ref, ref->owner, new_name); - if (error == GIT_SUCCESS) { - if (!force) - return git__throw(GIT_EEXISTS, "Failed to rename reference. Reference already exists"); + /* If we are forcing the rename, try to lookup a reference with the + * new one. If the lookup succeeds, we need to delete that ref + * before the renaming can proceed */ + if (force) { + error = git_reference_lookup(&existing_ref, ref->owner, new_name); - error = reference_delete(new_ref); - } - - if (error < GIT_SUCCESS) { - git_path_join(aux_path, ref->owner->path_repository, new_name); - /* If we couldn't read the reference because it doesn't - * exist it's ok - otherwise return */ - if (git_futils_isfile(aux_path) == GIT_SUCCESS) + if (error == GIT_SUCCESS) { + error = git_reference_delete(existing_ref); + if (error < GIT_SUCCESS) + return git__rethrow(error, + "Failed to rename reference. " + "The existing reference cannot be deleted"); + } else if (error != GIT_ENOTFOUND) goto cleanup; - } - - if ((error = reference_available(ref->owner, new_name, ref->name)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to rename reference. Reference already exists"); - - /* - * First, we backup the reference targets. Just keeping the old - * reference won't work, since we may have to remove it to create - * the new reference, e.g. when renaming foo/bar -> foo. - */ - if (ref->type & GIT_REF_SYMBOLIC) - tmp_ref = git__malloc(sizeof(reference_symbolic)); - else - tmp_ref = git__malloc(sizeof(reference_oid)); + /* If we're not forcing the rename, check if the reference exists. + * If it does, renaming cannot continue */ + } else { + int exists; - if (tmp_ref == NULL) - return GIT_ENOMEM; + error = reference_exists(&exists, ref->owner, normalized); + if (error < GIT_SUCCESS) + goto cleanup; - tmp_ref->name = git__strdup(ref->name); - tmp_ref->type = ref->type; - tmp_ref->owner = ref->owner; + if (exists) + return git__throw(GIT_EEXISTS, + "Failed to rename reference. Reference already exists"); + } - if (ref->type & GIT_REF_SYMBOLIC) - ((reference_symbolic *)tmp_ref)->target = git__strdup(((reference_symbolic *)ref)->target); - else - ((reference_oid *)tmp_ref)->oid = ((reference_oid *)ref)->oid; + if ((error = reference_available(ref->owner, new_name, ref->name)) < GIT_SUCCESS) + return git__rethrow(error, + "Failed to rename reference. Reference already exists"); /* * Now delete the old ref and remove an possibly existing directory - * named `new_name`. + * named `new_name`. Note that using the internal `reference_delete` + * method deletes the ref from disk but doesn't free the pointer, so + * we can still access the ref's attributes for creating the new one */ - if ((error = reference_delete(ref)) < GIT_SUCCESS) goto cleanup; - git_path_join(aux_path, tmp_ref->owner->path_repository, new_name); + git_path_join(aux_path, ref->owner->path_repository, new_name); if (git_futils_exists(aux_path) == GIT_SUCCESS) { if (git_futils_isdir(aux_path) == GIT_SUCCESS) { if ((error = git_futils_rmdir_r(aux_path, 0)) < GIT_SUCCESS) @@ -1513,8 +1334,7 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) * TODO * */ - - git_path_join_n(aux_path, 3, tmp_ref->owner->path_repository, "logs", tmp_ref->name); + git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", ref->name); if (git_futils_isfile(aux_path) == GIT_SUCCESS) { if ((error = p_unlink(aux_path)) < GIT_SUCCESS) goto rollback; @@ -1523,174 +1343,107 @@ int git_reference_rename(git_reference *ref_in, const char *new_name, int force) /* * Finally we can create the new reference. */ - if (tmp_ref->type & GIT_REF_SYMBOLIC) { - if ((error = reference_create_symbolic(&new_ref, tmp_ref->owner, new_name, ((reference_symbolic *)tmp_ref)->target, 0)) < GIT_SUCCESS) - goto rollback; + if (ref->flags & GIT_REF_SYMBOLIC) { + error = git_reference_create_symbolic( + NULL, ref->owner, new_name, ref->target.symbolic, 0); } else { - if ((error = reference_create_oid(&new_ref, tmp_ref->owner, new_name, &((reference_oid *)tmp_ref)->oid, 0)) < GIT_SUCCESS) - goto rollback; + error = git_reference_create_oid( + NULL, ref->owner, new_name, &ref->target.oid, 0); } - /* - * Change the name of the reference given by the user. - */ - git__free(ref_in->name); - ref_in->name = git__strdup(new_ref->name); - - if ((error = git_hashtable_insert(new_ref->owner->references.loose_cache, new_ref->name, new_ref)) < GIT_SUCCESS) - goto rollback; + if (error < GIT_SUCCESS) + goto cleanup; /* * Check if we have to update HEAD. */ - - if ((error = reference_lookup(&head, new_ref->owner, GIT_HEAD_FILE)) < GIT_SUCCESS) + error = git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE); + if (error < GIT_SUCCESS) goto cleanup; - head_target = ref_target(head); + head_target = git_reference_target(head); - if (head_target && !strcmp(head_target, tmp_ref->name)) - if ((error = reference_create_symbolic(&head, new_ref->owner, "HEAD", new_ref->name, 1)) < GIT_SUCCESS) - goto rollback; + if (head_target && !strcmp(head_target, ref->name)) { + error = git_reference_create_symbolic( + &head, ref->owner, "HEAD", new_name, 1); + + if (error < GIT_SUCCESS) + goto cleanup; + } + + /* + * Change the name of the reference given by the user. + */ + git__free(ref->name); + ref->name = git__strdup(new_name); + + /* The reference is no longer packed */ + ref->flags &= ~GIT_REF_PACKED; cleanup: - reference_free(tmp_ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference"); + /* We no longer need the newly created reference nor the head */ + git_reference_free(head); + return error == GIT_SUCCESS ? + GIT_SUCCESS : + git__rethrow(error, "Failed to rename reference"); rollback: /* * Try to create the old reference again. */ - if (ref->type & GIT_REF_SYMBOLIC) - error = reference_create_symbolic(&new_ref, tmp_ref->owner, tmp_ref->name, ((reference_symbolic *)tmp_ref)->target, 0); + if (ref->flags & GIT_REF_SYMBOLIC) + error = git_reference_create_symbolic( + NULL, ref->owner, ref->name, ref->target.symbolic, 0); else - error = reference_create_oid(&new_ref, ref->owner, tmp_ref->name, &((reference_oid *)tmp_ref)->oid, 0); - - git__free(ref_in->name); - ref_in->name = git__strdup(tmp_ref->name); - - reference_free(tmp_ref); + error = git_reference_create_oid( + NULL, ref->owner, ref->name, &ref->target.oid, 0); return error == GIT_SUCCESS ? git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") : git__rethrow(error, "Failed to rename reference. Failed to rollback"); } -/* - * Delete a reference. - * - * If the reference is packed, this is an expensive - * operation. We need to remove the reference from - * the memory cache and then rewrite the whole pack - * - * If the reference is loose, we remove it on - * the filesystem and update the in-memory cache - * accordingly. We also make sure that an older version - * of it doesn't exist as a packed reference. If this - * is the case, this packed reference is removed as well. - * - * This obviously invalidates the `ref` pointer. - */ -int reference_delete(reference *ref) +int git_reference_resolve(git_reference **ref_out, git_reference *ref) { - int error; - reference *reference; + int error, i = 0; + git_repository *repo; assert(ref); - if (ref->type & GIT_REF_PACKED) { - /* load the existing packfile */ - if ((error = packed_load(ref->owner)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to delete reference"); - - if (git_hashtable_remove(ref->owner->references.packfile, ref->name) < GIT_SUCCESS) - return git__throw(GIT_ENOTFOUND, "Reference not found"); - - error = packed_write(ref->owner); - } else { - char full_path[GIT_PATH_MAX]; - git_path_join(full_path, ref->owner->path_repository, ref->name); - git_hashtable_remove(ref->owner->references.loose_cache, ref->name); - error = p_unlink(full_path); - if (error < GIT_SUCCESS) - goto cleanup; - - /* When deleting a loose reference, we have to ensure that an older - * packed version of it doesn't exist - */ - if (!reference_lookup(&reference, ref->owner, ref->name)) { - assert((reference->type & GIT_REF_PACKED) != 0); - error = reference_delete(reference); - } - } - -cleanup: - reference_free(ref); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to delete reference"); -} - -int git_reference_delete(git_reference *ref_in) -{ - reference *ref; - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to delete reference. Reference `%s` doesn't exist", ref_in->name); - - git_reference_free(ref_in); - - return reference_delete(ref); -} - -static int reference_resolve(reference **resolved_ref, reference *ref) -{ - git_repository *repo; - int error, i; + *ref_out = NULL; + repo = ref->owner; - assert(resolved_ref && ref); - *resolved_ref = NULL; + /* If the reference is already resolved, we need to return a + * copy. Instead of duplicating `ref`, we look it up again to + * ensure the copy is out to date */ + if (ref->flags & GIT_REF_OID) + return git_reference_lookup(ref_out, ref->owner, ref->name); - if ((error = loose_update(ref)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to resolve reference"); + /* Otherwise, keep iterating until the reference is resolved */ + for (i = 0; i < MAX_NESTING_LEVEL; ++i) { + git_reference *new_ref; - repo = ref->owner; + error = git_reference_lookup(&new_ref, repo, ref->target.symbolic); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to resolve reference"); - for (i = 0; i < MAX_NESTING_LEVEL; ++i) { - reference_symbolic *ref_sym; + /* Free intermediate references, except for the original one + * we've received */ + if (i > 0) + git_reference_free(ref); - *resolved_ref = ref; + ref = new_ref; - if (ref->type & GIT_REF_OID) + /* When the reference we've just looked up is an OID, we've + * successfully resolved the symbolic ref */ + if (ref->flags & GIT_REF_OID) { + *ref_out = ref; return GIT_SUCCESS; - - ref_sym = (reference_symbolic *)ref; - if ((error = reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS) - return error; + } } - return git__throw(GIT_ENOMEM, "Failed to resolve reference. Reference is too nested"); -} - -int git_reference_resolve(git_reference **resolved_ref, git_reference *ref_in) -{ - int error; - reference *ref = NULL, *out = NULL; - - *resolved_ref = NULL; - - ref = reference_get_internal(ref_in); - if (ref == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to resolve reference. Reference `%s` doesn't exist", ref_in->name); - - error = reference_resolve(&out, ref); - if (error < GIT_SUCCESS) - return error; - - *resolved_ref = reference_create_external(out); - if (*resolved_ref == NULL) - return GIT_ENOMEM; - - return GIT_SUCCESS; + return git__throw(GIT_ENOMEM, + "Failed to resolve reference. Reference is too nested"); } int git_reference_packall(git_repository *repo) @@ -1709,7 +1462,11 @@ int git_reference_packall(git_repository *repo) return packed_write(repo); } -int git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload) +int git_reference_foreach( + git_repository *repo, + unsigned int list_flags, + int (*callback)(const char *, void *), + void *payload) { int error; struct dirent_list_data data; @@ -1725,7 +1482,8 @@ int git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*c GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused, if ((error = callback(ref_name, payload)) < GIT_SUCCESS) - return git__throw(error, "Failed to list references. User callback failed"); + return git__throw(error, + "Failed to list references. User callback failed"); ); } @@ -1738,7 +1496,6 @@ int git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*c data.callback = callback; data.callback_payload = payload; - git_path_join(refs_path, repo->path_repository, GIT_REFS_DIR); return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data); } @@ -1748,7 +1505,10 @@ static int cb__reflist_add(const char *ref, void *data) return git_vector_insert((git_vector *)data, git__strdup(ref)); } -int git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags) +int git_reference_listall( + git_strarray *array, + git_repository *repo, + unsigned int list_flags) { int error; git_vector ref_list; @@ -1761,7 +1521,8 @@ int git_reference_listall(git_strarray *array, git_repository *repo, unsigned in if (git_vector_init(&ref_list, 8, NULL) < GIT_SUCCESS) return GIT_ENOMEM; - error = git_reference_foreach(repo, list_flags, &cb__reflist_add, (void *)&ref_list); + error = git_reference_foreach( + repo, list_flags, &cb__reflist_add, (void *)&ref_list); if (error < GIT_SUCCESS) { git_vector_free(&ref_list); @@ -1773,48 +1534,39 @@ int git_reference_listall(git_strarray *array, git_repository *repo, unsigned in return GIT_SUCCESS; } -int git_repository__refcache_init(git_refcache *refs) +int git_reference_reload(git_reference *ref) { - assert(refs); + int error = reference_lookup(ref); - refs->loose_cache = git_hashtable_alloc( - default_table_size, - reftable_hash, - (git_hash_keyeq_ptr)(&git__strcmp_cb)); - - /* packfile loaded lazily */ - refs->packfile = NULL; - refs->packfile_time = 0; + if (error < GIT_SUCCESS) { + git_reference_free(ref); + return git__rethrow(error, "Failed to reload reference"); + } - return (refs->loose_cache) ? GIT_SUCCESS : GIT_ENOMEM; + return GIT_SUCCESS; } + void git_repository__refcache_free(git_refcache *refs) { - reference *reference; - const void *GIT_UNUSED(_unused); - assert(refs); - GIT_HASHTABLE_FOREACH(refs->loose_cache, _unused, reference, - reference_free(reference); - ); - - git_hashtable_free(refs->loose_cache); - if (refs->packfile) { + const void *GIT_UNUSED(_unused); + struct packref *reference; + GIT_HASHTABLE_FOREACH(refs->packfile, _unused, reference, - reference_free(reference); + free(reference); ); git_hashtable_free(refs->packfile); } } -static int check_valid_ref_char(char ch) +static int is_valid_ref_char(char ch) { if ((unsigned) ch <= ' ') - return GIT_ERROR; + return 0; switch (ch) { case '~': @@ -1824,13 +1576,17 @@ static int check_valid_ref_char(char ch) case '?': case '[': case '*': - return GIT_ERROR; + return 0; default: - return GIT_SUCCESS; + return 1; } } -static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref) +static int normalize_name( + char *buffer_out, + size_t out_size, + const char *name, + int is_oid_ref) { const char *name_end, *buffer_out_start; const char *current; @@ -1847,26 +1603,33 @@ static int normalize_name(char *buffer_out, size_t out_size, const char *name, i /* A refname can not be empty */ if (name_end == name) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name is empty"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. Reference name is empty"); /* A refname can not end with a dot or a slash */ if (*(name_end - 1) == '.' || *(name_end - 1) == '/') - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with dot or slash"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. Reference name ends with dot or slash"); while (current < name_end && out_size) { - if (check_valid_ref_char(*current)) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains invalid characters"); + if (!is_valid_ref_char(*current)) + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. " + "Reference name contains invalid characters"); if (buffer_out > buffer_out_start) { char prev = *(buffer_out - 1); /* A refname can not start with a dot nor contain a double dot */ if (*current == '.' && ((prev == '.') || (prev == '/'))) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name starts with a dot or contains a double dot"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. " + "Reference name starts with a dot or contains a double dot"); /* '@{' is forbidden within a refname */ if (*current == '{' && prev == '@') - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains '@{'"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. Reference name contains '@{'"); /* Prevent multiple slashes from being added to the output */ if (*current == '/' && prev == '/') { @@ -1888,13 +1651,18 @@ static int normalize_name(char *buffer_out, size_t out_size, const char *name, i /* Object id refname have to contain at least one slash, except * for HEAD in a detached state or MERGE_HEAD if we're in the * middle of a merge */ - if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE) - && strcmp(name, GIT_FETCH_HEAD_FILE))) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains no slashes"); + if (is_oid_ref && + !contains_a_slash && + strcmp(name, GIT_HEAD_FILE) != 0 && + strcmp(name, GIT_MERGE_HEAD_FILE) != 0 && + strcmp(name, GIT_FETCH_HEAD_FILE) != 0) + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. Reference name contains no slashes"); /* A refname can not end with ".lock" */ if (!git__suffixcmp(name, GIT_FILELOCK_EXTENSION)) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with '.lock'"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. Reference name ends with '.lock'"); *buffer_out = '\0'; @@ -1904,17 +1672,25 @@ static int normalize_name(char *buffer_out, size_t out_size, const char *name, i */ if (is_oid_ref && !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) || strcmp(buffer_out_start, GIT_HEAD_FILE))) - return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name does not start with 'refs/'"); + return git__throw(GIT_EINVALIDREFNAME, + "Failed to normalize name. " + "Reference name does not start with 'refs/'"); return GIT_SUCCESS; } -int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name) +int git_reference__normalize_name( + char *buffer_out, + size_t out_size, + const char *name) { return normalize_name(buffer_out, out_size, name, 0); } -int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name) +int git_reference__normalize_name_oid( + char *buffer_out, + size_t out_size, + const char *name) { return normalize_name(buffer_out, out_size, name, 1); } diff --git a/src/refs.h b/src/refs.h index db0f5c4df..02e336e54 100644 --- a/src/refs.h +++ b/src/refs.h @@ -33,19 +33,23 @@ #define GIT_REFNAME_MAX 1024 struct git_reference { + unsigned int flags; git_repository *owner; char *name; + time_t mtime; + + union { + git_oid oid; + char *symbolic; + } target; }; typedef struct { git_hashtable *packfile; - git_hashtable *loose_cache; time_t packfile_time; } git_refcache; - void git_repository__refcache_free(git_refcache *refs); -int git_repository__refcache_init(git_refcache *refs); int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name); int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name); diff --git a/src/repository.c b/src/repository.c index 6c75aa190..f8195e2d9 100644 --- a/src/repository.c +++ b/src/repository.c @@ -172,11 +172,6 @@ static git_repository *repository_alloc(void) return NULL; } - if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) { - git__free(repo); - return NULL; - } - return repo; } @@ -777,7 +772,7 @@ int git_repository_head_orphan(git_repository *repo) int git_repository_is_empty(git_repository *repo) { - git_reference *head, *branch; + git_reference *head = NULL, *branch = NULL; int error; error = git_reference_lookup(&head, repo, "HEAD"); diff --git a/tests/t10-refs.c b/tests/t10-refs.c index 12632b02b..e5e722992 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -143,22 +143,23 @@ BEGIN_TEST(readsym2, "lookup the HEAD and resolve the master branch") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name)); - must_pass(git_reference_resolve(&resolved_ref, reference)); - comp_base_ref = resolved_ref; + must_pass(git_reference_resolve(&comp_base_ref, reference)); + git_reference_free(reference); must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE)); must_pass(git_reference_resolve(&resolved_ref, reference)); must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); + git_reference_free(reference); + git_reference_free(resolved_ref); must_pass(git_reference_lookup(&reference, repo, current_head_target)); must_pass(git_reference_resolve(&resolved_ref, reference)); must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); - - git_repository_free(repo); - git_reference_free(reference); git_reference_free(resolved_ref); + git_reference_free(comp_base_ref); + git_repository_free(repo); END_TEST BEGIN_TEST(readsym3, "lookup the master branch and then the HEAD") @@ -902,6 +903,9 @@ BEGIN_TEST(delete1, "can delete a just packed reference") /* Pack all existing references */ must_pass(git_reference_packall(repo)); + /* Reload the reference from disk */ + must_pass(git_reference_reload(ref)); + /* Ensure it's a packed reference */ must_be_true(git_reference_is_packed(ref) == 1); -- cgit v1.2.1 From 62dd6d1637e40f9fa16005ef447d4fc6f8fb25e8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 6 Nov 2011 02:52:43 +0100 Subject: reflog: Do not free references before time --- src/reflog.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/reflog.c b/src/reflog.c index 81e171acf..e0fa7a060 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -215,27 +215,37 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old, const git_oid *oid; if ((error = git_reference_resolve(&r, ref)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to write reflog. Cannot resolve reference `%s`", ref->name); + return git__rethrow(error, + "Failed to write reflog. Cannot resolve reference `%s`", ref->name); oid = git_reference_oid(r); if (oid == NULL) { git_reference_free(r); - return git__throw(GIT_ERROR, "Failed to write reflog. Cannot resolve reference `%s`", r->name); + return git__throw(GIT_ERROR, + "Failed to write reflog. Cannot resolve reference `%s`", r->name); } - git_reference_free(r); - git_oid_to_string(new, GIT_OID_HEXSZ+1, oid); - git_path_join_n(log_path, 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name); + git_path_join_n(log_path, 3, + ref->owner->path_repository, GIT_REFLOG_DIR, ref->name); + + git_reference_free(r); if (git_futils_exists(log_path)) { - if ((error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to write reflog. Cannot create reflog directory"); + error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE); + if (error < GIT_SUCCESS) + return git__rethrow(error, + "Failed to write reflog. Cannot create reflog directory"); + } else if (git_futils_isfile(log_path)) { - return git__throw(GIT_ERROR, "Failed to write reflog. `%s` is directory", log_path); - } else if (oid_old == NULL) - return git__throw(GIT_ERROR, "Failed to write reflog. Old OID cannot be NULL for existing reference"); + return git__throw(GIT_ERROR, + "Failed to write reflog. `%s` is directory", log_path); + + } else if (oid_old == NULL) { + return git__throw(GIT_ERROR, + "Failed to write reflog. Old OID cannot be NULL for existing reference"); + } if (oid_old) git_oid_to_string(old, GIT_OID_HEXSZ+1, oid_old); -- cgit v1.2.1 From faeebd06e41f2711ad4b3c99f3f10e5778c8a5cd Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Sun, 6 Nov 2011 19:35:35 -0600 Subject: examples/network/fetch.c: revert overzealous conversion of free to git__free Since git__free is not exported (it's actually a macro), it should not be used in client programs. Change this call to 'git__free' back to 'free'. --- examples/network/fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index 35fc3eae4..dd732f22e 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -119,7 +119,7 @@ int fetch(git_repository *repo, int argc, char **argv) if (error < GIT_SUCCESS) return error; - git__free(packname); + free(packname); git_indexer_free(idx); git_remote_free(remote); -- cgit v1.2.1 From 983562e47537eef4c9d7706d036245a1896dd5f2 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Sun, 6 Nov 2011 19:43:44 -0600 Subject: examples/network/git2.c: add newline to usage message --- examples/network/git2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network/git2.c b/examples/network/git2.c index 0468c8ace..a4bff4a2a 100644 --- a/examples/network/git2.c +++ b/examples/network/git2.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) int i, error; if (argc < 2) { - fprintf(stderr, "usage: %s [repo]", argv[0]); + fprintf(stderr, "usage: %s [repo]\n", argv[0]); } for (i = 0; commands[i].name != NULL; ++i) { -- cgit v1.2.1 From 349532d0b1fd4eb94b398616602674ff516f6d76 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Sun, 6 Nov 2011 19:44:29 -0600 Subject: examples/network/git2.c: exit with proper status, and avoid segfault This function should exit after printing usage information if too few arguments were specified. Additionally, it should exit with a failure status if the first argument supplied is not one in the internal command list. --- examples/network/git2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/network/git2.c b/examples/network/git2.c index a4bff4a2a..def56e83b 100644 --- a/examples/network/git2.c +++ b/examples/network/git2.c @@ -45,6 +45,7 @@ int main(int argc, char **argv) if (argc < 2) { fprintf(stderr, "usage: %s [repo]\n", argv[0]); + exit(EXIT_FAILURE); } for (i = 0; commands[i].name != NULL; ++i) { @@ -53,5 +54,5 @@ int main(int argc, char **argv) } fprintf(stderr, "Command not found: %s\n", argv[1]); - + return 1; } -- cgit v1.2.1 From 0b142c9cb207444e22c4136c64c4d7bcecb2ccef Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Sun, 6 Nov 2011 20:07:27 -0600 Subject: examples/network/.gitignore: ignore 'git2' --- examples/network/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/network/.gitignore diff --git a/examples/network/.gitignore b/examples/network/.gitignore new file mode 100644 index 000000000..1b48e66ed --- /dev/null +++ b/examples/network/.gitignore @@ -0,0 +1 @@ +/git2 -- cgit v1.2.1 From 0c49ec2d3b5bfc32d69d189b7dc69cc26beb6a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 7 Nov 2011 19:34:24 +0100 Subject: Implement p_rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the callers of git_futils_mv_atomic to use p_rename. Signed-off-by: Carlos Martín Nieto --- src/filebuf.c | 2 +- src/fileops.c | 25 +------------------------ src/posix.c | 14 ++++++++++++++ src/posix.h | 1 + src/win32/posix.h | 1 + src/win32/posix_w32.c | 14 ++++++++++++++ tests-clay/status/worktree.c | 2 +- tests/t18-status.c | 18 +++++++++--------- 8 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/filebuf.c b/src/filebuf.c index 1a3fe6d9b..199418032 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -278,7 +278,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode) goto cleanup; } - error = git_futils_mv_atomic(file->path_lock, file->path_original); + error = p_rename(file->path_lock, file->path_original); cleanup: git_filebuf_cleanup(file); diff --git a/src/fileops.c b/src/fileops.c index 2030c786d..955bb1bf6 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -8,29 +8,6 @@ #include "fileops.h" #include -int git_futils_mv_atomic(const char *from, const char *to) -{ -#ifdef GIT_WIN32 - /* - * Win32 POSIX compilance my ass. If the destination - * file exists, the `rename` call fails. This is as - * close as it gets with the Win32 API. - */ - return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR; -#else - /* Don't even try this on Win32 */ - if (!link(from, to)) { - p_unlink(from); - return GIT_SUCCESS; - } - - if (!rename(from, to)) - return GIT_SUCCESS; - - return GIT_ERROR; -#endif -} - int git_futils_mkpath2file(const char *file_path, const mode_t mode) { int error = GIT_SUCCESS; @@ -216,7 +193,7 @@ int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmod if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS) return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */ - return git_futils_mv_atomic(from, to); /* The callee already takes care of setting the correct error message. */ + return p_rename(from, to); /* The callee already takes care of setting the correct error message. */ } int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len) diff --git a/src/posix.c b/src/posix.c index 7cd0749b6..8c19588ee 100644 --- a/src/posix.c +++ b/src/posix.c @@ -39,6 +39,20 @@ int p_getcwd(char *buffer_out, size_t size) return GIT_SUCCESS; } +int p_rename(const char *from, const char *to) +{ + if (!link(from, to)) { + p_unlink(from); + return GIT_SUCCESS; + } + + if (!rename(from, to)) + return GIT_SUCCESS; + + return GIT_ERROR; + +} + #endif int p_read(git_file fd, void *buf, size_t cnt) diff --git a/src/posix.h b/src/posix.h index 55cd35a38..c12b41364 100644 --- a/src/posix.h +++ b/src/posix.h @@ -45,6 +45,7 @@ extern int p_write(git_file fd, const void *buf, size_t cnt); extern int p_open(const char *path, int flags); extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); +extern int p_rename(const char *from, const char *to); #ifndef GIT_WIN32 diff --git a/src/win32/posix.h b/src/win32/posix.h index 7b5553061..ae6323679 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -48,5 +48,6 @@ extern int p_fsync(int fd); extern int p_open(const char *path, int flags); extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); +extern int p_rename(const char *from, const char *to); #endif diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 4b1b0074d..6f722581e 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -388,3 +388,17 @@ int p_access(const char* path, mode_t mode) return ret; } + +extern int p_rename(const char *from, const char *to) +{ + wchar_t *wfrom = gitwin_to_utf16(from); + wchar_t *wto = gitwin_to_utf16(to); + int ret; + + ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR; + + git__free(wfrom); + git__free(wto); + + return ret; +} diff --git a/tests-clay/status/worktree.c b/tests-clay/status/worktree.c index 7449c6de9..1e8a5ddbc 100644 --- a/tests-clay/status/worktree.c +++ b/tests-clay/status/worktree.c @@ -71,7 +71,7 @@ void test_status_worktree__initialize(void) * inside the fixtures folder in our libgit2 repo. */ cl_git_pass( - git_futils_mv_atomic("status/.gitted", "status/.git") + p_rename("status/.gitted", "status/.git") ); /* diff --git a/tests/t18-status.c b/tests/t18-status.c index d836fb9a9..73e328c2c 100644 --- a/tests/t18-status.c +++ b/tests/t18-status.c @@ -136,7 +136,7 @@ BEGIN_TEST(statuscb0, "test retrieving status for worktree of repository") struct status_entry_counts counts; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); memset(&counts, 0x0, sizeof(struct status_entry_counts)); @@ -223,7 +223,7 @@ BEGIN_TEST(statuscb2, "test retrieving status for a purged worktree of an valid struct status_entry_counts counts; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); /* Purging the working */ @@ -309,12 +309,12 @@ BEGIN_TEST(statuscb3, "test retrieving status for a worktree where a file and a struct status_entry_counts counts; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap")); - must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file")); - must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir")); + must_pass(p_rename(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap")); + must_pass(p_rename(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file")); + must_pass(p_rename(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir")); must_pass(file_create(TEMP_REPO_FOLDER ".HEADER", "dummy")); must_pass(file_create(TEMP_REPO_FOLDER "42-is-not-prime.sigh", "dummy")); @@ -341,7 +341,7 @@ BEGIN_TEST(singlestatus0, "test retrieving status for single file") int i; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); for (i = 0; i < ENTRY_COUNT0; ++i) { @@ -360,7 +360,7 @@ BEGIN_TEST(singlestatus1, "test retrieving status for nonexistent file") int error; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); // "nonexistent" does not exist in HEAD, Index or the worktree @@ -421,7 +421,7 @@ BEGIN_TEST(singlestatus4, "can't determine the status for a folder") int error; must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER)); - must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); + must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); error = git_status_file(&status_flags, repo, "subdir"); -- cgit v1.2.1 From 718eb4b8ae2d26ef76f9f3abe69b8b5e18fc1f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 7 Nov 2011 20:06:01 +0100 Subject: Reword packed-refs error messages so they're easier to track down MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Martín Nieto --- src/refs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/refs.c b/src/refs.c index 563406660..d2650bde6 100644 --- a/src/refs.c +++ b/src/refs.c @@ -757,7 +757,7 @@ static int packed_write(git_repository *repo) total_refs = repo->references.packfile->key_count; if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to write packed reference"); + return git__rethrow(error, "Failed to init packed refernces list"); /* Load all the packfile into a vector */ { @@ -776,14 +776,14 @@ static int packed_write(git_repository *repo) /* Now we can open the file! */ git_path_join(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE); if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to write packed reference"); + return git__rethrow(error, "Failed to write open packed references file"); /* Packfiles have a header... apparently * This is in fact not required, but we might as well print it * just for kicks */ if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to write packed reference"); + return git__rethrow(error, "Failed to write packed references file header"); for (i = 0; i < packing_list.length; ++i) { struct packref *ref = (struct packref *)git_vector_get(&packing_list, i); @@ -821,7 +821,7 @@ cleanup: return error == GIT_SUCCESS ? GIT_SUCCESS : - git__rethrow(error, "Failed to write packed reference"); + git__rethrow(error, "Failed to write packed references file"); } static int _reference_available_cb(const char *ref, void *data) -- cgit v1.2.1 From 657a3951860f07cf26e2accfe2ada6d62ca5a9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 7 Nov 2011 20:32:03 +0100 Subject: Write packed-refs with 0644 permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Martín Nieto --- src/refs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/refs.c b/src/refs.c index d2650bde6..05f935796 100644 --- a/src/refs.c +++ b/src/refs.c @@ -16,6 +16,8 @@ #define MAX_NESTING_LEVEL 5 +#define GIT_PACKED_REFS_FILE_MODE 0644 + enum { GIT_PACKREF_HAS_PEEL = 1, GIT_PACKREF_WAS_LOOSE = 2 @@ -802,7 +804,7 @@ cleanup: /* if we've written all the references properly, we can commit * the packfile to make the changes effective */ if (error == GIT_SUCCESS) { - error = git_filebuf_commit(&pack_file, GIT_PACK_FILE_MODE); + error = git_filebuf_commit(&pack_file, GIT_PACKED_REFS_FILE_MODE); /* when and only when the packfile has been properly written, * we can go ahead and remove the loose refs */ -- cgit v1.2.1 From a15c550db8b0552902e58c9bf2194005fb7fb0e9 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 16 Nov 2011 14:09:44 +0100 Subject: threads: Fix the shared global state with TLS See `global.c` for a description of what we're doing. When libgit2 is built with GIT_THREADS support, the threading system must be explicitly initialized with `git_threads_init()`. --- include/git2.h | 1 + include/git2/common.h | 13 ----- include/git2/thread-utils.h | 60 -------------------- include/git2/threads.h | 48 ++++++++++++++++ src/common.h | 1 - src/errors.c | 32 ++++++----- src/global.c | 134 ++++++++++++++++++++++++++++++++++++++++++++ src/global.h | 24 ++++++++ src/mwindow.c | 96 ++++++++++++++++--------------- src/mwindow.h | 3 - src/pack.c | 4 +- src/thread-utils.h | 2 +- 12 files changed, 282 insertions(+), 136 deletions(-) delete mode 100644 include/git2/thread-utils.h create mode 100644 include/git2/threads.h create mode 100644 src/global.c create mode 100644 src/global.h diff --git a/include/git2.h b/include/git2.h index ad92809bb..14c090e39 100644 --- a/include/git2.h +++ b/include/git2.h @@ -11,6 +11,7 @@ #include "git2/version.h" #include "git2/common.h" +#include "git2/threads.h" #include "git2/errors.h" #include "git2/zlib.h" diff --git a/include/git2/common.h b/include/git2/common.h index ef279eac1..eee918a23 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -7,7 +7,6 @@ #ifndef INCLUDE_git_common_h__ #define INCLUDE_git_common_h__ -#include "thread-utils.h" #include #include @@ -38,18 +37,6 @@ # define GIT_EXTERN(type) extern type #endif -/** Declare a public TLS symbol exported for application use. */ -#if __GNUC__ >= 4 -# define GIT_EXTERN_TLS(type) extern \ - __attribute__((visibility("default"))) \ - GIT_TLS \ - type -#elif defined(_MSC_VER) -# define GIT_EXTERN_TLS(type) __declspec(dllexport) GIT_TLS type -#else -# define GIT_EXTERN_TLS(type) extern GIT_TLS type -#endif - /** Declare a function as always inlined. */ #if defined(_MSC_VER) # define GIT_INLINE(type) static __inline type diff --git a/include/git2/thread-utils.h b/include/git2/thread-utils.h deleted file mode 100644 index 81c62d135..000000000 --- a/include/git2/thread-utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2009-2011 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_git_thread_utils_h__ -#define INCLUDE_git_thread_utils_h__ - -/* - * How TLS works is compiler+platform dependant - * Sources: http://en.wikipedia.org/wiki/Thread-Specific_Storage - * http://predef.sourceforge.net/precomp.html - */ - -#ifdef GIT_THREADS -# define GIT_HAS_TLS 1 - -/* No TLS in Cygwin */ -# if defined(__CHECKER__) || defined(__CYGWIN__) -# undef GIT_HAS_TLS -# define GIT_TLS - -/* No TLS in Mach binaries for Mac OS X */ -# elif defined(__APPLE__) && defined(__MACH__) -# undef GIT_TLS -# define GIT_TLS - -/* Normal TLS for GCC */ -# elif defined(__GNUC__) || \ - defined(__SUNPRO_C) || \ - defined(__SUNPRO_CC) || \ - defined(__xlc__) || \ - defined(__xlC__) -# define GIT_TLS __thread - -/* ICC may run on Windows or Linux */ -# elif defined(__INTEL_COMPILER) -# if defined(_WIN32) || defined(_WIN32_CE) -# define GIT_TLS __declspec(thread) -# else -# define GIT_TLS __thread -# endif - -/* Declspec for MSVC in Win32 */ -# elif defined(_WIN32) || \ - defined(_WIN32_CE) || \ - defined(__BORLANDC__) -# define GIT_TLS __declspec(thread) - -/* Other platform; no TLS */ -# else -# undef GIT_HAS_TLS -# define GIT_TLS /* nothing: tls vars are thread-global */ -# endif -#else /* Disable TLS if libgit2 is not threadsafe */ -# define GIT_TLS -#endif /* GIT_THREADS */ - -#endif /* INCLUDE_git_thread_utils_h__ */ diff --git a/include/git2/threads.h b/include/git2/threads.h new file mode 100644 index 000000000..85472a441 --- /dev/null +++ b/include/git2/threads.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_threads_h__ +#define INCLUDE_git_threads_h__ + +#include "common.h" + +/** + * @file git2/threads.h + * @brief Library level thread functions + * @defgroup git_thread Threading functions + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Init the threading system. + * + * If libgit2 has been built with GIT_THREADS + * on, this function must be called once before + * any other library functions. + * + * If libgit2 has been built without GIT_THREADS + * support, this function is a no-op. + */ +GIT_EXTERN(void) git_threads_init(void); + +/** + * Shutdown the threading system. + * + * If libgit2 has been built with GIT_THREADS + * on, this function must be called before shutting + * down the library. + * + * If libgit2 has been built without GIT_THREADS + * support, this function is a no-op. + */ +GIT_EXTERN(void) git_threads_shutdown(void); + +/** @} */ +GIT_END_DECL +#endif + diff --git a/src/common.h b/src/common.h index f7a41d47e..727a08e77 100644 --- a/src/common.h +++ b/src/common.h @@ -8,7 +8,6 @@ #define INCLUDE_common_h__ #include "git2/common.h" -#include "git2/thread-utils.h" #include "cc-compat.h" #include diff --git a/src/errors.c b/src/errors.c index 18afff3b5..81770e786 100644 --- a/src/errors.c +++ b/src/errors.c @@ -5,13 +5,9 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" -#include "git2/thread-utils.h" /* for GIT_TLS */ -#include "thread-utils.h" /* for GIT_TLS */ - +#include "global.h" #include -static GIT_TLS char g_last_error[1024]; - static struct { int num; const char *str; @@ -59,19 +55,26 @@ const char *git_strerror(int num) return "Unknown error"; } +#define ERROR_MAX_LEN 1024 + void git___rethrow(const char *msg, ...) { - char new_error[1024]; + char new_error[ERROR_MAX_LEN]; + char *last_error; char *old_error = NULL; va_list va; + last_error = GIT_GLOBAL->error.last; + va_start(va, msg); - vsnprintf(new_error, sizeof(new_error), msg, va); + vsnprintf(new_error, ERROR_MAX_LEN, msg, va); va_end(va); - old_error = git__strdup(g_last_error); - snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error); + old_error = git__strdup(last_error); + + snprintf(last_error, ERROR_MAX_LEN, "%s \n - %s", new_error, old_error); + git__free(old_error); } @@ -80,19 +83,22 @@ void git___throw(const char *msg, ...) va_list va; va_start(va, msg); - vsnprintf(g_last_error, sizeof(g_last_error), msg, va); + vsnprintf(GIT_GLOBAL->error.last, ERROR_MAX_LEN, msg, va); va_end(va); } const char *git_lasterror(void) { - if (!g_last_error[0]) + char *last_error = GIT_GLOBAL->error.last; + + if (!last_error[0]) return NULL; - return g_last_error; + return last_error; } void git_clearerror(void) { - g_last_error[0] = '\0'; + char *last_error = GIT_GLOBAL->error.last; + last_error[0] = '\0'; } diff --git a/src/global.c b/src/global.c new file mode 100644 index 000000000..8ef286ef0 --- /dev/null +++ b/src/global.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "common.h" +#include "global.h" +#include "git2/threads.h" +#include "thread-utils.h" + +/** + * Handle the global state with TLS + * + * If libgit2 is built with GIT_THREADS enabled, + * the `git_threads_init()` function must be called + * before calling any other function of the library. + * + * This function allocates a TLS index (using pthreads + * or the native Win32 API) to store the global state + * on a per-thread basis. + * + * Any internal method that requires global state will + * then call `git__global_state()` which returns a pointer + * to the global state structure; this pointer is lazily + * allocated on each thread. + * + * Before shutting down the library, the + * `git_threads_shutdown` method must be called to free + * the previously reserved TLS index. + * + * If libgit2 is built without threading support, the + * `git__global_statestate()` call returns a pointer to a single, + * statically allocated global state. The `git_thread_` + * functions are not available in that case. + */ + +#if defined(GIT_THREADS) && defined(GIT_WIN32) + +static DWORD _tls_index; +static int _tls_init = 0; + +void git_threads_init(void) +{ + if (_tls_init) + return; + + _tls_index = TlsAlloc(); + _tls_init = 1; +} + +void git_threads_shutdown(void) +{ + TlsFree(_tls_index); + _tls_init = 0; +} + +git_global_st *git__global_state(void) +{ + void *ptr; + + if ((ptr = TlsGetValue(_tls_index)) != NULL) + return ptr; + + ptr = malloc(sizeof(git_global_st)); + if (!ptr) + return NULL; + + memset(ptr, 0x0, sizeof(git_global_st)); + TlsSetValue(_tls_index, ptr); + return ptr; +} + +#elif defined(GIT_THREADS) && defined(_POSIX_THREADS) + +static pthread_key_t _tls_key; +static int _tls_init = 0; + +static void cb__free_status(void *st) +{ + free(st); +} + +void git_threads_init(void) +{ + if (_tls_init) + return; + + pthread_key_create(&_tls_key, &cb__free_status); + _tls_init = 1; +} + +void git_threads_shutdown(void) +{ + pthread_key_delete(_tls_key); + _tls_init = 0; +} + +git_global_st *git__global_state(void) +{ + void *ptr; + + if ((ptr = pthread_getspecific(_tls_key)) != NULL) + return ptr; + + ptr = malloc(sizeof(git_global_st)); + if (!ptr) + return NULL; + + memset(ptr, 0x0, sizeof(git_global_st)); + pthread_setspecific(_tls_key, ptr); + return ptr; +} + +#else + +static git_global_st __state; + +void git_threads_init(void) +{ + /* noop */ +} + +void git_threads_shutdown(void) +{ + /* noop */ +} + +git_global_st *git__global_state(void) +{ + return &__state; +} + +#endif /* GIT_THREADS */ diff --git a/src/global.h b/src/global.h new file mode 100644 index 000000000..641f47cbc --- /dev/null +++ b/src/global.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_global_h__ +#define INCLUDE_global_h__ + +#include "mwindow.h" + +typedef struct { + struct { + char last[1024]; + } error; + + git_mwindow_ctl mem_ctl; +} git_global_st; + +git_global_st *git__global_state(void); + +#define GIT_GLOBAL (git__global_state()) + +#endif diff --git a/src/mwindow.c b/src/mwindow.c index 126268fd9..8dc4573b4 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -10,6 +10,7 @@ #include "vector.h" #include "fileops.h" #include "map.h" +#include "global.h" #define DEFAULT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ @@ -20,21 +21,15 @@ ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL)) /* - * We need this because each process is only allowed a specific amount - * of memory. Making it writable should generate one instance per - * process, but we still need to set a couple of variables. + * These are the global options for mmmap limits. + * TODO: allow the user to change these */ - -static git_mwindow_ctl ctl = { - 0, - 0, +static struct { + size_t window_size; + size_t mapped_limit; +} _mw_options = { DEFAULT_WINDOW_SIZE, DEFAULT_MAPPED_LIMIT, - 0, - 0, - 0, - 0, - {0, 0, 0, 0, 0} }; /* @@ -43,28 +38,29 @@ static git_mwindow_ctl ctl = { */ void git_mwindow_free_all(git_mwindow_file *mwf) { + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; unsigned int i; /* * Remove these windows from the global list */ - for (i = 0; i < ctl.windowfiles.length; ++i){ - if (git_vector_get(&ctl.windowfiles, i) == mwf) { - git_vector_remove(&ctl.windowfiles, i); + for (i = 0; i < ctl->windowfiles.length; ++i){ + if (git_vector_get(&ctl->windowfiles, i) == mwf) { + git_vector_remove(&ctl->windowfiles, i); break; } } - if (ctl.windowfiles.length == 0) { - git_vector_free(&ctl.windowfiles); - ctl.windowfiles.contents = NULL; + if (ctl->windowfiles.length == 0) { + git_vector_free(&ctl->windowfiles); + ctl->windowfiles.contents = NULL; } while (mwf->windows) { git_mwindow *w = mwf->windows; assert(w->inuse_cnt == 0); - ctl.mapped -= w->window_map.len; - ctl.open_windows--; + ctl->mapped -= w->window_map.len; + ctl->open_windows--; git_futils_mmap_free(&w->window_map); @@ -115,6 +111,7 @@ void git_mwindow_scan_lru( */ static int git_mwindow_close_lru(git_mwindow_file *mwf) { + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; unsigned int i; git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows; @@ -122,16 +119,16 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf) if(mwf->windows) git_mwindow_scan_lru(mwf, &lru_w, &lru_l); - for (i = 0; i < ctl.windowfiles.length; ++i) { + for (i = 0; i < ctl->windowfiles.length; ++i) { git_mwindow *last = lru_w; - git_mwindow_file *cur = git_vector_get(&ctl.windowfiles, i); + git_mwindow_file *cur = git_vector_get(&ctl->windowfiles, i); git_mwindow_scan_lru(cur, &lru_w, &lru_l); if (lru_w != last) list = &cur->windows; } if (lru_w) { - ctl.mapped -= lru_w->window_map.len; + ctl->mapped -= lru_w->window_map.len; git_futils_mmap_free(&lru_w->window_map); if (lru_l) @@ -140,7 +137,7 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf) *list = lru_w->next; git__free(lru_w); - ctl.open_windows--; + ctl->open_windows--; return GIT_SUCCESS; } @@ -148,9 +145,14 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf) return git__throw(GIT_ERROR, "Failed to close memory window. Couln't find LRU"); } -static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t size, git_off_t offset) +static git_mwindow *new_window( + git_mwindow_file *mwf, + git_file fd, + git_off_t size, + git_off_t offset) { - size_t walign = ctl.window_size / 2; + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; + size_t walign = _mw_options.window_size / 2; git_off_t len; git_mwindow *w; @@ -162,16 +164,16 @@ static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t siz w->offset = (offset / walign) * walign; len = size - w->offset; - if (len > (git_off_t)ctl.window_size) - len = (git_off_t)ctl.window_size; + if (len > (git_off_t)_mw_options.window_size) + len = (git_off_t)_mw_options.window_size; - ctl.mapped += (size_t)len; + ctl->mapped += (size_t)len; - while(ctl.mapped_limit < ctl.mapped && - git_mwindow_close_lru(mwf) == GIT_SUCCESS) {} + while (_mw_options.mapped_limit < ctl->mapped && + git_mwindow_close_lru(mwf) == GIT_SUCCESS) /* nop */; /* - * We treat ctl.mapped_limit as a soft limit. If we can't find a + * We treat _mw_options.mapped_limit as a soft limit. If we can't find a * window to close and are above the limit, we still mmap the new * window. */ @@ -179,14 +181,14 @@ static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t siz if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS) goto cleanup; - ctl.mmap_calls++; - ctl.open_windows++; + ctl->mmap_calls++; + ctl->open_windows++; - if (ctl.mapped > ctl.peak_mapped) - ctl.peak_mapped = ctl.mapped; + if (ctl->mapped > ctl->peak_mapped) + ctl->peak_mapped = ctl->mapped; - if (ctl.open_windows > ctl.peak_open_windows) - ctl.peak_open_windows = ctl.open_windows; + if (ctl->open_windows > ctl->peak_open_windows) + ctl->peak_open_windows = ctl->open_windows; return w; @@ -199,9 +201,14 @@ cleanup: * Open a new window, closing the least recenty used until we have * enough space. Don't forget to add it to your list */ -unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, - git_off_t offset, int extra, unsigned int *left) +unsigned char *git_mwindow_open( + git_mwindow_file *mwf, + git_mwindow **cursor, + git_off_t offset, + int extra, + unsigned int *left) { + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; git_mwindow *w = *cursor; if (!w || !git_mwindow_contains(w, offset + extra)) { @@ -229,7 +236,7 @@ unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, /* If we changed w, store it in the cursor */ if (w != *cursor) { - w->last_used = ctl.used_ctr++; + w->last_used = ctl->used_ctr++; w->inuse_cnt++; *cursor = w; } @@ -245,13 +252,14 @@ unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, int git_mwindow_file_register(git_mwindow_file *mwf) { + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; int error; - if (ctl.windowfiles.length == 0 && - (error = git_vector_init(&ctl.windowfiles, 8, NULL)) < GIT_SUCCESS) + if (ctl->windowfiles.length == 0 && + (error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS) return error; - return git_vector_insert(&ctl.windowfiles, mwf); + return git_vector_insert(&ctl->windowfiles, mwf); } void git_mwindow_close(git_mwindow **window) diff --git a/src/mwindow.h b/src/mwindow.h index ec75f901f..11c3aa840 100644 --- a/src/mwindow.h +++ b/src/mwindow.h @@ -10,7 +10,6 @@ #include "map.h" #include "vector.h" -#include "fileops.h" typedef struct git_mwindow { struct git_mwindow *next; @@ -29,8 +28,6 @@ typedef struct git_mwindow_file { typedef struct git_mwindow_ctl { size_t mapped; unsigned int open_windows; - size_t window_size; /* needs default value */ - size_t mapped_limit; /* needs default value */ unsigned int mmap_calls; unsigned int peak_open_windows; size_t peak_mapped; diff --git a/src/pack.c b/src/pack.c index 429bb5e0f..ae954b988 100644 --- a/src/pack.c +++ b/src/pack.c @@ -5,11 +5,13 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "mwindow.h" +#include "common.h" #include "odb.h" #include "pack.h" #include "delta-apply.h" #include "sha1_lookup.h" +#include "mwindow.h" +#include "fileops.h" #include "git2/oid.h" #include "git2/zlib.h" diff --git a/src/thread-utils.h b/src/thread-utils.h index 3361ed8bc..c5554799c 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_thread_utils_h__ #define INCLUDE_thread_utils_h__ - +#include "common.h" /* Common operations even if threading has been disabled */ typedef struct { -- cgit v1.2.1 From 7b6156108c8559cd2a4fd91b34411caf9cdd7d20 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Wed, 16 Nov 2011 10:22:13 -0800 Subject: Fix docs about the command to mix the clay tests --- tests-clay/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clay/README.md b/tests-clay/README.md index 4939f5717..f3e54d6c6 100644 --- a/tests-clay/README.md +++ b/tests-clay/README.md @@ -11,7 +11,7 @@ https://github.com/tanoku/clay * Mix the tests: - ./clay + ./clay . * Make sure you actually build the tests by setting: -- cgit v1.2.1 From 7096d0f9e47d39a8fd4f315a7633f3b86a7d6c93 Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Wed, 16 Nov 2011 11:36:13 -0800 Subject: refs: use 0666 permissions when writing packed-refs, not 0644 This matches stock Git's behavior. --- src/refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refs.c b/src/refs.c index 05f935796..4f32f4400 100644 --- a/src/refs.c +++ b/src/refs.c @@ -16,7 +16,7 @@ #define MAX_NESTING_LEVEL 5 -#define GIT_PACKED_REFS_FILE_MODE 0644 +#define GIT_PACKED_REFS_FILE_MODE 0666 enum { GIT_PACKREF_HAS_PEEL = 1, -- cgit v1.2.1 From 9788e72ad4443dbcaa7aef92f09aaba7ffc3a98b Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Wed, 16 Nov 2011 11:39:03 -0800 Subject: refs: move GIT_PACKED_REFS_FILE_MODE to refs.h as GIT_PACKEDREFS_FILE_MODE This groups the #define with the other ref-related file modes, and it makes the name consistent with the other packed-refs definitions. --- src/refs.c | 4 +--- src/refs.h | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/refs.c b/src/refs.c index 4f32f4400..569efbf78 100644 --- a/src/refs.c +++ b/src/refs.c @@ -16,8 +16,6 @@ #define MAX_NESTING_LEVEL 5 -#define GIT_PACKED_REFS_FILE_MODE 0666 - enum { GIT_PACKREF_HAS_PEEL = 1, GIT_PACKREF_WAS_LOOSE = 2 @@ -804,7 +802,7 @@ cleanup: /* if we've written all the references properly, we can commit * the packfile to make the changes effective */ if (error == GIT_SUCCESS) { - error = git_filebuf_commit(&pack_file, GIT_PACKED_REFS_FILE_MODE); + error = git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE); /* when and only when the packfile has been properly written, * we can go ahead and remove the loose refs */ diff --git a/src/refs.h b/src/refs.h index 02e336e54..c90f5bcc4 100644 --- a/src/refs.h +++ b/src/refs.h @@ -24,6 +24,7 @@ #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " +#define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_HEAD_FILE "HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" -- cgit v1.2.1 From a07d899449b18b39c39e0bdbbb7653e92a91c1fb Mon Sep 17 00:00:00 2001 From: Andy Lester Date: Wed, 16 Nov 2011 17:33:02 -0600 Subject: Quoted the asterisk to avoid markdown highlighter confusion --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82517bc48..6ba9e6407 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Building libgit2 - Using CMake ============================== libgit2 builds cleanly on most platforms without any external dependencies. -Under Unix-like systems, like Linux, * BSD and Mac OS X, libgit2 expects `pthreads` to be available; +Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthreads` to be available; they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API for threading. -- cgit v1.2.1 From 9432af36fc62ee22d76fb927b8be73e123ba3f3c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 17 Nov 2011 01:23:19 +0100 Subject: Rename `git_tree_frompath` to `git_tree_get_subtree` That makes more sense to me. --- include/git2/tree.h | 14 +++++----- src/tree.c | 56 +++++++++++++++++++++++++++++---------- tests-clay/object/tree/frompath.c | 2 +- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/include/git2/tree.h b/include/git2/tree.h index 68d82351a..2ff167f44 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -269,19 +269,19 @@ GIT_EXTERN(void) git_treebuilder_filter(git_treebuilder *bld, int (*filter)(cons GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld); /** - * Retrieve the tree object containing a tree entry, given - * a relative path to this tree entry + * Retrieve a subtree contained in a tree, given its + * relative path. * * The returned tree is owned by the repository and * should be closed with the `git_object_close` method. * - * @param parent_out Pointer where to store the parent tree + * @param subtree Pointer where to store the subtree * @param root A previously loaded tree which will be the root of the relative path - * @param treeentry_path Path to the tree entry from which to extract the last tree object - * @return GIT_SUCCESS on success; GIT_ENOTFOUND if the path does not lead to an - * entry, GIT_EINVALIDPATH or an error code + * @param subtree_path Path to the contained subtree + * @return GIT_SUCCESS on success; GIT_ENOTFOUND if the path does not lead to a + * subtree, GIT_EINVALIDPATH or an error code */ -GIT_EXTERN(int) git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path); +GIT_EXTERN(int) git_tree_get_subtree(git_tree **subtree, git_tree *root, const char *subtree_path); /** Callback for the tree traversal method */ typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry); diff --git a/src/tree.c b/src/tree.c index 6efedcff5..458689196 100644 --- a/src/tree.c +++ b/src/tree.c @@ -610,7 +610,11 @@ void git_treebuilder_free(git_treebuilder *bld) git__free(bld); } -static int tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path, int offset) +static int tree_frompath( + git_tree **parent_out, + git_tree *root, + const char *treeentry_path, + int offset) { char *slash_pos = NULL; const git_tree_entry* entry; @@ -618,15 +622,21 @@ static int tree_frompath(git_tree **parent_out, git_tree *root, const char *tree git_tree *subtree; if (!*(treeentry_path + offset)) - return git__rethrow(GIT_EINVALIDPATH, "Invalid relative path to a tree entry '%s'.", treeentry_path); + return git__rethrow(GIT_EINVALIDPATH, + "Invalid relative path to a tree entry '%s'.", treeentry_path); slash_pos = (char *)strchr(treeentry_path + offset, '/'); if (slash_pos == NULL) - return git_tree_lookup(parent_out, root->object.repo, git_object_id((const git_object *)root)); + return git_tree_lookup( + parent_out, + root->object.repo, + git_object_id((const git_object *)root) + ); if (slash_pos == treeentry_path + offset) - return git__rethrow(GIT_EINVALIDPATH, "Invalid relative path to a tree entry '%s'.", treeentry_path); + return git__rethrow(GIT_EINVALIDPATH, + "Invalid relative path to a tree entry '%s'.", treeentry_path); *slash_pos = '\0'; @@ -636,28 +646,44 @@ static int tree_frompath(git_tree **parent_out, git_tree *root, const char *tree *slash_pos = '/'; if (entry == NULL) - return git__rethrow(GIT_ENOTFOUND, "No tree entry can be found from the given tree and relative path '%s'.", treeentry_path); + return git__rethrow(GIT_ENOTFOUND, + "No tree entry can be found from " + "the given tree and relative path '%s'.", treeentry_path); - if ((error = git_tree_lookup(&subtree, root->object.repo, &entry->oid)) < GIT_SUCCESS) + + error = git_tree_lookup(&subtree, root->object.repo, &entry->oid); + if (error < GIT_SUCCESS) return error; - error = tree_frompath(parent_out, subtree, treeentry_path, slash_pos - treeentry_path + 1); + error = tree_frompath( + parent_out, + subtree, + treeentry_path, + slash_pos - treeentry_path + 1 + ); git_tree_close(subtree); return error; } -int git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path) +int git_tree_get_subtree( + git_tree **subtree, + git_tree *root, + const char *subtree_path) { char buffer[GIT_PATH_MAX]; - assert(root && treeentry_path); + assert(subtree && root && subtree_path); - strcpy(buffer, treeentry_path); - return tree_frompath(parent_out, root, buffer, 0); + strncpy(buffer, subtree_path, GIT_PATH_MAX); + return tree_frompath(subtree, root, buffer, 0); } -static int tree_walk_post(git_tree *tree, git_treewalk_cb callback, char *root, size_t root_len) +static int tree_walk_post( + git_tree *tree, + git_treewalk_cb callback, + char *root, + size_t root_len) { int error; unsigned int i; @@ -673,13 +699,15 @@ static int tree_walk_post(git_tree *tree, git_treewalk_cb callback, char *root, if (ENTRY_IS_TREE(entry)) { git_tree *subtree; - if ((error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid)) < 0) + if ((error = git_tree_lookup( + &subtree, tree->object.repo, &entry->oid)) < 0) return error; strcpy(root + root_len, entry->filename); root[root_len + entry->filename_len] = '/'; - tree_walk_post(subtree, callback, root, root_len + entry->filename_len + 1); + tree_walk_post(subtree, + callback, root, root_len + entry->filename_len + 1); git_tree_close(subtree); } diff --git a/tests-clay/object/tree/frompath.c b/tests-clay/object/tree/frompath.c index 33a76e8aa..1effcb1db 100644 --- a/tests-clay/object/tree/frompath.c +++ b/tests-clay/object/tree/frompath.c @@ -29,7 +29,7 @@ static void assert_tree_from_path(git_tree *root, const char *path, git_error ex { git_tree *containing_tree = NULL; - cl_assert(git_tree_frompath(&containing_tree, root, path) == expected_result); + cl_assert(git_tree_get_subtree(&containing_tree, root, path) == expected_result); if (containing_tree == NULL && expected_result != GIT_SUCCESS) return; -- cgit v1.2.1 From 2ba14f2367b14187e1714f32c11236476c22ddfa Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 17 Nov 2011 02:13:46 +0100 Subject: tree: Add payload to `git_tree_walk` --- include/git2/tree.h | 4 ++-- src/tree.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/git2/tree.h b/include/git2/tree.h index 2ff167f44..bd89de34f 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -284,7 +284,7 @@ GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_tr GIT_EXTERN(int) git_tree_get_subtree(git_tree **subtree, git_tree *root, const char *subtree_path); /** Callback for the tree traversal method */ -typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry); +typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry, void *payload); /** Tree traversal modes */ enum git_treewalk_mode { @@ -310,7 +310,7 @@ enum git_treewalk_mode { * @param mode Traversal mode (pre or post-order) * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_tree_walk(git_tree *walk, git_treewalk_cb callback, int mode); +GIT_EXTERN(int) git_tree_walk(git_tree *walk, git_treewalk_cb callback, int mode, void *payload); /** @} */ GIT_END_DECL diff --git a/src/tree.c b/src/tree.c index 458689196..92ca5ab77 100644 --- a/src/tree.c +++ b/src/tree.c @@ -683,7 +683,8 @@ static int tree_walk_post( git_tree *tree, git_treewalk_cb callback, char *root, - size_t root_len) + size_t root_len, + void *payload) { int error; unsigned int i; @@ -693,7 +694,7 @@ static int tree_walk_post( root[root_len] = '\0'; - if (callback(root, entry) < 0) + if (callback(root, entry, payload) < 0) continue; if (ENTRY_IS_TREE(entry)) { @@ -707,7 +708,10 @@ static int tree_walk_post( root[root_len + entry->filename_len] = '/'; tree_walk_post(subtree, - callback, root, root_len + entry->filename_len + 1); + callback, root, + root_len + entry->filename_len + 1, + payload + ); git_tree_close(subtree); } @@ -716,14 +720,14 @@ static int tree_walk_post( return GIT_SUCCESS; } -int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode) +int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload) { char root_path[GIT_PATH_MAX]; root_path[0] = '\0'; switch (mode) { case GIT_TREEWALK_POST: - return tree_walk_post(tree, callback, root_path, 0); + return tree_walk_post(tree, callback, root_path, 0, payload); case GIT_TREEWALK_PRE: return git__throw(GIT_ENOTIMPLEMENTED, -- cgit v1.2.1 From d1a721c5953c6eaee52042e6ace57f6d7e2cc4ba Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 17 Nov 2011 06:01:09 +0100 Subject: clay: Bump to 0.9.0, add TAP support Comes with schu's stress tests for config files. Hopefully the diffs will stay minimal from now on. --- tests-clay/clay | 217 ++++++++++------ tests-clay/clay.h | 81 +++--- tests-clay/clay_libgit2.h | 2 +- tests-clay/clay_main.c | 602 +++++++++++++++++++++++++-------------------- tests-clay/config/stress.c | 41 +++ 5 files changed, 565 insertions(+), 378 deletions(-) create mode 100644 tests-clay/config/stress.c diff --git a/tests-clay/clay b/tests-clay/clay index d042a2a1c..a40f6601a 100755 --- a/tests-clay/clay +++ b/tests-clay/clay @@ -4,13 +4,13 @@ from __future__ import with_statement from string import Template import re, fnmatch, os -VERSION = "0.8.0" +VERSION = "0.9.0" -TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*(void)?\s*\))\s*\{" +TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*void\s*\))\s*\{" CLAY_HEADER = """ /* - * Clay v0.7.0 + * Clay v0.9.0 * * This is an autogenerated file. Do not modify. * To add new unit tests or suites, regenerate the whole @@ -18,27 +18,17 @@ CLAY_HEADER = """ */ """ -TEMPLATE_SUITE = Template( -r""" - { - "${clean_name}", - ${initialize}, - ${cleanup}, - ${cb_ptr}, ${cb_count} - } -""") - def main(): from optparse import OptionParser parser = OptionParser() parser.add_option('-c', '--clay-path', dest='clay_path') - parser.add_option('-v', '--report-to', dest='print_mode', default='stdout') + parser.add_option('-v', '--report-to', dest='print_mode', default='default') options, args = parser.parse_args() - for folder in args: + for folder in args or ['.']: builder = ClayTestBuilder(folder, clay_path = options.clay_path, print_mode = options.print_mode) @@ -47,17 +37,22 @@ def main(): class ClayTestBuilder: - def __init__(self, path, clay_path = None, print_mode = 'stdout'): + def __init__(self, path, clay_path = None, print_mode = 'default'): self.declarations = [] - self.callbacks = [] - self.suites = [] - self.suite_list = [] + self.suite_names = [] + self.callback_data = {} + self.suite_data = {} self.clay_path = os.path.abspath(clay_path) if clay_path else None - self.print_mode = print_mode self.path = os.path.abspath(path) - self.modules = ["clay_sandbox.c", "clay_fixtures.c", "clay_fs.c"] + self.modules = [ + "clay_sandbox.c", + "clay_fixtures.c", + "clay_fs.c" + ] + + self.modules.append("clay_print_%s.c" % print_mode) print("Loading test suites...") @@ -66,7 +61,6 @@ class ClayTestBuilder: module_root = [c for c in module_root.split(os.sep) if c] tests_in_module = fnmatch.filter(files, "*.c") - tests_in_module.sort() for test_file in tests_in_module: full_path = os.path.join(root, test_file) @@ -75,51 +69,107 @@ class ClayTestBuilder: with open(full_path) as f: self._process_test_file(test_name, f.read()) - if not self.suites: + if not self.suite_data: raise RuntimeError( 'No tests found under "%s"' % folder_name) def render(self): main_file = os.path.join(self.path, 'clay_main.c') with open(main_file, "w") as out: - template = Template(self._load_file('clay.c')) + out.write(self._render_main()) + + header_file = os.path.join(self.path, 'clay.h') + with open(header_file, "w") as out: + out.write(self._render_header()) + + print ('Written Clay suite to "%s"' % self.path) + + ##################################################### + # Internal methods + ##################################################### + + def _render_cb(self, cb): + return '{"%s", &%s}' % (cb['short_name'], cb['symbol']) + + def _render_suite(self, suite): + template = Template( +r""" + { + "${clean_name}", + ${initialize}, + ${cleanup}, + ${cb_ptr}, ${cb_count} + } +""") - output = template.substitute( - clay_print = self._get_print_method(), - clay_modules = self._get_modules(), + callbacks = {} + for cb in ['initialize', 'cleanup']: + callbacks[cb] = (self._render_cb(suite[cb]) + if suite[cb] else "{NULL, NULL}") + + return template.substitute( + clean_name = suite['name'].replace("_", "::"), + initialize = callbacks['initialize'], + cleanup = callbacks['cleanup'], + cb_ptr = "_clay_cb_%s" % suite['name'], + cb_count = suite['cb_count'] + ).strip() - suites_str = ", ".join(self.suite_list), + def _render_callbacks(self, suite_name, callbacks): + template = Template( +r""" +static const struct clay_func _clay_cb_${suite_name}[] = { + ${callbacks} +}; +""") + callbacks = [ + self._render_cb(cb) + for cb in callbacks + if cb['short_name'] not in ('initialize', 'cleanup') + ] + + return template.substitute( + suite_name = suite_name, + callbacks = ",\n\t".join(callbacks) + ).strip() - test_callbacks = ",\n\t".join(self.callbacks), - cb_count = len(self.callbacks), + def _render_header(self): + template = Template(self._load_file('clay.h')) - test_suites = ",\n\t".join(self.suites), - suite_count = len(self.suites), - ) + declarations = "\n".join( + "extern %s;" % decl + for decl in sorted(self.declarations) + ) - out.write(output) + return template.substitute( + extern_declarations = declarations, + ) - header_file = os.path.join(self.path, 'clay.h') - with open(header_file, "w") as out: - template = Template(self._load_file('clay.h')) + def _render_main(self): + template = Template(self._load_file('clay.c')) + suite_names = sorted(self.suite_names) - output = template.substitute( - extern_declarations = "\n".join(self.declarations), - ) + suite_data = [ + self._render_suite(self.suite_data[s]) + for s in suite_names + ] - out.write(output) + callbacks = [ + self._render_callbacks(s, self.callback_data[s]) + for s in suite_names + ] - print ('Written Clay suite to "%s"' % self.path) + callback_count = sum( + len(cbs) for cbs in self.callback_data.values() + ) - ##################################################### - # Internal methods - ##################################################### - def _get_print_method(self): - return { - 'stdout' : 'printf(__VA_ARGS__)', - 'stderr' : 'fprintf(stderr, __VA_ARGS__)', - 'silent' : '' - }[self.print_mode] + return template.substitute( + clay_modules = self._get_modules(), + clay_callbacks = "\n".join(callbacks), + clay_suites = ",\n\t".join(suite_data), + clay_suite_count = len(suite_data), + clay_callback_count = callback_count, + ) def _load_file(self, filename): if self.clay_path: @@ -151,52 +201,67 @@ class ClayTestBuilder: return comment - def _process_test_file(self, test_name, contents): - regex_string = TEST_FUNC_REGEX % test_name + def _process_test_file(self, suite_name, contents): + regex_string = TEST_FUNC_REGEX % suite_name regex = re.compile(regex_string, re.MULTILINE) callbacks = [] - initialize = cleanup = "{NULL, NULL, 0}" + initialize = cleanup = None - for (declaration, symbol, short_name, _) in regex.findall(contents): - self.declarations.append("extern %s;" % declaration) - func_ptr = '{"%s", &%s, %d}' % ( - short_name, symbol, len(self.suites) - ) + for (declaration, symbol, short_name) in regex.findall(contents): + data = { + "short_name" : short_name, + "declaration" : declaration, + "symbol" : symbol + } if short_name == 'initialize': - initialize = func_ptr + initialize = data elif short_name == 'cleanup': - cleanup = func_ptr + cleanup = data else: - callbacks.append(func_ptr) + callbacks.append(data) if not callbacks: return - clean_name = test_name.replace("_", "::") + tests_in_suite = len(callbacks) - suite = TEMPLATE_SUITE.substitute( - clean_name = clean_name, - initialize = initialize, - cleanup = cleanup, - cb_ptr = "&_all_callbacks[%d]" % len(self.callbacks), - cb_count = len(callbacks) - ).strip() + suite = { + "name" : suite_name, + "initialize" : initialize, + "cleanup" : cleanup, + "cb_count" : tests_in_suite + } + + if initialize: + self.declarations.append(initialize['declaration']) + + if cleanup: + self.declarations.append(cleanup['declaration']) + + self.declarations += [ + callback['declaration'] + for callback in callbacks + ] + + callbacks.sort(key=lambda x: x['short_name']) + self.callback_data[suite_name] = callbacks + self.suite_data[suite_name] = suite + self.suite_names.append(suite_name) - self.callbacks += callbacks - self.suites.append(suite) - self.suite_list.append(clean_name) + print(" %s (%d tests)" % (suite_name, tests_in_suite)) - print(" %s (%d tests)" % (clean_name, len(callbacks))) CLAY_FILES = { -"clay.c" : r"""eJy9GWtT20jys/wrZk3AEggHyDd74SqVu1xRl2WrAqlsFaFUsjTGc9HDqxkFONb//brnpdHLux+uji+gnu6efndPc8CKJKtTSn6OOaeVmG+uJgcWxqn4d77twESasVUPxsouqGLFYxuWx2KDkMnbY1LR32tW0ZSsy4rwuEhX5TMQkOO3LpMX/la8bCnv8AYwF7EUdnKQ0jUrKEmy+CXawqXCn8/nAXnz2kB2gMbWgEiir9c37y4mB55l9sSKtHxSNzRQrU4D4BuaZfGWdcAp6JBoQTwtSfTL++ub6MMHEkVJSpPMOUKp/S2YIYQ/AxK1vxu8/Dsw1gd5mVJAbUAOXrKxQBI5Hw1GnCSU8zarPsyVsErrrQ+/pHj2A5Vg60LaMPrl+uafX99dRBEAvW0VP+YxSco8p2B8CI6QTKW53l1MkbPDuki2L74oQ7Kuyjwkoow4+w+IpI8iLg812GBFd5+/3Hx4f/cPl9nX6Nd/kbMLB3IbXd/+/fqz/xwQ338mRyQCyEeABOSnS3LmEuffBc23kTFBRgtp4B4QSGiRsvXEwyhE3UHQOhHKceT27v1ddLecHNCM01awQIA+xQzjgkCs459blvoXgQzvBq8uGKSOCqlO8PSu7NwoxWpyYorBPt9MJxPEYwn5UTLILR5VuZ+UBRcQKnFFjiNe1lVCg2UXLynBMwOYIXGBKYUwXdpL3KPJmj2LuqIRmq/FaRXzDhuDWsQ5VeykijJhaVVBRXideC6BgHuXEzCcIPhnVNT5ilbLNhKvmaAd2JplVBNmYN5hQnlllPNHhBs9k4ptBSsLEM/ry3dc0GeQaNfYQuN0BI8TwX7QSMs/cKKFViLKD3UDN+qWIs4syDFBUtaFGBHOchg4y2Igln8jsXS/f5yVCdySZDQu6m3gS+gxeEadt4/BwS9ZGadIDt0hWtVrIqo435ZoYSO2BUS0iFcZBfQdlCgQpOPvdV0kXathXCytcFsoP1IkFAgLQ2QsVRgPNOzkwQi/3rWsYILFGbAcOtX6Wr/1EGRY8kYo1y8oF6T+R6hgWjDV4+YJ1gA3+eRpXehzo6jGQFu65ObY5TCRCFVdyDDz94sbjh831tiDZGJk8qocrXIHUC+Vd+ftGJ54CtqPByA4lwG9Jr6aM/wuakAusXCjNyVaI+DpFQQFlvWbL58+BXDsdc58tJHnocb229vtF+fMiKNwWkHv3jVwPERi8iQwbDW8J7sLV3JrIW04nZwgVE5NefkDmnrxQuRdp2A5E6ckp2JTphzja0hGom5cDh4aYS0SREAzUE0Pk2lo7OI6mFzZAAjI38js44wsyGw+Ay12AzEquSlSH4MHqrFpDGNVTAaaKwohh2lAPsYsgw6y+FaAYMAm6EnMF4tDTvxDHpB7+DhMH8j9qYBfSAJWl9xPr6Q2zrfOEW9alMTpAi4J9hTn0+krHT4a2pMNVOBScI1r+48NFX3gCNAOmHFeDknvXsAbcUxFt2WlPcNVjTEJzlSijraZ0PTCiVLdFgLbhJ42YDCtk1VDJjUSAr4WXbFx1TOhcnKi9cMs9tYVpQMW6pzJTyORZr0bVh4qpwwDvx+Kqp2o0UKF4p7aChdJROV9pzGwJqndtt/g6wY1kGC6LOEryWfyCzzys3uP7jjk5IQpq7Yu0nLhr3v2MNcXee2WcaSPQ3KkGTu9wMJM6d9vSHjEZUOW/JMW1DP0mC3+uh37FjAIk47+Uqq/qPuQ4jWPH2lr5o2rR6mFDOO1P/2CGAvIVXJfymjlUIdk3iLmskH8VZ0uVK5aMCGn4rffvolv4nNdkLLIXojYUKkUUVWGwHGPhg/QKJN1iegzE/7p+VjhjitOIxCV+6oqwJ9JqHVFZX/sGxniLFvFyXce2oRIVipq/zQUHBoVCpKsKU6t3DhXuYGyOelgHVLj+xTQUFwI9qU5wzjBOd/zdE+SowOWYUN0f/aAhWt2OpOzhuNzyevsQU0bipG6QdGdy1uAJYaoqESZWZ7khFxAfJnPkJyfBfbiRly89tvZjPzxB0oG2p3tFYE/MZFsQHIpijYAvL/ITMwWck4C7r6yaIAMry6tMxQ21FAdQPA0hcSDx/ydE2WHKUlLyklRwuz3DM/XudOCkboJJPjAiavdr25FXAkYt3zVoAPdjUFy6e57Gyz3wPJB53+hCpdC7GCYN6TnFDVdhI7aqCabRy9RMq8qGn+XDJXh+Kjh3Igcs92tm23/U+MdS9sRrZJri5YpZGM7crC6WqZ0HdeZWIyGFUrSqvggiyoL+r2xvyA4j3OOG6X/f6VwTfgJhlywIHhCUS3M/IQDaeBQGsuiyM4I7zzFApmN0vEdt6Mppziiwk2iNOvNpmKDYwpaofMlJuYX7j6fWJaRbVUmFOggkTdlLZzd6FyX6p0WBk0OA/i5zvJOnVYO0Z5wsiZsTKo1DFsGQ1V3BDdakm0zwQyGohIJLTA0oPRGkz0+BFITpao2d2OYN6HYHWu1YQZG2WYGbl7YiFpRUVeFnlTbOxZg3zS+SK3FdZCD9CnDwhr2t0xhs2UKR9ZLHbgzu2piDh7P0ihegQYycseGbhuPRiBsCkondxBHp5eJfw4eBjeWGJ8dfkHQfvSaSav72rUTWOt6/ZC0G6WBV7I9U/O9y6FH7Zw5ryj7oGjv0vrvLIvo7mFa77wuK7MxdB52gKJ3hv3nHZzpFVf34WZEV0tEZZyRx9vA0+7SbN27j7f+DIybAK8ftWpBIFcpbgjZzclPY2sPnZYD9QsLGFyg9FqQuLNmIFXMOJSpuIBOllAp83yqeovbxWQTy8ricWjBExKFtTNJB5dEnAq7VtEbwO5iMlSbs+NyG/9eu8+F7sKjWeHt33koRjL39f+N8jKtM8p3nV13r2dFkGJRM088ALPXCYGfN68qDM3Rzl0Wj5VByU1XwR4rBR/gI8tJ1LQrSTp989pAdlOgwQpj/zeVx6zwu41b9vwHtCdeq2uk0+mJ/nF6i3tvaBHaVgnxn3G66ew6SKYFaWk1ksSRb5H/AuhDZ38=""", +"clay.c" : r"""eJydWVtv3DYWftb8CnayjTW2PL7kzdMYCLKbwtjWBRIHKRAbAkfieLiRSFWkYnvT+e89PCQl6jJO0bx4dG48PJePh8wLLrKiyRn5iSrFar3cXs5etDTF9P/KakDTecHXIxqXQ1LNxX2fVlK9HSnSGqVmJ4ekZn80vGY52ciaKCrytXwEI+TwJFR5Uif6qWJqYAnISlPcAJA3OduQ9NPV9avz2YuolXrgIpcPVrWjOt87gtqyoqAVH5BzcC5zK0SwABeMpL++ubpO374laZrlLCsClnEnrmDPCfxckLT/3cmVX8CwY5QyZyDakQK5bNsSSRp8dBI0y5hSfVNjWuhhnTdVDH/QvfbDbIJvBMYw/fXq+udPr87TFIhRVdP7kpJMliUTOoZKSMgcw/XqfG4sB6ZFVj3FWiZkU8syIVqmiv8fXHKsVCHTkb1UevP+4/XbNzf/CY19Sn/7Lzk9Dygf0qsP/756Hz8uSBw/kpckBco7oCzID6/JaahcftGsrFIfgoIJDPCICCpM5Hwzi0x5mb2Do02mbeLIh5s3N+nNavaCFYr1igUq74FyUxcEitj8rHgeny+wbju5RnAod1tSg+IZLTlYEd3qin2eFfRpuZ3PZkaOZ+Sr5NA0Kq3LOJNCaSgVWpPDVMmmzthiNZTLJGRmQjIhITFnUKardpGQNdvwR93ULDXh61laUzUw40UFLZk1h1s0e0hZXUOrf5tFoYKGdVczCJwm5mcqmnLN6lVfSDVcswFtwwvmFAsI77QiLpmW6t7Q/T6zmleaSwHuRWP/DgV7BI92XSyczMBxmmn+laXO/wmOc9q6iB92BeW3KzUtWlIQgkw2Qu9xrrUwwSsoKONvo4zpjw8LmcEqWcGoaKpFjNRDyIzl99mQ4KdC0tyow1GQrpsN0TUtK2ki7N1uCSkTdF0wEN8BRIEjg3xvGpENo2bqYtU6VwH8oEsLH/BOGyO2R320Chdcc1oAtExx3fbaNI0EsAoxqmAh7afB+AWd/g4Ay2pUcNbp9HCZmZYPey3gGn/ifkIT0tWBI4xKHNtGDVo4MKu2jYYjTXzftCHY4kfCfpMohPaggbxL+wpvvxkpjDvxsLNxQ9aboLstYUOhg/PnTOKO4ukoPadH17Lu+wIIkJDlcrkYJtMNHnuS2QjH90XqJIz7obpnG9tvGi3vmWA11TDcmF2TnGpK1k+oYtb51zdUhs4r1jT7onYD2B23Qdr9Vp/vyGvoCwL/nCFL3/UwyxZyoGcLAVRDJUvcrSbVvH9DzT7d9cdbWTO7W9NRBl7VIKQzVK4bgZgZP9+MyX521+vPCHnAm32zqGV7QZld4OaWfUCeRZY6BjdQOEN03pDYTsjxUHRBXpspxGAVinUOHl8CwpkZ5frjL78sgB0NeLEpmigyO26/o93z7px6d6xMD8HDtSbYUyoe9BferKOPfA/p1m/nZItDR0eGirN9Kb/ChCqeCK51DJHzKExKprcyx+qY8pHYFVeTTO9sKwQVMAKhNqAIPm0kArwEWjwuA3LZlgns1xxJs4n6ZRWAi9Owfe9rjNta2XtsJ362mEWW7GuxPdQftgCJJLZcH3qsK6MI8siBjaGZKNy7w/Gjo4R4qI6iTc1Y7HSCwWfAw0/vkTPd1aCLjfe1GzLaHEyGCdo8hO8xpFksx+A9BwSwCgoeXw7OaD5Kvl3PSfsB1O0inMk6k26cmCgF12bmbhpz/IL0/hS64uYDcnTEbYp6CznXzZ/P/G7pFor6EPjSsRPy0hkOsK2leSjDrOzwvktOzeXDXGpkTWtePJGcK4sP+zBXwd26mMrGdzB3lKx9wfr7gR6HyAvMBgFCr/5mcHbt1Wm0/0bR+/4cQet73AyWziaefzQSF+RHRT5LbBF1dytuxTwhRnLVCf5muRfAA/LJScsg5Fj//vutvtXvG0GkgJzorTsR7dRDgI1aoY6a0LGxGyqxRxgpj8/2wFJFa8VScFbhLAc/ssTt1Wz2awdSvbI+s2VtxINKbmPUmHs/iBkLUKcrz6OZvT9FkRsc8RQzh4dX+nx6ZwDs4PgAj70gDWjr9M4efNaQXcHqneEqYNIUj661LFqb5IicQ+b9Z0LOThftwp27Ztnb0wPy55/GM9jd6bMuqAeusy14jq64AMC9lhyogws8ssF6bEFnYQxevh6PVVYt6uORHUPnH8J0/piTXDJFhISZ5JErvcQqAy6icBSkGT4MCgegYQHuZW8YBM07K7yuGf2CW8rZhjaFvti7bWPZgkk30No6wrbbX0HDK445SOFjMTUwJn1meD0BznyOR6wfOYJZeoEpw4BuXKconQPUGLVo/g6vDXB79o+GXZ9BjGDuNhFFyRugmRfFB14UpKplxkAPsr2VjQ5eHJeuwXbOGbNzGAXOXCkMusvGBQNidIh5IELB7liKRsfGKAK22b6bXH7nHZu6BP7z4LuBKHiAcMkY3HrM6jXTTS3IWAWBqEOg1L4pxxZmAGxzbhoqGb/aJN2rTbLnuWZAD2YXp6wgiUWeYothZe4butoS8w6ZqNs9hYOYiZ7M4rMEr0DSlNzA3mLRn7v92TccuNszsbf8aHgaD+otz853oYWJ0avlORV3mo5O2FVPwl3AW8HwocPL+aN7fJ53MiaNIOLe4BwxeIYDnnsycrw2s951+yhngxOkN4zLeHC1Z4J5uO5Ps1NTibmMTBS6vaPgbS4sofby9sO+m5eD+AmER9wGXIJF7N4uCB3cdkhNuQL0oQJQP2Po93JucTtEfAT8Qor7qXtmQqzUzjceLJLCzaq93blXteFjX2JfNA5lRf9owiFueO/q3smev3pZQ9j/7kmglHlTmCeImWnO9r9JSsrF6DTBY+jOuGGeMBy8dIdPD2B3s78AAFrlyw==""", +"clay_print_default.c" : r"""eJyFU01P4zAQPSe/YqgU1a5Cuafa3RunistqT4AiEztgKbUje9LVCvHfsccpOGhbTs48z3t+85HSo0DdwdFqCd0g/rWj0wZbbTSy8AGoPLadnQzWEGM/aVQnoLPGI3QvwsEmXRhxUJ6Xr2XBoiT/pO/KgqR7ttpbIZWESiY130DlH8yqhvgiX7yQq2YKv1E4VDKQAvpWlmeq8C8TSvvXfF9JBJRz1iXgXAUJypgfWEbelZ9GH0zyWJArp0brsKVczy5apxzybabDqdMe3dRhSqME2NBBdk9PQmgsh1uhh8mphvoaJHjuqvJNU3lgledwH4JKPsL9NYYjppdFQarXP6nQLI69iOHKWJDKd06PqO2C0ushZwzahPFNhyflvujM6MIXnBZhzktNPfhnytI9sPkiexyufsDdn/2eB/lzOlk6X07n8v5YE52yfM2T9bCPaWeyShLQh74r+XV/ImG3RIiTrXTVBb+JDb9gfbuGBtbb9Tf+aELs//8hmbjZgLF2hM3NcnuTo0vS4ins6kI6DKKG7XZLwkfRDjpcCfc87ij08adkMa4hzaw49nN5HmWYBeE1UXjiKCPZHL6V7yZUhjs=""", +"clay_print_tap.c" : r"""eJyFU8Fu2zAMPUdfwXoIYBuxgWK3Btuwnotih/U2wFBtORXmSIEkZyiG/ntJylnkNFlOMh+fyMdnSvggg25hb3UH7SBfm53TJjTa6JDjBwTlQ9Pa0YQVUOxHHdQBaK3xAdoX6aCMCSO3yhfir1jkVLJI0PUc4xKIcb8+z35+/wF75by2Bm4//zJZkSRv63rZIbZK9GD+TYgL+v3LGDr7x1yfgQDlnHVT1aP247UL0iOWXF6Lo+Q4wWWFfI3lmXF7sNIHN7Yh0pgAJR+JKmSnbQCqqjpxCwDt9nKj4A6Wnm3jKtXXqHXrN3O6V+i8Dq930Es9fKjGUwN8qMb4nEqewRkq4XNmrwd1jkn4nDloc2B2KZPwBu14Vq4gS3QP+ZTqlG+d3gVappsv8Pj08FCIRVIzIZwKSFLF3Om6rq/9VWto0jx9GLxG9ALirsWQVUeALFcd/+FDq6XHUaGahKHwyIFvkBkbwP7O0IwMD8qlBf+F2E4sWD6Lc2pn3bRzPr8yAf/W/Pzbnsn8BGVZokg62MGE9/8W8hnlzFrgTq7IYG6wl82gMSXdZrfmECvhBYpXMK1vP8nw+NBHfMjZPZoE+HkDvL/7UwK3oBJFrKlMl0/hm3gHeFWmnA==""", "clay_sandbox.c" : r"""eJyNVV1P20AQfLZ/xRIkYpNATItaVSkPlaBVVEoiEgQSRJaxz+SEfY7uLmkD4r931+fEHwRahBST3Zudmb0xSgeahxDOAgl+mAQrfx7o2e2x9+XTtG/bypS50DZX/jJIeOTrdJ43OWEmlDZH9+kL1362rfHk28SfgNJ42uIxOAThULkLe0q7sHMCnmtblmR6IQV4676dsT8Ynw4u8cCh0n6aRcxt9hXPThCGTKkC9dof/nThhGD79kuNc8xFlW/O9H4Rx0x2QfEn5mtImHgw1Hd5LCIWg389uPj4wbYKHKOy6F4G0g+zhdBwAsf9Ro/BZ2KJRkl1O8UeNMRqTX6NUFerC/SUf5yZz6vx2eXocvh9cH7WssF6QYlgFZM46Y0zCQ5HHK8PHL6W4/vQ6XA3h2/MxuYHpvHB2RDhUzTGMibjl2QqndJcLBhNySuv10utZgTKlCKcr5y1d1jqrp0j6MqSLOvFxl/b6u3DIAY9Y9TNZSZShrZFGVOijX4GKwjESs+4eOiClivQGSwUgx7Oh/2e/QapFtVbBa8mLVOsMasQQ1K7LFHMQP9gesLS+YhAndPr4eWpa451wcA1Lt8uExGPja7JjCtQK6VZuhGU8EeGAmpaSHy4kDIXziULdYbFd8Qdvqns8D1Z6z8PjqoBWGY8gjzSC6ECEd1nfxz6Lo8pEajk3ZtSgNp3XrtUjVcDI1FNRDhDFcgSaVYMiZUv0wpYM4XoJ08iv6BglG54VG4vFXwd8CRPTivHI2tu8p8WpW0T2fVLox7wkoOJdxZXabkYoOqbh9yyLQTDaeg3PtRFNNU/A65eZDLFpT2xnC4tejQcD24Ak/o7kBGoJFAzpvIlV6JsvYoyiShD3NwHL/Zxl+/DsholaPfam6htFtHAIGUHcDSlNy72m0H1eqdTgtE9Wl+7sgs6xLRbLmebszgGm7ZYRozSR4zJ3Ff/3E7jH4NZj0Gga1c97n32vK0HKgHHUzS4xhM9vbg6P391qDCwTFX9AucI/x8h2Nvbdue33z9CMbmqEt3qRY3eX120XBI=""", "clay_fixtures.c" : r"""eJyFUV1LwzAUfW5+xZU9rLUVJ4ggZQ9DFAUfRCZMRglZmrBAl5Qkk03xv9v0a82U+Zabc+45595rLLGCAlXSWKBrouEccbGzW81wSew6HCIrYljicTuqJBsWoS8UmFbPobXA8npye5OlFSI+GbaglbK4YDJFKOjeMAVjdfUInUPkyFZLWu7DWiKBxtgpKN78RZETEByactlLXcBVBmdTGF+OIxQEPhrHGdRQ1zzMv5xUYN84ROLY8b1MEPeTJEdsV3tRq0wdt06tWcWVzXpS9I3QSPCccbh7nr3jh6fF/O31Hr/M5o9ouGpa4NYlPHmBVt074i/lBLy+OsWHEjkcXLAhMl+p3Wk3bjBV1VIG6TxOApgWZN8s4k8bWjAit+W/NnoTejMddI+GqW1GTOaCox8pOffr""", "clay_fs.c" : r"""eJylVdtu20YQfSa/YkAD8TKWY8dJX6L0wXDEVqgsBhINN7UFhiGX1qIkl9hd+dLG/57ZCynJUWEkfZE0s7NnZufMGe2xsqAlpJfj6ZsT399DgzUUojhKo8npb3Mg+ud8PBlNE/hq/NP4LJ5G49n5aTKOp71zNJvFs4vx06DzPz6MZ6HvS5UplkO+zAS89EtWUd7KtM3UkuS8kcqdGE/o/+t71tYm/ArTi8lk6HuS/UNTBRVtbtRyAGzo+x4rgaQ2zMaFvucJqlaicdd8z15AHKkE/rbxIQI6+DqrKp4TF3YAJ2GH/AxwTeu8fTBRA0jtl0Xp0K+sucAsx9suzPPauX2v5AIIMxYweO9AhnBwwELAbvTFXLGFrmf/aF+X4/Uu2L++3scEjwjmitRnQ/+x7/0tZ0XXecIaBTUv6AC22i/5SuRPnQWVynAy/z3CSYg/zpPZxVkCJQLp4m2YvYqVbJHrEHU7bJgG+y7IZNBQf1HBz2nNxQN5oeEHoDnnJdlOHYa2aa18dRetmlxziI8ZOl8bCV5ruk3u3ptw9OlUnaeMquxGorOfd/OcKs2kpEKlBFuMibHUuKUCm8gbW1aoOTge4HFwyZqC30l4EgdlhmYR+J4tVVBK1q0wpnv0U4JkKmqygxTDQEdfFKcfRpNRMsKx6zgzM7oLL+c4oz9A80aSs/jjp40U6bpmA46t0vgVzZpVS7TLApg3lOwe55A6ivMqe3AKCV4GoQXZo5WkXbk4kr5c0qpK+UoRW5SrMBM3t1cLg60HV19YSS0nVuA+wE/dY/zSg8XF32StX/S9h2OrobIVeLskUhVUCM2eF8wfpKI1oM3FO/hsb3+GHDeCo/DVdRNozjx6zxQ5fB06lXXwehIsPr2n+S0xtR4vBqboLvguYwqD9YUBvLD1D/DesFfr5ejPcTJPTpOLObHn/4PLnkprmpJ+WQy3pbpeqNZOcenovvVCxm1ZIK0bEl4Hrpdpf2pbYs2rjchDs+f6nfVfAXYRuu6hGRx9Yc1R3gZD5zVBweGsd5wsNjVuXG+0y81O6KRuDt4u+r8Ro/B6JRWOo5RG5OuxM6QZYUeGfVAcdM9B6b3lRlpqr8ya4gu/363wZ0W9oekNjt4udvVA1N/1oNxuQvfiHc342TdbTYNa0u2XPiN9I/NV464Qs/e1a8PxiLJvClb63wD3Q6FA""", -"clay.h" : r"""eJy9Vctu2zAQPEdfsbV6sAQhTq9pGsAIbMSAERStg7YngqZWEVGZVEmqcVH030NSfkm2qqYHn0wtOTuzu0M65JlIMQNC7ubjb2Qx+bwg94QEoQ1ygUfxIOSCFVWKcKNNWvDlZX4bBD8lT4EV9BchVGtUZhhccGGASZFyw6VIggu71jaSUwVxxgtM6iOFZWntolJStWIpaqZ4ucnlgDqXVZESupTKRO93GohGQ1iBVFTl0MeG8eYzqr/jKIF6IUv6o0IL3mIz3YC6tCHPXH98F6azr4vHTxPycby4Dw7VOShfm0rhsFmmjxFBVw2WTVhTkS7l+jWQrbq/QEK0Pc+CYBTHAcQw9vOwbYMVZUpqeOYmB1yXBWfcgO81rFBr+oT2/Gg3ecu6qrQhpZ0oGVqASsBNIWoO2u9EcPsBrhLrlulsPiHEreazB78aTCvBvABGiwIyamefXsMAwn3OBN5FR8TuZD/xTSfvZF0iM5hC1hBgpNfQo6Am6ad/01235Ve2r46YaxDSgFEVnuLdzuouR/b9P+bEHO5Mg7qKjpnPPKlTEs4wqKuo51IJ+Y/XaSOpecPqYAIPj/P56cvQgtVd74Rtyt9hto5uArqt11fN3nR7jkMjdgrbe6YN7KnIH2pjOuqZSsWcoWxG+zaOnqkSXDy1a/AiTnimyykLtK9ufTEuB6cfjg3Ta7J+qSGQVsr9GEeCa2SVc9j14IT/vI4VmlymdtOSKOrOal/f29+4NqgEOdz5E2z/GF4ABeagMA==""" +"clay.h" : r"""eJy9Vctu2zAQPEdfwVo9WIIQp9c0DWAENmLACIrWQdsTQZOriKhMqiTVqCj67yUp+aGH46YHn0wtdzizu0M65KlgkCKM75bTb3g1+7zC9xgHoQ1yAb14EHJB85IButGG5Xx9md0GwU/JGaI5+YUx0RqUGQcXXBhEpWDccCmS4MKutY1kRKE45TkkdUpuWTq7oJRUnRgDTRUvmrMcUGeyzBkma6lM9H6nAWswmOZARFmMfWwcN59R/R1HCaoXsiA/SrDgLTbVLag7NuSp64/vwnzxdfX4aYY/Tlf3waE6B+WVKRWM22X6GBZk02JpwpoItpbVayBbdS9AQrA9T4NgEscBitHUz8O2DW0IVVKjZ24yBFWRc8oN8r1GG9CaPIHNn+wmb1k3pTa4sBPFYwtQCXJTiNqD9jsRuv2ArhLrlvliOcPYrZaLB78azUtBvQBK8hylxM6eXaMRCvdnJuhd1CN2maeJb47yzqoCqAGG0pYAI72GEwpqktP0b47XbfmV7asj5hoJaZBRJQzxbmd1lwH9/h9zog53pkFdRX3mM09qSMIZBnUVnbhUQv7jdWokDd2wh8flcvgqdECHPe+BmtJ3iLab6/TjpjtVx95ue4a+BXui9l7pwl6sxad0EYOVzKWizkT2NPseTp6JElw8ddV7AQM+OeaOFdiXtr4Ml6Phx6Jhes2pX2oIYqVyP8aRQAW0dK66Hg14zuvYgMkks5uWRBGXq319b39DZUAJfLjzJ9j+GfwFGCyeSg==""" } if __name__ == '__main__': main() diff --git a/tests-clay/clay.h b/tests-clay/clay.h index cbdf1381d..15e1770e0 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -37,16 +37,16 @@ void cl_fixture_cleanup(const char *fixture_name); /** * Assertion macros with no error message */ -#define cl_must_pass(expr) cl_must_pass_((expr), NULL) -#define cl_must_fail(expr) cl_must_fail_((expr), NULL) -#define cl_assert(expr) cl_assert_((expr), NULL) +#define cl_must_pass(expr) cl_must_pass_(expr, NULL) +#define cl_must_fail(expr) cl_must_fail_(expr, NULL) +#define cl_assert(expr) cl_assert_(expr, NULL) /** * Check macros with no error message */ -#define cl_check_pass(expr) cl_check_pass_((expr), NULL) -#define cl_check_fail(expr) cl_check_fail_((expr), NULL) -#define cl_check(expr) cl_check_((expr), NULL) +#define cl_check_pass(expr) cl_check_pass_(expr, NULL) +#define cl_check_fail(expr) cl_check_fail_(expr, NULL) +#define cl_check(expr) cl_check_(expr, NULL) /** * Forced failure/warning @@ -57,21 +57,13 @@ void cl_fixture_cleanup(const char *fixture_name); /** * Test method declarations */ -extern void test_status_single__hash_single_file(void); -extern void test_status_worktree__initialize(void); -extern void test_status_worktree__cleanup(void); -extern void test_status_worktree__whole_repository(void); -extern void test_status_worktree__empty_repository(void); -extern void test_network_remotes__initialize(void); -extern void test_network_remotes__cleanup(void); -extern void test_network_remotes__parsing(void); -extern void test_network_remotes__refspec_parsing(void); -extern void test_network_remotes__fnmatch(void); -extern void test_network_remotes__transform(void); +extern void test_config_stress__cleanup(void); +extern void test_config_stress__dont_break_on_invalid_input(void); +extern void test_config_stress__initialize(void); extern void test_core_dirent__dont_traverse_dot(void); -extern void test_core_dirent__traverse_subfolder(void); -extern void test_core_dirent__traverse_slash_terminated_folder(void); extern void test_core_dirent__dont_traverse_empty_folders(void); +extern void test_core_dirent__traverse_slash_terminated_folder(void); +extern void test_core_dirent__traverse_subfolder(void); extern void test_core_dirent__traverse_weird_filenames(void); extern void test_core_filebuf__0(void); extern void test_core_filebuf__1(void); @@ -83,9 +75,9 @@ extern void test_core_path__1(void); extern void test_core_path__2(void); extern void test_core_path__5(void); extern void test_core_path__6(void); -extern void test_core_rmdir__initialize(void); extern void test_core_rmdir__delete_recursive(void); extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); +extern void test_core_rmdir__initialize(void); extern void test_core_string__0(void); extern void test_core_string__1(void); extern void test_core_strtol__int32(void); @@ -93,40 +85,51 @@ extern void test_core_strtol__int64(void); extern void test_core_vector__0(void); extern void test_core_vector__1(void); extern void test_core_vector__2(void); -extern void test_object_tree_frompath__initialize(void); -extern void test_object_tree_frompath__cleanup(void); -extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void); -extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void); -extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void); -extern void test_object_raw_chars__find_invalid_chars_in_oid(void); +extern void test_network_remotes__cleanup(void); +extern void test_network_remotes__fnmatch(void); +extern void test_network_remotes__initialize(void); +extern void test_network_remotes__parsing(void); +extern void test_network_remotes__refspec_parsing(void); +extern void test_network_remotes__transform(void); extern void test_object_raw_chars__build_valid_oid_from_raw_bytes(void); +extern void test_object_raw_chars__find_invalid_chars_in_oid(void); +extern void test_object_raw_compare__compare_allocfmt_oids(void); +extern void test_object_raw_compare__compare_fmt_oids(void); +extern void test_object_raw_compare__compare_pathfmt_oids(void); extern void test_object_raw_compare__succeed_on_copy_oid(void); -extern void test_object_raw_compare__succeed_on_oid_comparison_lesser(void); extern void test_object_raw_compare__succeed_on_oid_comparison_equal(void); extern void test_object_raw_compare__succeed_on_oid_comparison_greater(void); -extern void test_object_raw_compare__compare_fmt_oids(void); -extern void test_object_raw_compare__compare_allocfmt_oids(void); -extern void test_object_raw_compare__compare_pathfmt_oids(void); +extern void test_object_raw_compare__succeed_on_oid_comparison_lesser(void); extern void test_object_raw_convert__succeed_on_oid_to_string_conversion(void); extern void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void); extern void test_object_raw_fromstr__fail_on_invalid_oid_string(void); extern void test_object_raw_fromstr__succeed_on_valid_oid_string(void); -extern void test_object_raw_hash__hash_by_blocks(void); extern void test_object_raw_hash__hash_buffer_in_single_call(void); -extern void test_object_raw_hash__hash_vector(void); -extern void test_object_raw_hash__hash_junk_data(void); +extern void test_object_raw_hash__hash_by_blocks(void); extern void test_object_raw_hash__hash_commit_object(void); -extern void test_object_raw_hash__hash_tree_object(void); -extern void test_object_raw_hash__hash_tag_object(void); -extern void test_object_raw_hash__hash_zero_length_object(void); +extern void test_object_raw_hash__hash_junk_data(void); +extern void test_object_raw_hash__hash_multi_byte_object(void); extern void test_object_raw_hash__hash_one_byte_object(void); +extern void test_object_raw_hash__hash_tag_object(void); +extern void test_object_raw_hash__hash_tree_object(void); extern void test_object_raw_hash__hash_two_byte_object(void); -extern void test_object_raw_hash__hash_multi_byte_object(void); +extern void test_object_raw_hash__hash_vector(void); +extern void test_object_raw_hash__hash_zero_length_object(void); extern void test_object_raw_short__oid_shortener_no_duplicates(void); extern void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void); extern void test_object_raw_size__validate_oid_size(void); -extern void test_object_raw_type2string__convert_type_to_string(void); -extern void test_object_raw_type2string__convert_string_to_type(void); extern void test_object_raw_type2string__check_type_is_loose(void); +extern void test_object_raw_type2string__convert_string_to_type(void); +extern void test_object_raw_type2string__convert_type_to_string(void); +extern void test_object_tree_frompath__cleanup(void); +extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void); +extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void); +extern void test_object_tree_frompath__initialize(void); +extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void); +extern void test_status_single__hash_single_file(void); +extern void test_status_worktree__cleanup(void); +extern void test_status_worktree__empty_repository(void); +extern void test_status_worktree__initialize(void); +extern void test_status_worktree__whole_repository(void); #endif diff --git a/tests-clay/clay_libgit2.h b/tests-clay/clay_libgit2.h index ab3cf67ec..a5208962e 100644 --- a/tests-clay/clay_libgit2.h +++ b/tests-clay/clay_libgit2.h @@ -23,6 +23,6 @@ * just for consistency. Use with `git_` library * calls that are supposed to fail! */ -#define cl_git_fail(expr) cl_must_fail((expr)) +#define cl_git_fail(expr) cl_must_fail(expr) #endif diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index 2f3cee39c..3a63dfefa 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -4,13 +4,12 @@ #include #include #include +#include /* required for sandboxing */ #include #include -#define clay_print(...) printf(__VA_ARGS__) - #ifdef _WIN32 # include # include @@ -82,7 +81,6 @@ static struct { struct clay_func { const char *name; void (*ptr)(void); - size_t suite_n; }; struct clay_suite { @@ -93,10 +91,259 @@ struct clay_suite { size_t test_count; }; +/* From clay_print_*.c */ +static void clay_print_init(int test_count, int suite_count, const char *suite_names); +static void clay_print_shutdown(int test_count, int suite_count, int error_count); +static void clay_print_error(int num, const struct clay_error *error); +static void clay_print_ontest(const char *test_name, int test_number, int failed); +static void clay_print_onsuite(const char *suite_name); +static void clay_print_onabort(const char *msg, ...); + /* From clay_sandbox.c */ static void clay_unsandbox(void); static int clay_sandbox(void); +/* Autogenerated test data by clay */ +static const struct clay_func _clay_cb_config_stress[] = { + {"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input} +}; +static const struct clay_func _clay_cb_core_dirent[] = { + {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot}, + {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders}, + {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder}, + {"traverse_subfolder", &test_core_dirent__traverse_subfolder}, + {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames} +}; +static const struct clay_func _clay_cb_core_filebuf[] = { + {"0", &test_core_filebuf__0}, + {"1", &test_core_filebuf__1}, + {"2", &test_core_filebuf__2} +}; +static const struct clay_func _clay_cb_core_oid[] = { + {"streq", &test_core_oid__streq} +}; +static const struct clay_func _clay_cb_core_path[] = { + {"0", &test_core_path__0}, + {"1", &test_core_path__1}, + {"2", &test_core_path__2}, + {"5", &test_core_path__5}, + {"6", &test_core_path__6} +}; +static const struct clay_func _clay_cb_core_rmdir[] = { + {"delete_recursive", &test_core_rmdir__delete_recursive}, + {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir} +}; +static const struct clay_func _clay_cb_core_string[] = { + {"0", &test_core_string__0}, + {"1", &test_core_string__1} +}; +static const struct clay_func _clay_cb_core_strtol[] = { + {"int32", &test_core_strtol__int32}, + {"int64", &test_core_strtol__int64} +}; +static const struct clay_func _clay_cb_core_vector[] = { + {"0", &test_core_vector__0}, + {"1", &test_core_vector__1}, + {"2", &test_core_vector__2} +}; +static const struct clay_func _clay_cb_network_remotes[] = { + {"fnmatch", &test_network_remotes__fnmatch}, + {"parsing", &test_network_remotes__parsing}, + {"refspec_parsing", &test_network_remotes__refspec_parsing}, + {"transform", &test_network_remotes__transform} +}; +static const struct clay_func _clay_cb_object_raw_chars[] = { + {"build_valid_oid_from_raw_bytes", &test_object_raw_chars__build_valid_oid_from_raw_bytes}, + {"find_invalid_chars_in_oid", &test_object_raw_chars__find_invalid_chars_in_oid} +}; +static const struct clay_func _clay_cb_object_raw_compare[] = { + {"compare_allocfmt_oids", &test_object_raw_compare__compare_allocfmt_oids}, + {"compare_fmt_oids", &test_object_raw_compare__compare_fmt_oids}, + {"compare_pathfmt_oids", &test_object_raw_compare__compare_pathfmt_oids}, + {"succeed_on_copy_oid", &test_object_raw_compare__succeed_on_copy_oid}, + {"succeed_on_oid_comparison_equal", &test_object_raw_compare__succeed_on_oid_comparison_equal}, + {"succeed_on_oid_comparison_greater", &test_object_raw_compare__succeed_on_oid_comparison_greater}, + {"succeed_on_oid_comparison_lesser", &test_object_raw_compare__succeed_on_oid_comparison_lesser} +}; +static const struct clay_func _clay_cb_object_raw_convert[] = { + {"succeed_on_oid_to_string_conversion", &test_object_raw_convert__succeed_on_oid_to_string_conversion}, + {"succeed_on_oid_to_string_conversion_big", &test_object_raw_convert__succeed_on_oid_to_string_conversion_big} +}; +static const struct clay_func _clay_cb_object_raw_fromstr[] = { + {"fail_on_invalid_oid_string", &test_object_raw_fromstr__fail_on_invalid_oid_string}, + {"succeed_on_valid_oid_string", &test_object_raw_fromstr__succeed_on_valid_oid_string} +}; +static const struct clay_func _clay_cb_object_raw_hash[] = { + {"hash_buffer_in_single_call", &test_object_raw_hash__hash_buffer_in_single_call}, + {"hash_by_blocks", &test_object_raw_hash__hash_by_blocks}, + {"hash_commit_object", &test_object_raw_hash__hash_commit_object}, + {"hash_junk_data", &test_object_raw_hash__hash_junk_data}, + {"hash_multi_byte_object", &test_object_raw_hash__hash_multi_byte_object}, + {"hash_one_byte_object", &test_object_raw_hash__hash_one_byte_object}, + {"hash_tag_object", &test_object_raw_hash__hash_tag_object}, + {"hash_tree_object", &test_object_raw_hash__hash_tree_object}, + {"hash_two_byte_object", &test_object_raw_hash__hash_two_byte_object}, + {"hash_vector", &test_object_raw_hash__hash_vector}, + {"hash_zero_length_object", &test_object_raw_hash__hash_zero_length_object} +}; +static const struct clay_func _clay_cb_object_raw_short[] = { + {"oid_shortener_no_duplicates", &test_object_raw_short__oid_shortener_no_duplicates}, + {"oid_shortener_stresstest_git_oid_shorten", &test_object_raw_short__oid_shortener_stresstest_git_oid_shorten} +}; +static const struct clay_func _clay_cb_object_raw_size[] = { + {"validate_oid_size", &test_object_raw_size__validate_oid_size} +}; +static const struct clay_func _clay_cb_object_raw_type2string[] = { + {"check_type_is_loose", &test_object_raw_type2string__check_type_is_loose}, + {"convert_string_to_type", &test_object_raw_type2string__convert_string_to_type}, + {"convert_type_to_string", &test_object_raw_type2string__convert_type_to_string} +}; +static const struct clay_func _clay_cb_object_tree_frompath[] = { + {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path}, + {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment}, + {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry} +}; +static const struct clay_func _clay_cb_status_single[] = { + {"hash_single_file", &test_status_single__hash_single_file} +}; +static const struct clay_func _clay_cb_status_worktree[] = { + {"empty_repository", &test_status_worktree__empty_repository}, + {"whole_repository", &test_status_worktree__whole_repository} +}; + +static const struct clay_suite _clay_suites[] = { + { + "config::stress", + {"initialize", &test_config_stress__initialize}, + {"cleanup", &test_config_stress__cleanup}, + _clay_cb_config_stress, 1 + }, + { + "core::dirent", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_dirent, 5 + }, + { + "core::filebuf", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_filebuf, 3 + }, + { + "core::oid", + {"initialize", &test_core_oid__initialize}, + {NULL, NULL}, + _clay_cb_core_oid, 1 + }, + { + "core::path", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_path, 5 + }, + { + "core::rmdir", + {"initialize", &test_core_rmdir__initialize}, + {NULL, NULL}, + _clay_cb_core_rmdir, 2 + }, + { + "core::string", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_string, 2 + }, + { + "core::strtol", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_strtol, 2 + }, + { + "core::vector", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_core_vector, 3 + }, + { + "network::remotes", + {"initialize", &test_network_remotes__initialize}, + {"cleanup", &test_network_remotes__cleanup}, + _clay_cb_network_remotes, 4 + }, + { + "object::raw::chars", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_chars, 2 + }, + { + "object::raw::compare", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_compare, 7 + }, + { + "object::raw::convert", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_convert, 2 + }, + { + "object::raw::fromstr", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_fromstr, 2 + }, + { + "object::raw::hash", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_hash, 11 + }, + { + "object::raw::short", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_short, 2 + }, + { + "object::raw::size", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_size, 1 + }, + { + "object::raw::type2string", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_object_raw_type2string, 3 + }, + { + "object::tree::frompath", + {"initialize", &test_object_tree_frompath__initialize}, + {"cleanup", &test_object_tree_frompath__cleanup}, + _clay_cb_object_tree_frompath, 3 + }, + { + "status::single", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_status_single, 1 + }, + { + "status::worktree", + {"initialize", &test_status_worktree__initialize}, + {"cleanup", &test_status_worktree__cleanup}, + _clay_cb_status_worktree, 2 + } +}; + +static size_t _clay_suite_count = 21; +static size_t _clay_callback_count = 64; + +/* Core test functions */ static void clay_run_test( const struct clay_func *test, @@ -128,28 +375,11 @@ clay_run_test( _clay.local_cleanup = NULL; _clay.local_cleanup_payload = NULL; - clay_print("%c", (_clay.suite_errors > error_st) ? 'F' : '.'); -} - -static void -clay_print_error(int num, const struct clay_error *error) -{ - clay_print(" %d) Failure:\n", num); - - clay_print("%s::%s (%s) [%s:%d] [-t%d]\n", - error->suite, - error->test, - "no description", - error->file, - error->line_number, - error->test_number); - - clay_print(" %s\n", error->error_msg); - - if (error->description != NULL) - clay_print(" %s\n", error->description); - - clay_print("\n"); + clay_print_ontest( + test->name, + _clay.test_count, + (_clay.suite_errors > error_st) + ); } static void @@ -166,6 +396,8 @@ clay_report_errors(void) free(error); error = next; } + + _clay.errors = _clay.last_error = NULL; } static void @@ -174,6 +406,8 @@ clay_run_suite(const struct clay_suite *suite) const struct clay_func *test = suite->tests; size_t i; + clay_print_onsuite(suite->name); + _clay.active_suite = suite->name; _clay.suite_errors = 0; @@ -183,6 +417,7 @@ clay_run_suite(const struct clay_suite *suite) } } +#if 0 /* temporarily disabled */ static void clay_run_single(const struct clay_func *test, const struct clay_suite *suite) @@ -193,24 +428,20 @@ clay_run_single(const struct clay_func *test, clay_run_test(test, &suite->initialize, &suite->cleanup); } +#endif static void clay_usage(const char *arg) { printf("Usage: %s [options]\n\n", arg); printf("Options:\n"); - printf(" -tXX\t\tRun only the test number XX\n"); +// printf(" -tXX\t\tRun only the test number XX\n"); printf(" -sXX\t\tRun only the suite number XX\n"); exit(-1); } static void -clay_parse_args( - int argc, char **argv, - const struct clay_func *callbacks, - size_t cb_count, - const struct clay_suite *suites, - size_t suite_count) +clay_parse_args(int argc, char **argv) { int i; @@ -229,27 +460,13 @@ clay_parse_args( clay_usage(argv[0]); switch (action) { - case 't': - if ((size_t)num >= cb_count) { - fprintf(stderr, "Test number %d does not exist.\n", num); - exit(-1); - } - - clay_print("Started (%s::%s)\n", - suites[callbacks[num].suite_n].name, - callbacks[num].name); - - clay_run_single(&callbacks[num], &suites[callbacks[num].suite_n]); - break; - case 's': - if ((size_t)num >= suite_count) { - fprintf(stderr, "Suite number %d does not exist.\n", num); + if ((size_t)num >= _clay_suite_count) { + clay_print_onabort("Suite number %d does not exist.\n", num); exit(-1); } - clay_print("Started (%s::*)\n", suites[num].name); - clay_run_suite(&suites[num]); + clay_run_suite(&_clay_suites[num]); break; default: @@ -259,15 +476,13 @@ clay_parse_args( } static int -clay_test( - int argc, char **argv, - const char *suites_str, - const struct clay_func *callbacks, - size_t cb_count, - const struct clay_suite *suites, - size_t suite_count) +clay_test(int argc, char **argv) { - clay_print("Loaded %d suites: %s\n", (int)suite_count, suites_str); + clay_print_init( + (int)_clay_callback_count, + (int)_clay_suite_count, + "" + ); if (clay_sandbox() < 0) { fprintf(stderr, @@ -276,21 +491,18 @@ clay_test( } if (argc > 1) { - clay_parse_args(argc, argv, - callbacks, cb_count, suites, suite_count); - + clay_parse_args(argc, argv); } else { size_t i; - clay_print("Started\n"); - - for (i = 0; i < suite_count; ++i) { - const struct clay_suite *s = &suites[i]; - clay_run_suite(s); - } + for (i = 0; i < _clay_suite_count; ++i) + clay_run_suite(&_clay_suites[i]); } - clay_print("\n\n"); - clay_report_errors(); + clay_print_shutdown( + (int)_clay_callback_count, + (int)_clay_suite_count, + _clay.total_errors + ); clay_unsandbox(); return _clay.total_errors; @@ -335,7 +547,7 @@ clay__assert( if (should_abort) { if (!_clay.trampoline_enabled) { - fprintf(stderr, + clay_print_onabort( "Fatal error: a cleanup method raised an exception."); exit(-1); } @@ -659,202 +871,68 @@ cl_fs_cleanup(void) #endif -static const struct clay_func _all_callbacks[] = { - {"hash_single_file", &test_status_single__hash_single_file, 0}, - {"whole_repository", &test_status_worktree__whole_repository, 1}, - {"empty_repository", &test_status_worktree__empty_repository, 1}, - {"parsing", &test_network_remotes__parsing, 2}, - {"refspec_parsing", &test_network_remotes__refspec_parsing, 2}, - {"fnmatch", &test_network_remotes__fnmatch, 2}, - {"transform", &test_network_remotes__transform, 2}, - {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 3}, - {"traverse_subfolder", &test_core_dirent__traverse_subfolder, 3}, - {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 3}, - {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 3}, - {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 3}, - {"0", &test_core_filebuf__0, 4}, - {"1", &test_core_filebuf__1, 4}, - {"2", &test_core_filebuf__2, 4}, - {"streq", &test_core_oid__streq, 5}, - {"0", &test_core_path__0, 6}, - {"1", &test_core_path__1, 6}, - {"2", &test_core_path__2, 6}, - {"5", &test_core_path__5, 6}, - {"6", &test_core_path__6, 6}, - {"delete_recursive", &test_core_rmdir__delete_recursive, 7}, - {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 7}, - {"0", &test_core_string__0, 8}, - {"1", &test_core_string__1, 8}, - {"int32", &test_core_strtol__int32, 9}, - {"int64", &test_core_strtol__int64, 9}, - {"0", &test_core_vector__0, 10}, - {"1", &test_core_vector__1, 10}, - {"2", &test_core_vector__2, 10}, - {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry, 11}, - {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment, 11}, - {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path, 11}, - {"find_invalid_chars_in_oid", &test_object_raw_chars__find_invalid_chars_in_oid, 12}, - {"build_valid_oid_from_raw_bytes", &test_object_raw_chars__build_valid_oid_from_raw_bytes, 12}, - {"succeed_on_copy_oid", &test_object_raw_compare__succeed_on_copy_oid, 13}, - {"succeed_on_oid_comparison_lesser", &test_object_raw_compare__succeed_on_oid_comparison_lesser, 13}, - {"succeed_on_oid_comparison_equal", &test_object_raw_compare__succeed_on_oid_comparison_equal, 13}, - {"succeed_on_oid_comparison_greater", &test_object_raw_compare__succeed_on_oid_comparison_greater, 13}, - {"compare_fmt_oids", &test_object_raw_compare__compare_fmt_oids, 13}, - {"compare_allocfmt_oids", &test_object_raw_compare__compare_allocfmt_oids, 13}, - {"compare_pathfmt_oids", &test_object_raw_compare__compare_pathfmt_oids, 13}, - {"succeed_on_oid_to_string_conversion", &test_object_raw_convert__succeed_on_oid_to_string_conversion, 14}, - {"succeed_on_oid_to_string_conversion_big", &test_object_raw_convert__succeed_on_oid_to_string_conversion_big, 14}, - {"fail_on_invalid_oid_string", &test_object_raw_fromstr__fail_on_invalid_oid_string, 15}, - {"succeed_on_valid_oid_string", &test_object_raw_fromstr__succeed_on_valid_oid_string, 15}, - {"hash_by_blocks", &test_object_raw_hash__hash_by_blocks, 16}, - {"hash_buffer_in_single_call", &test_object_raw_hash__hash_buffer_in_single_call, 16}, - {"hash_vector", &test_object_raw_hash__hash_vector, 16}, - {"hash_junk_data", &test_object_raw_hash__hash_junk_data, 16}, - {"hash_commit_object", &test_object_raw_hash__hash_commit_object, 16}, - {"hash_tree_object", &test_object_raw_hash__hash_tree_object, 16}, - {"hash_tag_object", &test_object_raw_hash__hash_tag_object, 16}, - {"hash_zero_length_object", &test_object_raw_hash__hash_zero_length_object, 16}, - {"hash_one_byte_object", &test_object_raw_hash__hash_one_byte_object, 16}, - {"hash_two_byte_object", &test_object_raw_hash__hash_two_byte_object, 16}, - {"hash_multi_byte_object", &test_object_raw_hash__hash_multi_byte_object, 16}, - {"oid_shortener_no_duplicates", &test_object_raw_short__oid_shortener_no_duplicates, 17}, - {"oid_shortener_stresstest_git_oid_shorten", &test_object_raw_short__oid_shortener_stresstest_git_oid_shorten, 17}, - {"validate_oid_size", &test_object_raw_size__validate_oid_size, 18}, - {"convert_type_to_string", &test_object_raw_type2string__convert_type_to_string, 19}, - {"convert_string_to_type", &test_object_raw_type2string__convert_string_to_type, 19}, - {"check_type_is_loose", &test_object_raw_type2string__check_type_is_loose, 19} -}; +static void clay_print_init(int test_count, int suite_count, const char *suite_names) +{ + (void)suite_names; + (void)suite_count; + printf("TAP version 13\n"); + printf("1..%d\n", test_count); +} -static const struct clay_suite _all_suites[] = { - { - "status::single", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[0], 1 - }, - { - "status::worktree", - {"initialize", &test_status_worktree__initialize, 1}, - {"cleanup", &test_status_worktree__cleanup, 1}, - &_all_callbacks[1], 2 - }, - { - "network::remotes", - {"initialize", &test_network_remotes__initialize, 2}, - {"cleanup", &test_network_remotes__cleanup, 2}, - &_all_callbacks[3], 4 - }, - { - "core::dirent", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[7], 5 - }, - { - "core::filebuf", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[12], 3 - }, - { - "core::oid", - {"initialize", &test_core_oid__initialize, 5}, - {NULL, NULL, 0}, - &_all_callbacks[15], 1 - }, - { - "core::path", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[16], 5 - }, - { - "core::rmdir", - {"initialize", &test_core_rmdir__initialize, 7}, - {NULL, NULL, 0}, - &_all_callbacks[21], 2 - }, - { - "core::string", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[23], 2 - }, - { - "core::strtol", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[25], 2 - }, - { - "core::vector", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[27], 3 - }, - { - "object::tree::frompath", - {"initialize", &test_object_tree_frompath__initialize, 11}, - {"cleanup", &test_object_tree_frompath__cleanup, 11}, - &_all_callbacks[30], 3 - }, - { - "object::raw::chars", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[33], 2 - }, - { - "object::raw::compare", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[35], 7 - }, - { - "object::raw::convert", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[42], 2 - }, - { - "object::raw::fromstr", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[44], 2 - }, - { - "object::raw::hash", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[46], 11 - }, - { - "object::raw::short", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[57], 2 - }, - { - "object::raw::size", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[59], 1 - }, - { - "object::raw::type2string", - {NULL, NULL, 0}, - {NULL, NULL, 0}, - &_all_callbacks[60], 3 - } -}; +static void clay_print_shutdown(int test_count, int suite_count, int error_count) +{ + (void)test_count; + (void)suite_count; + (void)error_count; + + printf("\n"); +} + +static void clay_print_error(int num, const struct clay_error *error) +{ + (void)num; + + printf(" ---\n"); + printf(" message : %s\n", error->error_msg); + printf(" severity: fail\n"); + printf(" suite : %s\n", error->suite); + printf(" test : %s\n", error->test); + printf(" file : %s\n", error->file); + printf(" line : %d\n", error->line_number); + + if (error->description != NULL) + printf(" description: %s\n", error->description); + + printf(" ...\n"); +} + +static void clay_print_ontest(const char *test_name, int test_number, int failed) +{ + printf("%s %d - %s\n", + failed ? "not ok" : "ok", + test_number, + test_name + ); + + clay_report_errors(); +} + +static void clay_print_onsuite(const char *suite_name) +{ + printf("# *** %s ***\n", suite_name); +} + +static void clay_print_onabort(const char *msg, ...) +{ + va_list argp; + va_start(argp, msg); + fprintf(stdout, "Bail out! "); + vfprintf(stdout, msg, argp); + va_end(argp); +} -static const char _suites_str[] = "status::single, status::worktree, network::remotes, core::dirent, core::filebuf, core::oid, core::path, core::rmdir, core::string, core::strtol, core::vector, object::tree::frompath, object::raw::chars, object::raw::compare, object::raw::convert, object::raw::fromstr, object::raw::hash, object::raw::short, object::raw::size, object::raw::type2string"; int _MAIN_CC main(int argc, char *argv[]) { - return clay_test( - argc, argv, _suites_str, - _all_callbacks, 63, - _all_suites, 20 - ); + return clay_test(argc, argv); } diff --git a/tests-clay/config/stress.c b/tests-clay/config/stress.c new file mode 100644 index 000000000..7b81400c1 --- /dev/null +++ b/tests-clay/config/stress.c @@ -0,0 +1,41 @@ +#include "clay_libgit2.h" + +#include "filebuf.h" +#include "fileops.h" +#include "posix.h" + +#define TEST_CONFIG "git-test-config" + +void test_config_stress__initialize(void) +{ + git_filebuf file; + + git_filebuf_open(&file, TEST_CONFIG, 0); + + git_filebuf_printf(&file, "[color]\n\tui = auto\n"); + git_filebuf_printf(&file, "[core]\n\teditor = \n"); + + git_filebuf_commit(&file, 0666); +} + +void test_config_stress__cleanup(void) +{ + p_unlink(TEST_CONFIG); +} + +void test_config_stress__dont_break_on_invalid_input(void) +{ + const char *editor, *color; + struct git_config_file *file; + git_config *config; + + cl_git_pass(git_futils_exists(TEST_CONFIG)); + cl_git_pass(git_config_file__ondisk(&file, TEST_CONFIG)); + cl_git_pass(git_config_new(&config)); + cl_git_pass(git_config_add_file(config, file, 0)); + + cl_git_pass(git_config_get_string(config, "color.ui", &color)); + cl_git_pass(git_config_get_string(config, "core.editor", &editor)); + + git_config_free(config); +} -- cgit v1.2.1 From 2cbca8b06cb7cab08d916438a63e19734256b3fa Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 18 Nov 2011 01:43:27 +0100 Subject: include: Unify internal include strategies Do not add the `git2` path to internal includes, or that will cause an extra path dependency. --- include/git2/indexer.h | 4 ++-- include/git2/refspec.h | 2 +- include/git2/remote.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/git2/indexer.h b/include/git2/indexer.h index bd9b9b6ab..1e5eb380c 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -7,8 +7,8 @@ #ifndef _INCLUDE_git_indexer_h__ #define _INCLUDE_git_indexer_h__ -#include "git2/common.h" -#include "git2/oid.h" +#include "common.h" +#include "oid.h" GIT_BEGIN_DECL diff --git a/include/git2/refspec.h b/include/git2/refspec.h index eccbeaa7c..0f8b13cec 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_git_refspec_h__ #define INCLUDE_git_refspec_h__ -#include "git2/types.h" +#include "types.h" /** * @file git2/refspec.h diff --git a/include/git2/remote.h b/include/git2/remote.h index e0be93757..54116c22e 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -7,9 +7,9 @@ #ifndef INCLUDE_git_remote_h__ #define INCLUDE_git_remote_h__ -#include "git2/common.h" -#include "git2/repository.h" -#include "git2/refspec.h" +#include "common.h" +#include "repository.h" +#include "refspec.h" /** * @file git2/remote.h * @brief Git remote management functions -- cgit v1.2.1 From 472d4d858bed9758b2e9300e544417c0d9d43623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 17 Nov 2011 20:32:04 +0100 Subject: Don't overwrite existing objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's redundant to do this (git doesn't) and Windows doesn't allow us to overwrite a read-only file (which objects are). Signed-off-by: Carlos Martín Nieto --- src/odb_loose.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/odb_loose.c b/src/odb_loose.c index 8c0331834..57a0b0a8e 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -670,6 +670,17 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) return git__rethrow(error, "Failed to write loose backend"); stream->finished = 1; + + /* + * Don't try to add an existing object to the repository. This + * is what git does and allows us to sidestep the fact that + * we're not allowed to overwrite a read-only file on Windows. + */ + if (git_futils_exists(final_path) == GIT_SUCCESS) { + git_filebuf_cleanup(&stream->fbuf); + return GIT_SUCCESS; + } + return git_filebuf_commit_at(&stream->fbuf, final_path, GIT_OBJECT_FILE_MODE); } -- cgit v1.2.1 From c515b5bf1e63455686ee1ab89152f3da6eca73a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 18 Nov 2011 02:16:24 +0100 Subject: Add test for renaming a file and adding it to the index Thanks to Emeric. --- tests-clay/clay.h | 1 + tests-clay/clay_main.c | 13 ++++++++-- tests-clay/index/rename.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests-clay/index/rename.c diff --git a/tests-clay/clay.h b/tests-clay/clay.h index 15e1770e0..db3a475b2 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -85,6 +85,7 @@ extern void test_core_strtol__int64(void); extern void test_core_vector__0(void); extern void test_core_vector__1(void); extern void test_core_vector__2(void); +extern void test_index_rename__single_file(void); extern void test_network_remotes__cleanup(void); extern void test_network_remotes__fnmatch(void); extern void test_network_remotes__initialize(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index 3a63dfefa..4ad6fc467 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -146,6 +146,9 @@ static const struct clay_func _clay_cb_core_vector[] = { {"1", &test_core_vector__1}, {"2", &test_core_vector__2} }; +static const struct clay_func _clay_cb_index_rename[] = { + {"single_file", &test_index_rename__single_file} +}; static const struct clay_func _clay_cb_network_remotes[] = { {"fnmatch", &test_network_remotes__fnmatch}, {"parsing", &test_network_remotes__parsing}, @@ -265,6 +268,12 @@ static const struct clay_suite _clay_suites[] = { {NULL, NULL}, {NULL, NULL}, _clay_cb_core_vector, 3 + }, + { + "index::rename", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_index_rename, 1 }, { "network::remotes", @@ -340,8 +349,8 @@ static const struct clay_suite _clay_suites[] = { } }; -static size_t _clay_suite_count = 21; -static size_t _clay_callback_count = 64; +static size_t _clay_suite_count = 22; +static size_t _clay_callback_count = 65; /* Core test functions */ static void diff --git a/tests-clay/index/rename.c b/tests-clay/index/rename.c new file mode 100644 index 000000000..ba72b62f7 --- /dev/null +++ b/tests-clay/index/rename.c @@ -0,0 +1,60 @@ +#include "clay_libgit2.h" +#include "posix.h" + +static void file_create(const char *filename, const char *content) +{ + int fd; + + fd = p_creat(filename, 0666); + cl_assert(fd != 0); + cl_git_pass(p_write(fd, content, strlen(content))); + cl_git_pass(p_close(fd)) +} + +void test_index_rename__single_file(void) +{ + git_repository *repo; + git_index *index; + int position; + git_oid expected; + git_index_entry *entry; + + p_mkdir("rename", 0700); + + cl_git_pass(git_repository_init(&repo, "./rename", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + + file_create("./rename/lame.name.txt", "new_file\n"); + + /* This should add a new blob to the object database in 'd4/fa8600b4f37d7516bef4816ae2c64dbf029e3a' */ + cl_git_pass(git_index_add(index, "lame.name.txt", 0)); + cl_assert(git_index_entrycount(index) == 1); + + cl_git_pass(git_oid_fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a")); + + position = git_index_find(index, "lame.name.txt"); + + entry = git_index_get(index, position); + cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); + + /* This removes the entry from the index, but not from the object database */ + cl_git_pass(git_index_remove(index, position)); + cl_assert(git_index_entrycount(index) == 0); + + p_rename("./rename/lame.name.txt", "./rename/fancy.name.txt"); + + cl_git_pass(git_index_add(index, "fancy.name.txt", 0)); + cl_assert(git_index_entrycount(index) == 1); + + position = git_index_find(index, "fancy.name.txt"); + + entry = git_index_get(index, position); + cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("rename"); +} -- cgit v1.2.1 From e4c93a392763a006d11e1c1dd01c12f85498dad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 18 Nov 2011 02:26:10 +0100 Subject: Update clay instructions to use -vtap --- tests-clay/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clay/README.md b/tests-clay/README.md index f3e54d6c6..6b5a659f8 100644 --- a/tests-clay/README.md +++ b/tests-clay/README.md @@ -11,7 +11,7 @@ https://github.com/tanoku/clay * Mix the tests: - ./clay . + ./clay -vtap . * Make sure you actually build the tests by setting: -- cgit v1.2.1