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