/* Copyright (c) 1979 Regents of the University of California */ #include <retrofit.h> #include <stdio.h> /* * Diffdir - a (first) directory difference program * Bill Joy UCB March 16, 1978 * * This is a difference program which operates on the entire contents of * a directory. It reports common files which are different, running * diff if the files are ASCII files. It also reports files which are * unique to one of the two directories. * * An option "h" (for header) causes diffdir to print each difference * on a new page (using an appropriate "pr") and to summarize missing * files and differences in binary files on a final page. * * Option "s" causes files which are the same to be reported also. * * It would be nice if this were "difftree", and if it knew a few * more things, e.g to "size" objects which are different or some * such or at least to not say that "directories are different" calling * them files, i.e. "Files ex-1.1/temp and ex-1.2/temp are different". */ typedef char bool; struct entry { char *name; int flags; } *dir1, *dir2; #define ONLY 1 #define DIFFER 2 bool hflg; bool vflg; bool sflg; #define vprintf if (vflg) printf main(argc, argv) int argc; char *argv[]; { register struct entry *d1, *d2; register char *cp; while (argc > 1) { cp = argv[1]; if (*cp++ != '-') break; while (*cp) switch (*cp++) { case 'h': hflg++; continue; case 'v': vflg++; continue; case 's': sflg++; continue; default: usage: panic("Usage: diffdir [ -h ] dir1 dir2"); } argc--, argv++; } if (argc != 3) goto usage; setupdir(argv[1], &dir1); setupdir(argv[2], &dir2); d1 = dir1; d2 = dir2; while (d1->name != 0 || d2->name != 0) { if (useless(d1->name)) { d1++; continue; } if (useless(d2->name)) { d2++; continue; } if (d1->name != 0 && d2->name != 0) switch (sgn(strcmp(d1->name, d2->name))) { case -1: onlyin1: if (hflg) d1->flags =| ONLY; else printf("Only in %s: %s\n", argv[1], d1->name); d1++; continue; case 0: vprintf("In both: %s\n", d1->name); compare(d1, argv[1], argv[2]); d1++; d2++; continue; case 1: onlyin2: if (hflg) d2->flags =| ONLY; else printf("Only in %s: %s\n", argv[2], d2->name); d2++; continue; } if (d1->name != 0) goto onlyin1; else goto onlyin2; } if (hflg) { int header = 0; for (d1 = dir1; d1->name; d1++) if (d1->flags & ONLY) { if (header == 0) { printf("\fOnly in %s\n", argv[1]); header = 1; } printf("\t%s\n", d1->name); } for (d2 = dir2; d2->name != 0; d2++) { if (d2->flags & ONLY) { if (header == 0) printf("\f"); if ((header & 2) == 0) { printf("Only in %s\n", argv[2]); header =| 2; } printf("\t%s\n", d2->name); } } for (d1 = dir1; d1->name; d1++) if (d1->flags & DIFFER) { if (header == 0) { printf("\f"); header = 1; } if ((header & 4) == 0) { printf("Non-ascii files which differ:\n"); header =| 4; } printf("\t%s\n", d1->name); } } exit(0); } int entcmp(); setupdir(cp, head) char *cp; struct entry **head; { int count = 1; struct dirent0 { short ino; char fname[14]; }; struct dirent1 { short ino; char fname1[16]; } dirent; register struct entry *hp; close(0); if (open(cp, 0) < 0) { perror(cp); exit(1); } while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0)) if (dirent.ino) count++; lseek(0, (long) 0, 0); hp = *head = Calloc(count, sizeof **head); while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0)) if (dirent.ino) { hp->name = savestr(dirent.fname); hp++; } qsort(*head, count - 1, sizeof **head, entcmp); } entcmp(ep, ep2) struct entry *ep, *ep2; { return (strcmp(ep->name, ep2->name)); } Calloc(i, n) int i, n; { register unsigned mem; mem = calloc(i, n); if (mem == 0) panic("Ran out of memory"); return (mem); } savestr(cp) register char *cp; { return (strcpy(calloc(strlen(cp)+1, sizeof (char)), cp)); } panic(cp) char *cp; { fprintf(stderr, "%s\n", cp); exit(1); } sgn(i) int i; { if (i > 0) return (1); else if (i < 0) return (-1); return (0); } compare(dp, d1, d2) struct entry *dp; char *d1, *d2; { register int i; char path1[100], path2[100]; int t1, t2; char header[250]; char *name = dp->name; if (max(strlen(d1), strlen(d2)) + strlen(name) + 2 >= 100) panic("Path names too long"); strcat(strcat(strcpy(path1, d1), "/"), name); strcat(strcat(strcpy(path2, d2), "/"), name); i = callit("/usr/bin/cmp", "cmp", "-s", path1, path2, 0); if (i == 0) { if (sflg) printf("Files %s and %s same\n", path1, path2); return; } if (!ascii(path1) || !ascii(path2)) { if (hflg) dp->flags =| DIFFER; else printf("Files %s and %s differ\n", path1, path2); return; } if (hflg) { sprintf(header, "diff %s %s", path1, path2); prcallit(header, "/usr/bin/diff", "diff", path1, path2, 0); } else { printf("diff %s %s\n", path1, path2); callit("/usr/bin/diff", "diff", path1, path2, 0); } } prcallit(header, path, av) char *header, *path; { int status; int pid; int pv[2]; fflush(stdout); pipe(pv); pid = fork(); if (pid == -1) panic("No more processes"); if (pid == 0) { close(0); dup(pv[0]); close(pv[0]); close(pv[1]); execl("/bin/pr", "pr", "-h", header, 0); execl("/usr/bin/pr", "pr", "-h", header, 0); perror("/usr/bin/pr"); exit(1); } pid = fork(); if (pid == -1) panic("No more processes"); if (pid == 0) { close(1); dup(pv[1]); close(pv[0]); close(pv[1]); execv(path+4, &av); execv(path, &av); perror(path); exit(1); } close(pv[0]); close(pv[1]); while (wait(&status) != -1) continue; } callit(path, av) char *path; { int status; int pid; fflush(stdout); pid = fork(); if (pid == -1) panic("No more processes"); if (pid == 0) { execv(path+4, &av); execv(path, &av); perror(path); exit(1); } wait(&status); return (((status >> 8) & 0377) | (status & 0377)); } max(a,b) int a,b; { return (a > b ? a : b); } ascii(cp) char *cp; { int f; short w; f = open(cp, 0); if (f < 0) return (0); if (read(f, &w, sizeof w) != sizeof w) { close(f); return (1); } close(f); switch (w) { case 0405: /* Overlay executable */ case 0407: /* Executable */ case 0410: /* Pure executable */ case 0411: /* Separate executable */ case 0177545: /* Archive */ case 0177555: /* Old archive */ return (0); default: if (w & 0100200) return (0); return (1); } } useless(cp) char *cp; { if (strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) return (1); if (cp[0] == '.') return (1); /* For now */ return (0); }