1/* Still missing: 2 * 3 * mkctm 4 * -B regex Bogus 5 * -I regex Ignore 6 * -D int Damage 7 * -q decrease verbosity 8 * -v increase verbosity 9 * -l file logfile 10 * name cvs-cur 11 * prefix src/secure 12 * dir1 "Soll" 13 * dir2 "Ist" 14 * 15 */ 16 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <sys/mman.h> 20#include <sys/wait.h> 21#include <dirent.h> 22#include <regex.h> 23#include <stdio.h> 24#include <fcntl.h> 25#include <string.h> 26#include <stdlib.h> 27#include <unistd.h> 28#include <md5.h> 29#include <err.h> 30#include <signal.h> 31 32#define DEFAULT_IGNORE "/CVS$|/\\.#|00_TRANS\\.TBL$" 33#define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$|\\.o$" 34regex_t reg_ignore, reg_bogus; 35int flag_ignore, flag_bogus; 36 37int verbose; 38int damage, damage_limit; 39int change; 40 41FILE *logf; 42 43u_long s1_ignored, s2_ignored; 44u_long s1_bogus, s2_bogus; 45u_long s1_wrong, s2_wrong; 46u_long s_new_dirs, s_new_files, s_new_bytes; 47u_long s_del_dirs, s_del_files, s_del_bytes; 48u_long s_files_chg, s_bytes_add, s_bytes_del; 49u_long s_same_dirs, s_same_files, s_same_bytes; 50u_long s_edit_files, s_edit_bytes, s_edit_saves; 51u_long s_sub_files, s_sub_bytes; 52 53void 54Usage(void) 55{ 56 fprintf(stderr, "Usage:\n"); 57 fprintf(stderr, "\tmkctm [-options] name number timestamp prefix"); 58 fprintf(stderr, " dir1 dir2"); 59 fprintf(stderr, "Options:\n"); 60 fprintf(stderr, "\t\t-B bogus_regexp\n"); 61 fprintf(stderr, "\t\t-D damage_limit\n"); 62 fprintf(stderr, "\t\t-I ignore_regexp\n"); 63 fprintf(stderr, "\t\t-q\n"); 64 fprintf(stderr, "\t\t-v\n"); 65} 66 67void 68print_stat(FILE *fd, char *pre) 69{ 70 fprintf(fd, "%sNames:\n", pre); 71 fprintf(fd, "%s ignore: %5lu ref %5lu target\n", 72 pre, s1_ignored, s2_ignored); 73 fprintf(fd, "%s bogus: %5lu ref %5lu target\n", 74 pre, s1_bogus, s2_bogus); 75 fprintf(fd, "%s wrong: %5lu ref %5lu target\n", 76 pre, s1_wrong, s2_wrong); 77 fprintf(fd, "%sDelta:\n", pre); 78 fprintf(fd, "%s new: %5lu dirs %5lu files %9lu plus\n", 79 pre, s_new_dirs, s_new_files, s_new_bytes); 80 fprintf(fd, "%s del: %5lu dirs %5lu files %9lu minus\n", 81 pre, s_del_dirs, s_del_files, s_del_bytes); 82 fprintf(fd, "%s chg: %5lu files %9lu plus %9lu minus\n", 83 pre, s_files_chg, s_bytes_add, s_bytes_del); 84 fprintf(fd, "%s same: %5lu dirs %5lu files %9lu bytes\n", 85 pre, s_same_dirs, s_same_files, s_same_bytes); 86 fprintf(fd, "%sMethod:\n", pre); 87 fprintf(fd, "%s edit: %5lu files %9lu bytes %9lu saved\n", 88 pre, s_edit_files, s_edit_bytes, s_edit_saves); 89 fprintf(fd, "%s sub: %5lu files %9lu bytes\n", 90 pre, s_sub_files, s_sub_bytes); 91 92} 93 94void 95stat_info(int foo) 96{ 97 signal(SIGINFO, stat_info); 98 print_stat(stderr, "INFO: "); 99} 100 101void DoDir(const char *dir1, const char *dir2, const char *name); 102 103static struct stat st; 104static __inline struct stat * 105StatFile(char *name) 106{ 107 if (lstat(name, &st) < 0) 108 err(1, "Couldn't stat %s\n", name); 109 return &st; 110} 111 112int 113dirselect(struct dirent *de) 114{ 115 if (!strcmp(de->d_name, ".")) return 0; 116 if (!strcmp(de->d_name, "..")) return 0; 117 return 1; 118} 119 120void 121name_stat(const char *pfx, const char *dir, const char *name, struct dirent *de) 122{ 123 char *buf = alloca(strlen(dir) + strlen(name) + 124 strlen(de->d_name) + 3); 125 struct stat *st; 126 127 strcpy(buf, dir); 128 strcat(buf, "/"); strcat(buf, name); 129 strcat(buf, "/"); strcat(buf, de->d_name); 130 st = StatFile(buf); 131 printf("%s %s%s %u %u %o", 132 pfx, name, de->d_name, 133 st->st_uid, st->st_gid, st->st_mode & ~S_IFMT); 134 fprintf(logf, "%s %s%s\n", pfx, name, de->d_name); 135 if (verbose > 1) { 136 fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name); 137 } 138} 139 140void 141Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de) 142{ 143 if (de->d_type == DT_DIR) { 144 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 145 146 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 147 DoDir(dir1, dir2, p); 148 s_same_dirs++; 149 } else { 150 char *buf1 = alloca(strlen(dir1) + strlen(name) + 151 strlen(de->d_name) + 3); 152 char *buf2 = alloca(strlen(dir2) + strlen(name) + 153 strlen(de->d_name) + 3); 154 char *m1, md5_1[33], *m2, md5_2[33]; 155 u_char *p1, *p2; 156 int fd1, fd2; 157 struct stat s1, s2; 158 159 strcpy(buf1, dir1); 160 strcat(buf1, "/"); strcat(buf1, name); 161 strcat(buf1, "/"); strcat(buf1, de->d_name); 162 fd1 = open(buf1, O_RDONLY); 163 if(fd1 < 0) { perror(buf1); exit(3); } 164 fstat(fd1, &s1); 165 strcpy(buf2, dir2); 166 strcat(buf2, "/"); strcat(buf2, name); 167 strcat(buf2, "/"); strcat(buf2, de->d_name); 168 fd2 = open(buf2, O_RDONLY); 169 if(fd2 < 0) { perror(buf2); exit(3); } 170 fstat(fd2, &s2); 171#if 0 172 /* XXX if we could just trust the size to change... */ 173 if (s1.st_size == s2.st_size) { 174 s_same_files++; 175 s_same_bytes += s1.st_size; 176 close(fd1); 177 close(fd2); 178 goto finish; 179 } 180#endif 181 p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 182 if ((int)p1 == -1) { perror(buf1); exit(3); } 183 close(fd1); 184 185 p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); 186 if ((int)p2 == -1) { perror(buf2); exit(3); } 187 close(fd2); 188 189 /* If identical, we're done. */ 190 if((s1.st_size == s2.st_size) && !memcmp(p1, p2, s1.st_size)) { 191 s_same_files++; 192 s_same_bytes += s1.st_size; 193 goto finish; 194 } 195 196 s_files_chg++; 197 change++; 198 if (s1.st_size > s2.st_size) 199 s_bytes_del += (s1.st_size - s2.st_size); 200 else 201 s_bytes_add += (s2.st_size - s1.st_size); 202 203 m1 = MD5Data(p1, s1.st_size, md5_1); 204 m2 = MD5Data(p2, s2.st_size, md5_2); 205 206 /* Just a curiosity... */ 207 if(!strcmp(m1, m2)) { 208 if (s1.st_size != s2.st_size) 209 fprintf(stderr, 210 "Notice: MD5 same for files of diffent size:\n\t%s\n\t%s\n", 211 buf1, buf2); 212 goto finish; 213 } 214 215 { 216 u_long l = s2.st_size + 2; 217 u_char *cmd = alloca(strlen(buf1)+strlen(buf2)+100); 218 u_char *ob = alloca(l), *p; 219 int j; 220 FILE *F; 221
| 1/* Still missing: 2 * 3 * mkctm 4 * -B regex Bogus 5 * -I regex Ignore 6 * -D int Damage 7 * -q decrease verbosity 8 * -v increase verbosity 9 * -l file logfile 10 * name cvs-cur 11 * prefix src/secure 12 * dir1 "Soll" 13 * dir2 "Ist" 14 * 15 */ 16 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <sys/mman.h> 20#include <sys/wait.h> 21#include <dirent.h> 22#include <regex.h> 23#include <stdio.h> 24#include <fcntl.h> 25#include <string.h> 26#include <stdlib.h> 27#include <unistd.h> 28#include <md5.h> 29#include <err.h> 30#include <signal.h> 31 32#define DEFAULT_IGNORE "/CVS$|/\\.#|00_TRANS\\.TBL$" 33#define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$|\\.o$" 34regex_t reg_ignore, reg_bogus; 35int flag_ignore, flag_bogus; 36 37int verbose; 38int damage, damage_limit; 39int change; 40 41FILE *logf; 42 43u_long s1_ignored, s2_ignored; 44u_long s1_bogus, s2_bogus; 45u_long s1_wrong, s2_wrong; 46u_long s_new_dirs, s_new_files, s_new_bytes; 47u_long s_del_dirs, s_del_files, s_del_bytes; 48u_long s_files_chg, s_bytes_add, s_bytes_del; 49u_long s_same_dirs, s_same_files, s_same_bytes; 50u_long s_edit_files, s_edit_bytes, s_edit_saves; 51u_long s_sub_files, s_sub_bytes; 52 53void 54Usage(void) 55{ 56 fprintf(stderr, "Usage:\n"); 57 fprintf(stderr, "\tmkctm [-options] name number timestamp prefix"); 58 fprintf(stderr, " dir1 dir2"); 59 fprintf(stderr, "Options:\n"); 60 fprintf(stderr, "\t\t-B bogus_regexp\n"); 61 fprintf(stderr, "\t\t-D damage_limit\n"); 62 fprintf(stderr, "\t\t-I ignore_regexp\n"); 63 fprintf(stderr, "\t\t-q\n"); 64 fprintf(stderr, "\t\t-v\n"); 65} 66 67void 68print_stat(FILE *fd, char *pre) 69{ 70 fprintf(fd, "%sNames:\n", pre); 71 fprintf(fd, "%s ignore: %5lu ref %5lu target\n", 72 pre, s1_ignored, s2_ignored); 73 fprintf(fd, "%s bogus: %5lu ref %5lu target\n", 74 pre, s1_bogus, s2_bogus); 75 fprintf(fd, "%s wrong: %5lu ref %5lu target\n", 76 pre, s1_wrong, s2_wrong); 77 fprintf(fd, "%sDelta:\n", pre); 78 fprintf(fd, "%s new: %5lu dirs %5lu files %9lu plus\n", 79 pre, s_new_dirs, s_new_files, s_new_bytes); 80 fprintf(fd, "%s del: %5lu dirs %5lu files %9lu minus\n", 81 pre, s_del_dirs, s_del_files, s_del_bytes); 82 fprintf(fd, "%s chg: %5lu files %9lu plus %9lu minus\n", 83 pre, s_files_chg, s_bytes_add, s_bytes_del); 84 fprintf(fd, "%s same: %5lu dirs %5lu files %9lu bytes\n", 85 pre, s_same_dirs, s_same_files, s_same_bytes); 86 fprintf(fd, "%sMethod:\n", pre); 87 fprintf(fd, "%s edit: %5lu files %9lu bytes %9lu saved\n", 88 pre, s_edit_files, s_edit_bytes, s_edit_saves); 89 fprintf(fd, "%s sub: %5lu files %9lu bytes\n", 90 pre, s_sub_files, s_sub_bytes); 91 92} 93 94void 95stat_info(int foo) 96{ 97 signal(SIGINFO, stat_info); 98 print_stat(stderr, "INFO: "); 99} 100 101void DoDir(const char *dir1, const char *dir2, const char *name); 102 103static struct stat st; 104static __inline struct stat * 105StatFile(char *name) 106{ 107 if (lstat(name, &st) < 0) 108 err(1, "Couldn't stat %s\n", name); 109 return &st; 110} 111 112int 113dirselect(struct dirent *de) 114{ 115 if (!strcmp(de->d_name, ".")) return 0; 116 if (!strcmp(de->d_name, "..")) return 0; 117 return 1; 118} 119 120void 121name_stat(const char *pfx, const char *dir, const char *name, struct dirent *de) 122{ 123 char *buf = alloca(strlen(dir) + strlen(name) + 124 strlen(de->d_name) + 3); 125 struct stat *st; 126 127 strcpy(buf, dir); 128 strcat(buf, "/"); strcat(buf, name); 129 strcat(buf, "/"); strcat(buf, de->d_name); 130 st = StatFile(buf); 131 printf("%s %s%s %u %u %o", 132 pfx, name, de->d_name, 133 st->st_uid, st->st_gid, st->st_mode & ~S_IFMT); 134 fprintf(logf, "%s %s%s\n", pfx, name, de->d_name); 135 if (verbose > 1) { 136 fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name); 137 } 138} 139 140void 141Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de) 142{ 143 if (de->d_type == DT_DIR) { 144 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 145 146 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 147 DoDir(dir1, dir2, p); 148 s_same_dirs++; 149 } else { 150 char *buf1 = alloca(strlen(dir1) + strlen(name) + 151 strlen(de->d_name) + 3); 152 char *buf2 = alloca(strlen(dir2) + strlen(name) + 153 strlen(de->d_name) + 3); 154 char *m1, md5_1[33], *m2, md5_2[33]; 155 u_char *p1, *p2; 156 int fd1, fd2; 157 struct stat s1, s2; 158 159 strcpy(buf1, dir1); 160 strcat(buf1, "/"); strcat(buf1, name); 161 strcat(buf1, "/"); strcat(buf1, de->d_name); 162 fd1 = open(buf1, O_RDONLY); 163 if(fd1 < 0) { perror(buf1); exit(3); } 164 fstat(fd1, &s1); 165 strcpy(buf2, dir2); 166 strcat(buf2, "/"); strcat(buf2, name); 167 strcat(buf2, "/"); strcat(buf2, de->d_name); 168 fd2 = open(buf2, O_RDONLY); 169 if(fd2 < 0) { perror(buf2); exit(3); } 170 fstat(fd2, &s2); 171#if 0 172 /* XXX if we could just trust the size to change... */ 173 if (s1.st_size == s2.st_size) { 174 s_same_files++; 175 s_same_bytes += s1.st_size; 176 close(fd1); 177 close(fd2); 178 goto finish; 179 } 180#endif 181 p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 182 if ((int)p1 == -1) { perror(buf1); exit(3); } 183 close(fd1); 184 185 p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); 186 if ((int)p2 == -1) { perror(buf2); exit(3); } 187 close(fd2); 188 189 /* If identical, we're done. */ 190 if((s1.st_size == s2.st_size) && !memcmp(p1, p2, s1.st_size)) { 191 s_same_files++; 192 s_same_bytes += s1.st_size; 193 goto finish; 194 } 195 196 s_files_chg++; 197 change++; 198 if (s1.st_size > s2.st_size) 199 s_bytes_del += (s1.st_size - s2.st_size); 200 else 201 s_bytes_add += (s2.st_size - s1.st_size); 202 203 m1 = MD5Data(p1, s1.st_size, md5_1); 204 m2 = MD5Data(p2, s2.st_size, md5_2); 205 206 /* Just a curiosity... */ 207 if(!strcmp(m1, m2)) { 208 if (s1.st_size != s2.st_size) 209 fprintf(stderr, 210 "Notice: MD5 same for files of diffent size:\n\t%s\n\t%s\n", 211 buf1, buf2); 212 goto finish; 213 } 214 215 { 216 u_long l = s2.st_size + 2; 217 u_char *cmd = alloca(strlen(buf1)+strlen(buf2)+100); 218 u_char *ob = alloca(l), *p; 219 int j; 220 FILE *F; 221
|
231 if (verbose > 0) 232 fprintf(stderr, 233 "last char != \\n in %s\n", 234 buf2); 235 goto subst; 236 } 237 238 for (p=p1; p<p1+s1.st_size; p++) 239 if (!*p) { 240 if (verbose > 0) 241 fprintf(stderr, 242 "NULL char in %s\n", 243 buf1); 244 goto subst; 245 } 246 247 for (p=p2; p<p2+s2.st_size; p++) 248 if (!*p) { 249 if (verbose > 0) 250 fprintf(stderr, 251 "NULL char in %s\n", 252 buf2); 253 goto subst; 254 } 255 256 strcpy(cmd, "diff -n "); 257 strcat(cmd, buf1); 258 strcat(cmd, " "); 259 strcat(cmd, buf2); 260 F = popen(cmd, "r"); 261 for (j = 1, l = 0; l < s2.st_size; ) { 262 j = fread(ob+l, 1, s2.st_size - l, F); 263 if (j < 1) 264 break; 265 l += j; 266 continue; 267 } 268 if (j) { 269 l = 0; 270 while (EOF != fgetc(F)) 271 continue; 272 } 273 pclose(F); 274 275 if (l && l < s2.st_size) { 276 name_stat("CTMFN", dir2, name, de); 277 printf(" %s %s %d\n", m1, m2, (unsigned)l); 278 fwrite(ob, 1, l, stdout); 279 putchar('\n'); 280 s_edit_files++; 281 s_edit_bytes += l; 282 s_edit_saves += (s2.st_size - l); 283 } else { 284 subst: 285 name_stat("CTMFS", dir2, name, de); 286 printf(" %s %s %u\n", m1, m2, (unsigned)s2.st_size); 287 fwrite(p2, 1, s2.st_size, stdout); 288 putchar('\n'); 289 s_sub_files++; 290 s_sub_bytes += s2.st_size; 291 } 292 } 293 finish: 294 munmap(p1, s1.st_size); 295 munmap(p2, s2.st_size); 296 } 297} 298 299void 300Add(const char *dir1, const char *dir2, const char *name, struct dirent *de) 301{ 302 change++; 303 if (de->d_type == DT_DIR) { 304 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 305 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 306 name_stat("CTMDM", dir2, name, de); 307 putchar('\n'); 308 s_new_dirs++; 309 DoDir(dir1, dir2, p); 310 } else if (de->d_type == DT_REG) { 311 char *buf2 = alloca(strlen(dir2) + strlen(name) + 312 strlen(de->d_name) + 3); 313 char *m2, md5_2[33]; 314 u_char *p1; 315 struct stat st; 316 int fd1; 317 318 strcpy(buf2, dir2); 319 strcat(buf2, "/"); strcat(buf2, name); 320 strcat(buf2, "/"); strcat(buf2, de->d_name); 321 fd1 = open(buf2, O_RDONLY); 322 if (fd1 < 0) {perror(buf2); exit (3); } 323 fstat(fd1, &st); 324 p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 325 if ((int)p1 == -1) { perror(buf2); exit(3); } 326 close(fd1); 327 m2 = MD5Data(p1, st.st_size, md5_2); 328 name_stat("CTMFM", dir2, name, de); 329 printf(" %s %u\n", m2, (unsigned)st.st_size); 330 fwrite(p1, 1, st.st_size, stdout); 331 putchar('\n'); 332 munmap(p1, st.st_size); 333 s_new_files++; 334 s_new_bytes += st.st_size; 335 } 336} 337 338void 339Del (const char *dir1, const char *dir2, const char *name, struct dirent *de) 340{ 341 damage++; 342 change++; 343 if (de->d_type == DT_DIR) { 344 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 345 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 346 DoDir(dir1, dir2, p); 347 printf("CTMDR %s%s\n", name, de->d_name); 348 fprintf(logf, "CTMDR %s%s\n", name, de->d_name); 349 if (verbose > 1) { 350 fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); 351 } 352 s_del_dirs++; 353 } else if (de->d_type == DT_REG) { 354 char *buf1 = alloca(strlen(dir1) + strlen(name) + 355 strlen(de->d_name) + 3); 356 char *m1, md5_1[33]; 357 strcpy(buf1, dir1); 358 strcat(buf1, "/"); strcat(buf1, name); 359 strcat(buf1, "/"); strcat(buf1, de->d_name); 360 m1 = MD5File(buf1, md5_1); 361 printf("CTMFR %s%s %s\n", name, de->d_name, m1); 362 fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1); 363 if (verbose > 1) { 364 fprintf(stderr, "CTMFR %s%s\n", name, de->d_name); 365 } 366 s_del_files++; 367 s_del_bytes += StatFile(buf1)->st_size; 368 } 369} 370 371void 372GetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u_long *ignored, u_long *bogus, u_long *wrong) 373{ 374 char buf[BUFSIZ]; 375 char buf1[BUFSIZ]; 376 377 for (;;) { 378 for (;;) { 379 (*i)++; 380 if (*i >= *n) 381 return; 382 strcpy(buf1, name); 383 if (buf1[strlen(buf1)-1] != '/') 384 strcat(buf1, "/"); 385 strcat(buf1, nl[*i]->d_name); 386 if (flag_ignore && 387 !regexec(®_ignore, buf1, 0, 0, 0)) { 388 (*ignored)++; 389 fprintf(logf, "Ignore %s\n", buf1); 390 if (verbose > 2) { 391 fprintf(stderr, "Ignore %s\n", buf1); 392 } 393 } else if (flag_bogus && 394 !regexec(®_bogus, buf1, 0, 0, 0)) { 395 (*bogus)++; 396 fprintf(logf, "Bogus %s\n", buf1); 397 fprintf(stderr, "Bogus %s\n", buf1); 398 damage++; 399 } else { 400 *buf = 0; 401 if (*dir != '/') 402 strcat(buf, "/"); 403 strcat(buf, dir); 404 if (buf[strlen(buf)-1] != '/') 405 strcat(buf, "/"); 406 strcat(buf, buf1); 407 break; 408 } 409 free(nl[*i]); nl[*i] = 0; 410 } 411 /* If the filesystem didn't tell us, find type */ 412 if (nl[*i]->d_type == DT_UNKNOWN) 413 nl[*i]->d_type = IFTODT(StatFile(buf)->st_mode); 414 if (nl[*i]->d_type == DT_REG || nl[*i]->d_type == DT_DIR) 415 break; 416 (*wrong)++; 417 if (verbose > 0) 418 fprintf(stderr, "Wrong %s\n", buf); 419 free(nl[*i]); nl[*i] = 0; 420 } 421} 422 423void 424DoDir(const char *dir1, const char *dir2, const char *name) 425{ 426 int i1, i2, n1, n2, i; 427 struct dirent **nl1, **nl2; 428 char *buf1 = alloca(strlen(dir1) + strlen(name) + 4); 429 char *buf2 = alloca(strlen(dir2) + strlen(name) + 4); 430 431 strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, name); 432 strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, name); 433 n1 = scandir(buf1, &nl1, dirselect, alphasort); 434 n2 = scandir(buf2, &nl2, dirselect, alphasort); 435 i1 = i2 = -1; 436 GetNext(&i1, &n1, nl1, dir1, name, &s1_ignored, &s1_bogus, &s1_wrong); 437 GetNext(&i2, &n2, nl2, dir2, name, &s2_ignored, &s2_bogus, &s2_wrong); 438 for (;i1 < n1 || i2 < n2;) { 439 440 if (damage_limit && damage > damage_limit) 441 break; 442 443 /* Get next item from list 1 */ 444 if (i1 < n1 && !nl1[i1]) 445 GetNext(&i1, &n1, nl1, dir1, name, 446 &s1_ignored, &s1_bogus, &s1_wrong); 447 448 /* Get next item from list 2 */ 449 if (i2 < n2 && !nl2[i2]) 450 GetNext(&i2, &n2, nl2, dir2, name, 451 &s2_ignored, &s2_bogus, &s2_wrong); 452 453 if (i1 >= n1 && i2 >= n2) { 454 /* Done */ 455 break; 456 } else if (i1 >= n1 && i2 < n2) { 457 /* end of list 1, add anything left on list 2 */ 458 Add(dir1, dir2, name, nl2[i2]); 459 free(nl2[i2]); nl2[i2] = 0; 460 } else if (i1 < n1 && i2 >= n2) { 461 /* end of list 2, delete anything left on list 1 */ 462 Del(dir1, dir2, name, nl1[i1]); 463 free(nl1[i1]); nl1[i1] = 0; 464 } else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) { 465 /* Identical names */ 466 if (nl1[i1]->d_type == nl2[i2]->d_type) { 467 /* same type */ 468 Equ(dir1, dir2, name, nl1[i1]); 469 } else { 470 /* different types */ 471 Del(dir1, dir2, name, nl1[i1]); 472 Add(dir1, dir2, name, nl2[i2]); 473 } 474 free(nl1[i1]); nl1[i1] = 0; 475 free(nl2[i2]); nl2[i2] = 0; 476 } else if (i < 0) { 477 /* Something extra in list 1, delete it */ 478 Del(dir1, dir2, name, nl1[i1]); 479 free(nl1[i1]); nl1[i1] = 0; 480 } else { 481 /* Something extra in list 2, add it */ 482 Add(dir1, dir2, name, nl2[i2]); 483 free(nl2[i2]); nl2[i2] = 0; 484 } 485 } 486 if (n1 >= 0) 487 free(nl1); 488 if (n2 >= 0) 489 free(nl2); 490} 491 492int 493main(int argc, char **argv) 494{ 495 int i; 496 extern char *optarg; 497 extern int optind; 498 499 setbuf(stderr, NULL); 500 501#if 0 502 if (regcomp(®_bogus, DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE)) 503 /* XXX use regerror to explain it */ 504 errx(1, "Default regular expression argument to -B is botched"); 505 flag_bogus = 1; 506 507 if (regcomp(®_ignore, DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE)) 508 /* XXX use regerror to explain it */ 509 errx(1, "Default regular expression argument to -I is botched"); 510 flag_ignore = 1; 511#endif 512 513 while ((i = getopt(argc, argv, "D:I:B:l:qv")) != EOF) 514 switch (i) { 515 case 'D': 516 damage_limit = strtol(optarg, 0, 0); 517 if (damage_limit < 0) 518 errx(1, "Damage limit must be positive"); 519 break; 520 case 'I': 521 if (flag_ignore) 522 regfree(®_ignore); 523 flag_ignore = 0; 524 if (!*optarg) 525 break; 526 if (regcomp(®_ignore, optarg, 527 REG_EXTENDED | REG_NEWLINE)) 528 /* XXX use regerror to explain it */ 529 errx(1, "Regular expression argument to -I is botched"); 530 flag_ignore = 1; 531 break; 532 case 'B': 533 if (flag_bogus) 534 regfree(®_bogus); 535 flag_bogus = 0; 536 if (!*optarg) 537 break; 538 if (regcomp(®_bogus, optarg, 539 REG_EXTENDED | REG_NEWLINE)) 540 /* XXX use regerror to explain it */ 541 errx(1, "Regular expression argument to -B is botched"); 542 flag_bogus = 1; 543 break; 544 case 'l': 545 logf = fopen(optarg, "w"); 546 if (!logf) 547 err(1, optarg); 548 break; 549 case 'q': 550 verbose--; 551 break; 552 case 'v': 553 verbose++; 554 break; 555 case '?': 556 default: 557 Usage(); 558 return (1); 559 } 560 argc -= optind; 561 argv += optind; 562 563 if (!logf) 564 logf = fopen("/dev/null", "w"); 565 566 setbuf(stdout, 0); 567 568 if (argc != 6) { 569 Usage(); 570 return (1); 571 } 572 573 signal(SIGINFO, stat_info); 574 575 fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n", 576 argv[0], argv[1], argv[2], argv[3]); 577 fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n", 578 argv[0], argv[1], argv[2], argv[3]); 579 printf("CTM_BEGIN 2.0 %s %s %s %s\n", 580 argv[0], argv[1], argv[2], argv[3]); 581 DoDir(argv[4], argv[5], ""); 582 if (damage_limit && damage > damage_limit) { 583 print_stat(stderr, "DAMAGE: "); 584 errx(1, "Damage of %d would exceed %d files", 585 damage, damage_limit); 586 } else if (change < 2) { 587 errx(4, "No changes"); 588 } else { 589 printf("CTM_END "); 590 fprintf(logf, "CTM_END\n"); 591 print_stat(stderr, "END: "); 592 } 593 exit(0); 594}
| 231 if (verbose > 0) 232 fprintf(stderr, 233 "last char != \\n in %s\n", 234 buf2); 235 goto subst; 236 } 237 238 for (p=p1; p<p1+s1.st_size; p++) 239 if (!*p) { 240 if (verbose > 0) 241 fprintf(stderr, 242 "NULL char in %s\n", 243 buf1); 244 goto subst; 245 } 246 247 for (p=p2; p<p2+s2.st_size; p++) 248 if (!*p) { 249 if (verbose > 0) 250 fprintf(stderr, 251 "NULL char in %s\n", 252 buf2); 253 goto subst; 254 } 255 256 strcpy(cmd, "diff -n "); 257 strcat(cmd, buf1); 258 strcat(cmd, " "); 259 strcat(cmd, buf2); 260 F = popen(cmd, "r"); 261 for (j = 1, l = 0; l < s2.st_size; ) { 262 j = fread(ob+l, 1, s2.st_size - l, F); 263 if (j < 1) 264 break; 265 l += j; 266 continue; 267 } 268 if (j) { 269 l = 0; 270 while (EOF != fgetc(F)) 271 continue; 272 } 273 pclose(F); 274 275 if (l && l < s2.st_size) { 276 name_stat("CTMFN", dir2, name, de); 277 printf(" %s %s %d\n", m1, m2, (unsigned)l); 278 fwrite(ob, 1, l, stdout); 279 putchar('\n'); 280 s_edit_files++; 281 s_edit_bytes += l; 282 s_edit_saves += (s2.st_size - l); 283 } else { 284 subst: 285 name_stat("CTMFS", dir2, name, de); 286 printf(" %s %s %u\n", m1, m2, (unsigned)s2.st_size); 287 fwrite(p2, 1, s2.st_size, stdout); 288 putchar('\n'); 289 s_sub_files++; 290 s_sub_bytes += s2.st_size; 291 } 292 } 293 finish: 294 munmap(p1, s1.st_size); 295 munmap(p2, s2.st_size); 296 } 297} 298 299void 300Add(const char *dir1, const char *dir2, const char *name, struct dirent *de) 301{ 302 change++; 303 if (de->d_type == DT_DIR) { 304 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 305 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 306 name_stat("CTMDM", dir2, name, de); 307 putchar('\n'); 308 s_new_dirs++; 309 DoDir(dir1, dir2, p); 310 } else if (de->d_type == DT_REG) { 311 char *buf2 = alloca(strlen(dir2) + strlen(name) + 312 strlen(de->d_name) + 3); 313 char *m2, md5_2[33]; 314 u_char *p1; 315 struct stat st; 316 int fd1; 317 318 strcpy(buf2, dir2); 319 strcat(buf2, "/"); strcat(buf2, name); 320 strcat(buf2, "/"); strcat(buf2, de->d_name); 321 fd1 = open(buf2, O_RDONLY); 322 if (fd1 < 0) {perror(buf2); exit (3); } 323 fstat(fd1, &st); 324 p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 325 if ((int)p1 == -1) { perror(buf2); exit(3); } 326 close(fd1); 327 m2 = MD5Data(p1, st.st_size, md5_2); 328 name_stat("CTMFM", dir2, name, de); 329 printf(" %s %u\n", m2, (unsigned)st.st_size); 330 fwrite(p1, 1, st.st_size, stdout); 331 putchar('\n'); 332 munmap(p1, st.st_size); 333 s_new_files++; 334 s_new_bytes += st.st_size; 335 } 336} 337 338void 339Del (const char *dir1, const char *dir2, const char *name, struct dirent *de) 340{ 341 damage++; 342 change++; 343 if (de->d_type == DT_DIR) { 344 char *p = alloca(strlen(name)+strlen(de->d_name)+2); 345 strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 346 DoDir(dir1, dir2, p); 347 printf("CTMDR %s%s\n", name, de->d_name); 348 fprintf(logf, "CTMDR %s%s\n", name, de->d_name); 349 if (verbose > 1) { 350 fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); 351 } 352 s_del_dirs++; 353 } else if (de->d_type == DT_REG) { 354 char *buf1 = alloca(strlen(dir1) + strlen(name) + 355 strlen(de->d_name) + 3); 356 char *m1, md5_1[33]; 357 strcpy(buf1, dir1); 358 strcat(buf1, "/"); strcat(buf1, name); 359 strcat(buf1, "/"); strcat(buf1, de->d_name); 360 m1 = MD5File(buf1, md5_1); 361 printf("CTMFR %s%s %s\n", name, de->d_name, m1); 362 fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1); 363 if (verbose > 1) { 364 fprintf(stderr, "CTMFR %s%s\n", name, de->d_name); 365 } 366 s_del_files++; 367 s_del_bytes += StatFile(buf1)->st_size; 368 } 369} 370 371void 372GetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u_long *ignored, u_long *bogus, u_long *wrong) 373{ 374 char buf[BUFSIZ]; 375 char buf1[BUFSIZ]; 376 377 for (;;) { 378 for (;;) { 379 (*i)++; 380 if (*i >= *n) 381 return; 382 strcpy(buf1, name); 383 if (buf1[strlen(buf1)-1] != '/') 384 strcat(buf1, "/"); 385 strcat(buf1, nl[*i]->d_name); 386 if (flag_ignore && 387 !regexec(®_ignore, buf1, 0, 0, 0)) { 388 (*ignored)++; 389 fprintf(logf, "Ignore %s\n", buf1); 390 if (verbose > 2) { 391 fprintf(stderr, "Ignore %s\n", buf1); 392 } 393 } else if (flag_bogus && 394 !regexec(®_bogus, buf1, 0, 0, 0)) { 395 (*bogus)++; 396 fprintf(logf, "Bogus %s\n", buf1); 397 fprintf(stderr, "Bogus %s\n", buf1); 398 damage++; 399 } else { 400 *buf = 0; 401 if (*dir != '/') 402 strcat(buf, "/"); 403 strcat(buf, dir); 404 if (buf[strlen(buf)-1] != '/') 405 strcat(buf, "/"); 406 strcat(buf, buf1); 407 break; 408 } 409 free(nl[*i]); nl[*i] = 0; 410 } 411 /* If the filesystem didn't tell us, find type */ 412 if (nl[*i]->d_type == DT_UNKNOWN) 413 nl[*i]->d_type = IFTODT(StatFile(buf)->st_mode); 414 if (nl[*i]->d_type == DT_REG || nl[*i]->d_type == DT_DIR) 415 break; 416 (*wrong)++; 417 if (verbose > 0) 418 fprintf(stderr, "Wrong %s\n", buf); 419 free(nl[*i]); nl[*i] = 0; 420 } 421} 422 423void 424DoDir(const char *dir1, const char *dir2, const char *name) 425{ 426 int i1, i2, n1, n2, i; 427 struct dirent **nl1, **nl2; 428 char *buf1 = alloca(strlen(dir1) + strlen(name) + 4); 429 char *buf2 = alloca(strlen(dir2) + strlen(name) + 4); 430 431 strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, name); 432 strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, name); 433 n1 = scandir(buf1, &nl1, dirselect, alphasort); 434 n2 = scandir(buf2, &nl2, dirselect, alphasort); 435 i1 = i2 = -1; 436 GetNext(&i1, &n1, nl1, dir1, name, &s1_ignored, &s1_bogus, &s1_wrong); 437 GetNext(&i2, &n2, nl2, dir2, name, &s2_ignored, &s2_bogus, &s2_wrong); 438 for (;i1 < n1 || i2 < n2;) { 439 440 if (damage_limit && damage > damage_limit) 441 break; 442 443 /* Get next item from list 1 */ 444 if (i1 < n1 && !nl1[i1]) 445 GetNext(&i1, &n1, nl1, dir1, name, 446 &s1_ignored, &s1_bogus, &s1_wrong); 447 448 /* Get next item from list 2 */ 449 if (i2 < n2 && !nl2[i2]) 450 GetNext(&i2, &n2, nl2, dir2, name, 451 &s2_ignored, &s2_bogus, &s2_wrong); 452 453 if (i1 >= n1 && i2 >= n2) { 454 /* Done */ 455 break; 456 } else if (i1 >= n1 && i2 < n2) { 457 /* end of list 1, add anything left on list 2 */ 458 Add(dir1, dir2, name, nl2[i2]); 459 free(nl2[i2]); nl2[i2] = 0; 460 } else if (i1 < n1 && i2 >= n2) { 461 /* end of list 2, delete anything left on list 1 */ 462 Del(dir1, dir2, name, nl1[i1]); 463 free(nl1[i1]); nl1[i1] = 0; 464 } else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) { 465 /* Identical names */ 466 if (nl1[i1]->d_type == nl2[i2]->d_type) { 467 /* same type */ 468 Equ(dir1, dir2, name, nl1[i1]); 469 } else { 470 /* different types */ 471 Del(dir1, dir2, name, nl1[i1]); 472 Add(dir1, dir2, name, nl2[i2]); 473 } 474 free(nl1[i1]); nl1[i1] = 0; 475 free(nl2[i2]); nl2[i2] = 0; 476 } else if (i < 0) { 477 /* Something extra in list 1, delete it */ 478 Del(dir1, dir2, name, nl1[i1]); 479 free(nl1[i1]); nl1[i1] = 0; 480 } else { 481 /* Something extra in list 2, add it */ 482 Add(dir1, dir2, name, nl2[i2]); 483 free(nl2[i2]); nl2[i2] = 0; 484 } 485 } 486 if (n1 >= 0) 487 free(nl1); 488 if (n2 >= 0) 489 free(nl2); 490} 491 492int 493main(int argc, char **argv) 494{ 495 int i; 496 extern char *optarg; 497 extern int optind; 498 499 setbuf(stderr, NULL); 500 501#if 0 502 if (regcomp(®_bogus, DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE)) 503 /* XXX use regerror to explain it */ 504 errx(1, "Default regular expression argument to -B is botched"); 505 flag_bogus = 1; 506 507 if (regcomp(®_ignore, DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE)) 508 /* XXX use regerror to explain it */ 509 errx(1, "Default regular expression argument to -I is botched"); 510 flag_ignore = 1; 511#endif 512 513 while ((i = getopt(argc, argv, "D:I:B:l:qv")) != EOF) 514 switch (i) { 515 case 'D': 516 damage_limit = strtol(optarg, 0, 0); 517 if (damage_limit < 0) 518 errx(1, "Damage limit must be positive"); 519 break; 520 case 'I': 521 if (flag_ignore) 522 regfree(®_ignore); 523 flag_ignore = 0; 524 if (!*optarg) 525 break; 526 if (regcomp(®_ignore, optarg, 527 REG_EXTENDED | REG_NEWLINE)) 528 /* XXX use regerror to explain it */ 529 errx(1, "Regular expression argument to -I is botched"); 530 flag_ignore = 1; 531 break; 532 case 'B': 533 if (flag_bogus) 534 regfree(®_bogus); 535 flag_bogus = 0; 536 if (!*optarg) 537 break; 538 if (regcomp(®_bogus, optarg, 539 REG_EXTENDED | REG_NEWLINE)) 540 /* XXX use regerror to explain it */ 541 errx(1, "Regular expression argument to -B is botched"); 542 flag_bogus = 1; 543 break; 544 case 'l': 545 logf = fopen(optarg, "w"); 546 if (!logf) 547 err(1, optarg); 548 break; 549 case 'q': 550 verbose--; 551 break; 552 case 'v': 553 verbose++; 554 break; 555 case '?': 556 default: 557 Usage(); 558 return (1); 559 } 560 argc -= optind; 561 argv += optind; 562 563 if (!logf) 564 logf = fopen("/dev/null", "w"); 565 566 setbuf(stdout, 0); 567 568 if (argc != 6) { 569 Usage(); 570 return (1); 571 } 572 573 signal(SIGINFO, stat_info); 574 575 fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n", 576 argv[0], argv[1], argv[2], argv[3]); 577 fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n", 578 argv[0], argv[1], argv[2], argv[3]); 579 printf("CTM_BEGIN 2.0 %s %s %s %s\n", 580 argv[0], argv[1], argv[2], argv[3]); 581 DoDir(argv[4], argv[5], ""); 582 if (damage_limit && damage > damage_limit) { 583 print_stat(stderr, "DAMAGE: "); 584 errx(1, "Damage of %d would exceed %d files", 585 damage, damage_limit); 586 } else if (change < 2) { 587 errx(4, "No changes"); 588 } else { 589 printf("CTM_END "); 590 fprintf(logf, "CTM_END\n"); 591 print_stat(stderr, "END: "); 592 } 593 exit(0); 594}
|