changelog shortlog tags branches changeset files file revisions raw help

Mercurial > hg > plan9front / annotate sys/src/games/wadfs.c

changeset 7216: 249468ce1239
parent: 7e153241a8f6
author: cinap_lenrek@felloff.net
date: Tue, 07 May 2019 21:49:49 +0200
permissions: -rw-r--r--
description: wadfs: avoid comma operator after PBIT32() macros
qwx@6125 1
 #include <u.h>
qwx@6125 2
 #include <libc.h>
qwx@6125 3
 #include <ctype.h>
qwx@6125 4
 #include <fcall.h>
qwx@6125 5
 #include <thread.h>
qwx@6125 6
 #include <9p.h>
qwx@6125 7
 #include <bio.h>
qwx@6125 8
 
qwx@6125 9
 enum{
qwx@6125 10
 	Nsig = 4,
qwx@6125 11
 	Nhdr = Nsig+4+4,
qwx@6125 12
 	Ndict = 4+4+8,
qwx@6125 13
 	Nname = 8,
qwx@6125 14
 	Nbuf = 8192,
qwx@6125 15
 	Maxsz = 0x7fffffff - Nhdr
qwx@6125 16
 };
qwx@6125 17
 
qwx@6125 18
 enum{
qwx@6125 19
 	LTnil,
qwx@6125 20
 	LTreg,
qwx@6125 21
 	LTmap,
qwx@6125 22
 	LTmrk,
qwx@6125 23
 	LTend
qwx@6125 24
 };
qwx@6125 25
 typedef struct Lump Lump;
qwx@6125 26
 struct Lump{
qwx@6125 27
 	char name[Nname+1];
qwx@6125 28
 	u32int ofs;
qwx@6125 29
 	uchar *buf;
qwx@6125 30
 	ulong nbuf;
qwx@6125 31
 	int type;
qwx@6125 32
 	File *f;
qwx@6125 33
 	Lump *l;
qwx@6125 34
 	Lump *lp;
qwx@6125 35
 };
qwx@6125 36
 Lump l1 = {.l = &l1, .lp = &l1}, *lumps = &l1;
qwx@6125 37
 
qwx@6125 38
 Biobuf *wad;
qwx@6125 39
 u32int nlmp;
qwx@6125 40
 File *ldir, *fsig, *fwad;
qwx@6125 41
 int rdonly, dirty;
qwx@6125 42
 
qwx@6125 43
 Srv fs;
qwx@6125 44
 
qwx@6125 45
 char *mapn[] = {
qwx@6125 46
 	"things", "linedefs", "sidedefs", "vertexes", "segs",
qwx@6125 47
 	"ssectors", "nodes", "sectors", "reject", "blockmap"
qwx@6125 48
 };
qwx@6125 49
 
qwx@6125 50
 void
qwx@6125 51
 strupr(char *s, char *p)
qwx@6125 52
 {
qwx@6125 53
 	char c;
qwx@6125 54
 
qwx@6125 55
 	do{
qwx@6125 56
 		c = *p++;
qwx@6125 57
 		*s++ = toupper(c);
qwx@6125 58
 	}while(c != 0);
qwx@6125 59
 }
qwx@6125 60
 
qwx@6125 61
 void
qwx@6125 62
 strlwr(char *s, char *p)
qwx@6125 63
 {
qwx@6125 64
 	char c;
qwx@6125 65
 
qwx@6125 66
 	do{
qwx@6125 67
 		c = *p++;
qwx@6125 68
 		*s++ = tolower(c);
qwx@6125 69
 	}while(c != 0);
qwx@6125 70
 }
qwx@6125 71
 
qwx@6125 72
 void
qwx@6125 73
 link(Lump *l, Lump *lp, int len)
qwx@6125 74
 {
qwx@6125 75
 	l->lp = lp;
qwx@6125 76
 	l->l = lp->l;
qwx@6125 77
 	lp->l->lp = l;
qwx@6125 78
 	lp->l = l;
qwx@6125 79
 	nlmp++;
qwx@6125 80
 	fwad->length += Ndict + len;
qwx@6125 81
 }
qwx@6125 82
 
qwx@6125 83
 void
qwx@6125 84
 unlink(Lump *l)
qwx@6125 85
 {
qwx@6125 86
 	if(l->l == nil)
qwx@6125 87
 		return;
qwx@6125 88
 	l->lp->l = l->l;
qwx@6125 89
 	l->l->lp = l->lp;
qwx@6125 90
 	l->l = nil;
qwx@6125 91
 	nlmp--;
qwx@6125 92
 	fwad->length -= Ndict + (l->f != nil ? l->f->length : 0);
qwx@6125 93
 }
qwx@6125 94
 
qwx@6125 95
 void
qwx@6125 96
 freelump(Lump *l)
qwx@6125 97
 {
qwx@6125 98
 	unlink(l);
qwx@6125 99
 	free(l->buf);
qwx@6125 100
 	free(l);
qwx@6125 101
 }
qwx@6125 102
 
qwx@6125 103
 void
qwx@6125 104
 readlump(Lump *l, uchar *p, long n)
qwx@6125 105
 {
qwx@6125 106
 	if(n <= 0)
qwx@6125 107
 		return;
qwx@6125 108
 	Bseek(wad, l->ofs, 0);
qwx@6125 109
 	if(Bread(wad, p, n) != n)
qwx@6125 110
 		fprint(2, "readlump: short read: %r\n");
qwx@6125 111
 }
