1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)diffdir.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include "diff.h"
13 /*
14 * diff - directory comparison
15 */
16 #define d_flags d_ino
17
18 #define ONLY 1 /* Only in this directory */
19 #define SAME 2 /* Both places and same */
20 #define DIFFER 4 /* Both places and different */
21 #define DIRECT 8 /* Directory */
22
23 struct dir {
24 u_long d_ino;
25 short d_reclen;
26 short d_namlen;
27 char *d_entry;
28 };
29
30 struct dir *setupdir();
31 int header;
32 static int dirstatus; /* exit status from diffdir */
33 extern int status;
34 char title[2*BUFSIZ], *etitle;
35
diffdir(argv)36 diffdir(argv)
37 char **argv;
38 {
39 register struct dir *d1, *d2;
40 struct dir *dir1, *dir2;
41 register int i;
42 int cmp;
43
44 if (opt == D_IFDEF) {
45 fprintf(stderr, "diff: can't specify -I with directories\n");
46 done();
47 }
48 if (opt == D_EDIT && (sflag || lflag))
49 fprintf(stderr,
50 "diff: warning: shouldn't give -s or -l with -e\n");
51 title[0] = 0;
52 strcpy(title, "diff ");
53 for (i = 1; diffargv[i+2]; i++) {
54 if (!strcmp(diffargv[i], "-"))
55 continue; /* was -S, dont look silly */
56 strcat(title, diffargv[i]);
57 strcat(title, " ");
58 }
59 for (etitle = title; *etitle; etitle++)
60 ;
61 setfile(&file1, &efile1, file1);
62 setfile(&file2, &efile2, file2);
63 argv[0] = file1;
64 argv[1] = file2;
65 dir1 = setupdir(file1);
66 dir2 = setupdir(file2);
67 d1 = dir1; d2 = dir2;
68 while (d1->d_entry != 0 || d2->d_entry != 0) {
69 if (d1->d_entry && useless(d1->d_entry)) {
70 d1++;
71 continue;
72 }
73 if (d2->d_entry && useless(d2->d_entry)) {
74 d2++;
75 continue;
76 }
77 if (d1->d_entry == 0)
78 cmp = 1;
79 else if (d2->d_entry == 0)
80 cmp = -1;
81 else
82 cmp = strcmp(d1->d_entry, d2->d_entry);
83 if (cmp < 0) {
84 if (lflag)
85 d1->d_flags |= ONLY;
86 else if (opt == 0 || opt == 2)
87 only(d1, 1);
88 d1++;
89 dirstatus |= 1;
90 } else if (cmp == 0) {
91 compare(d1);
92 d1++;
93 d2++;
94 } else {
95 if (lflag)
96 d2->d_flags |= ONLY;
97 else if (opt == 0 || opt == 2)
98 only(d2, 2);
99 d2++;
100 dirstatus |= 1;
101 }
102 }
103 if (lflag) {
104 scanpr(dir1, ONLY, "Only in %.*s", file1, efile1, 0, 0);
105 scanpr(dir2, ONLY, "Only in %.*s", file2, efile2, 0, 0);
106 scanpr(dir1, SAME, "Common identical files in %.*s and %.*s",
107 file1, efile1, file2, efile2);
108 scanpr(dir1, DIFFER, "Binary files which differ in %.*s and %.*s",
109 file1, efile1, file2, efile2);
110 scanpr(dir1, DIRECT, "Common subdirectories of %.*s and %.*s",
111 file1, efile1, file2, efile2);
112 }
113 if (rflag) {
114 if (header && lflag)
115 printf("\f");
116 for (d1 = dir1; d1->d_entry; d1++) {
117 if ((d1->d_flags & DIRECT) == 0)
118 continue;
119 strcpy(efile1, d1->d_entry);
120 strcpy(efile2, d1->d_entry);
121 calldiff(0);
122 }
123 }
124 status = dirstatus;
125 }
126
setfile(fpp,epp,file)127 setfile(fpp, epp, file)
128 char **fpp, **epp;
129 char *file;
130 {
131 register char *cp;
132
133 *fpp = malloc(BUFSIZ);
134 if (*fpp == 0) {
135 fprintf(stderr, "diff: ran out of memory\n");
136 exit(1);
137 }
138 strcpy(*fpp, file);
139 for (cp = *fpp; *cp; cp++)
140 continue;
141 *cp++ = '/';
142 *epp = cp;
143 }
144
scanpr(dp,test,title,file1,efile1,file2,efile2)145 scanpr(dp, test, title, file1, efile1, file2, efile2)
146 register struct dir *dp;
147 int test;
148 char *title, *file1, *efile1, *file2, *efile2;
149 {
150 int titled = 0;
151
152 for (; dp->d_entry; dp++) {
153 if ((dp->d_flags & test) == 0)
154 continue;
155 if (titled == 0) {
156 if (header == 0)
157 header = 1;
158 else
159 printf("\n");
160 printf(title,
161 efile1 - file1 - 1, file1,
162 efile2 - file2 - 1, file2);
163 printf(":\n");
164 titled = 1;
165 }
166 printf("\t%s\n", dp->d_entry);
167 }
168 }
169
170 only(dp, which)
171 struct dir *dp;
172 int which;
173 {
174 char *file = which == 1 ? file1 : file2;
175 char *efile = which == 1 ? efile1 : efile2;
176
177 printf("Only in %.*s: %s\n", efile - file - 1, file, dp->d_entry);
178
179 }
180
181 int entcmp();
182
183 struct dir *
setupdir(cp)184 setupdir(cp)
185 char *cp;
186 {
187 register struct dir *dp, *ep;
188 register struct direct *rp;
189 register int nitems, n;
190 DIR *dirp;
191
192 dirp = opendir(cp);
193 if (dirp == NULL) {
194 fprintf(stderr, "diff: ");
195 perror(cp);
196 done();
197 }
198 nitems = 0;
199 dp = (struct dir *)malloc(sizeof (struct dir));
200 if (dp == 0) {
201 fprintf(stderr, "diff: ran out of memory\n");
202 done();
203 }
204 while (rp = readdir(dirp)) {
205 ep = &dp[nitems++];
206 ep->d_reclen = rp->d_reclen;
207 ep->d_namlen = rp->d_namlen;
208 ep->d_entry = 0;
209 ep->d_flags = 0;
210 if (ep->d_namlen > 0) {
211 ep->d_entry = malloc(ep->d_namlen + 1);
212 if (ep->d_entry == 0) {
213 fprintf(stderr, "diff: out of memory\n");
214 done();
215 }
216 strcpy(ep->d_entry, rp->d_name);
217 }
218 dp = (struct dir *)realloc((char *)dp,
219 (nitems + 1) * sizeof (struct dir));
220 if (dp == 0) {
221 fprintf(stderr, "diff: ran out of memory\n");
222 done();
223 }
224 }
225 dp[nitems].d_entry = 0; /* delimiter */
226 closedir(dirp);
227 qsort(dp, nitems, sizeof (struct dir), entcmp);
228 return (dp);
229 }
230
231 entcmp(d1, d2)
232 struct dir *d1, *d2;
233 {
234 return (strcmp(d1->d_entry, d2->d_entry));
235 }
236
compare(dp)237 compare(dp)
238 register struct dir *dp;
239 {
240 register int i, j;
241 int f1, f2, fmt1, fmt2;
242 struct stat stb1, stb2;
243 int flag = 0;
244 char buf1[BUFSIZ], buf2[BUFSIZ];
245
246 strcpy(efile1, dp->d_entry);
247 strcpy(efile2, dp->d_entry);
248 f1 = open(file1, 0);
249 if (f1 < 0) {
250 perror(file1);
251 return;
252 }
253 f2 = open(file2, 0);
254 if (f2 < 0) {
255 perror(file2);
256 close(f1);
257 return;
258 }
259 fstat(f1, &stb1); fstat(f2, &stb2);
260 fmt1 = stb1.st_mode & S_IFMT;
261 fmt2 = stb2.st_mode & S_IFMT;
262 if (fmt1 != S_IFREG || fmt2 != S_IFREG) {
263 if (fmt1 == fmt2) {
264 if (fmt1 != S_IFDIR && stb1.st_rdev == stb2.st_rdev)
265 goto same;
266 if (fmt1 == S_IFDIR) {
267 dp->d_flags = DIRECT;
268 if (lflag || opt == D_EDIT)
269 goto closem;
270 printf("Common subdirectories: %s and %s\n",
271 file1, file2);
272 goto closem;
273 }
274 }
275 goto notsame;
276 }
277 if (stb1.st_size != stb2.st_size)
278 goto notsame;
279 for (;;) {
280 i = read(f1, buf1, BUFSIZ);
281 j = read(f2, buf2, BUFSIZ);
282 if (i < 0 || j < 0 || i != j)
283 goto notsame;
284 if (i == 0 && j == 0)
285 goto same;
286 for (j = 0; j < i; j++)
287 if (buf1[j] != buf2[j])
288 goto notsame;
289 }
290 same:
291 if (sflag == 0)
292 goto closem;
293 if (lflag)
294 dp->d_flags = SAME;
295 else
296 printf("Files %s and %s are identical\n", file1, file2);
297 goto closem;
298 notsame:
299 dirstatus |= 1;
300 if (!ascii(f1) || !ascii(f2)) {
301 if (lflag)
302 dp->d_flags |= DIFFER;
303 else if (opt == D_NORMAL || opt == D_CONTEXT)
304 printf("Binary files %s and %s differ\n",
305 file1, file2);
306 goto closem;
307 }
308 close(f1); close(f2);
309 anychange = 1;
310 if (lflag)
311 calldiff(title);
312 else {
313 if (opt == D_EDIT) {
314 printf("ed - %s << '-*-END-*-'\n", dp->d_entry);
315 calldiff(0);
316 } else {
317 printf("%s%s %s\n", title, file1, file2);
318 calldiff(0);
319 }
320 if (opt == D_EDIT)
321 printf("w\nq\n-*-END-*-\n");
322 }
323 return;
324 closem:
325 close(f1); close(f2);
326 }
327
328 char *prargs[] = { "pr", "-h", 0, "-f", 0, 0 };
329
calldiff(wantpr)330 calldiff(wantpr)
331 char *wantpr;
332 {
333 int pid, lstatus, lstatus2, pv[2];
334
335 prargs[2] = wantpr;
336 fflush(stdout);
337 if (wantpr) {
338 (void)sprintf(etitle, "%s %s", file1, file2);
339 pipe(pv);
340 pid = fork();
341 if (pid == -1) {
342 fprintf(stderr, "No more processes");
343 done();
344 }
345 if (pid == 0) {
346 close(0);
347 dup(pv[0]);
348 close(pv[0]);
349 close(pv[1]);
350 execv(pr+4, prargs);
351 execv(pr, prargs);
352 perror(pr);
353 done();
354 }
355 }
356 pid = fork();
357 if (pid == -1) {
358 fprintf(stderr, "diff: No more processes\n");
359 done();
360 }
361 if (pid == 0) {
362 if (wantpr) {
363 close(1);
364 dup(pv[1]);
365 close(pv[0]);
366 close(pv[1]);
367 }
368 execv(diff+4, diffargv);
369 execv(diff, diffargv);
370 perror(diff);
371 done();
372 }
373 if (wantpr) {
374 close(pv[0]);
375 close(pv[1]);
376 }
377 while (wait(&lstatus) != pid)
378 continue;
379 while (wait(&lstatus2) != -1)
380 continue;
381 /*
382 if ((lstatus >> 8) >= 2)
383 done();
384 */
385 dirstatus |= lstatus >> 8;
386 }
387
388 #include <a.out.h>
389
ascii(f)390 ascii(f)
391 int f;
392 {
393 char buf[BUFSIZ];
394 register int cnt;
395 register char *cp;
396
397 lseek(f, (long)0, 0);
398 cnt = read(f, buf, BUFSIZ);
399 if (cnt >= sizeof (struct exec)) {
400 struct exec hdr;
401 hdr = *(struct exec *)buf;
402 if (!N_BADMAG(hdr))
403 return (0);
404 }
405 cp = buf;
406 while (--cnt >= 0)
407 if (*cp++ & 0200)
408 return (0);
409 return (1);
410 }
411
412 /*
413 * THIS IS CRUDE.
414 */
useless(cp)415 useless(cp)
416 register char *cp;
417 {
418
419 if (cp[0] == '.') {
420 if (cp[1] == '\0')
421 return (1); /* directory "." */
422 if (cp[1] == '.' && cp[2] == '\0')
423 return (1); /* directory ".." */
424 }
425 if (Start && strcmp(Start, cp) > 0)
426 return (1);
427 return (0);
428 }
429