summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Straub <bstraub@github.com>2012-06-05 12:52:44 -0700
committerBen Straub <bstraub@github.com>2012-06-05 12:52:44 -0700
commit56a5000d580ef5c9605bc9076610b5af9aa67518 (patch)
tree4026c8333991fbe221a17b5d16e5e4b52f66cb20 /src
parente267c9fc1a4910d1081e97b4d7a411658ddc0def (diff)
parent01dbe273c9b6f86a613b67cee27212cf4bacf4c0 (diff)
downloadlibgit2-56a5000d580ef5c9605bc9076610b5af9aa67518.tar.gz
Merge branch 'development' into rev-parse
Conflicts: src/util.h tests-clar/refs/branches/listall.c
Diffstat (limited to 'src')
-rw-r--r--src/attr.c137
-rw-r--r--src/attr_file.c28
-rw-r--r--src/attr_file.h13
-rw-r--r--src/blob.c56
-rw-r--r--src/branch.c6
-rw-r--r--src/buffer.c70
-rw-r--r--src/buffer.h16
-rw-r--r--src/commit.c9
-rw-r--r--src/compat/fnmatch.c (renamed from src/win32/fnmatch.c)0
-rw-r--r--src/compat/fnmatch.h (renamed from src/win32/fnmatch.h)4
-rw-r--r--src/config.c72
-rw-r--r--src/config_cache.c10
-rw-r--r--src/config_file.c4
-rw-r--r--src/crlf.c10
-rw-r--r--src/delta-apply.c2
-rw-r--r--src/delta-apply.h2
-rw-r--r--src/diff.c112
-rw-r--r--src/diff_output.c13
-rw-r--r--src/fetch.c2
-rw-r--r--src/fileops.c154
-rw-r--r--src/fileops.h3
-rw-r--r--src/filter.c4
-rw-r--r--src/filter.h2
-rw-r--r--src/index.c11
-rw-r--r--src/index.h2
-rw-r--r--src/indexer.c30
-rw-r--r--src/iterator.c323
-rw-r--r--src/iterator.h57
-rw-r--r--src/mwindow.c2
-rw-r--r--src/netops.c4
-rw-r--r--src/notes.c159
-rw-r--r--src/object.c10
-rw-r--r--src/odb.c35
-rw-r--r--src/pack.c12
-rw-r--r--src/path.c33
-rw-r--r--src/pkt.c4
-rw-r--r--src/protocol.c2
-rw-r--r--src/refs.c8
-rw-r--r--src/refspec.c11
-rw-r--r--src/refspec.h2
-rw-r--r--src/remote.c12
-rw-r--r--src/repository.c91
-rw-r--r--src/revwalk.c23
-rw-r--r--src/signature.c4
-rw-r--r--src/status.c253
-rw-r--r--src/submodule.c5
-rw-r--r--src/tag.c10
-rw-r--r--src/transport.c6
-rw-r--r--src/transports/git.c12
-rw-r--r--src/transports/http.c8
-rw-r--r--src/transports/local.c14
-rw-r--r--src/tree.c314
-rw-r--r--src/tree.h12
-rw-r--r--src/unix/posix.h10
-rw-r--r--src/util.c24
-rw-r--r--src/util.h14
-rw-r--r--src/vector.c23
-rw-r--r--src/vector.h17
-rw-r--r--src/win32/posix.h2
-rw-r--r--src/win32/utf-conv.c23
60 files changed, 1322 insertions, 989 deletions
diff --git a/src/attr.c b/src/attr.c
index 616cec6ff..fb6651196 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -13,11 +13,11 @@ static int collect_attr_files(
int git_attr_get(
+ const char **value,
git_repository *repo,
uint32_t flags,
const char *pathname,
- const char *name,
- const char **value)
+ const char *name)
{
int error;
git_attr_path path;
@@ -64,12 +64,12 @@ typedef struct {
} attr_get_many_info;
int git_attr_get_many(
+ const char **values,
git_repository *repo,
uint32_t flags,
const char *pathname,
size_t num_attr,
- const char **names,
- const char **values)
+ const char **names)
{
int error;
git_attr_path path;
@@ -235,31 +235,91 @@ bool git_attr_cache__is_cached(
return rval;
}
-static int load_attr_file(const char *filename, const char **data)
+static int load_attr_file(
+ const char **data,
+ git_attr_file_stat_sig *sig,
+ const char *filename)
{
int error;
git_buf content = GIT_BUF_INIT;
+ struct stat st;
- error = git_futils_readbuffer(&content, filename);
- *data = error ? NULL : git_buf_detach(&content);
+ if (p_stat(filename, &st) < 0)
+ return GIT_ENOTFOUND;
- return error;
+ if (sig != NULL &&
+ (git_time_t)st.st_mtime == sig->seconds &&
+ (git_off_t)st.st_size == sig->size &&
+ (unsigned int)st.st_ino == sig->ino)
+ return GIT_ENOTFOUND;
+
+ error = git_futils_readbuffer_updated(&content, filename, NULL, NULL);
+ if (error < 0)
+ return error;
+
+ if (sig != NULL) {
+ sig->seconds = (git_time_t)st.st_mtime;
+ sig->size = (git_off_t)st.st_size;
+ sig->ino = (unsigned int)st.st_ino;
+ }
+
+ *data = git_buf_detach(&content);
+
+ return 0;
}
static int load_attr_blob_from_index(
- git_repository *repo, const char *filename, git_blob **blob)
+ const char **content,
+ git_blob **blob,
+ git_repository *repo,
+ const git_oid *old_oid,
+ const char *relfile)
{
int error;
git_index *index;
git_index_entry *entry;
if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
- (error = git_index_find(index, filename)) < 0)
+ (error = git_index_find(index, relfile)) < 0)
return error;
entry = git_index_get(index, error);
- return git_blob_lookup(blob, repo, &entry->oid);
+ if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0)
+ return GIT_ENOTFOUND;
+
+ if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0)
+ return error;
+
+ *content = git_blob_rawcontent(*blob);
+ return 0;
+}
+
+static int load_attr_from_cache(
+ git_attr_file **file,
+ git_attr_cache *cache,
+ git_attr_file_source source,
+ const char *relative_path)
+{
+ git_buf cache_key = GIT_BUF_INIT;
+ khiter_t cache_pos;
+
+ *file = NULL;
+
+ if (!cache || !cache->files)
+ return 0;
+
+ if (git_buf_printf(&cache_key, "%d#%s", (int)source, relative_path) < 0)
+ return -1;
+
+ cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr);
+
+ git_buf_free(&cache_key);
+
+ if (git_strmap_valid_index(cache->files, cache_pos))
+ *file = git_strmap_value_at(cache->files, cache_pos);
+
+ return 0;
}
int git_attr_cache__internal_file(
@@ -301,6 +361,7 @@ int git_attr_cache__push_file(
git_attr_cache *cache = git_repository_attr_cache(repo);
git_attr_file *file = NULL;
git_blob *blob = NULL;
+ git_attr_file_stat_sig st;
assert(filename && stack);
@@ -316,30 +377,23 @@ int git_attr_cache__push_file(
relfile += strlen(workdir);
/* check cache */
- if (cache && cache->files) {
- git_buf cache_key = GIT_BUF_INIT;
- khiter_t cache_pos;
-
- if (git_buf_printf(&cache_key, "%d#%s", (int)source, relfile) < 0)
- return -1;
+ if (load_attr_from_cache(&file, cache, source, relfile) < 0)
+ return -1;
- cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr);
+ /* if not in cache, load data, parse, and cache */
- git_buf_free(&cache_key);
+ if (source == GIT_ATTR_FILE_FROM_FILE) {
+ if (file)
+ memcpy(&st, &file->cache_data.st, sizeof(st));
+ else
+ memset(&st, 0, sizeof(st));
- if (git_strmap_valid_index(cache->files, cache_pos)) {
- file = git_strmap_value_at(cache->files, cache_pos);
- goto finish;
- }
+ error = load_attr_file(&content, &st, filename);
+ } else {
+ error = load_attr_blob_from_index(&content, &blob,
+ repo, file ? &file->cache_data.oid : NULL, relfile);
}
- /* if not in cache, load data, parse, and cache */
-
- if (source == GIT_ATTR_FILE_FROM_FILE)
- error = load_attr_file(filename, &content);
- else
- error = load_attr_blob_from_index(repo, relfile, &blob);
-
if (error) {
/* not finding a file is not an error for this function */
if (error == GIT_ENOTFOUND) {
@@ -349,11 +403,14 @@ int git_attr_cache__push_file(
goto finish;
}
- if (blob)
- content = git_blob_rawcontent(blob);
-
- if ((error = git_attr_file__new(&file, source, relfile, &cache->pool)) < 0)
- goto finish;
+ /* if we got here, we have to parse and/or reparse the file */
+ if (file)
+ git_attr_file__clear_rules(file);
+ else {
+ error = git_attr_file__new(&file, source, relfile, &cache->pool);
+ if (error < 0)
+ goto finish;
+ }
if (parse && (error = parse(repo, content, file)) < 0)
goto finish;
@@ -362,6 +419,12 @@ int git_attr_cache__push_file(
if (error > 0)
error = 0;
+ /* remember "cache buster" file signature */
+ if (blob)
+ git_oid_cpy(&file->cache_data.oid, git_object_id((git_object *)blob));
+ else
+ memcpy(&file->cache_data.st, &st, sizeof(st));
+
finish:
/* push file onto vector if we found one*/
if (!error && file != NULL)
@@ -518,11 +581,11 @@ int git_attr_cache__init(git_repository *repo)
if (git_repository_config__weakptr(&cfg, repo) < 0)
return -1;
- ret = git_config_get_string(cfg, GIT_ATTR_CONFIG, &cache->cfg_attr_file);
+ ret = git_config_get_string(&cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG);
if (ret < 0 && ret != GIT_ENOTFOUND)
return ret;
- ret = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &cache->cfg_excl_file);
+ ret = git_config_get_string(&cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG);
if (ret < 0 && ret != GIT_ENOTFOUND)
return ret;
diff --git a/src/attr_file.c b/src/attr_file.c
index 49ff7319f..ca2f8fb58 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -139,18 +139,23 @@ int git_attr_file__new_and_load(
return error;
}
-void git_attr_file__free(git_attr_file *file)
+void git_attr_file__clear_rules(git_attr_file *file)
{
unsigned int i;
git_attr_rule *rule;
- if (!file)
- return;
-
git_vector_foreach(&file->rules, i, rule)
git_attr_rule__free(rule);
git_vector_free(&file->rules);
+}
+
+void git_attr_file__free(git_attr_file *file)
+{
+ if (!file)
+ return;
+
+ git_attr_file__clear_rules(file);
if (file->pool_is_allocated) {
git_pool_clear(file->pool);
@@ -338,10 +343,13 @@ int git_attr_fnmatch__parse(
const char **base)
{
const char *pattern, *scan;
- int slash_count;
+ int slash_count, allow_space;
assert(spec && base && *base);
+ spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE);
+ allow_space = (spec->flags != 0);
+
pattern = *base;
while (git__isspace(*pattern)) pattern++;
@@ -350,8 +358,6 @@ int git_attr_fnmatch__parse(
return GIT_ENOTFOUND;
}
- spec->flags = 0;
-
if (*pattern == '[') {
if (strncmp(pattern, "[attr]", 6) == 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO;
@@ -368,8 +374,10 @@ int git_attr_fnmatch__parse(
slash_count = 0;
for (scan = pattern; *scan != '\0'; ++scan) {
/* scan until (non-escaped) white space */
- if (git__isspace(*scan) && *(scan - 1) != '\\')
- break;
+ if (git__isspace(*scan) && *(scan - 1) != '\\') {
+ if (!allow_space || (*scan != ' ' && *scan != '\t'))
+ break;
+ }
if (*scan == '/') {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_FULLPATH;
@@ -378,7 +386,7 @@ int git_attr_fnmatch__parse(
pattern++;
}
/* remember if we see an unescaped wildcard in pattern */
- else if ((*scan == '*' || *scan == '.' || *scan == '[') &&
+ else if (git__iswildcard(*scan) &&
(scan == pattern || (*(scan - 1) != '\\')))
spec->flags = spec->flags | GIT_ATTR_FNMATCH_HASWILD;
}
diff --git a/src/attr_file.h b/src/attr_file.h
index ec488c4dc..7939f838a 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -22,6 +22,7 @@
#define GIT_ATTR_FNMATCH_MACRO (1U << 3)
#define GIT_ATTR_FNMATCH_IGNORE (1U << 4)
#define GIT_ATTR_FNMATCH_HASWILD (1U << 5)
+#define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6)
typedef struct {
char *pattern;
@@ -48,10 +49,20 @@ typedef struct {
} git_attr_assignment;
typedef struct {
+ git_time_t seconds;
+ git_off_t size;
+ unsigned int ino;
+} git_attr_file_stat_sig;
+
+typedef struct {
char *key; /* cache "source#path" this was loaded from */
git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool *pool;
bool pool_is_allocated;
+ union {
+ git_oid oid;
+ git_attr_file_stat_sig st;
+ } cache_data;
} git_attr_file;
typedef struct {
@@ -78,6 +89,8 @@ extern int git_attr_file__new_and_load(
extern void git_attr_file__free(git_attr_file *file);
+extern void git_attr_file__clear_rules(git_attr_file *file);
+
extern int git_attr_file__parse_buffer(
git_repository *repo, const char *buf, git_attr_file *file);
diff --git a/src/blob.c b/src/blob.c
index 36571c70a..e25944b91 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -148,30 +148,20 @@ static int write_symlink(
return error;
}
-int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
+static int blob_create_internal(git_oid *oid, git_repository *repo, const char *path)
{
int error;
- git_buf full_path = GIT_BUF_INIT;
- git_off_t size;
struct stat st;
- const char *workdir;
git_odb *odb = NULL;
+ git_off_t size;
- workdir = git_repository_workdir(repo);
- assert(workdir); /* error to call this on bare repo */
-
- if ((error = git_buf_joinpath(&full_path, workdir, path)) < 0 ||
- (error = git_path_lstat(full_path.ptr, &st)) < 0 ||
- (error = git_repository_odb__weakptr(&odb, repo)) < 0)
- {
- git_buf_free(&full_path);
+ if ((error = git_path_lstat(path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0)
return error;
- }
size = st.st_size;
if (S_ISLNK(st.st_mode)) {
- error = write_symlink(oid, odb, full_path.ptr, (size_t)size);
+ error = write_symlink(oid, odb, path, (size_t)size);
} else {
git_vector write_filters = GIT_VECTOR_INIT;
int filter_count;
@@ -186,10 +176,10 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
} else if (filter_count == 0) {
/* No filters need to be applied to the document: we can stream
* directly from disk */
- error = write_file_stream(oid, odb, full_path.ptr, size);
+ error = write_file_stream(oid, odb, path, size);
} else {
/* We need to apply one or more filters */
- error = write_file_filtered(oid, odb, full_path.ptr, &write_filters);
+ error = write_file_filtered(oid, odb, path, &write_filters);
}
git_filters_free(&write_filters);
@@ -209,7 +199,41 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
*/
}
+ return error;
+}
+
+int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
+{
+ git_buf full_path = GIT_BUF_INIT;
+ const char *workdir;
+ int error;
+
+ workdir = git_repository_workdir(repo);
+ assert(workdir); /* error to call this on bare repo */
+
+ if (git_buf_joinpath(&full_path, workdir, path) < 0) {
+ git_buf_free(&full_path);
+ return -1;
+ }
+
+ error = blob_create_internal(oid, repo, git_buf_cstr(&full_path));
+
git_buf_free(&full_path);
return error;
}
+int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path)
+{
+ int error;
+ git_buf full_path = GIT_BUF_INIT;
+
+ if ((error = git_path_prettify(&full_path, path, NULL)) < 0) {
+ git_buf_free(&full_path);
+ return error;
+ }
+
+ error = blob_create_internal(oid, repo, git_buf_cstr(&full_path));
+
+ git_buf_free(&full_path);
+ return error;
+}
diff --git a/src/branch.c b/src/branch.c
index c980cf08c..5d5a24038 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -105,7 +105,7 @@ cleanup:
return error;
}
-int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_type branch_type)
+int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_t branch_type)
{
git_reference *branch = NULL;
git_reference *head = NULL;
@@ -114,7 +114,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE));
if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0)
- goto on_error;
+ return error;
if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) {
giterr_set(GITERR_REFERENCE, "Cannot locate HEAD.");
@@ -170,7 +170,7 @@ int git_branch_list(git_strarray *branch_names, git_repository *repo, unsigned i
filter.branchlist = &branchlist;
filter.branch_type = list_flags;
- error = git_reference_foreach(repo, GIT_REF_OID|GIT_REF_PACKED, &branch_list_cb, (void *)&filter);
+ error = git_reference_foreach(repo, GIT_REF_LISTALL, &branch_list_cb, (void *)&filter);
if (error < 0) {
git_vector_free(&branchlist);
return -1;
diff --git a/src/buffer.c b/src/buffer.c
index 2ecb088f8..783a36eb8 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -12,9 +12,9 @@
/* Used as default value for git_buf->ptr so that people can always
* assume ptr is non-NULL and zero terminated even for new git_bufs.
*/
-char git_buf_initbuf[1];
+char git_buf__initbuf[1];
-static char git_buf__oom;
+char git_buf__oom[1];
#define ENSURE_SIZE(b, d) \
if ((d) > buf->asize && git_buf_grow(b, (d)) < 0)\
@@ -25,7 +25,7 @@ void git_buf_init(git_buf *buf, size_t initial_size)
{
buf->asize = 0;
buf->size = 0;
- buf->ptr = git_buf_initbuf;
+ buf->ptr = git_buf__initbuf;
if (initial_size)
git_buf_grow(buf, initial_size);
@@ -35,7 +35,7 @@ int git_buf_grow(git_buf *buf, size_t target_size)
{
int error = git_buf_try_grow(buf, target_size);
if (error != 0)
- buf->ptr = &git_buf__oom;
+ buf->ptr = git_buf__oom;
return error;
}
@@ -44,7 +44,7 @@ int git_buf_try_grow(git_buf *buf, size_t target_size)
char *new_ptr;
size_t new_size;
- if (buf->ptr == &git_buf__oom)
+ if (buf->ptr == git_buf__oom)
return -1;
if (target_size <= buf->asize)
@@ -85,7 +85,7 @@ void git_buf_free(git_buf *buf)
{
if (!buf) return;
- if (buf->ptr != git_buf_initbuf && buf->ptr != &git_buf__oom)
+ if (buf->ptr != git_buf__initbuf && buf->ptr != git_buf__oom)
git__free(buf->ptr);
git_buf_init(buf, 0);
@@ -98,11 +98,6 @@ void git_buf_clear(git_buf *buf)
buf->ptr[0] = '\0';
}
-bool git_buf_oom(const git_buf *buf)
-{
- return (buf->ptr == &git_buf__oom);
-}
-
int git_buf_set(git_buf *buf, const char *data, size_t len)
{
if (len == 0 || data == NULL) {
@@ -164,7 +159,7 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
if (len < 0) {
git__free(buf->ptr);
- buf->ptr = &git_buf__oom;
+ buf->ptr = git_buf__oom;
return -1;
}
@@ -244,7 +239,7 @@ char *git_buf_detach(git_buf *buf)
{
char *data = buf->ptr;
- if (buf->asize == 0 || buf->ptr == &git_buf__oom)
+ if (buf->asize == 0 || buf->ptr == git_buf__oom)
return NULL;
git_buf_init(buf, 0);
@@ -415,3 +410,52 @@ int git_buf_cmp(const git_buf *a, const git_buf *b)
return (result != 0) ? result :
(a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
}
+
+int git_buf_common_prefix(git_buf *buf, const git_strarray *strings)
+{
+ size_t i;
+ const char *str, *pfx;
+
+ git_buf_clear(buf);
+
+ if (!strings || !strings->count)
+ return 0;
+
+ /* initialize common prefix to first string */
+ if (git_buf_sets(buf, strings->strings[0]) < 0)
+ return -1;
+
+ /* go through the rest of the strings, truncating to shared prefix */
+ for (i = 1; i < strings->count; ++i) {
+
+ for (str = strings->strings[i], pfx = buf->ptr;
+ *str && *str == *pfx; str++, pfx++)
+ /* scanning */;
+
+ git_buf_truncate(buf, pfx - buf->ptr);
+
+ if (!buf->size)
+ break;
+ }
+
+ return 0;
+}
+
+bool git_buf_is_binary(const git_buf *buf)
+{
+ size_t i;
+ int printable = 0, nonprintable = 0;
+
+ for (i = 0; i < buf->size; i++) {
+ unsigned char c = buf->ptr[i];
+ if (c > 0x1F && c < 0x7F)
+ printable++;
+ else if (c == '\0')
+ return true;
+ else if (!git__isspace(c))
+ nonprintable++;
+ }
+
+ return ((printable >> 7) < nonprintable);
+}
+
diff --git a/src/buffer.h b/src/buffer.h
index 1f0ec1c15..50c75f64e 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -15,9 +15,10 @@ typedef struct {
size_t asize, size;
} git_buf;
-extern char git_buf_initbuf[];
+extern char git_buf__initbuf[];
+extern char git_buf__oom[];
-#define GIT_BUF_INIT { git_buf_initbuf, 0, 0 }
+#define GIT_BUF_INIT { git_buf__initbuf, 0, 0 }
/**
* Initialize a git_buf structure.
@@ -61,7 +62,10 @@ void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
*
* @return false if no error, true if allocation error
*/
-bool git_buf_oom(const git_buf *buf);
+GIT_INLINE(bool) git_buf_oom(const git_buf *buf)
+{
+ return (buf->ptr == git_buf__oom);
+}
/*
* Functions below that return int value error codes will return 0 on
@@ -122,4 +126,10 @@ void git_buf_rtrim(git_buf *buf);
int git_buf_cmp(const git_buf *a, const git_buf *b);
+/* Fill buf with the common prefix of a array of strings */
+int git_buf_common_prefix(git_buf *buf, const git_strarray *strings);
+
+/* Check if buffer looks like it contains binary data */
+bool git_buf_is_binary(const git_buf *buf);
+
#endif
diff --git a/src/commit.c b/src/commit.c
index 2bf12f3a5..2f40dc67d 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -18,15 +18,6 @@
#include <stdarg.h>
-#define COMMIT_BASIC_PARSE 0x0
-#define COMMIT_FULL_PARSE 0x1
-
-#define COMMIT_PRINT(commit) {\
- char oid[41]; oid[40] = 0;\
- git_oid_fmt(oid, &commit->object.id);\
- printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
-}
-
static void clear_parents(git_commit *commit)
{
unsigned int i;
diff --git a/src/win32/fnmatch.c b/src/compat/fnmatch.c
index 835d811bc..835d811bc 100644
--- a/src/win32/fnmatch.c
+++ b/src/compat/fnmatch.c
diff --git a/src/win32/fnmatch.h b/src/compat/fnmatch.h
index eb7c5f6f7..7faef09b3 100644
--- a/src/win32/fnmatch.h
+++ b/src/compat/fnmatch.h
@@ -4,8 +4,8 @@
* 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_fnmatch__w32_h__
-#define INCLUDE_fnmatch__w32_h__
+#ifndef INCLUDE_fnmatch__compat_h__
+#define INCLUDE_fnmatch__compat_h__
#include "common.h"
diff --git a/src/config.c b/src/config.c
index 0ab0cd424..618202c34 100644
--- a/src/config.c
+++ b/src/config.c
@@ -199,30 +199,6 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
return file->set(file, name, value);
}
-int git_config_parse_bool(int *out, const char *value)
-{
- /* A missing value means true */
- if (value == NULL) {
- *out = 1;
- return 0;
- }
-
- if (!strcasecmp(value, "true") ||
- !strcasecmp(value, "yes") ||
- !strcasecmp(value, "on")) {
- *out = 1;
- return 0;
- }
- if (!strcasecmp(value, "false") ||
- !strcasecmp(value, "no") ||
- !strcasecmp(value, "off")) {
- *out = 0;
- return 0;
- }
-
- return -1;
-}
-
static int parse_int64(int64_t *out, const char *value)
{
const char *num_end;
@@ -297,7 +273,7 @@ int git_config_lookup_map_value(
case GIT_CVAR_TRUE: {
int bool_val;
- if (git_config_parse_bool(&bool_val, value) == 0 &&
+ if (git__parse_bool(&bool_val, value) == 0 &&
bool_val == (int)m->cvar_type) {
*out = m->map_value;
return 0;
@@ -322,12 +298,17 @@ int git_config_lookup_map_value(
return GIT_ENOTFOUND;
}
-int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out)
+int git_config_get_mapped(
+ int *out,
+ git_config *cfg,
+ const char *name,
+ git_cvar_map *maps,
+ size_t map_n)
{
const char *value;
int ret;
- ret = git_config_get_string(cfg, name, &value);
+ ret = git_config_get_string(&value, cfg, name);
if (ret < 0)
return ret;
@@ -339,12 +320,12 @@ int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps,
return -1;
}
-int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
+int git_config_get_int64(int64_t *out, git_config *cfg, const char *name)
{
const char *value;
int ret;
- ret = git_config_get_string(cfg, name, &value);
+ ret = git_config_get_string(&value, cfg, name);
if (ret < 0)
return ret;
@@ -356,12 +337,12 @@ int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
return 0;
}
-int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
+int git_config_get_int32(int32_t *out, git_config *cfg, const char *name)
{
const char *value;
int ret;
- ret = git_config_get_string(cfg, name, &value);
+ ret = git_config_get_string(&value, cfg, name);
if (ret < 0)
return ret;
@@ -373,16 +354,16 @@ int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
return 0;
}
-int git_config_get_bool(git_config *cfg, const char *name, int *out)
+int git_config_get_bool(int *out, git_config *cfg, const char *name)
{
const char *value;
int ret;
- ret = git_config_get_string(cfg, name, &value);
+ ret = git_config_get_string(&value, cfg, name);
if (ret < 0)
return ret;
- if (git_config_parse_bool(out, value) == 0)
+ if (git__parse_bool(out, value) == 0)
return 0;
if (parse_int32(out, value) == 0) {
@@ -394,7 +375,7 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out)
return -1;
}
-int git_config_get_string(git_config *cfg, const char *name, const char **out)
+int git_config_get_string(const char **out, git_config *cfg, const char *name)
{
file_internal *internal;
unsigned int i;
@@ -462,7 +443,7 @@ int git_config_find_global_r(git_buf *path)
return git_futils_find_global_file(path, GIT_CONFIG_FILENAME);
}
-int git_config_find_global(char *global_config_path)
+int git_config_find_global(char *global_config_path, size_t length)
{
git_buf path = GIT_BUF_INIT;
int ret = git_config_find_global_r(&path);
@@ -472,14 +453,14 @@ int git_config_find_global(char *global_config_path)
return ret;
}
- if (path.size > GIT_PATH_MAX) {
+ if (path.size >= length) {
git_buf_free(&path);
giterr_set(GITERR_NOMEMORY,
"Path is to long to fit on the given buffer");
return -1;
}
- git_buf_copy_cstr(global_config_path, GIT_PATH_MAX, &path);
+ git_buf_copy_cstr(global_config_path, length, &path);
git_buf_free(&path);
return 0;
}
@@ -489,7 +470,7 @@ int git_config_find_system_r(git_buf *path)
return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM);
}
-int git_config_find_system(char *system_config_path)
+int git_config_find_system(char *system_config_path, size_t length)
{
git_buf path = GIT_BUF_INIT;
int ret = git_config_find_system_r(&path);
@@ -499,14 +480,14 @@ int git_config_find_system(char *system_config_path)
return ret;
}
- if (path.size > GIT_PATH_MAX) {
+ if (path.size >= length) {
git_buf_free(&path);
giterr_set(GITERR_NOMEMORY,
"Path is to long to fit on the given buffer");
return -1;
}
- git_buf_copy_cstr(system_config_path, GIT_PATH_MAX, &path);
+ git_buf_copy_cstr(system_config_path, length, &path);
git_buf_free(&path);
return 0;
}
@@ -514,11 +495,14 @@ int git_config_find_system(char *system_config_path)
int git_config_open_global(git_config **out)
{
int error;
- char global_path[GIT_PATH_MAX];
+ git_buf path = GIT_BUF_INIT;
- if ((error = git_config_find_global(global_path)) < 0)
+ if ((error = git_config_find_global_r(&path)) < 0)
return error;
- return git_config_open_ondisk(out, global_path);
+ error = git_config_open_ondisk(out, git_buf_cstr(&path));
+ git_buf_free(&path);
+
+ return error;
}
diff --git a/src/config_cache.c b/src/config_cache.c
index 3679a9646..ca9602e56 100644
--- a/src/config_cache.c
+++ b/src/config_cache.c
@@ -66,22 +66,22 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
int error;
error = git_repository_config__weakptr(&config, repo);
- if (error < GIT_SUCCESS)
+ if (error < 0)
return error;
- error = git_config_get_mapped(
- config, data->cvar_name, data->maps, data->map_count, out);
+ error = git_config_get_mapped(out,
+ config, data->cvar_name, data->maps, data->map_count);
if (error == GIT_ENOTFOUND)
*out = data->default_value;
- else if (error < GIT_SUCCESS)
+ else if (error < 0)
return error;
repo->cvar_cache[(int)cvar] = *out;
}
- return GIT_SUCCESS;
+ return 0;
}
void git_repository__cvar_cache_clear(git_repository *repo)
diff --git a/src/config_file.c b/src/config_file.c
index cbc48bcd9..1c748fad1 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -443,8 +443,10 @@ static int config_delete(git_config_file *cfg, const char *name)
pos = git_strmap_lookup_index(b->values, key);
git__free(key);
- if (!git_strmap_valid_index(b->values, pos))
+ if (!git_strmap_valid_index(b->values, pos)) {
+ giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name);
return GIT_ENOTFOUND;
+ }
var = git_strmap_value_at(b->values, pos);
diff --git a/src/crlf.c b/src/crlf.c
index 5d09a1f40..303a46d3b 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -82,8 +82,8 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con
const char *attr_vals[NUM_CONV_ATTRS];
int error;
- error = git_attr_get_many(
- repo, 0, path, NUM_CONV_ATTRS, attr_names, attr_vals);
+ error = git_attr_get_many(attr_vals,
+ repo, 0, path, NUM_CONV_ATTRS, attr_names);
if (error == GIT_ENOTFOUND) {
ca->crlf_action = GIT_CRLF_GUESS;
@@ -91,7 +91,7 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con
return 0;
}
- if (error == GIT_SUCCESS) {
+ if (error == 0) {
ca->crlf_action = check_crlf(attr_vals[2]); /* text */
if (ca->crlf_action == GIT_CRLF_GUESS)
ca->crlf_action = check_crlf(attr_vals[0]); /* clrf */
@@ -100,7 +100,7 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con
return 0;
}
- return error;
+ return -1;
}
static int drop_crlf(git_buf *dest, const git_buf *source)
@@ -207,7 +207,7 @@ int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const
int auto_crlf;
if ((error = git_repository__cvar(
- &auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < GIT_SUCCESS)
+ &auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < 0)
return error;
if (auto_crlf == GIT_AUTO_CRLF_FALSE)
diff --git a/src/delta-apply.c b/src/delta-apply.c
index d3be084e0..815ca8f16 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -111,7 +111,7 @@ int git__delta_apply(
if (delta != delta_end || res_sz)
goto fail;
- return GIT_SUCCESS;
+ return 0;
fail:
git__free(out->data);
diff --git a/src/delta-apply.h b/src/delta-apply.h
index e46ef9af4..66fa76d43 100644
--- a/src/delta-apply.h
+++ b/src/delta-apply.h
@@ -20,7 +20,7 @@
* @param delta the delta to execute copy/insert instructions from.
* @param delta_len total number of bytes in the delta.
* @return
- * - GIT_SUCCESS on a successful delta unpack.
+ * - 0 on a successful delta unpack.
* - GIT_ERROR if the delta is corrupt or doesn't match the base.
*/
extern int git__delta_apply(
diff --git a/src/diff.c b/src/diff.c
index fed22f403..90baa9588 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -11,6 +11,25 @@
#include "config.h"
#include "attr_file.h"
+static char *diff_prefix_from_pathspec(const git_strarray *pathspec)
+{
+ git_buf prefix = GIT_BUF_INIT;
+ const char *scan;
+
+ if (git_buf_common_prefix(&prefix, pathspec) < 0)
+ return NULL;
+
+ /* diff prefix will only be leading non-wildcards */
+ for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan);
+ git_buf_truncate(&prefix, scan - prefix.ptr);
+
+ if (prefix.size > 0)
+ return git_buf_detach(&prefix);
+
+ git_buf_free(&prefix);
+ return NULL;
+}
+
static bool diff_pathspec_is_interesting(const git_strarray *pathspec)
{
const char *str;
@@ -251,8 +270,10 @@ static int diff_delta__cmp(const void *a, const void *b)
static int config_bool(git_config *cfg, const char *name, int defvalue)
{
int val = defvalue;
- if (git_config_get_bool(cfg, name, &val) < 0)
+
+ if (git_config_get_bool(&val, cfg, name) < 0)
giterr_clear();
+
return val;
}
@@ -321,6 +342,7 @@ static git_diff_list *git_diff_list_alloc(
git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
if (!match)
goto fail;
+ match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) {
git__free(match);
@@ -532,29 +554,27 @@ static int diff_from_iterators(
* matched in old (and/or descend into directories as needed)
*/
else if (nitem && (!oitem || strcmp(oitem->path, nitem->path) > 0)) {
- int is_ignored;
- git_delta_t delta_type = GIT_DELTA_ADDED;
+ git_delta_t delta_type = GIT_DELTA_UNTRACKED;
- /* contained in ignored parent directory, so this can be skipped. */
+ /* check if contained in ignored parent directory */
if (git_buf_len(&ignore_prefix) &&
git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
- {
- if (git_iterator_advance(new_iter, &nitem) < 0)
- goto fail;
-
- continue;
- }
-
- is_ignored = git_iterator_current_is_ignored(new_iter);
+ delta_type = GIT_DELTA_IGNORED;
if (S_ISDIR(nitem->mode)) {
- /* recurse into directory if explicitly requested or
- * if there are tracked items inside the directory
+ /* recurse into directory only if there are tracked items in
+ * it or if the user requested the contents of untracked
+ * directories and it is not under an ignored directory.
*/
- if ((diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) ||
- (oitem && git__prefixcmp(oitem->path, nitem->path) == 0))
+ if ((oitem && git__prefixcmp(oitem->path, nitem->path) == 0) ||
+ (delta_type == GIT_DELTA_UNTRACKED &&
+ (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0))
{
- if (is_ignored)
+ /* if this directory is ignored, remember it as the
+ * "ignore_prefix" for processing contained items
+ */
+ if (delta_type == GIT_DELTA_UNTRACKED &&
+ git_iterator_current_is_ignored(new_iter))
git_buf_sets(&ignore_prefix, nitem->path);
if (git_iterator_advance_into_directory(new_iter, &nitem) < 0)
@@ -562,12 +582,34 @@ static int diff_from_iterators(
continue;
}
- delta_type = GIT_DELTA_UNTRACKED;
}
- else if (is_ignored)
+
+ /* In core git, the next two "else if" clauses are effectively
+ * reversed -- i.e. when an untracked file contained in an
+ * ignored directory is individually ignored, it shows up as an
+ * ignored file in the diff list, even though other untracked
+ * files in the same directory are skipped completely.
+ *
+ * To me, this is odd. If the directory is ignored and the file
+ * is untracked, we should skip it consistently, regardless of
+ * whether it happens to match a pattern in the ignore file.
+ *
+ * To match the core git behavior, just reverse the following
+ * two "else if" cases so that individual file ignores are
+ * checked before container directory exclusions are used to
+ * skip the file.
+ */
+ else if (delta_type == GIT_DELTA_IGNORED) {
+ if (git_iterator_advance(new_iter, &nitem) < 0)
+ goto fail;
+ continue; /* ignored parent directory, so skip completely */
+ }
+
+ else if (git_iterator_current_is_ignored(new_iter))
delta_type = GIT_DELTA_IGNORED;
- else if (new_iter->type == GIT_ITERATOR_WORKDIR)
- delta_type = GIT_DELTA_UNTRACKED;
+
+ else if (new_iter->type != GIT_ITERATOR_WORKDIR)
+ delta_type = GIT_DELTA_ADDED;
if (diff_delta__from_one(diff, delta_type, nitem) < 0 ||
git_iterator_advance(new_iter, &nitem) < 0)
@@ -613,13 +655,16 @@ int git_diff_tree_to_tree(
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
+ char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && old_tree && new_tree && diff);
- if (git_iterator_for_tree(repo, old_tree, &a) < 0 ||
- git_iterator_for_tree(repo, new_tree, &b) < 0)
+ if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
+ git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0)
return -1;
+ git__free(prefix);
+
return diff_from_iterators(repo, opts, a, b, diff);
}
@@ -630,13 +675,16 @@ int git_diff_index_to_tree(
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
+ char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && diff);
- if (git_iterator_for_tree(repo, old_tree, &a) < 0 ||
- git_iterator_for_index(repo, &b) < 0)
+ if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
+ git_iterator_for_index_range(&b, repo, prefix, prefix) < 0)
return -1;
+ git__free(prefix);
+
return diff_from_iterators(repo, opts, a, b, diff);
}
@@ -646,13 +694,16 @@ int git_diff_workdir_to_index(
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
+ char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && diff);
- if (git_iterator_for_index(repo, &a) < 0 ||
- git_iterator_for_workdir(repo, &b) < 0)
+ if (git_iterator_for_index_range(&a, repo, prefix, prefix) < 0 ||
+ git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0)
return -1;
+ git__free(prefix);
+
return diff_from_iterators(repo, opts, a, b, diff);
}
@@ -664,13 +715,16 @@ int git_diff_workdir_to_tree(
git_diff_list **diff)
{
git_iterator *a = NULL, *b = NULL;
+ char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
assert(repo && old_tree && diff);
- if (git_iterator_for_tree(repo, old_tree, &a) < 0 ||
- git_iterator_for_workdir(repo, &b) < 0)
+ if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
+ git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0)
return -1;
+ git__free(prefix);
+
return diff_from_iterators(repo, opts, a, b, diff);
}
diff --git a/src/diff_output.c b/src/diff_output.c
index 9c8e07972..5ffa641c4 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -103,7 +103,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file)
{
const char *value;
- if (git_attr_get(repo, 0, file->path, "diff", &value) < 0)
+ if (git_attr_get(&value, repo, 0, file->path, "diff") < 0)
return -1;
if (GIT_ATTR_FALSE(value))
@@ -174,15 +174,12 @@ static int file_is_binary_by_content(
git_map *new_data)
{
git_buf search;
- git_text_stats stats;
if ((delta->old_file.flags & BINARY_DIFF_FLAGS) == 0) {
search.ptr = old_data->data;
search.size = min(old_data->len, 4000);
- git_text_gather_stats(&stats, &search);
-
- if (git_text_is_binary(&stats))
+ if (git_buf_is_binary(&search))
delta->old_file.flags |= GIT_DIFF_FILE_BINARY;
else
delta->old_file.flags |= GIT_DIFF_FILE_NOT_BINARY;
@@ -192,9 +189,7 @@ static int file_is_binary_by_content(
search.ptr = new_data->data;
search.size = min(new_data->len, 4000);
- git_text_gather_stats(&stats, &search);
-
- if (git_text_is_binary(&stats))
+ if (git_buf_is_binary(&search))
delta->new_file.flags |= GIT_DIFF_FILE_BINARY;
else
delta->new_file.flags |= GIT_DIFF_FILE_NOT_BINARY;
@@ -392,7 +387,7 @@ int git_diff_foreach(
if (error < 0)
goto cleanup;
- if ((delta->new_file.flags | GIT_DIFF_FILE_VALID_OID) == 0) {
+ if ((delta->new_file.flags & GIT_DIFF_FILE_VALID_OID) == 0) {
error = git_odb_hash(
&delta->new_file.oid, new_data.data, new_data.len, GIT_OBJ_BLOB);
diff --git a/src/fetch.c b/src/fetch.c
index 08c789ddb..c92cf4ef5 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -165,7 +165,7 @@ int git_fetch_setup_walk(git_revwalk **out, git_repository *repo)
unsigned int i;
git_reference *ref;
- if (git_reference_listall(&refs, repo, GIT_REF_LISTALL) < 0)
+ if (git_reference_list(&refs, repo, GIT_REF_LISTALL) < 0)
return -1;
if (git_revwalk_new(&walk, repo) < 0)
diff --git a/src/fileops.c b/src/fileops.c
index bf95f769c..95a65893c 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -185,9 +185,6 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
p_close(fd);
- if (mtime != NULL)
- *mtime = st.st_mtime;
-
if (updated != NULL)
*updated = 1;
@@ -244,28 +241,36 @@ void git_futils_mmap_free(git_map *out)
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
{
- int root_path_offset;
git_buf make_path = GIT_BUF_INIT;
- size_t start;
+ size_t start = 0;
char *pp, *sp;
bool failed = false;
if (base != NULL) {
+ /*
+ * when a base is being provided, it is supposed to already exist.
+ * Therefore, no attempt is being made to recursively create this leading path
+ * segment. It's just skipped. */
start = strlen(base);
if (git_buf_joinpath(&make_path, base, path) < 0)
return -1;
} else {
- start = 0;
+ int root_path_offset;
+
if (git_buf_puts(&make_path, path) < 0)
return -1;
+
+ root_path_offset = git_path_root(make_path.ptr);
+ if (root_path_offset > 0) {
+ /*
+ * On Windows, will skip the drive name (eg. C: or D:)
+ * or the leading part of a network path (eg. //computer_name ) */
+ start = root_path_offset;
+ }
}
pp = make_path.ptr + start;
- root_path_offset = git_path_root(make_path.ptr);
- if (root_path_offset > 0)
- pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
-
while (!failed && (sp = strchr(pp, '/')) != NULL) {
if (sp != pp && git_path_isdir(make_path.ptr) == false) {
*sp = 0;
@@ -309,7 +314,7 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
return -1;
if (p_rmdir(path->ptr) < 0) {
- if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && errno == ENOTEMPTY)
+ if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && (errno == ENOTEMPTY || errno == EEXIST))
return 0;
giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr);
@@ -348,72 +353,23 @@ int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type
return error;
}
-int git_futils_find_global_file(git_buf *path, const char *filename)
-{
- const char *home = getenv("HOME");
-
#ifdef GIT_WIN32
- if (home == NULL)
- home = getenv("USERPROFILE");
-#endif
-
- if (home == NULL) {
- giterr_set(GITERR_OS, "Global file lookup failed. "
- "Cannot locate the user's home directory");
- return -1;
- }
-
- if (git_buf_joinpath(path, home, filename) < 0)
- return -1;
-
- if (git_path_exists(path->ptr) == false) {
- git_buf_clear(path);
- return GIT_ENOTFOUND;
- }
-
- return 0;
-}
-
-#ifdef GIT_WIN32
-typedef struct {
- wchar_t *path;
+struct win32_path {
+ wchar_t path[MAX_PATH];
DWORD len;
-} win32_path;
+};
-static const win32_path *win32_system_root(void)
+static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ)
{
- static win32_path s_root = { 0, 0 };
-
- if (s_root.path == NULL) {
- const wchar_t *root_tmpl = L"%PROGRAMFILES%\\Git\\etc\\";
-
- s_root.len = ExpandEnvironmentStringsW(root_tmpl, NULL, 0);
- if (s_root.len <= 0) {
- giterr_set(GITERR_OS, "Failed to expand environment strings");
- return NULL;
- }
-
- s_root.path = git__calloc(s_root.len, sizeof(wchar_t));
- if (s_root.path == NULL)
- return NULL;
-
- if (ExpandEnvironmentStringsW(root_tmpl, s_root.path, s_root.len) != s_root.len) {
- giterr_set(GITERR_OS, "Failed to expand environment strings");
- git__free(s_root.path);
- s_root.path = NULL;
- return NULL;
- }
- }
-
- return &s_root;
+ s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH);
+ return s_root->len ? 0 : -1;
}
-static int win32_find_system_file(git_buf *path, const char *filename)
+static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename)
{
int error = 0;
- const win32_path *root = win32_system_root();
size_t len;
- wchar_t *file_utf16 = NULL, *scan;
+ wchar_t *file_utf16 = NULL;
char *file_utf8 = NULL;
if (!root || !filename || (len = strlen(filename)) == 0)
@@ -435,10 +391,6 @@ static int win32_find_system_file(git_buf *path, const char *filename)
goto cleanup;
}
- for (scan = file_utf16; *scan; scan++)
- if (*scan == L'/')
- *scan = L'\\';
-
/* check access */
if (_waccess(file_utf16, F_OK) < 0) {
error = GIT_ENOTFOUND;
@@ -455,13 +407,30 @@ static int win32_find_system_file(git_buf *path, const char *filename)
cleanup:
git__free(file_utf16);
-
return error;
}
#endif
int git_futils_find_system_file(git_buf *path, const char *filename)
{
+#ifdef GIT_WIN32
+ struct win32_path root;
+
+ if (win32_expand_path(&root, L"%PROGRAMFILES%\\Git\\etc\\") < 0 ||
+ root.path[0] == L'%') /* i.e. no expansion happened */
+ {
+ giterr_set(GITERR_OS, "Cannot locate the system's Program Files directory");
+ return -1;
+ }
+
+ if (win32_find_file(path, &root, filename) < 0) {
+ git_buf_clear(path);
+ return GIT_ENOTFOUND;
+ }
+
+ return 0;
+
+#else
if (git_buf_joinpath(path, "/etc", filename) < 0)
return -1;
@@ -469,10 +438,45 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
return 0;
git_buf_clear(path);
+ return GIT_ENOTFOUND;
+#endif
+}
+int git_futils_find_global_file(git_buf *path, const char *filename)
+{
#ifdef GIT_WIN32
- return win32_find_system_file(path, filename);
+ struct win32_path root;
+
+ if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 ||
+ root.path[0] == L'%') /* i.e. no expansion happened */
+ {
+ giterr_set(GITERR_OS, "Cannot locate the user's profile directory");
+ return -1;
+ }
+
+ if (win32_find_file(path, &root, filename) < 0) {
+ git_buf_clear(path);
+ return GIT_ENOTFOUND;
+ }
+
+ return 0;
#else
- return GIT_ENOTFOUND;
+ const char *home = getenv("HOME");
+
+ if (home == NULL) {
+ giterr_set(GITERR_OS, "Global file lookup failed. "
+ "Cannot locate the user's home directory");
+ return -1;
+ }
+
+ if (git_buf_joinpath(path, home, filename) < 0)
+ return -1;
+
+ if (git_path_exists(path->ptr) == false) {
+ git_buf_clear(path);
+ return GIT_ENOTFOUND;
+ }
+
+ return 0;
#endif
}
diff --git a/src/fileops.h b/src/fileops.h
index be619d620..b0c5779e5 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -49,6 +49,9 @@ extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmo
/**
* Create a path recursively
+ *
+ * If a base parameter is being passed, it's expected to be valued with a path pointing to an already
+ * exisiting directory.
*/
extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode);
diff --git a/src/filter.c b/src/filter.c
index 73fe83e61..8fa3eb684 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -129,7 +129,7 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters)
if (git_buf_len(source) == 0) {
git_buf_clear(dest);
- return GIT_SUCCESS;
+ return 0;
}
/* Pre-grow the destination buffer to more or less the size
@@ -160,6 +160,6 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters)
if (src != 1)
git_buf_swap(dest, source);
- return GIT_SUCCESS;
+ return 0;
}
diff --git a/src/filter.h b/src/filter.h
index 5a77f25c6..66e370aef 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -75,7 +75,7 @@ extern int git_filters_load(git_vector *filters, git_repository *repo, const cha
* @param dest Buffer to store the result of the filtering
* @param source Buffer containing the document to filter
* @param filters A non-empty vector of filters as supplied by `git_filters_load`
- * @return GIT_SUCCESS on success, an error code otherwise
+ * @return 0 on success, an error code otherwise
*/
extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters);
diff --git a/src/index.c b/src/index.c
index 216ede777..f1ae9a710 100644
--- a/src/index.c
+++ b/src/index.c
@@ -502,6 +502,15 @@ int git_index_find(git_index *index, const char *path)
return git_vector_bsearch2(&index->entries, index_srch, path);
}
+unsigned int git_index__prefix_position(git_index *index, const char *path)
+{
+ unsigned int pos;
+
+ git_vector_bsearch3(&pos, &index->entries, index_srch, path);
+
+ return pos;
+}
+
void git_index_uniq(git_index *index)
{
git_vector_uniq(&index->entries);
@@ -930,7 +939,7 @@ static int read_tree_cb(const char *root, git_tree_entry *tentry, void *data)
git_index_entry *entry = NULL;
git_buf path = GIT_BUF_INIT;
- if (entry_is_tree(tentry))
+ if (git_tree_entry__is_tree(tentry))
return 0;
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
diff --git a/src/index.h b/src/index.h
index e745c8f69..8515f4fcb 100644
--- a/src/index.h
+++ b/src/index.h
@@ -33,4 +33,6 @@ struct git_index {
extern void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry);
+extern unsigned int git_index__prefix_position(git_index *index, const char *path);
+
#endif
diff --git a/src/indexer.c b/src/indexer.c
index 0baa194d6..f0e0a6381 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -110,12 +110,12 @@ static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack)
}
if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) {
- giterr_set(GITERR_INVALID, "Wrong pack signature");
+ giterr_set(GITERR_INDEXER, "Wrong pack signature");
return -1;
}
if (!pack_version_ok(hdr->hdr_version)) {
- giterr_set(GITERR_INVALID, "Wrong pack version");
+ giterr_set(GITERR_INDEXER, "Wrong pack version");
return -1;
}
@@ -205,9 +205,9 @@ static int store_delta(git_indexer_stream *idx)
}
error = packfile_unpack_compressed(&obj, idx->pack, &w, &idx->off, entry_size, type);
- if (error == GIT_ESHORTBUFFER) {
+ if (error == GIT_EBUFS) {
idx->off = entry_start;
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
} else if (error < 0){
return -1;
}
@@ -248,7 +248,7 @@ static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t ent
/* FIXME: Parse the object instead of hashing it */
if (git_odb__hashobj(&oid, obj) < 0) {
- giterr_set(GITERR_INVALID, "Failed to hash object");
+ giterr_set(GITERR_INDEXER, "Failed to hash object");
return -1;
}
@@ -355,7 +355,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
return 0;
error = git_packfile_unpack(&obj, idx->pack, &idx->off);
- if (error == GIT_ESHORTBUFFER) {
+ if (error == GIT_EBUFS) {
idx->off = entry_start;
return 0;
}
@@ -363,7 +363,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
if (error < 0) {
idx->off = entry_start;
error = store_delta(idx);
- if (error == GIT_ESHORTBUFFER)
+ if (error == GIT_EBUFS)
return 0;
if (error < 0)
return error;
@@ -441,10 +441,21 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
git_oid file_hash;
SHA_CTX ctx;
+ /* Test for this before resolve_deltas(), as it plays with idx->off */
+ if (idx->off < idx->pack->mwf.size - GIT_OID_RAWSZ) {
+ giterr_set(GITERR_INDEXER, "Indexing error: junk at the end of the pack");
+ return -1;
+ }
+
if (idx->deltas.length > 0)
if (resolve_deltas(idx, stats) < 0)
return -1;
+ if (stats->processed != stats->total) {
+ giterr_set(GITERR_INDEXER, "Indexing error: early EOF");
+ return -1;
+ }
+
git_vector_sort(&idx->objects);
git_buf_sets(&filename, idx->pack->pack_name);
@@ -583,7 +594,7 @@ int git_indexer_new(git_indexer **out, const char *packname)
assert(out && packname);
if (git_path_root(packname) < 0) {
- giterr_set(GITERR_INVALID, "Path is not absolute");
+ giterr_set(GITERR_INDEXER, "Path is not absolute");
return -1;
}
@@ -815,7 +826,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
/* FIXME: Parse the object instead of hashing it */
error = git_odb__hashobj(&oid, &obj);
if (error < 0) {
- giterr_set(GITERR_INVALID, "Failed to hash object");
+ giterr_set(GITERR_INDEXER, "Failed to hash object");
goto cleanup;
}
@@ -828,7 +839,6 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
git_oid_cpy(&pentry->sha1, &oid);
pentry->offset = entry_start;
git_oid_fmt(fmt, &oid);
- printf("adding %s to cache\n", fmt);
error = git_vector_insert(&idx->pack->cache, pentry);
if (error < 0)
goto cleanup;
diff --git a/src/iterator.c b/src/iterator.c
index 646990d3f..819b0e22a 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -11,6 +11,23 @@
#include "buffer.h"
#include "git2/submodule.h"
+#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \
+ (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
+ GITERR_CHECK_ALLOC(P); \
+ (P)->base.type = GIT_ITERATOR_ ## NAME_UC; \
+ (P)->base.start = start ? git__strdup(start) : NULL; \
+ (P)->base.end = end ? git__strdup(end) : NULL; \
+ (P)->base.current = NAME_LC ## _iterator__current; \
+ (P)->base.at_end = NAME_LC ## _iterator__at_end; \
+ (P)->base.advance = NAME_LC ## _iterator__advance; \
+ (P)->base.seek = NAME_LC ## _iterator__seek; \
+ (P)->base.reset = NAME_LC ## _iterator__reset; \
+ (P)->base.free = NAME_LC ## _iterator__free; \
+ if ((start && !(P)->base.start) || (end && !(P)->base.end)) \
+ return -1; \
+ } while (0)
+
+
static int empty_iterator__no_item(
git_iterator *iter, const git_index_entry **entry)
{
@@ -31,6 +48,13 @@ static int empty_iterator__noop(git_iterator *iter)
return 0;
}
+static int empty_iterator__seek(git_iterator *iter, const char *prefix)
+{
+ GIT_UNUSED(iter);
+ GIT_UNUSED(prefix);
+ return -1;
+}
+
static void empty_iterator__free(git_iterator *iter)
{
GIT_UNUSED(iter);
@@ -45,6 +69,7 @@ int git_iterator_for_nothing(git_iterator **iter)
i->current = empty_iterator__no_item;
i->at_end = empty_iterator__at_end;
i->advance = empty_iterator__no_item;
+ i->seek = empty_iterator__seek;
i->reset = empty_iterator__noop;
i->free = empty_iterator__free;
@@ -53,10 +78,12 @@ int git_iterator_for_nothing(git_iterator **iter)
return 0;
}
+
typedef struct tree_iterator_frame tree_iterator_frame;
struct tree_iterator_frame {
tree_iterator_frame *next;
git_tree *tree;
+ char *start;
unsigned int index;
};
@@ -66,6 +93,7 @@ typedef struct {
tree_iterator_frame *stack;
git_index_entry entry;
git_buf path;
+ bool path_has_filename;
} tree_iterator;
static const git_tree_entry *tree_iterator__tree_entry(tree_iterator *ti)
@@ -74,25 +102,62 @@ static const git_tree_entry *tree_iterator__tree_entry(tree_iterator *ti)
git_tree_entry_byindex(ti->stack->tree, ti->stack->index);
}
+static char *tree_iterator__current_filename(
+ tree_iterator *ti, const git_tree_entry *te)
+{
+ if (!ti->path_has_filename) {
+ if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0)
+ return NULL;
+ ti->path_has_filename = true;
+ }
+
+ return ti->path.ptr;
+}
+
+static void tree_iterator__pop_frame(tree_iterator *ti)
+{
+ tree_iterator_frame *tf = ti->stack;
+ ti->stack = tf->next;
+ if (ti->stack != NULL) /* don't free the initial tree */
+ git_tree_free(tf->tree);
+ git__free(tf);
+}
+
+static int tree_iterator__to_end(tree_iterator *ti)
+{
+ while (ti->stack && ti->stack->next)
+ tree_iterator__pop_frame(ti);
+
+ if (ti->stack)
+ ti->stack->index = git_tree_entrycount(ti->stack->tree);
+
+ return 0;
+}
+
static int tree_iterator__current(
git_iterator *self, const git_index_entry **entry)
{
tree_iterator *ti = (tree_iterator *)self;
const git_tree_entry *te = tree_iterator__tree_entry(ti);
- *entry = NULL;
+ if (entry)
+ *entry = NULL;
if (te == NULL)
return 0;
ti->entry.mode = te->attr;
git_oid_cpy(&ti->entry.oid, &te->oid);
- if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0)
+
+ ti->entry.path = tree_iterator__current_filename(ti, te);
+ if (ti->entry.path == NULL)
return -1;
- ti->entry.path = ti->path.ptr;
+ if (ti->base.end && git__prefixcmp(ti->entry.path, ti->base.end) > 0)
+ return tree_iterator__to_end(ti);
- *entry = &ti->entry;
+ if (entry)
+ *entry = &ti->entry;
return 0;
}
@@ -102,11 +167,20 @@ static int tree_iterator__at_end(git_iterator *self)
return (tree_iterator__tree_entry((tree_iterator *)self) == NULL);
}
-static tree_iterator_frame *tree_iterator__alloc_frame(git_tree *tree)
+static tree_iterator_frame *tree_iterator__alloc_frame(
+ git_tree *tree, char *start)
{
tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame));
- if (tf != NULL)
- tf->tree = tree;
+ if (!tf)
+ return NULL;
+
+ tf->tree = tree;
+
+ if (start && *start) {
+ tf->start = start;
+ tf->index = git_tree__prefix_position(tree, start);
+ }
+
return tf;
}
@@ -116,35 +190,43 @@ static int tree_iterator__expand_tree(tree_iterator *ti)
git_tree *subtree;
const git_tree_entry *te = tree_iterator__tree_entry(ti);
tree_iterator_frame *tf;
+ char *relpath;
+
+ while (te != NULL && git_tree_entry__is_tree(te)) {
+ if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0)
+ return -1;
+
+ /* check that we have not passed the range end */
+ if (ti->base.end != NULL &&
+ git__prefixcmp(ti->path.ptr, ti->base.end) > 0)
+ return tree_iterator__to_end(ti);
- while (te != NULL && entry_is_tree(te)) {
if ((error = git_tree_lookup(&subtree, ti->repo, &te->oid)) < 0)
return error;
- if ((tf = tree_iterator__alloc_frame(subtree)) == NULL)
+ relpath = NULL;
+
+ /* apply range start to new frame if relevant */
+ if (ti->stack->start &&
+ git__prefixcmp(ti->stack->start, te->filename) == 0)
+ {
+ size_t namelen = strlen(te->filename);
+ if (ti->stack->start[namelen] == '/')
+ relpath = ti->stack->start + namelen + 1;
+ }
+
+ if ((tf = tree_iterator__alloc_frame(subtree, relpath)) == NULL)
return -1;
tf->next = ti->stack;
ti->stack = tf;
- if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0)
- return -1;
-
te = tree_iterator__tree_entry(ti);
}
return 0;
}
-static void tree_iterator__pop_frame(tree_iterator *ti)
-{
- tree_iterator_frame *tf = ti->stack;
- ti->stack = tf->next;
- if (ti->stack != NULL) /* don't free the initial tree */
- git_tree_free(tf->tree);
- git__free(tf);
-}
-
static int tree_iterator__advance(
git_iterator *self, const git_index_entry **entry)
{
@@ -155,26 +237,40 @@ static int tree_iterator__advance(
if (entry != NULL)
*entry = NULL;
- while (ti->stack != NULL) {
- /* remove old entry filename */
+ if (ti->path_has_filename) {
git_buf_rtruncate_at_char(&ti->path, '/');
+ ti->path_has_filename = false;
+ }
+ while (ti->stack != NULL) {
te = git_tree_entry_byindex(ti->stack->tree, ++ti->stack->index);
if (te != NULL)
break;
tree_iterator__pop_frame(ti);
+
+ git_buf_rtruncate_at_char(&ti->path, '/');
}
- if (te && entry_is_tree(te))
+ if (te && git_tree_entry__is_tree(te))
error = tree_iterator__expand_tree(ti);
- if (!error && entry != NULL)
+ if (!error)
error = tree_iterator__current(self, entry);
return error;
}
+static int tree_iterator__seek(git_iterator *self, const char *prefix)
+{
+ GIT_UNUSED(self);
+ GIT_UNUSED(prefix);
+ /* pop stack until matches prefix */
+ /* seek item in current frame matching prefix */
+ /* push stack which matches prefix */
+ return -1;
+}
+
static void tree_iterator__free(git_iterator *self)
{
tree_iterator *ti = (tree_iterator *)self;
@@ -186,15 +282,25 @@ static void tree_iterator__free(git_iterator *self)
static int tree_iterator__reset(git_iterator *self)
{
tree_iterator *ti = (tree_iterator *)self;
+
while (ti->stack && ti->stack->next)
tree_iterator__pop_frame(ti);
+
if (ti->stack)
- ti->stack->index = 0;
+ ti->stack->index =
+ git_tree__prefix_position(ti->stack->tree, ti->base.start);
+
+ git_buf_clear(&ti->path);
+
return tree_iterator__expand_tree(ti);
}
-int git_iterator_for_tree(
- git_repository *repo, git_tree *tree, git_iterator **iter)
+int git_iterator_for_tree_range(
+ git_iterator **iter,
+ git_repository *repo,
+ git_tree *tree,
+ const char *start,
+ const char *end)
{
int error;
tree_iterator *ti;
@@ -202,22 +308,16 @@ int git_iterator_for_tree(
if (tree == NULL)
return git_iterator_for_nothing(iter);
- ti = git__calloc(1, sizeof(tree_iterator));
- GITERR_CHECK_ALLOC(ti);
+ ITERATOR_BASE_INIT(ti, tree, TREE);
- ti->base.type = GIT_ITERATOR_TREE;
- ti->base.current = tree_iterator__current;
- ti->base.at_end = tree_iterator__at_end;
- ti->base.advance = tree_iterator__advance;
- ti->base.reset = tree_iterator__reset;
- ti->base.free = tree_iterator__free;
- ti->repo = repo;
- ti->stack = tree_iterator__alloc_frame(tree);
+ ti->repo = repo;
+ ti->stack = tree_iterator__alloc_frame(tree, ti->base.start);
if ((error = tree_iterator__expand_tree(ti)) < 0)
git_iterator_free((git_iterator *)ti);
else
*iter = (git_iterator *)ti;
+
return error;
}
@@ -232,7 +332,19 @@ static int index_iterator__current(
git_iterator *self, const git_index_entry **entry)
{
index_iterator *ii = (index_iterator *)self;
- *entry = git_index_get(ii->index, ii->current);
+ git_index_entry *ie = git_index_get(ii->index, ii->current);
+
+ if (ie != NULL &&
+ ii->base.end != NULL &&
+ git__prefixcmp(ie->path, ii->base.end) > 0)
+ {
+ ii->current = git_index_entrycount(ii->index);
+ ie = NULL;
+ }
+
+ if (entry)
+ *entry = ie;
+
return 0;
}
@@ -246,11 +358,19 @@ static int index_iterator__advance(
git_iterator *self, const git_index_entry **entry)
{
index_iterator *ii = (index_iterator *)self;
+
if (ii->current < git_index_entrycount(ii->index))
ii->current++;
- if (entry)
- *entry = git_index_get(ii->index, ii->current);
- return 0;
+
+ return index_iterator__current(self, entry);
+}
+
+static int index_iterator__seek(git_iterator *self, const char *prefix)
+{
+ GIT_UNUSED(self);
+ GIT_UNUSED(prefix);
+ /* find last item before prefix */
+ return -1;
}
static int index_iterator__reset(git_iterator *self)
@@ -267,24 +387,24 @@ static void index_iterator__free(git_iterator *self)
ii->index = NULL;
}
-int git_iterator_for_index(git_repository *repo, git_iterator **iter)
+int git_iterator_for_index_range(
+ git_iterator **iter,
+ git_repository *repo,
+ const char *start,
+ const char *end)
{
int error;
- index_iterator *ii = git__calloc(1, sizeof(index_iterator));
- GITERR_CHECK_ALLOC(ii);
+ index_iterator *ii;
- ii->base.type = GIT_ITERATOR_INDEX;
- ii->base.current = index_iterator__current;
- ii->base.at_end = index_iterator__at_end;
- ii->base.advance = index_iterator__advance;
- ii->base.reset = index_iterator__reset;
- ii->base.free = index_iterator__free;
- ii->current = 0;
+ ITERATOR_BASE_INIT(ii, index, INDEX);
if ((error = git_repository_index(&ii->index, repo)) < 0)
git__free(ii);
- else
+ else {
+ ii->current = start ? git_index__prefix_position(ii->index, start) : 0;
*iter = (git_iterator *)ii;
+ }
+
return error;
}
@@ -294,6 +414,7 @@ struct workdir_iterator_frame {
workdir_iterator_frame *next;
git_vector entries;
unsigned int index;
+ char *start;
};
typedef struct {
@@ -332,6 +453,12 @@ static void workdir_iterator__free_frame(workdir_iterator_frame *wf)
static int workdir_iterator__update_entry(workdir_iterator *wi);
+static int workdir_iterator__entry_cmp(const void *prefix, const void *item)
+{
+ const git_path_with_stat *ps = item;
+ return git__prefixcmp((const char *)prefix, ps->path);
+}
+
static int workdir_iterator__expand_dir(workdir_iterator *wi)
{
int error;
@@ -345,6 +472,17 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi)
}
git_vector_sort(&wf->entries);
+
+ if (!wi->stack)
+ wf->start = wi->base.start;
+ else if (wi->stack->start &&
+ git__prefixcmp(wi->stack->start, wi->path.ptr + wi->root_len) == 0)
+ wf->start = wi->stack->start;
+
+ if (wf->start)
+ git_vector_bsearch3(
+ &wf->index, &wf->entries, workdir_iterator__entry_cmp, wf->start);
+
wf->next = wi->stack;
wi->stack = wf;
@@ -412,6 +550,16 @@ static int workdir_iterator__advance(
return error;
}
+static int workdir_iterator__seek(git_iterator *self, const char *prefix)
+{
+ GIT_UNUSED(self);
+ GIT_UNUSED(prefix);
+ /* pop stack until matching prefix */
+ /* find prefix item in current frame */
+ /* push subdirectories as deep as possible while matching */
+ return 0;
+}
+
static int workdir_iterator__reset(git_iterator *self)
{
workdir_iterator *wi = (workdir_iterator *)self;
@@ -445,10 +593,18 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
git_path_with_stat *ps = git_vector_get(&wi->stack->entries, wi->stack->index);
git_buf_truncate(&wi->path, wi->root_len);
+ memset(&wi->entry, 0, sizeof(wi->entry));
+
+ if (!ps)
+ return 0;
+
if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0)
return -1;
- memset(&wi->entry, 0, sizeof(wi->entry));
+ if (wi->base.end &&
+ git__prefixcmp(wi->path.ptr + wi->root_len, wi->base.end) > 0)
+ return 0;
+
wi->entry.path = ps->path;
/* skip over .git directory */
@@ -495,19 +651,26 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
return 0;
}
-int git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
+int git_iterator_for_workdir_range(
+ git_iterator **iter,
+ git_repository *repo,
+ const char *start,
+ const char *end)
{
int error;
- workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator));
- GITERR_CHECK_ALLOC(wi);
+ workdir_iterator *wi;
- wi->base.type = GIT_ITERATOR_WORKDIR;
- wi->base.current = workdir_iterator__current;
- wi->base.at_end = workdir_iterator__at_end;
- wi->base.advance = workdir_iterator__advance;
- wi->base.reset = workdir_iterator__reset;
- wi->base.free = workdir_iterator__free;
- wi->repo = repo;
+ assert(iter && repo);
+
+ if (git_repository_is_bare(repo)) {
+ giterr_set(GITERR_INVALID,
+ "Cannot scan working directory for bare repo");
+ return -1;
+ }
+
+ ITERATOR_BASE_INIT(wi, workdir, WORKDIR);
+
+ wi->repo = repo;
if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 ||
git_path_to_dir(&wi->path) < 0 ||
@@ -519,10 +682,16 @@ int git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
wi->root_len = wi->path.size;
- if ((error = workdir_iterator__expand_dir(wi)) < 0)
- git_iterator_free((git_iterator *)wi);
- else
- *iter = (git_iterator *)wi;
+ if ((error = workdir_iterator__expand_dir(wi)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+ else {
+ git_iterator_free((git_iterator *)wi);
+ wi = NULL;
+ }
+ }
+
+ *iter = (git_iterator *)wi;
return error;
}
@@ -559,3 +728,21 @@ int git_iterator_advance_into_directory(
return entry ? git_iterator_current(iter, entry) : 0;
}
+
+int git_iterator_cmp(
+ git_iterator *iter, const char *path_prefix)
+{
+ const git_index_entry *entry;
+
+ /* a "done" iterator is after every prefix */
+ if (git_iterator_current(iter, &entry) < 0 ||
+ entry == NULL)
+ return 1;
+
+ /* a NULL prefix is after any valid iterator */
+ if (!path_prefix)
+ return -1;
+
+ return git__prefixcmp(entry->path, path_prefix);
+}
+
diff --git a/src/iterator.h b/src/iterator.h
index 12eb96bb0..b916a9080 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -21,23 +21,48 @@ typedef enum {
struct git_iterator {
git_iterator_type_t type;
+ char *start;
+ char *end;
int (*current)(git_iterator *, const git_index_entry **);
int (*at_end)(git_iterator *);
int (*advance)(git_iterator *, const git_index_entry **);
+ int (*seek)(git_iterator *, const char *prefix);
int (*reset)(git_iterator *);
void (*free)(git_iterator *);
};
-int git_iterator_for_nothing(git_iterator **iter);
+extern int git_iterator_for_nothing(git_iterator **iter);
-int git_iterator_for_tree(
- git_repository *repo, git_tree *tree, git_iterator **iter);
+extern int git_iterator_for_tree_range(
+ git_iterator **iter, git_repository *repo, git_tree *tree,
+ const char *start, const char *end);
-int git_iterator_for_index(
- git_repository *repo, git_iterator **iter);
+GIT_INLINE(int) git_iterator_for_tree(
+ git_iterator **iter, git_repository *repo, git_tree *tree)
+{
+ return git_iterator_for_tree_range(iter, repo, tree, NULL, NULL);
+}
+
+extern int git_iterator_for_index_range(
+ git_iterator **iter, git_repository *repo,
+ const char *start, const char *end);
+
+GIT_INLINE(int) git_iterator_for_index(
+ git_iterator **iter, git_repository *repo)
+{
+ return git_iterator_for_index_range(iter, repo, NULL, NULL);
+}
+
+extern int git_iterator_for_workdir_range(
+ git_iterator **iter, git_repository *repo,
+ const char *start, const char *end);
+
+GIT_INLINE(int) git_iterator_for_workdir(
+ git_iterator **iter, git_repository *repo)
+{
+ return git_iterator_for_workdir_range(iter, repo, NULL, NULL);
+}
-int git_iterator_for_workdir(
- git_repository *repo, git_iterator **iter);
/* Entry is not guaranteed to be fully populated. For a tree iterator,
* we will only populate the mode, oid and path, for example. For a workdir
@@ -64,6 +89,12 @@ GIT_INLINE(int) git_iterator_advance(
return iter->advance(iter, entry);
}
+GIT_INLINE(int) git_iterator_seek(
+ git_iterator *iter, const char *prefix)
+{
+ return iter->seek(iter, prefix);
+}
+
GIT_INLINE(int) git_iterator_reset(git_iterator *iter)
{
return iter->reset(iter);
@@ -71,7 +102,16 @@ GIT_INLINE(int) git_iterator_reset(git_iterator *iter)
GIT_INLINE(void) git_iterator_free(git_iterator *iter)
{
+ if (iter == NULL)
+ return;
+
iter->free(iter);
+
+ git__free(iter->start);
+ git__free(iter->end);
+
+ memset(iter, 0, sizeof(*iter));
+
git__free(iter);
}
@@ -105,4 +145,7 @@ extern int git_iterator_current_is_ignored(git_iterator *iter);
extern int git_iterator_advance_into_directory(
git_iterator *iter, const git_index_entry **entry);
+extern int git_iterator_cmp(
+ git_iterator *iter, const char *path_prefix);
+
#endif
diff --git a/src/mwindow.c b/src/mwindow.c
index b59c4d2f7..57adabd48 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -89,7 +89,6 @@ void git_mwindow_scan_lru(
{
git_mwindow *w, *w_l;
- puts("LRU");
for (w_l = NULL, w = mwf->windows; w; w = w->next) {
if (!w->inuse_cnt) {
/*
@@ -247,7 +246,6 @@ unsigned char *git_mwindow_open(
if (left)
*left = (unsigned int)(w->window_map.len - offset);
- fflush(stdout);
return (unsigned char *) w->window_map.data + offset;
}
diff --git a/src/netops.c b/src/netops.c
index 4d461a049..e16cae8e6 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -12,9 +12,9 @@
# include <netdb.h>
#else
# include <winsock2.h>
-# include <Ws2tcpip.h>
+# include <ws2tcpip.h>
# ifdef _MSC_VER
-# pragma comment(lib, "Ws2_32.lib")
+# pragma comment(lib, "ws2_32.lib")
# endif
#endif
diff --git a/src/notes.c b/src/notes.c
index 4afdac0bd..84ad94087 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -10,6 +10,7 @@
#include "git2.h"
#include "refs.h"
#include "config.h"
+#include "iterator.h"
static int find_subtree(git_tree **subtree, const git_oid *root,
git_repository *repo, const char *target, int *fanout)
@@ -273,7 +274,7 @@ static int note_get_default_ref(const char **out, git_repository *repo)
if (git_repository_config__weakptr(&cfg, repo) < 0)
return -1;
- ret = git_config_get_string(cfg, "core.notesRef", out);
+ ret = git_config_get_string(out, cfg, "core.notesRef");
if (ret == GIT_ENOTFOUND) {
*out = GIT_NOTES_DEFAULT_REF;
return 0;
@@ -282,41 +283,54 @@ static int note_get_default_ref(const char **out, git_repository *repo)
return ret;
}
+static int normalize_namespace(const char **notes_ref, git_repository *repo)
+{
+ if (*notes_ref)
+ return 0;
+
+ return note_get_default_ref(notes_ref, repo);
+}
+
+static int retrieve_note_tree_oid(git_oid *tree_oid_out, git_repository *repo, const char *notes_ref)
+{
+ int error = -1;
+ git_commit *commit = NULL;
+ git_oid oid;
+
+ if ((error = git_reference_name_to_oid(&oid, repo, notes_ref)) < 0)
+ goto cleanup;
+
+ if (git_commit_lookup(&commit, repo, &oid) < 0)
+ goto cleanup;
+
+ git_oid_cpy(tree_oid_out, git_commit_tree_oid(commit));
+
+ error = 0;
+
+cleanup:
+ git_commit_free(commit);
+ return error;
+}
+
int git_note_read(git_note **out, git_repository *repo,
const char *notes_ref, const git_oid *oid)
{
int error;
char *target;
- git_reference *ref;
- git_commit *commit;
- const git_oid *sha;
+ git_oid sha;
*out = NULL;
- if (!notes_ref && note_get_default_ref(&notes_ref, repo) < 0)
+ if (normalize_namespace(&notes_ref, repo) < 0)
return -1;
- error = git_reference_lookup(&ref, repo, notes_ref);
- if (error < 0)
+ if ((error = retrieve_note_tree_oid(&sha, repo, notes_ref)) < 0)
return error;
- assert(git_reference_type(ref) == GIT_REF_OID);
-
- sha = git_reference_oid(ref);
- error = git_commit_lookup(&commit, repo, sha);
-
- git_reference_free(ref);
-
- if (error < 0)
- return error;
-
- sha = git_commit_tree_oid(commit);
- git_commit_free(commit);
-
target = git_oid_allocfmt(oid);
GITERR_CHECK_ALLOC(target);
- error = note_lookup(out, repo, sha, target);
+ error = note_lookup(out, repo, &sha, target);
git__free(target);
return error;
@@ -334,7 +348,7 @@ int git_note_create(
git_commit *commit = NULL;
git_reference *ref;
- if (!notes_ref && note_get_default_ref(&notes_ref, repo) < 0)
+ if (normalize_namespace(&notes_ref, repo) < 0)
return -1;
error = git_reference_lookup(&ref, repo, notes_ref);
@@ -379,8 +393,7 @@ int git_note_remove(git_repository *repo, const char *notes_ref,
git_commit *commit;
git_reference *ref;
-
- if (!notes_ref && note_get_default_ref(&notes_ref, repo) < 0)
+ if (normalize_namespace(&notes_ref, repo) < 0)
return -1;
error = git_reference_lookup(&ref, repo, notes_ref);
@@ -435,3 +448,101 @@ void git_note_free(git_note *note)
git__free(note->message);
git__free(note);
}
+
+static int process_entry_path(
+ const char* entry_path,
+ const git_oid *note_oid,
+ int (*note_cb)(git_note_data *note_data, void *payload),
+ void *payload)
+{
+ int i = 0, j = 0, error = -1, len;
+ git_buf buf = GIT_BUF_INIT;
+ git_note_data note_data;
+
+ if (git_buf_puts(&buf, entry_path) < 0)
+ goto cleanup;
+
+ len = git_buf_len(&buf);
+
+ while (i < len) {
+ if (buf.ptr[i] == '/') {
+ i++;
+ continue;
+ }
+
+ if (git__fromhex(buf.ptr[i]) < 0) {
+ /* This is not a note entry */
+ error = 0;
+ goto cleanup;
+ }
+
+ if (i != j)
+ buf.ptr[j] = buf.ptr[i];
+
+ i++;
+ j++;
+ }
+
+ buf.ptr[j] = '\0';
+ buf.size = j;
+
+ if (j != GIT_OID_HEXSZ) {
+ /* This is not a note entry */
+ error = 0;
+ goto cleanup;
+ }
+
+ if (git_oid_fromstr(&note_data.annotated_object_oid, buf.ptr) < 0)
+ return -1;
+
+ git_oid_cpy(&note_data.blob_oid, note_oid);
+
+ error = note_cb(&note_data, payload);
+
+cleanup:
+ git_buf_free(&buf);
+ return error;
+}
+
+int git_note_foreach(
+ git_repository *repo,
+ const char *notes_ref,
+ int (*note_cb)(git_note_data *note_data, void *payload),
+ void *payload)
+{
+ int error = -1;
+ git_oid tree_oid;
+ git_iterator *iter = NULL;
+ git_tree *tree = NULL;
+ const git_index_entry *item;
+
+ if (normalize_namespace(&notes_ref, repo) < 0)
+ return -1;
+
+ if ((error = retrieve_note_tree_oid(&tree_oid, repo, notes_ref)) < 0)
+ goto cleanup;
+
+ if (git_tree_lookup(&tree, repo, &tree_oid) < 0)
+ goto cleanup;
+
+ if (git_iterator_for_tree(&iter, repo, tree) < 0)
+ goto cleanup;
+
+ if (git_iterator_current(iter, &item) < 0)
+ goto cleanup;
+
+ while (item) {
+ if (process_entry_path(item->path, &item->oid, note_cb, payload) < 0)
+ goto cleanup;
+
+ if (git_iterator_advance(iter, &item) < 0)
+ goto cleanup;
+ }
+
+ error = 0;
+
+cleanup:
+ git_iterator_free(iter);
+ git_tree_free(tree);
+ return error;
+}
diff --git a/src/object.c b/src/object.c
index 02be5dac8..d3673eda0 100644
--- a/src/object.c
+++ b/src/object.c
@@ -74,7 +74,7 @@ static int create_object(git_object **object_out, git_otype type)
object->type = type;
*object_out = object;
- return GIT_SUCCESS;
+ return 0;
}
int git_object_lookup_prefix(
@@ -87,7 +87,7 @@ int git_object_lookup_prefix(
git_object *object = NULL;
git_odb *odb = NULL;
git_odb_object *odb_obj;
- int error = GIT_SUCCESS;
+ int error = 0;
assert(repo && object_out && id);
@@ -95,7 +95,7 @@ int git_object_lookup_prefix(
return GIT_EAMBIGUOUS;
error = git_repository_odb__weakptr(&odb, repo);
- if (error < GIT_SUCCESS)
+ if (error < 0)
return error;
if (len > GIT_OID_HEXSZ)
@@ -109,8 +109,8 @@ int git_object_lookup_prefix(
if (object != NULL) {
if (type != GIT_OBJ_ANY && type != object->type) {
git_object_free(object);
- giterr_set(GITERR_INVALID, "The given type does not match the type in ODB");
- return -1;
+ giterr_set(GITERR_ODB, "The given type does not match the type in ODB");
+ return GIT_ENOTFOUND;
}
*object_out = object;
diff --git a/src/odb.c b/src/odb.c
index 934b317ed..a6a18f831 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -505,7 +505,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
error = b->read_header(len_p, type_p, b, id);
}
- if (!error || error == GIT_EPASSTHROUGH)
+ if (!error || error == GIT_PASSTHROUGH)
return 0;
/*
@@ -545,7 +545,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
* will never have called giterr_set().
*/
- if (error && error != GIT_EPASSTHROUGH)
+ if (error && error != GIT_PASSTHROUGH)
return error;
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
@@ -557,9 +557,9 @@ int git_odb_read_prefix(
{
unsigned int i;
int error = GIT_ENOTFOUND;
- git_oid full_oid;
+ git_oid found_full_oid = {{0}};
git_rawobj raw;
- int found = 0;
+ bool found = false;
assert(out && db);
@@ -575,25 +575,30 @@ int git_odb_read_prefix(
return 0;
}
- for (i = 0; i < db->backends.length && found < 2; ++i) {
+ for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
if (b->read != NULL) {
+ git_oid full_oid;
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len);
- if (!error)
- found++;
- else if (error != GIT_ENOTFOUND && error != GIT_EPASSTHROUGH)
+ if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
+ continue;
+
+ if (error)
return error;
+
+ if (found && git_oid_cmp(&full_oid, &found_full_oid))
+ return git_odb__error_ambiguous("multiple matches for prefix");
+ found_full_oid = full_oid;
+ found = true;
}
}
- if (found == 0)
+ if (!found)
return git_odb__error_notfound("no match for prefix", short_id);
- if (found > 1)
- return git_odb__error_ambiguous("multiple matches for prefix");
- *out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw));
+ *out = git_cache_try_store(&db->cache, new_odb_object(&found_full_oid, &raw));
return 0;
}
@@ -618,7 +623,7 @@ int git_odb_write(
error = b->write(oid, b, data, len, type);
}
- if (!error || error == GIT_EPASSTHROUGH)
+ if (!error || error == GIT_PASSTHROUGH)
return 0;
/* if no backends were able to write the object directly, we try a streaming
@@ -657,7 +662,7 @@ int git_odb_open_wstream(
error = init_fake_wstream(stream, b, size, type);
}
- if (error == GIT_EPASSTHROUGH)
+ if (error == GIT_PASSTHROUGH)
error = 0;
return error;
@@ -678,7 +683,7 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi
error = b->readstream(stream, b, oid);
}
- if (error == GIT_EPASSTHROUGH)
+ if (error == GIT_PASSTHROUGH)
error = 0;
return error;
diff --git a/src/pack.c b/src/pack.c
index 4a6bc6ae8..0db1069de 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -222,7 +222,7 @@ static int packfile_unpack_header1(
shift = 4;
while (c & 0x80) {
if (len <= used)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
if (bitsizeof(long) <= shift) {
*usedp = 0;
@@ -260,11 +260,11 @@ int git_packfile_unpack_header(
// base = pack_window_open(p, w_curs, *curpos, &left);
base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
if (base == NULL)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
ret = packfile_unpack_header1(&used, size_p, type_p, base, left);
git_mwindow_close(w_curs);
- if (ret == GIT_ESHORTBUFFER)
+ if (ret == GIT_EBUFS)
return ret;
else if (ret < 0)
return packfile_error("header length is zero");
@@ -428,7 +428,7 @@ int packfile_unpack_compressed(
if (st == Z_BUF_ERROR && in == NULL) {
inflateEnd(&stream);
git__free(buffer);
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
}
*curpos += stream.next_in - in;
@@ -467,7 +467,7 @@ git_off_t get_delta_base(
base_info = pack_window_open(p, w_curs, *curpos, &left);
/* Assumption: the only reason this would fail is because the file is too small */
if (base_info == NULL)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
/* pack_window_open() assured us we have [base_info, base_info + 20)
* as a range that we can look at without walking off the
* end of the mapped window. Its actually the hash size
@@ -480,7 +480,7 @@ git_off_t get_delta_base(
base_offset = c & 127;
while (c & 128) {
if (left <= used)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
base_offset += 1;
if (!base_offset || MSB(base_offset, 7))
return 0; /* overflow */
diff --git a/src/path.c b/src/path.c
index 9f31676b1..84edf6d89 100644
--- a/src/path.c
+++ b/src/path.c
@@ -494,7 +494,7 @@ int git_path_direach(
{
ssize_t wd_len;
DIR *dir;
- struct dirent de_buf, *de;
+ struct dirent *de, *de_buf;
if (git_path_to_dir(path) < 0)
return -1;
@@ -506,14 +506,23 @@ int git_path_direach(
return -1;
}
- while (p_readdir_r(dir, &de_buf, &de) == 0 && de != NULL) {
+#ifdef __sun
+ de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1);
+#else
+ de_buf = git__malloc(sizeof(struct dirent));
+#endif
+
+ while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) {
int result;
if (is_dot_or_dotdot(de->d_name))
continue;
- if (git_buf_puts(path, de->d_name) < 0)
+ if (git_buf_puts(path, de->d_name) < 0) {
+ closedir(dir);
+ git__free(de_buf);
return -1;
+ }
result = fn(arg, path);
@@ -521,11 +530,13 @@ int git_path_direach(
if (result < 0) {
closedir(dir);
+ git__free(de_buf);
return -1;
}
}
closedir(dir);
+ git__free(de_buf);
return 0;
}
@@ -537,7 +548,7 @@ int git_path_dirload(
{
int error, need_slash;
DIR *dir;
- struct dirent de_buf, *de;
+ struct dirent *de, *de_buf;
size_t path_len;
assert(path != NULL && contents != NULL);
@@ -549,11 +560,17 @@ int git_path_dirload(
return -1;
}
+#ifdef __sun
+ de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1);
+#else
+ de_buf = git__malloc(sizeof(struct dirent));
+#endif
+
path += prefix_len;
path_len -= prefix_len;
need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
- while ((error = p_readdir_r(dir, &de_buf, &de)) == 0 && de != NULL) {
+ while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) {
char *entry_path;
size_t entry_len;
@@ -573,11 +590,15 @@ int git_path_dirload(
memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len);
entry_path[path_len + need_slash + entry_len] = '\0';
- if (git_vector_insert(contents, entry_path) < 0)
+ if (git_vector_insert(contents, entry_path) < 0) {
+ closedir(dir);
+ git__free(de_buf);
return -1;
+ }
}
closedir(dir);
+ git__free(de_buf);
if (error != 0)
giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path);
diff --git a/src/pkt.c b/src/pkt.c
index b9c87f169..95430ddfc 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -208,7 +208,7 @@ int git_pkt_parse_line(
/* Not even enough for the length */
if (bufflen > 0 && bufflen < PKT_LEN_SIZE)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
len = parse_len(line);
if (len < 0) {
@@ -230,7 +230,7 @@ int git_pkt_parse_line(
* enough in the buffer to satisfy this line
*/
if (bufflen > 0 && bufflen < (size_t)len)
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
line += PKT_LEN_SIZE;
/*
diff --git a/src/protocol.c b/src/protocol.c
index a75354121..6b3861796 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -34,7 +34,7 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
return 0;
error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf));
- if (error == GIT_ESHORTBUFFER)
+ if (error == GIT_EBUFS)
return 0; /* Ask for more */
if (error < 0)
return p->error = -1;
diff --git a/src/refs.c b/src/refs.c
index 28e8f786b..1ef3e13a4 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -194,10 +194,10 @@ corrupt:
return -1;
}
-static git_rtype loose_guess_rtype(const git_buf *full_path)
+static git_ref_t loose_guess_rtype(const git_buf *full_path)
{
git_buf ref_file = GIT_BUF_INIT;
- git_rtype type;
+ git_ref_t type;
type = GIT_REF_INVALID;
@@ -1153,7 +1153,7 @@ int git_reference_lookup_resolved(
/**
* Getters
*/
-git_rtype git_reference_type(git_reference *ref)
+git_ref_t git_reference_type(git_reference *ref)
{
assert(ref);
@@ -1518,7 +1518,7 @@ static int cb__reflist_add(const char *ref, void *data)
return git_vector_insert((git_vector *)data, git__strdup(ref));
}
-int git_reference_listall(
+int git_reference_list(
git_strarray *array,
git_repository *repo,
unsigned int list_flags)
diff --git a/src/refspec.c b/src/refspec.c
index ee4d3a158..b6b1158b7 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -53,6 +53,13 @@ const char *git_refspec_dst(const git_refspec *refspec)
return refspec == NULL ? NULL : refspec->dst;
}
+int git_refspec_force(const git_refspec *refspec)
+{
+ assert(refspec);
+
+ return refspec->force;
+}
+
int git_refspec_src_matches(const git_refspec *refspec, const char *refname)
{
if (refspec == NULL || refspec->src == NULL)
@@ -68,7 +75,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
baselen = strlen(spec->dst);
if (outlen <= baselen) {
giterr_set(GITERR_INVALID, "Reference name too long");
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
}
/*
@@ -90,7 +97,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
if (outlen <= baselen + namelen) {
giterr_set(GITERR_INVALID, "Reference name too long");
- return GIT_ESHORTBUFFER;
+ return GIT_EBUFS;
}
memcpy(out, spec->dst, baselen);
diff --git a/src/refspec.h b/src/refspec.h
index 64c0ded0c..2db504910 100644
--- a/src/refspec.h
+++ b/src/refspec.h
@@ -28,7 +28,7 @@ int git_refspec_parse(struct git_refspec *refspec, const char *str);
* @param out where to store the target name
* @param spec the refspec
* @param name the name of the reference to transform
- * @return GIT_SUCCESS or error if buffer allocation fails
+ * @return 0 or error if buffer allocation fails
*/
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name);
diff --git a/src/remote.c b/src/remote.c
index a5cfc822e..5993ad02b 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -48,7 +48,7 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha
int error;
const char *val;
- if ((error = git_config_get_string(cfg, var, &val)) < 0)
+ if ((error = git_config_get_string(&val, cfg, var)) < 0)
return error;
return refspec_parse(refspec, val);
@@ -121,7 +121,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
goto cleanup;
}
- if ((error = git_config_get_string(config, git_buf_cstr(&buf), &val)) < 0)
+ if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
goto cleanup;
remote->repo = repo;
@@ -189,6 +189,8 @@ int git_remote_save(const git_remote *remote)
git_buf_clear(&buf);
git_buf_clear(&value);
git_buf_printf(&buf, "remote.%s.fetch", remote->name);
+ if (remote->fetch.force)
+ git_buf_putc(&value, '+');
git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst);
if (git_buf_oom(&buf) || git_buf_oom(&value))
return -1;
@@ -201,6 +203,8 @@ int git_remote_save(const git_remote *remote)
git_buf_clear(&buf);
git_buf_clear(&value);
git_buf_printf(&buf, "remote.%s.push", remote->name);
+ if (remote->push.force)
+ git_buf_putc(&value, '+');
git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst);
if (git_buf_oom(&buf) || git_buf_oom(&value))
return -1;
@@ -338,7 +342,7 @@ int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, co
assert(remote);
if (refs->length == 0)
- return GIT_SUCCESS;
+ return 0;
/* HEAD is only allowed to be the first in the list */
head = refs->contents[0];
@@ -490,7 +494,7 @@ int git_remote_add(git_remote **out, git_repository *repo, const char *name, con
{
git_buf buf = GIT_BUF_INIT;
- if (git_buf_printf(&buf, "refs/heads/*:refs/remotes/%s/*", name) < 0)
+ if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
return -1;
if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0)
diff --git a/src/repository.c b/src/repository.c
index 886de5806..5120356bf 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -25,8 +25,7 @@
#define GIT_BRANCH_MASTER "master"
-#define GIT_CONFIG_CORE_REPOSITORYFORMATVERSION "core.repositoryformatversion"
-#define GIT_REPOSITORYFORMATVERSION 0
+#define GIT_REPO_VERSION 0
static void drop_odb(git_repository *repo)
{
@@ -125,11 +124,12 @@ static int load_config_data(git_repository *repo)
if (git_repository_config__weakptr(&config, repo) < 0)
return -1;
- if (git_config_get_bool(config, "core.bare", &is_bare) < 0)
- return -1; /* FIXME: We assume that a missing core.bare
- variable is an error. Is this right? */
+ /* Try to figure out if it's bare, default to non-bare if it's not set */
+ if (git_config_get_bool(&is_bare, config, "core.bare") < 0)
+ repo->is_bare = 0;
+ else
+ repo->is_bare = is_bare;
- repo->is_bare = is_bare;
return 0;
}
@@ -146,7 +146,7 @@ static int load_workdir(git_repository *repo, git_buf *parent_path)
if (git_repository_config__weakptr(&config, repo) < 0)
return -1;
- error = git_config_get_string(config, "core.worktree", &worktree);
+ error = git_config_get_string(&worktree, config, "core.worktree");
if (!error && worktree != NULL)
repo->workdir = git__strdup(worktree);
else if (error != GIT_ENOTFOUND)
@@ -607,13 +607,13 @@ static int check_repositoryformatversion(git_repository *repo)
if (git_repository_config__weakptr(&config, repo) < 0)
return -1;
- if (git_config_get_int32(config, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, &version) < 0)
+ if (git_config_get_int32(&version, config, "core.repositoryformatversion") < 0)
return -1;
- if (GIT_REPOSITORYFORMATVERSION < version) {
+ if (GIT_REPO_VERSION < version) {
giterr_set(GITERR_REPOSITORY,
"Unsupported repository version %d. Only versions up to %d are supported.",
- version, GIT_REPOSITORYFORMATVERSION);
+ version, GIT_REPO_VERSION);
return -1;
}
@@ -676,7 +676,7 @@ static int repo_init_config(const char *git_dir, int is_bare)
}
SET_REPO_CONFIG(bool, "core.bare", is_bare);
- SET_REPO_CONFIG(int32, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, GIT_REPOSITORYFORMATVERSION);
+ SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
/* TODO: what other defaults? */
git_buf_free(&cfg_path);
@@ -684,6 +684,59 @@ static int repo_init_config(const char *git_dir, int is_bare)
return 0;
}
+#define GIT_HOOKS_DIR "hooks/"
+#define GIT_HOOKS_DIR_MODE 0755
+
+#define GIT_HOOKS_README_FILE GIT_HOOKS_DIR "README.sample"
+#define GIT_HOOKS_README_MODE 0755
+#define GIT_HOOKS_README_CONTENT \
+"#!/bin/sh\n"\
+"#\n"\
+"# Place appropriately named executable hook scripts into this directory\n"\
+"# to intercept various actions that git takes. See `git help hooks` for\n"\
+"# more information.\n"
+
+#define GIT_INFO_DIR "info/"
+#define GIT_INFO_DIR_MODE 0755
+
+#define GIT_INFO_EXCLUDE_FILE GIT_INFO_DIR "exclude"
+#define GIT_INFO_EXCLUDE_MODE 0644
+#define GIT_INFO_EXCLUDE_CONTENT \
+"# File patterns to ignore; see `git help ignore` for more information.\n"\
+"# Lines that start with '#' are comments.\n"
+
+#define GIT_DESC_FILE "description"
+#define GIT_DESC_MODE 0644
+#define GIT_DESC_CONTENT "Unnamed repository; edit this file 'description' to name the repository.\n"
+
+static int repo_write_template(
+ const char *git_dir, const char *file, mode_t mode, const char *content)
+{
+ git_buf path = GIT_BUF_INIT;
+ int fd, error = 0;
+
+ if (git_buf_joinpath(&path, git_dir, file) < 0)
+ return -1;
+
+ fd = p_open(git_buf_cstr(&path), O_WRONLY | O_CREAT | O_EXCL, mode);
+
+ if (fd >= 0) {
+ error = p_write(fd, content, strlen(content));
+
+ p_close(fd);
+ }
+ else if (errno != EEXIST)
+ error = fd;
+
+ git_buf_free(&path);
+
+ if (error)
+ giterr_set(GITERR_OS,
+ "Failed to initialize repository with template '%s'", file);
+
+ return error;
+}
+
static int repo_init_structure(const char *git_dir, int is_bare)
{
int i;
@@ -692,8 +745,16 @@ static int repo_init_structure(const char *git_dir, int is_bare)
{ GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */
{ GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/heads/' */
{ GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/tags/' */
+ { GIT_HOOKS_DIR, GIT_HOOKS_DIR_MODE }, /* '/hooks/' */
+ { GIT_INFO_DIR, GIT_INFO_DIR_MODE }, /* '/info/' */
{ NULL, 0 }
};
+ struct { const char *file; mode_t mode; const char *content; } tmpl[] = {
+ { GIT_DESC_FILE, GIT_DESC_MODE, GIT_DESC_CONTENT },
+ { GIT_HOOKS_README_FILE, GIT_HOOKS_README_MODE, GIT_HOOKS_README_CONTENT },
+ { GIT_INFO_EXCLUDE_FILE, GIT_INFO_EXCLUDE_MODE, GIT_INFO_EXCLUDE_CONTENT },
+ { NULL, 0, NULL }
+ };
/* Make the base directory */
if (git_futils_mkdir_r(git_dir, NULL, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE) < 0)
@@ -716,7 +777,13 @@ static int repo_init_structure(const char *git_dir, int is_bare)
return -1;
}
- /* TODO: what's left? templates? */
+ /* Make template files as needed */
+ for (i = 0; tmpl[i].file != NULL; ++i) {
+ if (repo_write_template(
+ git_dir, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
+ return -1;
+ }
+
return 0;
}
diff --git a/src/revwalk.c b/src/revwalk.c
index 1b539787f..e64d93f20 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -316,7 +316,7 @@ static int merge_bases_many(commit_list **out, git_revwalk *walk, commit_object
if ((p->flags & flags) == flags)
continue;
- if ((error = commit_parse(walk, p)) < GIT_SUCCESS)
+ if ((error = commit_parse(walk, p)) < 0)
return error;
p->flags |= flags;
@@ -600,7 +600,7 @@ static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk)
}
}
- return GIT_EREVWALKOVER;
+ return GIT_REVWALKOVER;
}
static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)
@@ -618,7 +618,7 @@ static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)
}
}
- return GIT_EREVWALKOVER;
+ return GIT_REVWALKOVER;
}
static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
@@ -629,7 +629,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
for (;;) {
next = commit_list_pop(&walk->iterator_topo);
if (next == NULL)
- return GIT_EREVWALKOVER;
+ return GIT_REVWALKOVER;
if (next->in_degree > 0) {
next->topo_delay = 1;
@@ -654,7 +654,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk)
{
*object_out = commit_list_pop(&walk->iterator_reverse);
- return *object_out ? 0 : GIT_EREVWALKOVER;
+ return *object_out ? 0 : GIT_REVWALKOVER;
}
@@ -670,7 +670,7 @@ static int prepare_walk(git_revwalk *walk)
* so we know that the walk is already over.
*/
if (walk->one == NULL)
- return GIT_EREVWALKOVER;
+ return GIT_REVWALKOVER;
/* first figure out what the merge bases are */
if (merge_bases_many(&bases, walk, walk->one, &walk->twos) < 0)
@@ -698,7 +698,7 @@ static int prepare_walk(git_revwalk *walk)
return -1;
}
- if (error != GIT_EREVWALKOVER)
+ if (error != GIT_REVWALKOVER)
return error;
walk->get_next = &revwalk_next_toposort;
@@ -710,7 +710,7 @@ static int prepare_walk(git_revwalk *walk)
if (commit_list_insert(next, &walk->iterator_reverse) == NULL)
return -1;
- if (error != GIT_EREVWALKOVER)
+ if (error != GIT_REVWALKOVER)
return error;
walk->get_next = &revwalk_next_reverse;
@@ -809,9 +809,9 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk)
error = walk->get_next(&next, walk);
- if (error == GIT_EREVWALKOVER) {
+ if (error == GIT_REVWALKOVER) {
git_revwalk_reset(walk);
- return GIT_EREVWALKOVER;
+ return GIT_REVWALKOVER;
}
if (!error)
@@ -838,5 +838,8 @@ void git_revwalk_reset(git_revwalk *walk)
commit_list_free(&walk->iterator_rand);
commit_list_free(&walk->iterator_reverse);
walk->walking = 0;
+
+ walk->one = NULL;
+ git_vector_clear(&walk->twos);
}
diff --git a/src/signature.c b/src/signature.c
index 74ef84376..6b28a3e4c 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -155,7 +155,7 @@ static int parse_timezone_offset(const char *buffer, int *offset_out)
if (*offset_start == '\n') {
*offset_out = 0;
- return GIT_SUCCESS;
+ return 0;
}
if (offset_start[0] != '-' && offset_start[0] != '+')
@@ -164,7 +164,7 @@ static int parse_timezone_offset(const char *buffer, int *offset_out)
if (offset_start[1] < '0' || offset_start[1] > '9')
return timezone_error("expected initial digit");
- if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
+ if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < 0)
return timezone_error("not a valid number");
if (offset_end - offset_start != 5)
diff --git a/src/status.c b/src/status.c
index d07b0c41c..e9ad3cfe4 100644
--- a/src/status.c
+++ b/src/status.c
@@ -70,7 +70,7 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
int git_status_foreach_ext(
git_repository *repo,
- git_status_options *opts,
+ const git_status_options *opts,
int (*cb)(const char *, unsigned int, void *),
void *cbdata)
{
@@ -163,244 +163,71 @@ int git_status_foreach(
return git_status_foreach_ext(repo, &opts, callback, payload);
}
-
-/*
- * the old stuff
- */
-
-struct status_entry {
- git_index_time mtime;
-
- git_oid head_oid;
- git_oid index_oid;
- git_oid wt_oid;
-
- unsigned int status_flags;
-
- char path[GIT_FLEX_ARRAY]; /* more */
+struct status_file_info {
+ unsigned int count;
+ unsigned int status;
+ char *expected;
};
-static struct status_entry *status_entry_new(git_vector *entries, const char *path)
-{
- struct status_entry *e = git__calloc(sizeof(*e) + strlen(path) + 1, 1);
- if (e == NULL)
- return NULL;
-
- if (entries != NULL)
- git_vector_insert(entries, e);
-
- strcpy(e->path, path);
-
- return e;
-}
-
-GIT_INLINE(void) status_entry_update_from_tree_entry(struct status_entry *e, const git_tree_entry *tree_entry)
-{
- assert(e && tree_entry);
-
- git_oid_cpy(&e->head_oid, &tree_entry->oid);
-}
-
-GIT_INLINE(void) status_entry_update_from_index_entry(struct status_entry *e, const git_index_entry *index_entry)
-{
- assert(e && index_entry);
-
- git_oid_cpy(&e->index_oid, &index_entry->oid);
- e->mtime = index_entry->mtime;
-}
-
-static void status_entry_update_from_index(struct status_entry *e, git_index *index)
-{
- int idx;
- git_index_entry *index_entry;
-
- assert(e && index);
-
- idx = git_index_find(index, e->path);
- if (idx < 0)
- return;
-
- index_entry = git_index_get(index, idx);
-
- status_entry_update_from_index_entry(e, index_entry);
-}
-
-static int status_entry_update_from_workdir(struct status_entry *e, const char* full_path)
-{
- struct stat filest;
-
- if (p_stat(full_path, &filest) < 0) {
- giterr_set(GITERR_OS, "Cannot access file '%s'", full_path);
- return GIT_ENOTFOUND;
- }
-
- if (e->mtime.seconds == (git_time_t)filest.st_mtime)
- git_oid_cpy(&e->wt_oid, &e->index_oid);
- else
- git_odb_hashfile(&e->wt_oid, full_path, GIT_OBJ_BLOB);
-
- return 0;
-}
-
-static int status_entry_update_flags(struct status_entry *e)
-{
- git_oid zero;
- int head_zero, index_zero, wt_zero;
-
- memset(&zero, 0x0, sizeof(git_oid));
-
- head_zero = git_oid_cmp(&zero, &e->head_oid);
- index_zero = git_oid_cmp(&zero, &e->index_oid);
- wt_zero = git_oid_cmp(&zero, &e->wt_oid);
-
- if (head_zero == 0 && index_zero == 0 && wt_zero == 0)
- return GIT_ENOTFOUND;
-
- if (head_zero == 0 && index_zero != 0)
- e->status_flags |= GIT_STATUS_INDEX_NEW;
- else if (index_zero == 0 && head_zero != 0)
- e->status_flags |= GIT_STATUS_INDEX_DELETED;
- else if (git_oid_cmp(&e->head_oid, &e->index_oid) != 0)
- e->status_flags |= GIT_STATUS_INDEX_MODIFIED;
-
- if (index_zero == 0 && wt_zero != 0)
- e->status_flags |= GIT_STATUS_WT_NEW;
- else if (wt_zero == 0 && index_zero != 0)
- e->status_flags |= GIT_STATUS_WT_DELETED;
- else if (git_oid_cmp(&e->index_oid, &e->wt_oid) != 0)
- e->status_flags |= GIT_STATUS_WT_MODIFIED;
-
- return 0;
-}
-
-static int status_entry_is_ignorable(struct status_entry *e)
+static int get_one_status(const char *path, unsigned int status, void *data)
{
- /* don't ignore files that exist in head or index already */
- return (e->status_flags == GIT_STATUS_WT_NEW);
-}
+ struct status_file_info *sfi = data;
-static int status_entry_update_ignore(struct status_entry *e, git_ignores *ignores, const char *path)
-{
- int ignored;
+ sfi->count++;
+ sfi->status = status;
- if (git_ignore__lookup(ignores, path, &ignored) < 0)
+ if (sfi->count > 1 || strcmp(sfi->expected, path) != 0) {
+ giterr_set(GITERR_INVALID,
+ "Ambiguous path '%s' given to git_status_file", sfi->expected);
return -1;
-
- if (ignored)
- /* toggle off WT_NEW and on IGNORED */
- e->status_flags =
- (e->status_flags & ~GIT_STATUS_WT_NEW) | GIT_STATUS_IGNORED;
-
- return 0;
-}
-
-static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char *path)
-{
- char *dir_sep;
- const git_tree_entry *tree_entry;
- git_tree *subtree;
- int error;
-
- dir_sep = strchr(path, '/');
- if (!dir_sep) {
- if ((tree_entry = git_tree_entry_byname(tree, path)) != NULL)
- /* The leaf exists in the tree*/
- status_entry_update_from_tree_entry(e, tree_entry);
- return 0;
- }
-
- /* Retrieve subtree name */
- *dir_sep = '\0';
-
- if ((tree_entry = git_tree_entry_byname(tree, path)) == NULL)
- return 0; /* The subtree doesn't exist in the tree*/
-
- *dir_sep = '/';
-
- /* Retreive subtree */
- error = git_tree_lookup(&subtree, tree->object.repo, &tree_entry->oid);
- if (!error) {
- error = recurse_tree_entry(subtree, e, dir_sep+1);
- git_tree_free(subtree);
}
- return error;
+ return 0;
}
int git_status_file(
- unsigned int *status_flags, git_repository *repo, const char *path)
+ unsigned int *status_flags,
+ git_repository *repo,
+ const char *path)
{
- struct status_entry *e;
- git_index *index = NULL;
- git_buf temp_path = GIT_BUF_INIT;
- int error = 0;
- git_tree *tree = NULL;
- const char *workdir;
+ int error;
+ git_status_options opts;
+ struct status_file_info sfi;
assert(status_flags && repo && path);
- if ((workdir = git_repository_workdir(repo)) == NULL) {
- giterr_set(GITERR_INVALID, "Cannot get file status from bare repo");
+ memset(&sfi, 0, sizeof(sfi));
+ if ((sfi.expected = git__strdup(path)) == NULL)
return -1;
- }
-
- if (git_buf_joinpath(&temp_path, workdir, path) < 0)
- return -1;
-
- if (git_path_isdir(temp_path.ptr)) {
- giterr_set(GITERR_INVALID, "Cannot get file status for directory '%s'", temp_path.ptr);
- git_buf_free(&temp_path);
- return -1;
- }
-
- e = status_entry_new(NULL, path);
- GITERR_CHECK_ALLOC(e);
-
- /* Find file in Workdir */
- if (git_path_exists(temp_path.ptr) == true &&
- (error = status_entry_update_from_workdir(e, temp_path.ptr)) < 0)
- goto cleanup;
-
- /* Find file in Index */
- if ((error = git_repository_index__weakptr(&index, repo)) < 0)
- goto cleanup;
- status_entry_update_from_index(e, index);
- /* Try to find file in HEAD */
- if ((error = git_repository_head_tree(&tree, repo)) < 0)
- goto cleanup;
-
- if (tree != NULL) {
- if ((error = git_buf_sets(&temp_path, path)) < 0 ||
- (error = recurse_tree_entry(tree, e, temp_path.ptr)) < 0)
- goto cleanup;
- }
-
- /* Determine status */
- if ((error = status_entry_update_flags(e)) < 0)
- giterr_set(GITERR_OS, "Cannot find file '%s' to determine status", path);
-
- if (!error && status_entry_is_ignorable(e)) {
- git_ignores ignores;
+ memset(&opts, 0, sizeof(opts));
+ opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
+ opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
+ GIT_STATUS_OPT_INCLUDE_UNTRACKED |
+ GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
+ GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
+ opts.pathspec.count = 1;
+ opts.pathspec.strings = &sfi.expected;
- if ((error = git_ignore__for_path(repo, path, &ignores)) == 0)
- error = status_entry_update_ignore(e, &ignores, path);
+ error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
- git_ignore__free(&ignores);
+ if (!error && !sfi.count) {
+ giterr_set(GITERR_INVALID,
+ "Attempt to get status of nonexistent file '%s'", path);
+ error = GIT_ENOTFOUND;
}
- if (!error)
- *status_flags = e->status_flags;
+ *status_flags = sfi.status;
-cleanup:
- git_buf_free(&temp_path);
- git_tree_free(tree);
- git__free(e);
+ git__free(sfi.expected);
return error;
}
-int git_status_should_ignore(git_repository *repo, const char *path, int *ignored)
+int git_status_should_ignore(
+ int *ignored,
+ git_repository *repo,
+ const char *path)
{
int error;
git_ignores ignores;
diff --git a/src/submodule.c b/src/submodule.c
index 1b5b59f45..3c07e657d 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -218,8 +218,11 @@ static int submodule_from_config(
sm->update = (git_submodule_update_t)val;
}
else if (strcmp(property, "fetchRecurseSubmodules") == 0) {
- if (git_config_parse_bool(&sm->fetch_recurse, value) < 0)
+ if (git__parse_bool(&sm->fetch_recurse, value) < 0) {
+ giterr_set(GITERR_INVALID,
+ "Invalid value for submodule 'fetchRecurseSubmodules' property: '%s'", value);
goto fail;
+ }
}
else if (strcmp(property, "ignore") == 0) {
int val;
diff --git a/src/tag.c b/src/tag.c
index 13481c2a6..63424f530 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -168,7 +168,7 @@ static int retrieve_tag_reference(
return -1;
error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr);
- if (error < GIT_SUCCESS)
+ if (error < 0)
return error; /* Be it not foundo or corrupted */
*tag_reference_out = tag_ref;
@@ -254,7 +254,7 @@ static int git_tag_create__internal(
}
error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name);
- if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
+ if (error < 0 && error != GIT_ENOTFOUND)
return -1;
/** Ensure the tag name doesn't conflict with an already existing
@@ -332,7 +332,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
}
error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name);
- if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
+ if (error < 0 && error != GIT_ENOTFOUND)
goto on_error;
/* We don't need these objects after this */
@@ -414,7 +414,7 @@ static int tag_list_cb(const char *tag_name, void *payload)
return 0;
filter = (tag_filter_data *)payload;
- if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == GIT_SUCCESS)
+ if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0)
return git_vector_insert(filter->taglist, git__strdup(tag_name));
return 0;
@@ -428,7 +428,7 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit
assert(tag_names && repo && pattern);
- if (git_vector_init(&taglist, 8, NULL) < GIT_SUCCESS)
+ if (git_vector_init(&taglist, 8, NULL) < 0)
return -1;
filter.taglist = &taglist;
diff --git a/src/transport.c b/src/transport.c
index bc4248d5b..5b2cd7ea4 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -37,7 +37,7 @@ static git_transport_cb transport_find_fn(const char *url)
}
/* still here? Check to see if the path points to a file on the local file system */
- if ((git_path_exists(url) == GIT_SUCCESS) && git_path_isdir(url))
+ if ((git_path_exists(url) == 0) && git_path_isdir(url))
return &git_transport_local;
/* It could be a SSH remote path. Check to see if there's a : */
@@ -72,7 +72,7 @@ int git_transport_new(git_transport **out, const char *url)
}
error = fn(&transport);
- if (error < GIT_SUCCESS)
+ if (error < 0)
return error;
transport->url = git__strdup(url);
@@ -80,7 +80,7 @@ int git_transport_new(git_transport **out, const char *url)
*out = transport;
- return GIT_SUCCESS;
+ return 0;
}
/* from remote.h */
diff --git a/src/transports/git.c b/src/transports/git.c
index 9a1741941..844b350be 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -147,7 +147,7 @@ static int store_refs(transport_git *t)
return 0;
ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
- if (ret == GIT_ESHORTBUFFER) {
+ if (ret == GIT_EBUFS) {
gitno_consume_n(buf, buf->len);
continue;
}
@@ -279,7 +279,7 @@ static int recv_pkt(gitno_buffer *buf)
return -1;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- if (error == GIT_ESHORTBUFFER)
+ if (error == GIT_EBUFS)
continue;
if (error < 0)
return -1;
@@ -344,7 +344,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
}
}
- if (error < 0 && error != GIT_EREVWALKOVER)
+ if (error < 0 && error != GIT_REVWALKOVER)
goto on_error;
/* Tell the other end that we're done negotiating */
@@ -384,10 +384,10 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git
}
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- if (error == GIT_ESHORTBUFFER)
+ if (error == GIT_EBUFS)
break;
- if (error < GIT_SUCCESS)
+ if (error < 0)
return error;
if (pkt->type == GIT_PKT_PACK) {
@@ -417,6 +417,8 @@ static int git_close(git_transport *transport)
return -1;
}
+ t->parent.connected = 0;
+
#ifdef GIT_WIN32
WSACleanup();
#endif
diff --git a/src/transports/http.c b/src/transports/http.c
index bc4a615f1..9ea21a61d 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -354,10 +354,10 @@ static int on_body_parse_response(http_parser *parser, const char *str, size_t l
return 0;
error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf));
- if (error == GIT_ESHORTBUFFER) {
+ if (error == GIT_EBUFS) {
return 0; /* Ask for more */
}
- if (error < GIT_SUCCESS)
+ if (error < 0)
return t->error = -1;
git_buf_consume(buf, line_end);
@@ -486,7 +486,7 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
git_buf_clear(&request);
git_buf_clear(&data);
- if (ret < GIT_SUCCESS || i >= 256)
+ if (ret < 0 || i >= 256)
break;
if ((ret = parse_response(t)) < 0)
@@ -610,6 +610,8 @@ static int http_close(git_transport *transport)
return -1;
}
+ t->parent.connected = 0;
+
return 0;
}
diff --git a/src/transports/local.c b/src/transports/local.c
index 5dc350103..0e1ae3752 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -91,7 +91,7 @@ static int store_refs(transport_local *t)
assert(t);
- if (git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
+ if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
git_vector_init(&t->refs, (unsigned int)ref_names.count, NULL) < 0)
goto on_error;
@@ -176,10 +176,21 @@ static int local_connect(git_transport *transport, int direction)
return 0;
}
+static int local_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants)
+{
+ GIT_UNUSED(transport);
+ GIT_UNUSED(repo);
+ GIT_UNUSED(wants);
+
+ giterr_set(GITERR_NET, "Fetch via local transport isn't implemented. Sorry");
+ return -1;
+}
+
static int local_close(git_transport *transport)
{
transport_local *t = (transport_local *)transport;
+ t->parent.connected = 0;
git_repository_free(t->repo);
t->repo = NULL;
@@ -220,6 +231,7 @@ int git_transport_local(git_transport **out)
t->parent.connect = local_connect;
t->parent.ls = local_ls;
+ t->parent.negotiate_fetch = local_negotiate_fetch;
t->parent.close = local_close;
t->parent.free = local_free;
diff --git a/src/tree.c b/src/tree.c
index 7e2bfc102..92b1b1e39 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -31,8 +31,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_path_cmp(
- entry_a->filename, entry_a->filename_len, entry_is_tree(entry_a),
- entry_b->filename, entry_b->filename_len, entry_is_tree(entry_b));
+ entry_a->filename, entry_a->filename_len, git_tree_entry__is_tree(entry_a),
+ entry_b->filename, entry_b->filename_len, git_tree_entry__is_tree(entry_b));
}
@@ -170,7 +170,10 @@ git_otype git_tree_entry_type(const git_tree_entry *entry)
return GIT_OBJ_BLOB;
}
-int git_tree_entry_2object(git_object **object_out, git_repository *repo, const git_tree_entry *entry)
+int git_tree_entry_to_object(
+ git_object **object_out,
+ git_repository *repo,
+ const git_tree_entry *entry)
{
assert(entry && object_out);
return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
@@ -195,6 +198,33 @@ const git_tree_entry *git_tree_entry_byindex(git_tree *tree, unsigned int idx)
return git_vector_get(&tree->entries, idx);
}
+int git_tree__prefix_position(git_tree *tree, const char *path)
+{
+ git_vector *entries = &tree->entries;
+ struct tree_key_search ksearch;
+ unsigned int at_pos;
+
+ ksearch.filename = path;
+ ksearch.filename_len = strlen(path);
+
+ /* Find tree entry with appropriate prefix */
+ git_vector_bsearch3(&at_pos, entries, &homing_search_cmp, &ksearch);
+
+ for (; at_pos < entries->length; ++at_pos) {
+ const git_tree_entry *entry = entries->contents[at_pos];
+ if (homing_search_cmp(&ksearch, entry) < 0)
+ break;
+ }
+
+ for (; at_pos > 0; --at_pos) {
+ const git_tree_entry *entry = entries->contents[at_pos - 1];
+ if (homing_search_cmp(&ksearch, entry) > 0)
+ break;
+ }
+
+ return at_pos;
+}
+
unsigned int git_tree_entrycount(git_tree *tree)
{
assert(tree);
@@ -617,7 +647,7 @@ static int tree_frompath(
{
char *slash_pos = NULL;
const git_tree_entry* entry;
- int error = GIT_SUCCESS;
+ int error = 0;
git_tree *subtree;
if (!*(treeentry_path->ptr + offset)) {
@@ -694,7 +724,7 @@ static int tree_walk_post(
git_buf *path,
void *payload)
{
- int error = GIT_SUCCESS;
+ int error = 0;
unsigned int i;
for (i = 0; i < tree->entries.length; ++i) {
@@ -703,7 +733,7 @@ static int tree_walk_post(
if (callback(path->ptr, entry, payload) < 0)
continue;
- if (entry_is_tree(entry)) {
+ if (git_tree_entry__is_tree(entry)) {
git_tree *subtree;
size_t path_len = git_buf_len(path);
@@ -731,7 +761,7 @@ static int tree_walk_post(
int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload)
{
- int error = GIT_SUCCESS;
+ int error = 0;
git_buf root_path = GIT_BUF_INIT;
switch (mode) {
@@ -753,273 +783,3 @@ int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payl
return error;
}
-static int tree_entry_cmp(const git_tree_entry *a, const git_tree_entry *b)
-{
- int ret;
-
- ret = a->attr - b->attr;
- if (ret != 0)
- return ret;
-
- return git_oid_cmp(&a->oid, &b->oid);
-}
-
-static void mark_del(git_tree_diff_data *diff, git_tree_entry *entry)
-{
- diff->old_attr = entry->attr;
- git_oid_cpy(&diff->old_oid, &entry->oid);
- diff->path = entry->filename;
- diff->status |= GIT_STATUS_DELETED;
-}
-
-static void mark_add(git_tree_diff_data *diff, git_tree_entry *entry)
-{
- diff->new_attr = entry->attr;
- git_oid_cpy(&diff->new_oid, &entry->oid);
- diff->path = entry->filename;
- diff->status |= GIT_STATUS_ADDED;
-}
-
-static int signal_additions(git_tree *tree, int start, int end, git_tree_diff_cb cb, void *data)
-{
- git_tree_diff_data diff;
- git_tree_entry *entry;
- int i;
-
- if (end < 0)
- end = git_tree_entrycount(tree);
-
- for (i = start; i < end; ++i) {
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
- entry = git_vector_get(&tree->entries, i);
- mark_add(&diff, entry);
-
- if (cb(&diff, data) < 0)
- return -1;
- }
-
- return 0;
-}
-
-static int signal_addition(git_tree_entry *entry, git_tree_diff_cb cb, void *data)
-{
- git_tree_diff_data diff;
-
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
-
- mark_add(&diff, entry);
-
- return cb(&diff, data);
-}
-
-static int signal_deletions(git_tree *tree, int start, int end, git_tree_diff_cb cb, void *data)
-{
- git_tree_diff_data diff;
- git_tree_entry *entry;
- int i;
-
- if (end < 0)
- end = git_tree_entrycount(tree);
-
- for (i = start; i < end; ++i) {
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
- entry = git_vector_get(&tree->entries, i);
- mark_del(&diff, entry);
-
- if (cb(&diff, data) < 0)
- return -1;
- }
-
- return 0;
-}
-
-static int signal_deletion(git_tree_entry *entry, git_tree_diff_cb cb, void *data)
-{
- git_tree_diff_data diff;
-
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
-
- mark_del(&diff, entry);
-
- return cb(&diff, data);
-}
-
-static int signal_modification(git_tree_entry *a, git_tree_entry *b,
- git_tree_diff_cb cb, void *data)
-{
- git_tree_diff_data diff;
-
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
-
- mark_del(&diff, a);
- mark_add(&diff, b);
-
- return cb(&diff, data);
-}
-
-int git_tree_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data)
-{
- unsigned int i_a = 0, i_b = 0; /* Counters for trees a and b */
- git_tree_entry *entry_a = NULL, *entry_b = NULL;
- git_tree_diff_data diff;
- int cmp;
-
- while (1) {
- entry_a = a == NULL ? NULL : git_vector_get(&a->entries, i_a);
- entry_b = b == NULL ? NULL : git_vector_get(&b->entries, i_b);
-
- if (!entry_a && !entry_b)
- return 0;
-
- memset(&diff, 0x0, sizeof(git_tree_diff_data));
-
- /*
- * We've run out of tree on one side so the rest of the
- * entries on the tree with remaining entries are all
- * deletions or additions.
- */
- if (entry_a && !entry_b)
- return signal_deletions(a, i_a, -1, cb, data);
- if (!entry_a && entry_b)
- return signal_additions(b, i_b, -1, cb, data);
-
- /*
- * Both trees are sorted with git's almost-alphabetical
- * sorting, so a comparison value < 0 means the entry was
- * deleted in the right tree. > 0 means the entry was added.
- */
- cmp = entry_sort_cmp(entry_a, entry_b);
-
- if (cmp == 0) {
- i_a++;
- i_b++;
-
- /* If everything's the same, jump to next pair */
- if (!tree_entry_cmp(entry_a, entry_b))
- continue;
-
- /* If they're not both dirs or both files, it's add + del */
- if (S_ISDIR(entry_a->attr) != S_ISDIR(entry_b->attr)) {
- if (signal_addition(entry_a, cb, data) < 0)
- return -1;
- if (signal_deletion(entry_b, cb, data) < 0)
- return -1;
- }
-
- /* Otherwise consider it a modification */
- if (signal_modification(entry_a, entry_b, cb, data) < 0)
- return -1;
-
- } else if (cmp < 0) {
- i_a++;
- if (signal_deletion(entry_a, cb, data) < 0)
- return -1;
- } else if (cmp > 0) {
- i_b++;
- if (signal_addition(entry_b, cb, data) < 0)
- return -1;
- }
- }
-
- return 0;
-}
-
-struct diff_index_cbdata {
- git_index *index;
- unsigned int i;
- git_tree_diff_cb cb;
- void *data;
-};
-
-static int cmp_tentry_ientry(git_tree_entry *tentry, git_index_entry *ientry)
-{
- int cmp;
-
- cmp = tentry->attr - ientry->mode;
- if (cmp != 0)
- return cmp;
-
- return git_oid_cmp(&tentry->oid, &ientry->oid);
-}
-
-static void make_tentry(git_tree_entry *tentry, git_index_entry *ientry)
-{
- char *last_slash;
-
- memset(tentry, 0x0, sizeof(git_tree_entry));
- tentry->attr = ientry->mode;
-
- last_slash = strrchr(ientry->path, '/');
- if (last_slash)
- last_slash++;
- else
- last_slash = ientry->path;
- tentry->filename = last_slash;
-
- git_oid_cpy(&tentry->oid, &ientry->oid);
- tentry->filename_len = strlen(tentry->filename);
-}
-
-static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data)
-{
- struct diff_index_cbdata *cbdata = (struct diff_index_cbdata *) data;
- git_index_entry *ientry = git_index_get(cbdata->index, cbdata->i);
- git_tree_entry fake_entry;
- git_buf fn_buf = GIT_BUF_INIT;
- int cmp;
-
- if (entry_is_tree(tentry))
- return 0;
-
- if (!ientry)
- return signal_deletion(tentry, cbdata->cb, cbdata->data);
-
- git_buf_puts(&fn_buf, root);
- git_buf_puts(&fn_buf, tentry->filename);
-
- /* Like with 'git diff-index', the index is the right side*/
- cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path);
- git_buf_free(&fn_buf);
- if (cmp == 0) {
- cbdata->i++;
- if (!cmp_tentry_ientry(tentry, ientry))
- return 0;
- /* modification */
- make_tentry(&fake_entry, ientry);
- if (signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data) < 0)
- return -1;
- } else if (cmp < 0) {
- /* deletion */
- memcpy(&fake_entry, tentry, sizeof(git_tree_entry));
- if (signal_deletion(tentry, cbdata->cb, cbdata->data) < 0)
- return -1;
- } else {
- /* addition */
- cbdata->i++;
- make_tentry(&fake_entry, ientry);
- if (signal_addition(&fake_entry, cbdata->cb, cbdata->data) < 0)
- return -1;
- /*
- * The index has an addition. This means that we need to use
- * the next entry in the index without advancing the tree
- * walker, so call ourselves with the same tree state.
- */
- if (diff_index_cb(root, tentry, data) < 0)
- return -1;;
- }
-
- return 0;
-}
-
-int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data)
-{
- struct diff_index_cbdata cbdata;
- git_buf dummy_path = GIT_BUF_INIT;
-
- cbdata.index = index;
- cbdata.i = 0;
- cbdata.cb = cb;
- cbdata.data = data;
-
- return tree_walk_post(tree, diff_index_cb, &dummy_path, &cbdata);
-}
diff --git a/src/tree.h b/src/tree.h
index fd00afde5..498a90d66 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -30,7 +30,7 @@ struct git_treebuilder {
};
-GIT_INLINE(unsigned int) entry_is_tree(const struct git_tree_entry *e)
+GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
{
return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr));
}
@@ -38,4 +38,14 @@ GIT_INLINE(unsigned int) entry_is_tree(const struct git_tree_entry *e)
void git_tree__free(git_tree *tree);
int git_tree__parse(git_tree *tree, git_odb_object *obj);
+/**
+ * Lookup the first position in the tree with a given prefix.
+ *
+ * @param tree a previously loaded tree.
+ * @param prefix the beginning of a path to find in the tree.
+ * @return index of the first item at or after the given prefix.
+ */
+int git_tree__prefix_position(git_tree *tree, const char *prefix);
+
+
#endif
diff --git a/src/unix/posix.h b/src/unix/posix.h
index 9973acf30..48b492941 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -7,7 +7,14 @@
#ifndef INCLUDE_posix__w32_h__
#define INCLUDE_posix__w32_h__
-#include <fnmatch.h>
+#ifndef __sun
+# include <fnmatch.h>
+# define p_fnmatch(p, s, f) fnmatch(p, s, f)
+#else
+# include "compat/fnmatch.h"
+#endif
+
+#include <stdio.h>
#define p_lstat(p,b) lstat(p,b)
#define p_readlink(a, b, c) readlink(a, b, c)
@@ -16,7 +23,6 @@
#define p_mkdir(p,m) mkdir(p, m)
#define p_fsync(fd) fsync(fd)
#define p_realpath(p, po) realpath(p, po)
-#define p_fnmatch(p, s, f) fnmatch(p, s, f)
#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a)
#define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__)
#define p_mkstemp(p) mkstemp(p)
diff --git a/src/util.c b/src/util.c
index 9fd5f286c..ce770203a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -411,3 +411,27 @@ int git__strcmp_cb(const void *a, const void *b)
return strcmp(stra, strb);
}
+
+int git__parse_bool(int *out, const char *value)
+{
+ /* A missing value means true */
+ if (value == NULL) {
+ *out = 1;
+ return 0;
+ }
+
+ if (!strcasecmp(value, "true") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "on")) {
+ *out = 1;
+ return 0;
+ }
+ if (!strcasecmp(value, "false") ||
+ !strcasecmp(value, "no") ||
+ !strcasecmp(value, "off")) {
+ *out = 0;
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/util.h b/src/util.h
index 9003c08ad..c4a55f524 100644
--- a/src/util.h
+++ b/src/util.h
@@ -216,4 +216,18 @@ GIT_INLINE(int) git__time_cmp(const git_time *a, const git_time *b)
return (int)(adjusted_a - b->time);
}
+GIT_INLINE(bool) git__iswildcard(int c)
+{
+ return (c == '*' || c == '?' || c == '[');
+}
+
+/*
+ * Parse a string value as a boolean, just like Core Git
+ * does.
+ *
+ * Valid values for true are: 'true', 'yes', 'on'
+ * Valid values for false are: 'false', 'no', 'off'
+ */
+extern int git__parse_bool(int *out, const char *value);
+
#endif /* INCLUDE_util_h__ */
diff --git a/src/vector.c b/src/vector.c
index 304f324f0..6f9aacccf 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -116,8 +116,13 @@ void git_vector_sort(git_vector *v)
v->sorted = 1;
}
-int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key)
+int git_vector_bsearch3(
+ unsigned int *at_pos,
+ git_vector *v,
+ git_vector_cmp key_lookup,
+ const void *key)
{
+ int rval;
size_t pos;
assert(v && key && key_lookup);
@@ -127,13 +132,16 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke
git_vector_sort(v);
- if (git__bsearch(v->contents, v->length, key, key_lookup, &pos) >= 0)
- return (int)pos;
+ rval = git__bsearch(v->contents, v->length, key, key_lookup, &pos);
- return GIT_ENOTFOUND;
+ if (at_pos != NULL)
+ *at_pos = (unsigned int)pos;
+
+ return (rval >= 0) ? (int)pos : GIT_ENOTFOUND;
}
-int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key)
+int git_vector_search2(
+ git_vector *v, git_vector_cmp key_lookup, const void *key)
{
unsigned int i;
@@ -157,11 +165,6 @@ int git_vector_search(git_vector *v, const void *entry)
return git_vector_search2(v, v->_cmp ? v->_cmp : strict_comparison, entry);
}
-int git_vector_bsearch(git_vector *v, const void *key)
-{
- return git_vector_bsearch2(v, v->_cmp, key);
-}
-
int git_vector_remove(git_vector *v, unsigned int idx)
{
unsigned int i;
diff --git a/src/vector.h b/src/vector.h
index 5bc27914a..9139db345 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -26,13 +26,24 @@ void git_vector_free(git_vector *v);
void git_vector_clear(git_vector *v);
void git_vector_swap(git_vector *a, git_vector *b);
+void git_vector_sort(git_vector *v);
+
int git_vector_search(git_vector *v, const void *entry);
int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key);
-int git_vector_bsearch(git_vector *v, const void *entry);
-int git_vector_bsearch2(git_vector *v, git_vector_cmp cmp, const void *key);
+int git_vector_bsearch3(
+ unsigned int *at_pos, git_vector *v, git_vector_cmp cmp, const void *key);
-void git_vector_sort(git_vector *v);
+GIT_INLINE(int) git_vector_bsearch(git_vector *v, const void *key)
+{
+ return git_vector_bsearch3(NULL, v, v->_cmp, key);
+}
+
+GIT_INLINE(int) git_vector_bsearch2(
+ git_vector *v, git_vector_cmp cmp, const void *key)
+{
+ return git_vector_bsearch3(NULL, v, cmp, key);
+}
GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position)
{
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 55732f5ac..c38caa8ee 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -8,7 +8,7 @@
#define INCLUDE_posix__w32_h__
#include "common.h"
-#include "fnmatch.h"
+#include "compat/fnmatch.h"
#include "utf-conv.h"
GIT_INLINE(int) p_link(const char *old, const char *new)
diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c
index 76f1e4237..0a705c0ad 100644
--- a/src/win32/utf-conv.c
+++ b/src/win32/utf-conv.c
@@ -32,19 +32,16 @@ void gitwin_set_utf8(void)
wchar_t* gitwin_to_utf16(const char* str)
{
wchar_t* ret;
- size_t cb;
+ int cb;
if (!str)
return NULL;
- cb = strlen(str) * sizeof(wchar_t);
+ cb = MultiByteToWideChar(_active_codepage, 0, str, -1, NULL, 0);
if (cb == 0)
return (wchar_t *)git__calloc(1, sizeof(wchar_t));
- /* Add space for null terminator */
- cb += sizeof(wchar_t);
-
- ret = (wchar_t *)git__malloc(cb);
+ ret = (wchar_t *)git__malloc(cb * sizeof(wchar_t));
if (!ret)
return NULL;
@@ -59,7 +56,8 @@ wchar_t* gitwin_to_utf16(const char* str)
int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len)
{
- int result = MultiByteToWideChar(_active_codepage, 0, str, -1, buffer, (int)len);
+ int result = MultiByteToWideChar(
+ _active_codepage, 0, str, -1, buffer, (int)len);
if (result == 0)
giterr_set(GITERR_OS, "Could not convert string to UTF-16");
return result;
@@ -68,23 +66,22 @@ int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len)
char* gitwin_from_utf16(const wchar_t* str)
{
char* ret;
- size_t cb;
+ int cb;
if (!str)
return NULL;
- cb = wcslen(str) * sizeof(char);
+ cb = WideCharToMultiByte(_active_codepage, 0, str, -1, NULL, 0, NULL, NULL);
if (cb == 0)
return (char *)git__calloc(1, sizeof(char));
- /* Add space for null terminator */
- cb += sizeof(char);
-
ret = (char*)git__malloc(cb);
if (!ret)
return NULL;
- if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0) {
+ if (WideCharToMultiByte(
+ _active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0)
+ {
giterr_set(GITERR_OS, "Could not convert string to UTF-8");
git__free(ret);
ret = NULL;