qwx@6125 112
 
qwx@6125 113
 void
qwx@6125 114
 loadlump(File *f, ulong n)
qwx@6125 115
 {
qwx@6125 116
 	Lump *l;
qwx@6125 117
 
qwx@6125 118
 	l = f->aux;
qwx@6125 119
 	if(f->length > n)
qwx@6125 120
 		n = f->length;
qwx@6125 121
 	l->buf = emalloc9p(n);
qwx@6125 122
 	l->nbuf = n;
qwx@6125 123
 	l->ofs = 0;
qwx@6125 124
 	readlump(l, l->buf, f->length);
qwx@6125 125
 }
qwx@6125 126
 
qwx@6125 127
 Lump *
qwx@6125 128
 lastlump(Lump *lp)
qwx@6125 129
 {
qwx@6125 130
 	File *f, *dir;
qwx@6125 131
 
qwx@6125 132
 	for(dir=lp->f, f=lp->l->f; lp->l!=lumps; lp=lp->l, f=lp->l->f)
qwx@6125 133
 		if(f->parent != dir && f->parent->parent != dir)
qwx@6125 134
 			break;
qwx@6125 135
 	if(lp->type == LTend && lp->f->parent == dir)
qwx@6125 136
 		lp = lp->lp;
qwx@6125 137
 	return lp;
qwx@6125 138
 }
qwx@6125 139
 
qwx@6125 140
 int
qwx@6125 141
 nextmaplump(char *s)
qwx@6125 142
 {
qwx@6125 143
 	char **p;
qwx@6125 144
 
qwx@6125 145
 	for(p=mapn; p<mapn+nelem(mapn); p++)
qwx@6125 146
 		if(strcmp(s, *p) == 0)
qwx@6125 147
 			return p-mapn;
qwx@6125 148
 	return -1;
qwx@6125 149
 }
qwx@6125 150
 
qwx@6125 151
 Lump *
qwx@6125 152
 sortmap(Lump *lp, Lump *l)
qwx@6125 153
 {
qwx@6125 154
 	int ip, i;
qwx@6125 155
 
qwx@6125 156
 	i = nextmaplump(l->f->name);
qwx@6125 157
 	for(; lp->l != lumps; lp=lp->l){
qwx@6125 158
 		ip = nextmaplump(lp->l->f->name);
qwx@6125 159
 		if(ip < 0 || ip > i)
qwx@6125 160
 			break;
qwx@6125 161
 	}
qwx@6125 162
 	return lp;
qwx@6125 163
 }
qwx@6125 164
 
qwx@6125 165
 int
qwx@6125 166
 ismaplump(char *s)
qwx@6125 167
 {
qwx@6125 168
 	return nextmaplump(s) >= 0;
qwx@6125 169
 }
qwx@6125 170
 
qwx@6125 171
 int
qwx@6125 172
 ismapname(char *s)
qwx@6125 173
 {
qwx@6125 174
 	if(strncmp(s, "map", 3) == 0)
qwx@6125 175
 		return isdigit(s[3]) && isdigit(s[4]);
qwx@6125 176
 	return s[0] == 'e' && isdigit(s[1])
qwx@6125 177
 		&& s[2] == 'm' && isdigit(s[3]);
qwx@6125 178
 }
qwx@6125 179
 
qwx@6125 180
 int
qwx@6125 181
 ismarkname(char *s, char *m)
qwx@6125 182
 {
qwx@6125 183
 	char *p;
qwx@6125 184
 
qwx@6125 185
 	p = strstr(s, m);
qwx@6125 186
 	if(p == nil || p[strlen(m)] != 0)
qwx@6125 187
 		return 0;
qwx@6125 188
 	if(p - s > 2)
qwx@6125 189
 		return 0;
qwx@6125 190
 	return 1;
qwx@6125 191
 }
qwx@6125 192
 
qwx@6125 193
 int
qwx@6125 194
 validname(char *s, File *dir, int *type, int isnew, int isdir)
