Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * archfs - mount mkfs style archives
3
 */
4
 
5
#include <u.h>
6
#include <libc.h>
7
#include <bio.h>
8
#include <auth.h>
9
#include <fcall.h>
10
#include <thread.h>
11
#include <9p.h>
12
 
13
Tree *archtree;
14
Biobuf *b;
15
int verbose;
16
 
17
typedef struct Ahdr Ahdr;
18
struct Ahdr {
19
	char *name;
20
	Dir;
21
};
22
 
23
typedef struct Arch Arch;
24
struct Arch {
25
	vlong off;
26
	vlong length;
27
};
28
 
29
static void*
30
emalloc(long sz)
31
{
32
	void *v;
33
 
34
	v = malloc(sz);
35
	if(v == nil)
36
		sysfatal("malloc %lud fails", sz);
37
	memset(v, 0, sz);
38
	return v;
39
}
40
 
41
static char*
42
estrdup(char *s)
43
{
44
	s = strdup(s);
45
	if(s == nil)
46
		sysfatal("strdup (%.10s) fails", s);
47
	return s;
48
}
49
 
50
static char*
51
Bgetline(Biobuf *b)
52
{
53
	char *p;
54
 
55
	if(p = Brdline(b, '\n'))
56
		p[Blinelen(b)-1] = '\0';
57
	return p;
58
}
59
 
60
Ahdr*
61
gethdr(Biobuf *b)
62
{
63
	Ahdr *a;
64
	char *p, *f[10];
65
 
66
	if((p = Bgetline(b)) == nil)
67
		return nil;
68
 
69
	if(strcmp(p, "end of archive") == 0) {
70
		werrstr("");
71
		return nil;
72
	}
73
 
74
	if(tokenize(p, f, nelem(f)) != 6) {
75
		werrstr("bad format");
76
		return nil;
77
	}
78
 
79
	a = emalloc(sizeof(*a));
80
	a->name = estrdup(f[0]);
81
	a->mode = strtoul(f[1], 0, 8);
82
	a->uid = estrdup(f[2]);
83
	a->gid = estrdup(f[3]);
84
	a->mtime = strtoll(f[4], 0, 10);
85
	a->length = strtoll(f[5], 0, 10);
86
	return a;
87
}
88
 
89
static Arch*
90
newarch(vlong off, vlong length)
91
{
92
	static Arch *abuf;
93
	static int nabuf;
94
 
95
	if(nabuf == 0) {
96
		nabuf = 256;
97
		abuf = emalloc(sizeof(Arch)*nabuf);
98
	}
99
 
100
	nabuf--;
101
	abuf->off = off;
102
	abuf->length = length;
103
	return abuf++;
104
}
105
 
106
static File*
107
createpath(File *f, char *name, char *u, ulong m)
108
{
109
	char *p;
110
	File *nf;
111
 
112
	if(verbose)
113
		fprint(2, "createpath %s\n", name);
114
	incref(f);
115
	while(f && (p = strchr(name, '/'))) {
116
		*p = '\0';
117
		if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
118
			/* this would be a race if we were multithreaded */
119
			incref(f);	/* so walk doesn't kill it immediately on failure */
120
			if((nf = walkfile(f, name)) == nil)
121
				nf = createfile(f, name, u, DMDIR|0777, nil);
122
			decref(f);
123
			f = nf;
124
		}
125
		*p = '/';
126
		name = p+1;
127
	}
128
	if(f == nil)
129
		return nil;
130
 
131
	incref(f);
132
	if((nf = walkfile(f, name)) == nil)
133
		nf = createfile(f, name, u, m, nil);
134
	decref(f);
135
	return nf;
136
}
137
 
138
static void
139
archcreatefile(char *name, Arch *arch, Dir *d)
140
{
141
	File *f;
142
	f = createpath(archtree->root, name, d->uid, d->mode);
143
	if(f == nil)
144
		sysfatal("creating %s: %r", name);
145
	free(f->gid);
146
	f->gid = estrdup9p(d->gid);
147
	f->aux = arch;
148
	f->mtime = d->mtime;
149
	f->length = d->length;
150
	decref(f);
151
}
152
 
153
static void
154
fsread(Req *r)
155
{
156
	Arch *a;
157
	char err[ERRMAX];
158
	int n;
159
 
160
	a = r->fid->file->aux;
161
	if(a->length <= r->ifcall.offset) 
162
		r->ifcall.count = 0;
163
	else if(a->length <= r->ifcall.offset+r->ifcall.count)
164
		r->ifcall.count = a->length - r->ifcall.offset;
165
 
166
	werrstr("unknown error");
167
	if(Bseek(b, a->off+r->ifcall.offset, 0) < 0 
168
	|| (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {
169
		err[0] = '\0';
170
		errstr(err, sizeof err);
171
		respond(r, err);
172
	} else {
173
		r->ofcall.count = n;
174
		respond(r, nil);	
175
	}
176
}
177
 
178
Srv fs = {
179
	.read=	fsread,
180
};
181
 
182
static void
183
usage(void)
184
{
185
	fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");
186
	exits("usage");
187
}
188
 
189
void
190
main(int argc, char **argv)
191
{
192
	Ahdr *a;
193
	ulong flag;
194
	char *mtpt;
195
	char err[ERRMAX];
196
 
197
	flag = 0;
198
	mtpt = "/mnt/arch";
199
	ARGBEGIN{
200
	case 'D':
201
		chatty9p++;
202
		break;
203
	case 'a':
204
		flag |= MAFTER;
205
		break;
206
	case 'b':
207
		flag |= MBEFORE;
208
		break;
209
	case 'c':
210
		flag |= MCREATE;
211
		break;
212
	case 'C':
213
		flag |= MCACHE;
214
		break;
215
	case 'm':
216
		mtpt = EARGF(usage());
217
		break;
218
	default:
219
		usage();
220
		break;
221
	}ARGEND;
222
 
223
	if(argc != 1)
224
		usage();
225
 
226
	if((b = Bopen(argv[0], OREAD)) == nil)
227
		sysfatal("open '%s': %r", argv[0]);
228
 
229
	archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);
230
	while(a = gethdr(b)) {
231
		archcreatefile(a->name, newarch(Boffset(b), a->length), a);
232
		Bseek(b, a->length, 1);
233
	}
234
 
235
	err[0] = '\0';
236
	errstr(err, sizeof err);
237
	if(err[0])
238
		sysfatal("reading archive: %s", err);
239
 
240
	postmountsrv(&fs, nil, mtpt, flag);
241
	exits(0);
242
}