gitweb: Convert project name to UTF-8
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 591318501f6ba072c4888ed7cf9e5b34d26fb32f..03e8dfec9fcb2c9fffc7c809048fa90a0e02b0af 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -663,6 +663,8 @@ struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
 
 struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1)
 {
+       if (check_ref_format(ref) == -1)
+               return NULL;
        return lock_ref_sha1_basic(ref, old_sha1, NULL);
 }
 
@@ -992,7 +994,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
        const char *lockpath;
        char ref[1000];
        int fd, len, written;
-       const char *git_HEAD = git_path("%s", ref_target);
+       char *git_HEAD = xstrdup(git_path("%s", ref_target));
        unsigned char old_sha1[20], new_sha1[20];
 
        if (logmsg && read_ref(ref_target, old_sha1))
@@ -1010,36 +1012,38 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
        len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
        if (sizeof(ref) <= len) {
                error("refname too long: %s", refs_heads_master);
-               return -1;
+               goto error_free_return;
        }
        lockpath = mkpath("%s.lock", git_HEAD);
        fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
        if (fd < 0) {
                error("Unable to open %s for writing", lockpath);
-               return -5;
+               goto error_free_return;
        }
        written = write_in_full(fd, ref, len);
        close(fd);
        if (written != len) {
-               unlink(lockpath);
                error("Unable to write to %s", lockpath);
-               return -2;
+               goto error_unlink_return;
        }
        if (rename(lockpath, git_HEAD) < 0) {
-               unlink(lockpath);
                error("Unable to create %s", git_HEAD);
-               return -3;
+               goto error_unlink_return;
        }
        if (adjust_shared_perm(git_HEAD)) {
-               unlink(lockpath);
                error("Unable to fix permissions on %s", lockpath);
-               return -4;
+       error_unlink_return:
+               unlink(lockpath);
+       error_free_return:
+               free(git_HEAD);
+               return -1;
        }
 
        done:
        if (logmsg && !read_ref(refs_heads_master, new_sha1))
                log_ref_write(ref_target, old_sha1, new_sha1, logmsg);
 
+       free(git_HEAD);
        return 0;
 }
 
@@ -1199,3 +1203,53 @@ int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
        return ret;
 }
 
+static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)
+{
+       DIR *dir = opendir(git_path("logs/%s", base));
+       int retval = errno;
+
+       if (dir) {
+               struct dirent *de;
+               int baselen = strlen(base);
+               char *log = xmalloc(baselen + 257);
+
+               memcpy(log, base, baselen);
+               if (baselen && base[baselen-1] != '/')
+                       log[baselen++] = '/';
+
+               while ((de = readdir(dir)) != NULL) {
+                       struct stat st;
+                       int namelen;
+
+                       if (de->d_name[0] == '.')
+                               continue;
+                       namelen = strlen(de->d_name);
+                       if (namelen > 255)
+                               continue;
+                       if (has_extension(de->d_name, ".lock"))
+                               continue;
+                       memcpy(log + baselen, de->d_name, namelen+1);
+                       if (stat(git_path("logs/%s", log), &st) < 0)
+                               continue;
+                       if (S_ISDIR(st.st_mode)) {
+                               retval = do_for_each_reflog(log, fn, cb_data);
+                       } else {
+                               unsigned char sha1[20];
+                               if (!resolve_ref(log, sha1, 0, NULL))
+                                       retval = error("bad ref for %s", log);
+                               else
+                                       retval = fn(log, sha1, 0, cb_data);
+                       }
+                       if (retval)
+                               break;
+               }
+               free(log);
+               closedir(dir);
+       }
+       return retval;
+}
+
+int for_each_reflog(each_ref_fn fn, void *cb_data)
+{
+       return do_for_each_reflog("", fn, cb_data);
+}