aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-24 14:44:59 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-24 14:44:59 +0000
commit04211fd2049435ee48ab69b116ea9f91914ef94b (patch)
treebeccdfc5a2625b1603c1a5581a2393f2b285a8e7
parentdc1cbf839dc68f6f3fdd4a7dd007b1763b7c8c3c (diff)
downloadbusybox-w32-04211fd2049435ee48ab69b116ea9f91914ef94b.tar.gz
busybox-w32-04211fd2049435ee48ab69b116ea9f91914ef94b.tar.bz2
busybox-w32-04211fd2049435ee48ab69b116ea9f91914ef94b.zip
diff: make it work on pipes etc (needed for kernel compile)
function old new delta get_recursive_dirlist - 177 +177 make_temp - 144 +144 diffreg 1818 1844 +26 files_differ 175 182 +7 diff_main 842 843 +1 get_dir 177 - -177 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 3/0 up/down: 355/-177) Total: 178 bytes
-rw-r--r--editors/diff.c139
1 files changed, 88 insertions, 51 deletions
diff --git a/editors/diff.c b/editors/diff.c
index 4afe7b2db..47297ebb3 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -34,8 +34,8 @@
34 * D_BINARY - binary files differ 34 * D_BINARY - binary files differ
35 * D_COMMON - subdirectory common to both dirs 35 * D_COMMON - subdirectory common to both dirs
36 * D_ONLY - file only exists in one dir 36 * D_ONLY - file only exists in one dir
37 * D_MISMATCH1 - path1 a dir, path2 a file 37 * D_ISDIR1 - path1 a dir, path2 a file
38 * D_MISMATCH2 - path1 a file, path2 a dir 38 * D_ISDIR2 - path1 a file, path2 a dir
39 * D_ERROR - error occurred 39 * D_ERROR - error occurred
40 * D_SKIPPED1 - skipped path1 as it is a special file 40 * D_SKIPPED1 - skipped path1 as it is a special file
41 * D_SKIPPED2 - skipped path2 as it is a special file 41 * D_SKIPPED2 - skipped path2 as it is a special file
@@ -45,8 +45,8 @@
45#define D_BINARY (1 << 1) 45#define D_BINARY (1 << 1)
46#define D_COMMON (1 << 2) 46#define D_COMMON (1 << 2)
47/*#define D_ONLY (1 << 3) - unused */ 47/*#define D_ONLY (1 << 3) - unused */
48#define D_MISMATCH1 (1 << 4) 48#define D_ISDIR1 (1 << 4)
49#define D_MISMATCH2 (1 << 5) 49#define D_ISDIR2 (1 << 5)
50#define D_ERROR (1 << 6) 50#define D_ERROR (1 << 6)
51#define D_SKIPPED1 (1 << 7) 51#define D_SKIPPED1 (1 << 7)
52#define D_SKIPPED2 (1 << 8) 52#define D_SKIPPED2 (1 << 8)
@@ -123,6 +123,7 @@ struct globals {
123 struct context_vec *context_vec_end; 123 struct context_vec *context_vec_end;
124 struct context_vec *context_vec_ptr; 124 struct context_vec *context_vec_ptr;
125 struct stat stb1, stb2; 125 struct stat stb1, stb2;
126 char *tempname1, *tempname2;
126}; 127};
127#define G (*ptr_to_globals) 128#define G (*ptr_to_globals)
128#define dl (G.dl ) 129#define dl (G.dl )
@@ -154,6 +155,8 @@ struct globals {
154#define context_vec_ptr (G.context_vec_ptr ) 155#define context_vec_ptr (G.context_vec_ptr )
155#define stb1 (G.stb1 ) 156#define stb1 (G.stb1 )
156#define stb2 (G.stb2 ) 157#define stb2 (G.stb2 )
158#define tempname1 (G.tempname1 )
159#define tempname2 (G.tempname2 )
157#define INIT_G() do { \ 160#define INIT_G() do { \
158 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 161 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
159 context = 3; \ 162 context = 3; \
@@ -194,11 +197,11 @@ static void print_status(int val, char *_path1, char *_path2)
194 if (option_mask32 & FLAG_s) 197 if (option_mask32 & FLAG_s)
195 printf("Files %s and %s are identical\n", _path1, _path2); 198 printf("Files %s and %s are identical\n", _path1, _path2);
196 break; 199 break;
197 case D_MISMATCH1: 200 case D_ISDIR1:
198 printf("File %s is a %s while file %s is a %s\n", 201 printf("File %s is a %s while file %s is a %s\n",
199 _path1, "directory", _path2, "regular file"); 202 _path1, "directory", _path2, "regular file");
200 break; 203 break;
201 case D_MISMATCH2: 204 case D_ISDIR2:
202 printf("File %s is a %s while file %s is a %s\n", 205 printf("File %s is a %s while file %s is a %s\n",
203 _path1, "regular file", _path2, "directory"); 206 _path1, "regular file", _path2, "directory");
204 break; 207 break;
@@ -282,6 +285,32 @@ static int readhash(FILE *fp)
282} 285}
283 286
284 287
288static char *make_temp(FILE *f, struct stat *sb)
289{
290 char *name;
291 int fd;
292
293 if (S_ISREG(sb->st_mode))
294 return NULL;
295 name = xstrdup("/tmp/difXXXXXX");
296 fd = mkstemp(name);
297 if (fd < 0)
298 bb_perror_msg_and_die("mkstemp");
299 if (bb_copyfd_eof(fileno(f), fd) < 0) {
300 clean_up:
301 unlink(name);
302 xfunc_die(); /* error message is printed by bb_copyfd_eof */
303 }
304 fstat(fd, sb);
305 close(fd);
306 if (freopen(name, "r+", f) == NULL) {
307 bb_perror_msg("freopen");
308 goto clean_up;
309 }
310 return name;
311}
312
313
285/* 314/*
286 * Check to see if the given files differ. 315 * Check to see if the given files differ.
287 * Returns 0 if they are the same, 1 if different, and -1 on error. 316 * Returns 0 if they are the same, 1 if different, and -1 on error.
@@ -290,9 +319,9 @@ static NOINLINE int files_differ(FILE *f1, FILE *f2, int flags)
290{ 319{
291 size_t i, j; 320 size_t i, j;
292 321
293 if ((flags & (D_EMPTY1 | D_EMPTY2)) || stb1.st_size != stb2.st_size 322 tempname1 = make_temp(f1, &stb1);
294 || (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT) 323 tempname2 = make_temp(f2, &stb2);
295 ) { 324 if ((flags & (D_EMPTY1 | D_EMPTY2)) || stb1.st_size != stb2.st_size) {
296 return 1; 325 return 1;
297 } 326 }
298 while (1) { 327 while (1) {
@@ -966,6 +995,8 @@ static void output(char *file1, FILE *f1, char *file2, FILE *f2)
966 * 3*(number of k-candidates installed), typically about 995 * 3*(number of k-candidates installed), typically about
967 * 6n words for files of length n. 996 * 6n words for files of length n.
968 */ 997 */
998/* NB: files can be not REGular. The only sure thing that they
999 * are not both DIRectories. */
969static unsigned diffreg(char *file1, char *file2, int flags) 1000static unsigned diffreg(char *file1, char *file2, int flags)
970{ 1001{
971 FILE *f1; 1002 FILE *f1;
@@ -976,12 +1007,11 @@ static unsigned diffreg(char *file1, char *file2, int flags)
976 anychange = 0; 1007 anychange = 0;
977 context_vec_ptr = context_vec_start - 1; 1008 context_vec_ptr = context_vec_start - 1;
978 1009
1010 /* Is any of them a directory? Then it's simple */
979 if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) 1011 if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode))
980 return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); 1012 return (S_ISDIR(stb1.st_mode) ? D_ISDIR1 : D_ISDIR2);
981
982 if (LONE_DASH(file1) && LONE_DASH(file2))
983 return D_SAME;
984 1013
1014 /* None of them are directories */
985 rval = D_SAME; 1015 rval = D_SAME;
986 1016
987 if (flags & D_EMPTY1) 1017 if (flags & D_EMPTY1)
@@ -993,20 +1023,12 @@ static unsigned diffreg(char *file1, char *file2, int flags)
993 else 1023 else
994 f2 = xfopen_stdin(file2); 1024 f2 = xfopen_stdin(file2);
995 1025
996/* We can't diff non-seekable stream - we use rewind(), fseek().
997 * This can be fixed (volunteers?).
998 * Meanwhile we should check it here by stat'ing input fds,
999 * but I am lazy and check that in main() instead.
1000 * Check in main won't catch "diffing fifos buried in subdirectories"
1001 * failure scenario - not very likely in real life... */
1002
1003 /* Quick check whether they are different */ 1026 /* Quick check whether they are different */
1027 /* NB: copies non-REG files to tempfiles and fills tempname1/2 */
1004 i = files_differ(f1, f2, flags); 1028 i = files_differ(f1, f2, flags);
1005 if (i == 0) 1029 if (i != 1) { /* not different? */
1006 goto closem; 1030 if (i != 0) /* error? */
1007 else if (i != 1) { /* 1 == ok */ 1031 status |= 2;
1008 /* error */
1009 status |= 2;
1010 goto closem; 1032 goto closem;
1011 } 1033 }
1012 1034
@@ -1059,6 +1081,14 @@ static unsigned diffreg(char *file1, char *file2, int flags)
1059 } 1081 }
1060 fclose_if_not_stdin(f1); 1082 fclose_if_not_stdin(f1);
1061 fclose_if_not_stdin(f2); 1083 fclose_if_not_stdin(f2);
1084 if (tempname1) {
1085 unlink(tempname1);
1086 free(tempname1);
1087 }
1088 if (tempname2) {
1089 unlink(tempname2);
1090 free(tempname2);
1091 }
1062 return rval; 1092 return rval;
1063} 1093}
1064 1094
@@ -1106,8 +1136,10 @@ static void do_diff(char *dir1, char *path1, char *dir2, char *path2)
1106 val = D_SKIPPED1; 1136 val = D_SKIPPED1;
1107 else if (!S_ISREG(stb2.st_mode) && !S_ISDIR(stb2.st_mode)) 1137 else if (!S_ISREG(stb2.st_mode) && !S_ISDIR(stb2.st_mode))
1108 val = D_SKIPPED2; 1138 val = D_SKIPPED2;
1109 else 1139 else {
1140 /* Both files are either REGular or DIRectories */
1110 val = diffreg(fullpath1, fullpath2, flags); 1141 val = diffreg(fullpath1, fullpath2, flags);
1142 }
1111 1143
1112 print_status(val, fullpath1, fullpath2 /*, NULL*/); 1144 print_status(val, fullpath1, fullpath2 /*, NULL*/);
1113 ret: 1145 ret:
@@ -1133,7 +1165,7 @@ static int add_to_dirlist(const char *filename,
1133 1165
1134 1166
1135/* This returns a sorted directory listing. */ 1167/* This returns a sorted directory listing. */
1136static char **get_dir(char *path) 1168static char **get_recursive_dirlist(char *path)
1137{ 1169{
1138 dl_count = 0; 1170 dl_count = 0;
1139 dl = xzalloc(sizeof(dl[0])); 1171 dl = xzalloc(sizeof(dl[0]));
@@ -1143,7 +1175,6 @@ static char **get_dir(char *path)
1143 * the recursed paths, so use void *userdata to specify the string 1175 * the recursed paths, so use void *userdata to specify the string
1144 * length of the root directory - '(void*)(strlen(path)+)'. 1176 * length of the root directory - '(void*)(strlen(path)+)'.
1145 * add_to_dirlist then removes root dir prefix. */ 1177 * add_to_dirlist then removes root dir prefix. */
1146
1147 if (option_mask32 & FLAG_r) { 1178 if (option_mask32 & FLAG_r) {
1148 recursive_action(path, ACTION_RECURSE|ACTION_FOLLOWLINKS, 1179 recursive_action(path, ACTION_RECURSE|ACTION_FOLLOWLINKS,
1149 add_to_dirlist, NULL, 1180 add_to_dirlist, NULL,
@@ -1184,8 +1215,8 @@ static void diffdir(char *p1, char *p2)
1184 *dp2 = '\0'; 1215 *dp2 = '\0';
1185 1216
1186 /* Get directory listings for p1 and p2. */ 1217 /* Get directory listings for p1 and p2. */
1187 dirlist1 = get_dir(p1); 1218 dirlist1 = get_recursive_dirlist(p1);
1188 dirlist2 = get_dir(p2); 1219 dirlist2 = get_recursive_dirlist(p2);
1189 1220
1190 /* If -S was set, find the starting point. */ 1221 /* If -S was set, find the starting point. */
1191 if (start) { 1222 if (start) {
@@ -1204,7 +1235,7 @@ static void diffdir(char *p1, char *p2)
1204 while (*dirlist1 != NULL || *dirlist2 != NULL) { 1235 while (*dirlist1 != NULL || *dirlist2 != NULL) {
1205 dp1 = *dirlist1; 1236 dp1 = *dirlist1;
1206 dp2 = *dirlist2; 1237 dp2 = *dirlist2;
1207 pos = dp1 == NULL ? 1 : dp2 == NULL ? -1 : strcmp(dp1, dp2); 1238 pos = dp1 == NULL ? 1 : (dp2 == NULL ? -1 : strcmp(dp1, dp2));
1208 if (pos == 0) { 1239 if (pos == 0) {
1209 do_diff(p1, dp1, p2, dp2); 1240 do_diff(p1, dp1, p2, dp2);
1210 dirlist1++; 1241 dirlist1++;
@@ -1230,7 +1261,7 @@ static void diffdir(char *p1, char *p2)
1230int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1261int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1231int diff_main(int argc ATTRIBUTE_UNUSED, char **argv) 1262int diff_main(int argc ATTRIBUTE_UNUSED, char **argv)
1232{ 1263{
1233 bool gotstdin = 0; 1264 int gotstdin = 0;
1234 char *f1, *f2; 1265 char *f1, *f2;
1235 llist_t *L_arg = NULL; 1266 llist_t *L_arg = NULL;
1236 1267
@@ -1264,37 +1295,43 @@ int diff_main(int argc ATTRIBUTE_UNUSED, char **argv)
1264 f2 = argv[1]; 1295 f2 = argv[1];
1265 if (LONE_DASH(f1)) { 1296 if (LONE_DASH(f1)) {
1266 fstat(STDIN_FILENO, &stb1); 1297 fstat(STDIN_FILENO, &stb1);
1267 gotstdin = 1; 1298 gotstdin++;
1268 } else 1299 } else
1269 xstat(f1, &stb1); 1300 xstat(f1, &stb1);
1270 if (LONE_DASH(f2)) { 1301 if (LONE_DASH(f2)) {
1271 fstat(STDIN_FILENO, &stb2); 1302 fstat(STDIN_FILENO, &stb2);
1272 gotstdin = 1; 1303 gotstdin++;
1273 } else 1304 } else
1274 xstat(f2, &stb2); 1305 xstat(f2, &stb2);
1306
1275 if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode))) 1307 if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
1276 bb_error_msg_and_die("can't compare - to a directory"); 1308 bb_error_msg_and_die("can't compare stdin to a directory");
1309
1277 if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) { 1310 if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
1278#if ENABLE_FEATURE_DIFF_DIR 1311#if ENABLE_FEATURE_DIFF_DIR
1279 diffdir(f1, f2); 1312 diffdir(f1, f2);
1313 return status;
1280#else 1314#else
1281 bb_error_msg_and_die("directory comparison not supported"); 1315 bb_error_msg_and_die("no support for directory comparison");
1282#endif 1316#endif
1283 } else {
1284 if (S_ISDIR(stb1.st_mode)) {
1285 f1 = concat_path_file(f1, f2);
1286 xstat(f1, &stb1);
1287 }
1288 if (S_ISDIR(stb2.st_mode)) {
1289 f2 = concat_path_file(f2, f1);
1290 xstat(f2, &stb2);
1291 }
1292/* XXX: FIXME: */
1293/* We can't diff e.g. stdin supplied by a pipe - we use rewind(), fseek().
1294 * This can be fixed (volunteers?) */
1295 if (!S_ISREG(stb1.st_mode) || !S_ISREG(stb2.st_mode))
1296 bb_error_msg_and_die("can't diff non-seekable stream");
1297 print_status(diffreg(f1, f2, 0), f1, f2 /*, NULL*/);
1298 } 1317 }
1318
1319 if (S_ISDIR(stb1.st_mode)) { /* "diff dir file" */
1320 /* NB: "diff dir dir2/dir3/file" must become
1321 * "diff dir/file dir2/dir3/file" */
1322 char *slash = strrchr(f2, '/');
1323 f1 = concat_path_file(f1, slash ? slash+1 : f2);
1324 xstat(f1, &stb1);
1325 }
1326 if (S_ISDIR(stb2.st_mode)) {
1327 char *slash = strrchr(f1, '/');
1328 f2 = concat_path_file(f2, slash ? slash+1 : f1);
1329 xstat(f2, &stb2);
1330 }
1331
1332 /* diffreg can get non-regular files here,
1333 * they are not both DIRestories */
1334 print_status((gotstdin > 1 ? D_SAME : diffreg(f1, f2, 0)),
1335 f1, f2 /*, NULL*/);
1299 return status; 1336 return status;
1300} 1337}