]>
Commit | Line | Data |
---|---|---|
9938af6a JH |
1 | #include "cache.h" |
2 | #include "commit.h" | |
3 | ||
4 | static int find_short_object_filename(int len, const char *name, unsigned char *sha1) | |
5 | { | |
6 | static char dirname[PATH_MAX]; | |
7 | char hex[40]; | |
8 | DIR *dir; | |
9 | int found; | |
10 | ||
11 | snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name); | |
12 | dir = opendir(dirname); | |
13 | sprintf(hex, "%.2s", name); | |
14 | found = 0; | |
15 | if (dir) { | |
16 | struct dirent *de; | |
17 | while ((de = readdir(dir)) != NULL) { | |
18 | if (strlen(de->d_name) != 38) | |
19 | continue; | |
20 | if (memcmp(de->d_name, name + 2, len-2)) | |
21 | continue; | |
22 | memcpy(hex + 2, de->d_name, 38); | |
23 | if (++found > 1) | |
24 | break; | |
25 | } | |
26 | closedir(dir); | |
27 | } | |
28 | if (found == 1) | |
29 | return get_sha1_hex(hex, sha1) == 0; | |
30 | return 0; | |
31 | } | |
32 | ||
33 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) | |
34 | { | |
35 | do { | |
36 | if (*a != *b) | |
37 | return 0; | |
38 | a++; | |
39 | b++; | |
40 | len -= 2; | |
41 | } while (len > 1); | |
42 | if (len) | |
43 | if ((*a ^ *b) & 0xf0) | |
44 | return 0; | |
45 | return 1; | |
46 | } | |
47 | ||
48 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) | |
49 | { | |
50 | struct packed_git *p; | |
51 | ||
52 | prepare_packed_git(); | |
53 | for (p = packed_git; p; p = p->next) { | |
54 | unsigned num = num_packed_objects(p); | |
55 | unsigned first = 0, last = num; | |
56 | while (first < last) { | |
57 | unsigned mid = (first + last) / 2; | |
58 | unsigned char now[20]; | |
59 | int cmp; | |
60 | ||
61 | nth_packed_object_sha1(p, mid, now); | |
62 | cmp = memcmp(match, now, 20); | |
63 | if (!cmp) { | |
64 | first = mid; | |
65 | break; | |
66 | } | |
67 | if (cmp > 0) { | |
68 | first = mid+1; | |
69 | continue; | |
70 | } | |
71 | last = mid; | |
72 | } | |
73 | if (first < num) { | |
74 | unsigned char now[20], next[20]; | |
75 | nth_packed_object_sha1(p, first, now); | |
76 | if (match_sha(len, match, now)) { | |
77 | if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) { | |
78 | memcpy(sha1, now, 20); | |
79 | return 1; | |
80 | } | |
81 | } | |
82 | } | |
83 | } | |
84 | return 0; | |
85 | } | |
86 | ||
87 | static int get_short_sha1(const char *name, unsigned char *sha1) | |
88 | { | |
89 | int i; | |
90 | char canonical[40]; | |
91 | unsigned char res[20]; | |
92 | ||
93 | memset(res, 0, 20); | |
94 | memset(canonical, 'x', 40); | |
95 | for (i = 0;;i++) { | |
96 | unsigned char c = name[i]; | |
97 | unsigned char val; | |
98 | if (!c || i > 40) | |
99 | break; | |
100 | if (c >= '0' && c <= '9') | |
101 | val = c - '0'; | |
102 | else if (c >= 'a' && c <= 'f') | |
103 | val = c - 'a' + 10; | |
104 | else if (c >= 'A' && c <='F') { | |
105 | val = c - 'A' + 10; | |
106 | c -= 'A' - 'a'; | |
107 | } | |
108 | else | |
109 | return -1; | |
110 | canonical[i] = c; | |
111 | if (!(i & 1)) | |
112 | val <<= 4; | |
113 | res[i >> 1] |= val; | |
114 | } | |
115 | if (i < 4) | |
116 | return -1; | |
117 | if (find_short_object_filename(i, canonical, sha1)) | |
118 | return 0; | |
119 | if (find_short_packed_object(i, res, sha1)) | |
120 | return 0; | |
121 | return -1; | |
122 | } | |
123 | ||
124 | static int get_sha1_file(const char *path, unsigned char *result) | |
125 | { | |
126 | char buffer[60]; | |
127 | int fd = open(path, O_RDONLY); | |
128 | int len; | |
129 | ||
130 | if (fd < 0) | |
131 | return -1; | |
132 | len = read(fd, buffer, sizeof(buffer)); | |
133 | close(fd); | |
134 | if (len < 40) | |
135 | return -1; | |
136 | return get_sha1_hex(buffer, result); | |
137 | } | |
138 | ||
139 | static int get_sha1_basic(const char *str, int len, unsigned char *sha1) | |
140 | { | |
141 | static const char *prefix[] = { | |
142 | "", | |
143 | "refs", | |
144 | "refs/tags", | |
145 | "refs/heads", | |
146 | "refs/snap", | |
147 | NULL | |
148 | }; | |
149 | const char **p; | |
150 | ||
151 | if (!get_sha1_hex(str, sha1)) | |
152 | return 0; | |
153 | ||
154 | for (p = prefix; *p; p++) { | |
155 | char *pathname = git_path("%s/%.*s", *p, len, str); | |
156 | if (!get_sha1_file(pathname, sha1)) | |
157 | return 0; | |
158 | } | |
159 | ||
160 | return -1; | |
161 | } | |
162 | ||
163 | static int get_sha1_1(const char *name, int len, unsigned char *sha1); | |
164 | ||
165 | static int get_parent(const char *name, int len, | |
166 | unsigned char *result, int idx) | |
167 | { | |
168 | unsigned char sha1[20]; | |
169 | int ret = get_sha1_1(name, len, sha1); | |
170 | struct commit *commit; | |
171 | struct commit_list *p; | |
172 | ||
173 | if (ret) | |
174 | return ret; | |
175 | commit = lookup_commit_reference(sha1); | |
176 | if (!commit) | |
177 | return -1; | |
178 | if (parse_commit(commit)) | |
179 | return -1; | |
180 | if (!idx) { | |
181 | memcpy(result, commit->object.sha1, 20); | |
182 | return 0; | |
183 | } | |
184 | p = commit->parents; | |
185 | while (p) { | |
186 | if (!--idx) { | |
187 | memcpy(result, p->item->object.sha1, 20); | |
188 | return 0; | |
189 | } | |
190 | p = p->next; | |
191 | } | |
192 | return -1; | |
193 | } | |
194 | ||
195 | static int get_sha1_1(const char *name, int len, unsigned char *sha1) | |
196 | { | |
197 | int parent, ret; | |
198 | ||
199 | /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */ | |
200 | if (len > 2 && name[len-2] == '^' && | |
201 | name[len-1] >= '0' && name[len-1] <= '9') { | |
202 | parent = name[len-1] - '0'; | |
203 | len -= 2; | |
204 | } | |
205 | else if (len > 1 && name[len-1] == '^') | |
206 | parent = 1; | |
207 | else | |
208 | parent = -1; | |
209 | ||
210 | if (0 <= parent) { | |
211 | ret = get_parent(name, len-1, sha1, parent); | |
212 | if (!ret) | |
213 | return 0; | |
214 | } | |
215 | ret = get_sha1_basic(name, len, sha1); | |
216 | if (!ret) | |
217 | return 0; | |
218 | return get_short_sha1(name, sha1); | |
219 | } | |
220 | ||
221 | /* | |
222 | * This is like "get_sha1_basic()", except it allows "sha1 expressions", | |
223 | * notably "xyz^" for "parent of xyz" | |
224 | */ | |
225 | int get_sha1(const char *name, unsigned char *sha1) | |
226 | { | |
227 | return get_sha1_1(name, strlen(name), sha1); | |
228 | } |