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