5
#include "archive.h"
6
#include "parse-options.h"
7
#include "unpack-trees.h"
8
+#include "dir.h"
9
10
static char const * const archive_usage[] = {
11
N_("git archive [options] <tree-ish> [<path>...]"),
98
check[1].attr = attr_export_subst;
99
}
100
101
+struct directory {
102
+ struct directory *up;
103
+ unsigned char sha1[20];
104
+ int baselen, len;
105
+ unsigned mode;
106
+ int stage;
107
+ char path[FLEX_ARRAY];
108
+};
109
+
110
struct archiver_context {
111
struct archiver_args *args;
112
write_archive_entry_fn_t write_entry;
113
+ struct directory *bottom;
114
};
115
116
static int write_archive_entry(const unsigned char *sha1, const char *base,
156
return write_entry(args, sha1, path.buf, path.len, mode);
157
}
158
159
+static void queue_directory(const unsigned char *sha1,
160
+ const char *base, int baselen, const char *filename,
161
+ unsigned mode, int stage, struct archiver_context *c)
162
+{
163
+ struct directory *d;
164
+ d = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));
165
+ d->up = c->bottom;
166
+ d->baselen = baselen;
167
+ d->mode = mode;
168
+ d->stage = stage;
169
+ c->bottom = d;
170
+ d->len = sprintf(d->path, "%.*s%s/", baselen, base, filename);
171
+ hashcpy(d->sha1, sha1);
172
+}
173
+
174
+static int write_directory(struct archiver_context *c)
175
+{
176
+ struct directory *d = c->bottom;
177
+ int ret;
178
+
179
+ if (!d)
180
+ return 0;
181
+ c->bottom = d->up;
182
+ d->path[d->len - 1] = '\0'; /* no trailing slash */
183
+ ret =
184
+ write_directory(c) ||
185
+ write_archive_entry(d->sha1, d->path, d->baselen,
186
+ d->path + d->baselen, d->mode,
187
+ d->stage, c) != READ_TREE_RECURSIVE;
188
+ free(d);
189
+ return ret ? -1 : 0;
190
+}
191
+
192
+static int queue_or_write_archive_entry(const unsigned char *sha1,
193
+ const char *base, int baselen, const char *filename,
194
+ unsigned mode, int stage, void *context)
195
+{
196
+ struct archiver_context *c = context;
197
+
198
+ while (c->bottom &&
199
+ !(baselen >= c->bottom->len &&
200
+ !strncmp(base, c->bottom->path, c->bottom->len))) {
201
+ struct directory *next = c->bottom->up;
202
+ free(c->bottom);
203
+ c->bottom = next;
204
+ }
205
+
206
+ if (S_ISDIR(mode)) {
207
+ queue_directory(sha1, base, baselen, filename,
208
+ mode, stage, c);
209
+ return READ_TREE_RECURSIVE;
210
+ }
211
+
212
+ if (write_directory(c))
213
+ return -1;
214
+ return write_archive_entry(sha1, base, baselen, filename, mode,
215
+ stage, context);
216
+}
217
+
218
int write_archive_entries(struct archiver_args *args,
219
write_archive_entry_fn_t write_entry)
220
{
236
return err;
237
}
238
239
+ memset(&context, 0, sizeof(context));
240
context.args = args;
241
context.write_entry = write_entry;
242
257
}
258
259
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
189
- write_archive_entry, &context);
260
+ args->pathspec.has_wildcard ?
261
+ queue_or_write_archive_entry :
262
+ write_archive_entry,
263
+ &context);
264
if (err == READ_TREE_RECURSIVE)
265
err = 0;
266
+ while (context.bottom) {
267
+ struct directory *next = context.bottom->up;
268
+ free(context.bottom);
269
+ context.bottom = next;
270
+ }
271
return err;
272
}
273
289
int baselen, const char *filename, unsigned mode,
290
int stage, void *context)
291
{
213
- return -1;
292
+ int ret = -1;
293
+ if (S_ISDIR(mode)) {
294
+ struct strbuf sb = STRBUF_INIT;
295
+ strbuf_addstr(&sb, base);
296
+ strbuf_addstr(&sb, filename);
297
+ if (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))
298
+ ret = READ_TREE_RECURSIVE;
299
+ strbuf_release(&sb);
300
+ }
301
+ return ret;
302
}
303
304
static int path_exists(struct tree *tree, const char *path)
308
int ret;
309
310
parse_pathspec(&pathspec, 0, 0, "", paths);
223
- ret = read_tree_recursive(tree, "", 0, 0, &pathspec, reject_entry, NULL);
311
+ pathspec.recursive = 1;
312
+ ret = read_tree_recursive(tree, "", 0, 0, &pathspec,
313
+ reject_entry, &pathspec);
314
free_pathspec(&pathspec);
315
return ret != 0;
316
}
326
parse_pathspec(&ar_args->pathspec, 0,
327
PATHSPEC_PREFER_FULL,
328
"", pathspec);
329
+ ar_args->pathspec.recursive = 1;
330
if (pathspec) {
331
while (*pathspec) {
332
if (**pathspec && !path_exists(ar_args->tree, *pathspec))