summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-04-17 11:53:13 -0700
committerRussell Belfer <rb@github.com>2014-04-17 15:04:41 -0700
commit823c0e9cc142529912976f2e6abff3db456cb204 (patch)
treec07051b17bfcff2ef3edc24da05a8bb5ed6616e1
parente6e8530aa6c8773dd523fd6fe07629b9481a8fee (diff)
downloadlibgit2-823c0e9cc142529912976f2e6abff3db456cb204.tar.gz
Fix broken logic for attr cache invalidation
The checks to see if files were out of date in the attibute cache was wrong because the cache-breaker data wasn't getting stored correctly. Additionally, when the cache-breaker triggered, the old file data was being leaked.
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/attr.c24
-rw-r--r--src/attr_file.c115
-rw-r--r--src/attr_file.h51
-rw-r--r--src/attrcache.c122
-rw-r--r--src/attrcache.h47
-rw-r--r--src/fileops.c14
-rw-r--r--src/fileops.h6
-rw-r--r--src/ignore.c62
-rw-r--r--tests/attr/file.c8
-rw-r--r--tests/attr/lookup.c6
-rw-r--r--tests/attr/repo.c9
-rw-r--r--tests/status/ignore.c6
13 files changed, 265 insertions, 210 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 23c5af1fc..918e5b8f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -305,6 +305,11 @@ ELSE ()
ENDIF ()
IF (APPLE) # Apple deprecated OpenSSL
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
+
+ # With clang, disable some annoying extra warnings
+ IF (NOT CMAKE_COMPILER_IS_GNUCC)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-const-variable -Wno-unused-function")
+ ENDIF()
ENDIF ()
IF (PROFILE)
SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}")
diff --git a/src/attr.c b/src/attr.c
index 2e314998f..622874348 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -260,26 +260,26 @@ typedef struct {
} attr_walk_up_info;
static int attr_decide_sources(
- uint32_t flags, bool has_wd, bool has_index, git_attr_cache_source *srcs)
+ uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs)
{
int count = 0;
switch (flags & 0x03) {
case GIT_ATTR_CHECK_FILE_THEN_INDEX:
if (has_wd)
- srcs[count++] = GIT_ATTR_CACHE__FROM_FILE;
+ srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
if (has_index)
- srcs[count++] = GIT_ATTR_CACHE__FROM_INDEX;
+ srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
break;
case GIT_ATTR_CHECK_INDEX_THEN_FILE:
if (has_index)
- srcs[count++] = GIT_ATTR_CACHE__FROM_INDEX;
+ srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
if (has_wd)
- srcs[count++] = GIT_ATTR_CACHE__FROM_FILE;
+ srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
break;
case GIT_ATTR_CHECK_INDEX_ONLY:
if (has_index)
- srcs[count++] = GIT_ATTR_CACHE__FROM_INDEX;
+ srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
break;
}
@@ -289,7 +289,7 @@ static int attr_decide_sources(
static int push_attr_file(
git_repository *repo,
git_vector *list,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *base,
const char *filename)
{
@@ -297,7 +297,7 @@ static int push_attr_file(
git_attr_file *file = NULL;
error = git_attr_cache__get(
- &file, repo, source, base, filename, git_attr_file__parse_buffer, NULL);
+ &file, repo, source, base, filename, git_attr_file__parse_buffer);
if (error < 0)
return error;
@@ -313,7 +313,7 @@ static int push_one_attr(void *ref, git_buf *path)
{
int error = 0, n_src, i;
attr_walk_up_info *info = (attr_walk_up_info *)ref;
- git_attr_cache_source src[2];
+ git_attr_file_source src[2];
n_src = attr_decide_sources(
info->flags, info->workdir != NULL, info->index != NULL, src);
@@ -367,7 +367,7 @@ static int collect_attr_files(
*/
error = push_attr_file(
- repo, files, GIT_ATTR_CACHE__FROM_FILE,
+ repo, files, GIT_ATTR_FILE__FROM_FILE,
git_repository_path(repo), GIT_ATTR_FILE_INREPO);
if (error < 0)
goto cleanup;
@@ -385,7 +385,7 @@ static int collect_attr_files(
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
error = push_attr_file(
- repo, files, GIT_ATTR_CACHE__FROM_FILE,
+ repo, files, GIT_ATTR_FILE__FROM_FILE,
NULL, git_repository_attr_cache(repo)->cfg_attr_file);
if (error < 0)
goto cleanup;
@@ -395,7 +395,7 @@ static int collect_attr_files(
error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
if (!error)
error = push_attr_file(
- repo, files, GIT_ATTR_CACHE__FROM_FILE, NULL, dir.ptr);
+ repo, files, GIT_ATTR_FILE__FROM_FILE, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND) {
giterr_clear();
error = 0;
diff --git a/src/attr_file.c b/src/attr_file.c
index 574de25bb..65bbf78e8 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -2,6 +2,7 @@
#include "repository.h"
#include "filebuf.h"
#include "attr_file.h"
+#include "attrcache.h"
#include "git2/blob.h"
#include "git2/tree.h"
#include "index.h"
@@ -22,8 +23,8 @@ static void attr_file_free(git_attr_file *file)
int git_attr_file__new(
git_attr_file **out,
- git_attr_cache_entry *ce,
- git_attr_cache_source source)
+ git_attr_file_entry *entry,
+ git_attr_file_source source)
{
git_attr_file *attrs = git__calloc(1, sizeof(git_attr_file));
GITERR_CHECK_ALLOC(attrs);
@@ -40,7 +41,7 @@ int git_attr_file__new(
}
GIT_REFCOUNT_INC(attrs);
- attrs->ce = ce;
+ attrs->entry = entry;
attrs->source = source;
*out = attrs;
return 0;
@@ -95,42 +96,77 @@ static int attr_file_oid_from_index(
int git_attr_file__load(
git_attr_file **out,
git_repository *repo,
- git_attr_cache_entry *ce,
- git_attr_cache_source source,
- git_attr_cache_parser parser,
- void *payload)
+ git_attr_file_entry *entry,
+ git_attr_file_source source,
+ git_attr_file_parser parser)
{
int error = 0;
git_blob *blob = NULL;
git_buf content = GIT_BUF_INIT;
const char *data = NULL;
git_attr_file *file;
+ struct stat st;
*out = NULL;
- if (source == GIT_ATTR_CACHE__FROM_INDEX) {
+ switch (source) {
+ case GIT_ATTR_FILE__IN_MEMORY:
+ /* in-memory attribute file doesn't need data */
+ break;
+ case GIT_ATTR_FILE__FROM_INDEX: {
git_oid id;
- if ((error = attr_file_oid_from_index(&id, repo, ce->path)) < 0 ||
+ if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
(error = git_blob_lookup(&blob, repo, &id)) < 0)
return error;
data = git_blob_rawcontent(blob);
- } else {
- if ((error = git_futils_readbuffer(&content, ce->fullpath)) < 0)
- /* always return ENOTFOUND so item will just be skipped */
- /* TODO: issue a warning once warnings API is available */
+ break;
+ }
+ case GIT_ATTR_FILE__FROM_FILE: {
+ int fd;
+
+ if (p_stat(entry->fullpath, &st) < 0)
+ return git_path_set_error(errno, entry->fullpath, "stat");
+ if (S_ISDIR(st.st_mode))
return GIT_ENOTFOUND;
+
+ /* For open or read errors, return ENOTFOUND to skip item */
+ /* TODO: issue warning when warning API is available */
+
+ if ((fd = git_futils_open_ro(entry->fullpath)) < 0)
+ return GIT_ENOTFOUND;
+
+ error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size);
+ p_close(fd);
+
+ if (error < 0)
+ return GIT_ENOTFOUND;
+
data = content.ptr;
+ break;
+ }
+ default:
+ giterr_set(GITERR_INVALID, "Unknown file source %d", source);
+ return -1;
}
- if ((error = git_attr_file__new(&file, ce, source)) < 0)
+ if ((error = git_attr_file__new(&file, entry, source)) < 0)
goto cleanup;
- if (parser && (error = parser(repo, file, data, payload)) < 0)
+ if (parser && (error = parser(repo, file, data)) < 0) {
git_attr_file__free(file);
- else
- *out = file;
+ goto cleanup;
+ }
+
+ /* write cache breaker */
+ if (source == GIT_ATTR_FILE__FROM_INDEX)
+ git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
+ else if (source == GIT_ATTR_FILE__FROM_FILE)
+ git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
+ /* else always cacheable */
+
+ *out = file;
cleanup:
git_blob_free(blob);
@@ -144,18 +180,29 @@ int git_attr_file__out_of_date(git_repository *repo, git_attr_file *file)
if (!file)
return 1;
- if (file->source == GIT_ATTR_CACHE__FROM_INDEX) {
+ switch (file->source) {
+ case GIT_ATTR_FILE__IN_MEMORY:
+ return 0;
+
+ case GIT_ATTR_FILE__FROM_FILE:
+ return git_futils_filestamp_check(
+ &file->cache_data.stamp, file->entry->fullpath);
+
+ case GIT_ATTR_FILE__FROM_INDEX: {
int error;
git_oid id;
- if ((error = attr_file_oid_from_index(&id, repo, file->ce->path)) < 0)
+ if ((error = attr_file_oid_from_index(
+ &id, repo, file->entry->path)) < 0)
return error;
return (git_oid__cmp(&file->cache_data.oid, &id) != 0);
}
- return git_futils_filestamp_check(
- &file->cache_data.stamp, file->ce->fullpath);
+ default:
+ giterr_set(GITERR_INVALID, "Invalid file type %d", file->source);
+ return -1;
+ }
}
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
@@ -166,22 +213,17 @@ static bool parse_optimized_patterns(
const char *pattern);
int git_attr_file__parse_buffer(
- git_repository *repo,
- git_attr_file *attrs,
- const char *data,
- void *payload)
+ git_repository *repo, git_attr_file *attrs, const char *data)
{
int error = 0;
const char *scan = data, *context = NULL;
git_attr_rule *rule = NULL;
- GIT_UNUSED(payload);
-
/* if subdir file path, convert context for file paths */
- if (attrs->ce &&
- git_path_root(attrs->ce->path) < 0 &&
- !git__suffixcmp(attrs->ce->path, "/" GIT_ATTR_FILE))
- context = attrs->ce->path;
+ if (attrs->entry &&
+ git_path_root(attrs->entry->path) < 0 &&
+ !git__suffixcmp(attrs->entry->path, "/" GIT_ATTR_FILE))
+ context = attrs->entry->path;
if (git_mutex_lock(&attrs->lock) < 0) {
giterr_set(GITERR_OS, "Failed to lock attribute file");
@@ -268,19 +310,18 @@ int git_attr_file__lookup_one(
return 0;
}
-int git_attr_file__load_standalone(
- git_attr_file **out,
- const char *path)
+int git_attr_file__load_standalone(git_attr_file **out, const char *path)
{
int error;
git_attr_file *file;
git_buf content = GIT_BUF_INIT;
- error = git_attr_file__new(&file, NULL, GIT_ATTR_CACHE__FROM_FILE);
+ error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE);
if (error < 0)
return error;
- error = git_attr_cache_entry__new(&file->ce, NULL, path, &file->pool);
+ error = git_attr_cache__alloc_file_entry(
+ &file->entry, NULL, path, &file->pool);
if (error < 0) {
git_attr_file__free(file);
return error;
@@ -290,7 +331,7 @@ int git_attr_file__load_standalone(
*/
if (!(error = git_futils_readbuffer(&content, path))) {
- error = git_attr_file__parse_buffer(NULL, file, content.ptr, NULL);
+ error = git_attr_file__parse_buffer(NULL, file, content.ptr);
git_buf_free(&content);
}
diff --git a/src/attr_file.h b/src/attr_file.h
index 9b4b8724b..c906be44d 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -13,7 +13,6 @@
#include "pool.h"
#include "buffer.h"
#include "fileops.h"
-#include "attrcache.h"
#define GIT_ATTR_FILE ".gitattributes"
#define GIT_ATTR_FILE_INREPO "info/attributes"
@@ -36,6 +35,14 @@
(GIT_ATTR_FNMATCH_ALLOWSPACE | \
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
+typedef enum {
+ GIT_ATTR_FILE__IN_MEMORY = 0,
+ GIT_ATTR_FILE__FROM_FILE = 1,
+ GIT_ATTR_FILE__FROM_INDEX = 2,
+
+ GIT_ATTR_FILE_NUM_SOURCES = 3
+} git_attr_file_source;
+
extern const char *git_attr__true;
extern const char *git_attr__false;
extern const char *git_attr__unset;
@@ -46,10 +53,10 @@ typedef struct {
unsigned int flags;
} git_attr_fnmatch;
-struct git_attr_rule {
+typedef struct {
git_attr_fnmatch match;
git_vector assigns; /* vector of <git_attr_assignment*> */
-};
+} git_attr_rule;
typedef struct {
git_refcount unused;
@@ -64,19 +71,32 @@ typedef struct {
const char *value;
} git_attr_assignment;
-struct git_attr_file {
+typedef struct git_attr_file_entry git_attr_file_entry;
+
+typedef struct {
git_refcount rc;
git_mutex lock;
- git_attr_cache_entry *ce;
- git_attr_cache_source source;
+ git_attr_file_entry *entry;
+ git_attr_file_source source;
git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool pool;
union {
git_oid oid;
git_futils_filestamp stamp;
} cache_data;
+} git_attr_file;
+
+struct git_attr_file_entry {
+ git_attr_file *file[GIT_ATTR_FILE_NUM_SOURCES];
+ const char *path; /* points into fullpath */
+ char fullpath[GIT_FLEX_ARRAY];
};
+typedef int (*git_attr_file_parser)(
+ git_repository *repo,
+ git_attr_file *file,
+ const char *data);
+
typedef struct {
git_buf full;
char *path;
@@ -90,31 +110,26 @@ typedef struct {
int git_attr_file__new(
git_attr_file **out,
- git_attr_cache_entry *ce,
- git_attr_cache_source source);
+ git_attr_file_entry *entry,
+ git_attr_file_source source);
void git_attr_file__free(git_attr_file *file);
int git_attr_file__load(
git_attr_file **out,
git_repository *repo,
- git_attr_cache_entry *ce,
- git_attr_cache_source source,
- git_attr_cache_parser parser,
- void *payload);
+ git_attr_file_entry *ce,
+ git_attr_file_source source,
+ git_attr_file_parser parser);
int git_attr_file__load_standalone(
- git_attr_file **out,
- const char *path);
+ git_attr_file **out, const char *path);
int git_attr_file__out_of_date(
git_repository *repo, git_attr_file *file);
int git_attr_file__parse_buffer(
- git_repository *repo,
- git_attr_file *attrs,
- const char *data,
- void *payload);
+ git_repository *repo, git_attr_file *attrs, const char *data);
int git_attr_file__clear_rules(
git_attr_file *file, bool need_lock);
diff --git a/src/attrcache.c b/src/attrcache.c
index a7dc0c887..925abb57f 100644
--- a/src/attrcache.c
+++ b/src/attrcache.c
@@ -24,7 +24,7 @@ GIT_INLINE(void) attr_cache_unlock(git_attr_cache *cache)
git_mutex_unlock(&cache->lock);
}
-GIT_INLINE(git_attr_cache_entry *) attr_cache_lookup_entry(
+GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
git_attr_cache *cache, const char *path)
{
khiter_t pos = git_strmap_lookup_index(cache->files, path);
@@ -35,15 +35,15 @@ GIT_INLINE(git_attr_cache_entry *) attr_cache_lookup_entry(
return NULL;
}
-int git_attr_cache_entry__new(
- git_attr_cache_entry **out,
+int git_attr_cache__alloc_file_entry(
+ git_attr_file_entry **out,
const char *base,
const char *path,
git_pool *pool)
{
size_t baselen = 0, pathlen = strlen(path);
- size_t cachesize = sizeof(git_attr_cache_entry) + pathlen + 1;
- git_attr_cache_entry *ce;
+ size_t cachesize = sizeof(git_attr_file_entry) + pathlen + 1;
+ git_attr_file_entry *ce;
if (base != NULL && git_path_root(path) < 0) {
baselen = strlen(base);
@@ -72,41 +72,41 @@ int git_attr_cache_entry__new(
/* call with attrcache locked */
static int attr_cache_make_entry(
- git_attr_cache_entry **out, git_repository *repo, const char *path)
+ git_attr_file_entry **out, git_repository *repo, const char *path)
{
int error = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_cache_entry *ce = NULL;
+ git_attr_file_entry *entry = NULL;
- error = git_attr_cache_entry__new(
- &ce, git_repository_workdir(repo), path, &cache->pool);
+ error = git_attr_cache__alloc_file_entry(
+ &entry, git_repository_workdir(repo), path, &cache->pool);
if (!error) {
- git_strmap_insert(cache->files, ce->path, ce, error);
+ git_strmap_insert(cache->files, entry->path, entry, error);
if (error > 0)
error = 0;
}
- *out = ce;
+ *out = entry;
return error;
}
/* insert entry or replace existing if we raced with another thread */
static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
{
- git_attr_cache_entry *ce;
+ git_attr_file_entry *entry;
git_attr_file *old;
if (attr_cache_lock(cache) < 0)
return -1;
- ce = attr_cache_lookup_entry(cache, file->ce->path);
-
- old = ce->file[file->source];
+ entry = attr_cache_lookup_entry(cache, file->entry->path);
- GIT_REFCOUNT_OWN(file, ce);
+ GIT_REFCOUNT_OWN(file, entry);
GIT_REFCOUNT_INC(file);
- ce->file[file->source] = file;
+
+ old = git__compare_and_swap(
+ &entry->file[file->source], entry->file[file->source], file);
if (old) {
GIT_REFCOUNT_OWN(old, NULL);
@@ -120,7 +120,7 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
{
int error = 0;
- git_attr_cache_entry *ce;
+ git_attr_file_entry *entry;
bool found = false;
if (!file)
@@ -128,27 +128,29 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
if ((error = attr_cache_lock(cache)) < 0)
return error;
- if ((ce = attr_cache_lookup_entry(cache, file->ce->path)) != NULL &&
- ce->file[file->source] == file)
- {
- ce->file[file->source] = NULL;
- GIT_REFCOUNT_OWN(file, NULL);
- found = true;
- }
+ if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
+ file = git__compare_and_swap(&entry->file[file->source], file, NULL);
attr_cache_unlock(cache);
- if (found)
+ if (found) {
+ GIT_REFCOUNT_OWN(file, NULL);
git_attr_file__free(file);
+ }
return error;
}
+/* Look up cache entry and file.
+ * - If entry is not present, create it while the cache is locked.
+ * - If file is present, increment refcount before returning it, so the
+ * cache can be unlocked and it won't go away.
+ */
static int attr_cache_lookup(
git_attr_file **out_file,
- git_attr_cache_entry **out_ce,
+ git_attr_file_entry **out_entry,
git_repository *repo,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *base,
const char *filename)
{
@@ -156,7 +158,7 @@ static int attr_cache_lookup(
git_buf path = GIT_BUF_INIT;
const char *wd = git_repository_workdir(repo), *relfile;
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_cache_entry *ce = NULL;
+ git_attr_file_entry *entry = NULL;
git_attr_file *file = NULL;
/* join base and path as needed */
@@ -174,20 +176,20 @@ static int attr_cache_lookup(
if ((error = attr_cache_lock(cache)) < 0)
goto cleanup;
- ce = attr_cache_lookup_entry(cache, relfile);
- if (!ce) {
- if ((error = attr_cache_make_entry(&ce, repo, relfile)) < 0)
+ entry = attr_cache_lookup_entry(cache, relfile);
+ if (!entry) {
+ if ((error = attr_cache_make_entry(&entry, repo, relfile)) < 0)
goto cleanup;
- } else if (ce->file[source] != NULL) {
- file = ce->file[source];
+ } else if (entry->file[source] != NULL) {
+ file = entry->file[source];
GIT_REFCOUNT_INC(file);
}
attr_cache_unlock(cache);
cleanup:
- *out_file = file;
- *out_ce = ce;
+ *out_file = file;
+ *out_entry = entry;
git_buf_free(&path);
return error;
@@ -196,29 +198,26 @@ cleanup:
int git_attr_cache__get(
git_attr_file **out,
git_repository *repo,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *base,
const char *filename,
- git_attr_cache_parser parser,
- void *payload)
+ git_attr_file_parser parser)
{
int error = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_cache_entry *ce = NULL;
+ git_attr_file_entry *entry = NULL;
git_attr_file *file = NULL;
- if ((error = attr_cache_lookup(&file, &ce, repo, source, base, filename)) < 0)
+ if ((error = attr_cache_lookup(
+ &file, &entry, repo, source, base, filename)) < 0)
goto cleanup;
- /* if this is not a file backed entry, just create a new empty one */
- if (!parser) {
- if (!file && !(error = git_attr_file__new(&file, ce, source)))
- error = attr_cache_upsert(cache, file);
- }
- /* otherwise load and/or reload as needed */
- else if (!file || (error = git_attr_file__out_of_date(repo, file)) > 0) {
- if (!(error = git_attr_file__load(
- &file, repo, ce, source, parser, payload)))
+ /* if file not found or out of date, load up-to-date data and replace */
+ if (!file || (error = git_attr_file__out_of_date(repo, file)) > 0) {
+ /* decrement refcount (if file was found) b/c we will not return it */
+ git_attr_file__free(file);
+
+ if (!(error = git_attr_file__load(&file, repo, entry, source, parser)))
error = attr_cache_upsert(cache, file);
}
@@ -245,13 +244,13 @@ cleanup:
bool git_attr_cache__is_cached(
git_repository *repo,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *filename)
{
git_attr_cache *cache = git_repository_attr_cache(repo);
git_strmap *files;
khiter_t pos;
- git_attr_cache_entry *ce;
+ git_attr_file_entry *entry;
if (!(cache = git_repository_attr_cache(repo)) ||
!(files = cache->files))
@@ -261,9 +260,9 @@ bool git_attr_cache__is_cached(
if (!git_strmap_valid_index(files, pos))
return false;
- ce = git_strmap_value_at(files, pos);
+ entry = git_strmap_value_at(files, pos);
- return ce && (ce->file[source] != NULL);
+ return entry && (entry->file[source] != NULL);
}
@@ -307,14 +306,15 @@ static void attr_cache__free(git_attr_cache *cache)
unlock = (git_mutex_lock(&cache->lock) == 0);
if (cache->files != NULL) {
- git_attr_cache_entry *ce;
+ git_attr_file_entry *entry;
+ git_attr_file *file;
int i;
- git_strmap_foreach_value(cache->files, ce, {
- for (i = 0; i < GIT_ATTR_CACHE_NUM_SOURCES; ++i) {
- if (ce->file[i]) {
- GIT_REFCOUNT_OWN(ce->file[i], NULL);
- git_attr_file__free(ce->file[i]);
+ git_strmap_foreach_value(cache->files, entry, {
+ for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
+ if ((file = git__swap(entry->file[i], NULL)) != NULL) {
+ GIT_REFCOUNT_OWN(file, NULL);
+ git_attr_file__free(file);
}
}
});
@@ -345,7 +345,7 @@ static void attr_cache__free(git_attr_cache *cache)
git__free(cache);
}
-int git_attr_cache__init(git_repository *repo)
+int git_attr_cache__do_init(git_repository *repo)
{
int ret = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
diff --git a/src/attrcache.h b/src/attrcache.h
index 8e7f022b0..be0a22f5c 100644
--- a/src/attrcache.h
+++ b/src/attrcache.h
@@ -7,9 +7,8 @@
#ifndef INCLUDE_attrcache_h__
#define INCLUDE_attrcache_h__
-#include "pool.h"
+#include "attr_file.h"
#include "strmap.h"
-#include "buffer.h"
#define GIT_ATTR_CONFIG "core.attributesfile"
#define GIT_IGNORE_CONFIG "core.excludesfile"
@@ -23,55 +22,35 @@ typedef struct {
git_pool pool;
} git_attr_cache;
-extern int git_attr_cache__init(git_repository *repo);
+extern int git_attr_cache__do_init(git_repository *repo);
-typedef enum {
- GIT_ATTR_CACHE__FROM_FILE = 0,
- GIT_ATTR_CACHE__FROM_INDEX = 1,
-
- GIT_ATTR_CACHE_NUM_SOURCES = 2
-} git_attr_cache_source;
-
-typedef struct git_attr_file git_attr_file;
-typedef struct git_attr_rule git_attr_rule;
-
-typedef struct {
- git_attr_file *file[GIT_ATTR_CACHE_NUM_SOURCES];
- const char *path; /* points into fullpath */
- char fullpath[GIT_FLEX_ARRAY];
-} git_attr_cache_entry;
-
-typedef int (*git_attr_cache_parser)(
- git_repository *repo,
- git_attr_file *file,
- const char *data,
- void *payload);
+#define git_attr_cache__init(REPO) \
+ (git_repository_attr_cache(REPO) ? 0 : git_attr_cache__do_init(REPO))
/* get file - loading and reload as needed */
extern int git_attr_cache__get(
git_attr_file **file,
git_repository *repo,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *base,
const char *filename,
- git_attr_cache_parser parser,
- void *payload);
+ git_attr_file_parser parser);
extern bool git_attr_cache__is_cached(
git_repository *repo,
- git_attr_cache_source source,
+ git_attr_file_source source,
const char *path);
+extern int git_attr_cache__alloc_file_entry(
+ git_attr_file_entry **out,
+ const char *base,
+ const char *path,
+ git_pool *pool);
+
extern int git_attr_cache__insert_macro(
git_repository *repo, git_attr_rule *macro);
extern git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name);
-extern int git_attr_cache_entry__new(
- git_attr_cache_entry **out,
- const char *base,
- const char *path,
- git_pool *pool);
-
#endif
diff --git a/src/fileops.c b/src/fileops.c
index d8d819151..13b8f6a39 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -132,6 +132,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
if (read_size != (ssize_t)len) {
giterr_set(GITERR_OS, "Failed to read descriptor");
+ git_buf_free(buf);
return -1;
}
@@ -829,3 +830,16 @@ void git_futils_filestamp_set(
else
memset(target, 0, sizeof(*target));
}
+
+
+void git_futils_filestamp_set_from_stat(
+ git_futils_filestamp *stamp, struct stat *st)
+{
+ if (st) {
+ stamp->mtime = (git_time_t)st->st_mtime;
+ stamp->size = (git_off_t)st->st_size;
+ stamp->ino = (unsigned int)st->st_ino;
+ } else {
+ memset(stamp, 0, sizeof(*stamp));
+ }
+}
diff --git a/src/fileops.h b/src/fileops.h
index cfc2ce701..62227abae 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -317,4 +317,10 @@ extern int git_futils_filestamp_check(
extern void git_futils_filestamp_set(
git_futils_filestamp *tgt, const git_futils_filestamp *src);
+/**
+ * Set file stamp data from stat structure
+ */
+extern void git_futils_filestamp_set_from_stat(
+ git_futils_filestamp *stamp, struct stat *st);
+
#endif /* INCLUDE_fileops_h__ */
diff --git a/src/ignore.c b/src/ignore.c
index fbebd9ad3..deae204f8 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -1,7 +1,7 @@
#include "git2/ignore.h"
#include "common.h"
#include "ignore.h"
-#include "attr_file.h"
+#include "attrcache.h"
#include "path.h"
#include "config.h"
@@ -10,30 +10,24 @@
#define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n"
static int parse_ignore_file(
- git_repository *repo,
- git_attr_file *attrs,
- const char *data,
- void *payload)
+ git_repository *repo, git_attr_file *attrs, const char *data)
{
int error = 0;
int ignore_case = false;
const char *scan = data, *context = NULL;
git_attr_fnmatch *match = NULL;
- /* either read ignore_case from ignores structure or use repo config */
- if (payload != NULL)
- ignore_case = ((git_ignores *)payload)->ignore_case;
- else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
+ if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
giterr_clear();
/* if subdir file path, convert context for file paths */
- if (attrs->ce &&
- git_path_root(attrs->ce->path) < 0 &&
- !git__suffixcmp(attrs->ce->path, "/" GIT_IGNORE_FILE))
- context = attrs->ce->path;
+ if (attrs->entry &&
+ git_path_root(attrs->entry->path) < 0 &&
+ !git__suffixcmp(attrs->entry->path, "/" GIT_IGNORE_FILE))
+ context = attrs->entry->path;
if (git_mutex_lock(&attrs->lock) < 0) {
- giterr_set(GITERR_OS, "Failed to lock attribute file");
+ giterr_set(GITERR_OS, "Failed to lock ignore file");
return -1;
}
@@ -84,8 +78,8 @@ static int push_ignore_file(
git_attr_file *file = NULL;
error = git_attr_cache__get(
- &file, ignores->repo, GIT_ATTR_CACHE__FROM_FILE,
- base, filename, parse_ignore_file, ignores);
+ &file, ignores->repo, GIT_ATTR_FILE__FROM_FILE,
+ base, filename, parse_ignore_file);
if (error < 0)
return error;
@@ -111,14 +105,12 @@ static int get_internal_ignores(git_attr_file **out, git_repository *repo)
if ((error = git_attr_cache__init(repo)) < 0)
return error;
- /* get with NULL parser, gives existing or empty git_attr_file */
error = git_attr_cache__get(
- out, repo, GIT_ATTR_CACHE__FROM_FILE,
- NULL, GIT_IGNORE_INTERNAL, NULL, NULL);
+ out, repo, GIT_ATTR_FILE__IN_MEMORY, NULL, GIT_IGNORE_INTERNAL, NULL);
/* if internal rules list is empty, insert default rules */
if (!error && !(*out)->rules.length)
- error = parse_ignore_file(repo, *out, GIT_IGNORE_DEFAULT_RULES, NULL);
+ error = parse_ignore_file(repo, *out, GIT_IGNORE_DEFAULT_RULES);
return error;
}
@@ -199,7 +191,7 @@ int git_ignore__pop_dir(git_ignores *ign)
{
if (ign->ign_path.length > 0) {
git_attr_file *file = git_vector_last(&ign->ign_path);
- const char *start = file->ce->path, *end;
+ const char *start = file->entry->path, *end;
/* - ign->dir looks something like "/home/user/a/b/" (or "a/b/c/d/")
* - file->path looks something like "a/b/.gitignore
@@ -302,35 +294,33 @@ cleanup:
return 0;
}
-int git_ignore_add_rule(
- git_repository *repo,
- const char *rules)
+int git_ignore_add_rule(git_repository *repo, const char *rules)
{
int error;
git_attr_file *ign_internal = NULL;
- if (!(error = get_internal_ignores(&ign_internal, repo))) {
- error = parse_ignore_file(repo, ign_internal, rules, NULL);
- git_attr_file__free(ign_internal);
- }
+ if ((error = get_internal_ignores(&ign_internal, repo)) < 0)
+ return error;
+
+ error = parse_ignore_file(repo, ign_internal, rules);
+ git_attr_file__free(ign_internal);
return error;
}
-int git_ignore_clear_internal_rules(
- git_repository *repo)
+int git_ignore_clear_internal_rules(git_repository *repo)
{
int error;
git_attr_file *ign_internal;
- if (!(error = get_internal_ignores(&ign_internal, repo))) {
- if (!(error = git_attr_file__clear_rules(ign_internal, true)))
- error = parse_ignore_file(
- repo, ign_internal, GIT_IGNORE_DEFAULT_RULES, NULL);
+ if ((error = get_internal_ignores(&ign_internal, repo)) < 0)
+ return error;
- git_attr_file__free(ign_internal);
- }
+ if (!(error = git_attr_file__clear_rules(ign_internal, true)))
+ error = parse_ignore_file(
+ repo, ign_internal, GIT_IGNORE_DEFAULT_RULES);
+ git_attr_file__free(ign_internal);
return error;
}
diff --git a/tests/attr/file.c b/tests/attr/file.c
index e35957b51..1f4108c3c 100644
--- a/tests/attr/file.c
+++ b/tests/attr/file.c
@@ -13,7 +13,7 @@ void test_attr_file__simple_read(void)
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1);
rule = get_rule(0);
@@ -39,7 +39,7 @@ void test_attr_file__match_variants(void)
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10);
/* let's do a thorough check of this rule, then just verify
@@ -123,7 +123,7 @@ void test_attr_file__assign_variants(void)
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr2")));
- cl_assert_equal_s(cl_fixture("attr/attr2"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr2"), file->entry->path);
cl_assert(file->rules.length == 11);
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
@@ -188,7 +188,7 @@ void test_attr_file__check_attr_examples(void)
git_attr_assignment *assign;
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
- cl_assert_equal_s(cl_fixture("attr/attr3"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr3"), file->entry->path);
cl_assert(file->rules.length == 3);
rule = get_rule(0);
diff --git a/tests/attr/lookup.c b/tests/attr/lookup.c
index 099597efc..030ea075d 100644
--- a/tests/attr/lookup.c
+++ b/tests/attr/lookup.c
@@ -10,7 +10,7 @@ void test_attr_lookup__simple(void)
const char *value = NULL;
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL));
@@ -130,7 +130,7 @@ void test_attr_lookup__match_variants(void)
};
cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->ce->path);
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
@@ -252,7 +252,7 @@ void test_attr_lookup__from_buffer(void)
cl_git_pass(git_attr_file__new(&file, NULL, 0));
- cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz", NULL));
+ cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz"));
cl_assert(file->rules.length == 3);
diff --git a/tests/attr/repo.c b/tests/attr/repo.c
index 49cccdc5a..71dc7a5b5 100644
--- a/tests/attr/repo.c
+++ b/tests/attr/repo.c
@@ -68,9 +68,12 @@ void test_attr_repo__get_one(void)
attr_check_expected(scan->expected, scan->expected_str, scan->attr, value);
}
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes"));
}
void test_attr_repo__get_many(void)
diff --git a/tests/status/ignore.c b/tests/status/ignore.c
index d6c26a847..052a8eae8 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -54,8 +54,10 @@ void test_status_ignore__0(void)
}
/* confirm that ignore files were cached */
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
}