]>
Commit | Line | Data |
---|---|---|
a6da9395 JR |
1 | #define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */ |
2 | #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ | |
bfac5d94 | 3 | #include <time.h> |
d98b46f8 | 4 | #include "cache.h" |
8e440259 PE |
5 | #include "blob.h" |
6 | #include "commit.h" | |
7 | #include "tree.h" | |
d98b46f8 LT |
8 | |
9 | struct entry { | |
10 | unsigned char old_sha1[20]; | |
11 | unsigned char new_sha1[20]; | |
12 | int converted; | |
13 | }; | |
14 | ||
15 | #define MAXOBJECTS (1000000) | |
16 | ||
17 | static struct entry *convert[MAXOBJECTS]; | |
18 | static int nr_convert; | |
19 | ||
20 | static struct entry * convert_entry(unsigned char *sha1); | |
21 | ||
22 | static struct entry *insert_new(unsigned char *sha1, int pos) | |
23 | { | |
90321c10 | 24 | struct entry *new = xcalloc(1, sizeof(struct entry)); |
d98b46f8 LT |
25 | memcpy(new->old_sha1, sha1, 20); |
26 | memmove(convert + pos + 1, convert + pos, (nr_convert - pos) * sizeof(struct entry *)); | |
27 | convert[pos] = new; | |
28 | nr_convert++; | |
29 | if (nr_convert == MAXOBJECTS) | |
30 | die("you're kidding me - hit maximum object limit"); | |
31 | return new; | |
32 | } | |
33 | ||
34 | static struct entry *lookup_entry(unsigned char *sha1) | |
35 | { | |
36 | int low = 0, high = nr_convert; | |
37 | ||
38 | while (low < high) { | |
39 | int next = (low + high) / 2; | |
40 | struct entry *n = convert[next]; | |
41 | int cmp = memcmp(sha1, n->old_sha1, 20); | |
42 | if (!cmp) | |
43 | return n; | |
44 | if (cmp < 0) { | |
45 | high = next; | |
46 | continue; | |
47 | } | |
48 | low = next+1; | |
49 | } | |
50 | return insert_new(sha1, low); | |
51 | } | |
52 | ||
d98b46f8 LT |
53 | static void convert_binary_sha1(void *buffer) |
54 | { | |
55 | struct entry *entry = convert_entry(buffer); | |
56 | memcpy(buffer, entry->new_sha1, 20); | |
57 | } | |
58 | ||
59 | static void convert_ascii_sha1(void *buffer) | |
60 | { | |
61 | unsigned char sha1[20]; | |
62 | struct entry *entry; | |
63 | ||
64 | if (get_sha1_hex(buffer, sha1)) | |
79db12e8 | 65 | die("expected sha1, got '%s'", (char*) buffer); |
d98b46f8 LT |
66 | entry = convert_entry(sha1); |
67 | memcpy(buffer, sha1_to_hex(entry->new_sha1), 40); | |
68 | } | |
69 | ||
4e81304a LT |
70 | static unsigned int convert_mode(unsigned int mode) |
71 | { | |
72 | unsigned int newmode; | |
73 | ||
74 | newmode = mode & S_IFMT; | |
75 | if (S_ISREG(mode)) | |
76 | newmode |= (mode & 0100) ? 0755 : 0644; | |
77 | return newmode; | |
78 | } | |
79 | ||
bfac5d94 | 80 | static int write_subdirectory(void *buffer, unsigned long size, const char *base, int baselen, unsigned char *result_sha1) |
d98b46f8 | 81 | { |
812666c8 | 82 | char *new = xmalloc(size); |
a44c9a5e | 83 | unsigned long newlen = 0; |
bfac5d94 | 84 | unsigned long used; |
bfac5d94 LT |
85 | |
86 | used = 0; | |
87 | while (size) { | |
88 | int len = 21 + strlen(buffer); | |
89 | char *path = strchr(buffer, ' '); | |
90 | unsigned char *sha1; | |
91 | unsigned int mode; | |
92 | char *slash, *origpath; | |
93 | ||
94 | if (!path || sscanf(buffer, "%o", &mode) != 1) | |
95 | die("bad tree conversion"); | |
4e81304a | 96 | mode = convert_mode(mode); |
bfac5d94 LT |
97 | path++; |
98 | if (memcmp(path, base, baselen)) | |
99 | break; | |
100 | origpath = path; | |
101 | path += baselen; | |
102 | slash = strchr(path, '/'); | |
103 | if (!slash) { | |
104 | newlen += sprintf(new + newlen, "%o %s", mode, path); | |
105 | new[newlen++] = '\0'; | |
106 | memcpy(new + newlen, buffer + len - 20, 20); | |
107 | newlen += 20; | |
108 | ||
109 | used += len; | |
110 | size -= len; | |
111 | buffer += len; | |
112 | continue; | |
113 | } | |
114 | ||
f220fb6b | 115 | newlen += sprintf(new + newlen, "%o %.*s", S_IFDIR, (int)(slash - path), path); |
bfac5d94 LT |
116 | new[newlen++] = 0; |
117 | sha1 = (unsigned char *)(new + newlen); | |
118 | newlen += 20; | |
119 | ||
120 | len = write_subdirectory(buffer, size, origpath, slash-origpath+1, sha1); | |
121 | ||
122 | used += len; | |
123 | size -= len; | |
124 | buffer += len; | |
125 | } | |
126 | ||
8e440259 | 127 | write_sha1_file(new, newlen, tree_type, result_sha1); |
bfac5d94 LT |
128 | free(new); |
129 | return used; | |
130 | } | |
131 | ||
132 | static void convert_tree(void *buffer, unsigned long size, unsigned char *result_sha1) | |
133 | { | |
134 | void *orig_buffer = buffer; | |
135 | unsigned long orig_size = size; | |
136 | ||
d98b46f8 LT |
137 | while (size) { |
138 | int len = 1+strlen(buffer); | |
139 | ||
140 | convert_binary_sha1(buffer + len); | |
141 | ||
142 | len += 20; | |
143 | if (len > size) | |
144 | die("corrupt tree object"); | |
145 | size -= len; | |
146 | buffer += len; | |
147 | } | |
bfac5d94 LT |
148 | |
149 | write_subdirectory(orig_buffer, orig_size, "", 0, result_sha1); | |
150 | } | |
151 | ||
152 | static unsigned long parse_oldstyle_date(const char *buf) | |
153 | { | |
154 | char c, *p; | |
155 | char buffer[100]; | |
156 | struct tm tm; | |
157 | const char *formats[] = { | |
158 | "%c", | |
159 | "%a %b %d %T", | |
160 | "%Z", | |
161 | "%Y", | |
162 | " %Y", | |
163 | NULL | |
164 | }; | |
165 | /* We only ever did two timezones in the bad old format .. */ | |
166 | const char *timezones[] = { | |
3f053897 | 167 | "PDT", "PST", "CEST", NULL |
bfac5d94 LT |
168 | }; |
169 | const char **fmt = formats; | |
170 | ||
171 | p = buffer; | |
172 | while (isspace(c = *buf)) | |
173 | buf++; | |
174 | while ((c = *buf++) != '\n') | |
175 | *p++ = c; | |
176 | *p++ = 0; | |
177 | buf = buffer; | |
178 | memset(&tm, 0, sizeof(tm)); | |
179 | do { | |
180 | const char *next = strptime(buf, *fmt, &tm); | |
181 | if (next) { | |
182 | if (!*next) | |
183 | return mktime(&tm); | |
184 | buf = next; | |
185 | } else { | |
186 | const char **p = timezones; | |
187 | while (isspace(*buf)) | |
188 | buf++; | |
189 | while (*p) { | |
190 | if (!memcmp(buf, *p, strlen(*p))) { | |
191 | buf += strlen(*p); | |
192 | break; | |
193 | } | |
194 | p++; | |
195 | } | |
196 | } | |
197 | fmt++; | |
198 | } while (*buf && *fmt); | |
199 | printf("left: %s\n", buf); | |
200 | return mktime(&tm); | |
201 | } | |
202 | ||
203 | static int convert_date_line(char *dst, void **buf, unsigned long *sp) | |
204 | { | |
205 | unsigned long size = *sp; | |
206 | char *line = *buf; | |
207 | char *next = strchr(line, '\n'); | |
208 | char *date = strchr(line, '>'); | |
209 | int len; | |
210 | ||
211 | if (!next || !date) | |
212 | die("missing or bad author/committer line %s", line); | |
213 | next++; date += 2; | |
214 | ||
215 | *buf = next; | |
216 | *sp = size - (next - line); | |
217 | ||
218 | len = date - line; | |
219 | memcpy(dst, line, len); | |
220 | dst += len; | |
221 | ||
222 | /* Is it already in new format? */ | |
223 | if (isdigit(*date)) { | |
224 | int datelen = next - date; | |
225 | memcpy(dst, date, datelen); | |
bfac5d94 LT |
226 | return len + datelen; |
227 | } | |
228 | ||
93256315 LT |
229 | /* |
230 | * Hacky hacky: one of the sparse old-style commits does not have | |
231 | * any date at all, but we can fake it by using the committer date. | |
232 | */ | |
233 | if (*date == '\n' && strchr(next, '>')) | |
234 | date = strchr(next, '>')+2; | |
235 | ||
bfac5d94 | 236 | return len + sprintf(dst, "%lu -0700\n", parse_oldstyle_date(date)); |
d98b46f8 LT |
237 | } |
238 | ||
bfac5d94 | 239 | static void convert_date(void *buffer, unsigned long size, unsigned char *result_sha1) |
d98b46f8 | 240 | { |
812666c8 | 241 | char *new = xmalloc(size + 100); |
a44c9a5e | 242 | unsigned long newlen = 0; |
812666c8 | 243 | |
bfac5d94 LT |
244 | // "tree <sha1>\n" |
245 | memcpy(new + newlen, buffer, 46); | |
246 | newlen += 46; | |
247 | buffer += 46; | |
248 | size -= 46; | |
249 | ||
250 | // "parent <sha1>\n" | |
251 | while (!memcmp(buffer, "parent ", 7)) { | |
252 | memcpy(new + newlen, buffer, 48); | |
253 | newlen += 48; | |
254 | buffer += 48; | |
255 | size -= 48; | |
256 | } | |
257 | ||
258 | // "author xyz <xyz> date" | |
259 | newlen += convert_date_line(new + newlen, &buffer, &size); | |
260 | // "committer xyz <xyz> date" | |
261 | newlen += convert_date_line(new + newlen, &buffer, &size); | |
262 | ||
263 | // Rest | |
264 | memcpy(new + newlen, buffer, size); | |
265 | newlen += size; | |
266 | ||
8e440259 PE |
267 | write_sha1_file(new, newlen, commit_type, result_sha1); |
268 | free(new); | |
bfac5d94 LT |
269 | } |
270 | ||
271 | static void convert_commit(void *buffer, unsigned long size, unsigned char *result_sha1) | |
272 | { | |
273 | void *orig_buffer = buffer; | |
274 | unsigned long orig_size = size; | |
275 | ||
4e81304a | 276 | if (memcmp(buffer, "tree ", 5)) |
79db12e8 | 277 | die("Bad commit '%s'", (char*) buffer); |
d98b46f8 LT |
278 | convert_ascii_sha1(buffer+5); |
279 | buffer += 46; /* "tree " + "hex sha1" + "\n" */ | |
280 | while (!memcmp(buffer, "parent ", 7)) { | |
281 | convert_ascii_sha1(buffer+7); | |
282 | buffer += 48; | |
283 | } | |
bfac5d94 | 284 | convert_date(orig_buffer, orig_size, result_sha1); |
d98b46f8 LT |
285 | } |
286 | ||
287 | static struct entry * convert_entry(unsigned char *sha1) | |
288 | { | |
289 | struct entry *entry = lookup_entry(sha1); | |
290 | char type[20]; | |
291 | void *buffer, *data; | |
a44c9a5e | 292 | unsigned long size; |
d98b46f8 LT |
293 | |
294 | if (entry->converted) | |
295 | return entry; | |
296 | data = read_sha1_file(sha1, type, &size); | |
297 | if (!data) | |
298 | die("unable to read object %s", sha1_to_hex(sha1)); | |
299 | ||
812666c8 | 300 | buffer = xmalloc(size); |
a44c9a5e | 301 | memcpy(buffer, data, size); |
8e440259 PE |
302 | |
303 | if (!strcmp(type, blob_type)) { | |
304 | write_sha1_file(buffer, size, blob_type, entry->new_sha1); | |
305 | } else if (!strcmp(type, tree_type)) | |
a44c9a5e | 306 | convert_tree(buffer, size, entry->new_sha1); |
8e440259 | 307 | else if (!strcmp(type, commit_type)) |
a44c9a5e | 308 | convert_commit(buffer, size, entry->new_sha1); |
d98b46f8 LT |
309 | else |
310 | die("unknown object type '%s' in %s", type, sha1_to_hex(sha1)); | |
d98b46f8 LT |
311 | entry->converted = 1; |
312 | free(buffer); | |
4e81304a | 313 | free(data); |
d98b46f8 LT |
314 | return entry; |
315 | } | |
316 | ||
317 | int main(int argc, char **argv) | |
318 | { | |
319 | unsigned char sha1[20]; | |
320 | struct entry *entry; | |
321 | ||
53228a5f JH |
322 | setup_git_directory(); |
323 | ||
3c249c95 | 324 | if (argc != 2 || get_sha1(argv[1], sha1)) |
215a7ad1 | 325 | usage("git-convert-objects <sha1>"); |
d98b46f8 LT |
326 | |
327 | entry = convert_entry(sha1); | |
328 | printf("new sha1: %s\n", sha1_to_hex(entry->new_sha1)); | |
329 | return 0; | |
330 | } |