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