qwx@6125 195
 {
qwx@6125 196
 	int n;
qwx@6125 197
 	char c, *p;
qwx@6125 198
 	Lump *lp;
qwx@6125 199
 
qwx@6125 200
 	*type = LTnil;
qwx@6125 201
 	n = strlen(s);
qwx@6125 202
 	if(n < 1 || n > sizeof(lp->name)-1){
qwx@6125 203
 		werrstr("invalid lump name");
qwx@6125 204
 		return 0;
qwx@6125 205
 	}
qwx@6125 206
 	for(p=s+n-1; c=*p, p-->=s;)
qwx@6125 207
 		if(!isprint(c) || isupper(c) || c == '/'){
qwx@6125 208
 			werrstr("invalid char %c in filename", c);
qwx@6125 209
 			return 0;
qwx@6125 210
 		}
qwx@6125 211
 	if(isnew && !ismaplump(s))
qwx@6125 212
 		for(lp=lumps->l; lp!=lumps; lp=lp->l)
qwx@6125 213
 			if(cistrcmp(s, lp->name) == 0){
qwx@6125 214
 				werrstr("duplicate non map lump");
qwx@6125 215
 				return 0;
qwx@6125 216
 			}
qwx@6125 217
 	*type = LTreg;
qwx@6125 218
 	lp = dir->aux;
qwx@6125 219
 	if(ismapname(s)){
qwx@6125 220
 		*type = LTmap;
qwx@6125 221
 		if(isnew && !isdir){
qwx@6125 222
 			werrstr("map marker not a directory");
qwx@6125 223
 			return 0;
qwx@6125 224
 		}else if(dir != fs.tree->root){
qwx@6125 225
 			werrstr("nested map directory");
qwx@6125 226
 			return 0;
qwx@6125 227
 		}
qwx@6125 228
 		return 1;
qwx@6125 229
 	}else if(ismarkname(s, "_end")){
qwx@6125 230
 		*type = LTend;
qwx@6125 231
 		if(dir == fs.tree->root || lp == nil || lp->type == LTmap){
qwx@6125 232
 			werrstr("orphaned end marker");
qwx@6125 233
 			return 0;
qwx@6125 234
 		}
qwx@6125 235
 		return 1;
qwx@6125 236
 	}else if(ismarkname(s, "_start")){
qwx@6125 237
 		*type = LTmrk;
qwx@6125 238
 		if(isnew){
qwx@6125 239
 			werrstr("not allowed");
qwx@6125 240
 			return 0;
qwx@6125 241
 		}
qwx@6125 242
 		goto mrkchk;
qwx@6125 243
 	}else if(isnew && isdir){
qwx@6125 244
 		*type = LTmrk;
qwx@6125 245
 		if(n > 2){
qwx@6125 246
 			werrstr("marker name too long");
qwx@6125 247
 			return 0;
qwx@6125 248
 		}
qwx@6125 249
 mrkchk:
qwx@6125 250
 		if(dir->parent != fs.tree->root){
qwx@6125 251
 			werrstr("start marker nested too deep");
qwx@6125 252
 			return 0;
qwx@6125 253
 		}else if(lp != nil && lp->type == LTmap){
qwx@6125 254
 			werrstr("start marker within map directory");
qwx@6125 255
 			return 0;
qwx@6125 256
 		}
qwx@6125 257
 		return 1;
qwx@6125 258
 	}else if(ismaplump(s) ^ (lp != nil && lp->type == LTmap)){
qwx@6125 259
 		werrstr("map lump outside of map directory");
qwx@6125 260
 		return 0;
qwx@6125 261
 	}
qwx@6125 262
 	return 1;
qwx@6125 263
 }
qwx@6125 264
 
qwx@6125 265
 int
qwx@6125 266
 endldir(Lump *lp, Lump *le)
qwx@6125 267
 {
qwx@6125 268
 	char *s, name[sizeof lp->name];
qwx@6125 269
 	Lump *l;
qwx@6125 270
 	File *f;
qwx@6125 271
 
qwx@6125 272
 	l = emalloc9p(sizeof *l);
qwx@6125 273
 	strcpy(l->name, lp->name);
qwx@6125 274
 	s = strrchr(l->name, '_');
qwx@6125 275
 	strcpy(s, "_END");
qwx@6125 276
 	strlwr(name, l->name);
qwx@6125 277
 	fprint(2, "adding end marker %s\n", l->name);
qwx@6125 278
 	if(!validname(name, lp->f, &l->type, 1, 0) || l->type != LTend)
qwx@6125 279
 		goto err;
qwx@6125 280
 	f = createfile(lp->f, name, nil, lp->f->mode & 0666, l);
qwx@6125 281
 	if(f == nil)
qwx@6125 282
 		goto err;
qwx@6125 283
 	closefile(f);
qwx@6125 284
 	l->f = f;
qwx@6125 285
 	link(l, le, 0);
qwx@6125 286
 	return 0;
qwx@6125 287
 err:
qwx@6125 288
 	free(l);
qwx@6125 289
 	return -1;
qwx@6125 290
 }
qwx@6125 291
 
qwx@6125 292
 void
qwx@6125 293
 accessfile(File *f, int mode)
qwx@6125 294
 {
qwx@6125 295
 	f->atime = time(nil);
qwx@6125 296
 	if(mode & AWRITE){
qwx@6125 297
 		f->mtime = f->atime;
qwx@6125 298
 		f->qid.vers++;
qwx@6125 299
 		dirty = 1;
qwx@6125 300
 	}
qwx@6125 301
 }
qwx@6125 302
 
qwx@6125 303
 void
qwx@6125 304
 fswstat(Req *r)
