Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 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 | { |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 6 | struct alternate_object_database *alt; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 7 | char hex[40]; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 8 | int found = 0; |
| 9 | static struct alternate_object_database *fakeent; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 10 | |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 11 | if (!fakeent) { |
| 12 | const char *objdir = get_object_directory(); |
| 13 | int objdir_len = strlen(objdir); |
| 14 | int entlen = objdir_len + 43; |
| 15 | fakeent = xmalloc(sizeof(*fakeent) + entlen); |
| 16 | memcpy(fakeent->base, objdir, objdir_len); |
| 17 | fakeent->name = fakeent->base + objdir_len + 1; |
| 18 | fakeent->name[-1] = '/'; |
| 19 | } |
| 20 | fakeent->next = alt_odb_list; |
| 21 | |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 22 | sprintf(hex, "%.2s", name); |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 23 | for (alt = fakeent; alt && found < 2; alt = alt->next) { |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 24 | struct dirent *de; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 25 | DIR *dir; |
| 26 | sprintf(alt->name, "%.2s/", name); |
| 27 | dir = opendir(alt->base); |
| 28 | if (!dir) |
| 29 | continue; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 30 | while ((de = readdir(dir)) != NULL) { |
| 31 | if (strlen(de->d_name) != 38) |
| 32 | continue; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 33 | if (memcmp(de->d_name, name + 2, len - 2)) |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 34 | continue; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 35 | if (!found) { |
| 36 | memcpy(hex + 2, de->d_name, 38); |
| 37 | found++; |
| 38 | } |
| 39 | else if (memcmp(hex + 2, de->d_name, 38)) { |
| 40 | found = 2; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 41 | break; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 42 | } |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 43 | } |
| 44 | closedir(dir); |
| 45 | } |
| 46 | if (found == 1) |
| 47 | return get_sha1_hex(hex, sha1) == 0; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 48 | return found; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) |
| 52 | { |
| 53 | do { |
| 54 | if (*a != *b) |
| 55 | return 0; |
| 56 | a++; |
| 57 | b++; |
| 58 | len -= 2; |
| 59 | } while (len > 1); |
| 60 | if (len) |
| 61 | if ((*a ^ *b) & 0xf0) |
| 62 | return 0; |
| 63 | return 1; |
| 64 | } |
| 65 | |
| 66 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) |
| 67 | { |
| 68 | struct packed_git *p; |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 69 | unsigned char found_sha1[20]; |
| 70 | int found = 0; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 71 | |
| 72 | prepare_packed_git(); |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 73 | for (p = packed_git; p && found < 2; p = p->next) { |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 74 | unsigned num = num_packed_objects(p); |
| 75 | unsigned first = 0, last = num; |
| 76 | while (first < last) { |
| 77 | unsigned mid = (first + last) / 2; |
| 78 | unsigned char now[20]; |
| 79 | int cmp; |
| 80 | |
| 81 | nth_packed_object_sha1(p, mid, now); |
| 82 | cmp = memcmp(match, now, 20); |
| 83 | if (!cmp) { |
| 84 | first = mid; |
| 85 | break; |
| 86 | } |
| 87 | if (cmp > 0) { |
| 88 | first = mid+1; |
| 89 | continue; |
| 90 | } |
| 91 | last = mid; |
| 92 | } |
| 93 | if (first < num) { |
Junio C Hamano | 0bc4589 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 94 | unsigned char now[20], next[20]; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 95 | nth_packed_object_sha1(p, first, now); |
| 96 | if (match_sha(len, match, now)) { |
Junio C Hamano | 0bc4589 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 97 | if (nth_packed_object_sha1(p, first+1, next) || |
| 98 | !match_sha(len, match, next)) { |
| 99 | /* unique within this pack */ |
| 100 | if (!found) { |
| 101 | memcpy(found_sha1, now, 20); |
| 102 | found++; |
| 103 | } |
| 104 | else if (memcmp(found_sha1, now, 20)) { |
| 105 | found = 2; |
| 106 | break; |
| 107 | } |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 108 | } |
Junio C Hamano | 0bc4589 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 109 | else { |
| 110 | /* not even unique within this pack */ |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 111 | found = 2; |
| 112 | break; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | } |
| 116 | } |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 117 | if (found == 1) |
| 118 | memcpy(sha1, found_sha1, 20); |
| 119 | return found; |
| 120 | } |
| 121 | |
| 122 | static int find_unique_short_object(int len, char *canonical, |
| 123 | unsigned char *res, unsigned char *sha1) |
| 124 | { |
| 125 | int has_unpacked, has_packed; |
| 126 | unsigned char unpacked_sha1[20], packed_sha1[20]; |
| 127 | |
| 128 | has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1); |
| 129 | has_packed = find_short_packed_object(len, res, packed_sha1); |
| 130 | if (!has_unpacked && !has_packed) |
| 131 | return -1; |
| 132 | if (1 < has_unpacked || 1 < has_packed) |
Junio C Hamano | 0bc4589 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 133 | return error("short SHA1 %.*s is ambiguous.", len, canonical); |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 134 | if (has_unpacked != has_packed) { |
| 135 | memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20); |
| 136 | return 0; |
| 137 | } |
| 138 | /* Both have unique ones -- do they match? */ |
| 139 | if (memcmp(packed_sha1, unpacked_sha1, 20)) |
Junio C Hamano | 5a82b4f | 2005-10-03 00:36:13 -0700 | [diff] [blame] | 140 | return error("short SHA1 %.*s is ambiguous.", len, canonical); |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 141 | memcpy(sha1, packed_sha1, 20); |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 142 | return 0; |
| 143 | } |
| 144 | |
Linus Torvalds | af61c6e | 2005-09-19 15:16:03 -0700 | [diff] [blame] | 145 | static int get_short_sha1(const char *name, int len, unsigned char *sha1) |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 146 | { |
| 147 | int i; |
| 148 | char canonical[40]; |
| 149 | unsigned char res[20]; |
| 150 | |
Linus Torvalds | af61c6e | 2005-09-19 15:16:03 -0700 | [diff] [blame] | 151 | if (len < 4) |
| 152 | return -1; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 153 | memset(res, 0, 20); |
| 154 | memset(canonical, 'x', 40); |
Linus Torvalds | af61c6e | 2005-09-19 15:16:03 -0700 | [diff] [blame] | 155 | for (i = 0; i < len ;i++) { |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 156 | unsigned char c = name[i]; |
| 157 | unsigned char val; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 158 | if (c >= '0' && c <= '9') |
| 159 | val = c - '0'; |
| 160 | else if (c >= 'a' && c <= 'f') |
| 161 | val = c - 'a' + 10; |
| 162 | else if (c >= 'A' && c <='F') { |
| 163 | val = c - 'A' + 10; |
| 164 | c -= 'A' - 'a'; |
| 165 | } |
| 166 | else |
| 167 | return -1; |
| 168 | canonical[i] = c; |
| 169 | if (!(i & 1)) |
| 170 | val <<= 4; |
| 171 | res[i >> 1] |= val; |
| 172 | } |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 173 | |
| 174 | return find_unique_short_object(i, canonical, res, sha1); |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 175 | } |
| 176 | |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 177 | static int get_sha1_basic(const char *str, int len, unsigned char *sha1) |
| 178 | { |
| 179 | static const char *prefix[] = { |
| 180 | "", |
| 181 | "refs", |
| 182 | "refs/tags", |
| 183 | "refs/heads", |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 184 | NULL |
| 185 | }; |
| 186 | const char **p; |
| 187 | |
Linus Torvalds | 3c3852e | 2005-08-13 11:05:25 -0700 | [diff] [blame] | 188 | if (len == 40 && !get_sha1_hex(str, sha1)) |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 189 | return 0; |
| 190 | |
| 191 | for (p = prefix; *p; p++) { |
| 192 | char *pathname = git_path("%s/%.*s", *p, len, str); |
Linus Torvalds | ca8db14 | 2005-09-25 09:59:37 -0700 | [diff] [blame] | 193 | if (!read_ref(pathname, sha1)) |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 194 | return 0; |
| 195 | } |
| 196 | |
| 197 | return -1; |
| 198 | } |
| 199 | |
| 200 | static int get_sha1_1(const char *name, int len, unsigned char *sha1); |
| 201 | |
| 202 | static int get_parent(const char *name, int len, |
| 203 | unsigned char *result, int idx) |
| 204 | { |
| 205 | unsigned char sha1[20]; |
| 206 | int ret = get_sha1_1(name, len, sha1); |
| 207 | struct commit *commit; |
| 208 | struct commit_list *p; |
| 209 | |
| 210 | if (ret) |
| 211 | return ret; |
| 212 | commit = lookup_commit_reference(sha1); |
| 213 | if (!commit) |
| 214 | return -1; |
| 215 | if (parse_commit(commit)) |
| 216 | return -1; |
| 217 | if (!idx) { |
| 218 | memcpy(result, commit->object.sha1, 20); |
| 219 | return 0; |
| 220 | } |
| 221 | p = commit->parents; |
| 222 | while (p) { |
| 223 | if (!--idx) { |
| 224 | memcpy(result, p->item->object.sha1, 20); |
| 225 | return 0; |
| 226 | } |
| 227 | p = p->next; |
| 228 | } |
| 229 | return -1; |
| 230 | } |
| 231 | |
Junio C Hamano | 4f7599a | 2005-08-21 02:43:54 -0700 | [diff] [blame] | 232 | static int get_nth_ancestor(const char *name, int len, |
| 233 | unsigned char *result, int generation) |
| 234 | { |
| 235 | unsigned char sha1[20]; |
| 236 | int ret = get_sha1_1(name, len, sha1); |
| 237 | if (ret) |
| 238 | return ret; |
| 239 | |
| 240 | while (generation--) { |
| 241 | struct commit *commit = lookup_commit_reference(sha1); |
| 242 | |
| 243 | if (!commit || parse_commit(commit) || !commit->parents) |
| 244 | return -1; |
| 245 | memcpy(sha1, commit->parents->item->object.sha1, 20); |
| 246 | } |
| 247 | memcpy(result, sha1, 20); |
| 248 | return 0; |
| 249 | } |
| 250 | |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 251 | static int get_sha1_1(const char *name, int len, unsigned char *sha1) |
| 252 | { |
| 253 | int parent, ret; |
Junio C Hamano | 4f7599a | 2005-08-21 02:43:54 -0700 | [diff] [blame] | 254 | const char *cp; |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 255 | |
| 256 | /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */ |
| 257 | if (len > 2 && name[len-2] == '^' && |
| 258 | name[len-1] >= '0' && name[len-1] <= '9') { |
| 259 | parent = name[len-1] - '0'; |
| 260 | len -= 2; |
| 261 | } |
Johannes Schindelin | ef0bd2e | 2005-08-10 05:07:36 +0200 | [diff] [blame] | 262 | else if (len > 1 && name[len-1] == '^') { |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 263 | parent = 1; |
Johannes Schindelin | ef0bd2e | 2005-08-10 05:07:36 +0200 | [diff] [blame] | 264 | len--; |
| 265 | } else |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 266 | parent = -1; |
| 267 | |
Linus Torvalds | 02a4a32 | 2005-08-13 10:50:56 -0700 | [diff] [blame] | 268 | if (parent >= 0) |
| 269 | return get_parent(name, len, sha1, parent); |
| 270 | |
Junio C Hamano | 4f7599a | 2005-08-21 02:43:54 -0700 | [diff] [blame] | 271 | /* "name~3" is "name^^^", |
| 272 | * "name~12" is "name^^^^^^^^^^^^", and |
| 273 | * "name~" and "name~0" are name -- not "name^0"! |
| 274 | */ |
| 275 | parent = 0; |
| 276 | for (cp = name + len - 1; name <= cp; cp--) { |
| 277 | int ch = *cp; |
| 278 | if ('0' <= ch && ch <= '9') |
| 279 | continue; |
| 280 | if (ch != '~') |
| 281 | parent = -1; |
| 282 | break; |
| 283 | } |
| 284 | if (!parent && *cp == '~') { |
| 285 | int len1 = cp - name; |
| 286 | cp++; |
| 287 | while (cp < name + len) |
| 288 | parent = parent * 10 + *cp++ - '0'; |
| 289 | return get_nth_ancestor(name, len1, sha1, parent); |
| 290 | } |
| 291 | |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 292 | ret = get_sha1_basic(name, len, sha1); |
| 293 | if (!ret) |
| 294 | return 0; |
Linus Torvalds | af61c6e | 2005-09-19 15:16:03 -0700 | [diff] [blame] | 295 | return get_short_sha1(name, len, sha1); |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | /* |
| 299 | * This is like "get_sha1_basic()", except it allows "sha1 expressions", |
| 300 | * notably "xyz^" for "parent of xyz" |
| 301 | */ |
| 302 | int get_sha1(const char *name, unsigned char *sha1) |
| 303 | { |
Junio C Hamano | 99a19b4 | 2005-10-02 21:40:51 -0700 | [diff] [blame] | 304 | prepare_alt_odb(); |
Junio C Hamano | 9938af6 | 2005-08-03 22:15:49 -0700 | [diff] [blame] | 305 | return get_sha1_1(name, strlen(name), sha1); |
| 306 | } |