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