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
 * bzip2-based file system.
3
 * the file system itself is just a bzipped2 xzipped mkfs archive
4
 * prefixed with "bzfilesystem\n" and suffixed with
5
 * a kilobyte of zeros.
6
 *
7
 * changes to the file system are only kept in 
8
 * memory, not written back to the disk.
9
 *
10
 * this is intended for use on a floppy boot disk.
11
 * we assume the file is in the dos file system and
12
 * contiguous on the disk: finding it amounts to
13
 * looking at the beginning of each sector for 
14
 * "bzfilesystem\n".  then we pipe it through 
15
 * bunzip2 and store the files in a file tree in memory.
16
 * things are slightly complicated by the fact that
17
 * devfloppy requires reads to be on a 512-byte
18
 * boundary and be a multiple of 512 bytes; we
19
 * fork a process to relieve bunzip2 of this restriction.
20
 */
21
 
22
#include <u.h>
23
#include <libc.h>
24
#include <bio.h>
25
#include <auth.h>
26
#include <fcall.h>
27
#include "bzfs.h"
28
 
29
enum{
30
	LEN	= 8*1024,
31
	NFLDS	= 6,		/* filename, modes, uid, gid, mtime, bytes */
32
};
33
 
34
void	mkdirs(char*, char*);
35
void	mkdir(char*, ulong, ulong, char*, char*);
36
void	extract(char*, ulong, ulong, char*, char*, ulong);
37
void	seekpast(ulong);
38
void	error(char*, ...);
39
void	warn(char*, ...);
40
void	usage(void);
41
char *mtpt;
42
Biobufhdr bin;
43
uchar	binbuf[2*LEN];
44
 
45
void
46
usage(void)
47
{
48
	fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n");
49
	exits("usage");
50
}
51
 
52
/*
53
 * floppy disks can only be read on 512-byte 
54
 * boundaries and in 512 byte multiples.
55
 * feed one over a pipe to allow arbitrary reading.
56
 */
57
char zero[512];
58
int
59
blockread(int in, char *first, int nfirst)
60
{
61
	int p[2], out, n, rv;
62
	char blk[512];
63
 
64
	if(pipe(p) < 0)
65
		sysfatal("pipe: %r");
66
	rv = p[0];
67
	out = p[1];
68
	switch(rfork(RFPROC|RFNOTEG|RFFDG)){
69
	case -1:
70
		sysfatal("fork: %r");
71
	case 0:
72
		close(rv);
73
		break;
74
	default:
75
		close(in);
76
		close(out);
77
		return rv;
78
	}
79
 
80
	write(out, first, nfirst);
81
 
82
	while((n=read(in, blk, sizeof blk)) > 0){
83
		if(write(out, blk, n) != n)
84
			break;
85
		if(n == sizeof(blk) && memcmp(zero, blk, n) == n)
86
			break;
87
	}
88
	_exits(0);
89
	return -1;
90
}
91
 
92
enum { NAMELEN = 28 };
93
 
94
void
95
main(int argc, char **argv)
96
{
97
	char *rargv[10];
98
	int rargc;
99
	char *fields[NFLDS], name[2*LEN], *p, *namep;
100
	char uid[NAMELEN], gid[NAMELEN];
101
	ulong mode, bytes, mtime;
102
	char *file;
103
	int i, n, stdin, fd, chatty;
104
	char blk[512];
105
 
106
	if(argc>1 && strcmp(argv[1], "RAMFS") == 0){
107
		argv[1] = argv[0];
108
		ramfsmain(argc-1, argv+1);
109
		exits(nil);
110
	}
111
	if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){
112
		_unbzip(0, 1);
113
		exits(nil);
114
	}
115
 
116
	rfork(RFNOTEG);
117
	stdin = 0;
118
	file = nil;
119
	namep = name;
120
	mtpt = "/root";
121
	chatty = 0;
122
	ARGBEGIN{
123
	case 'd':
124
		chatty = !chatty;
125
		break;
126
	case 'f':
127
		file = ARGF();
128
		break;
129
	case 's':
130
		stdin++;
131
		break;
132
	case 'm':
133
		mtpt = ARGF();
134
		break;
135
	default:
136
		usage();
137
	}ARGEND
138
 
139
	if(argc != 0)
140
		usage();
141
 
142
	if(file == nil) {
143
		fprint(2, "must specify -f file\n");
144
		usage();
145
	}
146
 
