1 # include "../hdr/defines.h" 2 # include "../hdr/had.h" 3 # include "pathnames.h" 4 5 static char Sccsid[] = "@(#)delta.c 4.12 11/11/90"; 6 USXALLOC(); 7 8 # ifdef LOGDELTA 9 char *LogFile = _PATH_SCCSLOG; 10 FILE *Logf; 11 # endif 12 13 FILE *Diffin; 14 int Debug = 0; 15 struct packet gpkt; 16 struct sid sid; 17 int num_files; 18 char had[26]; 19 char *ilist, *elist, *glist; 20 char *Comments, *Mrs; 21 int Domrs; 22 int verbosity; 23 int Did_id; 24 long Szqfile; 25 char Pfilename[FILESIZE]; 26 FILE *Xiop; 27 int Xcreate; 28 29 main(argc,argv) 30 int argc; 31 register char *argv[]; 32 { 33 register int i; 34 register char *p; 35 char c; 36 int testmore; 37 extern delta(); 38 extern int Fcnt; 39 40 Fflags = FTLEXIT | FTLMSG | FTLCLN; 41 for(i=1; i<argc; i++) 42 if(argv[i][0] == '-' && (c=argv[i][1])) { 43 p = &argv[i][2]; 44 testmore = 0; 45 switch (c) { 46 47 case 'r': 48 if (!p[0]) { 49 argv[i] = 0; 50 continue; 51 } 52 chksid(sid_ab(p,&sid),&sid); 53 break; 54 case 'g': 55 glist = p; 56 break; 57 case 'y': 58 Comments = p; 59 break; 60 case 'm': 61 Mrs = p; 62 break; 63 case 'p': 64 case 'n': 65 case 's': 66 testmore++; 67 break; 68 default: 69 fatal("unknown key letter (cm1)"); 70 } 71 72 if (testmore) { 73 testmore = 0; 74 if (*p) { 75 sprintf(Error, "value after %c arg (cm7)",c); 76 fatal(Error); 77 } 78 } 79 if (had[c - 'a']++) 80 fatal("key letter twice (cm2)"); 81 argv[i] = 0; 82 } 83 else num_files++; 84 85 if (num_files == 0) 86 fatal("missing file arg (cm3)"); 87 if (!HADS) 88 verbosity = -1; 89 # ifdef LOGDELTA 90 Logf = fopen(LogFile, "a"); 91 # endif 92 setsig(); 93 Fflags &= ~FTLEXIT; 94 Fflags |= FTLJMP; 95 for (i=1; i<argc; i++) 96 if (p=argv[i]) 97 do_file(p,delta); 98 # ifdef LOGDELTA 99 if (Logf != NULL) 100 fclose(Logf); 101 # endif 102 exit(Fcnt ? 1 : 0); 103 } 104 105 106 delta(file) 107 char *file; 108 { 109 static int first = 1; 110 register char *p; 111 int n, linenum; 112 char type; 113 register int ser; 114 extern char had_dir, had_standinp; 115 extern char *Sflags[]; 116 char dfilename[FILESIZE]; 117 char gfilename[FILESIZE]; 118 char line[512]; 119 FILE *gin; 120 struct stats stats; 121 struct pfile *pp; 122 int inserted, deleted, orig; 123 int newser; 124 int status; 125 int diffloop; 126 int difflim; 127 128 if (setjmp(Fjmp)) 129 return; 130 if (first) { 131 first = 0; 132 dohist(file); 133 } 134 sinit(&gpkt,file,1); 135 if (lockit(auxf(gpkt.p_file,'z'),2,getpid())) 136 fatal("cannot create lock file (cm4)"); 137 gpkt.p_reopen = 1; 138 gpkt.p_stdout = stdout; 139 copy(auxf(gpkt.p_file,'g'),gfilename); 140 gin = xfopen(gfilename,0); 141 pp = rdpfile(&gpkt,&sid); 142 gpkt.p_cutoff = pp->pf_date; 143 ilist = pp->pf_ilist; 144 elist = pp->pf_elist; 145 146 if (dodelt(&gpkt,&stats,0,0) == 0) 147 fmterr(&gpkt); 148 if ((ser = sidtoser(&pp->pf_gsid,&gpkt)) == 0 || 149 sidtoser(&pp->pf_nsid,&gpkt)) 150 fatal("invalid sid in p-file (de3)"); 151 doie(&gpkt,ilist,elist,glist); 152 setup(&gpkt,ser); 153 finduser(&gpkt); 154 doflags(&gpkt); 155 bcopy(&pp->pf_nsid,&gpkt.p_reqsid,sizeof(gpkt.p_reqsid)); 156 permiss(&gpkt); 157 flushto(&gpkt,EUSERTXT,1); 158 gpkt.p_chkeof = 1; 159 copy(auxf(gpkt.p_file,'d'),dfilename); 160 gpkt.p_gout = xfcreat(dfilename,0444); 161 while(readmod(&gpkt)) { 162 chkid(gpkt.p_line); 163 fputs(gpkt.p_line,gpkt.p_gout); 164 } 165 fclose(gpkt.p_gout); 166 orig = gpkt.p_glnno; 167 gpkt.p_glnno = 0; 168 gpkt.p_verbose = verbosity; 169 Did_id = 0; 170 while (fgets(line,sizeof(line),gin) != NULL && !chkid(line)) 171 ; 172 fclose(gin); 173 if (gpkt.p_verbose && (num_files > 1 || had_dir || had_standinp)) 174 fprintf(gpkt.p_stdout,"\n%s:\n",gpkt.p_file); 175 if (!Did_id) 176 if (Sflags[IDFLAG - 'a']) 177 fatal("no id keywords (cm6)"); 178 else if (gpkt.p_verbose) 179 fprintf(stderr,"No id keywords (cm7)\n"); 180 181 /* 182 The following while loop executes 'bdiff' on g-file and 183 d-file. If 'bdiff' fails (usually because segmentation 184 limit it is using is too large for 'diff'), it is 185 invoked again, with a lower segmentation limit. 186 */ 187 difflim = 3500; 188 diffloop = 0; 189 while (1) { 190 inserted = deleted = 0; 191 gpkt.p_glnno = 0; 192 gpkt.p_upd = 1; 193 gpkt.p_wrttn = 1; 194 getline(&gpkt); 195 gpkt.p_wrttn = 1; 196 newser = mkdelt(&gpkt,&pp->pf_nsid,&pp->pf_gsid, 197 diffloop,orig); 198 diffloop = 1; 199 flushto(&gpkt,EUSERTXT,0); 200 Diffin = dodiff(auxf(gpkt.p_file,'g'),dfilename,difflim); 201 while (n = getdiff(&type,&linenum)) { 202 if (type == INS) { 203 inserted += n; 204 insert(&gpkt,linenum,n,newser); 205 } 206 else { 207 deleted += n; 208 delete(&gpkt,linenum,n,newser); 209 } 210 } 211 fclose(Diffin); 212 if (gpkt.p_iop) 213 while (readmod(&gpkt)) 214 ; 215 wait(&status); 216 if (status) { /* diff failed */ 217 /* 218 Check top byte (exit code of child). 219 */ 220 if (((status >> 8) & 0377) == 32) { /* 'execl' failed */ 221 sprintf(Error, "cannot execute '%s' (de12)", 222 _PATH_BDIFF); 223 fatal(Error); 224 } 225 /* 226 Re-try. 227 */ 228 if (difflim -= 500) { /* reduce segmentation */ 229 fprintf(stderr, 230 "'%s' failed, re-trying, segmentation = %d (de13)\n", 231 _PATH_BDIFF,difflim); 232 fclose(Xiop); /* set up */ 233 Xiop = 0; /* for new x-file */ 234 Xcreate = 0; 235 /* 236 Re-open s-file. 237 */ 238 gpkt.p_iop = xfopen(gpkt.p_file,0); 239 setbuf(gpkt.p_iop,gpkt.p_buf); 240 /* 241 Reset counters. 242 */ 243 gpkt.p_slnno = 0; 244 gpkt.p_ihash = 0; 245 gpkt.p_chash = 0; 246 gpkt.p_nhash = 0; 247 gpkt.p_keep = 0; 248 } 249 else 250 /* tried up to 500 lines, can't go on */ 251 fatal("diff failed (de4)"); 252 } 253 else { /* no need to try again, worked */ 254 break; /* exit while loop */ 255 } 256 } 257 unlink(dfilename); 258 stats.s_ins = inserted; 259 stats.s_del = deleted; 260 stats.s_unc = orig - deleted; 261 if (gpkt.p_verbose) { 262 fprintf(gpkt.p_stdout,"%u inserted\n",stats.s_ins); 263 fprintf(gpkt.p_stdout,"%u deleted\n",stats.s_del); 264 fprintf(gpkt.p_stdout,"%u unchanged\n",stats.s_unc); 265 } 266 flushline(&gpkt,&stats); 267 rename(auxf(gpkt.p_file,'x'),gpkt.p_file); 268 if (Szqfile) 269 rename(auxf(&gpkt.p_file,'q'),Pfilename); 270 else { 271 xunlink(Pfilename); 272 xunlink(auxf(&gpkt.p_file,'q')); 273 } 274 clean_up(0); 275 if (!HADN) { 276 setuid(getuid()); 277 unlink(gfilename); 278 } 279 } 280 281 282 mkdelt(pkt,sp,osp,diffloop,orig_nlines) 283 struct packet *pkt; 284 struct sid *sp, *osp; 285 int diffloop; 286 int orig_nlines; 287 { 288 extern long Timenow; 289 struct deltab dt; 290 char str[128]; 291 int newser; 292 extern char *Sflags[]; 293 register char *p; 294 int ser_inc, opred, nulldel; 295 296 if (!diffloop && pkt->p_verbose) { 297 sid_ba(sp,str); 298 fprintf(pkt->p_stdout,"%s\n",str); 299 } 300 sprintf(str,"%c%c00000\n",CTLCHAR,HEAD); 301 putline(pkt,str); 302 newstats(pkt,str,"0"); 303 bcopy(sp,&dt.d_sid,sizeof(dt.d_sid)); 304 305 /* 306 Check if 'null' deltas should be inserted 307 (only if 'null' flag is in file and 308 releases are being skipped) and set 309 'nulldel' indicator appropriately. 310 */ 311 if (Sflags[NULLFLAG - 'a'] && (sp->s_rel > osp->s_rel + 1) && 312 !sp->s_br && !sp->s_seq && 313 !osp->s_br && !osp->s_seq) 314 nulldel = 1; 315 else 316 nulldel = 0; 317 /* 318 Calculate how many serial numbers are needed. 319 */ 320 if (nulldel) 321 ser_inc = sp->s_rel - osp->s_rel; 322 else 323 ser_inc = 1; 324 /* 325 Find serial number of the new delta. 326 */ 327 newser = dt.d_serial = maxser(pkt) + ser_inc; 328 /* 329 Find old predecessor's serial number. 330 */ 331 opred = sidtoser(osp,pkt); 332 if (nulldel) 333 dt.d_pred = newser - 1; /* set predecessor to 'null' delta */ 334 else 335 dt.d_pred = opred; 336 dt.d_datetime = Timenow; 337 substr(logname(),dt.d_pgmr,0,LNLNAM); 338 dt.d_type = 'D'; 339 del_ba(&dt,str); 340 putline(pkt,str); 341 # ifdef LOGDELTA 342 if (Logf != NULL) { 343 if (pkt->p_file[0] != '/') { 344 char buf[1024]; 345 346 if (getwd(buf) != NULL) 347 fprintf(Logf, "%s/", buf); 348 } 349 fprintf(Logf, "%s:\n%s%s\n", pkt->p_file, str + 5, Comments); 350 } 351 # endif 352 if (ilist) 353 mkixg(pkt,INCLUSER,INCLUDE); 354 if (elist) 355 mkixg(pkt,EXCLUSER,EXCLUDE); 356 if (glist) 357 mkixg(pkt,IGNRUSER,IGNORE); 358 if (Mrs) { 359 if (!(p = Sflags[VALFLAG - 'a'])) 360 fatal("MRs not allowed (de8)"); 361 if (*p && !diffloop && valmrs(pkt,p)) 362 fatal("invalid MRs (de9)"); 363 putmrs(pkt); 364 } 365 else if (Sflags[VALFLAG - 'a']) 366 fatal("MRs required (de10)"); 367 sprintf(str,"%c%c ",CTLCHAR,COMMENTS); 368 putline(pkt,str); 369 putline(pkt,Comments); 370 putline(pkt,"\n"); 371 sprintf(str,CTLSTR,CTLCHAR,EDELTAB); 372 putline(pkt,str); 373 if (nulldel) /* insert 'null' deltas */ 374 while (--ser_inc) { 375 sprintf(str,"%c%c %s/%s/%05u\n", CTLCHAR, STATS, "00000", "00000", orig_nlines); 376 putline(pkt,str); 377 dt.d_sid.s_rel -= 1; 378 dt.d_serial -= 1; 379 if (ser_inc != 1) 380 dt.d_pred -= 1; 381 else 382 dt.d_pred = opred; /* point to old pred */ 383 del_ba(&dt,str); 384 putline(pkt,str); 385 sprintf(str,"%c%c ",CTLCHAR,COMMENTS); 386 putline(pkt,str); 387 putline(pkt,"AUTO NULL DELTA\n"); 388 sprintf(str,CTLSTR,CTLCHAR,EDELTAB); 389 putline(pkt,str); 390 } 391 return(newser); 392 } 393 394 395 mkixg(pkt,reason,ch) 396 struct packet *pkt; 397 int reason; 398 char ch; 399 { 400 int n; 401 char str[512]; 402 403 sprintf(str,"%c%c",CTLCHAR,ch); 404 putline(pkt,str); 405 for (n = maxser(pkt); n; n--) { 406 if (pkt->p_apply[n].a_reason == reason) { 407 sprintf(str," %u",n); 408 putline(pkt,str); 409 } 410 } 411 putline(pkt,"\n"); 412 } 413 414 415 putmrs(pkt) 416 struct packet *pkt; 417 { 418 register char **argv; 419 char str[64]; 420 extern char *Varg[]; 421 422 for (argv = &Varg[VSTART]; *argv; argv++) { 423 sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv); 424 putline(pkt,str); 425 } 426 } 427 428 429 rdpfile(pkt,sp) 430 register struct packet *pkt; 431 struct sid *sp; 432 { 433 char *user; 434 struct pfile pf; 435 static struct pfile goodpf; 436 char line[512]; 437 int cnt, root; 438 FILE *in, *out; 439 440 cnt = -1; 441 user = logname(); 442 bzero(&goodpf,sizeof(goodpf)); 443 in = xfopen(auxf(pkt->p_file,'p'),0); 444 out = xfcreat(auxf(pkt->p_file,'q'),0644); 445 root = getuid() == 0; 446 while (fgets(line,sizeof(line),in) != NULL) { 447 pf_ab(line,&pf,1); 448 if (root || equal(pf.pf_user,user)) { 449 if (sp->s_rel == 0) { 450 if (++cnt) { 451 fclose(out); 452 fclose(in); 453 fatal("missing -r argument (de1)"); 454 } 455 bcopy(&pf,&goodpf,sizeof(pf)); 456 continue; 457 } 458 else if (sp->s_rel == pf.pf_gsid.s_rel && 459 sp->s_lev == pf.pf_gsid.s_lev && 460 sp->s_br == pf.pf_gsid.s_br && 461 sp->s_seq == pf.pf_gsid.s_seq) { 462 bcopy(&pf,&goodpf,sizeof(pf)); 463 continue; 464 } 465 } 466 fputs(line,out); 467 } 468 fflush(out); 469 fstat(fileno(out),&Statbuf); 470 Szqfile = Statbuf.st_size; 471 copy(auxf(pkt->p_file,'p'),Pfilename); 472 fclose(out); 473 fclose(in); 474 if (!goodpf.pf_user[0]) 475 fatal("not in p-file (de2)"); 476 return(&goodpf); 477 } 478 479 480 dodiff(newf,oldf,difflim) 481 char *newf, *oldf; 482 int difflim; 483 { 484 register int i; 485 int pfd[2]; 486 FILE *iop; 487 char num[10]; 488 489 xpipe(pfd); 490 if ((i = fork()) < 0) { 491 close(pfd[0]); 492 close(pfd[1]); 493 fatal("cannot fork, try again (de11)"); 494 } 495 else if (i == 0) { 496 close(pfd[0]); 497 dup2(pfd[1], 1); 498 if (pfd[1] != 1) 499 close(pfd[1]); 500 for (i = getdtablesize(); i > 4; i--) 501 close(i); 502 sprintf(num,"%d",difflim); 503 execl(_PATH_BDIFF,"bdiff",oldf,newf,num,"-s",0); 504 close(1); 505 exit(32); /* tell parent that 'execl' failed */ 506 } 507 else { 508 close(pfd[1]); 509 iop = fdopen(pfd[0],"r"); 510 return(iop); 511 } 512 } 513 514 515 getdiff(type,plinenum) 516 register char *type; 517 register int *plinenum; 518 { 519 char line[512]; 520 register char *p; 521 int num_lines; 522 static int chg_num, chg_ln; 523 int lowline, highline; 524 525 if ((p = rddiff(line,sizeof (line))) == NULL) 526 return(0); 527 528 if (*p == '-') { 529 *type = INS; 530 *plinenum = chg_ln; 531 num_lines = chg_num; 532 } 533 else { 534 p = linerange(p,&lowline,&highline); 535 *plinenum = lowline; 536 537 switch(*p++) { 538 case 'd': 539 num_lines = highline - lowline + 1; 540 *type = DEL; 541 skiplines(line,num_lines); 542 break; 543 544 case 'a': 545 linerange(p,&lowline,&highline); 546 num_lines = highline - lowline + 1; 547 *type = INS; 548 break; 549 550 case 'c': 551 chg_ln = lowline; 552 num_lines = highline - lowline + 1; 553 linerange(p,&lowline,&highline); 554 chg_num = highline - lowline + 1; 555 *type = DEL; 556 skiplines(line,num_lines); 557 break; 558 } 559 } 560 561 return(num_lines); 562 } 563 564 565 insert(pkt,linenum,n,ser) 566 register struct packet *pkt; 567 register int linenum; 568 register int n; 569 int ser; 570 { 571 char str[512]; 572 573 after(pkt,linenum); 574 sprintf(str,"%c%c %u\n",CTLCHAR,INS,ser); 575 putline(pkt,str); 576 for (++n; --n; ) { 577 rddiff(str,sizeof(str)); 578 putline(pkt,&str[2]); 579 } 580 sprintf(str,"%c%c %u\n",CTLCHAR,END,ser); 581 putline(pkt,str); 582 } 583 584 585 delete(pkt,linenum,n,ser) 586 register struct packet *pkt; 587 register int linenum; 588 int n; 589 register int ser; 590 { 591 char str[512]; 592 593 before(pkt,linenum); 594 sprintf(str,"%c%c %u\n",CTLCHAR,DEL,ser); 595 putline(pkt,str); 596 after(pkt,linenum + n - 1); 597 sprintf(str,"%c%c %u\n",CTLCHAR,END,ser); 598 putline(pkt,str); 599 } 600 601 602 after(pkt,n) 603 register struct packet *pkt; 604 register int n; 605 { 606 before(pkt,n); 607 if (pkt->p_glnno == n) 608 putline(pkt,0); 609 } 610 611 612 before(pkt,n) 613 register struct packet *pkt; 614 register int n; 615 { 616 while (pkt->p_glnno < n) { 617 if (!readmod(pkt)) 618 break; 619 } 620 } 621 622 623 linerange(cp,low,high) 624 register char *cp; 625 register int *low, *high; 626 { 627 cp = satoi(cp,low); 628 if (*cp == ',') 629 cp = satoi(++cp,high); 630 else 631 *high = *low; 632 633 return(cp); 634 } 635 636 637 skiplines(lp,num) 638 register char *lp; 639 register int num; 640 { 641 for (++num;--num;) 642 rddiff(lp,512); 643 } 644 645 646 rddiff(s,n) 647 register char *s; 648 register int n; 649 { 650 register int r; 651 652 if ((r = fgets(s,n,Diffin)) != NULL && HADP) 653 fputs(s,gpkt.p_stdout); 654 return(r); 655 } 656 657 658 enter(pkt,ch,n,sidp) 659 struct packet *pkt; 660 char ch; 661 int n; 662 struct sid *sidp; 663 { 664 char str[32]; 665 register struct apply *ap; 666 667 sid_ba(sidp,str); 668 ap = &pkt->p_apply[n]; 669 if (pkt->p_cutoff > pkt->p_idel[n].i_datetime) 670 switch(ap->a_code) { 671 672 case EMPTY: 673 switch (ch) { 674 case INCLUDE: 675 condset(ap,APPLY,INCLUSER); 676 break; 677 case EXCLUDE: 678 condset(ap,NOAPPLY,EXCLUSER); 679 break; 680 case IGNORE: 681 condset(ap,EMPTY,IGNRUSER); 682 break; 683 } 684 break; 685 case APPLY: 686 fatal("internal error in delta/enter() (de5)"); 687 break; 688 case NOAPPLY: 689 fatal("internal error in delta/enter() (de6)"); 690 break; 691 default: 692 fatal("internal error in delta/enter() (de7)"); 693 break; 694 } 695 } 696 697 698 escdodelt() /* dummy routine for dodelt() */ 699 { 700 } 701 702 703 clean_up(n) 704 { 705 if (gpkt.p_file[0]) 706 unlockit(auxf(gpkt.p_file,'z'),getpid()); 707 xrm(&gpkt); 708 xfreeall(); 709 } 710