@@ -173,6 +173,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
173173 args -> convert = check_attr_export_subst (check );
174174 }
175175
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+
176199 if (args -> verbose )
177200 fprintf (stderr , "%.*s\n" , (int )path .len , path .buf );
178201
@@ -408,15 +431,41 @@ static int reject_entry(const struct object_id *oid UNUSED,
408431 return ret ;
409432}
410433
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+
411455static int path_exists (struct archiver_args * args , const char * path )
412456{
413457 const char * paths [] = { path , NULL };
414458 struct path_exists_context ctx ;
415459 int ret ;
416460
417461 ctx .args = args ;
418- parse_pathspec (& ctx .pathspec , 0 , 0 , "" , paths );
462+ parse_pathspec (& ctx .pathspec , 0 , PATHSPEC_PREFER_CWD ,
463+ args -> prefix , paths );
419464 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 );
420469 ret = read_tree (args -> repo , args -> tree ,
421470 & ctx .pathspec ,
422471 reject_entry , & ctx );
@@ -432,9 +481,8 @@ static void parse_pathspec_arg(const char **pathspec,
432481 * Also if pathspec patterns are dependent, we're in big
433482 * trouble as we test each one separately
434483 */
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 );
438486 ar_args -> pathspec .recursive = 1 ;
439487 if (pathspec ) {
440488 while (* pathspec ) {
@@ -446,8 +494,7 @@ static void parse_pathspec_arg(const char **pathspec,
446494}
447495
448496static 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 )
451498{
452499 const char * name = argv [0 ];
453500 const struct object_id * commit_oid ;
@@ -487,20 +534,6 @@ static void parse_treeish_arg(const char **argv,
487534 if (!tree )
488535 die (_ ("not a tree object: %s" ), oid_to_hex (& oid ));
489536
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- }
504537 ar_args -> refname = ref ;
505538 ar_args -> tree = tree ;
506539 ar_args -> commit_oid = commit_oid ;
@@ -718,7 +751,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
718751 setup_git_directory ();
719752 }
720753
721- parse_treeish_arg (argv , & args , prefix , remote );
754+ parse_treeish_arg (argv , & args , remote );
722755 parse_pathspec_arg (argv + 1 , & args );
723756
724757 rc = ar -> write_archive (ar , & args );
0 commit comments