Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include <libsec.h>
6
#include "9p1.h"
7
 
8
char	*user;
9
int	newfd;
10
int	roldfd;
11
int	woldfd;
12
int	debug;
13
int	dofcall;
14
QLock	servelock;
15
QLock	fidlock;
16
QLock	taglock;
17
int	mainpid;
18
int	ntag;
19
int	nfork;
20
char FLUSHED[] = "FLUSHED";
21
 
22
enum{
23
	Maxfdata = 8192
24
};
25
 
26
enum{
27
	Command,
28
	Network,
29
	File,
30
	Stdio,
31
};
32
 
33
typedef struct Tag Tag;
34
struct Tag
35
{
36
	int	tag;
37
	int	flushed;
38
	int	received;
39
	int	ref;
40
	Tag	*next;
41
};
42
 
43
typedef struct Message Message;
44
struct Message
45
{
46
	char	*data;
47
	int	n;
48
};
49
 
50
typedef struct Fid Fid;
51
 
52
struct Fid
53
{
54
	short	busy;
55
	short	allocated;
56
	int	fid;
57
	Qid	qid;
58
	ulong	newoffset;
59
	ulong	oldoffset;
60
	Fid	*next;
61
};
62
 
63
Fid	*fids;
64
Tag	*tags;
65
 
66
char	*rflush(Fcall*, Fcall*, char*),
67
	*rversion(Fcall*, Fcall*, char*),
68
	*rauth(Fcall*, Fcall*, char*),
69
	*rattach(Fcall*, Fcall*, char*),
70
	*rwalk(Fcall*, Fcall*, char*),
71
	*ropen(Fcall*, Fcall*, char*),
72
	*rcreate(Fcall*, Fcall*, char*),
73
	*rread(Fcall*, Fcall*, char*),
74
	*rwrite(Fcall*, Fcall*, char*),
75
	*rclunk(Fcall*, Fcall*, char*),
76
	*rremove(Fcall*, Fcall*, char*),
77
	*rstat(Fcall*, Fcall*, char*),
78
	*rwstat(Fcall*, Fcall*, char*);
79
 
80
char 	*(*fcalls[])(Fcall*, Fcall*, char*) = {
81
	[Tversion]	rversion,
82
	[Tflush]	rflush,
83
	[Tauth]	rauth,
84
	[Tattach]	rattach,
85
	[Twalk]		rwalk,
86
	[Topen]		ropen,
87
	[Tcreate]	rcreate,
88
	[Tread]		rread,
89
	[Twrite]	rwrite,
90
	[Tclunk]	rclunk,
91
	[Tremove]	rremove,
92
	[Tstat]		rstat,
93
	[Twstat]	rwstat,
94
};
95
 
96
char Etoolong[] = "name too long";
97
 
98
void	connect(int, char*);
99
void	post(int, char*);
100
void	serve(void);
101
void	demux(void);
102
void*	emalloc(ulong);
103
char*	transact9p1(Fcall9p1*, Fcall9p1*, char*);
104
Fid*	newfid(int);
105
 
106
struct
107
{
108
	char	chal[CHALLEN];		/* my challenge */
109
	char	rchal[CHALLEN];		/* his challenge */
110
	char	authid[NAMEREC];
111
	char	authdom[DOMLEN];
112
	int	id;
113
} ai;
114
 
115
void
116
usage(void)
117
{
118
	fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n");
119
	exits("usage");
120
}
121
 
