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