xref: /inferno-os/os/port/sysfile.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1  #include	"u.h"
2  #include	"../port/lib.h"
3  #include	"mem.h"
4  #include	"dat.h"
5  #include	"fns.h"
6  #include	"../port/error.h"
7  
8  static int
9  growfd(Fgrp *f, int fd)
10  {
11  	int n;
12  	Chan **nfd, **ofd;
13  
14  	if(fd < f->nfd)
15  		return 0;
16  	n = f->nfd+DELTAFD;
17  	if(n > MAXNFD)
18  		n = MAXNFD;
19  	if(fd >= n)
20  		return -1;
21  	nfd = malloc(n*sizeof(Chan*));
22  	if(nfd == nil)
23  		return -1;
24  	ofd = f->fd;
25  	memmove(nfd, ofd, f->nfd*sizeof(Chan *));
26  	f->fd = nfd;
27  	f->nfd = n;
28  	free(ofd);
29  	return 0;
30  }
31  
32  int
33  newfd(Chan *c)
34  {
35  	int i;
36  	Fgrp *f = up->env->fgrp;
37  
38  	lock(f);
39  	for(i=f->minfd; i<f->nfd; i++)
40  		if(f->fd[i] == 0)
41  			break;
42  	if(i >= f->nfd && growfd(f, i) < 0){
43  		unlock(f);
44  		exhausted("file descriptors");
45  		return -1;
46  	}
47  	f->minfd = i + 1;
48  	if(i > f->maxfd)
49  		f->maxfd = i;
50  	f->fd[i] = c;
51  	unlock(f);
52  	return i;
53  }
54  
55  Chan*
56  fdtochan(Fgrp *f, int fd, int mode, int chkmnt, int iref)
57  {
58  	Chan *c;
59  
60  	c = 0;
61  
62  	lock(f);
63  	if(fd<0 || f->maxfd<fd || (c = f->fd[fd])==0) {
64  		unlock(f);
65  		error(Ebadfd);
66  	}
67  	if(iref)
68  		incref(c);
69  	unlock(f);
70  
71  	if(chkmnt && (c->flag&CMSG)) {
72  		if(iref)
73  			cclose(c);
74  		error(Ebadusefd);
75  	}
76  
77  	if(mode<0 || c->mode==ORDWR)
78  		return c;
79  
80  	if((mode&OTRUNC) && c->mode==OREAD) {
81  		if(iref)
82  			cclose(c);
83  		error(Ebadusefd);
84  	}
85  
86  	if((mode&~OTRUNC) != c->mode) {
87  		if(iref)
88  			cclose(c);
89  		error(Ebadusefd);
90  	}
91  
92  	return c;
93  }
94  
95  long
96  kchanio(void *vc, void *buf, int n, int mode)
97  {
98  	int r;
99  	Chan *c;
100  
101  	c = vc;
102  	if(waserror())
103  		return -1;
104  
105  	if(mode == OREAD)
106  		r = devtab[c->type]->read(c, buf, n, c->offset);
107  	else
108  		r = devtab[c->type]->write(c, buf, n, c->offset);
109  
110  	lock(c);
111  	c->offset += r;
112  	unlock(c);
113  	poperror();
114  	return r;
115  }
116  
117  int
118  openmode(ulong o)
119  {
120  	if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC))
121  		error(Ebadarg);
122  	o &= ~(OTRUNC|OCEXEC|ORCLOSE);
123  	if(o > OEXEC)
124  		error(Ebadarg);
125  	if(o == OEXEC)
126  		return OREAD;
127  	return o;
128  }
129  
130  void
131  fdclose(Fgrp *f, int fd)
132  {
133  	int i;
134  	Chan *c;
135  
136  	lock(f);
137  	c = f->fd[fd];
138  	if(c == 0){
139  		/* can happen for users with shared fd tables */
140  		unlock(f);
141  		return;
142  	}
143  	f->fd[fd] = 0;
144  	if(fd == f->maxfd)
145  		for(i=fd; --i>=0 && f->fd[i]==0; )
146  			f->maxfd = i;
147  	if(fd < f->minfd)
148  		f->minfd = fd;
149  	unlock(f);
150  	cclose(c);
151  }
152  
153  int
154  kchdir(char *path)
155  {
156  	Chan *c;
157  	Pgrp *pg;
158  
159  	if(waserror())
160  		return -1;
161  
162  	c = namec(path, Atodir, 0, 0);
163  	pg = up->env->pgrp;
164  	cclose(pg->dot);
165  	pg->dot = c;
166  	poperror();
167  	return 0;
168  }
169  
170  int
171  kfgrpclose(Fgrp *f, int fd)
172  {
173  	if(waserror())
174  		return -1;
175  
176  	/*
177  	 * Take no reference on the chan because we don't really need the
178  	 * data structure, and are calling fdtochan only for error checks.
179  	 * fdclose takes care of processes racing through here.
180  	 */
181  	fdtochan(f, fd, -1, 0, 0);
182  	fdclose(f, fd);
183  	poperror();
184  	return 0;
185  }
186  
187  int
188  kclose(int fd)
189  {
190  	return kfgrpclose(up->env->fgrp, fd);
191  }
192  
193  int
194  kcreate(char *path, int mode, ulong perm)
195  {
196  	int fd;
197  	Chan *c;
198  
199  	if(waserror())
200  		return -1;
201  
202  	openmode(mode&~OEXCL);	/* error check only; OEXCL okay here */
203  	c = namec(path, Acreate, mode, perm);
204  	if(waserror()) {
205  		cclose(c);
206  		nexterror();
207  	}
208  	fd = newfd(c);
209  	if(fd < 0)
210  		error(Enofd);
211  	poperror();
212  
213  	poperror();
214  	return fd;
215  }
216  
217  int
218  kdup(int old, int new)
219  {
220  	int fd;
221  	Chan *c, *oc;
222  	Fgrp *f = up->env->fgrp;
223  
224  	if(waserror())
225  		return -1;
226  
227  	c = fdtochan(up->env->fgrp, old, -1, 0, 1);
228  	if(c->qid.type & QTAUTH)
229  		error(Eperm);
230  	fd = new;
231  	if(fd != -1){
232  		lock(f);
233  		if(fd<0 || growfd(f, fd) < 0) {
234  			unlock(f);
235  			cclose(c);
236  			error(Ebadfd);
237  		}
238  		if(fd > f->maxfd)
239  			f->maxfd = fd;
240  		oc = f->fd[fd];
241  		f->fd[fd] = c;
242  		unlock(f);
243  		if(oc)
244  			cclose(oc);
245  	}else{
246  		if(waserror()) {
247  			cclose(c);
248  			nexterror();
249  		}
250  		fd = newfd(c);
251  		if(fd < 0)
252  			error(Enofd);
253  		poperror();
254  	}
255  	poperror();
256  	return fd;
257  }
258  
259  int
260  kfstat(int fd, uchar *buf, int n)
261  {
262  	Chan *c;
263  
264  	if(waserror())
265  		return -1;
266  
267  	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);
268  	if(waserror()) {
269  		cclose(c);
270  		nexterror();
271  	}
272  	devtab[c->type]->stat(c, buf, n);
273  
274  	poperror();
275  	cclose(c);
276  
277  	poperror();
278  	return n;
279  }
280  
281  char*
282  kfd2path(int fd)
283  {
284  	Chan *c;
285  	char *s;
286  
287  	if(waserror())
288  		return nil;
289  	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);
290  	s = nil;
291  	if(c->name != nil){
292  		s = malloc(c->name->len+1);
293  		if(s == nil){
294  			cclose(c);
295  			error(Enomem);
296  		}
297  		memmove(s, c->name->s, c->name->len+1);
298  		cclose(c);
299  	}
300  	poperror();
301  	return s;
302  }
303  
304  int
305  kfauth(int fd, char *aname)
306  {
307  	Chan *c, *ac;
308  
309  	if(waserror())
310  		return -1;
311  
312  	validname(aname, 1);
313  	c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
314  	if(waserror()){
315  		cclose(c);
316  		nexterror();
317  	}
318  
319  	ac = mntauth(c, aname);
320  
321  	/* at this point ac is responsible for keeping c alive */
322  	poperror();	/* c */
323  	cclose(c);
324  
325  	if(waserror()){
326  		cclose(ac);
327  		nexterror();
328  	}
329  
330  	fd = newfd(ac);
331  	if(fd < 0)
332  		error(Enofd);
333  	poperror();	/* ac */
334  
335  	poperror();
336  
337  	return fd;
338  }
339  
340  int
341  kfversion(int fd, uint msize, char *vers, uint arglen)
342  {
343  	int m;
344  	Chan *c;
345  
346  	if(waserror())
347  		return -1;
348  
349  	/* check there's a NUL in the version string */
350  	if(arglen==0 || memchr(vers, 0, arglen)==0)
351  		error(Ebadarg);
352  
353  	c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
354  	if(waserror()){
355  		cclose(c);
356  		nexterror();
357  	}
358  
359  	m = mntversion(c, vers, msize, arglen);
360  
361  	poperror();
362  	cclose(c);
363  
364  	poperror();
365  	return m;
366  }
367  
368  int
369  kpipe(int fd[2])
370  {
371  	Dev *d;
372  	Fgrp *f;
373  	Chan *c[2];
374  	static char *names[] = {"data", "data1"};
375  
376  	f = up->env->fgrp;
377  
378  	d = devtab[devno('|', 0)];
379  	c[0] = namec("#|", Atodir, 0, 0);
380  	c[1] = 0;
381  	fd[0] = -1;
382  	fd[1] = -1;
383  	if(waserror()) {
384  		if(c[0] != 0)
385  			cclose(c[0]);
386  		if(c[1] != 0)
387  			cclose(c[1]);
388  		if(fd[0] >= 0)
389  			f->fd[fd[0]]=0;
390  		if(fd[1] >= 0)
391  			f->fd[fd[1]]=0;
392  		return -1;
393  	}
394  	c[1] = cclone(c[0]);
395  	if(walk(&c[0], &names[0], 1, 1, nil) < 0)
396  		error(Egreg);
397  	if(walk(&c[1], &names[1], 1, 1, nil) < 0)
398  		error(Egreg);
399  	c[0] = d->open(c[0], ORDWR);
400  	c[1] = d->open(c[1], ORDWR);
401  	fd[0] = newfd(c[0]);
402  	if(fd[0] < 0)
403  		error(Enofd);
404  	fd[1] = newfd(c[1]);
405  	if(fd[1] < 0)
406  		error(Enofd);
407  	poperror();
408  	return 0;
409  }
410  
411  int
412  kfwstat(int fd, uchar *buf, int n)
413  {
414  	Chan *c;
415  
416  	if(waserror())
417  		return -1;
418  
419  	validstat(buf, n);
420  	c = fdtochan(up->env->fgrp, fd, -1, 1, 1);
421  	if(waserror()) {
422  		cclose(c);
423  		nexterror();
424  	}
425  	n = devtab[c->type]->wstat(c, buf, n);
426  	poperror();
427  	cclose(c);
428  
429  	poperror();
430  	return n;
431  }
432  
433  long
434  bindmount(Chan *c, char *old, int flag, char *spec)
435  {
436  	int ret;
437  	Chan *c1;
438  
439  	if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
440  		error(Ebadarg);
441  
442  	c1 = namec(old, Amount, 0, 0);
443  	if(waserror()){
444  		cclose(c1);
445  		nexterror();
446  	}
447  	ret = cmount(c, c1, flag, spec);
448  
449  	poperror();
450  	cclose(c1);
451  	return ret;
452  }
453  
454  int
455  kbind(char *new, char *old, int flags)
456  {
457  	long r;
458  	Chan *c0;
459  
460  	if(waserror())
461  		return -1;
462  
463  	c0 = namec(new, Abind, 0, 0);
464  	if(waserror()) {
465  		cclose(c0);
466  		nexterror();
467  	}
468  	r = bindmount(c0, old, flags, "");
469  	poperror();
470  	cclose(c0);
471  
472  	poperror();
473  	return r;
474  }
475  
476  int
477  kmount(int fd, int afd, char *old, int flags, char *spec)
478  {
479  	long r;
480  	volatile struct { Chan *c; } c0;
481  	volatile struct { Chan *c; } bc;
482  	volatile struct { Chan *c; } ac;
483  	Mntparam mntparam;
484  
485  	ac.c = nil;
486  	bc.c = nil;
487  	c0.c = nil;
488  	if(waserror()) {
489  		cclose(ac.c);
490  		cclose(bc.c);
491  		cclose(c0.c);
492  		return -1;
493  	}
494  	bc.c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
495  	if(afd >= 0)
496  		ac.c = fdtochan(up->env->fgrp, afd, ORDWR, 0, 1);
497  	mntparam.chan = bc.c;
498  	mntparam.authchan = ac.c;
499  	mntparam.spec = spec;
500  	mntparam.flags = flags;
501  	c0.c = devtab[devno('M', 0)]->attach((char*)&mntparam);
502  
503  	r = bindmount(c0.c, old, flags, spec);
504  	poperror();
505  	cclose(ac.c);
506  	cclose(bc.c);
507  	cclose(c0.c);
508  
509  	return r;
510  }
511  
512  int
513  kunmount(char *old, char *new)
514  {
515  	volatile struct { Chan *c; } cmount;
516  	volatile struct { Chan *c; } cmounted;
517  
518  	cmount.c = nil;
519  	cmounted.c = nil;
520  	if(waserror()) {
521  		cclose(cmount.c);
522  		cclose(cmounted.c);
523  		return -1;
524  	}
525  
526  	cmount.c = namec(new, Amount, 0, 0);
527  	if(old != nil && old[0] != '\0') {
528  		/*
529  		 * This has to be namec(..., Aopen, ...) because
530  		 * if arg[0] is something like /srv/cs or /fd/0,
531  		 * opening it is the only way to get at the real
532  		 * Chan underneath.
533  		 */
534  		cmounted.c = namec(old, Aopen, OREAD, 0);
535  	}
536  
537  	cunmount(cmount.c, cmounted.c);
538  	poperror();
539  	cclose(cmount.c);
540  	cclose(cmounted.c);
541  	return 0;
542  }
543  
544  int
545  kopen(char *path, int mode)
546  {
547  	int fd;
548  	Chan *c;
549  
550  	if(waserror())
551  		return -1;
552  
553  	openmode(mode);                         /* error check only */
554  	c = namec(path, Aopen, mode, 0);
555  	if(waserror()){
556  		cclose(c);
557  		nexterror();
558  	}
559  	fd = newfd(c);
560  	if(fd < 0)
561  		error(Enofd);
562  	poperror();
563  
564  	poperror();
565  	return fd;
566  }
567  
568  long
569  unionread(Chan *c, void *va, long n)
570  {
571  	int i;
572  	long nr;
573  	Mhead *m;
574  	Mount *mount;
575  
576  	qlock(&c->umqlock);
577  	m = c->umh;
578  	rlock(&m->lock);
579  	mount = m->mount;
580  	/* bring mount in sync with c->uri and c->umc */
581  	for(i = 0; mount != nil && i < c->uri; i++)
582  		mount = mount->next;
583  
584  	nr = 0;
585  	while(mount != nil) {
586  		/* Error causes component of union to be skipped */
587  		if(mount->to && !waserror()) {
588  			if(c->umc == nil){
589  				c->umc = cclone(mount->to);
590  				c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
591  			}
592  
593  			nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
594  			if(nr < 0)
595  				nr = 0;	/* dev.c can return -1 */
596  			c->umc->offset += nr;
597  			poperror();
598  		}
599  		if(nr > 0)
600  			break;
601  
602  		/* Advance to next element */
603  		c->uri++;
604  		if(c->umc) {
605  			cclose(c->umc);
606  			c->umc = nil;
607  		}
608  		mount = mount->next;
609  	}
610  	runlock(&m->lock);
611  	qunlock(&c->umqlock);
612  	return nr;
613  }
614  
615  static void
616  unionrewind(Chan *c)
617  {
618  	qlock(&c->umqlock);
619  	c->uri = 0;
620  	if(c->umc){
621  		cclose(c->umc);
622  		c->umc = nil;
623  	}
624  	qunlock(&c->umqlock);
625  }
626  
627  static long
628  rread(int fd, void *va, long n, vlong *offp)
629  {
630  	int dir;
631  	Chan *c;
632  	vlong off;
633  
634  	if(waserror())
635  		return -1;
636  
637  	c = fdtochan(up->env->fgrp, fd, OREAD, 1, 1);
638  	if(waserror()) {
639  		cclose(c);
640  		nexterror();
641  	}
642  
643  	if(n < 0)
644  		error(Etoosmall);
645  
646  	dir = c->qid.type & QTDIR;
647  	if(dir && c->umh)
648  		n = unionread(c, va, n);
649  	else{
650  		if(offp == nil){
651  			lock(c);	/* lock for vlong assignment */
652  			off = c->offset;
653  			unlock(c);
654  		}else
655  			off = *offp;
656  		if(off < 0)
657  			error(Enegoff);
658  		if(off == 0){
659  			if(offp == nil){
660  				lock(c);
661  				c->offset = 0;
662  				c->dri = 0;
663  				unlock(c);
664  			}
665  			unionrewind(c);
666  		}
667  		n = devtab[c->type]->read(c, va, n, off);
668  		lock(c);
669  		c->offset += n;
670  		unlock(c);
671  	}
672  
673  	poperror();
674  	cclose(c);
675  
676  	poperror();
677  	return n;
678  }
679  
680  long
681  kread(int fd, void *va, long n)
682  {
683  	return rread(fd, va, n, nil);
684  }
685  
686  long
687  kpread(int fd, void *va, long n, vlong off)
688  {
689  	return rread(fd, va, n, &off);
690  }
691  
692  int
693  kremove(char *path)
694  {
695  	Chan *c;
696  
697  	if(waserror())
698  		return -1;
699  
700  	c = namec(path, Aremove, 0, 0);
701  	if(waserror()) {
702  		c->type = 0;	/* see below */
703  		cclose(c);
704  		nexterror();
705  	}
706  	devtab[c->type]->remove(c);
707  	/*
708  	 * Remove clunks the fid, but we need to recover the Chan
709  	 * so fake it up.  rootclose() is known to be a nop.
710  	 */
711  	c->type = 0;
712  	poperror();
713  	cclose(c);
714  
715  	poperror();
716  	return 0;
717  }
718  
719  vlong
720  kseek(int fd, vlong off, int whence)
721  {
722  	Dir *dir;
723  	Chan *c;
724  
725  	if(waserror())
726  		return -1;
727  
728  	c = fdtochan(up->env->fgrp, fd, -1, 1, 1);
729  	if(waserror()) {
730  		cclose(c);
731  		nexterror();
732  	}
733  
734  	if(devtab[c->type]->dc == '|')
735  		error(Eisstream);
736  
737  	switch(whence) {
738  	case 0:
739  		if(c->qid.type & QTDIR){
740  			if(off != 0)
741  				error(Eisdir);
742  			unionrewind(c);
743  		}else if(off < 0)
744  			error(Enegoff);
745  		lock(c);	/* lock for vlong assignment */
746  		c->offset = off;
747  		unlock(c);
748  		break;
749  
750  	case 1:
751  		if(c->qid.type & QTDIR)
752  			error(Eisdir);
753  		lock(c);	/* lock for read/write update */
754  		off += c->offset;
755  		if(off < 0){
756  			unlock(c);
757  			error(Enegoff);
758  		}
759  		c->offset = off;
760  		unlock(c);
761  		break;
762  
763  	case 2:
764  		if(c->qid.type & QTDIR)
765  			error(Eisdir);
766  		dir = chandirstat(c);
767  		if(dir == nil)
768  			error("internal error: stat error in seek");
769  		off += dir->length;
770  		free(dir);
771  		if(off < 0)
772  			error(Enegoff);
773  		lock(c);	/* lock for read/write update */
774  		c->offset = off;
775  		unlock(c);
776  		break;
777  
778  	default:
779  		error(Ebadarg);
780  		break;
781  	}
782  	poperror();
783  	c->dri = 0;
784  	cclose(c);
785  	poperror();
786  	return off;
787  }
788  
789  void
790  validstat(uchar *s, int n)
791  {
792  	int m;
793  	char buf[64];
794  
795  	if(statcheck(s, n) < 0)
796  		error(Ebadstat);
797  	/* verify that name entry is acceptable */
798  	s += STATFIXLEN - 4*BIT16SZ;	/* location of first string */
799  	/*
800  	 * s now points at count for first string.
801  	 * if it's too long, let the server decide; this is
802  	 * only for his protection anyway. otherwise
803  	 * we'd have to allocate and waserror.
804  	 */
805  	m = GBIT16(s);
806  	s += BIT16SZ;
807  	if(m+1 > sizeof buf)
808  		return;
809  	memmove(buf, s, m);
810  	buf[m] = '\0';
811  	/* name could be '/' */
812  	if(strcmp(buf, "/") != 0)
813  		validname(buf, 0);
814  }
815  
816  int
817  kstat(char *path, uchar *buf, int n)
818  {
819  	Chan *c;
820  
821  	if(waserror())
822  		return -1;
823  
824  	c = namec(path, Aaccess, 0, 0);
825  	if(waserror()){
826  		cclose(c);
827  		nexterror();
828  	}
829  	devtab[c->type]->stat(c, buf, n);
830  	poperror();
831  	cclose(c);
832  
833  	poperror();
834  	return 0;
835  }
836  
837  static long
838  rwrite(int fd, void *va, long n, vlong *offp)
839  {
840  	Chan *c;
841  	vlong off;
842  	long m;
843  
844  	if(waserror())
845  		return -1;
846  	c = fdtochan(up->env->fgrp, fd, OWRITE, 1, 1);
847  	if(waserror()) {
848  		cclose(c);
849  		nexterror();
850  	}
851  	if(c->qid.type & QTDIR)
852  		error(Eisdir);
853  
854  	if(n < 0)
855  		error(Etoosmall);
856  
857  	if(offp == nil){
858  		lock(c);
859  		off = c->offset;
860  		c->offset += n;
861  		unlock(c);
862  	}else
863  		off = *offp;
864  
865  	if(waserror()){
866  		if(offp == nil){
867  			lock(c);
868  			c->offset -= n;
869  			unlock(c);
870  		}
871  		nexterror();
872  	}
873  	if(off < 0)
874  		error(Enegoff);
875  	m = devtab[c->type]->write(c, va, n, off);
876  	poperror();
877  
878  	if(offp == nil && m < n){
879  		lock(c);
880  		c->offset -= n - m;
881  		unlock(c);
882  	}
883  
884  	poperror();
885  	cclose(c);
886  
887  	poperror();
888  	return n;
889  }
890  
891  long
892  kwrite(int fd, void *va, long n)
893  {
894  	return rwrite(fd, va, n, nil);
895  }
896  
897  long
898  kpwrite(int fd, void *va, long n, vlong off)
899  {
900  	return rwrite(fd, va, n, &off);
901  }
902  
903  int
904  kwstat(char *path, uchar *buf, int n)
905  {
906  	Chan *c;
907  
908  	if(waserror())
909  		return -1;
910  
911  	validstat(buf, n);
912  	c = namec(path, Aaccess, 0, 0);
913  	if(waserror()){
914  		cclose(c);
915  		nexterror();
916  	}
917  	n = devtab[c->type]->wstat(c, buf, n);
918  	poperror();
919  	cclose(c);
920  
921  	poperror();
922  	return n;
923  }
924  
925  enum
926  {
927  	DIRSIZE = STATFIXLEN + 32 * 4,
928  	DIRREADLIM = 2048,	/* should handle the largest reasonable directory entry */
929  };
930  
931  Dir*
932  chandirstat(Chan *c)
933  {
934  	Dir *d;
935  	uchar *buf;
936  	int n, nd, i;
937  
938  	nd = DIRSIZE;
939  	for(i=0; i<2; i++){	/* should work by the second try */
940  		d = smalloc(sizeof(Dir) + nd);
941  		buf = (uchar*)&d[1];
942  		if(waserror()){
943  			free(d);
944  			return nil;
945  		}
946  		n = devtab[c->type]->stat(c, buf, nd);
947  		poperror();
948  		if(n < BIT16SZ){
949  			free(d);
950  			return nil;
951  		}
952  		nd = GBIT16((uchar*)buf) + BIT16SZ;	/* size needed to store whole stat buffer including count */
953  		if(nd <= n){
954  			convM2D(buf, n, d, (char*)&d[1]);
955  			return d;
956  		}
957  		/* else sizeof(Dir)+nd is plenty */
958  		free(d);
959  	}
960  	return nil;
961  
962  }
963  
964  Dir*
965  kdirstat(char *name)
966  {
967  	Chan *c;
968  	Dir *d;
969  
970  	if(waserror())
971  		return nil;
972  
973  	c = namec(name, Aaccess, 0, 0);
974  	if(waserror()){
975  		cclose(c);
976  		nexterror();
977  	}
978  	d = chandirstat(c);
979  	poperror();
980  	cclose(c);
981  
982  	poperror();
983  	return d;
984  }
985  
986  Dir*
987  kdirfstat(int fd)
988  {
989  	Chan *c;
990  	Dir *d;
991  
992  	if(waserror())
993  		return nil;
994  
995  	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);
996  	if(waserror()) {
997  		cclose(c);
998  		nexterror();
999  	}
1000  	d = chandirstat(c);
1001  	poperror();
1002  	cclose(c);
1003  
1004  	poperror();
1005  	return d;
1006  }
1007  
1008  int
1009  kdirwstat(char *name, Dir *dir)
1010  {
1011  	uchar *buf;
1012  	int r;
1013  
1014  	r = sizeD2M(dir);
1015  	buf = smalloc(r);
1016  	convD2M(dir, buf, r);
1017  	r = kwstat(name, buf, r);
1018  	free(buf);
1019  	return r < 0? r: 0;
1020  }
1021  
1022  int
1023  kdirfwstat(int fd, Dir *dir)
1024  {
1025  	uchar *buf;
1026  	int r;
1027  
1028  	r = sizeD2M(dir);
1029  	buf = smalloc(r);
1030  	convD2M(dir, buf, r);
1031  	r = kfwstat(fd, buf, r);
1032  	free(buf);
1033  	return r < 0? r: 0;
1034  }
1035  
1036  static long
1037  dirpackage(uchar *buf, long ts, Dir **d)
1038  {
1039  	char *s;
1040  	long ss, i, n, nn, m;
1041  
1042  	*d = nil;
1043  	if(ts <= 0)
1044  		return ts;
1045  
1046  	/*
1047  	 * first find number of all stats, check they look like stats, & size all associated strings
1048  	 */
1049  	ss = 0;
1050  	n = 0;
1051  	for(i = 0; i < ts; i += m){
1052  		m = BIT16SZ + GBIT16(&buf[i]);
1053  		if(statcheck(&buf[i], m) < 0)
1054  			break;
1055  		ss += m;
1056  		n++;
1057  	}
1058  
1059  	if(i != ts)
1060  		error("bad directory format");
1061  
1062  	*d = malloc(n * sizeof(Dir) + ss);
1063  	if(*d == nil)
1064  		error(Enomem);
1065  
1066  	/*
1067  	 * then convert all buffers
1068  	 */
1069  	s = (char*)*d + n * sizeof(Dir);
1070  	nn = 0;
1071  	for(i = 0; i < ts; i += m){
1072  		m = BIT16SZ + GBIT16((uchar*)&buf[i]);
1073  		if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
1074  			free(*d);
1075  			*d = nil;
1076  			error("bad directory entry");
1077  		}
1078  		nn++;
1079  		s += m;
1080  	}
1081  
1082  	return nn;
1083  }
1084  
1085  long
1086  kdirread(int fd, Dir **d)
1087  {
1088  	uchar *buf;
1089  	long ts;
1090  
1091  	*d = nil;
1092  	if(waserror())
1093  		return -1;
1094  	buf = malloc(DIRREADLIM);
1095  	if(buf == nil)
1096  		error(Enomem);
1097  	if(waserror()){
1098  		free(buf);
1099  		nexterror();
1100  	}
1101  	ts = kread(fd, buf, DIRREADLIM);
1102  	if(ts >= 0)
1103  		ts = dirpackage(buf, ts, d);
1104  	poperror();
1105  	free(buf);
1106  	poperror();
1107  	return ts;
1108  }
1109  
1110  int
1111  kiounit(int fd)
1112  {
1113  	Chan *c;
1114  	int n;
1115  
1116  	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);
1117  	if(waserror()){
1118  		cclose(c);
1119  		return 0;	/* n.b. */
1120  	}
1121  	n = c->iounit;
1122  	poperror();
1123  	cclose(c);
1124  	return n;
1125  }
1126