122
void
123
main(int argc, char *argv[])
124
{
125
	int method;
126
	char *oldstring;
127
	char *mountpoint, *postname;
128
	int mountflag, mountfd;
129
	int p[2];
130
int i;
131
 
132
	fmtinstall('F', fcallfmt);
133
	fmtinstall('G', fcallfmt9p1);
134
	fmtinstall('D', dirfmt);
135
 
136
	user = getuser();
137
	mountpoint = nil;
138
	mountflag = 0;
139
	postname = nil;
140
	oldstring = nil;
141
	method = -1;
142
	mountfd = -1;
143
 
144
	ARGBEGIN{
145
	case 'a':
146
		mountflag |= MAFTER;
147
		break;
148
	case 'b':
149
		mountflag |= MBEFORE;
150
		break;
151
	case 'c':
152
		mountflag |= MCREATE;
153
		break;
154
	case 'C':
155
		mountflag |= MCACHE;
156
		break;
157
	case 'd':
158
		debug++;
159
		break;
160
	case 'f':
161
		method = File;
162
		oldstring = ARGF();
163
		break;
164
	case 'F':
165
		dofcall++;
166
		break;
167
	case 'm':
168
		mountpoint = EARGF(usage());
169
		break;
170
	case 'n':
171
		method = Network;
172
		oldstring = ARGF();
173
		break;
174
	case 'p':
175
		postname = ARGF();
176
		if(postname == nil)
177
			usage();
178
		break;
179
	case 's':
180
		method = Stdio;
181
		break;
182
	case 'u':
183
		user = EARGF(usage());
184
		break;
185
	case 'x':
186
		method = Command;
187
		oldstring = ARGF();
188
		break;
189
	default:
190
		usage();
191
	}ARGEND;
192
 
193
	if(method == Stdio){
194
		if(mountpoint!=nil || argc!=0)
195
			usage();
196
	}else{
197
		if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil))
198
			usage();
199
	}
200
 
201
	rfork(RFNOTEG|RFREND);
202
 
203
	connect(method, oldstring);
204
 
205
	if(method == Stdio)
206
		newfd = 0;
207
	else{
208
		if(pipe(p) < 0)
209
			fatal("pipe: %r");
210
		if(postname != nil)
211
			post(p[0], postname);
212
		mountfd = p[0];
213
		newfd = p[1];
214
	}
215
	if(debug)
216
		fprint(2, "connected and posted\n");
217
 
218
	switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){
219
	case 0:
220
		mainpid = getpid();
221
		/* child does all the work */
222
		if(mountfd >= 0)
223
			close(mountfd);
224
		switch(rfork(RFPROC|RFMEM|RFFDG)){
225
		case 0:
226
			for(i = 0; i < 20; i++)
227
				if (i != roldfd) close(i);
228
			demux();
229
			return;
230
		case -1:
231
			fatal("fork error: %r");
232
			break;
233
		}
234
		for(i = 0; i < 20; i++)
235
			if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i);
236
		serve();
237
		break;
238
	case -1:
239
		fatal("fork error: %r");
240
		break;
241
	default:
242
		/* parent mounts if required, then exits */
243
		if(mountpoint){
244
			if(mount(mountfd, -1, mountpoint, mountflag, "") < 0)
245
				fatal("can't mount: %r");
246
		}
247
		break;
248
	}
249
	exits(nil);
250
}
251
 
252
void
253
connect(int method, char *oldstring)
254
{
255
	char *s;
256
	char dir[256];
257
 
258
	switch(method){
259
	default:
260
		roldfd = -1;
261
		woldfd = -1;
262
		fatal("can't handle method type %d", method);
263
		break;
264
	case Network:
265
		s = netmkaddr(oldstring, 0, "9fs");
266
		roldfd = dial(s, 0, dir, 0);
267
		if(roldfd < 0)
268
			fatal("dial %s: %r", s);
269
		woldfd = roldfd;
270
		if(dofcall)
271
			roldfd = fcall(woldfd);
272
		break;
273
	case File:
274
		roldfd = open(oldstring, ORDWR);
275
		if(roldfd < 0)
276
			fatal("can't open %s: %r", oldstring);
277
		woldfd = roldfd;
278
		if(dofcall)
279
			roldfd = fcall(woldfd);
280
		break;
281
	case Stdio:
282
		roldfd = fcall(1);
283
		woldfd = 1;
284
		break;
285
	}
286
}
287
 
288
void
289
post(int fd, char *srv)
290
{
291
	int f;
292
	char buf[128];
293
 
294
	snprint(buf, sizeof buf, "/srv/%s", srv);
295
	f = create(buf, OWRITE, 0666);
296
	if(f < 0)
297
		fatal("can't create %s: %r", buf);
298
	sprint(buf, "%d", fd);
299
	if(write(f, buf, strlen(buf)) != strlen(buf))
300
		fatal("post write: %r");
301
	close(f);
302
}
303
 
