1 #define _XOPEN_SOURCE /* glibc2 needs this */
7 unsigned char old_sha1
[20];
8 unsigned char new_sha1
[20];
12 #define MAXOBJECTS (1000000)
14 static struct entry
*convert
[MAXOBJECTS
];
15 static int nr_convert
;
17 static struct entry
* convert_entry(unsigned char *sha1
);
19 static struct entry
*insert_new(unsigned char *sha1
, int pos
)
21 struct entry
*new = malloc(sizeof(struct entry
));
23 memset(new, 0, sizeof(*new));
24 memcpy(new->old_sha1
, sha1
, 20);
25 memmove(convert
+ pos
+ 1, convert
+ pos
, (nr_convert
- pos
) * sizeof(struct entry
*));
28 if (nr_convert
== MAXOBJECTS
)
29 die("you're kidding me - hit maximum object limit");
33 static struct entry
*lookup_entry(unsigned char *sha1
)
35 int low
= 0, high
= nr_convert
;
38 int next
= (low
+ high
) / 2;
39 struct entry
*n
= convert
[next
];
40 int cmp
= memcmp(sha1
, n
->old_sha1
, 20);
49 return insert_new(sha1
, low
);
52 static void convert_binary_sha1(void *buffer
)
54 struct entry
*entry
= convert_entry(buffer
);
55 memcpy(buffer
, entry
->new_sha1
, 20);
58 static void convert_ascii_sha1(void *buffer
)
60 unsigned char sha1
[20];
63 if (get_sha1_hex(buffer
, sha1
))
65 entry
= convert_entry(sha1
);
66 memcpy(buffer
, sha1_to_hex(entry
->new_sha1
), 40);
69 #define ORIG_OFFSET (40)
71 static int prepend_integer(char *buffer
, unsigned val
, int i
)
75 buffer
[--i
] = '0' + (val
% 10);
82 static int write_subdirectory(void *buffer
, unsigned long size
, const char *base
, int baselen
, unsigned char *result_sha1
)
84 char *new = malloc(size
+ ORIG_OFFSET
);
85 unsigned long newlen
= ORIG_OFFSET
;
91 int len
= 21 + strlen(buffer
);
92 char *path
= strchr(buffer
, ' ');
95 char *slash
, *origpath
;
97 if (!path
|| sscanf(buffer
, "%o", &mode
) != 1)
98 die("bad tree conversion");
100 if (memcmp(path
, base
, baselen
))
104 slash
= strchr(path
, '/');
106 newlen
+= sprintf(new + newlen
, "%o %s", mode
, path
);
107 new[newlen
++] = '\0';
108 memcpy(new + newlen
, buffer
+ len
- 20, 20);
117 newlen
+= sprintf(new + newlen
, "%o %.*s", S_IFDIR
, slash
- path
, path
);
119 sha1
= (unsigned char *)(new + newlen
);
122 len
= write_subdirectory(buffer
, size
, origpath
, slash
-origpath
+1, sha1
);
129 i
= prepend_integer(new, newlen
- ORIG_OFFSET
, ORIG_OFFSET
);
131 memcpy(new + i
, "tree ", 5);
133 write_sha1_file(new + i
, newlen
- i
, result_sha1
);
138 static void convert_tree(void *buffer
, unsigned long size
, unsigned char *result_sha1
)
140 void *orig_buffer
= buffer
;
141 unsigned long orig_size
= size
;
144 int len
= 1+strlen(buffer
);
146 convert_binary_sha1(buffer
+ len
);
150 die("corrupt tree object");
155 write_subdirectory(orig_buffer
, orig_size
, "", 0, result_sha1
);
158 static unsigned long parse_oldstyle_date(const char *buf
)
163 const char *formats
[] = {
171 /* We only ever did two timezones in the bad old format .. */
172 const char *timezones
[] = {
173 "PDT", "PST", "CEST", NULL
175 const char **fmt
= formats
;
178 while (isspace(c
= *buf
))
180 while ((c
= *buf
++) != '\n')
184 memset(&tm
, 0, sizeof(tm
));
186 const char *next
= strptime(buf
, *fmt
, &tm
);
192 const char **p
= timezones
;
193 while (isspace(*buf
))
196 if (!memcmp(buf
, *p
, strlen(*p
))) {
204 } while (*buf
&& *fmt
);
205 printf("left: %s\n", buf
);
209 static int convert_date_line(char *dst
, void **buf
, unsigned long *sp
)
211 unsigned long size
= *sp
;
213 char *next
= strchr(line
, '\n');
214 char *date
= strchr(line
, '>');
218 die("missing or bad author/committer line %s", line
);
222 *sp
= size
- (next
- line
);
225 memcpy(dst
, line
, len
);
228 /* Is it already in new format? */
229 if (isdigit(*date
)) {
230 int datelen
= next
- date
;
231 memcpy(dst
, date
, datelen
);
232 return len
+ datelen
;
236 * Hacky hacky: one of the sparse old-style commits does not have
237 * any date at all, but we can fake it by using the committer date.
239 if (*date
== '\n' && strchr(next
, '>'))
240 date
= strchr(next
, '>')+2;
242 return len
+ sprintf(dst
, "%lu -0700\n", parse_oldstyle_date(date
));
245 static void convert_date(void *buffer
, unsigned long size
, unsigned char *result_sha1
)
247 char *new = malloc(size
+ ORIG_OFFSET
+ 100);
248 unsigned long newlen
= ORIG_OFFSET
;
252 memcpy(new + newlen
, buffer
, 46);
258 while (!memcmp(buffer
, "parent ", 7)) {
259 memcpy(new + newlen
, buffer
, 48);
265 // "author xyz <xyz> date"
266 newlen
+= convert_date_line(new + newlen
, &buffer
, &size
);
267 // "committer xyz <xyz> date"
268 newlen
+= convert_date_line(new + newlen
, &buffer
, &size
);
271 memcpy(new + newlen
, buffer
, size
);
274 i
= prepend_integer(new, newlen
- ORIG_OFFSET
, ORIG_OFFSET
);
276 memcpy(new + i
, "commit ", 7);
278 write_sha1_file(new + i
, newlen
- i
, result_sha1
);
282 static void convert_commit(void *buffer
, unsigned long size
, unsigned char *result_sha1
)
284 void *orig_buffer
= buffer
;
285 unsigned long orig_size
= size
;
287 convert_ascii_sha1(buffer
+5);
288 buffer
+= 46; /* "tree " + "hex sha1" + "\n" */
289 while (!memcmp(buffer
, "parent ", 7)) {
290 convert_ascii_sha1(buffer
+7);
293 convert_date(orig_buffer
, orig_size
, result_sha1
);
296 static struct entry
* convert_entry(unsigned char *sha1
)
298 struct entry
*entry
= lookup_entry(sha1
);
301 unsigned long size
, offset
;
303 if (entry
->converted
)
305 data
= read_sha1_file(sha1
, type
, &size
);
307 die("unable to read object %s", sha1_to_hex(sha1
));
309 buffer
= malloc(size
+ 100);
310 offset
= sprintf(buffer
, "%s %lu", type
, size
)+1;
311 memcpy(buffer
+ offset
, data
, size
);
313 if (!strcmp(type
, "blob")) {
314 write_sha1_file(buffer
, size
+ offset
, entry
->new_sha1
);
315 } else if (!strcmp(type
, "tree"))
316 convert_tree(buffer
+ offset
, size
, entry
->new_sha1
);
317 else if (!strcmp(type
, "commit"))
318 convert_commit(buffer
+ offset
, size
, entry
->new_sha1
);
320 die("unknown object type '%s' in %s", type
, sha1_to_hex(sha1
));
321 entry
->converted
= 1;
326 int main(int argc
, char **argv
)
328 unsigned char sha1
[20];
331 if (argc
!= 2 || get_sha1_hex(argv
[1], sha1
))
332 usage("convert-cache <sha1>");
334 entry
= convert_entry(sha1
);
335 printf("new sha1: %s\n", sha1_to_hex(entry
->new_sha1
));