Skip to content

Commit a876ed8

Browse files
Junio C HamanoJunio C Hamano
authored andcommitted
Use resolve_ref() to implement read_ref().
Symbolic refs are understood by resolve_ref(), so existing read_ref() users will automatically understand them as well. Signed-off-by: Junio C Hamano <[email protected]>
1 parent ca8db14 commit a876ed8

File tree

3 files changed

+64
-88
lines changed

3 files changed

+64
-88
lines changed

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ extern int get_sha1(const char *str, unsigned char *sha1);
230230
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
231231
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
232232
extern int read_ref(const char *filename, unsigned char *sha1);
233+
extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
233234

234235
/* General helper functions */
235236
extern void usage(const char *err) NORETURN;

refs.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,75 @@
77
/* We allow "recursive" symbolic refs. Only within reason, though */
88
#define MAXDEPTH 5
99

10-
int read_ref(const char *filename, unsigned char *sha1)
10+
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
1111
{
12-
int depth = 0;
13-
int ret = -1, fd;
12+
int depth = MAXDEPTH, len;
13+
char buffer[256];
1414

15-
while ((fd = open(filename, O_RDONLY)) >= 0) {
16-
char buffer[256];
17-
int len = read(fd, buffer, sizeof(buffer)-1);
15+
for (;;) {
16+
struct stat st;
17+
char *buf;
18+
int fd;
1819

19-
close(fd);
20-
if (len < 0)
21-
break;
20+
if (--depth < 0)
21+
return NULL;
2222

23-
buffer[len] = 0;
24-
while (len && isspace(buffer[len-1]))
25-
buffer[--len] = 0;
23+
/* Special case: non-existing file.
24+
* Not having the refs/heads/new-branch is OK
25+
* if we are writing into it, so is .git/HEAD
26+
* that points at refs/heads/master still to be
27+
* born. It is NOT OK if we are resolving for
28+
* reading.
29+
*/
30+
if (lstat(path, &st) < 0) {
31+
if (reading || errno != ENOENT)
32+
return NULL;
33+
memset(sha1, 0, 20);
34+
return path;
35+
}
2636

27-
if (!strncmp(buffer, "ref:", 4)) {
28-
char *buf;
29-
if (depth > MAXDEPTH)
30-
break;
31-
depth++;
32-
buf = buffer + 4;
33-
len -= 4;
34-
while (len && isspace(*buf))
35-
buf++, len--;
36-
filename = git_path("%.*s", len, buf);
37-
continue;
37+
/* Follow "normalized" - ie "refs/.." symlinks by hand */
38+
if (S_ISLNK(st.st_mode)) {
39+
len = readlink(path, buffer, sizeof(buffer)-1);
40+
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
41+
path = git_path("%.*s", len, buffer);
42+
continue;
43+
}
3844
}
39-
if (len >= 40)
40-
ret = get_sha1_hex(buffer, sha1);
41-
break;
45+
46+
/*
47+
* Anything else, just open it and try to use it as
48+
* a ref
49+
*/
50+
fd = open(path, O_RDONLY);
51+
if (fd < 0)
52+
return NULL;
53+
len = read(fd, buffer, sizeof(buffer)-1);
54+
close(fd);
55+
56+
/*
57+
* Is it a symbolic ref?
58+
*/
59+
if (len < 4 || memcmp("ref:", buffer, 4))
60+
break;
61+
buf = buffer + 4;
62+
len -= 4;
63+
while (len && isspace(*buf))
64+
buf++, len--;
65+
while (len && isspace(buf[len-1]))
66+
buf[--len] = 0;
67+
path = git_path("%.*s", len, buf);
4268
}
43-
return ret;
69+
if (len < 40 || get_sha1_hex(buffer, sha1))
70+
return NULL;
71+
return path;
72+
}
73+
74+
int read_ref(const char *filename, unsigned char *sha1)
75+
{
76+
if (resolve_ref(filename, sha1, 1))
77+
return 0;
78+
return -1;
4479
}
4580

4681
static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1))

update-ref.c

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,6 @@
44

55
static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]";
66

7-
#define MAXDEPTH 5
8-
9-
static const char *resolve_ref(const char *path, unsigned char *sha1)
10-
{
11-
int depth = MAXDEPTH, len;
12-
char buffer[256];
13-
14-
for (;;) {
15-
struct stat st;
16-
char *buf;
17-
int fd;
18-
19-
if (--depth < 0)
20-
return NULL;
21-
22-
/* Special case: non-existing file */
23-
if (lstat(path, &st) < 0) {
24-
if (errno != ENOENT)
25-
return NULL;
26-
memset(sha1, 0, 20);
27-
return path;
28-
}
29-
30-
/* Follow "normalized" - ie "refs/.." symlinks by hand */
31-
if (S_ISLNK(st.st_mode)) {
32-
len = readlink(path, buffer, sizeof(buffer)-1);
33-
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
34-
path = git_path("%.*s", len, buffer);
35-
continue;
36-
}
37-
}
38-
39-
/*
40-
* Anything else, just open it and try to use it as
41-
* a ref
42-
*/
43-
fd = open(path, O_RDONLY);
44-
if (fd < 0)
45-
return NULL;
46-
len = read(fd, buffer, sizeof(buffer)-1);
47-
close(fd);
48-
49-
/*
50-
* Is it a symbolic ref?
51-
*/
52-
if (len < 4 || memcmp("ref:", buffer, 4))
53-
break;
54-
buf = buffer + 4;
55-
len -= 4;
56-
while (len && isspace(*buf))
57-
buf++, len--;
58-
while (len && isspace(buf[len-1]))
59-
buf[--len] = 0;
60-
path = git_path("%.*s", len, buf);
61-
}
62-
if (len < 40 || get_sha1_hex(buffer, sha1))
63-
return NULL;
64-
return path;
65-
}
66-
677
static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *currsha1)
688
{
699
char buf[40];
@@ -97,7 +37,7 @@ int main(int argc, char **argv)
9737
if (oldval && get_sha1(oldval, oldsha1) < 0)
9838
die("%s: not a valid old SHA1", oldval);
9939

100-
path = resolve_ref(git_path("%s", refname), currsha1);
40+
path = resolve_ref(git_path("%s", refname), currsha1, !!oldval);
10141
if (!path)
10242
die("No such ref: %s", refname);
10343

0 commit comments

Comments
 (0)