304
Fid *
305
newfid(int fid)
306
{
307
	Fid *f, *ff;
308
 
309
	ff = 0;
310
	qlock(&fidlock);
311
	for(f = fids; f; f = f->next)
312
		if(f->fid == fid){
313
			f->allocated = 1;
314
			qunlock(&fidlock);
315
			return f;
316
		}
317
		else if(!ff && !f->allocated)
318
			ff = f;
319
	if(ff){
320
		ff->fid = fid;
321
		ff->allocated = 1;
322
		qunlock(&fidlock);
323
		return ff;
324
	}
325
	f = emalloc(sizeof *f);
326
	f->fid = fid;
327
	f->next = fids;
328
	f->allocated = 1;
329
	fids = f;
330
	qunlock(&fidlock);
331
	return f;
332
}
333
 
334
/*
335
 * Reads returning 9P1 messages and demultiplexes them.
336
 * BUG: assumes one read per message.
337
 */
338
void
339
demux(void)
340
{
341
	int m, n;
342
	char *data;
343
	Fcall9p1 r;
344
	Message *msg;
345
	Tag *t;
346
 
347
	for(;;){
348
		data = malloc(IOHDRSZ+Maxfdata);	/* no need to clear memory */
349
		if(data == nil)
350
			fatal("demux malloc: %r");
351
		m = read(roldfd, data, IOHDRSZ+Maxfdata);
352
		if(m <= 0)
353
			fatal("read error talking to old system: %r");
354
		n = convM2S9p1(data, &r, m);
355
		if(n == 0)
356
			fatal("bad conversion receiving from old system");
357
		if(debug)
358
			fprint(2, "srvold9p:<=%G\n", &r);
359
		qlock(&taglock);
360
		for(t=tags; t!=nil; t=t->next)
361
			if(t->tag == r.tag){
362
				t->received = 1;
363
				break;
364
			}
365
		qunlock(&taglock);
366
		/*
367
		 * Fcall9p1 tag is used to rendezvous.
368
		 * Recipient converts message a second time, but that's OK.
369
		 */
370
		msg = emalloc(sizeof(Message));
371
		msg->data = data;
372
		msg->n = n;
373
		rendezvous((void*)r.tag, msg);
374
	}
375
}
376
 
377
Tag*
378
newtag(int tag)
379
{
380
	Tag *t;
381
 
382
	t = emalloc(sizeof(Tag));
383
	t->tag = tag;
384
	t->flushed = 0;
385
	t->received = 0;
386
	t->ref = 1;
387
	qlock(&taglock);
388
	t->next = tags;
389
	tags = t;
390
	qunlock(&taglock);
391
	return t;
392
}
393
 
394
void
395
freetag(Tag *tag)	/* called with taglock set */
396
{
397
	Tag *t, *prev;
398
 
399
	if(tag->ref-- == 1){
400
		prev = nil;
401
		for(t=tags; t!=nil; t=t->next){
402
			if(t == tag){
403
				if(prev == nil)
404
					tags = t->next;
405
				else
406
					prev->next = t->next;
407
				break;
408
			}
409
			prev = t;
410
		}
411
		if(t == nil)
412
			sysfatal("freetag");
413
		free(tag);
414
	}
415
}
416
 
417
void
418
serve(void)
419
{
420
	char *err;
421
	int n;
422
	Fcall thdr;
423
	Fcall	rhdr;
424
	uchar mdata[IOHDRSZ+Maxfdata];
425
	char mdata9p1[IOHDRSZ+Maxfdata];
426
	Tag *tag;
427
 
428
	for(;;){
429
		qlock(&servelock);
430
		for(;;){
431
			n = read9pmsg(newfd, mdata, sizeof mdata);
432
 
433
			if(n == 0)
434
				continue;
435
			if(n < 0)
436
				break;
437
			if(n > 0 && convM2S(mdata, n, &thdr) > 0)
438
				break;
439
		}
440
		if(n>0 && servelock.head==nil)	/* no other processes waiting to read */
441
			switch(rfork(RFPROC|RFMEM)){
442
			case 0:
443
				/* child starts serving */
444
				continue;
445
				break;
446
			case -1:
447
				fatal("fork error: %r");
448
				break;
449
			default:
450
				break;
451
			}
452
		qunlock(&servelock);
453
 
454
		if(n < 0)
455
			fatal(nil);	/* exit quietly; remote end has just hung up */
456
 
457
		if(debug)
458
			fprint(2, "srvold9p:<-%F\n", &thdr);
459
 
460
		tag = newtag(thdr.tag);
461
 
462
		if(!fcalls[thdr.type])
463
			err = "bad fcall type";
464
		else
465
			err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1);
466
 
467
		qlock(&taglock);
468
		if(tag->flushed){
469
			freetag(tag);
470
			qunlock(&taglock);
471
			continue;
472
		}
473
		qunlock(&taglock);
474
 
475
		if(err){
476
			rhdr.type = Rerror;
477
			rhdr.ename = err;
478
		}else{
479
			rhdr.type = thdr.type + 1;
480
			rhdr.fid = thdr.fid;
481
		}
482
		rhdr.tag = thdr.tag;
483
		if(debug)
484
			fprint(2, "srvold9p:->%F\n", &rhdr);/**/
485
		n = convS2M(&rhdr, mdata, sizeof mdata);
486
		if(n == 0)
487
			fatal("convS2M error on write");
488
		if(write(newfd, mdata, n) != n)
489
			fatal("mount write");
490
 
491
		qlock(&taglock);
492
		freetag(tag);
493
		qunlock(&taglock);
494
	}