qwx@6125 305
 {
qwx@6125 306
 	int type;
qwx@6125 307
 	char *e;
qwx@6125 308
 	File *f, *fp;
qwx@6125 309
 	Lump *lp;
qwx@6125 310
 
qwx@6125 311
 	e = "permission denied";
qwx@6125 312
 	if(rdonly)
qwx@6125 313
 		goto err;
qwx@6125 314
 	if(r->d.mode != ~0 || r->d.gid[0] != 0)
qwx@6125 315
 		goto err;
qwx@6125 316
 	f = r->fid->file;
qwx@6125 317
 	lp = f->aux;
qwx@6125 318
 	if(r->d.length != ~0 && r->d.length != f->length){
qwx@6125 319
 		if(f == fsig || f->mode & DMDIR)
qwx@6125 320
 			goto err;
qwx@6125 321
 		if(!hasperm(f, r->fid->uid, AWRITE))
qwx@6125 322
 			goto err;
qwx@6125 323
 		if(r->d.length < 0){
qwx@6125 324
 			e = "invalid file length";
qwx@6125 325
 			goto err;
qwx@6125 326
 		}
qwx@6125 327
 		if(fwad->length - f->length + r->d.length >= Maxsz){
qwx@6125 328
 			e = "lump size exceeds wad limit";
qwx@6125 329
 			goto err;
qwx@6125 330
 		}
qwx@6125 331
 	}
qwx@6125 332
 	if(r->d.name[0] != 0 && strcmp(r->d.name, f->name) != 0){
qwx@6125 333
 		fp = f->parent;
qwx@6125 334
 		if(fp == nil){
qwx@6125 335
 			e = "orphaned file";
qwx@6125 336
 			goto err;
qwx@6125 337
 		}
qwx@6125 338
 		if(!hasperm(fp, r->fid->uid, AWRITE))
qwx@6125 339
 			goto err;
qwx@6125 340
 		if(!validname(r->d.name, fp, &type, 1, f->mode & DMDIR)){
qwx@6125 341
 			responderror(r);
qwx@6125 342
 			return;
qwx@6125 343
 		}
qwx@6125 344
 		if(lp->type != type){
qwx@6125 345
 			e = "incompatible lump type";
qwx@6125 346
 			goto err;
qwx@6125 347
 		}
qwx@6125 348
 		incref(fp);
qwx@6125 349
 		fp = walkfile(fp, r->d.name);
qwx@6125 350
 		if(fp != nil){
qwx@6125 351
 			e = "file already exists";
qwx@6125 352
 			goto err;
qwx@6125 353
 		}
qwx@6125 354
 	}
qwx@6125 355
 
qwx@6125 356
 	if(r->d.length != ~0 && r->d.length != f->length){
qwx@6125 357
 		if(lp->buf == nil)
qwx@6125 358
 			loadlump(f, r->d.length);
qwx@6125 359
 		fwad->length += r->d.length - f->length;
qwx@6125 360
 		f->length = r->d.length;
qwx@6125 361
 	}
qwx@6125 362
 	if(r->d.name[0] != 0 && strcmp(r->d.name, f->name) != 0){
qwx@6125 363
 		free(f->name);
qwx@6125 364
 		f->name = estrdup9p(r->d.name);
qwx@6125 365
 		strupr(lp->name, f->name);
qwx@6125 366
 		if(lp->type == LTmrk)
qwx@6125 367
 			strcat(lp->name, "_START");
qwx@6125 368
 	}
qwx@6125 369
 	accessfile(f, AWRITE);
qwx@6125 370
 	if(r->d.mtime != ~0)
qwx@6125 371
 		f->mtime = r->d.mtime;
qwx@6125 372
 	respond(r, nil);
qwx@6125 373
 	return;
qwx@6125 374
 err:
qwx@6125 375
 	respond(r, e);
qwx@6125 376
 }
qwx@6125 377
 
qwx@6125 378
 void
qwx@6125 379
 fsremove(Req *r)
qwx@6125 380
 {
qwx@6125 381
 	File *f;
qwx@6125 382
 	Lump *lp;
qwx@6125 383
 
qwx@6125 384
 	f = r->fid->file;
qwx@6125 385
 	lp = f->aux;
qwx@6125 386
 	if(f == fsig || f == fwad){
qwx@6125 387
 		respond(r, "not allowed");
qwx@6125 388
 		return;
qwx@6125 389
 	}else if(lp->l->f != nil && lp->l->f->parent == f){
qwx@6125 390
 		respond(r, "has children");
qwx@6125 391
 		return;
qwx@6125 392
 	}
qwx@6125 393
 	unlink(f->aux);
qwx@6125 394
 	dirty = 1;
qwx@6125 395
 	respond(r, nil);
qwx@6125 396
 }
qwx@6125 397
 
qwx@6125 398
 char *
qwx@6125 399
 writesig(uchar *buf, char *s, vlong n)
qwx@6125 400
 {
qwx@6125 401
 	if(n > Nsig+1 || strncmp(s, "IWAD", Nsig) != 0 && strncmp(s, "PWAD", Nsig) != 0)
qwx@6125 402
 		return "invalid wad signature";
qwx@6125 403
 	memcpy(buf, s, Nsig);
qwx@6125 404
 	dirty = 1;
qwx@6125 405
 	return nil;
qwx@6125 406
 }
qwx@6125 407
 
qwx@6125 408
 void
qwx@6125 409
 fswrite(Req *r)
qwx@6125 410
 {
qwx@6125 411
 	vlong n, m, ofs, end;
qwx@6125 412
 	File *f;
qwx@6125 413
 	Lump *l;
qwx@6125 414
 
qwx@6125 415
 	f = r->fid->file;
qwx@6125 416
 	n = r->ifcall.count;
qwx@6125 417
 	ofs = r->ifcall.offset;
qwx@6125 418
 	if(f->mode & DMAPPEND)
qwx@6125 419
 		ofs = f->length;
qwx@6125 420
 	end = ofs + n;
qwx@6125 421
 	l = f->aux;
qwx@6125 422
 	if(f == fsig){
qwx@6125 423
 		respond(r, writesig(l->buf, r->ifcall.data, n));
qwx@6125 424
 		return;
qwx@6125 425
 	}
qwx@6125 426
 	if(l->buf == nil)
qwx@6125 427
 		loadlump(f, end + Nbuf);
qwx@6125 428
 	if(end > l->nbuf){
qwx@6125 429
 		m = l->nbuf + Nbuf > end ? l->nbuf + Nbuf : end;
qwx@6125 430
 		if(fwad->length - l->nbuf + m >= Maxsz){
qwx@6125 431
 			respond(r, "lump size exceeds wad limit");
qwx@6125 432
 			return;
qwx@6125 433
 		}
qwx@6125 434
 		l->buf = erealloc9p(l->buf, m);
qwx@6125 435
 		l->nbuf = m;
qwx@6125 436
 	}
qwx@6125 437
 	memcpy(l->buf + ofs, r->ifcall.data, n);
qwx@6125 438
 	m = end - f->length;
qwx@6125 439
 	if(m > 0){
qwx@6125 440
 		f->length += m;
qwx@6125 441
 		fwad->length += m;
qwx@6125 442
 	}
qwx@6125 443
 	accessfile(f, AWRITE);
qwx@6125 444
 	r->ofcall.count = n;
qwx@6125 445
 	respond(r, nil);
qwx@6125 446
 }
