Use resolve_ref() to implement read_ref().
authorJunio C Hamano <junio@twinsun.com>
Fri, 30 Sep 2005 21:08:25 +0000 (14:08 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 2 Oct 2005 06:19:33 +0000 (23:19 -0700)
Symbolic refs are understood by resolve_ref(), so existing read_ref()
users will automatically understand them as well.

Signed-off-by: Junio C Hamano <junio@twinsun.com>
cache.h
refs.c
update-ref.c

diff --git a/cache.h b/cache.h
index 958c96e..63823c3 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -230,6 +230,7 @@ extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);   /* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
+extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
 
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
diff --git a/refs.c b/refs.c
index d4f3612..6aa6aec 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -7,40 +7,75 @@
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
 
-int read_ref(const char *filename, unsigned char *sha1)
+const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
 {
-       int depth = 0;
-       int ret = -1, fd;
+       int depth = MAXDEPTH, len;
+       char buffer[256];
 
-       while ((fd = open(filename, O_RDONLY)) >= 0) {
-               char buffer[256];
-               int len = read(fd, buffer, sizeof(buffer)-1);
+       for (;;) {
+               struct stat st;
+               char *buf;
+               int fd;
 
-               close(fd);
-               if (len < 0)
-                       break;
+               if (--depth < 0)
+                       return NULL;
 
-               buffer[len] = 0;
-               while (len && isspace(buffer[len-1]))
-                       buffer[--len] = 0;
+               /* Special case: non-existing file.
+                * Not having the refs/heads/new-branch is OK
+                * if we are writing into it, so is .git/HEAD
+                * that points at refs/heads/master still to be
+                * born.  It is NOT OK if we are resolving for
+                * reading.
+                */
+               if (lstat(path, &st) < 0) {
+                       if (reading || errno != ENOENT)
+                               return NULL;
+                       memset(sha1, 0, 20);
+                       return path;
+               }
 
-               if (!strncmp(buffer, "ref:", 4)) {
-                       char *buf;
-                       if (depth > MAXDEPTH)
-                               break;
-                       depth++;
-                       buf = buffer + 4;
-                       len -= 4;
-                       while (len && isspace(*buf))
-                               buf++, len--;
-                       filename = git_path("%.*s", len, buf);
-                       continue;
+               /* Follow "normalized" - ie "refs/.." symlinks by hand */
+               if (S_ISLNK(st.st_mode)) {
+                       len = readlink(path, buffer, sizeof(buffer)-1);
+                       if (len >= 5 && !memcmp("refs/", buffer, 5)) {
+                               path = git_path("%.*s", len, buffer);
+                               continue;
+                       }
                }
-               if (len >= 40)
-                       ret = get_sha1_hex(buffer, sha1);
-               break;
+
+               /*
+                * Anything else, just open it and try to use it as
+                * a ref
+                */
+               fd = open(path, O_RDONLY);
+               if (fd < 0)
+                       return NULL;
+               len = read(fd, buffer, sizeof(buffer)-1);
+               close(fd);
+
+               /*
+                * Is it a symbolic ref?
+                */
+               if (len < 4 || memcmp("ref:", buffer, 4))
+                       break;
+               buf = buffer + 4;
+               len -= 4;
+               while (len && isspace(*buf))
+                       buf++, len--;
+               while (len && isspace(buf[len-1]))
+                       buf[--len] = 0;
+               path = git_path("%.*s", len, buf);
        }
-       return ret;
+       if (len < 40 || get_sha1_hex(buffer, sha1))
+               return NULL;
+       return path;
+}
+
+int read_ref(const char *filename, unsigned char *sha1)
+{
+       if (resolve_ref(filename, sha1, 1))
+               return 0;
+       return -1;
 }
 
 static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1))
index 6919cea..4a1704c 100644 (file)
@@ -4,66 +4,6 @@
 
 static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]";
 
-#define MAXDEPTH 5
-
-static const char *resolve_ref(const char *path, unsigned char *sha1)
-{
-       int depth = MAXDEPTH, len;
-       char buffer[256];
-
-       for (;;) {
-               struct stat st;
-               char *buf;
-               int fd;
-
-               if (--depth < 0)
-                       return NULL;
-
-               /* Special case: non-existing file */
-               if (lstat(path, &st) < 0) {
-                       if (errno != ENOENT)
-                               return NULL;
-                       memset(sha1, 0, 20);
-                       return path;
-               }
-
-               /* Follow "normalized" - ie "refs/.." symlinks by hand */
-               if (S_ISLNK(st.st_mode)) {
-                       len = readlink(path, buffer, sizeof(buffer)-1);
-                       if (len >= 5 && !memcmp("refs/", buffer, 5)) {
-                               path = git_path("%.*s", len, buffer);
-                               continue;
-                       }
-               }
-
-               /*
-                * Anything else, just open it and try to use it as
-                * a ref
-                */
-               fd = open(path, O_RDONLY);
-               if (fd < 0)
-                       return NULL;
-               len = read(fd, buffer, sizeof(buffer)-1);
-               close(fd);
-
-               /*
-                * Is it a symbolic ref?
-                */
-               if (len < 4 || memcmp("ref:", buffer, 4))
-                       break;
-               buf = buffer + 4;
-               len -= 4;
-               while (len && isspace(*buf))
-                       buf++, len--;
-               while (len && isspace(buf[len-1]))
-                       buf[--len] = 0;
-               path = git_path("%.*s", len, buf);
-       }
-       if (len < 40 || get_sha1_hex(buffer, sha1))
-               return NULL;
-       return path;
-}
-
 static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *currsha1)
 {
        char buf[40];
@@ -97,7 +37,7 @@ int main(int argc, char **argv)
        if (oldval && get_sha1(oldval, oldsha1) < 0)
                die("%s: not a valid old SHA1", oldval);
 
-       path = resolve_ref(git_path("%s", refname), currsha1);
+       path = resolve_ref(git_path("%s", refname), currsha1, !!oldval);
        if (!path)
                die("No such ref: %s", refname);