495
}
496
 
497
void
498
send9p1(Fcall9p1 *t, char *data)
499
{
500
	int m, n;
501
 
502
	if(debug)
503
		fprint(2, "srvold9p:=>%G\n", t);
504
	n = convS2M9p1(t, data);
505
	if(n == 0)
506
		fatal("bad conversion sending to old system");
507
	m = write(woldfd, data, n);
508
	if(m != n)
509
		fatal("wrote %d to old system; should be %d", m, n);
510
}
511
 
512
int
513
recv9p1(Fcall9p1 *r, int tag, char *data)
514
{
515
	int n;
516
	Message *msg;
517
 
518
	msg = rendezvous((void*)tag, 0);
519
	if(msg == (void*)~0)
520
		fatal("rendezvous: %r");
521
	if(msg == nil){
522
		if(debug)
523
			fprint(2, "recv flushed\n");
524
		return -1;
525
	}
526
	/* copy data to local buffer */
527
	memmove(data, msg->data, msg->n);
528
	n = convM2S9p1(data, r, msg->n);
529
	if(n == 0)
530
		fatal("bad conversion receiving from old system");
531
	free(msg->data);
532
	free(msg);
533
	return 1;
534
}
535
 
536
char*
537
transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1)
538
{
539
	send9p1(t, mdata9p1);
540
	if(recv9p1(r, t->tag, mdata9p1) < 0)
541
		return FLUSHED;
542
	if(r->type == Rerror9p1)
543
		return r->ename;
544
	if(r->type != t->type+1)
545
		fatal("bad message type; expected %d got %d", t->type+1, r->type);
546
	return nil;
547
}
548
 
549
char*
550
rflush(Fcall *t, Fcall *, char *mdata9p1)
551
{
552
	Fcall9p1 t9, r9;
553
	Tag *oldt;
554
 
555
	t9.type = Tflush9p1;
556
	t9.tag = t->tag;
557
	t9.oldtag = t->oldtag;
558
	qlock(&taglock);
559
	for(oldt=tags; oldt!=nil; oldt=oldt->next)
560
		if(oldt->tag == t->oldtag){
561
			oldt->flushed = 1;
562
			oldt->ref++;
563
			break;
564
		}
565
	qunlock(&taglock);
566
 
567
	if(oldt == nil){	/* nothing to flush */
568
		if(debug)
569
			fprint(2, "no such tag to flush\n");
570
		return 0;
571
	}
572
 
573
	transact9p1(&t9, &r9, mdata9p1);	/* can't error */
574
 
575
	qlock(&taglock);
576
	if(oldt->received == 0){	/* wake up receiver */
577
		if(debug)
578
			fprint(2, "wake up receiver\n");
579
		oldt->received = 1;
580
		rendezvous((void*)t->oldtag, 0);
581
	}
582
	freetag(oldt);
583
	qunlock(&taglock);
584
	return 0;
585
}
586
 
587
char*
588
rversion(Fcall *t, Fcall *r, char*)
589
{
590
	Fid *f;
591
 
592
	/* just ack; this one doesn't go to old service */
593
	if(t->msize > IOHDRSZ+Maxfdata)
594
		r->msize = IOHDRSZ+Maxfdata;
595
	else
596
		r->msize = t->msize;
597
	if(strncmp(t->version, "9P2000", 6) != 0)
598
		return "unknown 9P version";
599
	r->version = "9P2000";
600
 
601
	qlock(&fidlock);
602
	for(f = fids; f; f = f->next){
603
		f->busy = 0;
604
		f->allocated = 0;
605
	}
606
	qunlock(&fidlock);
607
 
608
	return 0;
609
}
610
 
