1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include "diff.h" 5 6 #define DIRECTORY(s) ((s).qid.path&CHDIR) 7 #define REGULAR_FILE(s) ((s).type == 'M' && !DIRECTORY(s)) 8 9 Biobuf stdout; 10 11 static char *tmp[] = {"/tmp/diff1", "/tmp/diff2"}; 12 static int whichtmp; 13 static char *progname; 14 static char usage[] = "diff [ -efmnbwr ] file1 ... file2\n"; 15 16 static void 17 rmtmpfiles(void) 18 { 19 while (whichtmp > 0) { 20 whichtmp--; 21 remove(tmp[whichtmp]); 22 } 23 } 24 25 void 26 done(int status) 27 { 28 rmtmpfiles(); 29 switch(status) 30 { 31 case 0: 32 exits(""); 33 case 1: 34 exits("some"); 35 default: 36 exits("error"); 37 } 38 /*NOTREACHED*/ 39 } 40 41 void 42 panic(int status, char *fmt, ...) 43 { 44 va_list arg; 45 char buf[1024], *out; 46 47 Bflush(&stdout); 48 49 out = buf+snprint(buf, sizeof(buf), "%s: ", progname); 50 va_start(arg, fmt); 51 out = doprint(out, buf+sizeof(buf), fmt, arg); 52 va_end(arg); 53 write(2, buf, out-buf); 54 if (status) 55 done(status); 56 /*NOTREACHED*/ 57 } 58 59 static int 60 catch(void *a, char *msg) 61 { 62 USED(a); 63 panic(2, msg); 64 return 1; 65 } 66 67 int 68 mkpathname(char *pathname, char *path, char *name) 69 { 70 if (strlen(path) + strlen(name) > MAXPATHLEN) { 71 panic(0, "pathname %s/%s too long\n", path, name); 72 return 1; 73 } 74 sprint(pathname, "%s/%s", path, name); 75 return 0; 76 } 77 78 static char * 79 mktmpfile(int input, Dir *sb) 80 { 81 int fd, i; 82 char *p; 83 char buf[8192]; 84 85 atnotify(catch, 1); 86 p = tmp[whichtmp++]; 87 fd = create(p, OWRITE, 0600); 88 if (fd < 0) { 89 panic(mflag ? 0: 2, "cannot create %s: %r\n", p); 90 return 0; 91 } 92 while ((i = read(input, buf, sizeof(buf))) > 0) { 93 if ((i = write(fd, buf, i)) < 0) 94 break; 95 } 96 dirfstat(fd, sb); 97 close(fd); 98 if (i < 0) { 99 panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p); 100 return 0; 101 } 102 return p; 103 } 104 105 static char * 106 statfile(char *file, Dir *sb) 107 { 108 int input; 109 110 if (dirstat(file, sb) == -1) { 111 if (strcmp(file, "-") || dirfstat(0, sb) == -1) { 112 panic(mflag ? 0: 2, "cannot stat %s: %r\n", file); 113 return 0; 114 } 115 file = mktmpfile(0, sb); 116 } 117 else if (!REGULAR_FILE(*sb) && !DIRECTORY(*sb)) { 118 if ((input = open(file, OREAD)) == -1) { 119 panic(mflag ? 0: 2, "cannot open %s: %r\n", file); 120 return 0; 121 } 122 file = mktmpfile(input, sb); 123 close(input); 124 } 125 return file; 126 } 127 128 void 129 diff(char *f, char *t, int level) 130 { 131 char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1]; 132 Dir fsb, tsb; 133 134 if ((fp = statfile(f, &fsb)) == 0) 135 return; 136 if ((tp = statfile(t, &tsb)) == 0) 137 return; 138 if (DIRECTORY(fsb) && DIRECTORY(tsb)) { 139 if (rflag || level == 0) 140 diffdir(fp, tp, level); 141 else 142 Bprint(&stdout, "Common subdirectories: %s and %s\n", 143 fp, tp); 144 } 145 else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb)) 146 diffreg(fp, tp); 147 else { 148 if (REGULAR_FILE(fsb)) { 149 if ((p = utfrrune(f, '/')) == 0) 150 p = f; 151 else 152 p++; 153 if (mkpathname(tb, tp, p)) 154 return; 155 diffreg(fp, tb); 156 } 157 else { 158 if ((p = utfrrune(t, '/')) == 0) 159 p = t; 160 else 161 p++; 162 if (mkpathname(fb, fp, p)) 163 return; 164 diffreg(fb, tp); 165 } 166 } 167 } 168 169 void 170 main(int argc, char *argv[]) 171 { 172 char *p; 173 int i; 174 Dir fsb, tsb; 175 176 Binit(&stdout, 1, OWRITE); 177 progname = *argv; 178 while (--argc && (*++argv)[0] == '-' && (*argv)[1]) { 179 for (p = *argv+1; *p; p++) { 180 switch (*p) { 181 182 case 'e': 183 case 'f': 184 case 'n': 185 mode = *p; 186 break; 187 188 case 'w': 189 bflag = 2; 190 break; 191 192 case 'b': 193 bflag = 1; 194 break; 195 196 case 'r': 197 rflag = 1; 198 break; 199 200 case 'm': 201 mflag = 1; 202 break; 203 204 case 'h': 205 default: 206 progname = "Usage"; 207 panic(2, usage); 208 } 209 } 210 } 211 if (argc < 2) 212 panic(2, usage, progname); 213 if (dirstat(argv[argc-1], &tsb) == -1) 214 panic(2, "can't stat %s\n", argv[argc-1]); 215 if (argc > 2) { 216 if (!DIRECTORY(tsb)) 217 panic(2, usage, progname); 218 mflag = 1; 219 } 220 else { 221 if (dirstat(argv[0], &fsb) == -1) 222 panic(2, "can't stat %s\n", argv[0]); 223 if (DIRECTORY(fsb) && DIRECTORY(tsb)) 224 mflag = 1; 225 } 226 for (i = 0; i < argc-1; i++) { 227 diff(argv[i], argv[argc-1], 0); 228 rmtmpfiles(); 229 } 230 done(anychange); 231 /*NOTREACHED*/ 232 } 233 234 static char noroom[] = "out of memory - try diff -h\n"; 235 236 void * 237 emalloc(unsigned n) 238 { 239 register void *p; 240 241 if ((p = malloc(n)) == 0) 242 panic(2, noroom); 243 return p; 244 } 245 246 void * 247 erealloc(void *p, unsigned n) 248 { 249 register void *rp; 250 251 if ((rp = realloc(p, n)) == 0) 252 panic(2, noroom); 253 return rp; 254 } 255