147
	if((fd = open(file, OREAD)) < 0) {
148
		fprint(2, "cannot open \"%s\": %r\n", file);
149
		exits("open");
150
	}
151
 
152
	rargv[0] = "ramfs";
153
	rargc = 1;
154
	if(stdin)
155
		rargv[rargc++] = "-i";
156
	rargv[rargc++] = "-m";
157
	rargv[rargc++] = mtpt;
158
	rargv[rargc] = nil;
159
	ramfsmain(rargc, rargv);
160
 
161
	if(1 || strstr(file, "disk")) {	/* search for archive on block boundary */
162
if(chatty) fprint(2, "searching for bz\n");
163
		for(i=0;; i++){
164
			if((n = readn(fd, blk, sizeof blk)) != sizeof blk)
165
				sysfatal("read %d gets %d: %r\n", i, n);
166
			if(strncmp(blk, "bzfilesystem\n", 13) == 0)
167
				break;
168
		}
169
if(chatty) fprint(2, "found at %d\n", i);
170
	}
171
 
172
	if(chdir(mtpt) < 0)
173
		error("chdir %s: %r", mtpt);
174
 
175
	fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13)));
176
 
177
	Binits(&bin, fd, OREAD, binbuf, sizeof binbuf);
178
	while(p = Brdline(&bin, '\n')){
179
		p[Blinelen(&bin)-1] = '\0';
180
if(chatty) fprint(2, "%s\n", p);
181
		if(strcmp(p, "end of archive") == 0){
182
			_exits(0);
183
		}
184
		if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
185
			warn("too few fields in file header");
186
			continue;
187
		}
188
		strcpy(namep, fields[0]);
189
		mode = strtoul(fields[1], 0, 8);
190
		mtime = strtoul(fields[4], 0, 10);
191
		bytes = strtoul(fields[5], 0, 10);
192
		strncpy(uid, fields[2], NAMELEN);
193
		strncpy(gid, fields[3], NAMELEN);
194
		if(mode & DMDIR)
195
			mkdir(name, mode, mtime, uid, gid);
196
		else
197
			extract(name, mode, mtime, uid, gid, bytes);
198
	}
199
	fprint(2, "premature end of archive\n");
200
	exits("premature end of archive");
201
}
202
 
203
char buf[8192];
204
 
205
int
206
ffcreate(char *name, ulong mode, char *uid, char *gid, ulong mtime, int length)
207
{
208
	int fd, om;
209
	Dir nd;
210
 
211
	sprint(buf, "%s/%s", mtpt, name);
212
	om = ORDWR;
213
	if(mode&DMDIR)
214
		om = OREAD;
215
	if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0)
216
		error("create %s: %r", buf);
217
 
218
	nulldir(&nd);
219
	nd.mode = mode;
220
	nd.uid = uid;
221
	nd.gid = gid;
222
	nd.mtime = mtime;
223
	if(length)
224
		nd.length = length;
225
	if(dirfwstat(fd, &nd) < 0)	
226
		error("fwstat %s: %r", buf);
227
 
228
	return fd;
229
}
230
 
231
void
232
mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
233
{
234
	close(ffcreate(name, mode, uid, gid, mtime, 0));
235
}
236
 
237
void
238
extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
239
{
240
	int fd, tot, n;
241
 
242
	fd = ffcreate(name, mode, uid, gid, mtime, bytes);
243
 
244
	for(tot = 0; tot < bytes; tot += n){
245
		n = sizeof buf;
246
		if(tot + n > bytes)
247
			n = bytes - tot;
248
		n = Bread(&bin, buf, n);
249
		if(n <= 0)
250
			error("premature eof reading %s", name);
251
		if(write(fd, buf, n) != n)
252
			error("short write writing %s", name);
253
	}
254
	close(fd);
255
}
256
 
257
void
258
error(char *fmt, ...)
259
{
260
	char buf[1024];
261
	va_list arg;
262
 
263
	sprint(buf, "%s: ", argv0);
264
	va_start(arg, fmt);
265
	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
266
	va_end(arg);
267
	fprint(2, "%s\n", buf);
268
	exits(0);
269
}
270
 
271
void
272
warn(char *fmt, ...)
273
{
274
	char buf[1024];
275
	va_list arg;
276
 
277
	sprint(buf, "%s: ", argv0);
278
	va_start(arg, fmt);
279
	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
280
	va_end(arg);
281
	fprint(2, "%s\n", buf);
282
}
283
 
284
int
285
_efgfmt(Fmt*)
286
{
287
	return -1;
288
}