611
char*
612
rauth(Fcall *, Fcall *, char *)
613
{
614
	return "srvold9p: authentication not supported";
615
}
616
 
617
#ifdef asdf
618
 
619
void
620
memrandom(void *p, int n)
621
{
622
	ulong *lp;
623
	uchar *cp;
624
 
625
	for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong))
626
		*lp++ = fastrand();
627
	for(cp = (uchar*)lp; n > 0; n--)
628
		*cp++ = fastrand();
629
}
630
 
631
char*
632
rsession(Fcall *t, Fcall *r, char *mdata9p1)
633
{
634
	char *err;
635
	Fcall9p1 t9, r9;
636
	Fid *f;
637
 
638
	t9.type = Tsession9p1;
639
	t9.tag = t->tag;
640
	if(doauth)
641
		memrandom(t9.chal, sizeof t9.chal);
642
	else
643
		memset(t9.chal, 0, sizeof t9.chal);
644
	err = transact9p1(&t9, &r9, mdata9p1);
645
	if(err)
646
		return err;
647
 
648
	qlock(&fidlock);
649
	for(f = fids; f; f = f->next){
650
		f->busy = 0;
651
		f->allocated = 0;
652
	}
653
	qunlock(&fidlock);
654
 
655
	if(doauth){
656
		memmove(ai.authid, r9.authid, sizeof ai.authid);
657
		memmove(ai.authdom, r9.authdom, sizeof ai.authid);
658
		memmove(ai.rchal, r9.chal, sizeof ai.rchal);
659
		memmove(ai.chal, t9.chal, sizeof ai.chal);
660
		r->authid = ai.authid;
661
		r->authdom = ai.authdom;
662
		r->chal = (uchar*)ai.rchal;
663
		r->nchal = CHALLEN;
664
	} else {
665
		r->authid = "";
666
		r->authdom = "";
667
		r->nchal = 0;
668
		r->chal = nil;
669
	}
670
	return 0;
671
}
672
#endif
673
 
674
char*
675
rattach(Fcall *t, Fcall *r, char *mdata9p1)
676
{
677
	char *err;
678
	Fcall9p1 t9, r9;
679
	Fid *f;
680
 
681
	f = newfid(t->fid);
682
	if(f->busy)
683
		return "attach: fid in use";
684
	/* no authentication! */
685
	t9.type = Tattach9p1;
686
	t9.tag = t->tag;
687
	t9.fid = t->fid;
688
	strncpy(t9.uname, t->uname, NAMEREC);
689
	if(strcmp(user, "none") == 0)
690
		strncpy(t9.uname, user, NAMEREC);
691
	strncpy(t9.aname, t->aname, NAMEREC);
692
	memset(t9.ticket, 0, sizeof t9.ticket);
693
	memset(t9.auth, 0, sizeof t9.auth);
694
	err = transact9p1(&t9, &r9, mdata9p1);
695
	if(err)
696
		return err;
697
 
698
	r->qid.path = r9.qid.path & ~0x80000000;
699
	r->qid.vers = r9.qid.version;
700
	r->qid.type = QTDIR;
701
	f->busy = 1;
702
	f->qid = r->qid;
703
	return 0;
704
}
705
 
