xref: /inferno-os/appl/cmd/gettar.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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