@@ -173,6 +173,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
173
173
args -> convert = check_attr_export_subst (check );
174
174
}
175
175
176
+ if (args -> prefix ) {
177
+ static struct strbuf new_path = STRBUF_INIT ;
178
+ static struct strbuf buf = STRBUF_INIT ;
179
+ const char * rel ;
180
+
181
+ rel = relative_path (path_without_prefix , args -> prefix , & buf );
182
+
183
+ /*
184
+ * We don't add an entry for the current working
185
+ * directory when we are at the root; skip it also when
186
+ * we're in a subdirectory or submodule. Skip entries
187
+ * higher up as well.
188
+ */
189
+ if (!strcmp (rel , "./" ) || starts_with (rel , "../" ))
190
+ return S_ISDIR (mode ) ? READ_TREE_RECURSIVE : 0 ;
191
+
192
+ /* rel can refer to path, so don't edit it in place */
193
+ strbuf_reset (& new_path );
194
+ strbuf_add (& new_path , args -> base , args -> baselen );
195
+ strbuf_addstr (& new_path , rel );
196
+ strbuf_swap (& path , & new_path );
197
+ }
198
+
176
199
if (args -> verbose )
177
200
fprintf (stderr , "%.*s\n" , (int )path .len , path .buf );
178
201
@@ -408,15 +431,41 @@ static int reject_entry(const struct object_id *oid UNUSED,
408
431
return ret ;
409
432
}
410
433
434
+ static int reject_outside (const struct object_id * oid UNUSED ,
435
+ struct strbuf * base , const char * filename ,
436
+ unsigned mode , void * context )
437
+ {
438
+ struct archiver_args * args = context ;
439
+ struct strbuf buf = STRBUF_INIT ;
440
+ struct strbuf path = STRBUF_INIT ;
441
+ int ret = 0 ;
442
+
443
+ if (S_ISDIR (mode ))
444
+ return READ_TREE_RECURSIVE ;
445
+
446
+ strbuf_addbuf (& path , base );
447
+ strbuf_addstr (& path , filename );
448
+ if (starts_with (relative_path (path .buf , args -> prefix , & buf ), "../" ))
449
+ ret = -1 ;
450
+ strbuf_release (& buf );
451
+ strbuf_release (& path );
452
+ return ret ;
453
+ }
454
+
411
455
static int path_exists (struct archiver_args * args , const char * path )
412
456
{
413
457
const char * paths [] = { path , NULL };
414
458
struct path_exists_context ctx ;
415
459
int ret ;
416
460
417
461
ctx .args = args ;
418
- parse_pathspec (& ctx .pathspec , 0 , 0 , "" , paths );
462
+ parse_pathspec (& ctx .pathspec , 0 , PATHSPEC_PREFER_CWD ,
463
+ args -> prefix , paths );
419
464
ctx .pathspec .recursive = 1 ;
465
+ if (args -> prefix && read_tree (args -> repo , args -> tree , & ctx .pathspec ,
466
+ reject_outside , args ))
467
+ die (_ ("pathspec '%s' matches files outside the "
468
+ "current directory" ), path );
420
469
ret = read_tree (args -> repo , args -> tree ,
421
470
& ctx .pathspec ,
422
471
reject_entry , & ctx );
@@ -432,9 +481,8 @@ static void parse_pathspec_arg(const char **pathspec,
432
481
* Also if pathspec patterns are dependent, we're in big
433
482
* trouble as we test each one separately
434
483
*/
435
- parse_pathspec (& ar_args -> pathspec , 0 ,
436
- PATHSPEC_PREFER_FULL ,
437
- "" , pathspec );
484
+ parse_pathspec (& ar_args -> pathspec , 0 , PATHSPEC_PREFER_CWD ,
485
+ ar_args -> prefix , pathspec );
438
486
ar_args -> pathspec .recursive = 1 ;
439
487
if (pathspec ) {
440
488
while (* pathspec ) {
@@ -446,8 +494,7 @@ static void parse_pathspec_arg(const char **pathspec,
446
494
}
447
495
448
496
static void parse_treeish_arg (const char * * argv ,
449
- struct archiver_args * ar_args , const char * prefix ,
450
- int remote )
497
+ struct archiver_args * ar_args , int remote )
451
498
{
452
499
const char * name = argv [0 ];
453
500
const struct object_id * commit_oid ;
@@ -487,20 +534,6 @@ static void parse_treeish_arg(const char **argv,
487
534
if (!tree )
488
535
die (_ ("not a tree object: %s" ), oid_to_hex (& oid ));
489
536
490
- if (prefix ) {
491
- struct object_id tree_oid ;
492
- unsigned short mode ;
493
- int err ;
494
-
495
- err = get_tree_entry (ar_args -> repo ,
496
- & tree -> object .oid ,
497
- prefix , & tree_oid ,
498
- & mode );
499
- if (err || !S_ISDIR (mode ))
500
- die (_ ("current working directory is untracked" ));
501
-
502
- tree = parse_tree_indirect (& tree_oid );
503
- }
504
537
ar_args -> refname = ref ;
505
538
ar_args -> tree = tree ;
506
539
ar_args -> commit_oid = commit_oid ;
@@ -718,7 +751,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
718
751
setup_git_directory ();
719
752
}
720
753
721
- parse_treeish_arg (argv , & args , prefix , remote );
754
+ parse_treeish_arg (argv , & args , remote );
722
755
parse_pathspec_arg (argv + 1 , & args );
723
756
724
757
rc = ar -> write_archive (ar , & args );
0 commit comments