@matheusbsbs / matheus-bagliano / commits / 562e25abea
Fork 0

archive: centralize archive entry writing

Add the exported function write_archive_entries() to archive.c, which uses the new ability of read_tree_recursive() to pass a context pointer to its callback in order to centralize previously duplicated code. The new callback function write_archive_entry() does the work that every archiver backend needs to do: loading file contents, entering subdirectories, handling file attributes, constructing the full path of the entry. All that done, it calls the backend specific write_archive_entry_fn_t function. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Jul 14, 2008 at 21:22 UTC 562e25abea9f1f2d443053279c009a88d81a592b
4 files changed +133 -154
archive-tar.c
+37 -79
@@ -13,11 +13,7 @@
13 static char block[BLOCKSIZE];
14 static unsigned long offset;
15
16 -static time_t archive_time;
16 static int tar_umask = 002;
18 -static int verbose;
19 -static const struct commit *commit;
20 -static size_t base_len;
17
18 /* writes out the whole block, but only if it is full */
19 static void write_if_needed(void)
@@ -114,22 +110,24 @@ static unsigned int ustar_header_chksum(const struct ustar_header *header)
110 return chksum;
111 }
112
117 -static int get_path_prefix(const struct strbuf *path, int maxlen)
113 +static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
114 {
119 - int i = path->len;
115 + size_t i = pathlen;
116 if (i > maxlen)
117 i = maxlen;
118 do {
119 i--;
124 - } while (i > 0 && path->buf[i] != '/');
120 + } while (i > 0 && path[i] != '/');
121 return i;
122 }
123
128 -static void write_entry(const unsigned char *sha1, struct strbuf *path,
129 - unsigned int mode, void *buffer, unsigned long size)
124 +static int write_tar_entry(struct archiver_args *args,
125 + const unsigned char *sha1, const char *path, size_t pathlen,
126 + unsigned int mode, void *buffer, unsigned long size)
127 {
128 struct ustar_header header;
129 struct strbuf ext_header;
130 + int err = 0;
131
132 memset(&header, 0, sizeof(header));
133 strbuf_init(&ext_header, 0);
@@ -143,8 +141,6 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
141 mode = 0100666;
142 sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
143 } else {
146 - if (verbose)
147 - fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
144 if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
145 *header.typeflag = TYPEFLAG_DIR;
146 mode = (mode | 0777) & ~tar_umask;
@@ -155,24 +151,24 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
151 *header.typeflag = TYPEFLAG_REG;
152 mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
153 } else {
158 - error("unsupported file mode: 0%o (SHA1: %s)",
159 - mode, sha1_to_hex(sha1));
160 - return;
154 + return error("unsupported file mode: 0%o (SHA1: %s)",
155 + mode, sha1_to_hex(sha1));
156 }
162 - if (path->len > sizeof(header.name)) {
163 - int plen = get_path_prefix(path, sizeof(header.prefix));
164 - int rest = path->len - plen - 1;
157 + if (pathlen > sizeof(header.name)) {
158 + size_t plen = get_path_prefix(path, pathlen,
159 + sizeof(header.prefix));
160 + size_t rest = pathlen - plen - 1;
161 if (plen > 0 && rest <= sizeof(header.name)) {
166 - memcpy(header.prefix, path->buf, plen);
167 - memcpy(header.name, path->buf + plen + 1, rest);
162 + memcpy(header.prefix, path, plen);
163 + memcpy(header.name, path + plen + 1, rest);
164 } else {
165 sprintf(header.name, "%s.data",
166 sha1_to_hex(sha1));
167 strbuf_append_ext_header(&ext_header, "path",
172 - path->buf, path->len);
168 + path, pathlen);
169 }
170 } else
175 - memcpy(header.name, path->buf, path->len);
171 + memcpy(header.name, path, pathlen);
172 }
173
174 if (S_ISLNK(mode) && buffer) {
@@ -187,7 +183,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
183
184 sprintf(header.mode, "%07o", mode & 07777);
185 sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
190 - sprintf(header.mtime, "%011lo", archive_time);
186 + sprintf(header.mtime, "%011lo", args->time);
187
188 sprintf(header.uid, "%07o", 0);
189 sprintf(header.gid, "%07o", 0);
@@ -202,22 +198,30 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
198 sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
199
200 if (ext_header.len > 0) {
205 - write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
201 + err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf,
202 + ext_header.len);
203 + if (err)
204 + return err;
205 }
206 strbuf_release(&ext_header);
207 write_blocked(&header, sizeof(header));
208 if (S_ISREG(mode) && buffer && size > 0)
209 write_blocked(buffer, size);
210 + return err;
211 }
212
213 -static void write_global_extended_header(const unsigned char *sha1)
213 +static int write_global_extended_header(struct archiver_args *args)
214 {
215 + const unsigned char *sha1 = args->commit_sha1;
216 struct strbuf ext_header;
217 + int err;
218
219 strbuf_init(&ext_header, 0);
220 strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
219 - write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
221 + err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf,
222 + ext_header.len);
223 strbuf_release(&ext_header);
224 + return err;
225 }
226
227 static int git_tar_config(const char *var, const char *value, void *cb)
@@ -234,63 +238,17 @@ static int git_tar_config(const char *var, const char *value, void *cb)
238 return git_default_config(var, value, cb);
239 }
240
237 -static int write_tar_entry(const unsigned char *sha1, const char *base,
238 - int baselen, const char *filename, unsigned mode, int stage,
239 - void *context)
240 -{
241 - static struct strbuf path = STRBUF_INIT;
242 - void *buffer;
243 - enum object_type type;
244 - unsigned long size;
245 -
246 - strbuf_reset(&path);
247 - strbuf_grow(&path, PATH_MAX);
248 - strbuf_add(&path, base, baselen);
249 - strbuf_addstr(&path, filename);
250 - if (is_archive_path_ignored(path.buf + base_len))
251 - return 0;
252 - if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
253 - strbuf_addch(&path, '/');
254 - buffer = NULL;
255 - size = 0;
256 - } else {
257 - buffer = sha1_file_to_archive(path.buf + base_len, sha1, mode,
258 - &type, &size, commit);
259 - if (!buffer)
260 - die("cannot read %s", sha1_to_hex(sha1));
261 - }
262 -
263 - write_entry(sha1, &path, mode, buffer, size);
264 - free(buffer);
265 -
266 - return READ_TREE_RECURSIVE;
267 -}
268 -
241 int write_tar_archive(struct archiver_args *args)
242 {
271 - git_config(git_tar_config, NULL);
243 + int err = 0;
244
273 - archive_time = args->time;
274 - verbose = args->verbose;
275 - commit = args->commit;
276 - base_len = args->baselen;
245 + git_config(git_tar_config, NULL);
246
247 if (args->commit_sha1)
279 - write_global_extended_header(args->commit_sha1);
280 -
281 - if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
282 - char *base = xstrdup(args->base);
283 - int baselen = strlen(base);
284 -
285 - while (baselen > 0 && base[baselen - 1] == '/')
286 - base[--baselen] = '\0';
287 - write_tar_entry(args->tree->object.sha1, "", 0, base, 040777,
288 - 0, NULL);
289 - free(base);
290 - }
291 - read_tree_recursive(args->tree, args->base, args->baselen, 0,
292 - args->pathspec, write_tar_entry, NULL);
293 - write_trailer();
294 -
295 - return 0;
248 + err = write_global_extended_header(args);
249 + if (!err)
250 + err = write_archive_entries(args, write_tar_entry);
251 + if (!err)
252 + write_trailer();
253 + return err;
254 }
archive-zip.c
+15 -75
@@ -9,11 +9,8 @@
9 #include "builtin.h"
10 #include "archive.h"
11
12 -static int verbose;
12 static int zip_date;
13 static int zip_time;
15 -static const struct commit *commit;
16 -static size_t base_len;
14
15 static unsigned char *zip_dir;
16 static unsigned int zip_dir_size;
@@ -128,33 +125,9 @@ static void *zlib_deflate(void *data, unsigned long size,
125 return buffer;
126 }
127
131 -static char *construct_path(const char *base, int baselen,
132 - const char *filename, int isdir, int *pathlen)
133 -{
134 - int filenamelen = strlen(filename);
135 - int len = baselen + filenamelen;
136 - char *path, *p;
137 -
138 - if (isdir)
139 - len++;
140 - p = path = xmalloc(len + 1);
141 -
142 - memcpy(p, base, baselen);
143 - p += baselen;
144 - memcpy(p, filename, filenamelen);
145 - p += filenamelen;
146 - if (isdir)
147 - *p++ = '/';
148 - *p = '\0';
149 -
150 - *pathlen = len;
151 -
152 - return path;
153 -}
154 -
155 -static int write_zip_entry(const unsigned char *sha1, const char *base,
156 - int baselen, const char *filename, unsigned mode, int stage,
157 - void *context)
128 +static int write_zip_entry(struct archiver_args *args,
129 + const unsigned char *sha1, const char *path, size_t pathlen,
130 + unsigned int mode, void *buffer, unsigned long size)
131 {
132 struct zip_local_header header;
133 struct zip_dir_header dirent;
@@ -163,33 +136,20 @@ static int write_zip_entry(const unsigned char *sha1, const char *base,
136 unsigned long uncompressed_size;
137 unsigned long crc;
138 unsigned long direntsize;
166 - unsigned long size;
139 int method;
168 - int result = -1;
169 - int pathlen;
140 unsigned char *out;
171 - char *path;
172 - enum object_type type;
173 - void *buffer = NULL;
141 void *deflated = NULL;
142
143 crc = crc32(0, NULL, 0);
144
178 - path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
179 - if (is_archive_path_ignored(path + base_len))
180 - return 0;
181 - if (verbose)
182 - fprintf(stderr, "%s\n", path);
145 if (pathlen > 0xffff) {
184 - error("path too long (%d chars, SHA1: %s): %s", pathlen,
185 - sha1_to_hex(sha1), path);
186 - goto out;
146 + return error("path too long (%d chars, SHA1: %s): %s",
147 + (int)pathlen, sha1_to_hex(sha1), path);
148 }
149
150 if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
151 method = 0;
152 attr2 = 16;
192 - result = (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
153 out = NULL;
154 uncompressed_size = 0;
155 compressed_size = 0;
@@ -199,19 +159,13 @@ static int write_zip_entry(const unsigned char *sha1, const char *base,
159 (mode & 0111) ? ((mode) << 16) : 0;
160 if (S_ISREG(mode) && zlib_compression_level != 0)
161 method = 8;
202 - result = 0;
203 - buffer = sha1_file_to_archive(path + base_len, sha1, mode,
204 - &type, &size, commit);
205 - if (!buffer)
206 - die("cannot read %s", sha1_to_hex(sha1));
162 crc = crc32(crc, buffer, size);
163 out = buffer;
164 uncompressed_size = size;
165 compressed_size = size;
166 } else {
212 - error("unsupported file mode: 0%o (SHA1: %s)", mode,
213 - sha1_to_hex(sha1));
214 - goto out;
167 + return error("unsupported file mode: 0%o (SHA1: %s)", mode,
168 + sha1_to_hex(sha1));
169 }
170
171 if (method == 8) {
@@ -278,12 +232,9 @@ static int write_zip_entry(const unsigned char *sha1, const char *base,
232 zip_offset += compressed_size;
233 }
234
281 -out:
282 - free(buffer);
235 free(deflated);
284 - free(path);
236
286 - return result;
237 + return 0;
238 }
239
240 static void write_zip_trailer(const unsigned char *sha1)
@@ -316,31 +267,20 @@ static void dos_time(time_t *time, int *dos_date, int *dos_time)
267
268 int write_zip_archive(struct archiver_args *args)
269 {
270 + int err;
271 +
272 dos_time(&args->time, &zip_date, &zip_time);
273
274 zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
275 zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
323 - verbose = args->verbose;
324 - commit = args->commit;
325 - base_len = args->baselen;
326 -
327 - if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
328 - char *base = xstrdup(args->base);
329 - int baselen = strlen(base);
330 -
331 - while (baselen > 0 && base[baselen - 1] == '/')
332 - base[--baselen] = '\0';
333 - write_zip_entry(args->tree->object.sha1, "", 0, base, 040777,
334 - 0, NULL);
335 - free(base);
336 - }
337 - read_tree_recursive(args->tree, args->base, args->baselen, 0,
338 - args->pathspec, write_zip_entry, NULL);
339 - write_zip_trailer(args->commit_sha1);
276 +
277 + err = write_archive_entries(args, write_zip_entry);
278 + if (!err)
279 + write_zip_trailer(args->commit_sha1);
280
281 free(zip_dir);
282
343 - return 0;
283 + return err;
284 }
285
286 void *parse_extra_zip_args(int argc, const char **argv)
archive.c
+77
@@ -1,6 +1,7 @@
1 #include "cache.h"
2 #include "commit.h"
3 #include "attr.h"
4 +#include "archive.h"
5
6 static void format_subst(const struct commit *commit,
7 const char *src, size_t len,
@@ -95,3 +96,79 @@ int is_archive_path_ignored(const char *path)
96 return 0;
97 return ATTR_TRUE(check[0].value);
98 }
99 +
100 +struct archiver_context {
101 + struct archiver_args *args;
102 + write_archive_entry_fn_t write_entry;
103 +};
104 +
105 +static int write_archive_entry(const unsigned char *sha1, const char *base,
106 + int baselen, const char *filename, unsigned mode, int stage,
107 + void *context)
108 +{
109 + static struct strbuf path = STRBUF_INIT;
110 + struct archiver_context *c = context;
111 + struct archiver_args *args = c->args;
112 + write_archive_entry_fn_t write_entry = c->write_entry;
113 + int err;
114 + enum object_type type;
115 + unsigned long size;
116 + void *buffer;
117 +
118 + strbuf_reset(&path);
119 + strbuf_grow(&path, PATH_MAX);
120 + strbuf_add(&path, base, baselen);
121 + strbuf_addstr(&path, filename);
122 +
123 + if (is_archive_path_ignored(path.buf + args->baselen))
124 + return 0;
125 +
126 + if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
127 + strbuf_addch(&path, '/');
128 + if (args->verbose)
129 + fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
130 + err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
131 + if (err)
132 + return err;
133 + return READ_TREE_RECURSIVE;
134 + }
135 +
136 + buffer = sha1_file_to_archive(path.buf + args->baselen, sha1, mode,
137 + &type, &size, args->commit);
138 + if (!buffer)
139 + return error("cannot read %s", sha1_to_hex(sha1));
140 + if (args->verbose)
141 + fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
142 + err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
143 + free(buffer);
144 + return err;
145 +}
146 +
147 +int write_archive_entries(struct archiver_args *args,
148 + write_archive_entry_fn_t write_entry)
149 +{
150 + struct archiver_context context;
151 + int err;
152 +
153 + if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
154 + size_t len = args->baselen;
155 +
156 + while (len > 1 && args->base[len - 2] == '/')
157 + len--;
158 + if (args->verbose)
159 + fprintf(stderr, "%.*s\n", (int)len, args->base);
160 + err = write_entry(args, args->tree->object.sha1, args->base,
161 + len, 040777, NULL, 0);
162 + if (err)
163 + return err;
164 + }
165 +
166 + context.args = args;
167 + context.write_entry = write_entry;
168 +
169 + err = read_tree_recursive(args->tree, args->base, args->baselen, 0,
170 + args->pathspec, write_archive_entry, &context);
171 + if (err == READ_TREE_RECURSIVE)
172 + err = 0;
173 + return err;
174 +}
archive.h
+4
@@ -20,6 +20,8 @@ typedef int (*write_archive_fn_t)(struct archiver_args *);
20
21 typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
22
23 +typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
24 +
25 struct archiver {
26 const char *name;
27 write_archive_fn_t write_archive;
@@ -44,4 +46,6 @@ extern void *parse_extra_zip_args(int argc, const char **argv);
46 extern void *sha1_file_to_archive(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size, const struct commit *commit);
47 extern int is_archive_path_ignored(const char *path);
48
49 +extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
50 +
51 #endif /* ARCHIVE_H */