@@ -41,74 +41,119 @@ static int read_directory_contents(const char *path, struct string_list *list)
4141 */
4242static const char file_from_standard_input [] = "-" ;
4343
44- static int get_mode (const char * path , int * mode )
44+ /*
45+ * For paths given on the command-line we treat "-" as stdin and named
46+ * pipes and symbolic links to named pipes specially.
47+ */
48+ enum special {
49+ SPECIAL_NONE ,
50+ SPECIAL_STDIN ,
51+ SPECIAL_PIPE ,
52+ };
53+
54+ static int get_mode (const char * path , int * mode , enum special * special )
4555{
4656 struct stat st ;
4757
48- if (!path || !strcmp (path , "/dev/null" ))
58+ if (!path || !strcmp (path , "/dev/null" )) {
4959 * mode = 0 ;
5060#ifdef GIT_WINDOWS_NATIVE
51- else if (!strcasecmp (path , "nul "))
61+ } else if (!strcasecmp (path , "nul" )) {
5262 * mode = 0 ;
5363#endif
54- else if (path == file_from_standard_input )
64+ } else if (path == file_from_standard_input ) {
5565 * mode = create_ce_mode (0666 );
56- else if (lstat (path , & st ))
66+ * special = SPECIAL_STDIN ;
67+ } else if (lstat (path , & st )) {
5768 return error ("Could not access '%s'" , path );
58- else
69+ } else {
5970 * mode = st .st_mode ;
71+ }
72+ /*
73+ * For paths on the command-line treat named pipes and symbolic
74+ * links that resolve to a named pipe specially.
75+ */
76+ if (special &&
77+ (S_ISFIFO (* mode ) ||
78+ (S_ISLNK (* mode ) && !stat (path , & st ) && S_ISFIFO (st .st_mode )))) {
79+ * mode = create_ce_mode (0666 );
80+ * special = SPECIAL_PIPE ;
81+ }
82+
6083 return 0 ;
6184}
6285
63- static void populate_from_stdin (struct diff_filespec * s )
86+ static void populate_common (struct diff_filespec * s , struct strbuf * buf )
6487{
65- struct strbuf buf = STRBUF_INIT ;
6688 size_t size = 0 ;
6789
68- if (strbuf_read (& buf , 0 , 0 ) < 0 )
69- die_errno ("error while reading from stdin" );
70-
7190 s -> should_munmap = 0 ;
72- s -> data = strbuf_detach (& buf , & size );
91+ s -> data = strbuf_detach (buf , & size );
7392 s -> size = size ;
7493 s -> should_free = 1 ;
7594 s -> is_stdin = 1 ;
7695}
7796
78- static struct diff_filespec * noindex_filespec (const char * name , int mode )
97+ static void populate_from_pipe (struct diff_filespec * s )
98+ {
99+ struct strbuf buf = STRBUF_INIT ;
100+ int fd = xopen (s -> path , O_RDONLY );
101+
102+ if (strbuf_read (& buf , fd , 0 ) < 0 )
103+ die_errno ("error while reading from '%s'" , s -> path );
104+ close (fd );
105+ populate_common (s , & buf );
106+ }
107+
108+ static void populate_from_stdin (struct diff_filespec * s )
109+ {
110+ struct strbuf buf = STRBUF_INIT ;
111+
112+ if (strbuf_read (& buf , 0 , 0 ) < 0 )
113+ die_errno ("error while reading from stdin" );
114+ populate_common (s , & buf );
115+ }
116+
117+ static struct diff_filespec * noindex_filespec (const char * name , int mode ,
118+ enum special special )
79119{
80120 struct diff_filespec * s ;
81121
82122 if (!name )
83123 name = "/dev/null" ;
84124 s = alloc_filespec (name );
85125 fill_filespec (s , null_oid (), 0 , mode );
86- if (name == file_from_standard_input )
126+ if (special == SPECIAL_STDIN )
87127 populate_from_stdin (s );
128+ else if (special == SPECIAL_PIPE )
129+ populate_from_pipe (s );
88130 return s ;
89131}
90132
91133static int queue_diff (struct diff_options * o ,
92- const char * name1 , const char * name2 )
134+ const char * name1 , const char * name2 , int recursing )
93135{
94136 int mode1 = 0 , mode2 = 0 ;
137+ enum special special1 = SPECIAL_NONE , special2 = SPECIAL_NONE ;
95138
96- if (get_mode (name1 , & mode1 ) || get_mode (name2 , & mode2 ))
139+ /* Paths can only be special if we're not recursing. */
140+ if (get_mode (name1 , & mode1 , recursing ? NULL : & special1 ) ||
141+ get_mode (name2 , & mode2 , recursing ? NULL : & special2 ))
97142 return -1 ;
98143
99144 if (mode1 && mode2 && S_ISDIR (mode1 ) != S_ISDIR (mode2 )) {
100145 struct diff_filespec * d1 , * d2 ;
101146
102147 if (S_ISDIR (mode1 )) {
103148 /* 2 is file that is created */
104- d1 = noindex_filespec (NULL , 0 );
105- d2 = noindex_filespec (name2 , mode2 );
149+ d1 = noindex_filespec (NULL , 0 , SPECIAL_NONE );
150+ d2 = noindex_filespec (name2 , mode2 , special2 );
106151 name2 = NULL ;
107152 mode2 = 0 ;
108153 } else {
109154 /* 1 is file that is deleted */
110- d1 = noindex_filespec (name1 , mode1 );
111- d2 = noindex_filespec (NULL , 0 );
155+ d1 = noindex_filespec (name1 , mode1 , special1 );
156+ d2 = noindex_filespec (NULL , 0 , SPECIAL_NONE );
112157 name1 = NULL ;
113158 mode1 = 0 ;
114159 }
@@ -173,7 +218,7 @@ static int queue_diff(struct diff_options *o,
173218 n2 = buffer2 .buf ;
174219 }
175220
176- ret = queue_diff (o , n1 , n2 );
221+ ret = queue_diff (o , n1 , n2 , 1 );
177222 }
178223 string_list_clear (& p1 , 0 );
179224 string_list_clear (& p2 , 0 );
@@ -189,8 +234,8 @@ static int queue_diff(struct diff_options *o,
189234 SWAP (name1 , name2 );
190235 }
191236
192- d1 = noindex_filespec (name1 , mode1 );
193- d2 = noindex_filespec (name2 , mode2 );
237+ d1 = noindex_filespec (name1 , mode1 , special1 );
238+ d2 = noindex_filespec (name2 , mode2 , special2 );
194239 diff_queue (& diff_queued_diff , d1 , d2 );
195240 return 0 ;
196241 }
@@ -215,15 +260,27 @@ static void append_basename(struct strbuf *path, const char *dir, const char *fi
215260 */
216261static void fixup_paths (const char * * path , struct strbuf * replacement )
217262{
218- unsigned int isdir0 , isdir1 ;
263+ struct stat st ;
264+ unsigned int isdir0 = 0 , isdir1 = 0 ;
265+ unsigned int ispipe0 = 0 , ispipe1 = 0 ;
219266
220- isdir0 = path [0 ] != file_from_standard_input && is_directory (path [0 ]);
221- isdir1 = path [1 ] != file_from_standard_input && is_directory (path [1 ]);
267+ if (path [0 ] != file_from_standard_input && !stat (path [0 ], & st )) {
268+ isdir0 = S_ISDIR (st .st_mode );
269+ ispipe0 = S_ISFIFO (st .st_mode );
270+ }
271+
272+ if (path [1 ] != file_from_standard_input && !stat (path [1 ], & st )) {
273+ isdir1 = S_ISDIR (st .st_mode );
274+ ispipe1 = S_ISFIFO (st .st_mode );
275+ }
222276
223277 if ((path [0 ] == file_from_standard_input && isdir1 ) ||
224278 (isdir0 && path [1 ] == file_from_standard_input ))
225279 die (_ ("cannot compare stdin to a directory" ));
226280
281+ if ((isdir0 && ispipe1 ) || (ispipe0 && isdir1 ))
282+ die (_ ("cannot compare a named pipe to a directory" ));
283+
227284 if (isdir0 == isdir1 )
228285 return ;
229286 if (isdir0 ) {
@@ -297,7 +354,7 @@ int diff_no_index(struct rev_info *revs,
297354 setup_diff_pager (& revs -> diffopt );
298355 revs -> diffopt .flags .exit_with_status = 1 ;
299356
300- if (queue_diff (& revs -> diffopt , paths [0 ], paths [1 ]))
357+ if (queue_diff (& revs -> diffopt , paths [0 ], paths [1 ], 0 ))
301358 goto out ;
302359 diff_set_mnemonic_prefix (& revs -> diffopt , "1/" , "2/" );
303360 diffcore_std (& revs -> diffopt );
0 commit comments