1 /* $OpenBSD: diffdir.c,v 1.2 2003/06/25 01:23:38 deraadt Exp $ */ 2 3 /* 4 * Copyright (C) Caldera International Inc. 2001-2002. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code and documentation must retain the above 11 * copyright notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed or owned by Caldera 18 * International, Inc. 19 * 4. Neither the name of Caldera International, Inc. nor the names of other 20 * contributors may be used to endorse or promote products derived from 21 * this software without specific prior written permission. 22 * 23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28 * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 static char *sccsid = "@(#)diffdir.c 4.12 (Berkeley) 4/30/89"; 38 39 #include "diff.h" 40 /* 41 * diff - directory comparison 42 */ 43 #define d_flags d_ino 44 45 #define ONLY 1 /* Only in this directory */ 46 #define SAME 2 /* Both places and same */ 47 #define DIFFER 4 /* Both places and different */ 48 #define DIRECT 8 /* Directory */ 49 50 struct dir { 51 u_long d_ino; 52 short d_reclen; 53 short d_namlen; 54 char *d_entry; 55 }; 56 57 struct dir *setupdir(); 58 int header; 59 static int dirstatus; /* exit status from diffdir */ 60 extern int status; 61 char title[2*BUFSIZ], *etitle; 62 63 diffdir(argv) 64 char **argv; 65 { 66 register struct dir *d1, *d2; 67 struct dir *dir1, *dir2; 68 register int i; 69 int cmp; 70 71 if (opt == D_IFDEF) { 72 fprintf(stderr, "diff: can't specify -I with directories\n"); 73 done(); 74 } 75 if (opt == D_EDIT && (sflag || lflag)) 76 fprintf(stderr, 77 "diff: warning: shouldn't give -s or -l with -e\n"); 78 title[0] = 0; 79 strcpy(title, "diff "); 80 for (i = 1; diffargv[i+2]; i++) { 81 if (!strcmp(diffargv[i], "-")) 82 continue; /* was -S, dont look silly */ 83 strcat(title, diffargv[i]); 84 strcat(title, " "); 85 } 86 for (etitle = title; *etitle; etitle++) 87 ; 88 setfile(&file1, &efile1, file1); 89 setfile(&file2, &efile2, file2); 90 argv[0] = file1; 91 argv[1] = file2; 92 dir1 = setupdir(file1); 93 dir2 = setupdir(file2); 94 d1 = dir1; d2 = dir2; 95 while (d1->d_entry != 0 || d2->d_entry != 0) { 96 if (d1->d_entry && useless(d1->d_entry)) { 97 d1++; 98 continue; 99 } 100 if (d2->d_entry && useless(d2->d_entry)) { 101 d2++; 102 continue; 103 } 104 if (d1->d_entry == 0) 105 cmp = 1; 106 else if (d2->d_entry == 0) 107 cmp = -1; 108 else 109 cmp = strcmp(d1->d_entry, d2->d_entry); 110 if (cmp < 0) { 111 if (lflag) 112 d1->d_flags |= ONLY; 113 else if (opt == 0 || opt == 2) 114 only(d1, 1); 115 d1++; 116 dirstatus |= 1; 117 } else if (cmp == 0) { 118 compare(d1); 119 d1++; 120 d2++; 121 } else { 122 if (lflag) 123 d2->d_flags |= ONLY; 124 else if (opt == 0 || opt == 2) 125 only(d2, 2); 126 d2++; 127 dirstatus |= 1; 128 } 129 } 130 if (lflag) { 131 scanpr(dir1, ONLY, "Only in %.*s", file1, efile1, 0, 0); 132 scanpr(dir2, ONLY, "Only in %.*s", file2, efile2, 0, 0); 133 scanpr(dir1, SAME, "Common identical files in %.*s and %.*s", 134 file1, efile1, file2, efile2); 135 scanpr(dir1, DIFFER, "Binary files which differ in %.*s and %.*s", 136 file1, efile1, file2, efile2); 137 scanpr(dir1, DIRECT, "Common subdirectories of %.*s and %.*s", 138 file1, efile1, file2, efile2); 139 } 140 if (rflag) { 141 if (header && lflag) 142 printf("\f"); 143 for (d1 = dir1; d1->d_entry; d1++) { 144 if ((d1->d_flags & DIRECT) == 0) 145 continue; 146 strcpy(efile1, d1->d_entry); 147 strcpy(efile2, d1->d_entry); 148 calldiff(0); 149 } 150 } 151 status = dirstatus; 152 } 153 154 setfile(fpp, epp, file) 155 char **fpp, **epp; 156 char *file; 157 { 158 register char *cp; 159 160 *fpp = malloc(BUFSIZ); 161 if (*fpp == 0) { 162 fprintf(stderr, "diff: ran out of memory\n"); 163 exit(1); 164 } 165 strcpy(*fpp, file); 166 for (cp = *fpp; *cp; cp++) 167 continue; 168 *cp++ = '/'; 169 *epp = cp; 170 } 171 172 scanpr(dp, test, title, file1, efile1, file2, efile2) 173 register struct dir *dp; 174 int test; 175 char *title, *file1, *efile1, *file2, *efile2; 176 { 177 int titled = 0; 178 179 for (; dp->d_entry; dp++) { 180 if ((dp->d_flags & test) == 0) 181 continue; 182 if (titled == 0) { 183 if (header == 0) 184 header = 1; 185 else 186 printf("\n"); 187 printf(title, 188 efile1 - file1 - 1, file1, 189 efile2 - file2 - 1, file2); 190 printf(":\n"); 191 titled = 1; 192 } 193 printf("\t%s\n", dp->d_entry); 194 } 195 } 196 197 only(dp, which) 198 struct dir *dp; 199 int which; 200 { 201 char *file = which == 1 ? file1 : file2; 202 char *efile = which == 1 ? efile1 : efile2; 203 204 printf("Only in %.*s: %s\n", efile - file - 1, file, dp->d_entry); 205 206 } 207 208 int entcmp(); 209 210 struct dir * 211 setupdir(cp) 212 char *cp; 213 { 214 register struct dir *dp, *ep; 215 register struct direct *rp; 216 register int nitems, n; 217 DIR *dirp; 218 219 dirp = opendir(cp); 220 if (dirp == NULL) { 221 fprintf(stderr, "diff: "); 222 perror(cp); 223 done(); 224 } 225 nitems = 0; 226 dp = (struct dir *)malloc(sizeof (struct dir)); 227 if (dp == 0) { 228 fprintf(stderr, "diff: ran out of memory\n"); 229 done(); 230 } 231 while (rp = readdir(dirp)) { 232 ep = &dp[nitems++]; 233 ep->d_reclen = rp->d_reclen; 234 ep->d_namlen = rp->d_namlen; 235 ep->d_entry = 0; 236 ep->d_flags = 0; 237 if (ep->d_namlen > 0) { 238 ep->d_entry = malloc(ep->d_namlen + 1); 239 if (ep->d_entry == 0) { 240 fprintf(stderr, "diff: out of memory\n"); 241 done(); 242 } 243 strcpy(ep->d_entry, rp->d_name); 244 } 245 dp = (struct dir *)realloc((char *)dp, 246 (nitems + 1) * sizeof (struct dir)); 247 if (dp == 0) { 248 fprintf(stderr, "diff: ran out of memory\n"); 249 done(); 250 } 251 } 252 dp[nitems].d_entry = 0; /* delimiter */ 253 closedir(dirp); 254 qsort(dp, nitems, sizeof (struct dir), entcmp); 255 return (dp); 256 } 257 258 entcmp(d1, d2) 259 struct dir *d1, *d2; 260 { 261 return (strcmp(d1->d_entry, d2->d_entry)); 262 } 263 264 compare(dp) 265 register struct dir *dp; 266 { 267 register int i, j; 268 int f1, f2, fmt1, fmt2; 269 struct stat stb1, stb2; 270 int flag = 0; 271 char buf1[BUFSIZ], buf2[BUFSIZ]; 272 273 strcpy(efile1, dp->d_entry); 274 strcpy(efile2, dp->d_entry); 275 f1 = open(file1, 0); 276 if (f1 < 0) { 277 perror(file1); 278 return; 279 } 280 f2 = open(file2, 0); 281 if (f2 < 0) { 282 perror(file2); 283 close(f1); 284 return; 285 } 286 fstat(f1, &stb1); fstat(f2, &stb2); 287 fmt1 = stb1.st_mode & S_IFMT; 288 fmt2 = stb2.st_mode & S_IFMT; 289 if (fmt1 != S_IFREG || fmt2 != S_IFREG) { 290 if (fmt1 == fmt2) { 291 if (fmt1 != S_IFDIR && stb1.st_rdev == stb2.st_rdev) 292 goto same; 293 if (fmt1 == S_IFDIR) { 294 dp->d_flags = DIRECT; 295 if (lflag || opt == D_EDIT) 296 goto closem; 297 printf("Common subdirectories: %s and %s\n", 298 file1, file2); 299 goto closem; 300 } 301 } 302 goto notsame; 303 } 304 if (stb1.st_size != stb2.st_size) 305 goto notsame; 306 for (;;) { 307 i = read(f1, buf1, BUFSIZ); 308 j = read(f2, buf2, BUFSIZ); 309 if (i < 0 || j < 0 || i != j) 310 goto notsame; 311 if (i == 0 && j == 0) 312 goto same; 313 for (j = 0; j < i; j++) 314 if (buf1[j] != buf2[j]) 315 goto notsame; 316 } 317 same: 318 if (sflag == 0) 319 goto closem; 320 if (lflag) 321 dp->d_flags = SAME; 322 else 323 printf("Files %s and %s are identical\n", file1, file2); 324 goto closem; 325 notsame: 326 dirstatus |= 1; 327 if (!ascii(f1) || !ascii(f2)) { 328 if (lflag) 329 dp->d_flags |= DIFFER; 330 else if (opt == D_NORMAL || opt == D_CONTEXT) 331 printf("Binary files %s and %s differ\n", 332 file1, file2); 333 goto closem; 334 } 335 close(f1); close(f2); 336 anychange = 1; 337 if (lflag) 338 calldiff(title); 339 else { 340 if (opt == D_EDIT) { 341 printf("ed - %s << '-*-END-*-'\n", dp->d_entry); 342 calldiff(0); 343 } else { 344 printf("%s%s %s\n", title, file1, file2); 345 calldiff(0); 346 } 347 if (opt == D_EDIT) 348 printf("w\nq\n-*-END-*-\n"); 349 } 350 return; 351 closem: 352 close(f1); close(f2); 353 } 354 355 char *prargs[] = { "pr", "-h", 0, "-f", 0, 0 }; 356 357 calldiff(wantpr) 358 char *wantpr; 359 { 360 int pid, lstatus, lstatus2, pv[2]; 361 362 prargs[2] = wantpr; 363 fflush(stdout); 364 if (wantpr) { 365 (void)sprintf(etitle, "%s %s", file1, file2); 366 pipe(pv); 367 pid = fork(); 368 if (pid == -1) { 369 fprintf(stderr, "No more processes"); 370 done(); 371 } 372 if (pid == 0) { 373 close(0); 374 dup(pv[0]); 375 close(pv[0]); 376 close(pv[1]); 377 execv(pr+4, prargs); 378 execv(pr, prargs); 379 perror(pr); 380 done(); 381 } 382 } 383 pid = fork(); 384 if (pid == -1) { 385 fprintf(stderr, "diff: No more processes\n"); 386 done(); 387 } 388 if (pid == 0) { 389 if (wantpr) { 390 close(1); 391 dup(pv[1]); 392 close(pv[0]); 393 close(pv[1]); 394 } 395 execv(diff+4, diffargv); 396 execv(diff, diffargv); 397 perror(diff); 398 done(); 399 } 400 if (wantpr) { 401 close(pv[0]); 402 close(pv[1]); 403 } 404 while (wait(&lstatus) != pid) 405 continue; 406 while (wait(&lstatus2) != -1) 407 continue; 408 /* 409 if ((lstatus >> 8) >= 2) 410 done(); 411 */ 412 dirstatus |= lstatus >> 8; 413 } 414 415 #include <a.out.h> 416 417 ascii(f) 418 int f; 419 { 420 char buf[BUFSIZ]; 421 register int cnt; 422 register char *cp; 423 424 lseek(f, (long)0, 0); 425 cnt = read(f, buf, BUFSIZ); 426 if (cnt >= sizeof (struct exec)) { 427 struct exec hdr; 428 hdr = *(struct exec *)buf; 429 if (!N_BADMAG(hdr)) 430 return (0); 431 } 432 cp = buf; 433 while (--cnt >= 0) 434 if (*cp++ & 0200) 435 return (0); 436 return (1); 437 } 438 439 /* 440 * THIS IS CRUDE. 441 */ 442 useless(cp) 443 register char *cp; 444 { 445 446 if (cp[0] == '.') { 447 if (cp[1] == '\0') 448 return (1); /* directory "." */ 449 if (cp[1] == '.' && cp[2] == '\0') 450 return (1); /* directory ".." */ 451 } 452 if (start && strcmp(start, cp) > 0) 453 return (1); 454 return (0); 455 } 456