Merge branch 'nd/multiple-work-trees'
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index e23542b3869b38e47f59f102d28648d30d506574..0312f052575046f0dd539b19897b61eddc2862e0 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1382,7 +1382,7 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
 {
        int fd, len;
        char buffer[128], *p;
-       char *path;
+       const char *path;
 
        if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
                return -1;
@@ -1475,7 +1475,11 @@ static int resolve_missing_loose_ref(const char *refname,
 }
 
 /* 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_unsafe_1(const char *refname,
+                                       int resolve_flags,
+                                       unsigned char *sha1,
+                                       int *flags,
+                                       struct strbuf *sb_path)
 {
        int depth = MAXDEPTH;
        ssize_t len;
@@ -1506,7 +1510,7 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
                bad_name = 1;
        }
        for (;;) {
-               char path[PATH_MAX];
+               const char *path;
                struct stat st;
                char *buf;
                int fd;
@@ -1516,7 +1520,9 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
                        return NULL;
                }
 
-               git_snpath(path, sizeof(path), "%s", refname);
+               strbuf_reset(sb_path);
+               strbuf_git_path(sb_path, "%s", refname);
+               path = sb_path->buf;
 
                /*
                 * We might have to loop back here to avoid a race
@@ -1643,6 +1649,16 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
        }
 }
 
+const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
+                              unsigned char *sha1, int *flags)
+{
+       struct strbuf sb_path = STRBUF_INIT;
+       const char *ret = resolve_ref_unsafe_1(refname, resolve_flags,
+                                              sha1, flags, &sb_path);
+       strbuf_release(&sb_path);
+       return ret;
+}
+
 char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
 {
        return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
@@ -1934,6 +1950,11 @@ static int do_for_each_ref(struct ref_cache *refs, const char *base,
        data.fn = fn;
        data.cb_data = cb_data;
 
+       if (ref_paranoia < 0)
+               ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
+       if (ref_paranoia)
+               data.flags |= DO_FOR_EACH_INCLUDE_BROKEN;
+
        return do_for_each_entry(refs, base, do_one_ref, &data);
 }
 
@@ -2269,7 +2290,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const struct string_list *skip,
                                            unsigned int flags, int *type_p)
 {
-       char *ref_file;
+       const char *ref_file;
        const char *orig_refname = refname;
        struct ref_lock *lock;
        int last_errno = 0;
@@ -2338,7 +2359,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        ref_file = git_path("%s", refname);
 
  retry:
-       switch (safe_create_leading_directories(ref_file)) {
+       switch (safe_create_leading_directories_const(ref_file)) {
        case SCLD_OK:
                break; /* success */
        case SCLD_VANISHED:
@@ -2616,68 +2637,10 @@ int pack_refs(unsigned int flags)
        return 0;
 }
 
-/*
- * If entry is no longer needed in packed-refs, add it to the string
- * list pointed to by cb_data.  Reasons for deleting entries:
- *
- * - Entry is broken.
- * - Entry is overridden by a loose ref.
- * - Entry does not point at a valid object.
- *
- * In the first and third cases, also emit an error message because these
- * are indications of repository corruption.
- */
-static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
-{
-       struct string_list *refs_to_delete = cb_data;
-
-       if (entry->flag & REF_ISBROKEN) {
-               /* This shouldn't happen to packed refs. */
-               error("%s is broken!", entry->name);
-               string_list_append(refs_to_delete, entry->name);
-               return 0;
-       }
-       if (!has_sha1_file(entry->u.value.sha1)) {
-               unsigned char sha1[20];
-               int flags;
-
-               if (read_ref_full(entry->name, 0, sha1, &flags))
-                       /* We should at least have found the packed ref. */
-                       die("Internal error");
-               if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
-                       /*
-                        * This packed reference is overridden by a
-                        * loose reference, so it is OK that its value
-                        * is no longer valid; for example, it might
-                        * refer to an object that has been garbage
-                        * collected.  For this purpose we don't even
-                        * care whether the loose reference itself is
-                        * invalid, broken, symbolic, etc.  Silently
-                        * remove the packed reference.
-                        */
-                       string_list_append(refs_to_delete, entry->name);
-                       return 0;
-               }
-               /*
-                * There is no overriding loose reference, so the fact
-                * that this reference doesn't refer to a valid object
-                * indicates some kind of repository corruption.
-                * Report the problem, then omit the reference from
-                * the output.
-                */
-               error("%s does not point to a valid object!", entry->name);
-               string_list_append(refs_to_delete, entry->name);
-               return 0;
-       }
-
-       return 0;
-}
-
 int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 {
        struct ref_dir *packed;
-       struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
-       struct string_list_item *refname, *ref_to_delete;
+       struct string_list_item *refname;
        int ret, needs_repacking = 0, removed = 0;
 
        assert(err);
@@ -2713,13 +2676,6 @@ int repack_without_refs(struct string_list *refnames, struct strbuf *err)
                return 0;
        }
 
-       /* Remove any other accumulated cruft */
-       do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
-       for_each_string_list_item(ref_to_delete, &refs_to_delete) {
-               if (remove_entry(packed, ref_to_delete->string) == -1)
-                       die("internal error");
-       }
-
        /* Write what remains */
        ret = commit_packed_refs();
        if (ret)
@@ -2781,7 +2737,7 @@ static int rename_tmp_log(const char *newrefname)
        int attempts_remaining = 4;
 
  retry:
-       switch (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
+       switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) {
        case SCLD_OK:
                break; /* success */
        case SCLD_VANISHED:
@@ -2967,11 +2923,15 @@ static int copy_msg(char *buf, const char *msg)
 }
 
 /* This function must set a meaningful errno on failure */
-int log_ref_setup(const char *refname, char *logfile, int bufsize)
+int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
 {
        int logfd, oflags = O_APPEND | O_WRONLY;
+       char *logfile;
 
-       git_snpath(logfile, bufsize, "logs/%s", refname);
+       strbuf_git_path(sb_logfile, "logs/%s", refname);
+       logfile = sb_logfile->buf;
+       /* make sure the rest of the function can't change "logfile" */
+       sb_logfile = NULL;
        if (log_all_ref_updates &&
            (starts_with(refname, "refs/heads/") ||
             starts_with(refname, "refs/remotes/") ||
@@ -3042,18 +3002,22 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
        return 0;
 }
 
-static int log_ref_write(const char *refname, const unsigned char *old_sha1,
-                        const unsigned char *new_sha1, const char *msg)
+static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
+                          const unsigned char *new_sha1, const char *msg,
+                          struct strbuf *sb_log_file)
 {
        int logfd, result, oflags = O_APPEND | O_WRONLY;
-       char log_file[PATH_MAX];
+       char *log_file;
 
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
 
-       result = log_ref_setup(refname, log_file, sizeof(log_file));
+       result = log_ref_setup(refname, sb_log_file);
        if (result)
                return result;
+       log_file = sb_log_file->buf;
+       /* make sure the rest of the function can't change "log_file" */
+       sb_log_file = NULL;
 
        logfd = open(log_file, oflags);
        if (logfd < 0)
@@ -3076,6 +3040,15 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
        return 0;
 }
 
+static int log_ref_write(const char *refname, const unsigned char *old_sha1,
+                        const unsigned char *new_sha1, const char *msg)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
+       strbuf_release(&sb);
+       return ret;
+}
+
 int is_branch(const char *refname)
 {
        return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");