refs: make create_symref() virtual
[gitweb.git] / refs / files-backend.c
index 08340755d72815b10a1e9df090f604c49a51eb78..fc67cc6ec74725a28d212e525aea5a4ed64fc785 100644 (file)
@@ -1316,107 +1316,22 @@ static struct ref_dir *get_loose_refs(struct files_ref_store *refs)
        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 refs. Find <refname> in the packed-refs file
- * for the submodule.
- */
-static int resolve_gitlink_packed_ref(struct files_ref_store *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 files_ref_store *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->base.submodule
-               ? git_pathdup_submodule(refs->base.submodule, "%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);
-       struct strbuf submodule = STRBUF_INIT;
-       struct files_ref_store *refs;
-
-       while (len && path[len-1] == '/')
-               len--;
-       if (!len)
-               return -1;
-
-       strbuf_add(&submodule, path, len);
-       refs = get_files_ref_store(submodule.buf, "resolve_gitlink_ref");
-       if (!refs) {
-               strbuf_release(&submodule);
-               return -1;
-       }
-       strbuf_release(&submodule);
-
-       return resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
-}
-
 /*
  * 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)
 {
-       struct files_ref_store *refs =
-               get_files_ref_store(NULL, "get_packed_ref");
-
        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;
 
@@ -1424,7 +1339,7 @@ static int resolve_missing_loose_ref(const char *refname,
         * 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;
@@ -1434,9 +1349,12 @@ static int resolve_missing_loose_ref(const char *refname,
        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;
@@ -1448,7 +1366,12 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
 
        *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:
@@ -1465,7 +1388,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
        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;
                }
@@ -1499,7 +1422,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
                 * 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;
                }
@@ -1608,8 +1531,9 @@ static int lock_raw_ref(const char *refname, int mustexist,
                        unsigned int *type,
                        struct strbuf *err)
 {
+       struct ref_store *ref_store = get_ref_store(NULL);
        struct files_ref_store *refs =
-               get_files_ref_store(NULL, "lock_raw_ref");
+               files_downcast(ref_store, 0, "lock_raw_ref");
        struct ref_lock *lock;
        struct strbuf ref_file = STRBUF_INIT;
        int attempts_remaining = 3;
@@ -1699,7 +1623,8 @@ static int lock_raw_ref(const char *refname, int mustexist,
         * fear that its value will change.
         */
 
-       if (read_raw_ref(refname, lock->old_oid.hash, referent, type)) {
+       if (files_read_raw_ref(ref_store, refname,
+                              lock->old_oid.hash, referent, type)) {
                if (errno == ENOENT) {
                        if (mustexist) {
                                /* Garden variety missing reference. */
@@ -1836,6 +1761,7 @@ static enum peel_status peel_entry(struct ref_entry *entry, int repeel)
 
 int peel_ref(const char *refname, unsigned char *sha1)
 {
+       struct files_ref_store *refs = get_files_ref_store(NULL, "peel_ref");
        int flag;
        unsigned char base[20];
 
@@ -1860,7 +1786,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
         * 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;
@@ -2213,14 +2139,14 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
  * 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)
 {
-       struct files_ref_store *refs =
-               get_files_ref_store(NULL, "lock_packed_refs");
        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;
@@ -2249,16 +2175,16 @@ static int lock_packed_refs(int flags)
  * 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 files_ref_store *refs =
-               get_files_ref_store(NULL, "commit_packed_refs");
        struct packed_ref_cache *packed_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");
 
@@ -2285,13 +2211,13 @@ static int commit_packed_refs(void)
  * 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 files_ref_store *refs =
-               get_files_ref_store(NULL, "rollback_packed_refs");
        struct packed_ref_cache *packed_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);
@@ -2428,22 +2354,22 @@ static void prune_refs(struct ref_to_prune *r)
        }
 }
 
-int pack_refs(unsigned int flags)
+static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
 {
        struct files_ref_store *refs =
-               get_files_ref_store(NULL, "pack_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);
+       lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
        cbdata.packed_refs = get_packed_refs(refs);
 
        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);
@@ -2469,7 +2395,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *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;
                }
@@ -2479,7 +2405,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
        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;
        }
@@ -2494,12 +2420,12 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
                 * 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));
@@ -2623,13 +2549,14 @@ static int rename_tmp_log(const char *newrefname)
        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 files_ref_store *refs =
-               get_files_ref_store(NULL, "verify_refname_available");
+               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);
 
@@ -3084,12 +3011,16 @@ static int create_symref_locked(struct ref_lock *lock, const char *refname,
        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 strbuf err = STRBUF_INIT;
        struct ref_lock *lock;
        int ret;
 
+       files_downcast(ref_store, 0, "create_symref");
+
        lock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL,
                                   &err);
        if (!lock) {
@@ -3698,11 +3629,12 @@ static int lock_ref_for_update(struct ref_update *update,
        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 =
-               get_files_ref_store(NULL, "ref_transaction_commit");
+               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;
@@ -3917,7 +3849,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
                }
        }
 
-       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;
@@ -3932,7 +3864,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
                        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;
@@ -4091,5 +4023,12 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
 struct ref_storage_be refs_be_files = {
        NULL,
        "files",
-       files_ref_store_create
+       files_ref_store_create,
+       files_transaction_commit,
+
+       files_pack_refs,
+       files_create_symref,
+
+       files_read_raw_ref,
+       files_verify_refname_available
 };