706
char*
707
rwalk(Fcall *t, Fcall *r, char *mdata9p1)
708
{
709
	char *err;
710
	Fcall9p1 t9, r9;
711
	int i, fid;
712
	Qid *q;
713
	Fid *f, *nf;
714
 
715
	f = newfid(t->fid);
716
	if(!f->busy)
717
		return "walk: bad fid";
718
 
719
	fid = t->fid;
720
	nf = nil;
721
	if(t->fid != t->newfid){
722
		nf = newfid(t->newfid);
723
		if(nf->busy)
724
			return "walk: newfid in use";
725
		t9.type = Tclone9p1;
726
		t9.tag = t->tag;
727
		t9.fid = t->fid;
728
		t9.newfid = t->newfid;
729
		err = transact9p1(&t9, &r9, mdata9p1);
730
		if(err){
731
			nf->busy = 0;
732
			nf->allocated = 0;
733
			return err;
734
		}
735
		fid = t->newfid;
736
		nf->busy = 1;
737
	}
738
 
739
	err = nil;
740
	r->nwqid = 0;
741
	for(i=0; i<t->nwname && err==nil; i++){
742
		if(i > MAXWELEM)
743
			break;
744
		t9.type = Twalk9p1;
745
		t9.tag = t->tag;
746
		t9.fid = fid;
747
		strncpy(t9.name, t->wname[i], NAMEREC);
748
		err = transact9p1(&t9, &r9, mdata9p1);
749
		if(err == FLUSHED){
750
			i = -1;	/* guarantee cleanup */
751
			break;
752
		}
753
		if(err == nil){
754
			q = &r->wqid[r->nwqid++];
755
			q->type = QTFILE;
756
			if(r9.qid.path & 0x80000000)
757
				q->type = QTDIR;
758
			q->vers = r9.qid.version;
759
			q->path = r9.qid.path & ~0x80000000;
760
		}
761
	}
762
 
763
	if(nf!=nil && (err!=nil || i<t->nwname)){
764
		/* clunk the new fid */
765
		t9.type = Tclunk9p1;
766
		t9.tag = t->tag;
767
		t9.fid = t->newfid;
768
		transact9p1(&t9, &r9, mdata9p1);
769
		/* ignore more errors */
770
		nf->busy = 0;
771
		nf->allocated = 0;
772
	}
773
 
774
	if(i>0 && i==t->nwname && err==nil)
775
		f->qid = r->wqid[r->nwqid-1];
776
	if(i > 0)
777
		return 0;
778
	return err;
779
}
780
 
781
char*
782
ropen(Fcall *t, Fcall *r, char *mdata9p1)
783
{
784
	char *err;
785
	Fcall9p1 t9, r9;
786
	Fid *f;
787
 
788
	f = newfid(t->fid);
789
	if(!f->busy)
790
		return "open: bad fid";
791
 
792
	t9.type = Topen9p1;
793
	t9.tag = t->tag;
794
	t9.fid = t->fid;
795
	t9.mode = t->mode;
796
	err = transact9p1(&t9, &r9, mdata9p1);
797
	if(err)
798
		return err;
799
 
800
	r->qid.path = r9.qid.path & ~0x80000000;
801
	r->qid.vers = r9.qid.version;
802
	r->qid.type = QTFILE;
803
	if(r9.qid.path & 0x80000000)
804
		r->qid.type = QTDIR;
805
	f->qid = r->qid;
806
	f->newoffset = 0;
807
	f->oldoffset = 0;
808
	r->iounit = 0;
809
	return 0;
810
}
811
 
812
char*
813
rcreate(Fcall *t, Fcall *r, char *mdata9p1)
814
{
815
	char *err;
816
	Fcall9p1 t9, r9;
817
	Fid *f;
818
 
819
	f = newfid(t->fid);
820
	if(!f->busy)
821
		return "create: bad fid";
822
 
823
	t9.type = Tcreate9p1;
824
	t9.tag = t->tag;
825
	t9.fid = t->fid;
826
	if(strlen(t->name)+1 >= NAMEREC)
827
		return "file name element too long";
828
	strncpy(t9.name, t->name, NAMEREC);
829
	t9.perm = t->perm;
830
	t9.mode = t->mode;
831
	err = transact9p1(&t9, &r9, mdata9p1);
832
	if(err)
833
		return err;
834
 
835
	r->qid.path = r9.qid.path & ~0x80000000;
836
	r->qid.vers = r9.qid.version;
837
	r->qid.type = QTFILE;
838
	if(r9.qid.path & 0x80000000)
839
		r->qid.type = QTDIR;
840
	if(r9.qid.path & 0x40000000)
841
		r->qid.type |= QTAPPEND;
842
	if(r9.qid.path & 0x20000000)
843
		r->qid.type |= QTEXCL;
844
	f->qid = r->qid;
845
	r->iounit = 0;
846
	return 0;
847
}
848
 
