]> asedeno.scripts.mit.edu Git - git.git/blob - fast-import.c
Created fast-import, a tool to quickly generating a pack from blobs.
[git.git] / fast-import.c
1 #include "builtin.h"
2 #include "cache.h"
3 #include "object.h"
4 #include "blob.h"
5 #include "delta.h"
6 #include "pack.h"
7 #include "csum-file.h"
8
9 static int max_depth = 10;
10 static unsigned long object_count;
11 static int packfd;
12 static int current_depth;
13 static void *lastdat;
14 static unsigned long lastdatlen;
15 static unsigned char lastsha1[20];
16
17 static ssize_t yread(int fd, void *buffer, size_t length)
18 {
19         ssize_t ret = 0;
20         while (ret < length) {
21                 ssize_t size = xread(fd, (char *) buffer + ret, length - ret);
22                 if (size < 0) {
23                         return size;
24                 }
25                 if (size == 0) {
26                         return ret;
27                 }
28                 ret += size;
29         }
30         return ret;
31 }
32
33 static ssize_t ywrite(int fd, void *buffer, size_t length)
34 {
35         ssize_t ret = 0;
36         while (ret < length) {
37                 ssize_t size = xwrite(fd, (char *) buffer + ret, length - ret);
38                 if (size < 0) {
39                         return size;
40                 }
41                 if (size == 0) {
42                         return ret;
43                 }
44                 ret += size;
45         }
46         return ret;
47 }
48
49 static unsigned long encode_header(enum object_type type, unsigned long size, unsigned char *hdr)
50 {
51         int n = 1;
52         unsigned char c;
53
54         if (type < OBJ_COMMIT || type > OBJ_DELTA)
55                 die("bad type %d", type);
56
57         c = (type << 4) | (size & 15);
58         size >>= 4;
59         while (size) {
60                 *hdr++ = c | 0x80;
61                 c = size & 0x7f;
62                 size >>= 7;
63                 n++;
64         }
65         *hdr = c;
66         return n;
67 }
68
69 static void write_blob (void *dat, unsigned long datlen)
70 {
71         z_stream s;
72         void *out, *delta;
73         unsigned char hdr[64];
74         unsigned long hdrlen, deltalen;
75
76         if (lastdat && current_depth < max_depth) {
77                 delta = diff_delta(lastdat, lastdatlen,
78                         dat, datlen,
79                         &deltalen, 0);
80         } else
81                 delta = 0;
82
83         memset(&s, 0, sizeof(s));
84         deflateInit(&s, zlib_compression_level);
85
86         if (delta) {
87                 current_depth++;
88                 s.next_in = delta;
89                 s.avail_in = deltalen;
90                 hdrlen = encode_header(OBJ_DELTA, deltalen, hdr);
91                 if (ywrite(packfd, hdr, hdrlen) != hdrlen)
92                         die("Can't write object header: %s", strerror(errno));
93                 if (ywrite(packfd, lastsha1, sizeof(lastsha1)) != sizeof(lastsha1))
94                         die("Can't write object base: %s", strerror(errno));
95         } else {
96                 current_depth = 0;
97                 s.next_in = dat;
98                 s.avail_in = datlen;
99                 hdrlen = encode_header(OBJ_BLOB, datlen, hdr);
100                 if (ywrite(packfd, hdr, hdrlen) != hdrlen)
101                         die("Can't write object header: %s", strerror(errno));
102         }
103
104         s.avail_out = deflateBound(&s, s.avail_in);
105         s.next_out = out = xmalloc(s.avail_out);
106         while (deflate(&s, Z_FINISH) == Z_OK)
107                 /* nothing */;
108         deflateEnd(&s);
109
110         if (ywrite(packfd, out, s.total_out) != s.total_out)
111                 die("Failed writing compressed data %s", strerror(errno));
112
113         free(out);
114         if (delta)
115                 free(delta);
116 }
117
118 static void init_pack_header ()
119 {
120         const char* magic = "PACK";
121         unsigned long version = 2;
122         unsigned long zero = 0;
123
124         version = htonl(version);
125
126         if (ywrite(packfd, (char*)magic, 4) != 4)
127                 die("Can't write pack magic: %s", strerror(errno));
128         if (ywrite(packfd, &version, 4) != 4)
129                 die("Can't write pack version: %s", strerror(errno));
130         if (ywrite(packfd, &zero, 4) != 4)
131                 die("Can't write 0 object count: %s", strerror(errno));
132 }
133
134 static void fixup_header_footer ()
135 {
136         SHA_CTX c;
137         char hdr[8];
138         unsigned char sha1[20];
139         unsigned long cnt;
140         char *buf;
141         size_t n;
142
143         if (lseek(packfd, 0, SEEK_SET) != 0)
144                 die("Failed seeking to start: %s", strerror(errno));
145
146         SHA1_Init(&c);
147         if (yread(packfd, hdr, 8) != 8)
148                 die("Failed reading header: %s", strerror(errno));
149         SHA1_Update(&c, hdr, 8);
150
151 fprintf(stderr, "%lu objects\n", object_count);
152         cnt = htonl(object_count);
153         SHA1_Update(&c, &cnt, 4);
154         if (ywrite(packfd, &cnt, 4) != 4)
155                 die("Failed writing object count: %s", strerror(errno));
156
157         buf = xmalloc(128 * 1024);
158         for (;;) {
159                 n = xread(packfd, buf, 128 * 1024);
160                 if (n <= 0)
161                         break;
162                 SHA1_Update(&c, buf, n);
163         }
164         free(buf);
165
166         SHA1_Final(sha1, &c);
167         if (ywrite(packfd, sha1, sizeof(sha1)) != sizeof(sha1))
168                 die("Failed writing pack checksum: %s", strerror(errno));
169 }
170
171 int main (int argc, const char **argv)
172 {
173         packfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
174         if (packfd < 0)
175                 die("Can't create pack file %s: %s", argv[1], strerror(errno));
176
177         init_pack_header();
178         for (;;) {
179                 unsigned long datlen;
180                 int hdrlen;
181                 void *dat;
182                 char hdr[128];
183                 unsigned char sha1[20];
184                 SHA_CTX c;
185
186                 if (yread(0, &datlen, 4) != 4)
187                         break;
188
189                 dat = xmalloc(datlen);
190                 if (yread(0, dat, datlen) != datlen)
191                         break;
192
193                 hdrlen = sprintf(hdr, "blob %lu", datlen) + 1;
194                 SHA1_Init(&c);
195                 SHA1_Update(&c, hdr, hdrlen);
196                 SHA1_Update(&c, dat, datlen);
197                 SHA1_Final(sha1, &c);
198
199                 write_blob(dat, datlen);
200                 object_count++;
201                 printf("%s\n", sha1_to_hex(sha1));
202                 fflush(stdout);
203
204                 if (lastdat)
205                         free(lastdat);
206                 lastdat = dat;
207                 lastdatlen = datlen;
208                 memcpy(lastsha1, sha1, sizeof(sha1));
209         }
210         fixup_header_footer();
211         close(packfd);
212
213         return 0;
214 }