1 static char *sccsid = "@(#)arff.c 4.1 (Berkeley) 10/01/80"; 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <time.h> 5 #include <signal.h> 6 #include <stdio.h> 7 #define dbprintf printf 8 struct rt_dat { 9 unsigned short int rt_yr:5; /*Year - 1972 */ 10 unsigned short int rt_dy:5; /*day */ 11 unsigned short int rt_mo:5; /*month */ 12 }; 13 struct rt_axent { 14 char rt_sent[14]; 15 }; 16 17 struct rt_ent { 18 char rt_pad; /*unusued */ 19 char rt_stat; /*Type of entry, or end of seg*/ 20 unsigned short rt_name[3]; /*Name, 3 words in rad50 form */ 21 short rt_len; /*Length of file */ 22 char rt_chan; /*Only used in temporary files*/ 23 char rt_job; /*Only used in temporary files*/ 24 struct rt_dat rt_date; /*Creation Date */ 25 }; 26 #define RT_TEMP 1 27 #define RT_NULL 2 28 #define RT_FILE 4 29 #define RT_ESEG 8 30 #define RT_BLOCK 512 31 struct rt_head { 32 short rt_numseg; /*number of segments available*/ 33 short rt_nxtseg; /*segment no of next log. seg */ 34 short rt_lstseg; /*highest seg currenltly open */ 35 unsigned short rt_entpad; /*extra words/dir. entry */ 36 short rt_stfile; /*block no where files begin */ 37 }; 38 struct rt_dir { 39 struct rt_head rt_axhead; 40 struct rt_ent rt_ents[72]; 41 char _dirpad[6]; 42 }; 43 extern struct rt_dir rt_dir; 44 extern int rt_entsiz; 45 extern int floppydes; 46 extern char *rt_last; 47 typedef struct fldope { 48 int startad; 49 int count; 50 struct rt_ent *rtdope; 51 } FLDOPE; 52 FLDOPE *lookup(); 53 #define rt(p) ((struct rt_ent *) p ) 54 #define Ain1 03100 55 #define Ain2 050 56 #define flag(c) (flg[(c) - 'a']) 57 58 char *man = { "rxtd" }; 59 60 char zeroes[512]; 61 extern char *val; 62 extern char table[256]; 63 struct rt_dir rt_dir = {{4,0,1,0,14},{0,RT_NULL,{0,0,0},494,0}, {0,RT_ESEG}}; 64 int rt_entsiz; 65 int rt_nleft; 66 struct rt_ent *rt_curend; 67 int floppydes; 68 int dirdirty; 69 char *rt_last; 70 char *defdev = "/dev/floppy"; 71 72 char *opt = { "vf" }; 73 74 int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0}; 75 long lseek(); 76 int rcmd(); 77 int dcmd(); 78 int xcmd(); 79 int tcmd(); 80 int (*comfun)(); 81 char flg[26]; 82 char **namv; 83 int namc; 84 int file; 85 86 87 main(argc, argv) 88 char *argv[]; 89 { 90 register char *cp; 91 92 /*register i; 93 for(i=0; signum[i]; i++) 94 if(signal(signum[i], SIG_IGN) != SIG_IGN) 95 signal(signum[i], sigdone);*/ 96 if(argc < 2) 97 usage(); 98 cp = argv[1]; 99 for(cp = argv[1]; *cp; cp++) 100 switch(*cp) { 101 case 'm': 102 case 'v': 103 case 'u': 104 case 'w': 105 flg[*cp - 'a']++; 106 continue; 107 case 'c': 108 { 109 #define SURE "Are you sure you want to clobber the floppy?\n" 110 int tty; 111 char response[2]; 112 tty = open("/dev/tty",2); 113 write(tty,SURE,sizeof(SURE)); 114 read(tty,response,2); 115 if(*response!='y') 116 exit(50); 117 flag('c')++; 118 close(tty); 119 } 120 dirdirty++; 121 continue; 122 123 case 'r': 124 setcom(rcmd); 125 flag('r')++; 126 continue; 127 128 case 'd': 129 setcom(dcmd); 130 flag('d')++; 131 continue; 132 133 case 'x': 134 setcom(xcmd); 135 continue; 136 137 case 't': 138 setcom(tcmd); 139 continue; 140 141 case 'f': 142 defdev = argv[2]; 143 argv++; 144 argc--; 145 continue; 146 147 148 default: 149 fprintf(stderr, "arff: bad option `%c'\n", *cp); 150 exit(1); 151 } 152 namv = argv+2; 153 namc = argc-2; 154 if(comfun == 0) { 155 if(flg['u'-'a'] == 0) { 156 fprintf(stderr, "arff: one of [%s] must be specified\n", man); 157 exit(1); 158 } 159 setcom(rcmd); 160 } 161 (*comfun)(); 162 exit(notfound()); 163 } 164 165 setcom(fun) 166 int (*fun)(); 167 { 168 169 if(comfun != 0) { 170 fprintf(stderr, "arff: only one of [%s] allowed\n", man); 171 exit(1); 172 } 173 comfun = fun; 174 } 175 176 177 178 179 180 181 182 183 usage() 184 { 185 printf("usage: ar [%s][%s] archive files ...\n", opt, man); 186 exit(1); 187 } 188 189 190 191 notfound() 192 { 193 register i, n; 194 195 n = 0; 196 for(i=0; i<namc; i++) 197 if(namv[i]) { 198 fprintf(stderr, "arff: %s not found\n", namv[i]); 199 n++; 200 } 201 return(n); 202 } 203 204 205 206 phserr() 207 { 208 209 fprintf(stderr, "arff: phase error on %s\n", file); 210 } 211 212 mesg(c) 213 { 214 215 if(flg['v'-'a']) 216 if(c != 'c' || flg['v'-'a'] > 1) 217 printf("%c - %s\n", c, file); 218 } 219 220 tcmd() 221 { 222 register char *de; 223 FLDOPE *lookup(), *dope; 224 int nleft; register i; 225 register struct rt_ent *rde; 226 227 rt_init(); 228 if(namc==0) 229 for(de=((char *)&rt_dir)+10; de <= rt_last; de += rt_entsiz) { 230 if(rtls(rt(de))) { 231 nleft = (rt_last - de) / rt_entsiz; 232 printf("\n\n%d entries remaining.\n",nleft); 233 break; 234 } 235 } 236 else 237 for(i = 0; i < namc; i++) { 238 if(dope = lookup(namv[i])) { 239 rde = dope->rtdope; 240 rtls(rde); 241 namv[i] = 0; 242 } 243 } 244 } 245 rtls(de) 246 register struct rt_ent *de; 247 { 248 int month,day,year; 249 char name[12], ext[4]; 250 251 if(flg['v'-'a']) 252 switch(de->rt_stat) { 253 case RT_TEMP: 254 printf("Tempfile:\n"); 255 case RT_FILE: 256 unrad50(2,de->rt_name,name); 257 unrad50(1,&(de->rt_name[2]),ext); 258 day = de->rt_date.rt_dy; 259 year = de->rt_date.rt_yr + 72; 260 month = de->rt_date.rt_mo; 261 printf("%6.6s %3.3s %02d/%02d/%02d %d\n",name, 262 ext,month,day,year,de->rt_len); 263 break; 264 265 case RT_NULL: 266 printf("%-25.9s %d\n","<UNUSED>",de->rt_len); 267 break; 268 269 case RT_ESEG: 270 return(1); 271 } 272 else { 273 switch(de->rt_stat) { 274 case RT_TEMP: 275 case RT_FILE: 276 sunrad50(name,de->rt_name); 277 printf(name);putchar('\n'); 278 break; 279 280 case RT_ESEG: 281 return(1); 282 283 case RT_NULL: 284 ; 285 } 286 } 287 return(0); 288 } 289 xcmd() 290 { 291 register char *de; 292 char name[12]; 293 register int i; 294 295 rt_init(); 296 if(namc==0) 297 for(de=((char *)&rt_dir)+10; de <= rt_last; de += rt_entsiz) { 298 sunrad50(name,rt(de)->rt_name); 299 rtx(name); 300 } 301 302 else 303 for(i = 0; i < namc; i++) 304 if(rtx(namv[i])==0) namv[i] = 0; 305 } 306 rtx(name) 307 char *name; 308 { 309 register FLDOPE *dope; 310 FLDOPE *lookup(); 311 register startad, count; 312 int file; char buff[512]; 313 314 315 if(dope = lookup(name)) { 316 if(flg['v' - 'a']) 317 rtls(dope->rtdope); 318 else 319 printf("x - %s\n",name); 320 321 file = creat(name, 0666); 322 if(file < 0) return(1); 323 count = dope->count; 324 startad = dope->startad; 325 for( ; count > 0 ; count -= 512) { 326 lread(startad,512,buff); 327 write(file,buff,512); 328 startad += 512; 329 } 330 close(file); 331 return(0); 332 } 333 return(1); 334 } 335 rt_init() 336 { 337 static initized = 0; 338 register char *de; 339 int mode; 340 341 if(initized) return; 342 initized = 1; 343 if(flag('c') || flag('d') || flag('r')) 344 mode = 2; 345 else 346 mode = 0; 347 if((floppydes = open(defdev,mode)) < 0) 348 dbprintf("Floppy open failed\n"); 349 if(flag('c')==0) 350 lread(6*RT_BLOCK,2*RT_BLOCK,(char *)&rt_dir); 351 352 rt_entsiz = 2*rt_dir.rt_axhead.rt_entpad + 14; 353 rt_entsiz = 14; 354 rt_last = ((char *) &rt_dir) + 10 + 1014/rt_entsiz*rt_entsiz; 355 for(de=((char *)&rt_dir)+10; de <= rt_last; de += rt_entsiz) { 356 if(rt(de)->rt_stat==RT_ESEG) break; 357 } 358 rt_curend = rt(de); 359 rt_nleft = (rt_last - de) / rt_entsiz; 360 } 361 362 static FLDOPE result; 363 FLDOPE * 364 lookup(name) 365 char * name; 366 { 367 unsigned short rname[3]; 368 register char *de; 369 register index; 370 371 srad50(name,rname); 372 373 /* 374 * Search for name, accumulate blocks in index 375 */ 376 rt_init(); 377 index = 0; 378 for(de = ((char *) &rt_dir) + 10; de <= rt_last; de += rt_entsiz) { 379 switch(rt(de)->rt_stat) { 380 case RT_ESEG: 381 return((FLDOPE *) 0); 382 case RT_FILE: 383 case RT_TEMP: 384 if(samename(rname,rt(de)->rt_name)) 385 goto found; 386 case RT_NULL: 387 index += rt(de)->rt_len; 388 } 389 } 390 return((FLDOPE *) 0); 391 found: result.count = rt(de)->rt_len * 512; 392 result.startad = 512 * (rt_dir.rt_axhead.rt_stfile + index); 393 result.rtdope = (struct rt_ent *) de; 394 return(&result); 395 } 396 static 397 samename(a,b) 398 unsigned short a[3],b[3]; 399 { 400 return( a[0]==b[0] && a[1]==b[1] && a[2]==b[2] ); 401 } 402 403 404 rad50(cp,out) 405 register unsigned char *cp; 406 unsigned short *out; 407 { 408 register index; 409 register temp; 410 411 for(index = 0;*cp; index++) { 412 413 temp = Ain1 * table[*cp++]; 414 if(*cp!=0) { 415 temp += Ain2 * table[*cp++]; 416 417 if(*cp!=0) 418 temp += table[*cp++]; 419 } 420 421 out[index] = temp; 422 } 423 } 424 #define reduce(x,p,q) \ 425 (x = v[p/q], p %= q); 426 427 unrad50(count,in,cp) 428 unsigned short *in; 429 register char *cp; 430 { 431 register i, temp; register unsigned char *v = (unsigned char *) val; 432 433 for(i = 0; i < count; i++) { 434 temp = in[i]; 435 436 reduce (*cp++,temp,Ain1); 437 reduce (*cp++,temp,Ain2); 438 reduce (*cp++,temp,1); 439 } 440 *cp=0; 441 } 442 443 srad50(name,rname) 444 register char * name; 445 register unsigned short *rname; 446 { 447 register index; register char *cp; 448 char file[7],ext[4]; 449 /* 450 * Find end of pathname 451 */ 452 for(cp = name; *cp++; ); 453 while(cp >= name && *--cp != '/'); 454 cp++; 455 /* 456 * Change to rad50 457 * 458 */ 459 for(index = 0; *cp; ){ 460 file[index++] = *cp++; 461 if(*cp=='.') { 462 cp++; 463 break; 464 } 465 if(index>=6) { 466 break; 467 } 468 } 469 file[index] = 0; 470 for(index = 0; *cp; ){ 471 ext[index++] = *cp++; 472 if(*cp=='.' || index>=3) { 473 break; 474 } 475 } 476 ext[index]=0; 477 rname[0] = 0; 478 rname[1] = 0; 479 rname[2] = 0; 480 rad50((unsigned char *)file,rname); 481 rad50((unsigned char *)ext,rname+2); 482 } 483 sunrad50(name,rname) 484 unsigned short rname[3]; 485 register char *name; 486 { 487 register char *cp, *cp2; 488 char ext[4]; 489 490 unrad50(2,rname,name); 491 unrad50(1,rname + 2,ext); 492 /* Jam name and extension together with a dot 493 deleting white space */ 494 for(cp = name; *cp++;);--cp; while(*--cp==' ' && cp>=name); 495 *++cp = '.';cp++; 496 for(cp2=ext; *cp2!=' ' && cp2 < ext + 3;) { 497 *cp++ = *cp2++; 498 } 499 *cp=0; 500 if(cp[-1]=='.') cp[-1] = 0; 501 } 502 503 static char *oval = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.@0123456789"; 504 static char *val = " abcdefghijklmnopqrstuvwxyz$.@0123456789"; 505 static char table[256] = { 506 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 507 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 508 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 509 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29, 510 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 511 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, 512 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 513 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, 514 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 515 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 516 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 517 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29, 518 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 519 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, 520 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 521 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29 }; 522 523 long trans(logical) 524 register int logical; 525 { 526 /* Logical to physical adress translation */ 527 register int sector, bytes, track; 528 529 logical += 26 * 128; 530 bytes = (logical & 127); 531 logical >>= 7; 532 sector = logical % 26; 533 if(sector >= 13) 534 sector = sector *2 +1; 535 else 536 sector *= 2; 537 sector += 26 + ((track = (logical / 26)) - 1) * 6; 538 sector %= 26; 539 return( (((track *26) + sector) << 7) + bytes); 540 } 541 lread(startad,count,obuff) 542 register startad, count; 543 register char * obuff; 544 { 545 long trans(); 546 extern floppydes; 547 rt_init(); 548 if(flg['m'-'a']==0) 549 while( (count -= 128) >= 0) { 550 lseek(floppydes, trans(startad), 0); 551 read(floppydes,obuff,128); 552 obuff += 128; 553 startad += 128; 554 } 555 else 556 while( (count -= 512) >= 0) { 557 lseek(floppydes,(long) (startad), 0); 558 read(floppydes,obuff,512); 559 obuff += 512; 560 startad += 512; 561 } 562 } 563 lwrite(startad,count,obuff) 564 register startad, count; 565 register char * obuff; 566 { 567 long trans(); 568 extern floppydes; 569 rt_init(); 570 if(flg['m'-'a']==0) 571 while( (count -= 128) >= 0) { 572 lseek(floppydes, trans(startad), 0); 573 write(floppydes,obuff,128); 574 obuff += 128; 575 startad += 128; 576 } 577 else 578 while( (count -= 512) >= 0) { 579 lseek(floppydes,(long) (startad), 0); 580 write(floppydes,obuff,512); 581 obuff += 512; 582 startad += 512; 583 } 584 } 585 586 rcmd() 587 { 588 register int i; 589 590 rt_init(); 591 if(namc>0) 592 for(i = 0; i < namc; i++) 593 if(rtr(namv[i])==0) namv[i]=0; 594 595 596 } 597 598 rtr(name) 599 char *name; 600 { 601 register FLDOPE *dope; register struct rt_ent *de; 602 struct stat buf; register struct stat *bufp = &buf; 603 604 if(stat(name,bufp)<0) return(1); 605 if(dope = lookup(name)) { 606 /* can replace, no problem */ 607 de = dope->rtdope; 608 if(bufp->st_size <= (de->rt_len * 512)) 609 printf("r - %s\n",name), 610 toflop(name,bufp->st_size,dope); 611 else { 612 printf("%s will not fit in currently used file on floppy\n",name); 613 return(1); 614 } 615 } else { 616 /* Search for vacant spot */ 617 for(de = rt_dir.rt_ents; (char *) de <= rt_last; de++) { 618 switch((de)->rt_stat) { 619 case RT_NULL: 620 if(bufp->st_size <= (de->rt_len * 512)) { 621 printf("a - %s\n",name), 622 mkent(de,bufp,name); 623 goto found; 624 } 625 continue; 626 case RT_ESEG: 627 return(3); 628 } 629 } 630 return(5); 631 } 632 found: if(dope=lookup(name)) { 633 toflop(name,bufp->st_size,dope); 634 return(0); 635 } 636 return(7); 637 638 } 639 mkent(de,bufp,name) 640 register struct rt_ent *de; 641 register struct stat *bufp; 642 char *name; 643 { 644 struct tm *localtime(); register struct tm *timp; 645 register struct rt_ent *workp; int count; 646 647 count = (((bufp->st_size -1) >>9) + 1); 648 /* Make sure there is room */ 649 if(de->rt_len==count) 650 goto overwrite; 651 if(rt_nleft==0) { 652 if(flg['o'-'a']) 653 goto overwrite; 654 fprintf(stderr,"Directory full on %s\n",defdev); 655 exit(1); 656 } 657 /* copy directory entries up */ 658 for(workp = rt_curend+1; workp > de; workp--) 659 *workp = workp[-1]; 660 de[1].rt_len -= count; 661 de->rt_len = count; 662 rt_curend++; 663 rt_nleft--; 664 overwrite: 665 srad50(name,de->rt_name); 666 timp = localtime(&bufp->st_mtime); 667 de->rt_date.rt_dy = timp->tm_mday + 1; 668 de->rt_date.rt_mo = timp->tm_mon + 1; 669 de->rt_date.rt_yr = timp->tm_year - 72; 670 de->rt_stat = RT_FILE; 671 de->rt_pad = 0; 672 de->rt_chan = 0; 673 de->rt_job = 0; 674 lwrite(6*RT_BLOCK,2*RT_BLOCK,(char *)&rt_dir); 675 676 } 677 678 toflop(name,ocount,dope) 679 char *name; 680 register FLDOPE *dope; 681 long ocount; 682 { 683 register file, n, startad = dope->startad, count = ocount; 684 char buff[512]; 685 686 file = open(name,0); 687 if(file < 0) { 688 printf("arff: couldn't open %s\n",name);exit(1);} 689 for( ; count >= 512; count -= 512) { 690 read(file,buff,512); 691 lwrite(startad,512,buff); 692 startad += 512; 693 } 694 read(file,buff,count); 695 close(file); 696 if(count <= 0) return; 697 for(n = count; n < 512; n ++) buff[n] = 0; 698 lwrite(startad,512,buff); 699 count = (dope->rtdope->rt_len * 512 - ocount) / 512 ; 700 if(count <= 0) return; 701 for( ; count > 0 ; count--) { 702 startad += 512; 703 lwrite(startad,512,zeroes); 704 } 705 706 } 707 dcmd() 708 { 709 register int i; 710 711 rt_init(); 712 if(namc) 713 for(i = 0; i < namc; i++) 714 if(rtk(namv[i])==0) namv[i]=0; 715 if(dirdirty) 716 scrunch(); 717 718 } 719 rtk(name) 720 char *name; 721 { 722 register FLDOPE *dope; 723 register struct rt_ent *de; 724 FLDOPE *lookup(); 725 726 if(dope = lookup(name)) { 727 printf("d - %s\n",name); 728 de = dope->rtdope; 729 de->rt_stat = RT_NULL; 730 de->rt_name[0] = 0; 731 de->rt_name[1] = 0; 732 de->rt_name[2] = 0; 733 * ((unsigned short *) & (de->rt_date)) = 0; 734 dirdirty = 1; 735 return(0); 736 } 737 return(1); 738 } 739 scrunch() { 740 register struct rt_ent *de = rt_dir.rt_ents, *workp; 741 for(de = rt_dir.rt_ents; de <= rt_curend; de++) { 742 if(de->rt_stat==RT_NULL && de[1].rt_stat==RT_NULL) { 743 (de+1)->rt_len += de->rt_len; 744 for(workp = de; workp < rt_curend; workp++) 745 *workp = workp[1]; 746 de--; 747 rt_curend--; 748 rt_nleft++; 749 } 750 } 751 lwrite(6*RT_BLOCK,2*RT_BLOCK,(char *)&rt_dir); 752 } 753