@@ -41,74 +41,119 @@ static int read_directory_contents(const char *path, struct string_list *list)
41
41
*/
42
42
static const char file_from_standard_input [] = "-" ;
43
43
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 )
45
55
{
46
56
struct stat st ;
47
57
48
- if (!path || !strcmp (path , "/dev/null" ))
58
+ if (!path || !strcmp (path , "/dev/null" )) {
49
59
* mode = 0 ;
50
60
#ifdef GIT_WINDOWS_NATIVE
51
- else if (!strcasecmp (path , "nul "))
61
+ } else if (!strcasecmp (path , "nul" )) {
52
62
* mode = 0 ;
53
63
#endif
54
- else if (path == file_from_standard_input )
64
+ } else if (path == file_from_standard_input ) {
55
65
* mode = create_ce_mode (0666 );
56
- else if (lstat (path , & st ))
66
+ * special = SPECIAL_STDIN ;
67
+ } else if (lstat (path , & st )) {
57
68
return error ("Could not access '%s'" , path );
58
- else
69
+ } else {
59
70
* 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
+
60
83
return 0 ;
61
84
}
62
85
63
- static void populate_from_stdin (struct diff_filespec * s )
86
+ static void populate_common (struct diff_filespec * s , struct strbuf * buf )
64
87
{
65
- struct strbuf buf = STRBUF_INIT ;
66
88
size_t size = 0 ;
67
89
68
- if (strbuf_read (& buf , 0 , 0 ) < 0 )
69
- die_errno ("error while reading from stdin" );
70
-
71
90
s -> should_munmap = 0 ;
72
- s -> data = strbuf_detach (& buf , & size );
91
+ s -> data = strbuf_detach (buf , & size );
73
92
s -> size = size ;
74
93
s -> should_free = 1 ;
75
94
s -> is_stdin = 1 ;
76
95
}
77
96
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 )
79
119
{
80
120
struct diff_filespec * s ;
81
121
82
122
if (!name )
83
123
name = "/dev/null" ;
84
124
s = alloc_filespec (name );
85
125
fill_filespec (s , null_oid (), 0 , mode );
86
- if (name == file_from_standard_input )
126
+ if (special == SPECIAL_STDIN )
87
127
populate_from_stdin (s );
128
+ else if (special == SPECIAL_PIPE )
129
+ populate_from_pipe (s );
88
130
return s ;
89
131
}
90
132
91
133
static int queue_diff (struct diff_options * o ,
92
- const char * name1 , const char * name2 )
134
+ const char * name1 , const char * name2 , int recursing )
93
135
{
94
136
int mode1 = 0 , mode2 = 0 ;
137
+ enum special special1 = SPECIAL_NONE , special2 = SPECIAL_NONE ;
95
138
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 ))
97
142
return -1 ;
98
143
99
144
if (mode1 && mode2 && S_ISDIR (mode1 ) != S_ISDIR (mode2 )) {
100
145
struct diff_filespec * d1 , * d2 ;
101
146
102
147
if (S_ISDIR (mode1 )) {
103
148
/* 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 );
106
151
name2 = NULL ;
107
152
mode2 = 0 ;
108
153
} else {
109
154
/* 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 );
112
157
name1 = NULL ;
113
158
mode1 = 0 ;
114
159
}
@@ -173,7 +218,7 @@ static int queue_diff(struct diff_options *o,
173
218
n2 = buffer2 .buf ;
174
219
}
175
220
176
- ret = queue_diff (o , n1 , n2 );
221
+ ret = queue_diff (o , n1 , n2 , 1 );
177
222
}
178
223
string_list_clear (& p1 , 0 );
179
224
string_list_clear (& p2 , 0 );
@@ -189,8 +234,8 @@ static int queue_diff(struct diff_options *o,
189
234
SWAP (name1 , name2 );
190
235
}
191
236
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 );
194
239
diff_queue (& diff_queued_diff , d1 , d2 );
195
240
return 0 ;
196
241
}
@@ -215,15 +260,27 @@ static void append_basename(struct strbuf *path, const char *dir, const char *fi
215
260
*/
216
261
static void fixup_paths (const char * * path , struct strbuf * replacement )
217
262
{
218
- unsigned int isdir0 , isdir1 ;
263
+ struct stat st ;
264
+ unsigned int isdir0 = 0 , isdir1 = 0 ;
265
+ unsigned int ispipe0 = 0 , ispipe1 = 0 ;
219
266
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
+ }
222
276
223
277
if ((path [0 ] == file_from_standard_input && isdir1 ) ||
224
278
(isdir0 && path [1 ] == file_from_standard_input ))
225
279
die (_ ("cannot compare stdin to a directory" ));
226
280
281
+ if ((isdir0 && ispipe1 ) || (ispipe0 && isdir1 ))
282
+ die (_ ("cannot compare a named pipe to a directory" ));
283
+
227
284
if (isdir0 == isdir1 )
228
285
return ;
229
286
if (isdir0 ) {
@@ -297,7 +354,7 @@ int diff_no_index(struct rev_info *revs,
297
354
setup_diff_pager (& revs -> diffopt );
298
355
revs -> diffopt .flags .exit_with_status = 1 ;
299
356
300
- if (queue_diff (& revs -> diffopt , paths [0 ], paths [1 ]))
357
+ if (queue_diff (& revs -> diffopt , paths [0 ], paths [1 ], 0 ))
301
358
goto out ;
302
359
diff_set_mnemonic_prefix (& revs -> diffopt , "1/" , "2/" );
303
360
diffcore_std (& revs -> diffopt );
0 commit comments