@@ -26,8 +26,9 @@ static int show_killed;
2626static int show_valid_bit ;
2727static int line_terminator = '\n' ;
2828
29+ static const char * prefix ;
30+ static int max_prefix_len ;
2931static int prefix_len ;
30- static int prefix_offset ;
3132static const char * * pathspec ;
3233static int error_unmatch ;
3334static char * ps_matched ;
@@ -43,10 +44,15 @@ static const char *tag_modified = "";
4344static const char * tag_skip_worktree = "" ;
4445static const char * tag_resolve_undo = "" ;
4546
47+ static void write_name (const char * name , size_t len )
48+ {
49+ write_name_quoted_relative (name , len , prefix , prefix_len , stdout ,
50+ line_terminator );
51+ }
52+
4653static void show_dir_entry (const char * tag , struct dir_entry * ent )
4754{
48- int len = prefix_len ;
49- int offset = prefix_offset ;
55+ int len = max_prefix_len ;
5056
5157 if (len >= ent -> len )
5258 die ("git ls-files: internal error - directory entry not superset of prefix" );
@@ -55,7 +61,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
5561 return ;
5662
5763 fputs (tag , stdout );
58- write_name_quoted (ent -> name + offset , stdout , line_terminator );
64+ write_name (ent -> name , ent -> len );
5965}
6066
6167static void show_other_files (struct dir_struct * dir )
@@ -121,8 +127,7 @@ static void show_killed_files(struct dir_struct *dir)
121127
122128static void show_ce_entry (const char * tag , struct cache_entry * ce )
123129{
124- int len = prefix_len ;
125- int offset = prefix_offset ;
130+ int len = max_prefix_len ;
126131
127132 if (len >= ce_namelen (ce ))
128133 die ("git ls-files: internal error - cache entry not superset of prefix" );
@@ -156,40 +161,39 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
156161 find_unique_abbrev (ce -> sha1 ,abbrev ),
157162 ce_stage (ce ));
158163 }
159- write_name_quoted (ce -> name + offset , stdout , line_terminator );
164+ write_name (ce -> name , ce_namelen ( ce ) );
160165}
161166
162167static int show_one_ru (struct string_list_item * item , void * cbdata )
163168{
164- int offset = prefix_offset ;
165169 const char * path = item -> string ;
166170 struct resolve_undo_info * ui = item -> util ;
167171 int i , len ;
168172
169173 len = strlen (path );
170- if (len < prefix_len )
174+ if (len < max_prefix_len )
171175 return 0 ; /* outside of the prefix */
172- if (!match_pathspec (pathspec , path , len , prefix_len , ps_matched ))
176+ if (!match_pathspec (pathspec , path , len , max_prefix_len , ps_matched ))
173177 return 0 ; /* uninterested */
174178 for (i = 0 ; i < 3 ; i ++ ) {
175179 if (!ui -> mode [i ])
176180 continue ;
177181 printf ("%s%06o %s %d\t" , tag_resolve_undo , ui -> mode [i ],
178182 find_unique_abbrev (ui -> sha1 [i ], abbrev ),
179183 i + 1 );
180- write_name_quoted (path + offset , stdout , line_terminator );
184+ write_name (path , len );
181185 }
182186 return 0 ;
183187}
184188
185- static void show_ru_info (const char * prefix )
189+ static void show_ru_info (void )
186190{
187191 if (!the_index .resolve_undo )
188192 return ;
189193 for_each_string_list (show_one_ru , the_index .resolve_undo , NULL );
190194}
191195
192- static void show_files (struct dir_struct * dir , const char * prefix )
196+ static void show_files (struct dir_struct * dir )
193197{
194198 int i ;
195199
@@ -243,7 +247,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
243247 */
244248static void prune_cache (const char * prefix )
245249{
246- int pos = cache_name_pos (prefix , prefix_len );
250+ int pos = cache_name_pos (prefix , max_prefix_len );
247251 unsigned int first , last ;
248252
249253 if (pos < 0 )
@@ -256,7 +260,7 @@ static void prune_cache(const char *prefix)
256260 while (last > first ) {
257261 int next = (last + first ) >> 1 ;
258262 struct cache_entry * ce = active_cache [next ];
259- if (!strncmp (ce -> name , prefix , prefix_len )) {
263+ if (!strncmp (ce -> name , prefix , max_prefix_len )) {
260264 first = next + 1 ;
261265 continue ;
262266 }
@@ -265,11 +269,16 @@ static void prune_cache(const char *prefix)
265269 active_nr = last ;
266270}
267271
268- static const char * verify_pathspec (const char * prefix )
272+ static const char * pathspec_prefix (const char * prefix )
269273{
270274 const char * * p , * n , * prev ;
271275 unsigned long max ;
272276
277+ if (!pathspec ) {
278+ max_prefix_len = prefix ? strlen (prefix ) : 0 ;
279+ return prefix ;
280+ }
281+
273282 prev = NULL ;
274283 max = PATH_MAX ;
275284 for (p = pathspec ; (n = * p ) != NULL ; p ++ ) {
@@ -291,10 +300,7 @@ static const char *verify_pathspec(const char *prefix)
291300 }
292301 }
293302
294- if (prefix_offset > max || memcmp (prev , prefix , prefix_offset ))
295- die ("git ls-files: cannot generate relative filenames containing '..'" );
296-
297- prefix_len = max ;
303+ max_prefix_len = max ;
298304 return max ? xmemdupz (prev , max ) : NULL ;
299305}
300306
@@ -374,7 +380,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
374380 }
375381}
376382
377- int report_path_error (const char * ps_matched , const char * * pathspec , int prefix_offset )
383+ int report_path_error (const char * ps_matched , const char * * pathspec , int prefix_len )
378384{
379385 /*
380386 * Make sure all pathspec matched; otherwise it is an error.
@@ -404,7 +410,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
404410 continue ;
405411
406412 error ("pathspec '%s' did not match any file(s) known to git." ,
407- pathspec [num ] + prefix_offset );
413+ pathspec [num ] + prefix_len );
408414 errors ++ ;
409415 }
410416 return errors ;
@@ -456,9 +462,10 @@ static int option_parse_exclude_standard(const struct option *opt,
456462 return 0 ;
457463}
458464
459- int cmd_ls_files (int argc , const char * * argv , const char * prefix )
465+ int cmd_ls_files (int argc , const char * * argv , const char * cmd_prefix )
460466{
461467 int require_work_tree = 0 , show_tag = 0 ;
468+ const char * max_prefix ;
462469 struct dir_struct dir ;
463470 struct option builtin_ls_files_options [] = {
464471 { OPTION_CALLBACK , 'z' , NULL , NULL , NULL ,
@@ -504,7 +511,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
504511 { OPTION_CALLBACK , 0 , "exclude-standard" , & dir , NULL ,
505512 "add the standard git exclusions" ,
506513 PARSE_OPT_NOARG , option_parse_exclude_standard },
507- { OPTION_SET_INT , 0 , "full-name" , & prefix_offset , NULL ,
514+ { OPTION_SET_INT , 0 , "full-name" , & prefix_len , NULL ,
508515 "make the output relative to the project top directory" ,
509516 PARSE_OPT_NOARG | PARSE_OPT_NONEG , NULL },
510517 OPT_BOOLEAN (0 , "error-unmatch" , & error_unmatch ,
@@ -516,8 +523,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
516523 };
517524
518525 memset (& dir , 0 , sizeof (dir ));
526+ prefix = cmd_prefix ;
519527 if (prefix )
520- prefix_offset = strlen (prefix );
528+ prefix_len = strlen (prefix );
521529 git_config (git_default_config , NULL );
522530
523531 if (read_cache () < 0 )
@@ -555,9 +563,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
555563 if (pathspec )
556564 strip_trailing_slash_from_submodules ();
557565
558- /* Verify that the pathspec matches the prefix */
559- if (pathspec )
560- prefix = verify_pathspec (prefix );
566+ /* Find common prefix for all pathspec's */
567+ max_prefix = pathspec_prefix (prefix );
561568
562569 /* Treat unmatching pathspec elements as errors */
563570 if (pathspec && error_unmatch ) {
@@ -575,24 +582,24 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
575582 show_killed | show_modified | show_resolve_undo ))
576583 show_cached = 1 ;
577584
578- if (prefix )
579- prune_cache (prefix );
585+ if (max_prefix )
586+ prune_cache (max_prefix );
580587 if (with_tree ) {
581588 /*
582589 * Basic sanity check; show-stages and show-unmerged
583590 * would not make any sense with this option.
584591 */
585592 if (show_stage || show_unmerged )
586593 die ("ls-files --with-tree is incompatible with -s or -u" );
587- overlay_tree_on_cache (with_tree , prefix );
594+ overlay_tree_on_cache (with_tree , max_prefix );
588595 }
589- show_files (& dir , prefix );
596+ show_files (& dir );
590597 if (show_resolve_undo )
591- show_ru_info (prefix );
598+ show_ru_info ();
592599
593600 if (ps_matched ) {
594601 int bad ;
595- bad = report_path_error (ps_matched , pathspec , prefix_offset );
602+ bad = report_path_error (ps_matched , pathspec , prefix_len );
596603 if (bad )
597604 fprintf (stderr , "Did you forget to 'git add'?\n" );
598605
0 commit comments