qwx@6125 447
 
qwx@6125 448
 void
qwx@6125 449
 makewad(void)
qwx@6125 450
 {
qwx@6125 451
 	vlong n;
qwx@6125 452
 	uchar *p;
qwx@6125 453
 	u32int ofs;
qwx@6125 454
 	Lump *l, *lp;
qwx@6125 455
 
qwx@6125 456
 	l = fwad->aux;
qwx@6125 457
 	free(l->buf);
qwx@6125 458
 	l->buf = emalloc9p(fwad->length);
qwx@6125 459
 	p = l->buf;
qwx@6125 460
 	lp = fsig->aux;
qwx@6125 461
 	memcpy(p, lp->buf, 4), p += 4;
cinap_lenrek@7216 462
 	PBIT32(p, nlmp);
cinap_lenrek@7216 463
 	p += 8;
qwx@6125 464
 	for(lp=lumps->l; lp!=lumps; p+=n, lp=lp->l){
qwx@6125 465
 		n = lp->f->length;
qwx@6125 466
 		if(lp->buf != nil)
qwx@6125 467
 			memcpy(p, lp->buf, n);
qwx@6125 468
 		else
qwx@6125 469
 			readlump(lp, p, n);
qwx@6125 470
 	}
qwx@6125 471
 	PBIT32(l->buf + 8, p - l->buf);
qwx@6125 472
 	ofs = Nhdr;
qwx@6125 473
 	for(lp=lumps->l; lp!=lumps; ofs+=n, lp=lp->l){
qwx@6125 474
 		n = lp->f->length;
cinap_lenrek@7216 475
 		PBIT32(p, ofs);
cinap_lenrek@7216 476
 		p += 4;
cinap_lenrek@7216 477
 		PBIT32(p, n);
cinap_lenrek@7216 478
 		p += 4;
qwx@6125 479
 		memcpy(p, lp->name, 8), p += 8;
qwx@6125 480
 	}
qwx@6125 481
 	dirty = 0;
qwx@6125 482
 }
qwx@6125 483
 
qwx@6125 484
 void
qwx@6125 485
 fsread(Req *r)
qwx@6125 486
 {
qwx@6125 487
 	vlong n, ofs, end;
qwx@6125 488
 	File *f;
qwx@6125 489
 	Lump *l;
qwx@6125 490
 
qwx@6125 491
 	f = r->fid->file;
qwx@6125 492
 	l = f->aux;
qwx@6125 493
 	ofs = r->ifcall.offset + l->ofs;
qwx@6125 494
 	end = l->ofs + f->length;
qwx@6125 495
 	n = r->ifcall.count;
qwx@6125 496
 	if(ofs + n >= end)
qwx@6125 497
 		n = end - ofs;
qwx@6125 498
 	if(n <= 0){
qwx@6125 499
 		r->ofcall.count = 0;
qwx@6125 500
 		respond(r, nil);
qwx@6125 501
 		return;
qwx@6125 502
 	}
qwx@6125 503
 	if(f == fwad && dirty)
qwx@6125 504
 		makewad();
qwx@6125 505
 	if(l->buf != nil)
qwx@6125 506
 		memcpy(r->ofcall.data, l->buf+ofs, n);
qwx@6125 507
 	else{
qwx@6125 508
 		Bseek(wad, ofs, 0);
qwx@6125 509
 		n = Bread(wad, r->ofcall.data, n);
qwx@6125 510
 		if(n < 0){
qwx@6125 511
 			responderror(r);
qwx@6125 512
 			return;
qwx@6125 513
 		}
qwx@6125 514
 	}
qwx@6125 515
 	accessfile(f, AREAD);
qwx@6125 516
 	r->ofcall.count = n;
qwx@6125 517
 	respond(r, nil);
qwx@6125 518
 }
qwx@6125 519
 
qwx@6125 520
 int
qwx@6125 521
 addlump(Lump *l, File *dir)
qwx@6125 522
 {
qwx@6125 523
 	Lump *lp;
qwx@6125 524
 
qwx@6125 525
 	lp = lumps->lp;
qwx@6125 526
 	if(dir != fs.tree->root){
qwx@6125 527
 		lp = dir->aux;
qwx@6125 528
 		lp = lp->type == LTmap ? sortmap(lp, l) : lastlump(lp);
qwx@6125 529
 	}
qwx@6125 530
 	if(l->type == LTend && lp->l->type == LTend && lp->l->f->parent == dir){
qwx@6125 531
 		werrstr("an end marker already exists");
qwx@6125 532
 		return -1;
qwx@6125 533
 	}
qwx@6125 534
 	link(l, lp, 0);
qwx@6125 535
 	if(l->type == LTmrk){
qwx@6125 536
 		strcat(l->name, "_START");
qwx@6125 537
 		if(endldir(l, l) < 0)
qwx@6125 538
 			return -1;
qwx@6125 539
 	}else if(l->type == LTreg){
qwx@6125 540
 		l->buf = emalloc9p(Nbuf);
qwx@6125 541
 		l->nbuf = Nbuf;
qwx@6125 542
 	}
qwx@6125 543
 	dirty = 1;
qwx@6125 544
 	return 0;
qwx@6125 545
 }
