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 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 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 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 * 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 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 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 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 */ 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