@@ -13,6 +13,46 @@ static const char *diff_opts = "-pu";
1313
1414static int use_size_cache ;
1515
16+ static char * quote_one (const char * str )
17+ {
18+ int needlen ;
19+ char * xp ;
20+
21+ if (!str )
22+ return NULL ;
23+ needlen = quote_c_style (str , NULL , NULL , 0 );
24+ if (!needlen )
25+ return strdup (str );
26+ xp = xmalloc (needlen + 1 );
27+ quote_c_style (str , xp , NULL , 0 );
28+ return xp ;
29+ }
30+
31+ static char * quote_two (const char * one , const char * two )
32+ {
33+ int need_one = quote_c_style (one , NULL , NULL , 1 );
34+ int need_two = quote_c_style (two , NULL , NULL , 1 );
35+ char * xp ;
36+
37+ if (need_one + need_two ) {
38+ if (!need_one ) need_one = strlen (one );
39+ if (!need_two ) need_one = strlen (two );
40+
41+ xp = xmalloc (need_one + need_two + 3 );
42+ xp [0 ] = '"' ;
43+ quote_c_style (one , xp + 1 , NULL , 1 );
44+ quote_c_style (two , xp + need_one + 1 , NULL , 1 );
45+ strcpy (xp + need_one + need_two + 1 , "\"" );
46+ return xp ;
47+ }
48+ need_one = strlen (one );
49+ need_two = strlen (two );
50+ xp = xmalloc (need_one + need_two + 1 );
51+ strcpy (xp , one );
52+ strcpy (xp + need_one , two );
53+ return xp ;
54+ }
55+
1656static const char * external_diff (void )
1757{
1858 static const char * external_diff_cmd = NULL ;
@@ -133,55 +173,52 @@ static void builtin_diff(const char *name_a,
133173 int complete_rewrite )
134174{
135175 int i , next_at , cmd_size ;
136- const char * const diff_cmd = "diff -L%s%s -L%s %s" ;
176+ const char * const diff_cmd = "diff -L%s -L%s" ;
137177 const char * const diff_arg = "%s %s||:" ; /* "||:" is to return 0 */
138178 const char * input_name_sq [2 ];
139- const char * path0 [2 ];
140- const char * path1 [2 ];
141- const char * name_sq [2 ];
179+ const char * label_path [2 ];
142180 char * cmd ;
143181
144- name_sq [0 ] = sq_quote (name_a );
145- name_sq [1 ] = sq_quote (name_b );
146-
147- /* diff_cmd and diff_arg have 6 %s in total which makes
148- * the sum of these strings 12 bytes larger than required.
182+ /* diff_cmd and diff_arg have 4 %s in total which makes
183+ * the sum of these strings 8 bytes larger than required.
149184 * we use 2 spaces around diff-opts, and we need to count
150- * terminating NUL, so we subtract 9 here.
185+ * terminating NUL; we used to subtract 5 here, but we do not
186+ * care about small leaks in this subprocess that is about
187+ * to exec "diff" anymore.
151188 */
152- cmd_size = (strlen (diff_cmd ) + strlen (diff_opts ) +
153- strlen (diff_arg ) - 9 );
189+ cmd_size = (strlen (diff_cmd ) + strlen (diff_opts ) + strlen (diff_arg )
190+ + 128 );
191+
154192 for (i = 0 ; i < 2 ; i ++ ) {
155193 input_name_sq [i ] = sq_quote (temp [i ].name );
156- if (!strcmp (temp [i ].name , "/dev/null" )) {
157- path0 [i ] = "/dev/null" ;
158- path1 [i ] = "" ;
159- } else {
160- path0 [i ] = i ? "b/" : "a/" ;
161- path1 [i ] = name_sq [i ];
162- }
163- cmd_size += (strlen (path0 [i ]) + strlen (path1 [i ]) +
164- strlen (input_name_sq [i ]));
194+ if (!strcmp (temp [i ].name , "/dev/null" ))
195+ label_path [i ] = "/dev/null" ;
196+ else if (!i )
197+ label_path [i ] = sq_quote (quote_two ("a/" , name_a ));
198+ else
199+ label_path [i ] = sq_quote (quote_two ("b/" , name_b ));
200+ cmd_size += (strlen (label_path [i ]) + strlen (input_name_sq [i ]));
165201 }
166202
167203 cmd = xmalloc (cmd_size );
168204
169205 next_at = 0 ;
170206 next_at += snprintf (cmd + next_at , cmd_size - next_at ,
171- diff_cmd ,
172- path0 [0 ], path1 [0 ], path0 [1 ], path1 [1 ]);
207+ diff_cmd , label_path [0 ], label_path [1 ]);
173208 next_at += snprintf (cmd + next_at , cmd_size - next_at ,
174209 " %s " , diff_opts );
175210 next_at += snprintf (cmd + next_at , cmd_size - next_at ,
176211 diff_arg , input_name_sq [0 ], input_name_sq [1 ]);
177212
178- printf ("diff --git a/%s b/%s\n" , name_a , name_b );
179- if (!path1 [0 ][0 ]) {
213+ printf ("diff --git %s %s\n" ,
214+ quote_two ("a/" , name_a ), quote_two ("b/" , name_b ));
215+ if (label_path [0 ][0 ] == '/' ) {
216+ /* dev/null */
180217 printf ("new file mode %s\n" , temp [1 ].mode );
181218 if (xfrm_msg && xfrm_msg [0 ])
182219 puts (xfrm_msg );
183220 }
184- else if (! path1 [1 ][0 ]) {
221+ else if (label_path [1 ][0 ] == '/' ) {
185222 printf ("deleted file mode %s\n" , temp [0 ].mode );
186223 if (xfrm_msg && xfrm_msg [0 ])
187224 puts (xfrm_msg );
@@ -619,6 +656,7 @@ static void run_diff(struct diff_filepair *p)
619656 struct diff_filespec * two ;
620657 const char * name ;
621658 const char * other ;
659+ char * name_munged , * other_munged ;
622660 int complete_rewrite = 0 ;
623661 int len ;
624662
@@ -631,6 +669,8 @@ static void run_diff(struct diff_filepair *p)
631669
632670 name = p -> one -> path ;
633671 other = (strcmp (name , p -> two -> path ) ? p -> two -> path : NULL );
672+ name_munged = quote_one (name );
673+ other_munged = quote_one (other );
634674 one = p -> one ; two = p -> two ;
635675
636676 diff_fill_sha1_info (one );
@@ -644,15 +684,15 @@ static void run_diff(struct diff_filepair *p)
644684 "copy from %s\n"
645685 "copy to %s\n" ,
646686 (int )(0.5 + p -> score * 100.0 /MAX_SCORE ),
647- name , other );
687+ name_munged , other_munged );
648688 break ;
649689 case DIFF_STATUS_RENAMED :
650690 len += snprintf (msg + len , sizeof (msg ) - len ,
651691 "similarity index %d%%\n"
652692 "rename from %s\n"
653693 "rename to %s\n" ,
654694 (int )(0.5 + p -> score * 100.0 /MAX_SCORE ),
655- name , other );
695+ name_munged , other_munged );
656696 break ;
657697 case DIFF_STATUS_MODIFIED :
658698 if (p -> score ) {
@@ -702,6 +742,9 @@ static void run_diff(struct diff_filepair *p)
702742 else
703743 run_external_diff (pgm , name , other , one , two , xfrm_msg ,
704744 complete_rewrite );
745+
746+ free (name_munged );
747+ free (other_munged );
705748}
706749
707750void diff_setup (struct diff_options * options )
@@ -878,16 +921,13 @@ static void diff_flush_raw(struct diff_filepair *p,
878921{
879922 int two_paths ;
880923 char status [10 ];
924+ const char * path_one , * path_two ;
881925
926+ path_one = p -> one -> path ;
927+ path_two = p -> two -> path ;
882928 if (line_termination ) {
883- const char * const err =
884- "path %s cannot be expressed without -z" ;
885- if (strchr (p -> one -> path , line_termination ) ||
886- strchr (p -> one -> path , inter_name_termination ))
887- die (err , p -> one -> path );
888- if (strchr (p -> two -> path , line_termination ) ||
889- strchr (p -> two -> path , inter_name_termination ))
890- die (err , p -> two -> path );
929+ path_one = quote_one (path_one );
930+ path_two = quote_one (path_two );
891931 }
892932
893933 if (p -> score )
@@ -915,16 +955,29 @@ static void diff_flush_raw(struct diff_filepair *p,
915955 p -> one -> mode , p -> two -> mode , sha1_to_hex (p -> one -> sha1 ));
916956 printf ("%s " , sha1_to_hex (p -> two -> sha1 ));
917957 }
918- printf ("%s%c%s" ,status , inter_name_termination , p -> one -> path );
958+ printf ("%s%c%s" , status , inter_name_termination , path_one );
919959 if (two_paths )
920- printf ("%c%s" , inter_name_termination , p -> two -> path );
960+ printf ("%c%s" , inter_name_termination , path_two );
921961 putchar (line_termination );
962+ if (path_one != p -> one -> path )
963+ free ((void * )path_one );
964+ if (path_two != p -> two -> path )
965+ free ((void * )path_two );
922966}
923967
924968static void diff_flush_name (struct diff_filepair * p ,
969+ int inter_name_termination ,
925970 int line_termination )
926971{
927- printf ("%s%c" , p -> two -> path , line_termination );
972+ char * path = p -> two -> path ;
973+
974+ if (line_termination )
975+ path = quote_one (p -> two -> path );
976+ else
977+ path = p -> two -> path ;
978+ printf ("%s%c" , path , line_termination );
979+ if (p -> two -> path != path )
980+ free (path );
928981}
929982
930983int diff_unmodified_pair (struct diff_filepair * p )
@@ -1111,7 +1164,9 @@ void diff_flush(struct diff_options *options)
11111164 diff_output_format );
11121165 break ;
11131166 case DIFF_FORMAT_NAME :
1114- diff_flush_name (p , line_termination );
1167+ diff_flush_name (p ,
1168+ inter_name_termination ,
1169+ line_termination );
11151170 break ;
11161171 }
11171172 diff_free_filepair (q -> queue [i ]);
0 commit comments