qwx@6125 546
 
qwx@6125 547
 Lump *
qwx@6125 548
 createlump(char *s, File *dir, int ismark)
qwx@6125 549
 {
qwx@6125 550
 	int type;
qwx@6125 551
 	Lump *l;
qwx@6125 552
 
qwx@6125 553
 	if(!validname(s, dir, &type, 1, ismark))
qwx@6125 554
 		return nil;
qwx@6125 555
 	l = emalloc9p(sizeof *l);
qwx@6125 556
 	l->type = type;
qwx@6125 557
 	strupr(l->name, s);
qwx@6125 558
 	return l;
qwx@6125 559
 }
qwx@6125 560
 
qwx@6125 561
 void
qwx@6125 562
 fscreate(Req *r)
qwx@6125 563
 {
qwx@6125 564
 	int p;
qwx@6125 565
 	File *f;
qwx@6125 566
 	Lump *l;
qwx@6125 567
 
qwx@6125 568
 	f = r->fid->file;
qwx@6125 569
 	p = r->ifcall.perm;
qwx@6125 570
 	if(p & DMDIR)
qwx@6125 571
 		p = p & ~0777 | p & f->mode & 0777;
qwx@6125 572
 	else
qwx@6125 573
 		p = p & ~0666 | p & f->mode & 0666;
qwx@6125 574
 	l = createlump(r->ifcall.name, f, p & DMDIR);
qwx@6125 575
 	if(l == nil)
qwx@6125 576
 		goto err;
qwx@6125 577
 	f = createfile(f, r->ifcall.name, r->fid->uid, p, l);
qwx@6125 578
 	if(f == nil){
qwx@6125 579
 		free(l);
qwx@6125 580
 		goto err;
qwx@6125 581
 	}
qwx@6125 582
 	l->f = f;
qwx@6125 583
 	if(addlump(l, r->fid->file) < 0){
qwx@6125 584
 		removefile(f);
qwx@6125 585
 		goto err;
qwx@6125 586
 	}
qwx@6125 587
 	r->fid->file = f;
qwx@6125 588
 	r->ofcall.qid = f->qid;
qwx@6125 589
 	respond(r, nil);
qwx@6125 590
 	return;
qwx@6125 591
 err:
qwx@6125 592
 	responderror(r);
qwx@6125 593
 }
qwx@6125 594
 
qwx@6125 595
 void
qwx@6125 596
 fsopen(Req *r)
qwx@6125 597
 {
qwx@6125 598
 	File *f;
qwx@6125 599
 
qwx@6125 600
 	f = r->fid->file;
qwx@6125 601
 	if((f->mode & DMAPPEND) == 0 && (r->ifcall.mode & OTRUNC) != 0
qwx@6125 602
 	&& f != fsig){
qwx@6125 603
 		fwad->length -= f->length;
qwx@6125 604
 		f->length = 0;
qwx@6125 605
 		dirty = 1;
qwx@6125 606
 	}
qwx@6125 607
 	respond(r, nil);
qwx@6125 608
 }
qwx@6125 609
 
qwx@6125 610
 void
qwx@6125 611
 fsdestroyfile(File *f)
qwx@6125 612
 {
qwx@6125 613
 	freelump(f->aux);
qwx@6125 614
 }
qwx@6125 615
 
qwx@6125 616
 Srv fs = {
qwx@6125 617
 	.open = fsopen,
qwx@6125 618
 	.create = fscreate,
qwx@6125 619
 	.read = fsread,
qwx@6125 620
 	.write = fswrite,
qwx@6125 621
 	.remove = fsremove,
qwx@6125 622
 	.wstat = fswstat
qwx@6125 623
 };
qwx@6125 624
 
qwx@6125 625
 int
qwx@6125 626
 get32(Biobuf *bf, u32int *v)
qwx@6125 627
 {
qwx@6125 628
 	int n;
qwx@6125 629
 	uchar u[4];
qwx@6125 630
 
qwx@6125 631
 	n = Bread(bf, u, sizeof u);
qwx@6125 632
 	if(n != sizeof u)
qwx@6125 633
 		return -1;
qwx@6125 634
 	*v = GBIT32(u);
qwx@6125 635
 	return 0;
qwx@6125 636
 }
qwx@6125 637
 
qwx@6125 638
 File *
qwx@6125 639
 replacefile(File *dir, char *fname, int mode, Lump *l)
qwx@6125 640
 {
qwx@6125 641
 	File *f;
qwx@6125 642
 
qwx@6125 643
 	incref(dir);
qwx@6125 644
 	f = walkfile(dir, fname);
qwx@6125 645
 	if(f == nil)
qwx@6125 646
 		return nil;
qwx@6125 647
 	if(removefile(f) < 0)
qwx@6125 648
 		return nil;
qwx@6125 649
 	f = createfile(dir, fname, nil, mode, l);
qwx@6125 650
 	return f;
qwx@6125 651
 }
