summaryrefslogtreecommitdiff
path: root/src/attrcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/attrcache.c')
-rw-r--r--src/attrcache.c473
1 files changed, 0 insertions, 473 deletions
diff --git a/src/attrcache.c b/src/attrcache.c
deleted file mode 100644
index 2b36b7a9c..000000000
--- a/src/attrcache.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "attrcache.h"
-
-#include "repository.h"
-#include "attr_file.h"
-#include "config.h"
-#include "sysdir.h"
-#include "ignore.h"
-
-GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache)
-{
- GIT_UNUSED(cache); /* avoid warning if threading is off */
-
- if (git_mutex_lock(&cache->lock) < 0) {
- git_error_set(GIT_ERROR_OS, "unable to get attr cache lock");
- return -1;
- }
- return 0;
-}
-
-GIT_INLINE(void) attr_cache_unlock(git_attr_cache *cache)
-{
- GIT_UNUSED(cache); /* avoid warning if threading is off */
- git_mutex_unlock(&cache->lock);
-}
-
-GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
- git_attr_cache *cache, const char *path)
-{
- return git_strmap_get(cache->files, path);
-}
-
-int git_attr_cache__alloc_file_entry(
- git_attr_file_entry **out,
- git_repository *repo,
- const char *base,
- const char *path,
- git_pool *pool)
-{
- size_t baselen = 0, pathlen = strlen(path);
- 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);
- cachesize += baselen;
-
- if (baselen && base[baselen - 1] != '/')
- cachesize++;
- }
-
- ce = git_pool_mallocz(pool, cachesize);
- GIT_ERROR_CHECK_ALLOC(ce);
-
- if (baselen) {
- memcpy(ce->fullpath, base, baselen);
-
- if (base[baselen - 1] != '/')
- ce->fullpath[baselen++] = '/';
- }
- memcpy(&ce->fullpath[baselen], path, pathlen);
-
- if (git_path_validate_workdir_with_len(repo, ce->fullpath, pathlen + baselen) < 0)
- return -1;
-
- ce->path = &ce->fullpath[baselen];
- *out = ce;
-
- return 0;
-}
-
-/* call with attrcache locked */
-static int attr_cache_make_entry(
- git_attr_file_entry **out, git_repository *repo, const char *path)
-{
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_file_entry *entry = NULL;
- int error;
-
- if ((error = git_attr_cache__alloc_file_entry(&entry, repo,
- git_repository_workdir(repo), path, &cache->pool)) < 0)
- return error;
-
- if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
- return error;
-
- *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_file_entry *entry;
- git_attr_file *old;
-
- if (attr_cache_lock(cache) < 0)
- return -1;
-
- entry = attr_cache_lookup_entry(cache, file->entry->path);
-
- GIT_REFCOUNT_OWN(file, entry);
- GIT_REFCOUNT_INC(file);
-
- /*
- * Replace the existing value if another thread has
- * created it in the meantime.
- */
- old = git_atomic_swap(entry->file[file->source.type], file);
-
- if (old) {
- GIT_REFCOUNT_OWN(old, NULL);
- git_attr_file__free(old);
- }
-
- attr_cache_unlock(cache);
- return 0;
-}
-
-static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
-{
- int error = 0;
- git_attr_file_entry *entry;
- git_attr_file *oldfile = NULL;
-
- if (!file)
- return 0;
-
- if ((error = attr_cache_lock(cache)) < 0)
- return error;
-
- if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
- oldfile = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
-
- attr_cache_unlock(cache);
-
- if (oldfile == file) {
- 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_file_entry **out_entry,
- git_repository *repo,
- git_attr_session *attr_session,
- git_attr_file_source *source)
-{
- int error = 0;
- git_buf path = GIT_BUF_INIT;
- const char *wd = git_repository_workdir(repo);
- const char *filename;
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_file_entry *entry = NULL;
- git_attr_file *file = NULL;
-
- /* join base and path as needed */
- if (source->base != NULL && git_path_root(source->filename) < 0) {
- git_buf *p = attr_session ? &attr_session->tmp : &path;
-
- if (git_buf_joinpath(p, source->base, source->filename) < 0 ||
- git_path_validate_workdir_buf(repo, p) < 0)
- return -1;
-
- filename = p->ptr;
- } else {
- filename = source->filename;
- }
-
- if (wd && !git__prefixcmp(filename, wd))
- filename += strlen(wd);
-
- /* check cache for existing entry */
- if ((error = attr_cache_lock(cache)) < 0)
- goto cleanup;
-
- entry = attr_cache_lookup_entry(cache, filename);
-
- if (!entry) {
- error = attr_cache_make_entry(&entry, repo, filename);
- } else if (entry->file[source->type] != NULL) {
- file = entry->file[source->type];
- GIT_REFCOUNT_INC(file);
- }
-
- attr_cache_unlock(cache);
-
-cleanup:
- *out_file = file;
- *out_entry = entry;
-
- git_buf_dispose(&path);
- return error;
-}
-
-int git_attr_cache__get(
- git_attr_file **out,
- git_repository *repo,
- git_attr_session *attr_session,
- git_attr_file_source *source,
- git_attr_file_parser parser,
- bool allow_macros)
-{
- int error = 0;
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_file_entry *entry = NULL;
- git_attr_file *file = NULL, *updated = NULL;
-
- if ((error = attr_cache_lookup(&file, &entry, repo, attr_session, source)) < 0)
- return error;
-
- /* load file if we don't have one or if existing one is out of date */
- if (!file ||
- (error = git_attr_file__out_of_date(repo, attr_session, file, source)) > 0)
- error = git_attr_file__load(&updated, repo, attr_session,
- entry, source, parser,
- allow_macros);
-
- /* if we loaded the file, insert into and/or update cache */
- if (updated) {
- if ((error = attr_cache_upsert(cache, updated)) < 0) {
- git_attr_file__free(updated);
- } else {
- git_attr_file__free(file); /* offset incref from lookup */
- file = updated;
- }
- }
-
- /* if file could not be loaded */
- if (error < 0) {
- /* remove existing entry */
- if (file) {
- attr_cache_remove(cache, file);
- git_attr_file__free(file); /* offset incref from lookup */
- file = NULL;
- }
- /* no error if file simply doesn't exist */
- if (error == GIT_ENOTFOUND) {
- git_error_clear();
- error = 0;
- }
- }
-
- *out = file;
- return error;
-}
-
-bool git_attr_cache__is_cached(
- git_repository *repo,
- git_attr_file_source_t source_type,
- const char *filename)
-{
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_file_entry *entry;
- git_strmap *files;
-
- if (!cache || !(files = cache->files))
- return false;
-
- if ((entry = git_strmap_get(files, filename)) == NULL)
- return false;
-
- return entry && (entry->file[source_type] != NULL);
-}
-
-
-static int attr_cache__lookup_path(
- char **out, git_config *cfg, const char *key, const char *fallback)
-{
- git_buf buf = GIT_BUF_INIT;
- int error;
- git_config_entry *entry = NULL;
-
- *out = NULL;
-
- if ((error = git_config__lookup_entry(&entry, cfg, key, false)) < 0)
- return error;
-
- if (entry) {
- const char *cfgval = entry->value;
-
- /* expand leading ~/ as needed */
- if (cfgval && cfgval[0] == '~' && cfgval[1] == '/') {
- if (! (error = git_sysdir_expand_global_file(&buf, &cfgval[2])))
- *out = git_buf_detach(&buf);
- } else if (cfgval) {
- *out = git__strdup(cfgval);
- }
- }
- else if (!git_sysdir_find_xdg_file(&buf, fallback)) {
- *out = git_buf_detach(&buf);
- }
-
- git_config_entry_free(entry);
- git_buf_dispose(&buf);
-
- return error;
-}
-
-static void attr_cache__free(git_attr_cache *cache)
-{
- bool unlock;
-
- if (!cache)
- return;
-
- unlock = (attr_cache_lock(cache) == 0);
-
- if (cache->files != NULL) {
- git_attr_file_entry *entry;
- git_attr_file *file;
- int i;
-
- git_strmap_foreach_value(cache->files, entry, {
- for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
- if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) {
- GIT_REFCOUNT_OWN(file, NULL);
- git_attr_file__free(file);
- }
- }
- });
- git_strmap_free(cache->files);
- }
-
- if (cache->macros != NULL) {
- git_attr_rule *rule;
-
- git_strmap_foreach_value(cache->macros, rule, {
- git_attr_rule__free(rule);
- });
- git_strmap_free(cache->macros);
- }
-
- git_pool_clear(&cache->pool);
-
- git__free(cache->cfg_attr_file);
- cache->cfg_attr_file = NULL;
-
- git__free(cache->cfg_excl_file);
- cache->cfg_excl_file = NULL;
-
- if (unlock)
- attr_cache_unlock(cache);
- git_mutex_free(&cache->lock);
-
- git__free(cache);
-}
-
-int git_attr_cache__init(git_repository *repo)
-{
- int ret = 0;
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_config *cfg = NULL;
-
- if (cache)
- return 0;
-
- cache = git__calloc(1, sizeof(git_attr_cache));
- GIT_ERROR_CHECK_ALLOC(cache);
-
- /* set up lock */
- if (git_mutex_init(&cache->lock) < 0) {
- git_error_set(GIT_ERROR_OS, "unable to initialize lock for attr cache");
- git__free(cache);
- return -1;
- }
-
- if ((ret = git_repository_config_snapshot(&cfg, repo)) < 0)
- goto cancel;
-
- /* cache config settings for attributes and ignores */
- ret = attr_cache__lookup_path(
- &cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG, GIT_ATTR_FILE_XDG);
- if (ret < 0)
- goto cancel;
-
- ret = attr_cache__lookup_path(
- &cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG, GIT_IGNORE_FILE_XDG);
- if (ret < 0)
- goto cancel;
-
- /* allocate hashtable for attribute and ignore file contents,
- * hashtable for attribute macros, and string pool
- */
- if ((ret = git_strmap_new(&cache->files)) < 0 ||
- (ret = git_strmap_new(&cache->macros)) < 0 ||
- (ret = git_pool_init(&cache->pool, 1)) < 0)
- goto cancel;
-
- if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL)
- goto cancel; /* raced with another thread, free this but no error */
-
- git_config_free(cfg);
-
- /* insert default macros */
- return git_attr_add_macro(repo, "binary", "-diff -merge -text -crlf");
-
-cancel:
- attr_cache__free(cache);
- git_config_free(cfg);
- return ret;
-}
-
-int git_attr_cache_flush(git_repository *repo)
-{
- git_attr_cache *cache;
-
- /* this could be done less expensively, but for now, we'll just free
- * the entire attrcache and let the next use reinitialize it...
- */
- if (repo && (cache = git_atomic_swap(repo->attrcache, NULL)) != NULL)
- attr_cache__free(cache);
-
- return 0;
-}
-
-int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
-{
- git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_rule *preexisting;
- bool locked = false;
- int error = 0;
-
- /*
- * Callers assume that if we return success, that the
- * macro will have been adopted by the attributes cache.
- * Thus, we have to free the macro here if it's not being
- * added to the cache.
- *
- * TODO: generate warning log if (macro->assigns.length == 0)
- */
- if (macro->assigns.length == 0) {
- git_attr_rule__free(macro);
- goto out;
- }
-
- if ((error = attr_cache_lock(cache)) < 0)
- goto out;
- locked = true;
-
- if ((preexisting = git_strmap_get(cache->macros, macro->match.pattern)) != NULL)
- git_attr_rule__free(preexisting);
-
- if ((error = git_strmap_set(cache->macros, macro->match.pattern, macro)) < 0)
- goto out;
-
-out:
- if (locked)
- attr_cache_unlock(cache);
- return error;
-}
-
-git_attr_rule *git_attr_cache__lookup_macro(
- git_repository *repo, const char *name)
-{
- git_strmap *macros = git_repository_attr_cache(repo)->macros;
-
- return git_strmap_get(macros, name);
-}