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 ++++---- 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src') 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; -- 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 +++- 11 files changed, 30 insertions(+), 23 deletions(-) (limited to 'src') 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 { -- 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 ++- 17 files changed, 36 insertions(+), 18 deletions(-) (limited to 'src') 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) -- 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. --- 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 ---------- 8 files changed, 125 insertions(+), 104 deletions(-) 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 (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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 --- src/tree.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'src') 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. --- 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 ++-- 47 files changed, 270 insertions(+), 268 deletions(-) (limited to 'src') 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; } -- 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(-) (limited to 'src') 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 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(-) (limited to 'src') 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 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 --- src/commit.c | 5 +- src/refs.c | 424 ++++++++++++++++++++++++++++++++++++++++++----------------- src/refs.h | 2 - 3 files changed, 303 insertions(+), 128 deletions(-) (limited to 'src') 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 { -- 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 +++++-- 5 files changed, 77 insertions(+), 17 deletions(-) (limited to 'src') 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); -- 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(-) (limited to 'src') 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. --- src/refs.c | 1454 +++++++++++++++++++++++------------------------------- src/refs.h | 10 +- src/repository.c | 7 +- 3 files changed, 623 insertions(+), 848 deletions(-) (limited to 'src') 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"); -- 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(-) (limited to 'src') 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 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 ++++++++++++++ 6 files changed, 32 insertions(+), 25 deletions(-) (limited to 'src') 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; +} -- 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(-) (limited to 'src') 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(-) (limited to 'src') 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()`. --- 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 +- 8 files changed, 233 insertions(+), 63 deletions(-) create mode 100644 src/global.c create mode 100644 src/global.h (limited to 'src') 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 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(-) (limited to 'src') 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(-) (limited to 'src') 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 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. --- src/tree.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) (limited to 'src') 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); } -- 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` --- src/tree.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') 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 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(+) (limited to 'src') 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