From: Junio C Hamano Date: Mon, 19 Sep 2016 20:47:19 +0000 (-0700) Subject: Merge branch 'mh/ref-store' X-Git-Tag: v2.11.0-rc0~143 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/4322f3848a224843a2df81055f07899ce1a1b388?ds=inline;hp=-c Merge branch 'mh/ref-store' The ref-store abstraction was introduced to the refs API so that we can plug in different backends to store references. * mh/ref-store: (38 commits) refs: implement iteration over only per-worktree refs refs: make lock generic refs: add method to rename refs refs: add methods to init refs db refs: make delete_refs() virtual refs: add method for initial ref transaction commit refs: add methods for reflog refs: add method iterator_begin files_ref_iterator_begin(): take a ref_store argument split_symref_update(): add a files_ref_store argument lock_ref_sha1_basic(): add a files_ref_store argument lock_ref_for_update(): add a files_ref_store argument commit_ref_update(): add a files_ref_store argument lock_raw_ref(): add a files_ref_store argument repack_without_refs(): add a files_ref_store argument refs: make peel_ref() virtual refs: make create_symref() virtual refs: make pack_refs() virtual refs: make verify_refname_available() virtual refs: make read_raw_ref() virtual ... --- 4322f3848a224843a2df81055f07899ce1a1b388 diff --combined builtin/init-db.c index 3a45f0bcfb,082fa9f3ca..80192f65e4 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@@ -180,13 -180,7 +180,7 @@@ static int create_default_files(const c char junk[2]; int reinit; int filemode; - - /* - * Create .git/refs/{heads,tags} - */ - safe_create_dir(git_path_buf(&buf, "refs"), 1); - safe_create_dir(git_path_buf(&buf, "refs/heads"), 1); - safe_create_dir(git_path_buf(&buf, "refs/tags"), 1); + struct strbuf err = STRBUF_INIT; /* Just look for `init.templatedir` */ git_config(git_init_db_config, NULL); @@@ -210,11 -204,18 +204,18 @@@ */ if (get_shared_repository()) { adjust_shared_perm(get_git_dir()); - adjust_shared_perm(git_path_buf(&buf, "refs")); - adjust_shared_perm(git_path_buf(&buf, "refs/heads")); - adjust_shared_perm(git_path_buf(&buf, "refs/tags")); } + /* + * We need to create a "refs" dir in any case so that older + * versions of git can tell that this is a repository. + */ + safe_create_dir(git_path("refs"), 1); + adjust_shared_perm(git_path("refs")); + + if (refs_init_db(&err)) + die("failed to set up refs db: %s", err.buf); + /* * Create the default symlink from ".git/HEAD" to the "master" * branch, if it does not exist yet. @@@ -397,16 -398,13 +398,16 @@@ int init_db(const char *template_dir, u if (!(flags & INIT_DB_QUIET)) { int len = strlen(git_dir); - /* TRANSLATORS: The first '%s' is either "Reinitialized - existing" or "Initialized empty", the second " shared" or - "", and the last '%s%s' is the verbatim directory name. */ - printf(_("%s%s Git repository in %s%s\n"), - reinit ? _("Reinitialized existing") : _("Initialized empty"), - get_shared_repository() ? _(" shared") : "", - git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + if (reinit) + printf(get_shared_repository() + ? _("Reinitialized existing shared Git repository in %s%s\n") + : _("Reinitialized existing Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + else + printf(get_shared_repository() + ? _("Initialized empty shared Git repository in %s%s\n") + : _("Initialized empty Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); } return 0; diff --combined refs.c index b4e7cac7b2,60f518e004..113e3c83bf --- a/refs.c +++ b/refs.c @@@ -9,6 -9,25 +9,25 @@@ #include "object.h" #include "tag.h" + /* + * List of all available backends + */ + static struct ref_storage_be *refs_backends = &refs_be_files; + + static struct ref_storage_be *find_ref_storage_backend(const char *name) + { + struct ref_storage_be *be; + for (be = refs_backends; be; be = be->next) + if (!strcmp(be->name, name)) + return be; + return NULL; + } + + int ref_storage_backend_exists(const char *name) + { + return find_ref_storage_backend(name) != NULL; + } + /* * How to handle various characters in refnames: * 0: An acceptable character for refs @@@ -922,7 -941,7 +941,7 @@@ char *shorten_unambiguous_ref(const cha /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1; - scanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len)); + scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len)); offset = 0; for (i = 0; i < nr_rules; i++) { @@@ -1081,20 -1100,20 +1100,20 @@@ const char *find_descendant_ref(const c return NULL; } - int rename_ref_available(const char *oldname, const char *newname) + int rename_ref_available(const char *old_refname, const char *new_refname) { struct string_list skip = STRING_LIST_INIT_NODUP; struct strbuf err = STRBUF_INIT; - int ret; + int ok; - string_list_insert(&skip, oldname); - ret = !verify_refname_available(newname, NULL, &skip, &err); - if (!ret) + string_list_insert(&skip, old_refname); + ok = !verify_refname_available(new_refname, NULL, &skip, &err); + if (!ok) error("%s", err.buf); string_list_clear(&skip, 0); strbuf_release(&err); - return ret; + return ok; } int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data) @@@ -1132,9 -1151,13 +1151,13 @@@ int head_ref(each_ref_fn fn, void *cb_d static int do_for_each_ref(const char *submodule, const char *prefix, each_ref_fn fn, int trim, int flags, void *cb_data) { + struct ref_store *refs = get_ref_store(submodule); struct ref_iterator *iter; - iter = files_ref_iterator_begin(submodule, prefix, flags); + if (!refs) + return 0; + + iter = refs->be->iterator_begin(refs, prefix, flags); iter = prefix_ref_iterator_begin(iter, prefix, trim); return do_for_each_ref_iterator(iter, fn, cb_data); @@@ -1193,8 -1216,10 +1216,10 @@@ int for_each_rawref(each_ref_fn fn, voi } /* This function needs to return a meaningful errno on failure */ - const char *resolve_ref_unsafe(const char *refname, int resolve_flags, - unsigned char *sha1, int *flags) + static const char *resolve_ref_recursively(struct ref_store *refs, + const char *refname, + int resolve_flags, + unsigned char *sha1, int *flags) { static struct strbuf sb_refname = STRBUF_INIT; int unused_flags; @@@ -1226,7 -1251,8 +1251,8 @@@ for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { unsigned int read_flags = 0; - if (read_raw_ref(refname, sha1, &sb_refname, &read_flags)) { + if (refs->be->read_raw_ref(refs, refname, + sha1, &sb_refname, &read_flags)) { *flags |= read_flags; if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING)) return NULL; @@@ -1265,3 -1291,266 +1291,266 @@@ errno = ELOOP; return NULL; } + + /* backend functions */ + int refs_init_db(struct strbuf *err) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->init_db(refs, err); + } + + const char *resolve_ref_unsafe(const char *refname, int resolve_flags, + unsigned char *sha1, int *flags) + { + return resolve_ref_recursively(get_ref_store(NULL), refname, + resolve_flags, sha1, flags); + } + + int resolve_gitlink_ref(const char *submodule, const char *refname, + unsigned char *sha1) + { + size_t len = strlen(submodule); + struct ref_store *refs; + int flags; + + while (len && submodule[len - 1] == '/') + len--; + + if (!len) + return -1; + + if (submodule[len]) { + /* We need to strip off one or more trailing slashes */ + char *stripped = xmemdupz(submodule, len); + + refs = get_ref_store(stripped); + free(stripped); + } else { + refs = get_ref_store(submodule); + } + + if (!refs) + return -1; + + if (!resolve_ref_recursively(refs, refname, 0, sha1, &flags) || + is_null_sha1(sha1)) + return -1; + return 0; + } + + /* A pointer to the ref_store for the main repository: */ + static struct ref_store *main_ref_store; + + /* A linked list of ref_stores for submodules: */ + static struct ref_store *submodule_ref_stores; + + void base_ref_store_init(struct ref_store *refs, + const struct ref_storage_be *be, + const char *submodule) + { + refs->be = be; + if (!submodule) { + if (main_ref_store) + die("BUG: main_ref_store initialized twice"); + + refs->submodule = ""; + refs->next = NULL; + main_ref_store = refs; + } else { + if (lookup_ref_store(submodule)) + die("BUG: ref_store for submodule '%s' initialized twice", + submodule); + + refs->submodule = xstrdup(submodule); + refs->next = submodule_ref_stores; + submodule_ref_stores = refs; + } + } + + struct ref_store *ref_store_init(const char *submodule) + { + const char *be_name = "files"; + struct ref_storage_be *be = find_ref_storage_backend(be_name); + + if (!be) + die("BUG: reference backend %s is unknown", be_name); + + if (!submodule || !*submodule) + return be->init(NULL); + else + return be->init(submodule); + } + + struct ref_store *lookup_ref_store(const char *submodule) + { + struct ref_store *refs; + + if (!submodule || !*submodule) + return main_ref_store; + + for (refs = submodule_ref_stores; refs; refs = refs->next) { + if (!strcmp(submodule, refs->submodule)) + return refs; + } + + return NULL; + } + + struct ref_store *get_ref_store(const char *submodule) + { + struct ref_store *refs; + + if (!submodule || !*submodule) { + refs = lookup_ref_store(NULL); + + if (!refs) + refs = ref_store_init(NULL); + } else { + refs = lookup_ref_store(submodule); + + if (!refs) { + struct strbuf submodule_sb = STRBUF_INIT; + + strbuf_addstr(&submodule_sb, submodule); + if (is_nonbare_repository_dir(&submodule_sb)) + refs = ref_store_init(submodule); + strbuf_release(&submodule_sb); + } + } + + return refs; + } + + void assert_main_repository(struct ref_store *refs, const char *caller) + { + if (*refs->submodule) + die("BUG: %s called for a submodule", caller); + } + + /* backend functions */ + int pack_refs(unsigned int flags) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->pack_refs(refs, flags); + } + + int peel_ref(const char *refname, unsigned char *sha1) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->peel_ref(refs, refname, sha1); + } + + int create_symref(const char *ref_target, const char *refs_heads_master, + const char *logmsg) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->create_symref(refs, ref_target, refs_heads_master, + logmsg); + } + + int ref_transaction_commit(struct ref_transaction *transaction, + struct strbuf *err) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->transaction_commit(refs, transaction, err); + } + + int verify_refname_available(const char *refname, + const struct string_list *extra, + const struct string_list *skip, + struct strbuf *err) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->verify_refname_available(refs, refname, extra, skip, err); + } + + int for_each_reflog(each_ref_fn fn, void *cb_data) + { + struct ref_store *refs = get_ref_store(NULL); + struct ref_iterator *iter; + + iter = refs->be->reflog_iterator_begin(refs); + + return do_for_each_ref_iterator(iter, fn, cb_data); + } + + int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, + void *cb_data) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->for_each_reflog_ent_reverse(refs, refname, + fn, cb_data); + } + + int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, + void *cb_data) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->for_each_reflog_ent(refs, refname, fn, cb_data); + } + + int reflog_exists(const char *refname) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->reflog_exists(refs, refname); + } + + int safe_create_reflog(const char *refname, int force_create, + struct strbuf *err) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->create_reflog(refs, refname, force_create, err); + } + + int delete_reflog(const char *refname) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->delete_reflog(refs, refname); + } + + int reflog_expire(const char *refname, const unsigned char *sha1, + unsigned int flags, + reflog_expiry_prepare_fn prepare_fn, + reflog_expiry_should_prune_fn should_prune_fn, + reflog_expiry_cleanup_fn cleanup_fn, + void *policy_cb_data) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->reflog_expire(refs, refname, sha1, flags, + prepare_fn, should_prune_fn, + cleanup_fn, policy_cb_data); + } + + int initial_ref_transaction_commit(struct ref_transaction *transaction, + struct strbuf *err) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->initial_transaction_commit(refs, transaction, err); + } + + int delete_refs(struct string_list *refnames, unsigned int flags) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->delete_refs(refs, refnames, flags); + } + + int rename_ref(const char *oldref, const char *newref, const char *logmsg) + { + struct ref_store *refs = get_ref_store(NULL); + + return refs->be->rename_ref(refs, oldref, newref, logmsg); + } diff --combined refs.h index 1b02043758,20fae94d7d..d42458c8c9 --- a/refs.h +++ b/refs.h @@@ -66,6 -66,8 +66,8 @@@ int ref_exists(const char *refname) int is_branch(const char *refname); + extern int refs_init_db(struct strbuf *err); + /* * If refname is a non-symbolic reference that refers to a tag object, * and the tag can be (recursively) dereferenced to a non-tag object, @@@ -77,11 -79,12 +79,12 @@@ int peel_ref(const char *refname, unsigned char *sha1); /** - * Resolve refname in the nested "gitlink" repository that is located - * at path. If the resolution is successful, return 0 and set sha1 to - * the name of the object; otherwise, return a non-zero value. + * Resolve refname in the nested "gitlink" repository in the specified + * submodule (which must be non-NULL). If the resolution is + * successful, return 0 and set sha1 to the name of the object; + * otherwise, return a non-zero value. */ - int resolve_gitlink_ref(const char *path, const char *refname, + int resolve_gitlink_ref(const char *submodule, const char *refname, unsigned char *sha1); /* @@@ -360,7 -363,7 +363,7 @@@ struct ref_transaction *ref_transaction * msg -- a message describing the change (for the reflog). * * err -- a strbuf for receiving a description of any error that - * might have occured. + * might have occurred. * * The functions make internal copies of refname and msg, so the * caller retains ownership of these parameters. @@@ -544,4 -547,6 +547,6 @@@ int reflog_expire(const char *refname, reflog_expiry_cleanup_fn cleanup_fn, void *policy_cb_data); + int ref_storage_backend_exists(const char *name); + #endif /* REFS_H */ diff --combined refs/files-backend.c index 1f34b444af,47710fcf28..0709f60b8e --- a/refs/files-backend.c +++ b/refs/files-backend.c @@@ -39,7 -39,7 +39,7 @@@ struct ref_value struct object_id peeled; }; - struct ref_cache; + struct files_ref_store; /* * Information used (along with the information in ref_entry) to @@@ -78,8 -78,8 +78,8 @@@ struct ref_dir */ int sorted; - /* A pointer to the ref_cache that contains this ref_dir. */ - struct ref_cache *ref_cache; + /* A pointer to the files_ref_store that contains this ref_dir. */ + struct files_ref_store *ref_store; struct ref_entry **entries; }; @@@ -161,7 -161,7 +161,7 @@@ struct ref_entry static void read_loose_refs(const char *dirname, struct ref_dir *dir); static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len); - static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache, + static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store, const char *dirname, size_t len, int incomplete); static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry); @@@ -183,7 -183,7 +183,7 @@@ static struct ref_dir *get_ref_dir(stru int pos = search_ref_dir(dir, "refs/bisect/", 12); if (pos < 0) { struct ref_entry *child_entry; - child_entry = create_dir_entry(dir->ref_cache, + child_entry = create_dir_entry(dir->ref_store, "refs/bisect/", 12, 1); add_entry_to_dir(dir, child_entry); @@@ -261,13 -261,13 +261,13 @@@ static void clear_ref_dir(struct ref_di * dirname is the name of the directory with a trailing slash (e.g., * "refs/heads/") or "" for the top-level directory. */ - static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache, + static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store, const char *dirname, size_t len, int incomplete) { struct ref_entry *direntry; FLEX_ALLOC_MEM(direntry, name, dirname, len); - direntry->u.subdir.ref_cache = ref_cache; + direntry->u.subdir.ref_store = ref_store; direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0); return direntry; } @@@ -343,7 -343,7 +343,7 @@@ static struct ref_dir *search_for_subdi * therefore, create an empty record for it but mark * the record complete. */ - entry = create_dir_entry(dir->ref_cache, subdirname, len, 0); + entry = create_dir_entry(dir->ref_store, subdirname, len, 0); add_entry_to_dir(dir, entry); } else { entry = dir->entries[entry_index]; @@@ -887,9 -887,9 +887,9 @@@ struct packed_ref_cache /* * Count of references to the data structure in this instance, - * including the pointer from ref_cache::packed if any. The - * data will not be freed as long as the reference count is - * nonzero. + * including the pointer from files_ref_store::packed if any. + * The data will not be freed as long as the reference count + * is nonzero. */ unsigned int referrers; @@@ -910,17 -910,11 +910,11 @@@ * Future: need to be in "struct repository" * when doing a full libification. */ - static struct ref_cache { - struct ref_cache *next; + struct files_ref_store { + struct ref_store base; struct ref_entry *loose; struct packed_ref_cache *packed; - /* - * The submodule name, or "" for the main repo. We allocate - * length 1 rather than FLEX_ARRAY so that the main ref_cache - * is initialized correctly. - */ - char name[1]; - } ref_cache, *submodule_ref_caches; + }; /* Lock used for the main packed-refs file: */ static struct lock_file packlock; @@@ -949,7 -943,7 +943,7 @@@ static int release_packed_ref_cache(str } } - static void clear_packed_ref_cache(struct ref_cache *refs) + static void clear_packed_ref_cache(struct files_ref_store *refs) { if (refs->packed) { struct packed_ref_cache *packed_refs = refs->packed; @@@ -961,7 -955,7 +955,7 @@@ } } - static void clear_loose_ref_cache(struct ref_cache *refs) + static void clear_loose_ref_cache(struct files_ref_store *refs) { if (refs->loose) { free_ref_entry(refs->loose); @@@ -973,53 -967,34 +967,34 @@@ * Create a new submodule ref cache and add it to the internal * set of caches. */ - static struct ref_cache *create_ref_cache(const char *submodule) - { - struct ref_cache *refs; - if (!submodule) - submodule = ""; - FLEX_ALLOC_STR(refs, name, submodule); - refs->next = submodule_ref_caches; - submodule_ref_caches = refs; - return refs; - } - - static struct ref_cache *lookup_ref_cache(const char *submodule) + static struct ref_store *files_ref_store_create(const char *submodule) { - struct ref_cache *refs; + struct files_ref_store *refs = xcalloc(1, sizeof(*refs)); + struct ref_store *ref_store = (struct ref_store *)refs; - if (!submodule || !*submodule) - return &ref_cache; + base_ref_store_init(ref_store, &refs_be_files, submodule); - for (refs = submodule_ref_caches; refs; refs = refs->next) - if (!strcmp(submodule, refs->name)) - return refs; - return NULL; + return ref_store; } /* - * Return a pointer to a ref_cache for the specified submodule. For - * the main repository, use submodule==NULL; such a call cannot fail. - * For a submodule, the submodule must exist and be a nonbare - * repository, otherwise return NULL. - * - * The returned structure will be allocated and initialized but not - * necessarily populated; it should not be freed. + * Downcast ref_store to files_ref_store. Die if ref_store is not a + * files_ref_store. If submodule_allowed is not true, then also die if + * files_ref_store is for a submodule (i.e., not for the main + * repository). caller is used in any necessary error messages. */ - static struct ref_cache *get_ref_cache(const char *submodule) + static struct files_ref_store *files_downcast( + struct ref_store *ref_store, int submodule_allowed, + const char *caller) { - struct ref_cache *refs = lookup_ref_cache(submodule); - - if (!refs) { - struct strbuf submodule_sb = STRBUF_INIT; + if (ref_store->be != &refs_be_files) + die("BUG: ref_store is type \"%s\" not \"files\" in %s", + ref_store->be->name, caller); - strbuf_addstr(&submodule_sb, submodule); - if (is_nonbare_repository_dir(&submodule_sb)) - refs = create_ref_cache(submodule); - strbuf_release(&submodule_sb); - } + if (!submodule_allowed) + assert_main_repository(ref_store, caller); - return refs; + return (struct files_ref_store *)ref_store; } /* The length of a peeled reference line in packed-refs, including EOL: */ @@@ -1151,15 -1126,16 +1126,16 @@@ static void read_packed_refs(FILE *f, s } /* - * Get the packed_ref_cache for the specified ref_cache, creating it - * if necessary. + * Get the packed_ref_cache for the specified files_ref_store, + * creating it if necessary. */ - static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs) + static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs) { char *packed_refs_file; - if (*refs->name) - packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs"); + if (*refs->base.submodule) + packed_refs_file = git_pathdup_submodule(refs->base.submodule, + "packed-refs"); else packed_refs_file = git_pathdup("packed-refs"); @@@ -1189,7 -1165,7 +1165,7 @@@ static struct ref_dir *get_packed_ref_d return get_ref_dir(packed_ref_cache->root); } - static struct ref_dir *get_packed_refs(struct ref_cache *refs) + static struct ref_dir *get_packed_refs(struct files_ref_store *refs) { return get_packed_ref_dir(get_packed_ref_cache(refs)); } @@@ -1200,10 -1176,10 +1176,10 @@@ * lock_packed_refs()). To actually write the packed-refs file, call * commit_packed_refs(). */ - static void add_packed_ref(const char *refname, const unsigned char *sha1) + static void add_packed_ref(struct files_ref_store *refs, + const char *refname, const unsigned char *sha1) { - struct packed_ref_cache *packed_ref_cache = - get_packed_ref_cache(&ref_cache); + struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs); if (!packed_ref_cache->lock) die("internal error: packed refs not locked"); @@@ -1218,26 -1194,20 +1194,26 @@@ */ static void read_loose_refs(const char *dirname, struct ref_dir *dir) { - struct ref_cache *refs = dir->ref_cache; + struct files_ref_store *refs = dir->ref_store; DIR *d; struct dirent *de; int dirnamelen = strlen(dirname); struct strbuf refname; struct strbuf path = STRBUF_INIT; size_t path_baselen; + int err = 0; - if (*refs->name) - err = strbuf_git_path_submodule(&path, refs->name, "%s", dirname); + if (*refs->base.submodule) - strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname); ++ err = strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname); else strbuf_git_path(&path, "%s", dirname); path_baselen = path.len; + if (err) { + strbuf_release(&path); + return; + } + d = opendir(path.buf); if (!d) { strbuf_release(&path); @@@ -1268,10 -1238,10 +1244,10 @@@ } else { int read_ok; - if (*refs->name) { + if (*refs->base.submodule) { hashclr(sha1); flag = 0; - read_ok = !resolve_gitlink_ref(refs->name, + read_ok = !resolve_gitlink_ref(refs->base.submodule, refname.buf, sha1); } else { read_ok = !read_ref_full(refname.buf, @@@ -1312,7 -1282,7 +1288,7 @@@ closedir(d); } - static struct ref_dir *get_loose_refs(struct ref_cache *refs) + static struct ref_dir *get_loose_refs(struct files_ref_store *refs) { if (!refs->loose) { /* @@@ -1330,105 -1300,22 +1306,22 @@@ return get_ref_dir(refs->loose); } - #define MAXREFLEN (1024) - - /* - * Called by resolve_gitlink_ref_recursive() after it failed to read - * from the loose refs in ref_cache refs. Find in the - * packed-refs file for the submodule. - */ - static int resolve_gitlink_packed_ref(struct ref_cache *refs, - const char *refname, unsigned char *sha1) - { - struct ref_entry *ref; - struct ref_dir *dir = get_packed_refs(refs); - - ref = find_ref(dir, refname); - if (ref == NULL) - return -1; - - hashcpy(sha1, ref->u.value.oid.hash); - return 0; - } - - static int resolve_gitlink_ref_recursive(struct ref_cache *refs, - const char *refname, unsigned char *sha1, - int recursion) - { - int fd, len; - char buffer[128], *p; - char *path; - - if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN) - return -1; - path = *refs->name - ? git_pathdup_submodule(refs->name, "%s", refname) - : git_pathdup("%s", refname); - fd = open(path, O_RDONLY); - free(path); - if (fd < 0) - return resolve_gitlink_packed_ref(refs, refname, sha1); - - len = read(fd, buffer, sizeof(buffer)-1); - close(fd); - if (len < 0) - return -1; - while (len && isspace(buffer[len-1])) - len--; - buffer[len] = 0; - - /* Was it a detached head or an old-fashioned symlink? */ - if (!get_sha1_hex(buffer, sha1)) - return 0; - - /* Symref? */ - if (strncmp(buffer, "ref:", 4)) - return -1; - p = buffer + 4; - while (isspace(*p)) - p++; - - return resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1); - } - - int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1) - { - int len = strlen(path), retval; - struct strbuf submodule = STRBUF_INIT; - struct ref_cache *refs; - - while (len && path[len-1] == '/') - len--; - if (!len) - return -1; - - strbuf_add(&submodule, path, len); - refs = get_ref_cache(submodule.buf); - if (!refs) { - strbuf_release(&submodule); - return -1; - } - strbuf_release(&submodule); - - retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0); - return retval; - } - /* * Return the ref_entry for the given refname from the packed * references. If it does not exist, return NULL. */ - static struct ref_entry *get_packed_ref(const char *refname) + static struct ref_entry *get_packed_ref(struct files_ref_store *refs, + const char *refname) { - return find_ref(get_packed_refs(&ref_cache), refname); + return find_ref(get_packed_refs(refs), refname); } /* * A loose ref file doesn't exist; check for a packed ref. */ - static int resolve_missing_loose_ref(const char *refname, - unsigned char *sha1, - unsigned int *flags) + static int resolve_packed_ref(struct files_ref_store *refs, + const char *refname, + unsigned char *sha1, unsigned int *flags) { struct ref_entry *entry; @@@ -1436,7 -1323,7 +1329,7 @@@ * The loose reference file does not exist; check for a packed * reference. */ - entry = get_packed_ref(refname); + entry = get_packed_ref(refs, refname); if (entry) { hashcpy(sha1, entry->u.value.oid.hash); *flags |= REF_ISPACKED; @@@ -1446,9 -1333,12 +1339,12 @@@ return -1; } - int read_raw_ref(const char *refname, unsigned char *sha1, - struct strbuf *referent, unsigned int *type) + static int files_read_raw_ref(struct ref_store *ref_store, + const char *refname, unsigned char *sha1, + struct strbuf *referent, unsigned int *type) { + struct files_ref_store *refs = + files_downcast(ref_store, 1, "read_raw_ref"); struct strbuf sb_contents = STRBUF_INIT; struct strbuf sb_path = STRBUF_INIT; const char *path; @@@ -1460,7 -1350,12 +1356,12 @@@ *type = 0; strbuf_reset(&sb_path); - strbuf_git_path(&sb_path, "%s", refname); + + if (*refs->base.submodule) + strbuf_git_path_submodule(&sb_path, refs->base.submodule, "%s", refname); + else + strbuf_git_path(&sb_path, "%s", refname); + path = sb_path.buf; stat_ref: @@@ -1477,7 -1372,7 +1378,7 @@@ if (lstat(path, &st) < 0) { if (errno != ENOENT) goto out; - if (resolve_missing_loose_ref(refname, sha1, type)) { + if (resolve_packed_ref(refs, refname, sha1, type)) { errno = ENOENT; goto out; } @@@ -1511,7 -1406,7 +1412,7 @@@ * ref is supposed to be, there could still be a * packed ref: */ - if (resolve_missing_loose_ref(refname, sha1, type)) { + if (resolve_packed_ref(refs, refname, sha1, type)) { errno = EISDIR; goto out; } @@@ -1612,7 -1507,8 +1513,8 @@@ static void unlock_ref(struct ref_lock * avoided, namely if we were successfully able to read the ref * - Generate informative error messages in the case of failure */ - static int lock_raw_ref(const char *refname, int mustexist, + static int lock_raw_ref(struct files_ref_store *refs, + const char *refname, int mustexist, const struct string_list *extras, const struct string_list *skip, struct ref_lock **lock_p, @@@ -1626,6 -1522,8 +1528,8 @@@ int ret = TRANSACTION_GENERIC_ERROR; assert(err); + assert_main_repository(&refs->base, "lock_raw_ref"); + *type = 0; /* First lock the file so it can't change out from under us. */ @@@ -1709,7 -1607,8 +1613,8 @@@ retry * fear that its value will change. */ - if (read_raw_ref(refname, lock->old_oid.hash, referent, type)) { + if (files_read_raw_ref(&refs->base, refname, + lock->old_oid.hash, referent, type)) { if (errno == ENOENT) { if (mustexist) { /* Garden variety missing reference. */ @@@ -1752,7 -1651,7 +1657,7 @@@ REMOVE_DIR_EMPTY_ONLY)) { if (verify_refname_available_dir( refname, extras, skip, - get_loose_refs(&ref_cache), + get_loose_refs(refs), err)) { /* * The error message set by @@@ -1791,7 -1690,7 +1696,7 @@@ */ if (verify_refname_available_dir( refname, extras, skip, - get_packed_refs(&ref_cache), + get_packed_refs(refs), err)) { goto error_return; } @@@ -1844,8 -1743,10 +1749,10 @@@ static enum peel_status peel_entry(stru return status; } - int peel_ref(const char *refname, unsigned char *sha1) + static int files_peel_ref(struct ref_store *ref_store, + const char *refname, unsigned char *sha1) { + struct files_ref_store *refs = files_downcast(ref_store, 0, "peel_ref"); int flag; unsigned char base[20]; @@@ -1870,7 -1771,7 +1777,7 @@@ * have REF_KNOWS_PEELED. */ if (flag & REF_ISPACKED) { - struct ref_entry *r = get_packed_ref(refname); + struct ref_entry *r = get_packed_ref(refs, refname); if (r) { if (peel_entry(r, 0)) return -1; @@@ -1897,6 -1798,10 +1804,10 @@@ static int files_ref_iterator_advance(s int ok; while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) { + if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY && + ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE) + continue; + if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) && !ref_resolves_to_object(iter->iter0->refname, iter->iter0->oid, @@@ -1945,11 -1850,12 +1856,12 @@@ static struct ref_iterator_vtable files files_ref_iterator_abort }; - struct ref_iterator *files_ref_iterator_begin( - const char *submodule, + static struct ref_iterator *files_ref_iterator_begin( + struct ref_store *ref_store, const char *prefix, unsigned int flags) { - struct ref_cache *refs = get_ref_cache(submodule); + struct files_ref_store *refs = + files_downcast(ref_store, 1, "ref_iterator_begin"); struct ref_dir *loose_dir, *packed_dir; struct ref_iterator *loose_iter, *packed_iter; struct files_ref_iterator *iter; @@@ -2036,14 -1942,14 +1948,14 @@@ static int verify_lock(struct ref_lock errno = save_errno; return -1; } else { - hashclr(lock->old_oid.hash); + oidclr(&lock->old_oid); return 0; } } if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) { strbuf_addf(err, "ref '%s' is at %s but expected %s", lock->ref_name, - sha1_to_hex(lock->old_oid.hash), + oid_to_hex(&lock->old_oid), sha1_to_hex(old_sha1)); errno = EBUSY; return -1; @@@ -2065,7 -1971,8 +1977,8 @@@ static int remove_empty_directories(str * Locks a ref returning the lock on success and NULL on failure. * On failure errno is set to something meaningful. */ - static struct ref_lock *lock_ref_sha1_basic(const char *refname, + static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs, + const char *refname, const unsigned char *old_sha1, const struct string_list *extras, const struct string_list *skip, @@@ -2081,6 -1988,7 +1994,7 @@@ int attempts_remaining = 3; int resolved; + assert_main_repository(&refs->base, "lock_ref_sha1_basic"); assert(err); lock = xcalloc(1, sizeof(struct ref_lock)); @@@ -2102,8 -2010,9 +2016,9 @@@ */ if (remove_empty_directories(&ref_file)) { last_errno = errno; - if (!verify_refname_available_dir(refname, extras, skip, - get_loose_refs(&ref_cache), err)) + if (!verify_refname_available_dir( + refname, extras, skip, + get_loose_refs(refs), err)) strbuf_addf(err, "there are still refs under '%s'", refname); goto error_return; @@@ -2114,8 -2023,9 +2029,9 @@@ if (!resolved) { last_errno = errno; if (last_errno != ENOTDIR || - !verify_refname_available_dir(refname, extras, skip, - get_loose_refs(&ref_cache), err)) + !verify_refname_available_dir( + refname, extras, skip, + get_loose_refs(refs), err)) strbuf_addf(err, "unable to resolve reference '%s': %s", refname, strerror(last_errno)); @@@ -2130,7 -2040,8 +2046,8 @@@ */ if (is_null_oid(&lock->old_oid) && verify_refname_available_dir(refname, extras, skip, - get_packed_refs(&ref_cache), err)) { + get_packed_refs(refs), + err)) { last_errno = ENOTDIR; goto error_return; } @@@ -2217,13 -2128,14 +2134,14 @@@ static int write_packed_entry_fn(struc * hold_lock_file_for_update(). Return 0 on success. On errors, set * errno appropriately and return a nonzero value. */ - static int lock_packed_refs(int flags) + static int lock_packed_refs(struct files_ref_store *refs, int flags) { static int timeout_configured = 0; static int timeout_value = 1000; - struct packed_ref_cache *packed_ref_cache; + assert_main_repository(&refs->base, "lock_packed_refs"); + if (!timeout_configured) { git_config_get_int("core.packedrefstimeout", &timeout_value); timeout_configured = 1; @@@ -2239,7 -2151,7 +2157,7 @@@ * this will automatically invalidate the cache and re-read * the packed-refs file. */ - packed_ref_cache = get_packed_ref_cache(&ref_cache); + packed_ref_cache = get_packed_ref_cache(refs); packed_ref_cache->lock = &packlock; /* Increment the reference count to prevent it from being freed: */ acquire_packed_ref_cache(packed_ref_cache); @@@ -2252,14 -2164,16 +2170,16 @@@ * lock_packed_refs()). Return zero on success. On errors, set errno * and return a nonzero value */ - static int commit_packed_refs(void) + static int commit_packed_refs(struct files_ref_store *refs) { struct packed_ref_cache *packed_ref_cache = - get_packed_ref_cache(&ref_cache); + get_packed_ref_cache(refs); int error = 0; int save_errno = 0; FILE *out; + assert_main_repository(&refs->base, "commit_packed_refs"); + if (!packed_ref_cache->lock) die("internal error: packed-refs not locked"); @@@ -2286,17 -2200,19 +2206,19 @@@ * in-memory packed reference cache. (The packed-refs file will be * read anew if it is needed again after this function is called.) */ - static void rollback_packed_refs(void) + static void rollback_packed_refs(struct files_ref_store *refs) { struct packed_ref_cache *packed_ref_cache = - get_packed_ref_cache(&ref_cache); + get_packed_ref_cache(refs); + + assert_main_repository(&refs->base, "rollback_packed_refs"); if (!packed_ref_cache->lock) die("internal error: packed-refs not locked"); rollback_lock_file(packed_ref_cache->lock); packed_ref_cache->lock = NULL; release_packed_ref_cache(packed_ref_cache); - clear_packed_ref_cache(&ref_cache); + clear_packed_ref_cache(refs); } struct ref_to_prune { @@@ -2427,20 -2343,22 +2349,22 @@@ static void prune_refs(struct ref_to_pr } } - int pack_refs(unsigned int flags) + static int files_pack_refs(struct ref_store *ref_store, unsigned int flags) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "pack_refs"); struct pack_refs_cb_data cbdata; memset(&cbdata, 0, sizeof(cbdata)); cbdata.flags = flags; - lock_packed_refs(LOCK_DIE_ON_ERROR); - cbdata.packed_refs = get_packed_refs(&ref_cache); + lock_packed_refs(refs, LOCK_DIE_ON_ERROR); + cbdata.packed_refs = get_packed_refs(refs); - do_for_each_entry_in_dir(get_loose_refs(&ref_cache), 0, + do_for_each_entry_in_dir(get_loose_refs(refs), 0, pack_if_possible_fn, &cbdata); - if (commit_packed_refs()) + if (commit_packed_refs(refs)) die_errno("unable to overwrite old ref-pack file"); prune_refs(cbdata.ref_to_prune); @@@ -2454,17 -2372,19 +2378,19 @@@ * * The refs in 'refnames' needn't be sorted. `err` must not be NULL. */ - static int repack_without_refs(struct string_list *refnames, struct strbuf *err) + static int repack_without_refs(struct files_ref_store *refs, + struct string_list *refnames, struct strbuf *err) { struct ref_dir *packed; struct string_list_item *refname; int ret, needs_repacking = 0, removed = 0; + assert_main_repository(&refs->base, "repack_without_refs"); assert(err); /* Look for a packed ref */ for_each_string_list_item(refname, refnames) { - if (get_packed_ref(refname->string)) { + if (get_packed_ref(refs, refname->string)) { needs_repacking = 1; break; } @@@ -2474,11 -2394,11 +2400,11 @@@ if (!needs_repacking) return 0; /* no refname exists in packed refs */ - if (lock_packed_refs(0)) { + if (lock_packed_refs(refs, 0)) { unable_to_lock_message(git_path("packed-refs"), errno, err); return -1; } - packed = get_packed_refs(&ref_cache); + packed = get_packed_refs(refs); /* Remove refnames from the cache */ for_each_string_list_item(refname, refnames) @@@ -2489,12 -2409,12 +2415,12 @@@ * All packed entries disappeared while we were * acquiring the lock. */ - rollback_packed_refs(); + rollback_packed_refs(refs); return 0; } /* Write what remains */ - ret = commit_packed_refs(); + ret = commit_packed_refs(refs); if (ret) strbuf_addf(err, "unable to overwrite old ref-pack file: %s", strerror(errno)); @@@ -2519,15 -2439,18 +2445,18 @@@ static int delete_ref_loose(struct ref_ return 0; } - int delete_refs(struct string_list *refnames, unsigned int flags) + static int files_delete_refs(struct ref_store *ref_store, + struct string_list *refnames, unsigned int flags) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "delete_refs"); struct strbuf err = STRBUF_INIT; int i, result = 0; if (!refnames->nr) return 0; - result = repack_without_refs(refnames, &err); + result = repack_without_refs(refs, refnames, &err); if (result) { /* * If we failed to rewrite the packed-refs file, then @@@ -2618,13 -2541,16 +2547,16 @@@ out return ret; } - int verify_refname_available(const char *newname, - const struct string_list *extras, - const struct string_list *skip, - struct strbuf *err) + static int files_verify_refname_available(struct ref_store *ref_store, + const char *newname, + const struct string_list *extras, + const struct string_list *skip, + struct strbuf *err) { - struct ref_dir *packed_refs = get_packed_refs(&ref_cache); - struct ref_dir *loose_refs = get_loose_refs(&ref_cache); + struct files_ref_store *refs = + files_downcast(ref_store, 1, "verify_refname_available"); + struct ref_dir *packed_refs = get_packed_refs(refs); + struct ref_dir *loose_refs = get_loose_refs(refs); if (verify_refname_available_dir(newname, extras, skip, packed_refs, err) || @@@ -2637,12 -2563,17 +2569,17 @@@ static int write_ref_to_lockfile(struct ref_lock *lock, const unsigned char *sha1, struct strbuf *err); - static int commit_ref_update(struct ref_lock *lock, + static int commit_ref_update(struct files_ref_store *refs, + struct ref_lock *lock, const unsigned char *sha1, const char *logmsg, struct strbuf *err); - int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg) + static int files_rename_ref(struct ref_store *ref_store, + const char *oldrefname, const char *newrefname, + const char *logmsg) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "rename_ref"); unsigned char sha1[20], orig_sha1[20]; int flag = 0, logmoved = 0; struct ref_lock *lock; @@@ -2705,8 -2636,8 +2642,8 @@@ logmoved = log; - lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF, - NULL, &err); + lock = lock_ref_sha1_basic(refs, newrefname, NULL, NULL, NULL, + REF_NODEREF, NULL, &err); if (!lock) { error("unable to rename '%s' to '%s': %s", oldrefname, newrefname, err.buf); strbuf_release(&err); @@@ -2715,7 -2646,7 +2652,7 @@@ hashcpy(lock->old_oid.hash, orig_sha1); if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(lock, orig_sha1, logmsg, &err)) { + commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) { error("unable to write current sha1 into %s: %s", newrefname, err.buf); strbuf_release(&err); goto rollback; @@@ -2724,8 -2655,8 +2661,8 @@@ return 0; rollback: - lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF, - NULL, &err); + lock = lock_ref_sha1_basic(refs, oldrefname, NULL, NULL, NULL, + REF_NODEREF, NULL, &err); if (!lock) { error("unable to lock %s for rollback: %s", oldrefname, err.buf); strbuf_release(&err); @@@ -2735,7 -2666,7 +2672,7 @@@ flag = log_all_ref_updates; log_all_ref_updates = 0; if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(lock, orig_sha1, NULL, &err)) { + commit_ref_update(refs, lock, orig_sha1, NULL, &err)) { error("unable to write current sha1 into %s: %s", oldrefname, err.buf); strbuf_release(&err); } @@@ -2838,11 -2769,16 +2775,16 @@@ static int log_ref_setup(const char *re } - int safe_create_reflog(const char *refname, int force_create, struct strbuf *err) + static int files_create_reflog(struct ref_store *ref_store, + const char *refname, int force_create, + struct strbuf *err) { int ret; struct strbuf sb = STRBUF_INIT; + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "create_reflog"); + ret = log_ref_setup(refname, &sb, err, force_create); strbuf_release(&sb); return ret; @@@ -2971,11 -2907,14 +2913,14 @@@ static int write_ref_to_lockfile(struc * to the loose reference lockfile. Also update the reflogs if * necessary, using the specified lockmsg (which can be NULL). */ - static int commit_ref_update(struct ref_lock *lock, + static int commit_ref_update(struct files_ref_store *refs, + struct ref_lock *lock, const unsigned char *sha1, const char *logmsg, struct strbuf *err) { - clear_loose_ref_cache(&ref_cache); + assert_main_repository(&refs->base, "commit_ref_update"); + + clear_loose_ref_cache(refs); if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) { char *old_msg = strbuf_detach(err, NULL); strbuf_addf(err, "cannot update the ref '%s': %s", @@@ -3074,13 -3013,18 +3019,18 @@@ static int create_symref_locked(struct return 0; } - int create_symref(const char *refname, const char *target, const char *logmsg) + static int files_create_symref(struct ref_store *ref_store, + const char *refname, const char *target, + const char *logmsg) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "create_symref"); struct strbuf err = STRBUF_INIT; struct ref_lock *lock; int ret; - lock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL, + lock = lock_ref_sha1_basic(refs, refname, NULL, + NULL, NULL, REF_NODEREF, NULL, &err); if (!lock) { error("%s", err.buf); @@@ -3128,16 -3072,24 +3078,24 @@@ int set_worktree_head_symref(const cha return ret; } - int reflog_exists(const char *refname) + static int files_reflog_exists(struct ref_store *ref_store, + const char *refname) { struct stat st; + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "reflog_exists"); + return !lstat(git_path("logs/%s", refname), &st) && S_ISREG(st.st_mode); } - int delete_reflog(const char *refname) + static int files_delete_reflog(struct ref_store *ref_store, + const char *refname) { + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "delete_reflog"); + return remove_path(git_path("logs/%s", refname)); } @@@ -3180,13 -3132,19 +3138,19 @@@ static char *find_beginning_of_line(cha return scan; } - int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data) + static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store, + const char *refname, + each_reflog_ent_fn fn, + void *cb_data) { struct strbuf sb = STRBUF_INIT; FILE *logfp; long pos; int ret = 0, at_tail = 1; + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "for_each_reflog_ent_reverse"); + logfp = fopen(git_path("logs/%s", refname), "r"); if (!logfp) return -1; @@@ -3282,12 -3240,17 +3246,17 @@@ return ret; } - int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data) + static int files_for_each_reflog_ent(struct ref_store *ref_store, + const char *refname, + each_reflog_ent_fn fn, void *cb_data) { FILE *logfp; struct strbuf sb = STRBUF_INIT; int ret = 0; + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "for_each_reflog_ent"); + logfp = fopen(git_path("logs/%s", refname), "r"); if (!logfp) return -1; @@@ -3366,22 -3329,19 +3335,19 @@@ static struct ref_iterator_vtable files files_reflog_iterator_abort }; - struct ref_iterator *files_reflog_iterator_begin(void) + static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store) { struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter)); struct ref_iterator *ref_iterator = &iter->base; + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "reflog_iterator_begin"); + base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable); iter->dir_iterator = dir_iterator_begin(git_path("logs")); return ref_iterator; } - int for_each_reflog(each_ref_fn fn, void *cb_data) - { - return do_for_each_ref_iterator(files_reflog_iterator_begin(), - fn, cb_data); - } - static int ref_update_reject_duplicates(struct string_list *refnames, struct strbuf *err) { @@@ -3454,7 -3414,8 +3420,8 @@@ static int split_head_update(struct ref * Note that the new update will itself be subject to splitting when * the iteration gets to it. */ - static int split_symref_update(struct ref_update *update, + static int split_symref_update(struct files_ref_store *refs, + struct ref_update *update, const char *referent, struct ref_transaction *transaction, struct string_list *affected_refnames, @@@ -3523,38 -3484,6 +3490,38 @@@ static const char *original_update_refn return update->refname; } +/* + * Check whether the REF_HAVE_OLD and old_oid values stored in update + * are consistent with oid, which is the reference's current value. If + * everything is OK, return 0; otherwise, write an error message to + * err and return -1. + */ +static int check_old_oid(struct ref_update *update, struct object_id *oid, + struct strbuf *err) +{ + if (!(update->flags & REF_HAVE_OLD) || + !hashcmp(oid->hash, update->old_sha1)) + return 0; + + if (is_null_sha1(update->old_sha1)) + strbuf_addf(err, "cannot lock ref '%s': " + "reference already exists", + original_update_refname(update)); + else if (is_null_oid(oid)) + strbuf_addf(err, "cannot lock ref '%s': " + "reference is missing but expected %s", + original_update_refname(update), + sha1_to_hex(update->old_sha1)); + else + strbuf_addf(err, "cannot lock ref '%s': " + "is at %s but expected %s", + original_update_refname(update), + oid_to_hex(oid), + sha1_to_hex(update->old_sha1)); + + return -1; +} + /* * Prepare for carrying out update: * - Lock the reference referred to by update. @@@ -3568,7 -3497,8 +3535,8 @@@ * - If it is an update of head_ref, add a corresponding REF_LOG_ONLY * update of HEAD. */ - static int lock_ref_for_update(struct ref_update *update, + static int lock_ref_for_update(struct files_ref_store *refs, + struct ref_update *update, struct ref_transaction *transaction, const char *head_ref, struct string_list *affected_refnames, @@@ -3580,6 -3510,8 +3548,8 @@@ int ret; struct ref_lock *lock; + assert_main_repository(&refs->base, "lock_ref_for_update"); + if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) update->flags |= REF_DELETING; @@@ -3590,22 -3522,21 +3560,21 @@@ return ret; } - ret = lock_raw_ref(update->refname, mustexist, + ret = lock_raw_ref(refs, update->refname, mustexist, affected_refnames, NULL, - &update->lock, &referent, + &lock, &referent, &update->type, err); - if (ret) { char *reason; reason = strbuf_detach(err, NULL); strbuf_addf(err, "cannot lock ref '%s': %s", - update->refname, reason); + original_update_refname(update), reason); free(reason); return ret; } - lock = update->lock; + update->backend_data = lock; if (update->type & REF_ISSYMREF) { if (update->flags & REF_NODEREF) { @@@ -3614,17 -3545,28 +3583,17 @@@ * the transaction, so we have to read it here * to record and possibly check old_sha1: */ - if (read_ref_full(update->refname, - mustexist ? RESOLVE_REF_READING : 0, + if (read_ref_full(referent.buf, 0, lock->old_oid.hash, NULL)) { if (update->flags & REF_HAVE_OLD) { strbuf_addf(err, "cannot lock ref '%s': " - "can't resolve old value", - update->refname); - return TRANSACTION_GENERIC_ERROR; - } else { - hashclr(lock->old_oid.hash); + "error reading reference", + original_update_refname(update)); + return -1; } - } - if ((update->flags & REF_HAVE_OLD) && - hashcmp(lock->old_oid.hash, update->old_sha1)) { - strbuf_addf(err, "cannot lock ref '%s': " - "is at %s but expected %s", - update->refname, - sha1_to_hex(lock->old_oid.hash), - sha1_to_hex(update->old_sha1)); + } else if (check_old_oid(update, &lock->old_oid, err)) { return TRANSACTION_GENERIC_ERROR; } - } else { /* * Create a new update for the reference this @@@ -3633,7 -3575,8 +3602,8 @@@ * of processing the split-off update, so we * don't have to do it here. */ - ret = split_symref_update(update, referent.buf, transaction, + ret = split_symref_update(refs, update, + referent.buf, transaction, affected_refnames, err); if (ret) return ret; @@@ -3641,9 -3584,6 +3611,9 @@@ } else { struct ref_update *parent_update; + if (check_old_oid(update, &lock->old_oid, err)) + return TRANSACTION_GENERIC_ERROR; + /* * If this update is happening indirectly because of a * symref update, record the old SHA-1 in the parent @@@ -3652,8 -3592,23 +3622,9 @@@ for (parent_update = update->parent_update; parent_update; parent_update = parent_update->parent_update) { - oidcpy(&parent_update->lock->old_oid, &lock->old_oid); + struct ref_lock *parent_lock = parent_update->backend_data; + oidcpy(&parent_lock->old_oid, &lock->old_oid); } - - if ((update->flags & REF_HAVE_OLD) && - hashcmp(lock->old_oid.hash, update->old_sha1)) { - if (is_null_sha1(update->old_sha1)) - strbuf_addf(err, "cannot lock ref '%s': reference already exists", - original_update_refname(update)); - else - strbuf_addf(err, "cannot lock ref '%s': is at %s but expected %s", - original_update_refname(update), - sha1_to_hex(lock->old_oid.hash), - sha1_to_hex(update->old_sha1)); - - return TRANSACTION_GENERIC_ERROR; - } } if ((update->flags & REF_HAVE_NEW) && @@@ -3673,9 -3628,9 +3644,9 @@@ * The lock was freed upon failure of * write_ref_to_lockfile(): */ - update->lock = NULL; + update->backend_data = NULL; strbuf_addf(err, - "cannot update the ref '%s': %s", + "cannot update ref '%s': %s", update->refname, write_err); free(write_err); return TRANSACTION_GENERIC_ERROR; @@@ -3698,9 -3653,12 +3669,12 @@@ return 0; } - int ref_transaction_commit(struct ref_transaction *transaction, - struct strbuf *err) + static int files_transaction_commit(struct ref_store *ref_store, + struct ref_transaction *transaction, + struct strbuf *err) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "ref_transaction_commit"); int ret = 0, i; struct string_list refs_to_delete = STRING_LIST_INIT_NODUP; struct string_list_item *ref_to_delete; @@@ -3779,8 -3737,8 +3753,8 @@@ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; - ret = lock_ref_for_update(update, transaction, head_ref, - &affected_refnames, err); + ret = lock_ref_for_update(refs, update, transaction, + head_ref, &affected_refnames, err); if (ret) goto cleanup; } @@@ -3788,7 -3746,7 +3762,7 @@@ /* Perform updates first so live commits remain referenced */ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; - struct ref_lock *lock = update->lock; + struct ref_lock *lock = update->backend_data; if (update->flags & REF_NEEDS_COMMIT || update->flags & REF_LOG_ONLY) { @@@ -3801,17 -3759,17 +3775,17 @@@ lock->ref_name, old_msg); free(old_msg); unlock_ref(lock); - update->lock = NULL; + update->backend_data = NULL; ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } } if (update->flags & REF_NEEDS_COMMIT) { - clear_loose_ref_cache(&ref_cache); + clear_loose_ref_cache(refs); if (commit_ref(lock)) { strbuf_addf(err, "couldn't set '%s'", lock->ref_name); unlock_ref(lock); - update->lock = NULL; + update->backend_data = NULL; ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } @@@ -3820,34 -3778,35 +3794,35 @@@ /* Perform deletes now that updates are safely completed */ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; + struct ref_lock *lock = update->backend_data; if (update->flags & REF_DELETING && !(update->flags & REF_LOG_ONLY)) { - if (delete_ref_loose(update->lock, update->type, err)) { + if (delete_ref_loose(lock, update->type, err)) { ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } if (!(update->flags & REF_ISPRUNING)) string_list_append(&refs_to_delete, - update->lock->ref_name); + lock->ref_name); } } - if (repack_without_refs(&refs_to_delete, err)) { + if (repack_without_refs(refs, &refs_to_delete, err)) { ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } for_each_string_list_item(ref_to_delete, &refs_to_delete) unlink_or_warn(git_path("logs/%s", ref_to_delete->string)); - clear_loose_ref_cache(&ref_cache); + clear_loose_ref_cache(refs); cleanup: transaction->state = REF_TRANSACTION_CLOSED; for (i = 0; i < transaction->nr; i++) - if (transaction->updates[i]->lock) - unlock_ref(transaction->updates[i]->lock); + if (transaction->updates[i]->backend_data) + unlock_ref(transaction->updates[i]->backend_data); string_list_clear(&refs_to_delete, 0); free(head_ref); string_list_clear(&affected_refnames, 0); @@@ -3863,9 -3822,12 +3838,12 @@@ static int ref_present(const char *refn return string_list_has_string(affected_refnames, refname); } - int initial_ref_transaction_commit(struct ref_transaction *transaction, - struct strbuf *err) + static int files_initial_transaction_commit(struct ref_store *ref_store, + struct ref_transaction *transaction, + struct strbuf *err) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "initial_ref_transaction_commit"); int ret = 0, i; struct string_list affected_refnames = STRING_LIST_INIT_NODUP; @@@ -3913,7 -3875,7 +3891,7 @@@ } } - if (lock_packed_refs(0)) { + if (lock_packed_refs(refs, 0)) { strbuf_addf(err, "unable to lock packed-refs file: %s", strerror(errno)); ret = TRANSACTION_GENERIC_ERROR; @@@ -3925,10 -3887,10 +3903,10 @@@ if ((update->flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) - add_packed_ref(update->refname, update->new_sha1); + add_packed_ref(refs, update->refname, update->new_sha1); } - if (commit_packed_refs()) { + if (commit_packed_refs(refs)) { strbuf_addf(err, "unable to commit packed-refs file: %s", strerror(errno)); ret = TRANSACTION_GENERIC_ERROR; @@@ -3978,13 -3940,16 +3956,16 @@@ static int expire_reflog_ent(unsigned c return 0; } - int reflog_expire(const char *refname, const unsigned char *sha1, - unsigned int flags, - reflog_expiry_prepare_fn prepare_fn, - reflog_expiry_should_prune_fn should_prune_fn, - reflog_expiry_cleanup_fn cleanup_fn, - void *policy_cb_data) + static int files_reflog_expire(struct ref_store *ref_store, + const char *refname, const unsigned char *sha1, + unsigned int flags, + reflog_expiry_prepare_fn prepare_fn, + reflog_expiry_should_prune_fn should_prune_fn, + reflog_expiry_cleanup_fn cleanup_fn, + void *policy_cb_data) { + struct files_ref_store *refs = + files_downcast(ref_store, 0, "reflog_expire"); static struct lock_file reflog_lock; struct expire_reflog_cb cb; struct ref_lock *lock; @@@ -4003,7 -3968,8 +3984,8 @@@ * reference itself, plus we might need to update the * reference if --updateref was specified: */ - lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF, + lock = lock_ref_sha1_basic(refs, refname, sha1, + NULL, NULL, REF_NODEREF, &type, &err); if (!lock) { error("cannot lock ref '%s': %s", refname, err.buf); @@@ -4083,3 -4049,47 +4065,47 @@@ unlock_ref(lock); return -1; } + + static int files_init_db(struct ref_store *ref_store, struct strbuf *err) + { + /* Check validity (but we don't need the result): */ + files_downcast(ref_store, 0, "init_db"); + + /* + * Create .git/refs/{heads,tags} + */ + safe_create_dir(git_path("refs/heads"), 1); + safe_create_dir(git_path("refs/tags"), 1); + if (get_shared_repository()) { + adjust_shared_perm(git_path("refs/heads")); + adjust_shared_perm(git_path("refs/tags")); + } + return 0; + } + + struct ref_storage_be refs_be_files = { + NULL, + "files", + files_ref_store_create, + files_init_db, + files_transaction_commit, + files_initial_transaction_commit, + + files_pack_refs, + files_peel_ref, + files_create_symref, + files_delete_refs, + files_rename_ref, + + files_ref_iterator_begin, + files_read_raw_ref, + files_verify_refname_available, + + files_reflog_iterator_begin, + files_for_each_reflog_ent, + files_for_each_reflog_ent_reverse, + files_reflog_exists, + files_create_reflog, + files_delete_reflog, + files_reflog_expire + };