1*37da2899SCharles.Forsythimplement Gettar; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsyth print, sprint, fprint: import sys; 6*37da2899SCharles.Forsyth stdin, stderr: ref sys->FD; 7*37da2899SCharles.Forsyth 8*37da2899SCharles.Forsythinclude "draw.m"; 9*37da2899SCharles.Forsyth 10*37da2899SCharles.Forsythinclude "arg.m"; 11*37da2899SCharles.Forsyth 12*37da2899SCharles.ForsythTBLOCK: con 512; # tar logical blocksize 13*37da2899SCharles.Forsyth 14*37da2899SCharles.ForsythHeader: adt{ 15*37da2899SCharles.Forsyth name: string; 16*37da2899SCharles.Forsyth size: int; 17*37da2899SCharles.Forsyth mode: int; 18*37da2899SCharles.Forsyth mtime: int; 19*37da2899SCharles.Forsyth skip: int; 20*37da2899SCharles.Forsyth}; 21*37da2899SCharles.Forsyth 22*37da2899SCharles.ForsythGettar: module 23*37da2899SCharles.Forsyth{ 24*37da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, nil: list of string); 25*37da2899SCharles.Forsyth}; 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsytherror(mess: string) 28*37da2899SCharles.Forsyth{ 29*37da2899SCharles.Forsyth fprint(stderr,"gettar: %s\n",mess); 30*37da2899SCharles.Forsyth raise "fail:error"; 31*37da2899SCharles.Forsyth} 32*37da2899SCharles.Forsyth 33*37da2899SCharles.Forsythverbose := 0; 34*37da2899SCharles.ForsythNBLOCK: con 20; # traditional blocking factor for efficient read 35*37da2899SCharles.Forsythtarbuf := array[NBLOCK*TBLOCK] of byte; # static buffer 36*37da2899SCharles.Forsythnblock := NBLOCK; # how many blocks of data are in tarbuf 37*37da2899SCharles.Forsythrecno := NBLOCK; # how many blocks in tarbuf have been consumed 38*37da2899SCharles.Forsyth 39*37da2899SCharles.Forsythgetblock(): array of byte 40*37da2899SCharles.Forsyth{ 41*37da2899SCharles.Forsyth if(recno>=nblock){ 42*37da2899SCharles.Forsyth i := sys->read(stdin,tarbuf,TBLOCK*NBLOCK); 43*37da2899SCharles.Forsyth if(i==0) 44*37da2899SCharles.Forsyth return nil; 45*37da2899SCharles.Forsyth if(i<0) 46*37da2899SCharles.Forsyth error(sys->sprint("read error: %r")); 47*37da2899SCharles.Forsyth if(i%TBLOCK!=0) 48*37da2899SCharles.Forsyth error("blocksize error"); 49*37da2899SCharles.Forsyth nblock = i/TBLOCK; 50*37da2899SCharles.Forsyth recno = 0; 51*37da2899SCharles.Forsyth } 52*37da2899SCharles.Forsyth recno++; 53*37da2899SCharles.Forsyth return tarbuf[(recno-1)*TBLOCK:recno*TBLOCK]; 54*37da2899SCharles.Forsyth} 55*37da2899SCharles.Forsyth 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsythoctal(b:array of byte): int 58*37da2899SCharles.Forsyth{ 59*37da2899SCharles.Forsyth sum := 0; 60*37da2899SCharles.Forsyth for(i:=0; i<len b; i++){ 61*37da2899SCharles.Forsyth bi := int b[i]; 62*37da2899SCharles.Forsyth if(bi==' ') continue; 63*37da2899SCharles.Forsyth if(bi==0) break; 64*37da2899SCharles.Forsyth sum = 8*sum + bi-'0'; 65*37da2899SCharles.Forsyth } 66*37da2899SCharles.Forsyth return sum; 67*37da2899SCharles.Forsyth} 68*37da2899SCharles.Forsyth 69*37da2899SCharles.Forsythnullterm(b:array of byte): string 70*37da2899SCharles.Forsyth{ 71*37da2899SCharles.Forsyth for(i:=0; i<len b; i++) 72*37da2899SCharles.Forsyth if(b[i]==byte 0) break; 73*37da2899SCharles.Forsyth return string b[0:i]; 74*37da2899SCharles.Forsyth} 75*37da2899SCharles.Forsyth 76*37da2899SCharles.Forsythgetdir(): ref Header 77*37da2899SCharles.Forsyth{ 78*37da2899SCharles.Forsyth dblock := getblock(); 79*37da2899SCharles.Forsyth if(len dblock==0) 80*37da2899SCharles.Forsyth return nil; 81*37da2899SCharles.Forsyth if(dblock[0]==byte 0) 82*37da2899SCharles.Forsyth return nil; 83*37da2899SCharles.Forsyth 84*37da2899SCharles.Forsyth name := nullterm(dblock[0:100]); 85*37da2899SCharles.Forsyth if(int dblock[345]!=0) 86*37da2899SCharles.Forsyth name = nullterm(dblock[345:500])+"/"+name; 87*37da2899SCharles.Forsyth if(!absolute){ 88*37da2899SCharles.Forsyth if(name[0] == '#') 89*37da2899SCharles.Forsyth name = "./"+name; 90*37da2899SCharles.Forsyth else if(name[0] == '/') 91*37da2899SCharles.Forsyth name = "."+name; 92*37da2899SCharles.Forsyth } 93*37da2899SCharles.Forsyth 94*37da2899SCharles.Forsyth magic := string(dblock[257:262]); 95*37da2899SCharles.Forsyth if(magic[0]!=0 && magic!="ustar") 96*37da2899SCharles.Forsyth error("bad magic "+name); 97*37da2899SCharles.Forsyth chksum := octal(dblock[148:156]); 98*37da2899SCharles.Forsyth for(ci:=148; ci<156; ci++) 99*37da2899SCharles.Forsyth dblock[ci] = byte ' '; 100*37da2899SCharles.Forsyth for(i:=0; i<TBLOCK; i++) 101*37da2899SCharles.Forsyth chksum -= int dblock[i]; 102*37da2899SCharles.Forsyth if(chksum!=0) 103*37da2899SCharles.Forsyth error("directory checksum error "+name); 104*37da2899SCharles.Forsyth 105*37da2899SCharles.Forsyth skip := 1; 106*37da2899SCharles.Forsyth size := 0; 107*37da2899SCharles.Forsyth mode := 0; 108*37da2899SCharles.Forsyth mtime := 0; 109*37da2899SCharles.Forsyth case int dblock[156]{ 110*37da2899SCharles.Forsyth '0' or '7' or 0 => 111*37da2899SCharles.Forsyth skip = 0; 112*37da2899SCharles.Forsyth size = octal(dblock[124:136]); 113*37da2899SCharles.Forsyth mode = 8r777 & octal(dblock[100: 108]); 114*37da2899SCharles.Forsyth mtime = octal(dblock[136:148]); 115*37da2899SCharles.Forsyth '1' => 116*37da2899SCharles.Forsyth fprint(stderr,"gettar: skipping link %s -> %s\n",name,string(dblock[157:257])); 117*37da2899SCharles.Forsyth '2' or 's' => 118*37da2899SCharles.Forsyth fprint(stderr,"gettar: skipping symlink %s\n",name); 119*37da2899SCharles.Forsyth '3' or '4' or '6' => 120*37da2899SCharles.Forsyth fprint(stderr,"gettar: skipping special file %s\n",name); 121*37da2899SCharles.Forsyth '5' => 122*37da2899SCharles.Forsyth if(name[(len name)-1]=='/') 123*37da2899SCharles.Forsyth checkdir(name+"."); 124*37da2899SCharles.Forsyth else 125*37da2899SCharles.Forsyth checkdir(name+"/."); 126*37da2899SCharles.Forsyth * => 127*37da2899SCharles.Forsyth error(sprint("unrecognized typeflag %d for %s",int dblock[156],name)); 128*37da2899SCharles.Forsyth } 129*37da2899SCharles.Forsyth return ref Header(name, size, mode, mtime, skip); 130*37da2899SCharles.Forsyth} 131*37da2899SCharles.Forsyth 132*37da2899SCharles.Forsythkeep := 0; 133*37da2899SCharles.Forsythabsolute := 0; 134*37da2899SCharles.Forsyth 135*37da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string) 136*37da2899SCharles.Forsyth{ 137*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 138*37da2899SCharles.Forsyth stdin = sys->fildes(0); 139*37da2899SCharles.Forsyth stderr = sys->fildes(2); 140*37da2899SCharles.Forsyth ofile: ref sys->FD; 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsyth arg := load Arg Arg->PATH; 143*37da2899SCharles.Forsyth arg->init(args); 144*37da2899SCharles.Forsyth arg->setusage("gettar [-kTRv] [file ...]"); 145*37da2899SCharles.Forsyth while((o := arg->opt()) != 0) 146*37da2899SCharles.Forsyth case o { 147*37da2899SCharles.Forsyth 'k' => keep = 1; 148*37da2899SCharles.Forsyth 'v' => verbose = 1; 149*37da2899SCharles.Forsyth 'R' => absolute = 1; 150*37da2899SCharles.Forsyth * => arg->usage(); 151*37da2899SCharles.Forsyth } 152*37da2899SCharles.Forsyth args = arg->argv(); 153*37da2899SCharles.Forsyth arg = nil; 154*37da2899SCharles.Forsyth 155*37da2899SCharles.Forsyth while((file := getdir())!=nil){ 156*37da2899SCharles.Forsyth if(!file.skip){ 157*37da2899SCharles.Forsyth if((args == nil || matched(file.name, args)) && !(keep && exists(file.name))){ 158*37da2899SCharles.Forsyth if(verbose) 159*37da2899SCharles.Forsyth sys->fprint(stderr, "%s\n", file.name); 160*37da2899SCharles.Forsyth checkdir(file.name); 161*37da2899SCharles.Forsyth ofile = sys->create(file.name, Sys->OWRITE, 8r666); 162*37da2899SCharles.Forsyth if(ofile==nil){ 163*37da2899SCharles.Forsyth fprint(stderr, "gettar: cannot create %s: %r\n",file.name); 164*37da2899SCharles.Forsyth file.skip = 1; 165*37da2899SCharles.Forsyth } 166*37da2899SCharles.Forsyth }else 167*37da2899SCharles.Forsyth file.skip = 1; 168*37da2899SCharles.Forsyth } 169*37da2899SCharles.Forsyth bytes := file.size; 170*37da2899SCharles.Forsyth blocks := (bytes+TBLOCK-1)/TBLOCK; 171*37da2899SCharles.Forsyth if(file.skip){ 172*37da2899SCharles.Forsyth for(; blocks>0; blocks--) 173*37da2899SCharles.Forsyth getblock(); 174*37da2899SCharles.Forsyth continue; 175*37da2899SCharles.Forsyth } 176*37da2899SCharles.Forsyth 177*37da2899SCharles.Forsyth for(; blocks>0; blocks--){ 178*37da2899SCharles.Forsyth buf := getblock(); 179*37da2899SCharles.Forsyth nwrite := bytes; 180*37da2899SCharles.Forsyth if(nwrite>TBLOCK) 181*37da2899SCharles.Forsyth nwrite = TBLOCK; 182*37da2899SCharles.Forsyth if(sys->write(ofile,buf,nwrite)!=nwrite) 183*37da2899SCharles.Forsyth error(sprint("write error for %s: %r",file.name)); 184*37da2899SCharles.Forsyth bytes -= nwrite; 185*37da2899SCharles.Forsyth } 186*37da2899SCharles.Forsyth ofile = nil; 187*37da2899SCharles.Forsyth stat := sys->nulldir; 188*37da2899SCharles.Forsyth stat.mode = file.mode; 189*37da2899SCharles.Forsyth stat.mtime = file.mtime; 190*37da2899SCharles.Forsyth rc := sys->wstat(file.name,stat); 191*37da2899SCharles.Forsyth if(rc<0){ 192*37da2899SCharles.Forsyth # try just the mode 193*37da2899SCharles.Forsyth stat.mtime = ~0; 194*37da2899SCharles.Forsyth rc = sys->wstat(file.name, stat); 195*37da2899SCharles.Forsyth if(rc < 0) 196*37da2899SCharles.Forsyth fprint(stderr,"gettar: cannot set mode/mtime %s %#o %ud: %r\n",file.name, file.mode, file.mtime); 197*37da2899SCharles.Forsyth } 198*37da2899SCharles.Forsyth } 199*37da2899SCharles.Forsyth} 200*37da2899SCharles.Forsyth 201*37da2899SCharles.Forsythcheckdir(name: string) 202*37da2899SCharles.Forsyth{ 203*37da2899SCharles.Forsyth (nc,compl) := sys->tokenize(name,"/"); 204*37da2899SCharles.Forsyth path := ""; 205*37da2899SCharles.Forsyth while(compl!=nil){ 206*37da2899SCharles.Forsyth comp := hd compl; 207*37da2899SCharles.Forsyth if(comp=="..") 208*37da2899SCharles.Forsyth error(".. pathnames forbidden"); 209*37da2899SCharles.Forsyth if(nc>1){ 210*37da2899SCharles.Forsyth if(path=="") 211*37da2899SCharles.Forsyth path = comp; 212*37da2899SCharles.Forsyth else 213*37da2899SCharles.Forsyth path += "/"+comp; 214*37da2899SCharles.Forsyth (rc,stat) := sys->stat(path); 215*37da2899SCharles.Forsyth if(rc<0){ 216*37da2899SCharles.Forsyth fd := sys->create(path,Sys->OREAD,Sys->DMDIR+8r777); 217*37da2899SCharles.Forsyth if(fd==nil) 218*37da2899SCharles.Forsyth error(sprint("cannot mkdir %s: %r",path)); 219*37da2899SCharles.Forsyth fd = nil; 220*37da2899SCharles.Forsyth }else if(stat.mode&Sys->DMDIR==0) 221*37da2899SCharles.Forsyth error(sprint("found non-directory at %s",path)); 222*37da2899SCharles.Forsyth } 223*37da2899SCharles.Forsyth nc--; compl = tl compl; 224*37da2899SCharles.Forsyth } 225*37da2899SCharles.Forsyth} 226*37da2899SCharles.Forsyth 227*37da2899SCharles.Forsythexists(path: string): int 228*37da2899SCharles.Forsyth{ 229*37da2899SCharles.Forsyth return sys->stat(path).t0 >= 0; 230*37da2899SCharles.Forsyth} 231*37da2899SCharles.Forsyth 232*37da2899SCharles.Forsythmatched(n: string, names: list of string): int 233*37da2899SCharles.Forsyth{ 234*37da2899SCharles.Forsyth for(; names != nil; names = tl names){ 235*37da2899SCharles.Forsyth p := hd names; 236*37da2899SCharles.Forsyth if(prefix(p, n)) 237*37da2899SCharles.Forsyth return 1; 238*37da2899SCharles.Forsyth } 239*37da2899SCharles.Forsyth return 0; 240*37da2899SCharles.Forsyth} 241*37da2899SCharles.Forsyth 242*37da2899SCharles.Forsythprefix(p: string, s: string): int 243*37da2899SCharles.Forsyth{ 244*37da2899SCharles.Forsyth l := len p; 245*37da2899SCharles.Forsyth if(l > len s) 246*37da2899SCharles.Forsyth return 0; 247*37da2899SCharles.Forsyth return p == s[0:l] && (l == len s || s[l] == '/'); 248*37da2899SCharles.Forsyth} 249