summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Martín Nieto <carlos@cmartin.tk>2011-11-18 22:45:56 +0100
committerCarlos Martín Nieto <carlos@cmartin.tk>2011-11-18 22:45:56 +0100
commitbdd31dd5e832126b2f22fccbe244a1106c241ab0 (patch)
treeb08a2ad0fad57131563aa8c071221bea241128c1 /src
parent277b7efe493887081ce1dafd91199d0ee9f676c9 (diff)
parente4c93a392763a006d11e1c1dd01c12f85498dad5 (diff)
downloadlibgit2-error-handling.tar.gz
Merge branch 'development' into error-handlingerror-handling
The code in this branch has been modified so it works with the global state introduced in development.
Diffstat (limited to 'src')
-rw-r--r--src/blob.c2
-rw-r--r--src/buffer.c2
-rw-r--r--src/cache.c2
-rw-r--r--src/commit.c30
-rw-r--r--src/common.h1
-rw-r--r--src/config.c18
-rw-r--r--src/config.h1
-rw-r--r--src/config_file.c76
-rw-r--r--src/delta-apply.c2
-rw-r--r--src/errors.c18
-rw-r--r--src/fetch.c3
-rw-r--r--src/filebuf.c34
-rw-r--r--src/filebuf.h4
-rw-r--r--src/fileops.c50
-rw-r--r--src/fileops.h12
-rw-r--r--src/global.c134
-rw-r--r--src/global.h22
-rw-r--r--src/hash.c2
-rw-r--r--src/hashtable.c10
-rw-r--r--src/index.c26
-rw-r--r--src/index.h3
-rw-r--r--src/indexer.c12
-rw-r--r--src/mwindow.c102
-rw-r--r--src/mwindow.h3
-rw-r--r--src/netops.c2
-rw-r--r--src/object.c2
-rw-r--r--src/odb.c22
-rw-r--r--src/odb.h4
-rw-r--r--src/odb_loose.c35
-rw-r--r--src/odb_pack.c10
-rw-r--r--src/oid.c8
-rw-r--r--src/pack.c24
-rw-r--r--src/pack.h2
-rw-r--r--src/path.c4
-rw-r--r--src/pkt.c6
-rw-r--r--src/posix.c16
-rw-r--r--src/posix.h4
-rw-r--r--src/pqueue.c6
-rw-r--r--src/reflog.c60
-rw-r--r--src/reflog.h2
-rw-r--r--src/refs.c1293
-rw-r--r--src/refs.h13
-rw-r--r--src/refspec.c2
-rw-r--r--src/remote.c20
-rw-r--r--src/repository.c72
-rw-r--r--src/repository.h5
-rw-r--r--src/revwalk.c14
-rw-r--r--src/signature.c6
-rw-r--r--src/status.c139
-rw-r--r--src/tag.c34
-rw-r--r--src/thread-utils.h2
-rw-r--r--src/transports/git.c18
-rw-r--r--src/transports/http.c23
-rw-r--r--src/transports/local.c21
-rw-r--r--src/tree-cache.c4
-rw-r--r--src/tree.c126
-rw-r--r--src/tsort.c4
-rw-r--r--src/util.c4
-rw-r--r--src/util.h2
-rw-r--r--src/vector.c4
-rw-r--r--src/win32/dir.c23
-rw-r--r--src/win32/posix.h15
-rw-r--r--src/win32/posix_w32.c90
-rw-r--r--src/win32/utf-conv.c (renamed from src/win32/utf8-conv.c)34
-rw-r--r--src/win32/utf-conv.h (renamed from src/win32/utf8-conv.h)8
65 files changed, 1543 insertions, 1209 deletions
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..83bc9fc4c 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;
}
@@ -137,15 +137,18 @@ 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)
+ 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
@@ -153,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(head, oid);
+ error = git_reference_set_oid(target, oid);
+
+ git_reference_free(head);
+ git_reference_free(target);
}
if (error < GIT_SUCCESS)
diff --git a/src/common.h b/src/common.h
index 475edc518..f4dcc1ccd 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 <assert.h>
diff --git a/src/config.c b/src/config.c
index f53afa145..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 = conv_utf16_to_utf8(apphome_utf16);
- free(apphome_utf16);
+ apphome_utf8 = gitwin_from_utf16(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.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..aec29d4e2 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, &current_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, &current_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,12 +1029,12 @@ 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);
else
- error = git_filebuf_commit(&file);
+ error = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE);
git_futils_freebuffer(&cfg->reader.buffer);
return error;
@@ -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;
}
@@ -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)
- free(*var_name);
+ if (error != GIT_SUCCESS)
+ {
+ *var_value = NULL;
+ 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;
}
@@ -1182,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 923cb3507..22b8ae7bf 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -7,14 +7,10 @@
#include "common.h"
#include "errors.h"
-#include "git2/thread-utils.h" /* for GIT_TLS */
-#include "thread-utils.h" /* for GIT_TLS */
#include "posix.h"
-
+#include "global.h"
#include <stdarg.h>
-GIT_TLS git_error *git_errno;
-
static struct {
int num;
const char *str;
@@ -115,11 +111,11 @@ git_error * git_error_createf(const char *file, unsigned int line, int code,
va_end(ap);
err->code = code;
- err->child = git_errno;
+ err->child = GIT_GLOBAL->git_errno;
err->file = file;
err->line = line;
- git_errno = err;
+ GIT_GLOBAL->git_errno = err;
return err;
}
@@ -149,13 +145,13 @@ void git_error_free(git_error *err)
void git_clearerror(void)
{
- git_error_free(git_errno);
- git_errno = NULL;
+ git_error_free(GIT_GLOBAL->git_errno);
+ GIT_GLOBAL->git_errno = NULL;
}
const char *git_lasterror(void)
{
- return git_errno == NULL ? NULL : git_errno->msg;
+ return GIT_GLOBAL->git_errno == NULL ? NULL : GIT_GLOBAL->git_errno->msg;
}
void git_error_print_stack(git_error *error_in)
@@ -163,7 +159,7 @@ void git_error_print_stack(git_error *error_in)
git_error *error;
if (error_in == NULL)
- error_in = git_errno;
+ error_in = GIT_GLOBAL->git_errno;
for (error = error_in; error; error = error->child)
fprintf(stderr, "%s:%u %s\n", error->file, error->line, error->msg);
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 1a98e3f43..199418032 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)
@@ -23,9 +25,10 @@ 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, 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)
@@ -63,13 +66,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)
@@ -246,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);
+ git__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;
@@ -270,7 +273,12 @@ int git_filebuf_commit(git_filebuf *file)
p_close(file->fd);
file->fd = -1;
- error = git_futils_mv_atomic(file->path_lock, file->path_original);
+ if (p_chmod(file->path_lock, mode)) {
+ error = git__throw(GIT_EOSERR, "Failed to chmod locked file before committing");
+ goto cleanup;
+ }
+
+ error = p_rename(file->path_lock, file->path_original);
cleanup:
git_filebuf_cleanup(file);
@@ -368,12 +376,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/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/fileops.c b/src/fileops.c
index 203cce0a4..955bb1bf6 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -8,32 +8,8 @@
#include "fileops.h"
#include <ctype.h>
-int git_futils_mv_atomic(const char *from, const char *to)
+int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{
-#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 int mode = 0755; /* or 0777 ? */
int error = GIT_SUCCESS;
char target_folder_path[GIT_PATH_MAX];
@@ -67,23 +43,23 @@ 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 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);
}
-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 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);
@@ -181,7 +157,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,17 +183,17 @@ 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;
}
-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. */
+ 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)
@@ -289,7 +265,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;
@@ -326,7 +302,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/fileops.h b/src/fileops.h
index 5b69199d2..56c4770cb 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 dirmode, 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 dirmode, const mode_t mode);
/**
* Check if the given path points to a directory
@@ -74,13 +74,13 @@ 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
* 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/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..6a15a8d02
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,22 @@
+/*
+ * 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"
+#include "git2/types.h"
+
+typedef struct {
+ git_error *git_errno;
+ 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/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..1a9745a2c 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);
@@ -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) {
@@ -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/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..a69ab850c 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);
@@ -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..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,33 +38,34 @@ 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);
mwf->windows = w->next;
- free(w);
+ git__free(w);
}
}
@@ -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)
@@ -139,8 +136,8 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
else
*list = lru_w->next;
- free(lru_w);
- ctl.open_windows--;
+ git__free(lru_w);
+ 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,19 +181,19 @@ 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;
cleanup:
- free(w);
+ git__free(w);
return NULL;
}
@@ -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/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.h b/src/odb.h
index 4e850916b..833739e99 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -14,6 +14,10 @@
#include "vector.h"
#include "cache.h"
+#define GIT_OBJECTS_DIR "objects/"
+#define GIT_OBJECT_DIR_MODE 0777
+#define GIT_OBJECT_FILE_MODE 0444
+
/* DO NOT EXPORT */
typedef struct {
void *data; /**< Raw, decompressed object data. */
diff --git a/src/odb_loose.c b/src/odb_loose.c
index dbfe18b43..57a0b0a8e 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';
@@ -666,11 +666,22 @@ 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;
- return git_filebuf_commit_at(&stream->fbuf, final_path);
+
+ /*
+ * 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);
}
static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
@@ -686,7 +697,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 +750,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");
}
@@ -787,10 +798,10 @@ 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);
+ return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE);
cleanup:
git_filebuf_cleanup(&fbuf);
@@ -803,8 +814,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 +832,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..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"
@@ -181,7 +183,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 +299,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 +308,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 +392,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 +410,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 +506,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 +600,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 +612,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/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/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/posix.c b/src/posix.c
index 1b85b053d..8c19588ee 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);
}
@@ -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 59bec2794..c12b41364 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -40,10 +40,12 @@ 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, int mode);
+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/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..e0fa7a060 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;
}
@@ -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");
@@ -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)
@@ -215,23 +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)
- return git__throw(GIT_ERROR, "Failed to write reflog. Cannot resolve reference `%s`", r->name);
+ if (oid == NULL) {
+ git_reference_free(r);
+ return git__throw(GIT_ERROR,
+ "Failed to write reflog. Cannot resolve reference `%s`", r->name);
+ }
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_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);
diff --git a/src/reflog.h b/src/reflog.h
index 093874e51..44b063700 100644
--- a/src/reflog.h
+++ b/src/reflog.h
@@ -12,6 +12,8 @@
#include "vector.h"
#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..569efbf78 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -9,22 +9,24 @@
#include "hash.h"
#include "repository.h"
#include "fileops.h"
+#include "pack.h"
#include <git2/tag.h>
#include <git2/object.h>
#define MAX_NESTING_LEVEL 5
-typedef struct {
- git_reference ref;
- git_oid oid;
- git_oid peel_target;
-} reference_oid;
+enum {
+ GIT_PACKREF_HAS_PEEL = 1,
+ GIT_PACKREF_WAS_LOOSE = 2
+};
-typedef struct {
- git_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;
@@ -39,97 +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(git_reference *reference);
-static int reference_create(git_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_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(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_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);
-static int loose_update(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_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);
+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)
+
+void git_reference_free(git_reference *reference)
{
if (reference == NULL)
return;
- if (reference->name)
- free(reference->name);
+ git__free(reference->name);
- if (reference->type == GIT_REF_SYMBOLIC)
- free(((reference_symbolic *)reference)->target);
+ if (reference->flags & GIT_REF_SYMBOLIC)
+ git__free(reference->target.symbolic);
- free(reference);
+ git__free(reference);
}
static int reference_create(
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;
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)
@@ -144,62 +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);
}
-
-
-
-/*****************************************
- * Internal methods - Loose references
- *****************************************/
-static int loose_update(git_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(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,
@@ -212,13 +151,12 @@ static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
refname_start += header_len;
- 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");
@@ -230,21 +168,19 @@ 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(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;
@@ -258,7 +194,6 @@ static int loose_parse_oid(git_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;
@@ -277,52 +212,75 @@ static git_rtype loose_guess_rtype(const char *full_path)
return type;
}
-static int loose_lookup(
- git_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;
- git_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(git_reference *ref)
@@ -337,49 +295,36 @@ static int loose_write(git_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);
-
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");
}
-
-
-
-
-
-/*****************************************
- * Internal methods - Packed references
- *****************************************/
-
static int packed_parse_peel(
- reference_oid *tag_ref,
+ struct packref *tag_ref,
const char **buffer_out,
const char *buffer_end)
{
@@ -389,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);
@@ -449,22 +395,19 @@ static int packed_parse_oid(
goto cleanup;
}
- refname_len = refname_end - refname_begin;
-
- memcpy(refname, refname_begin, refname_len);
- refname[refname_len] = 0;
+ if (refname_end[-1] == '\r')
+ refname_end--;
- if (refname[refname_len - 1] == '\r')
- refname[refname_len - 1] = 0;
+ refname_len = refname_end - refname_begin;
- error = reference_create(&_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;
@@ -472,8 +415,8 @@ static int packed_parse_oid(
return GIT_SUCCESS;
cleanup:
- reference_free((git_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)
@@ -488,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;
@@ -497,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
@@ -535,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;
@@ -547,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((git_reference *)ref);
+ free(ref);
goto cleanup;
}
}
@@ -561,12 +504,10 @@ 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");
}
-
-
struct dirent_list_data {
git_repository *repo;
size_t repo_path_len;
@@ -582,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 &&
@@ -600,29 +542,35 @@ 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;
+ 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(&reference, repository, file_path, 1);
- if (error == GIT_SUCCESS && reference != NULL) {
- reference->type |= GIT_REF_PACKED;
+ error = loose_lookup_to_packfile(&ref, repository, file_path);
- if (git_hashtable_insert2(repository->references.packfile, reference->name, reference, &old_ref) < GIT_SUCCESS) {
- reference_free(reference);
+ if (error == GIT_SUCCESS) {
+
+ 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((git_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");
}
/*
@@ -640,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);
- git_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];
@@ -681,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");
}
/*
@@ -702,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");
@@ -735,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
@@ -746,7 +686,6 @@ static int packed_find_peel(reference_oid *ref)
}
git_object_close(object);
-
return GIT_SUCCESS;
}
@@ -766,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;
- git_reference *reference;
for (i = 0; i < packing_list->length; ++i) {
- git_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
- */
- reference = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name);
- if (reference != NULL)
+ if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
continue;
git_path_join(full_path, repo->path_repository, ref->name);
@@ -789,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 git_reference *ref_a = (const git_reference *)a;
- const git_reference *ref_b = (const git_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);
}
@@ -822,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)
- return git__rethrow(error, "Failed to write packed reference");
+ if ((error =
+ git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to init packed refernces list");
/* Load all the packfile into a vector */
{
- git_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);
);
}
@@ -841,27 +776,24 @@ 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");
+ if ((error =
+ git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to write packed references file header");
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;
}
@@ -870,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);
+ 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 */
@@ -887,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 references file");
}
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);
@@ -916,35 +850,168 @@ 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)
+{
+ const char *refs[2];
+
+ refs[0] = ref;
+ refs[1] = old_ref;
+
+ 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 GIT_SUCCESS;
+}
+
+static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
{
int error;
- git_vector refs;
+ char ref_path[GIT_PATH_MAX];
- if (git_vector_init(&refs, 2, NULL) < GIT_SUCCESS)
- return GIT_ENOMEM;
+ error = packed_load(repo);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Cannot resolve if a reference exists");
+
+ git_path_join(ref_path, repo->path_repository, ref_name);
- git_vector_insert(&refs, (void *)ref);
- git_vector_insert(&refs, (void *)old_ref);
+ if (git_futils_isfile(ref_path) == GIT_SUCCESS ||
+ git_hashtable_lookup(repo->references.packfile, ref_path) != NULL) {
+ *exists = 1;
+ } else {
+ *exists = 0;
+ }
+
+ return GIT_SUCCESS;
+}
- error = git_reference_foreach(repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&refs);
+static int packed_lookup(git_reference *ref)
+{
+ int error;
+ struct packref *pack_ref = NULL;
+
+ error = packed_load(ref->owner);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error,
+ "Failed to lookup reference from packfile");
+
+ if (ref->flags & GIT_REF_PACKED &&
+ ref->mtime == ref->owner->references.packfile_time)
+ return GIT_SUCCESS;
- git_vector_free(&refs);
+ if (ref->flags & GIT_REF_SYMBOLIC)
+ free(ref->target.symbolic);
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__throw(GIT_EEXISTS, "Reference name `%s` conflicts with existing reference", ref);
+ /* 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;
}
-/*****************************************
- * External Library API
- *****************************************/
+static int reference_lookup(git_reference *ref)
+{
+ int error_loose, error_packed;
-/**
- * Constructors
+ error_loose = loose_lookup(ref);
+ if (error_loose == GIT_SUCCESS)
+ return GIT_SUCCESS;
+
+ error_packed = packed_lookup(ref);
+ if (error_packed == GIT_SUCCESS)
+ return GIT_SUCCESS;
+
+ git_reference_free(ref);
+
+ if (error_loose != GIT_ENOTFOUND)
+ return git__rethrow(error_loose, "Failed to lookup reference");
+
+ if (error_packed != GIT_ENOTFOUND)
+ return git__rethrow(error_packed, "Failed to lookup reference");
+
+ return git__throw(GIT_ENOTFOUND, "Reference not found");
+}
+
+/*
+ * Delete a reference.
+ * This is an internal method; the reference is removed
+ * from disk or the packfile, but the pointer is not freed
*/
-int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name)
+static int reference_delete(git_reference *ref)
+{
+ int error;
+
+ assert(ref);
+
+ /* 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 (git_hashtable_remove(ref->owner->references.packfile,
+ ref->name) < GIT_SUCCESS)
+ return git__throw(GIT_ENOTFOUND, "Reference not found");
+
+ error = packed_write(ref->owner);
+
+ /* 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;
+
+ git_path_join(full_path, ref->owner->path_repository, 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 (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_delete(git_reference *ref)
+{
+ int error = reference_delete(ref);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ git_reference_free(ref);
+ return GIT_SUCCESS;
+}
+
+
+int git_reference_lookup(git_reference **ref_out,
+ git_repository *repo, const char *name)
{
int error;
char normalized_name[GIT_REFNAME_MAX];
+ git_reference *ref = NULL;
assert(ref_out && repo && name);
@@ -954,39 +1021,16 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to lookup reference");
- /* 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);
-
- /* Then check if there is a loose file for that reference.*/
- error = loose_lookup(ref_out, repo, normalized_name, 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));
-
- /* 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)
+ error = reference_create(&ref, repo, normalized_name);
+ if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to lookup reference");
- /*
- * 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 = reference_lookup(ref);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to lookup reference");
- /* Look up on the packfile */
- *ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name);
- if (*ref_out != NULL)
- return GIT_SUCCESS;
-
- /* The reference doesn't exist anywhere */
- return git__throw(GIT_ENOTFOUND, "Failed to lookup reference. Reference doesn't exist");
+ *ref_out = ref;
+ return GIT_SUCCESS;
}
/**
@@ -996,15 +1040,21 @@ git_rtype git_reference_type(git_reference *ref)
{
assert(ref);
- if (ref->type & GIT_REF_OID)
+ if (ref->flags & GIT_REF_OID)
return GIT_REF_OID;
- if (ref->type & GIT_REF_SYMBOLIC)
+ if (ref->flags & GIT_REF_SYMBOLIC)
return GIT_REF_SYMBOLIC;
return GIT_REF_INVALID;
}
+int git_reference_is_packed(git_reference *ref)
+{
+ assert(ref);
+ return !!(ref->flags & GIT_REF_PACKED);
+}
+
const char *git_reference_name(git_reference *ref)
{
assert(ref);
@@ -1021,219 +1071,154 @@ const git_oid *git_reference_oid(git_reference *ref)
{
assert(ref);
- if ((ref->type & GIT_REF_OID) == 0)
+ if ((ref->flags & GIT_REF_OID) == 0)
return NULL;
- if (loose_update(ref) < GIT_SUCCESS)
- return NULL;
-
- return &((reference_oid *)ref)->oid;
+ return &ref->target.oid;
}
const char *git_reference_target(git_reference *ref)
{
assert(ref);
- if ((ref->type & GIT_REF_SYMBOLIC) == 0)
- return NULL;
-
- if (loose_update(ref) < GIT_SUCCESS)
+ if ((ref->flags & GIT_REF_SYMBOLIC) == 0)
return NULL;
- return ((reference_symbolic *)ref)->target;
+ return ref->target.symbolic;
}
-int git_reference_create_symbolic(git_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;
+ int ref_exists, error = GIT_SUCCESS;
git_reference *ref = NULL;
- void *old_ref = NULL;
- if (git_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 = git_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((git_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_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, 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 = GIT_SUCCESS, updated = 0;
+ int error = GIT_SUCCESS, ref_exists;
git_reference *ref = NULL;
- void *old_ref = NULL;
+ char normalized[GIT_REFNAME_MAX];
+
+ error = normalize_name(normalized, sizeof(normalized), name, 1);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS))
+ return git__rethrow(error, "Failed to create OID reference");
- if(git_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 = 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((git_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");
+ git_reference_free(ref);
+ return git__rethrow(error, "Failed to create reference OID");
}
-/**
- * Setters
- */
-
/*
* 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 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;
+ return git__throw(GIT_ENOTFOUND,
+ "Failed to set OID target of reference. OID doesn't exist in ODB");
- ref_old->ref.name = git__strdup(ref->name);
- if (ref_old->ref.name == NULL) {
- free(ref_old);
- return GIT_ENOMEM;
- }
- }
-
- 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((git_reference *)ref_old);
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to set OID target of reference");
+ return git__rethrow(error, "Failed to set OID target of reference");
}
/*
@@ -1245,99 +1230,85 @@ cleanup:
*/
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");
- 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);
}
-/**
- * Other
- */
-
int git_reference_rename(git_reference *ref, 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;
- git_reference *new_ref = NULL, *head = NULL;
+ git_reference *existing_ref = NULL, *head = NULL;
- assert(ref);
+ error = normalize_name(normalized, sizeof(normalized),
+ new_name, ref->flags & GIT_REF_OID);
- 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 = git_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);
- }
+ /* 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);
- 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.
- */
-
- old_name = git__strdup(ref->name);
-
- if (ref->type & GIT_REF_SYMBOLIC) {
- if ((target_ref = git_reference_target(ref)) == NULL)
- goto cleanup;
+ /* If we're not forcing the rename, check if the reference exists.
+ * If it does, renaming cannot continue */
} else {
- if ((target_oid = git_reference_oid(ref)) == NULL)
+ int exists;
+
+ error = reference_exists(&exists, ref->owner, normalized);
+ if (error < GIT_SUCCESS)
goto cleanup;
+
+ if (exists)
+ return git__throw(GIT_EEXISTS,
+ "Failed to rename reference. Reference already exists");
}
+ 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 (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);
if (git_futils_exists(aux_path) == GIT_SUCCESS) {
@@ -1363,8 +1334,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
* TODO
*
*/
-
- git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", old_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;
@@ -1373,138 +1343,107 @@ 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)
- 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 = git_reference_create_oid(&new_ref, ref->owner, new_name, target_oid, 0)) < GIT_SUCCESS)
- goto rollback;
+ error = git_reference_create_oid(
+ NULL, ref->owner, new_name, &ref->target.oid, 0);
}
- 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.
- */
- new_ref->name = NULL;
- reference_free(new_ref);
-
- if ((error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref)) < GIT_SUCCESS)
- goto rollback;
+ if (error < GIT_SUCCESS)
+ goto cleanup;
/*
* Check if we have to update HEAD.
*/
-
- if ((error = git_reference_lookup(&head, 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 = git_reference_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)
- 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:
- free(old_name);
- 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 = git_reference_create_symbolic(&new_ref, ref->owner, old_name, target_ref, 0);
+ if (ref->flags & GIT_REF_SYMBOLIC)
+ error = git_reference_create_symbolic(
+ NULL, ref->owner, ref->name, ref->target.symbolic, 0);
else
- error = git_reference_create_oid(&new_ref, ref->owner, old_name, target_oid, 0);
-
- ref->name = old_name;
+ error = git_reference_create_oid(
+ NULL, ref->owner, ref->name, &ref->target.oid, 0);
- 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");
}
-/*
- * 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 git_reference_delete(git_reference *ref)
+int git_reference_resolve(git_reference **ref_out, git_reference *ref)
{
- int error;
- git_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 (!git_reference_lookup(&reference, ref->owner, ref->name)) {
- assert((reference->type & GIT_REF_PACKED) != 0);
- error = git_reference_delete(reference);
- }
- }
-
-cleanup:
- reference_free(ref);
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to delete reference");
-}
-
-int git_reference_resolve(git_reference **resolved_ref, git_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 = git_reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS)
- return error;
+ }
}
- return git__throw(GIT_ENOMEM, "Failed to resolve reference. Reference is too nested");
+ return git__throw(GIT_ENOMEM,
+ "Failed to resolve reference. Reference is too nested");
}
int git_reference_packall(git_repository *repo)
@@ -1523,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;
@@ -1539,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");
);
}
@@ -1552,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);
}
@@ -1562,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;
@@ -1575,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);
@@ -1587,59 +1534,39 @@ 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)
+int git_reference_reload(git_reference *ref)
{
- assert(refs);
-
- refs->loose_cache = git_hashtable_alloc(
- default_table_size,
- reftable_hash,
- (git_hash_keyeq_ptr)(&git__strcmp_cb));
+ int error = reference_lookup(ref);
- /* 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)
{
- git_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);
}
}
-
-
-/*****************************************
- * Name normalization
- *****************************************/
-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 '~':
@@ -1649,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;
@@ -1672,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 == '/') {
@@ -1713,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';
@@ -1729,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 c4b0b0e39..c90f5bcc4 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -16,12 +16,15 @@
#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_REFS_FILE_MODE 0666
#define GIT_RENAMED_REF_FILE GIT_REFS_DIR "RENAMED-REF"
#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"
@@ -31,21 +34,23 @@
#define GIT_REFNAME_MAX 1024
struct git_reference {
+ unsigned int flags;
git_repository *owner;
char *name;
- unsigned int type;
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/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 10303b467..51e77e584 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -37,7 +37,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;
}
@@ -69,7 +69,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;
}
@@ -151,7 +151,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);
@@ -261,17 +261,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..f8195e2d9 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -168,12 +168,7 @@ 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);
- return NULL;
- }
-
- if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
- free(repo);
+ git__free(repo);
return NULL;
}
@@ -467,13 +462,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 +484,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)
@@ -603,18 +598,23 @@ 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)
{
- const int 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 +628,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);
@@ -716,10 +716,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;
@@ -731,7 +736,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;
@@ -740,11 +745,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");
+ }
+
+ git_reference_free(ref);
- *head_out = ref;
+ *head_out = resolved_ref;
return GIT_SUCCESS;
}
@@ -755,25 +764,36 @@ 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;
}
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");
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/repository.h b/src/repository.h
index 99217e5a4..0c17958fd 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -18,11 +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_INDEX_FILE "index"
+#define GIT_DIR_MODE 0755
+#define GIT_BARE_DIR_MODE 0777
struct git_object {
git_cached_obj cached;
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 1deade9a5..d50199d9a 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");
@@ -168,41 +166,45 @@ 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;
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)
@@ -229,7 +231,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;
}
@@ -242,7 +244,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;
@@ -289,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;
@@ -324,30 +326,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);
-}
-
-/*
- * 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 */
@@ -355,7 +333,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;
@@ -370,15 +348,25 @@ 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);
- entry = git_index_entry_bypos(st->index, st->index_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))
return GIT_SUCCESS;
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;
@@ -396,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;
}
}
@@ -466,7 +454,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:
@@ -570,7 +558,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;
}
@@ -589,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;
}
@@ -626,7 +627,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;
}
@@ -659,7 +660,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..7372e68c7 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)
@@ -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,25 +334,31 @@ 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);
- 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/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 {
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..66b6f252c 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"
@@ -389,18 +390,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;
}
@@ -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)
@@ -749,13 +750,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..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,10 +111,13 @@ 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) {
- free(head->name);
- free(head);
+ git__free(head->name);
+ git__free(head);
}
return error;
}
@@ -190,16 +193,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 00aefc295..92ca5ab77 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));
}
@@ -128,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)
@@ -376,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;
@@ -439,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;
}
@@ -594,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);
@@ -605,10 +607,14 @@ 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)
+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;
@@ -616,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';
@@ -634,23 +646,95 @@ 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);
+
+ 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,
+ void *payload)
+{
+ 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, payload) < 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,
+ payload
+ );
- strcpy(buffer, treeentry_path);
- return tree_frompath(parent_out, root, buffer, 0);
+ git_tree_close(subtree);
+ }
+ }
+
+ return GIT_SUCCESS;
+}
+
+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, payload);
+
+ 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");
+ }
}
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 ab50318e3..01aaaaad3 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)
{
@@ -38,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 = conv_utf8_to_utf16(filter);
+ 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;
@@ -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,9 +91,9 @@ 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);
+ git__free(filter_w);
if (d->h != INVALID_HANDLE_VALUE)
d->first = 1;
@@ -106,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 442717e42..ae6323679 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))
{
@@ -19,14 +19,14 @@ 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);
+ wchar_t* buf = gitwin_to_utf16(path);
int ret = _wmkdir(buf);
GIT_UNUSED_ARG(mode)
- free(buf);
+ git__free(buf);
return ret;
}
@@ -41,12 +41,13 @@ 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);
+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 cc17cc71f..6f722581e 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 <errno.h>
#include <io.h>
#include <fcntl.h>
@@ -17,10 +17,10 @@ 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);
+ git__free(buf);
return ret;
}
@@ -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;
@@ -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:
@@ -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
@@ -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) {
@@ -223,20 +223,20 @@ 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);
+ git__free(buf);
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);
+ 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;
}
@@ -261,40 +261,40 @@ 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);
+ git__free(buf);
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);
+ wchar_t* buf = gitwin_to_utf16(path);
int ret = _wchmod(buf, mode);
- free(buf);
+ git__free(buf);
return ret;
}
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);
+ git__free(buf);
return ret;
}
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 */
- free(buf);
+ git__free(buf);
if (error < GIT_SUCCESS)
error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path);
@@ -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) {
@@ -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;
}
@@ -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,13 +378,27 @@ 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);
+ wchar_t *buf = gitwin_to_utf16(path);
int ret;
ret = _waccess(buf, mode);
- free(buf);
+ git__free(buf);
+
+ return ret;
+}
+
+extern int p_rename(const char *from, const char *to)
+{
+ wchar_t *wfrom = gitwin_to_utf16(from);
+ wchar_t *wto = gitwin_to_utf16(to);
+ int ret;
+
+ ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
+
+ git__free(wfrom);
+ git__free(wto);
return ret;
}
diff --git a/src/win32/utf8-conv.c b/src/win32/utf-conv.c
index dec6f8e79..b41c78f92 100644
--- a/src/win32/utf8-conv.c
+++ b/src/win32/utf-conv.c
@@ -6,9 +6,29 @@
*/
#include "common.h"
-#include "utf8-conv.h"
+#include "utf-conv.h"
-wchar_t* conv_utf8_to_utf16(const char* str)
+/*
+ * 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;
@@ -29,15 +49,15 @@ wchar_t* conv_utf8_to_utf16(const char* str)
ret = (wchar_t*)git__malloc(cb);
- if (MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, cb) == 0) {
- free(ret);
+ if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) {
+ git__free(ret);
ret = NULL;
}
return ret;
}
-char* conv_utf16_to_utf8(const wchar_t* str)
+char* gitwin_from_utf16(const wchar_t* str)
{
char* ret;
int cb;
@@ -58,8 +78,8 @@ char* conv_utf16_to_utf8(const wchar_t* str)
ret = (char*)git__malloc(cb);
- if (WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, cb, NULL, NULL) == 0) {
- free(ret);
+ if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) {
+ git__free(ret);
ret = NULL;
}
diff --git a/src/win32/utf8-conv.h b/src/win32/utf-conv.h
index 1967ac3a1..da03e3385 100644
--- a/src/win32/utf8-conv.h
+++ b/src/win32/utf-conv.h
@@ -7,11 +7,11 @@
#include <wchar.h>
-#ifndef INCLUDE_git_utf8conv_h__
-#define INCLUDE_git_utf8conv_h__
+#ifndef INCLUDE_git_utfconv_h__
+#define INCLUDE_git_utfconv_h__
-wchar_t* conv_utf8_to_utf16(const char* str);
-char* conv_utf16_to_utf8(const wchar_t* str);
+wchar_t* gitwin_to_utf16(const char* str);
+char* gitwin_from_utf16(const wchar_t* str);
#endif