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