|
|
1.1 root 1: #include <stdio.h>
2:
3: /*
4: * Diffdir - a (first) directory difference program
5: * Bill Joy UCB March 16, 1978
6: *
7: * This is a difference program which operates on the entire contents of
8: * a directory. It reports common files which are different, running
9: * diff if the files are ASCII files. It also reports files which are
10: * unique to one of the two directories.
11: *
12: * An option "h" (for header) causes diffdir to print each difference
13: * on a new page (using an appropriate "pr") and to summarize missing
14: * files and differences in binary files on a final page.
15: *
16: * Option "s" causes files which are the same to be reported also.
17: *
18: * It would be nice if this were "difftree", and if it knew a few
19: * more things, e.g to "size" objects which are different or some
20: * such or at least to not say that "directories are different" calling
21: * them files, i.e. "Files ex-1.1/temp and ex-1.2/temp are different".
22: */
23:
24: typedef char bool;
25:
26: struct entry {
27: char *name;
28: int flags;
29: } *dir1, *dir2;
30:
31: #define ONLY 1
32: #define DIFFER 2
33:
34: bool eflg;
35: bool hflg;
36: bool vflg;
37: bool sflg;
38:
39: #define vprintf if (vflg) printf
40: #define diffopt() (eflg ? "-e" : "")
41:
42: main(argc, argv)
43: int argc;
44: char *argv[];
45: {
46: register struct entry *d1, *d2;
47: register char *cp;
48:
49: while (argc > 1) {
50: cp = argv[1];
51: if (*cp++ != '-')
52: break;
53: while (*cp) switch (*cp++) {
54:
55: case 'h':
56: hflg++;
57: continue;
58:
59: case 'v':
60: vflg++;
61: continue;
62:
63: case 's':
64: sflg++;
65: continue;
66:
67: case 'e':
68: eflg++;
69: printf("#\n");
70: continue;
71:
72: default:
73: usage:
74: panic("Usage: diffdir [ -h ] dir1 dir2");
75: }
76: argc--, argv++;
77: }
78: if (argc != 3)
79: goto usage;
80: setupdir(argv[1], &dir1);
81: setupdir(argv[2], &dir2);
82: d1 = dir1; d2 = dir2;
83: while (d1->name != 0 || d2->name != 0) {
84: if (useless(d1->name)) {
85: d1++;
86: continue;
87: }
88: if (useless(d2->name)) {
89: d2++;
90: continue;
91: }
92: if (d1->name != 0 && d2->name != 0)
93: switch (sgn(strcmp(d1->name, d2->name))) {
94:
95: case -1:
96: onlyin1:
97: if (hflg)
98: d1->flags =| ONLY;
99: else if (!eflg)
100: printf("Only in %s: %s\n", argv[1], d1->name);
101: d1++;
102: continue;
103:
104: case 0:
105: vprintf("In both: %s\n", d1->name);
106: compare(d1, argv[1], argv[2]);
107: d1++;
108: d2++;
109: continue;
110:
111: case 1:
112: onlyin2: if (hflg)
113: d2->flags =| ONLY;
114: else if (!eflg)
115: printf("Only in %s: %s\n", argv[2], d2->name);
116: d2++;
117: continue;
118: }
119: if (d1->name != 0)
120: goto onlyin1;
121: else
122: goto onlyin2;
123: }
124: if (hflg) {
125: int header = 0;
126:
127: for (d1 = dir1; d1->name; d1++)
128: if (d1->flags & ONLY) {
129: if (header == 0) {
130: printf("\fOnly in %s\n", argv[1]);
131: header = 1;
132: }
133: printf("\t%s\n", d1->name);
134: }
135: for (d2 = dir2; d2->name != 0; d2++) {
136: if (d2->flags & ONLY) {
137: if (header == 0)
138: printf("\f");
139: if ((header & 2) == 0) {
140: printf("Only in %s\n", argv[2]);
141: header =| 2;
142: }
143: printf("\t%s\n", d2->name);
144: }
145: }
146: for (d1 = dir1; d1->name; d1++)
147: if (d1->flags & DIFFER) {
148: if (header == 0) {
149: printf("\f");
150: header = 1;
151: }
152: if ((header & 4) == 0) {
153: printf("Non-ascii files which differ:\n");
154: header =| 4;
155: }
156: printf("\t%s\n", d1->name);
157: }
158: }
159: exit(0);
160: }
161:
162: int entcmp();
163: setupdir(cp, head)
164: char *cp;
165: struct entry **head;
166: {
167: int count = 1;
168: struct dirent0 {
169: short ino;
170: char fname[14];
171: };
172:
173: struct dirent1 {
174: short ino;
175: char fname1[16];
176: } dirent;
177: register struct entry *hp;
178:
179: close(0);
180: if (open(cp, 0) < 0) {
181: perror(cp);
182: exit(1);
183: }
184: while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0))
185: if (dirent.ino)
186: count++;
187: lseek(0, (long) 0, 0);
188: hp = *head = Calloc(count, sizeof **head);
189: while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0))
190: if (dirent.ino) {
191: hp->name = savestr(dirent.fname);
192: hp++;
193: }
194: qsort(*head, count - 1, sizeof **head, entcmp);
195: }
196:
197: entcmp(ep, ep2)
198: struct entry *ep, *ep2;
199: {
200:
201: return (strcmp(ep->name, ep2->name));
202: }
203:
204: Calloc(i, n)
205: int i, n;
206: {
207: register unsigned mem;
208:
209: mem = calloc(i, n);
210: if (mem == 0)
211: panic("Ran out of memory");
212: return (mem);
213: }
214:
215: savestr(cp)
216: register char *cp;
217: {
218:
219: return (strcpy(calloc(strlen(cp)+1, sizeof (char)), cp));
220: }
221:
222: panic(cp)
223: char *cp;
224: {
225:
226: fprintf(stderr, "%s\n", cp);
227: exit(1);
228: }
229:
230: sgn(i)
231: int i;
232: {
233: if (i > 0)
234: return (1);
235: else if (i < 0)
236: return (-1);
237: return (0);
238: }
239:
240: compare(dp, d1, d2)
241: struct entry *dp;
242: char *d1, *d2;
243: {
244: register int i;
245: char path1[100], path2[100];
246: int t1, t2;
247: char header[250];
248: char *name = dp->name;
249:
250: if (max(strlen(d1), strlen(d2)) + strlen(name) + 2 >= 100)
251: panic("Path names too long");
252: strcat(strcat(strcpy(path1, d1), "/"), name);
253: strcat(strcat(strcpy(path2, d2), "/"), name);
254: i = callit("/usr/bin/cmp", "cmp", "-s", path1, path2, 0);
255: if (i == 0) {
256: if (sflg)
257: printf("Files %s and %s same\n", path1, path2);
258: return;
259: }
260: if (!ascii(path1) || !ascii(path2)) {
261: if (hflg)
262: dp->flags =| DIFFER;
263: else if (!eflg)
264: printf("Files %s and %s differ\n", path1, path2);
265: return;
266: }
267: if (hflg) {
268: sprintf(header, "diff %s %s %s", diffopt(), path1, path2);
269: prcallit(header, "/usr/bin/diff", "diff", path1, path2, 0);
270: } else {
271: if (eflg) {
272: printf("ed - %s << '-*-END-*-'\n", name);
273: callit("/usr/bin/diff", "diff", "-e", path1, path2, 0);
274: } else {
275: printf("diff %s %s\n", path1, path2);
276: callit("/usr/bin/diff", "diff", path1, path2, 0);
277: }
278: if (eflg)
279: printf("w\nq\n'-*-END-*-'\n");
280: }
281: }
282:
283: prcallit(header, path, av)
284: char *header, *path;
285: {
286: int status;
287: int pid;
288: int pv[2];
289:
290: fflush(stdout);
291: pipe(pv);
292: pid = fork();
293: if (pid == -1)
294: panic("No more processes");
295: if (pid == 0) {
296: close(0);
297: dup(pv[0]);
298: close(pv[0]);
299: close(pv[1]);
300: execl("/bin/pr", "pr", "-h", header, 0);
301: execl("/usr/bin/pr", "pr", "-h", header, 0);
302: perror("/usr/bin/pr");
303: exit(1);
304: }
305: pid = fork();
306: if (pid == -1)
307: panic("No more processes");
308: if (pid == 0) {
309: close(1);
310: dup(pv[1]);
311: close(pv[0]);
312: close(pv[1]);
313: execv(path+4, &av);
314: execv(path, &av);
315: perror(path);
316: exit(1);
317: }
318: close(pv[0]);
319: close(pv[1]);
320: while (wait(&status) != -1)
321: continue;
322: }
323:
324: callit(path, av)
325: char *path;
326: {
327: int status;
328: int pid;
329:
330: fflush(stdout);
331: pid = fork();
332: if (pid == -1)
333: panic("No more processes");
334: if (pid == 0) {
335: execv(path+4, &av);
336: execv(path, &av);
337: perror(path);
338: exit(1);
339: }
340: wait(&status);
341: return (((status >> 8) & 0377) | (status & 0377));
342: }
343:
344: max(a,b)
345: int a,b;
346: {
347:
348: return (a > b ? a : b);
349: }
350:
351: ascii(cp)
352: char *cp;
353: {
354: int f;
355: short w;
356:
357: f = open(cp, 0);
358: if (f < 0)
359: return (0);
360: if (read(f, &w, sizeof w) != sizeof w) {
361: close(f);
362: return (1);
363: }
364: close(f);
365: switch (w) {
366:
367: case 0405: /* Overlay executable */
368: case 0407: /* Executable */
369: case 0410: /* Pure executable */
370: case 0411: /* Separate executable */
371: case 0413: /* Demand executable */
372: case 0177545: /* Archive */
373: case 0177555: /* Old archive */
374: return (0);
375: default:
376: if (w & 0100200)
377: return (0);
378: return (1);
379: }
380: }
381:
382: useless(cp)
383: char *cp;
384: {
385:
386: if (strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0)
387: return (1);
388: if (cp[0] == '.')
389: return (1); /* For now */
390: return (0);
391: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.