Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * File system for tar archives (read-only)
3
 */
4
 
5
#include <u.h>
6
#include <libc.h>
7
#include <auth.h>
8
#include <fcall.h>
9
#include "tapefs.h"
10
 
11
/* fundamental constants */
12
enum {
13
	Tblock = 512,
14
	Namsiz = 100,
15
	Maxpfx = 155,		/* from POSIX */
16
	Maxname = Namsiz + 1 + Maxpfx,
17
	Binsize = 0x80,		/* flag in size[0], from gnu: positive binary size */
18
	Binnegsz = 0xff,	/* flag in size[0]: negative binary size */
19
};
20
 
21
/* POSIX link flags */
22
enum {
23
	LF_PLAIN1 =	'\0',
24
	LF_PLAIN2 =	'0',
25
	LF_LINK =	'1',
26
	LF_SYMLINK1 =	'2',
27
	LF_SYMLINK2 =	's',		/* 4BSD used this */
28
	LF_CHR =	'3',
29
	LF_BLK =	'4',
30
	LF_DIR =	'5',
31
	LF_FIFO =	'6',
32
	LF_CONTIG =	'7',
33
	/* 'A' - 'Z' are reserved for custom implementations */
34
};
35
 
36
typedef union {
37
	char	dummy[Tblock];
38
	char	tbuf[Maxbuf];
39
	struct Header {
40
		char	name[Namsiz];
41
		char	mode[8];
42
		char	uid[8];
43
		char	gid[8];
44
		char	size[12];
45
		char	mtime[12];
46
		char	chksum[8];
47
		char	linkflag;
48
		char	linkname[Namsiz];
49
 
50
		/* rest are defined by POSIX's ustar format; see p1003.2b */
51
		char	magic[6];	/* "ustar" */
52
		char	version[2];
53
		char	uname[32];
54
		char	gname[32];
55
		char	devmajor[8];
56
		char	devminor[8];
57
		char	prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
58
	};
59
} Hdr;
60
 
61
Hdr dblock;
62
int tapefile;
63
 
64
int	checksum(void);
65
 
66
static int
67
isustar(Hdr *hp)
68
{
69
	return strcmp(hp->magic, "ustar") == 0;
70
}
71
 
72
/*
73
 * s is at most n bytes long, but need not be NUL-terminated.
74
 * if shorter than n bytes, all bytes after the first NUL must also
75
 * be NUL.
76
 */
77
static int
78
strnlen(char *s, int n)
79
{
80
	return s[n - 1] != '\0'? n: strlen(s);
81
}
82
 
83
/* set fullname from header */
84
static char *
85
tarname(Hdr *hp)
86
{
87
	int pfxlen, namlen;
88
	static char fullname[Maxname+1];
89
 
90
	namlen = strnlen(hp->name, sizeof hp->name);
91
	if (hp->prefix[0] == '\0' || !isustar(hp)) {	/* old-style name? */
92
		memmove(fullname, hp->name, namlen);
93
		fullname[namlen] = '\0';
94
		return fullname;
95
	}
96
 
97
	/* posix name: name is in two pieces */
98
	pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
99
	memmove(fullname, hp->prefix, pfxlen);
100
	fullname[pfxlen] = '/';
101
	memmove(fullname + pfxlen + 1, hp->name, namlen);
102
	fullname[pfxlen + 1 + namlen] = '\0';
103
	return fullname;
104
}
105
 
106
void
107
populate(char *name)
108
{
109
	long chksum, linkflg;
110
	vlong blkno;
111
	char *fname;
112
	Fileinf f;
113
	Hdr *hp;
114
 
115
	tapefile = open(name, OREAD);
116
	if (tapefile < 0)
117
		error("Can't open argument file");
118
	replete = 1;
119
	hp = &dblock;
120
	for (blkno = 0; ; blkno++) {
121
		seek(tapefile, Tblock*blkno, 0);
122
		if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
123
			break;
124
		fname = tarname(hp);
125
		if (fname[0] == '\0')
126
			break;
127
 
128
		/* crack header */
129
		f.addr = blkno + 1;
130
		f.mode = strtoul(hp->mode, 0, 8);
131
		f.uid  = strtoul(hp->uid, 0, 8);
132
		f.gid  = strtoul(hp->gid, 0, 8);
133
		if((uchar)hp->size[0] == 0x80)
134
			f.size = b8byte(hp->size+3);
135
		else
136
			f.size = strtoull(hp->size, 0, 8);
137
		f.mdate = strtoul(hp->mtime, 0, 8);
138
		chksum  = strtoul(hp->chksum, 0, 8);
139
		/* the mode test is ugly but sometimes necessary */
140
		if (hp->linkflag == LF_DIR || (f.mode&0170000) == 040000 ||
141
		    strrchr(fname, '\0')[-1] == '/'){
142
			f.mode |= DMDIR;
143
			f.size = 0;
144
		}
145
		f.mode &= DMDIR | 0777;
146
 
147
		/* make file name safe, canonical and free of . and .. */
148
		while (fname[0] == '/')		/* don't allow absolute paths */
149
			++fname;
150
		cleanname(fname);
151
		while (strncmp(fname, "../", 3) == 0)
152
			fname += 3;
153
 
154
		/* reject links */
155
		linkflg = hp->linkflag == LF_SYMLINK1 ||
156
			hp->linkflag == LF_SYMLINK2 || hp->linkflag == LF_LINK;
157
		if (chksum != checksum()){
158
			fprint(2, "%s: bad checksum on %.28s at offset %lld\n",
159
				argv0, fname, Tblock*blkno);
160
			exits("checksum");
161
		}
162
		if (linkflg) {
163
			/*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
164
			f.size = 0;
165
		} else {
166
			/* accept this file */
167
			f.name = fname;
168
			if (f.name[0] == '\0')
169
				fprint(2, "%s: null name skipped\n", argv0);
170
			else
171
				poppath(f, 1);
172
			blkno += (f.size + Tblock - 1)/Tblock;
173
		}
174
	}
175
}
176
 
177
void
178
dotrunc(Ram *r)
179
{
180
	USED(r);
181
}
182
 
183
void
184
docreate(Ram *r)
185
{
186
	USED(r);
187
}
188
 
189
char *
190
doread(Ram *r, vlong off, long cnt)
191
{
192
	int n;
193
 
194
	seek(tapefile, Tblock*r->addr + off, 0);
195
	if (cnt > sizeof dblock.tbuf)
196
		error("read too big");
197
	n = readn(tapefile, dblock.tbuf, cnt);
198
	if (n != cnt)
199
		memset(dblock.tbuf + n, 0, cnt - n);
200
	return dblock.tbuf;
201
}
202
 
203
void
204
popdir(Ram *r)
205
{
206
	USED(r);
207
}
208
 
209
void
210
dowrite(Ram *r, char *buf, long off, long cnt)
211
{
212
	USED(r); USED(buf); USED(off); USED(cnt);
213
}
214
 
215
int
216
dopermw(Ram *r)
217
{
218
	USED(r);
219
	return 0;
220
}
221
 
222
int
223
checksum(void)
224
{
225
	int i, n;
226
	uchar *cp;
227
 
228
	memset(dblock.chksum, ' ', sizeof dblock.chksum);
229
	cp = (uchar *)dblock.dummy;
230
	i = 0;
231
	for (n = Tblock; n-- > 0; )
232
		i += *cp++;
233
	return i;
234
}