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