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 */