849
char*
850
dirrread(Fcall *t, Fcall *r, char *mdata9p1)
851
{
852
	char *err;
853
	Fcall9p1 t9, r9;
854
	Fid *f;
855
	int i, ndir, n, count;
856
	Dir d;
857
	uchar buf[Maxfdata];
858
	char *old;
859
 
860
	f = newfid(t->fid);
861
	if(!f->busy)
862
		return "dirread: bad fid";
863
 
864
	if(f->newoffset != t->offset)
865
		return "seek in directory disallowed";
866
 
867
	t9.type = Tread9p1;
868
	t9.tag = t->tag;
869
	t9.fid = t->fid;
870
	t9.offset = f->oldoffset;
871
	t9.count = t->count;	/* new directories tend to be smaller, so this may overshoot */
872
	err = transact9p1(&t9, &r9, mdata9p1);
873
	if(err)
874
		return err;
875
 
876
	ndir = r9.count/DIRREC;
877
	old = r9.data;
878
	count = 0;
879
	for(i=0; i<ndir; i++){
880
		if(convM2D9p1(old, &d) != DIRREC)
881
			return "bad dir conversion in read";
882
		n = convD2M(&d, buf+count, sizeof buf-count);
883
		if(n<=BIT16SZ || count+n>t->count)
884
			break;
885
		old += DIRREC;
886
		f->oldoffset += DIRREC;
887
		f->newoffset += n;
888
		count += n;
889
	}
890
	memmove(r9.data, buf, count);	/* put it back in stable storage */
891
	r->data = r9.data;
892
	r->count = count;
893
	return 0;
894
}
895
 
896
char*
897
rread(Fcall *t, Fcall *r, char *mdata9p1)
898
{
899
	char *err;
900
	Fcall9p1 t9, r9;
901
	Fid *f;
902
 
903
	f = newfid(t->fid);
904
	if(!f->busy)
905
		return "read: bad fid";
906
 
907
	if(f->qid.type & QTDIR)
908
		return dirrread(t, r, mdata9p1);
909
 
910
	t9.type = Tread9p1;
911
	t9.tag = t->tag;
912
	t9.fid = t->fid;
913
	t9.offset = t->offset;
914
	t9.count = t->count;
915
	err = transact9p1(&t9, &r9, mdata9p1);
916
	if(err)
917
		return err;
918
 
919
	r->count = r9.count;
920
	r->data = r9.data;	/* points to stable storage */
921
	return 0;
922
}
923
 
924
char*
925
rwrite(Fcall *t, Fcall *r, char *mdata9p1)
926
{
927
	char *err;
928
	Fcall9p1 t9, r9;
929
	Fid *f;
930
 
931
	f = newfid(t->fid);
932
	if(!f->busy)
933
		return "write: bad fid";
934
 
935
	t9.type = Twrite9p1;
936
	t9.tag = t->tag;
937
	t9.fid = t->fid;
938
	t9.offset = t->offset;
939
	t9.count = t->count;
940
	t9.data = t->data;
941
	err = transact9p1(&t9, &r9, mdata9p1);
942
	if(err)
943
		return err;
944
 
945
	r->count = r9.count;
946
	return 0;
947
}
948
 
949
char*
950
rclunk(Fcall *t, Fcall *, char *mdata9p1)
951
{
952
	Fcall9p1 t9, r9;
953
	Fid *f;
954
 
955
	f = newfid(t->fid);
956
	if(!f->busy)
957
		return "clunk: bad fid";
958
	t9.type = Tclunk9p1;
959
	t9.tag = t->tag;
960
	t9.fid = t->fid;
961
	transact9p1(&t9, &r9, mdata9p1);
962
	f->busy = 0;
963
	f->allocated = 0;
964
	/* disregard error */
965
	return 0;
966
}
967
 
968
char*
969
rremove(Fcall *t, Fcall*, char *mdata9p1)
970
{
971
	char *err;
972
	Fcall9p1 t9, r9;
973
	Fid *f;
974
 
975
	f = newfid(t->fid);
976
	if(!f->busy)
977
		return "remove: bad fid";
978
	t9.type = Tremove9p1;
979
	t9.tag = t->tag;
980
	t9.fid = t->fid;
981
	err = transact9p1(&t9, &r9, mdata9p1);
982
	f->busy = 0;
983
	f->allocated = 0;
984
	return err;
985
}
986
 