qwx@6125 652
 
qwx@6125 653
 void
qwx@6125 654
 addsigfile(char *sig)
qwx@6125 655
 {
qwx@6125 656
 	int n;
qwx@6125 657
 	Lump *l;
qwx@6125 658
 	File *f;
qwx@6125 659
 
qwx@6125 660
 	n = strlen(sig) + 1;
qwx@6125 661
 	l = emalloc9p(sizeof *l);
qwx@6125 662
 	l->buf = (uchar *)estrdup9p(sig);
qwx@6125 663
 	l->buf[n-1] = '\n';
qwx@6125 664
 	f = createfile(fs.tree->root, "SIG", nil, rdonly ? 0444 : 0666, l);
qwx@6125 665
 	if(f == nil)
qwx@6125 666
 		sysfatal("addsigfile: %r");
qwx@6125 667
 	else{
qwx@6125 668
 		fsig = f;
qwx@6125 669
 		f->length = n;
qwx@6125 670
 	}
qwx@6125 671
 }
qwx@6125 672
 
qwx@6125 673
 void
qwx@6125 674
 addwadfile(void)
qwx@6125 675
 {
qwx@6125 676
 	Lump *l;
qwx@6125 677
 	File *f;
qwx@6125 678
 
qwx@6125 679
 	l = emalloc9p(sizeof *l);
qwx@6125 680
 	f = createfile(fs.tree->root, "WAD", nil, 0444, l);
qwx@6125 681
 	if(f == nil)
qwx@6125 682
 		sysfatal("addwadfile: %r");
qwx@6125 683
 	else{
qwx@6125 684
 		fwad = f;
qwx@6125 685
 		f->length = Nhdr;
qwx@6125 686
 	}
qwx@6125 687
 	dirty++;
qwx@6125 688
 
qwx@6125 689
 }
qwx@6125 690
 
qwx@6125 691
 void
qwx@6125 692
 checkends(void)
qwx@6125 693
 {
qwx@6125 694
 	Lump *lp;
qwx@6125 695
 
qwx@6125 696
 	if(ldir == fs.tree->root)
qwx@6125 697
 		return;
qwx@6125 698
 	lp = ldir->aux;
qwx@6125 699
 	if(lp->type != LTmap && endldir(lp, lastlump(lp)) < 0)
qwx@6125 700
 		fprint(2, "checkends: %r\n");
qwx@6125 701
 	ldir = ldir->parent;
qwx@6125 702
 	checkends();
qwx@6125 703
 }
qwx@6125 704
 
qwx@6125 705
 int
qwx@6125 706
 addfile(Lump *l, u32int *len, int mode)
qwx@6125 707
 {
qwx@6125 708
 	int err;
qwx@6125 709
 	char fname[sizeof l->name], *s;
qwx@6125 710
 	Lump *lp;
qwx@6125 711
 	File *f;
qwx@6125 712
 
qwx@6125 713
 	*len = 0;
qwx@6125 714
 	if(get32(wad, &l->ofs) < 0 || get32(wad, len) < 0)
qwx@6125 715
 		return -1;
qwx@6125 716
 	if(Bread(wad, l->name, sizeof(l->name)-1) != sizeof(l->name)-1)
qwx@6125 717
 		return -1;
qwx@6125 718
 	strlwr(fname, l->name);
qwx@6125 719
 
qwx@6125 720
 	lp = ldir->aux;
qwx@6125 721
 	err = !validname(fname, ldir, &l->type, 0, 0);
qwx@6125 722
 	switch(l->type){
qwx@6125 723
 	case LTmap:
qwx@6125 724
 		closefile(ldir);
qwx@6125 725
 		ldir = fs.tree->root;
qwx@6125 726
 		if(err && lp != nil && lp->type != LTmap){
qwx@6125 727
 			fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
qwx@6125 728
 			if(endldir(lp, lastlump(lp)) < 0)
qwx@6125 729
 				fprint(2, "endldir: %r\n");
qwx@6125 730
 		}
qwx@6125 731
 		mode |= DMDIR|0111;
qwx@6125 732
 		*len = 0;
qwx@6125 733
 		break;
qwx@6125 734
 	case LTmrk:
qwx@6125 735
 		if(err){
qwx@6125 736
 			if(lp != nil && lp->type == LTmap){
qwx@6125 737
 				closefile(ldir);
qwx@6125 738
 				ldir = fs.tree->root;
qwx@6125 739
 			}else{
qwx@6125 740
 				fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
qwx@6125 741
 				if(endldir(lp, lastlump(lp)) < 0)
qwx@6125 742
 					return -1;
qwx@6125 743
 				ldir = ldir->parent;
qwx@6125 744
 			}
qwx@6125 745
 		}
qwx@6125 746
 		s = strrchr(fname, '_');
qwx@6125 747
 		*s = 0;
qwx@6125 748
 		mode |= DMDIR|0111;
qwx@6125 749
 		*len = 0;
qwx@6125 750
 		break;
qwx@6125 751
 	case LTend:
qwx@6125 752
 		if(err){
qwx@6125 753
 			ldir = ldir->parent;
qwx@6125 754
 			return -1;
qwx@6125 755
 		}
qwx@6125 756
 		*len = 0;
qwx@6125 757
 		break;
qwx@6125 758
 	case LTreg:
qwx@6125 759
 		if(err){
qwx@6125 760
 			if(ismaplump(fname))
qwx@6125 761
 				fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
qwx@6125 762
 			else
qwx@6125 763
 				ldir = fs.tree->root;
qwx@6125 764
 		}
qwx@6125 765
 		break;
qwx@6125 766
 	default:
qwx@6125 767
 		return -1;
qwx@6125 768
 	}
qwx@6125 769
 
qwx@6125 770
 	f = createfile(ldir, fname, nil, mode, l);
qwx@6125 771
 	if(f == nil){
qwx@6125 772
 		fprint(2, "createfile %s: %r\n", l->name);
qwx@6125 773
 		if(mode & DMDIR)
qwx@6125 774
 			return -1;
qwx@6125 775
 		f = replacefile(ldir, fname, mode, l);
qwx@6125 776
 		if(f == nil)
qwx@6125 777
 			return -1;
qwx@6125 778
 	}
qwx@6125 779
 	if(mode & DMDIR)
qwx@6125 780
 		ldir = f;
qwx@6125 781
 	else if(l->type == LTend)
qwx@6125 782
 		ldir = ldir->parent;
qwx@6125 783
 	else
qwx@6125 784
 		closefile(f);
qwx@6125 785
 	f->length = *len;
qwx@6125 786
 	l->f = f;
qwx@6125 787
 	return 0;
qwx@6125 788
 }