987
char*
988
rstat(Fcall *t, Fcall *r, char *mdata9p1)
989
{
990
	Fcall9p1 t9, r9;
991
	char *err;
992
	Fid *f;
993
	Dir d;
994
	uchar buf[256];	/* big enough; there's no long names */
995
 
996
	f = newfid(t->fid);
997
	if(!f->busy)
998
		return "stat: bad fid";
999
 
1000
	t9.type = Tstat9p1;
1001
	t9.tag = t->tag;
1002
	t9.fid = t->fid;
1003
	err = transact9p1(&t9, &r9, mdata9p1);
1004
	if(err)
1005
		return err;
1006
 
1007
	if(convM2D9p1(r9.stat, &d) != DIRREC)
1008
		return "bad conversion in stat";
1009
	r->stat = buf;
1010
	r->nstat = convD2M(&d, buf, sizeof buf);
1011
	return 0;
1012
}
1013
 
1014
int
1015
anydefault(Dir *d)
1016
{
1017
	if(d->name[0] == '\0')
1018
		return 1;
1019
	if(d->uid[0] == '\0')
1020
		return 1;
1021
	if(d->gid[0] == '\0')
1022
		return 1;
1023
	if(d->mode == ~0)
1024
		return 1;
1025
	if(d->mtime == ~0)
1026
		return 1;
1027
	return 0;
1028
}
1029
 
1030
char*
1031
rwstat(Fcall *t, Fcall *, char *mdata9p1)
1032
{
1033
	Fcall9p1 t9, r9;
1034
	char strs[DIRREC];
1035
	char *err;
1036
	Fid *f;
1037
	Dir d, cd;
1038
 
1039
	f = newfid(t->fid);
1040
	if(!f->busy)
1041
		return "wstat: bad fid";
1042
 
1043
	convM2D(t->stat, t->nstat, &d, strs);
1044
	cd = d;
1045
	if(anydefault(&d)){
1046
		/* must first stat file so we can copy current values */
1047
		t9.type = Tstat9p1;
1048
		t9.tag = t->tag;
1049
		t9.fid = t->fid;
1050
		err = transact9p1(&t9, &r9, mdata9p1);
1051
		if(err)
1052
			return err;
1053
		if(convM2D9p1(r9.stat, &cd) != DIRREC)
1054
			return "bad in conversion in wstat";
1055
 
1056
		/* fill in default values */
1057
		if(d.name[0] != '\0'){
1058
			if(strlen(d.name) >= NAMEREC)
1059
				return Etoolong;
1060
			cd.name = d.name;
1061
		}
1062
		if(d.uid[0] != '\0'){
1063
			if(strlen(d.uid) >= NAMEREC)
1064
				return Etoolong;
1065
			cd.uid = d.uid;
1066
		}
1067
		if(d.gid[0] != '\0'){
1068
			if(strlen(d.gid) >= NAMEREC)
1069
				return Etoolong;
1070
			cd.gid = d.gid;
1071
		}
1072
		if(d.mode != ~0)
1073
			cd.mode = d.mode;
1074
		if(d.mtime != ~0)
1075
			cd.mtime = d.mtime;
1076
		if(d.length != ~0LL)
1077
			cd.length = d.length;
1078
	}
1079
 
1080
	if(convD2M9p1(&cd, t9.stat) != DIRREC)
1081
		return "bad out conversion in wstat";
1082
 
1083
	t9.type = Twstat9p1;
1084
	t9.tag = t->tag;
1085
	t9.fid = t->fid;
1086
	err = transact9p1(&t9, &r9, mdata9p1);
1087
	if(err)
1088
		return err;
1089
	return 0;
1090
}
1091
 
1092
void *
1093
emalloc(ulong n)
1094
{
1095
	void *p;
1096
 
1097
	p = malloc(n);
1098
	if(!p)
1099
		fatal("out of memory: %r");
1100
	memset(p, 0, n);
1101
	return p;
1102
}
1103
 
1104
void
1105
fatal(char *fmt, ...)
1106
{
1107
	char buf[1024];
1108
	va_list arg;
1109
 
1110
	if(fmt){
1111
		va_start(arg, fmt);
1112
		vseprint(buf, buf+sizeof(buf), fmt, arg);
1113
		va_end(arg);
1114
		fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf);
1115
	}else
1116
		buf[0] = '\0';
1117
	if(mainpid){
1118
		/* two hits are sometimes needed */
1119
		postnote(PNGROUP, mainpid, "die1 - from srvold9p");
1120
		postnote(PNGROUP, mainpid, "die2 - from srvold9p");
1121
	}
1122
	exits(buf);
1123
}