qwx@6125 789
 
qwx@6125 790
 void
qwx@6125 791
 parsewad(void)
qwx@6125 792
 {
qwx@6125 793
 	int n, ne, mode;
qwx@6125 794
 	u32int len;
qwx@6125 795
 	Lump *l;
qwx@6125 796
 
qwx@6125 797
 	mode = rdonly ? 0444 : 0666;
qwx@6125 798
 	ldir = fs.tree->root;
qwx@6125 799
 	for(n=0, ne=nlmp, nlmp=0; n<ne; n++){
qwx@6125 800
 		l = emalloc9p(sizeof *l);
qwx@6125 801
 		if(addfile(l, &len, mode) < 0){
qwx@6125 802
 			fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, len);
qwx@6125 803
 			free(l);
qwx@6125 804
 			continue;
qwx@6125 805
 		}
qwx@6125 806
 		link(l, lumps->lp, len);
qwx@6125 807
 	}
qwx@6125 808
 	checkends();
qwx@6125 809
 }
qwx@6125 810
 
qwx@6125 811
 void
qwx@6125 812
 wadinfo(char *sig)
qwx@6125 813
 {
qwx@6125 814
 	int n;
qwx@6125 815
 	u32int dictofs;
qwx@6125 816
 
qwx@6125 817
 	n = Bread(wad, sig, Nsig);
qwx@6125 818
 	if(n != Nsig)
qwx@6125 819
 		sysfatal("readwad: short read: %r");
qwx@6125 820
 	sig[4] = 0;
qwx@6125 821
 	if(strcmp(sig, "IWAD") != 0 && strcmp(sig, "PWAD") != 0)
qwx@6125 822
 		sysfatal("invalid wad signature");
qwx@6125 823
 	if(get32(wad, &nlmp) < 0 || get32(wad, &dictofs) < 0)
qwx@6125 824
 		sysfatal("wadinfo: %r");
qwx@6125 825
 	Bseek(wad, dictofs, 0);
qwx@6125 826
 }
qwx@6125 827
 
qwx@6125 828
 void
qwx@6125 829
 usage(void)
qwx@6125 830
 {
qwx@6125 831
 	fprint(2, "usage: %s [-Dr] [-m mtpt] [-S srvname] [wad]\n", argv0);
qwx@6125 832
 	exits("usage");
qwx@6125 833
 }
qwx@6125 834
 
qwx@6125 835
 void
qwx@6125 836
 main(int argc, char **argv)
qwx@6125 837
 {
qwx@6125 838
 	int fl, p;
qwx@6125 839
 	char *mtpt, *srvname, sig[Nsig+1] = "PWAD";
qwx@6125 840
 
qwx@6125 841
 	mtpt = "/mnt/wad";
qwx@6125 842
 	srvname = nil;
qwx@6125 843
 	fl = MREPL|MCREATE;
qwx@6125 844
 	p = DMDIR|0777;
qwx@6125 845
 	ARGBEGIN{
qwx@6125 846
 	case 'D': chatty9p++; break;
qwx@6125 847
 	case 'S': srvname = EARGF(usage()); break;
qwx@6125 848
 	case 'm': mtpt = EARGF(usage()); break;
qwx@6125 849
 	case 'r': rdonly++; p &= ~0222; fl &= ~MCREATE; break;
qwx@6125 850
 	default: usage();
qwx@6125 851
 	}ARGEND
qwx@6125 852
 	if(*argv != nil){
qwx@6125 853
 		wad = Bopen(*argv, OREAD);
qwx@6125 854
 		if(wad == nil)
qwx@6125 855
 			sysfatal("Bopen: %r");
qwx@6125 856
 		wadinfo(sig);
qwx@6125 857
 	}
qwx@6125 858
 	fs.tree = alloctree(nil, nil, p, fsdestroyfile);
qwx@6125 859
 	addsigfile(sig);
qwx@6125 860
 	addwadfile();
qwx@6125 861
 	parsewad();
qwx@6125 862
 	postmountsrv(&fs, srvname, mtpt, fl);
qwx@6125 863
 	exits(nil);
qwx@6125 864
 }