13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "../port/error.h"
73e12c5d1SDavid du Colombier
83e12c5d1SDavid du Colombier /*
93e12c5d1SDavid du Colombier * The sys*() routines needn't poperror() as they return directly to syscall().
103e12c5d1SDavid du Colombier */
113e12c5d1SDavid du Colombier
12fb7f0c93SDavid du Colombier static void
unlockfgrp(Fgrp * f)13fb7f0c93SDavid du Colombier unlockfgrp(Fgrp *f)
14fb7f0c93SDavid du Colombier {
15fb7f0c93SDavid du Colombier int ex;
16fb7f0c93SDavid du Colombier
17fb7f0c93SDavid du Colombier ex = f->exceed;
18fb7f0c93SDavid du Colombier f->exceed = 0;
19fb7f0c93SDavid du Colombier unlock(f);
20fb7f0c93SDavid du Colombier if(ex)
21fb7f0c93SDavid du Colombier pprint("warning: process exceeds %d file descriptors\n", ex);
22fb7f0c93SDavid du Colombier }
23fb7f0c93SDavid du Colombier
243e12c5d1SDavid du Colombier int
growfd(Fgrp * f,int fd)257dd7cddfSDavid du Colombier growfd(Fgrp *f, int fd) /* fd is always >= 0 */
267dd7cddfSDavid du Colombier {
277dd7cddfSDavid du Colombier Chan **newfd, **oldfd;
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier if(fd < f->nfd)
307dd7cddfSDavid du Colombier return 0;
317dd7cddfSDavid du Colombier if(fd >= f->nfd+DELTAFD)
327dd7cddfSDavid du Colombier return -1; /* out of range */
337dd7cddfSDavid du Colombier /*
344cd3b231SDavid du Colombier * Unbounded allocation is unwise
357dd7cddfSDavid du Colombier */
367dd7cddfSDavid du Colombier if(f->nfd >= 5000){
377dd7cddfSDavid du Colombier Exhausted:
3859cc4ca5SDavid du Colombier print("no free file descriptors\n");
397dd7cddfSDavid du Colombier return -1;
407dd7cddfSDavid du Colombier }
417dd7cddfSDavid du Colombier newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
427dd7cddfSDavid du Colombier if(newfd == 0)
437dd7cddfSDavid du Colombier goto Exhausted;
447dd7cddfSDavid du Colombier oldfd = f->fd;
457dd7cddfSDavid du Colombier memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
467dd7cddfSDavid du Colombier f->fd = newfd;
477dd7cddfSDavid du Colombier free(oldfd);
487dd7cddfSDavid du Colombier f->nfd += DELTAFD;
49fb7f0c93SDavid du Colombier if(fd > f->maxfd){
50fb7f0c93SDavid du Colombier if(fd/100 > f->maxfd/100)
51fb7f0c93SDavid du Colombier f->exceed = (fd/100)*100;
527dd7cddfSDavid du Colombier f->maxfd = fd;
53fb7f0c93SDavid du Colombier }
547dd7cddfSDavid du Colombier return 1;
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier
5759cc4ca5SDavid du Colombier /*
5859cc4ca5SDavid du Colombier * this assumes that the fgrp is locked
5959cc4ca5SDavid du Colombier */
6059cc4ca5SDavid du Colombier int
findfreefd(Fgrp * f,int start)6159cc4ca5SDavid du Colombier findfreefd(Fgrp *f, int start)
6259cc4ca5SDavid du Colombier {
6359cc4ca5SDavid du Colombier int fd;
6459cc4ca5SDavid du Colombier
6559cc4ca5SDavid du Colombier for(fd=start; fd<f->nfd; fd++)
6659cc4ca5SDavid du Colombier if(f->fd[fd] == 0)
6759cc4ca5SDavid du Colombier break;
6859cc4ca5SDavid du Colombier if(fd >= f->nfd && growfd(f, fd) < 0)
6959cc4ca5SDavid du Colombier return -1;
7059cc4ca5SDavid du Colombier return fd;
7159cc4ca5SDavid du Colombier }
7259cc4ca5SDavid du Colombier
737dd7cddfSDavid du Colombier int
newfd(Chan * c)743e12c5d1SDavid du Colombier newfd(Chan *c)
753e12c5d1SDavid du Colombier {
767dd7cddfSDavid du Colombier int fd;
777dd7cddfSDavid du Colombier Fgrp *f;
783e12c5d1SDavid du Colombier
797dd7cddfSDavid du Colombier f = up->fgrp;
803e12c5d1SDavid du Colombier lock(f);
8159cc4ca5SDavid du Colombier fd = findfreefd(f, 0);
8259cc4ca5SDavid du Colombier if(fd < 0){
83fb7f0c93SDavid du Colombier unlockfgrp(f);
847dd7cddfSDavid du Colombier return -1;
853e12c5d1SDavid du Colombier }
867dd7cddfSDavid du Colombier if(fd > f->maxfd)
877dd7cddfSDavid du Colombier f->maxfd = fd;
887dd7cddfSDavid du Colombier f->fd[fd] = c;
89fb7f0c93SDavid du Colombier unlockfgrp(f);
907dd7cddfSDavid du Colombier return fd;
913e12c5d1SDavid du Colombier }
923e12c5d1SDavid du Colombier
9359cc4ca5SDavid du Colombier int
newfd2(int fd[2],Chan * c[2])9459cc4ca5SDavid du Colombier newfd2(int fd[2], Chan *c[2])
9559cc4ca5SDavid du Colombier {
9659cc4ca5SDavid du Colombier Fgrp *f;
9759cc4ca5SDavid du Colombier
9859cc4ca5SDavid du Colombier f = up->fgrp;
9959cc4ca5SDavid du Colombier lock(f);
10059cc4ca5SDavid du Colombier fd[0] = findfreefd(f, 0);
10159cc4ca5SDavid du Colombier if(fd[0] < 0){
102fb7f0c93SDavid du Colombier unlockfgrp(f);
10359cc4ca5SDavid du Colombier return -1;
10459cc4ca5SDavid du Colombier }
10559cc4ca5SDavid du Colombier fd[1] = findfreefd(f, fd[0]+1);
10659cc4ca5SDavid du Colombier if(fd[1] < 0){
107fb7f0c93SDavid du Colombier unlockfgrp(f);
10859cc4ca5SDavid du Colombier return -1;
10959cc4ca5SDavid du Colombier }
11059cc4ca5SDavid du Colombier if(fd[1] > f->maxfd)
11159cc4ca5SDavid du Colombier f->maxfd = fd[1];
11259cc4ca5SDavid du Colombier f->fd[fd[0]] = c[0];
11359cc4ca5SDavid du Colombier f->fd[fd[1]] = c[1];
114fb7f0c93SDavid du Colombier unlockfgrp(f);
11559cc4ca5SDavid du Colombier
11659cc4ca5SDavid du Colombier return 0;
11759cc4ca5SDavid du Colombier }
11859cc4ca5SDavid du Colombier
1193e12c5d1SDavid du Colombier Chan*
fdtochan(int fd,int mode,int chkmnt,int iref)1203e12c5d1SDavid du Colombier fdtochan(int fd, int mode, int chkmnt, int iref)
1213e12c5d1SDavid du Colombier {
1223e12c5d1SDavid du Colombier Chan *c;
1233e12c5d1SDavid du Colombier Fgrp *f;
1243e12c5d1SDavid du Colombier
1253e12c5d1SDavid du Colombier c = 0;
1267dd7cddfSDavid du Colombier f = up->fgrp;
1273e12c5d1SDavid du Colombier
1283e12c5d1SDavid du Colombier lock(f);
1297dd7cddfSDavid du Colombier if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
1303e12c5d1SDavid du Colombier unlock(f);
1313e12c5d1SDavid du Colombier error(Ebadfd);
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier if(iref)
1343e12c5d1SDavid du Colombier incref(c);
1353e12c5d1SDavid du Colombier unlock(f);
1363e12c5d1SDavid du Colombier
1373e12c5d1SDavid du Colombier if(chkmnt && (c->flag&CMSG)) {
1383e12c5d1SDavid du Colombier if(iref)
1397dd7cddfSDavid du Colombier cclose(c);
1403e12c5d1SDavid du Colombier error(Ebadusefd);
1413e12c5d1SDavid du Colombier }
1423e12c5d1SDavid du Colombier
1433e12c5d1SDavid du Colombier if(mode<0 || c->mode==ORDWR)
1443e12c5d1SDavid du Colombier return c;
1453e12c5d1SDavid du Colombier
1463e12c5d1SDavid du Colombier if((mode&OTRUNC) && c->mode==OREAD) {
1473e12c5d1SDavid du Colombier if(iref)
1487dd7cddfSDavid du Colombier cclose(c);
1493e12c5d1SDavid du Colombier error(Ebadusefd);
1503e12c5d1SDavid du Colombier }
1513e12c5d1SDavid du Colombier
1523e12c5d1SDavid du Colombier if((mode&~OTRUNC) != c->mode) {
1533e12c5d1SDavid du Colombier if(iref)
1547dd7cddfSDavid du Colombier cclose(c);
1553e12c5d1SDavid du Colombier error(Ebadusefd);
1563e12c5d1SDavid du Colombier }
1573e12c5d1SDavid du Colombier
1583e12c5d1SDavid du Colombier return c;
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier
1613e12c5d1SDavid du Colombier int
openmode(ulong o)1623e12c5d1SDavid du Colombier openmode(ulong o)
1633e12c5d1SDavid du Colombier {
1643e12c5d1SDavid du Colombier o &= ~(OTRUNC|OCEXEC|ORCLOSE);
1653e12c5d1SDavid du Colombier if(o > OEXEC)
1663e12c5d1SDavid du Colombier error(Ebadarg);
1673e12c5d1SDavid du Colombier if(o == OEXEC)
1683e12c5d1SDavid du Colombier return OREAD;
1693e12c5d1SDavid du Colombier return o;
1703e12c5d1SDavid du Colombier }
1713e12c5d1SDavid du Colombier
1723e12c5d1SDavid du Colombier long
sysfd2path(ulong * arg)1737dd7cddfSDavid du Colombier sysfd2path(ulong *arg)
1747dd7cddfSDavid du Colombier {
1757dd7cddfSDavid du Colombier Chan *c;
1767dd7cddfSDavid du Colombier
1777dd7cddfSDavid du Colombier validaddr(arg[1], arg[2], 1);
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
1804afe124fSDavid du Colombier snprint((char*)arg[1], arg[2], "%s", chanpath(c));
1817dd7cddfSDavid du Colombier cclose(c);
1827dd7cddfSDavid du Colombier return 0;
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier long
syspipe(ulong * arg)1863e12c5d1SDavid du Colombier syspipe(ulong *arg)
1873e12c5d1SDavid du Colombier {
1883e12c5d1SDavid du Colombier int fd[2];
1893e12c5d1SDavid du Colombier Chan *c[2];
1903e12c5d1SDavid du Colombier Dev *d;
1919a747e4fSDavid du Colombier static char *datastr[] = {"data", "data1"};
1923e12c5d1SDavid du Colombier
193fac6300fSDavid du Colombier validaddr(arg[0], sizeof(fd), 1);
194fac6300fSDavid du Colombier validalign(arg[0], sizeof(int));
1957dd7cddfSDavid du Colombier d = devtab[devno('|', 0)];
1967dd7cddfSDavid du Colombier c[0] = namec("#|", Atodir, 0, 0);
1973e12c5d1SDavid du Colombier c[1] = 0;
1983e12c5d1SDavid du Colombier fd[0] = -1;
1993e12c5d1SDavid du Colombier fd[1] = -1;
20059cc4ca5SDavid du Colombier
2013e12c5d1SDavid du Colombier if(waserror()){
2027dd7cddfSDavid du Colombier cclose(c[0]);
2033e12c5d1SDavid du Colombier if(c[1])
2047dd7cddfSDavid du Colombier cclose(c[1]);
2053e12c5d1SDavid du Colombier nexterror();
2063e12c5d1SDavid du Colombier }
2079a747e4fSDavid du Colombier c[1] = cclone(c[0]);
2089a747e4fSDavid du Colombier if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
2097dd7cddfSDavid du Colombier error(Egreg);
2109a747e4fSDavid du Colombier if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
2117dd7cddfSDavid du Colombier error(Egreg);
2127dd7cddfSDavid du Colombier c[0] = d->open(c[0], ORDWR);
2137dd7cddfSDavid du Colombier c[1] = d->open(c[1], ORDWR);
21459cc4ca5SDavid du Colombier if(newfd2(fd, c) < 0)
2157dd7cddfSDavid du Colombier error(Enofd);
21659cc4ca5SDavid du Colombier poperror();
21759cc4ca5SDavid du Colombier
218fac6300fSDavid du Colombier ((int*)arg[0])[0] = fd[0];
219fac6300fSDavid du Colombier ((int*)arg[0])[1] = fd[1];
2203e12c5d1SDavid du Colombier return 0;
2213e12c5d1SDavid du Colombier }
2223e12c5d1SDavid du Colombier
2233e12c5d1SDavid du Colombier long
sysdup(ulong * arg)2243e12c5d1SDavid du Colombier sysdup(ulong *arg)
2253e12c5d1SDavid du Colombier {
2263e12c5d1SDavid du Colombier int fd;
2273e12c5d1SDavid du Colombier Chan *c, *oc;
2287dd7cddfSDavid du Colombier Fgrp *f = up->fgrp;
2293e12c5d1SDavid du Colombier
2303e12c5d1SDavid du Colombier /*
2313e12c5d1SDavid du Colombier * Close after dup'ing, so date > #d/1 works
2323e12c5d1SDavid du Colombier */
2333e12c5d1SDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
2343e12c5d1SDavid du Colombier fd = arg[1];
2353e12c5d1SDavid du Colombier if(fd != -1){
2367dd7cddfSDavid du Colombier lock(f);
2377dd7cddfSDavid du Colombier if(fd<0 || growfd(f, fd)<0) {
238fb7f0c93SDavid du Colombier unlockfgrp(f);
2397dd7cddfSDavid du Colombier cclose(c);
2403e12c5d1SDavid du Colombier error(Ebadfd);
2413e12c5d1SDavid du Colombier }
2423e12c5d1SDavid du Colombier if(fd > f->maxfd)
2433e12c5d1SDavid du Colombier f->maxfd = fd;
2443e12c5d1SDavid du Colombier
2453e12c5d1SDavid du Colombier oc = f->fd[fd];
2463e12c5d1SDavid du Colombier f->fd[fd] = c;
247fb7f0c93SDavid du Colombier unlockfgrp(f);
2483e12c5d1SDavid du Colombier if(oc)
2497dd7cddfSDavid du Colombier cclose(oc);
2503e12c5d1SDavid du Colombier }else{
2513e12c5d1SDavid du Colombier if(waserror()) {
2527dd7cddfSDavid du Colombier cclose(c);
2533e12c5d1SDavid du Colombier nexterror();
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier fd = newfd(c);
2567dd7cddfSDavid du Colombier if(fd < 0)
2577dd7cddfSDavid du Colombier error(Enofd);
2583e12c5d1SDavid du Colombier poperror();
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier
2613e12c5d1SDavid du Colombier return fd;
2623e12c5d1SDavid du Colombier }
2633e12c5d1SDavid du Colombier
2643e12c5d1SDavid du Colombier long
sysopen(ulong * arg)2653e12c5d1SDavid du Colombier sysopen(ulong *arg)
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier int fd;
268d1be6b08SDavid du Colombier Chan *c;
2693e12c5d1SDavid du Colombier
2703e12c5d1SDavid du Colombier openmode(arg[1]); /* error check only */
271d1be6b08SDavid du Colombier validaddr(arg[0], 1, 0);
272d1be6b08SDavid du Colombier c = namec((char*)arg[0], Aopen, arg[1], 0);
2733e12c5d1SDavid du Colombier if(waserror()){
2747dd7cddfSDavid du Colombier cclose(c);
2753e12c5d1SDavid du Colombier nexterror();
2763e12c5d1SDavid du Colombier }
2773e12c5d1SDavid du Colombier fd = newfd(c);
2787dd7cddfSDavid du Colombier if(fd < 0)
2797dd7cddfSDavid du Colombier error(Enofd);
2803e12c5d1SDavid du Colombier poperror();
2813e12c5d1SDavid du Colombier return fd;
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier
2843e12c5d1SDavid du Colombier void
fdclose(int fd,int flag)2853e12c5d1SDavid du Colombier fdclose(int fd, int flag)
2863e12c5d1SDavid du Colombier {
2873e12c5d1SDavid du Colombier int i;
2883e12c5d1SDavid du Colombier Chan *c;
2897dd7cddfSDavid du Colombier Fgrp *f = up->fgrp;
2903e12c5d1SDavid du Colombier
2913e12c5d1SDavid du Colombier lock(f);
2923e12c5d1SDavid du Colombier c = f->fd[fd];
2933e12c5d1SDavid du Colombier if(c == 0){
2943e12c5d1SDavid du Colombier /* can happen for users with shared fd tables */
2953e12c5d1SDavid du Colombier unlock(f);
2963e12c5d1SDavid du Colombier return;
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier if(flag){
2993e12c5d1SDavid du Colombier if(c==0 || !(c->flag&flag)){
3003e12c5d1SDavid du Colombier unlock(f);
3013e12c5d1SDavid du Colombier return;
3023e12c5d1SDavid du Colombier }
3033e12c5d1SDavid du Colombier }
3043e12c5d1SDavid du Colombier f->fd[fd] = 0;
3053e12c5d1SDavid du Colombier if(fd == f->maxfd)
3063e12c5d1SDavid du Colombier for(i=fd; --i>=0 && f->fd[i]==0; )
3073e12c5d1SDavid du Colombier f->maxfd = i;
3083e12c5d1SDavid du Colombier
3093e12c5d1SDavid du Colombier unlock(f);
3107dd7cddfSDavid du Colombier cclose(c);
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier
3133e12c5d1SDavid du Colombier long
sysclose(ulong * arg)3143e12c5d1SDavid du Colombier sysclose(ulong *arg)
3153e12c5d1SDavid du Colombier {
3163e12c5d1SDavid du Colombier fdtochan(arg[0], -1, 0, 0);
3173e12c5d1SDavid du Colombier fdclose(arg[0], 0);
3183e12c5d1SDavid du Colombier
3193e12c5d1SDavid du Colombier return 0;
3203e12c5d1SDavid du Colombier }
3213e12c5d1SDavid du Colombier
3223e12c5d1SDavid du Colombier long
unionread(Chan * c,void * va,long n)3233e12c5d1SDavid du Colombier unionread(Chan *c, void *va, long n)
3243e12c5d1SDavid du Colombier {
3257dd7cddfSDavid du Colombier int i;
3263e12c5d1SDavid du Colombier long nr;
3277dd7cddfSDavid du Colombier Mhead *m;
3287dd7cddfSDavid du Colombier Mount *mount;
3293e12c5d1SDavid du Colombier
3309a747e4fSDavid du Colombier qlock(&c->umqlock);
3319a747e4fSDavid du Colombier m = c->umh;
3327dd7cddfSDavid du Colombier rlock(&m->lock);
3337dd7cddfSDavid du Colombier mount = m->mount;
3349a747e4fSDavid du Colombier /* bring mount in sync with c->uri and c->umc */
3357dd7cddfSDavid du Colombier for(i = 0; mount != nil && i < c->uri; i++)
3367dd7cddfSDavid du Colombier mount = mount->next;
3373e12c5d1SDavid du Colombier
3389a747e4fSDavid du Colombier nr = 0;
3397dd7cddfSDavid du Colombier while(mount != nil){
3407dd7cddfSDavid du Colombier /* Error causes component of union to be skipped */
3419a747e4fSDavid du Colombier if(mount->to && !waserror()){
3429a747e4fSDavid du Colombier if(c->umc == nil){
3439a747e4fSDavid du Colombier c->umc = cclone(mount->to);
3449a747e4fSDavid du Colombier c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier
3479a747e4fSDavid du Colombier nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
3489a747e4fSDavid du Colombier c->umc->offset += nr;
3493e12c5d1SDavid du Colombier poperror();
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier if(nr > 0)
3529a747e4fSDavid du Colombier break;
3533e12c5d1SDavid du Colombier
3549a747e4fSDavid du Colombier /* Advance to next element */
3559a747e4fSDavid du Colombier c->uri++;
3569a747e4fSDavid du Colombier if(c->umc){
3579a747e4fSDavid du Colombier cclose(c->umc);
3589a747e4fSDavid du Colombier c->umc = nil;
3599a747e4fSDavid du Colombier }
3609a747e4fSDavid du Colombier mount = mount->next;
3619a747e4fSDavid du Colombier }
3627dd7cddfSDavid du Colombier runlock(&m->lock);
3639a747e4fSDavid du Colombier qunlock(&c->umqlock);
3643e12c5d1SDavid du Colombier return nr;
3653e12c5d1SDavid du Colombier }
3663e12c5d1SDavid du Colombier
367dc5a79c1SDavid du Colombier static void
unionrewind(Chan * c)368dc5a79c1SDavid du Colombier unionrewind(Chan *c)
369dc5a79c1SDavid du Colombier {
370dc5a79c1SDavid du Colombier qlock(&c->umqlock);
371dc5a79c1SDavid du Colombier c->uri = 0;
372dc5a79c1SDavid du Colombier if(c->umc){
373dc5a79c1SDavid du Colombier cclose(c->umc);
374dc5a79c1SDavid du Colombier c->umc = nil;
375dc5a79c1SDavid du Colombier }
376dc5a79c1SDavid du Colombier qunlock(&c->umqlock);
377dc5a79c1SDavid du Colombier }
378dc5a79c1SDavid du Colombier
379e288d156SDavid du Colombier static int
dirfixed(uchar * p,uchar * e,Dir * d)380e288d156SDavid du Colombier dirfixed(uchar *p, uchar *e, Dir *d)
381dc5a79c1SDavid du Colombier {
382e288d156SDavid du Colombier int len;
383e288d156SDavid du Colombier
384e288d156SDavid du Colombier len = GBIT16(p)+BIT16SZ;
385e288d156SDavid du Colombier if(p + len > e)
386e288d156SDavid du Colombier return -1;
387e288d156SDavid du Colombier
388e288d156SDavid du Colombier p += BIT16SZ; /* ignore size */
389e288d156SDavid du Colombier d->type = devno(GBIT16(p), 1);
390e288d156SDavid du Colombier p += BIT16SZ;
391e288d156SDavid du Colombier d->dev = GBIT32(p);
392dc5a79c1SDavid du Colombier p += BIT32SZ;
393e288d156SDavid du Colombier d->qid.type = GBIT8(p);
394e288d156SDavid du Colombier p += BIT8SZ;
395e288d156SDavid du Colombier d->qid.vers = GBIT32(p);
396e288d156SDavid du Colombier p += BIT32SZ;
397e288d156SDavid du Colombier d->qid.path = GBIT64(p);
398e288d156SDavid du Colombier p += BIT64SZ;
399e288d156SDavid du Colombier d->mode = GBIT32(p);
400e288d156SDavid du Colombier p += BIT32SZ;
401e288d156SDavid du Colombier d->atime = GBIT32(p);
402e288d156SDavid du Colombier p += BIT32SZ;
403e288d156SDavid du Colombier d->mtime = GBIT32(p);
404e288d156SDavid du Colombier p += BIT32SZ;
405e288d156SDavid du Colombier d->length = GBIT64(p);
406e288d156SDavid du Colombier
407e288d156SDavid du Colombier return len;
408dc5a79c1SDavid du Colombier }
409dc5a79c1SDavid du Colombier
410dc5a79c1SDavid du Colombier static char*
dirname(uchar * p,int * n)411dc5a79c1SDavid du Colombier dirname(uchar *p, int *n)
412dc5a79c1SDavid du Colombier {
413dc5a79c1SDavid du Colombier p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
414dc5a79c1SDavid du Colombier + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
415dc5a79c1SDavid du Colombier *n = GBIT16(p);
416dc5a79c1SDavid du Colombier return (char*)p+BIT16SZ;
417dc5a79c1SDavid du Colombier }
418dc5a79c1SDavid du Colombier
419dc5a79c1SDavid du Colombier static long
dirsetname(char * name,int len,uchar * p,long n,long maxn)420dc5a79c1SDavid du Colombier dirsetname(char *name, int len, uchar *p, long n, long maxn)
421dc5a79c1SDavid du Colombier {
422dc5a79c1SDavid du Colombier char *oname;
423dc5a79c1SDavid du Colombier int olen;
424dc5a79c1SDavid du Colombier long nn;
425dc5a79c1SDavid du Colombier
426dc5a79c1SDavid du Colombier if(n == BIT16SZ)
427dc5a79c1SDavid du Colombier return BIT16SZ;
428dc5a79c1SDavid du Colombier
429dc5a79c1SDavid du Colombier oname = dirname(p, &olen);
430dc5a79c1SDavid du Colombier
431dc5a79c1SDavid du Colombier nn = n+len-olen;
432dc5a79c1SDavid du Colombier PBIT16(p, nn-BIT16SZ);
433dc5a79c1SDavid du Colombier if(nn > maxn)
434dc5a79c1SDavid du Colombier return BIT16SZ;
435dc5a79c1SDavid du Colombier
436dc5a79c1SDavid du Colombier if(len != olen)
437dc5a79c1SDavid du Colombier memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
438dc5a79c1SDavid du Colombier PBIT16((uchar*)(oname-2), len);
439dc5a79c1SDavid du Colombier memmove(oname, name, len);
440dc5a79c1SDavid du Colombier return nn;
441dc5a79c1SDavid du Colombier }
442dc5a79c1SDavid du Colombier
443dc5a79c1SDavid du Colombier /*
444dc5a79c1SDavid du Colombier * Mountfix might have caused the fixed results of the directory read
445dc5a79c1SDavid du Colombier * to overflow the buffer. Catch the overflow in c->dirrock.
446dc5a79c1SDavid du Colombier */
447dc5a79c1SDavid du Colombier static void
mountrock(Chan * c,uchar * p,uchar ** pe)448dc5a79c1SDavid du Colombier mountrock(Chan *c, uchar *p, uchar **pe)
449dc5a79c1SDavid du Colombier {
450dc5a79c1SDavid du Colombier uchar *e, *r;
451dc5a79c1SDavid du Colombier int len, n;
452dc5a79c1SDavid du Colombier
453dc5a79c1SDavid du Colombier e = *pe;
454dc5a79c1SDavid du Colombier
455dc5a79c1SDavid du Colombier /* find last directory entry */
456dc5a79c1SDavid du Colombier for(;;){
457dc5a79c1SDavid du Colombier len = BIT16SZ+GBIT16(p);
458dc5a79c1SDavid du Colombier if(p+len >= e)
459dc5a79c1SDavid du Colombier break;
460dc5a79c1SDavid du Colombier p += len;
461dc5a79c1SDavid du Colombier }
462dc5a79c1SDavid du Colombier
463dc5a79c1SDavid du Colombier /* save it away */
464dc5a79c1SDavid du Colombier qlock(&c->rockqlock);
465dc5a79c1SDavid du Colombier if(c->nrock+len > c->mrock){
466dc5a79c1SDavid du Colombier n = ROUND(c->nrock+len, 1024);
467dc5a79c1SDavid du Colombier r = smalloc(n);
468dc5a79c1SDavid du Colombier memmove(r, c->dirrock, c->nrock);
469dc5a79c1SDavid du Colombier free(c->dirrock);
470dc5a79c1SDavid du Colombier c->dirrock = r;
471dc5a79c1SDavid du Colombier c->mrock = n;
472dc5a79c1SDavid du Colombier }
473dc5a79c1SDavid du Colombier memmove(c->dirrock+c->nrock, p, len);
474dc5a79c1SDavid du Colombier c->nrock += len;
475dc5a79c1SDavid du Colombier qunlock(&c->rockqlock);
476dc5a79c1SDavid du Colombier
477dc5a79c1SDavid du Colombier /* drop it */
478dc5a79c1SDavid du Colombier *pe = p;
479dc5a79c1SDavid du Colombier }
480dc5a79c1SDavid du Colombier
481dc5a79c1SDavid du Colombier /*
482dc5a79c1SDavid du Colombier * Satisfy a directory read with the results saved in c->dirrock.
483dc5a79c1SDavid du Colombier */
484dc5a79c1SDavid du Colombier static int
mountrockread(Chan * c,uchar * op,long n,long * nn)485dc5a79c1SDavid du Colombier mountrockread(Chan *c, uchar *op, long n, long *nn)
486dc5a79c1SDavid du Colombier {
487dc5a79c1SDavid du Colombier long dirlen;
488dc5a79c1SDavid du Colombier uchar *rp, *erp, *ep, *p;
489dc5a79c1SDavid du Colombier
490dc5a79c1SDavid du Colombier /* common case */
491dc5a79c1SDavid du Colombier if(c->nrock == 0)
492dc5a79c1SDavid du Colombier return 0;
493dc5a79c1SDavid du Colombier
494dc5a79c1SDavid du Colombier /* copy out what we can */
495dc5a79c1SDavid du Colombier qlock(&c->rockqlock);
496dc5a79c1SDavid du Colombier rp = c->dirrock;
497dc5a79c1SDavid du Colombier erp = rp+c->nrock;
498dc5a79c1SDavid du Colombier p = op;
499dc5a79c1SDavid du Colombier ep = p+n;
500dc5a79c1SDavid du Colombier while(rp+BIT16SZ <= erp){
501dc5a79c1SDavid du Colombier dirlen = BIT16SZ+GBIT16(rp);
502dc5a79c1SDavid du Colombier if(p+dirlen > ep)
503dc5a79c1SDavid du Colombier break;
504dc5a79c1SDavid du Colombier memmove(p, rp, dirlen);
505dc5a79c1SDavid du Colombier p += dirlen;
506dc5a79c1SDavid du Colombier rp += dirlen;
507dc5a79c1SDavid du Colombier }
508dc5a79c1SDavid du Colombier
509dc5a79c1SDavid du Colombier if(p == op){
510dc5a79c1SDavid du Colombier qunlock(&c->rockqlock);
511dc5a79c1SDavid du Colombier return 0;
512dc5a79c1SDavid du Colombier }
513dc5a79c1SDavid du Colombier
514dc5a79c1SDavid du Colombier /* shift the rest */
515dc5a79c1SDavid du Colombier if(rp != erp)
516dc5a79c1SDavid du Colombier memmove(c->dirrock, rp, erp-rp);
517dc5a79c1SDavid du Colombier c->nrock = erp - rp;
518dc5a79c1SDavid du Colombier
519dc5a79c1SDavid du Colombier *nn = p - op;
520dc5a79c1SDavid du Colombier qunlock(&c->rockqlock);
521dc5a79c1SDavid du Colombier return 1;
522dc5a79c1SDavid du Colombier }
523dc5a79c1SDavid du Colombier
524dc5a79c1SDavid du Colombier static void
mountrewind(Chan * c)525dc5a79c1SDavid du Colombier mountrewind(Chan *c)
526dc5a79c1SDavid du Colombier {
527dc5a79c1SDavid du Colombier c->nrock = 0;
528dc5a79c1SDavid du Colombier }
529dc5a79c1SDavid du Colombier
530dc5a79c1SDavid du Colombier /*
531dc5a79c1SDavid du Colombier * Rewrite the results of a directory read to reflect current
532dc5a79c1SDavid du Colombier * name space bindings and mounts. Specifically, replace
533dc5a79c1SDavid du Colombier * directory entries for bind and mount points with the results
534dc5a79c1SDavid du Colombier * of statting what is mounted there. Except leave the old names.
535dc5a79c1SDavid du Colombier */
536dc5a79c1SDavid du Colombier static long
mountfix(Chan * c,uchar * op,long n,long maxn)537dc5a79c1SDavid du Colombier mountfix(Chan *c, uchar *op, long n, long maxn)
538dc5a79c1SDavid du Colombier {
539dc5a79c1SDavid du Colombier char *name;
540dc5a79c1SDavid du Colombier int nbuf, nname;
541dc5a79c1SDavid du Colombier Chan *nc;
542dc5a79c1SDavid du Colombier Mhead *mh;
543dc5a79c1SDavid du Colombier Mount *m;
544dc5a79c1SDavid du Colombier uchar *p;
545dc5a79c1SDavid du Colombier int dirlen, rest;
546dc5a79c1SDavid du Colombier long l;
547dc5a79c1SDavid du Colombier uchar *buf, *e;
548e288d156SDavid du Colombier Dir d;
549dc5a79c1SDavid du Colombier
550dc5a79c1SDavid du Colombier p = op;
551dc5a79c1SDavid du Colombier buf = nil;
552dc5a79c1SDavid du Colombier nbuf = 0;
553dc5a79c1SDavid du Colombier for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
554e288d156SDavid du Colombier dirlen = dirfixed(p, e, &d);
555e288d156SDavid du Colombier if(dirlen < 0)
556dc5a79c1SDavid du Colombier break;
557dc5a79c1SDavid du Colombier nc = nil;
558dc5a79c1SDavid du Colombier mh = nil;
559e288d156SDavid du Colombier if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
560dc5a79c1SDavid du Colombier /*
561dc5a79c1SDavid du Colombier * If it's a union directory and the original is
562dc5a79c1SDavid du Colombier * in the union, don't rewrite anything.
563dc5a79c1SDavid du Colombier */
564dc5a79c1SDavid du Colombier for(m=mh->mount; m; m=m->next)
565e288d156SDavid du Colombier if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
566dc5a79c1SDavid du Colombier goto Norewrite;
567dc5a79c1SDavid du Colombier
568dc5a79c1SDavid du Colombier name = dirname(p, &nname);
569dc5a79c1SDavid du Colombier /*
570dc5a79c1SDavid du Colombier * Do the stat but fix the name. If it fails, leave old entry.
571dc5a79c1SDavid du Colombier * BUG: If it fails because there isn't room for the entry,
572dc5a79c1SDavid du Colombier * what can we do? Nothing, really. Might as well skip it.
573dc5a79c1SDavid du Colombier */
574dc5a79c1SDavid du Colombier if(buf == nil){
575dc5a79c1SDavid du Colombier buf = smalloc(4096);
576dc5a79c1SDavid du Colombier nbuf = 4096;
577dc5a79c1SDavid du Colombier }
578dc5a79c1SDavid du Colombier if(waserror())
579dc5a79c1SDavid du Colombier goto Norewrite;
580dc5a79c1SDavid du Colombier l = devtab[nc->type]->stat(nc, buf, nbuf);
581dc5a79c1SDavid du Colombier l = dirsetname(name, nname, buf, l, nbuf);
582dc5a79c1SDavid du Colombier if(l == BIT16SZ)
5834b348146SDavid du Colombier error("dirsetname");
584dc5a79c1SDavid du Colombier poperror();
585dc5a79c1SDavid du Colombier
586dc5a79c1SDavid du Colombier /*
587dc5a79c1SDavid du Colombier * Shift data in buffer to accomodate new entry,
588dc5a79c1SDavid du Colombier * possibly overflowing into rock.
589dc5a79c1SDavid du Colombier */
590dc5a79c1SDavid du Colombier rest = e - (p+dirlen);
591dc5a79c1SDavid du Colombier if(l > dirlen){
592dc5a79c1SDavid du Colombier while(p+l+rest > op+maxn){
593dc5a79c1SDavid du Colombier mountrock(c, p, &e);
594dc5a79c1SDavid du Colombier if(e == p){
595dc5a79c1SDavid du Colombier dirlen = 0;
596dc5a79c1SDavid du Colombier goto Norewrite;
597dc5a79c1SDavid du Colombier }
598dc5a79c1SDavid du Colombier rest = e - (p+dirlen);
599dc5a79c1SDavid du Colombier }
600dc5a79c1SDavid du Colombier }
601dc5a79c1SDavid du Colombier if(l != dirlen){
602dc5a79c1SDavid du Colombier memmove(p+l, p+dirlen, rest);
603dc5a79c1SDavid du Colombier dirlen = l;
604dc5a79c1SDavid du Colombier e = p+dirlen+rest;
605dc5a79c1SDavid du Colombier }
606dc5a79c1SDavid du Colombier
607dc5a79c1SDavid du Colombier /*
608dc5a79c1SDavid du Colombier * Rewrite directory entry.
609dc5a79c1SDavid du Colombier */
610dc5a79c1SDavid du Colombier memmove(p, buf, l);
611dc5a79c1SDavid du Colombier
612dc5a79c1SDavid du Colombier Norewrite:
613dc5a79c1SDavid du Colombier cclose(nc);
614dc5a79c1SDavid du Colombier putmhead(mh);
615dc5a79c1SDavid du Colombier }
616dc5a79c1SDavid du Colombier }
617dc5a79c1SDavid du Colombier if(buf)
618dc5a79c1SDavid du Colombier free(buf);
619dc5a79c1SDavid du Colombier
620dc5a79c1SDavid du Colombier if(p != e)
621dc5a79c1SDavid du Colombier error("oops in rockfix");
622dc5a79c1SDavid du Colombier
623dc5a79c1SDavid du Colombier return e-op;
624dc5a79c1SDavid du Colombier }
625dc5a79c1SDavid du Colombier
6269a747e4fSDavid du Colombier static long
read(ulong * arg,vlong * offp)6279a747e4fSDavid du Colombier read(ulong *arg, vlong *offp)
6283e12c5d1SDavid du Colombier {
629dc5a79c1SDavid du Colombier long n, nn, nnn;
630dc5a79c1SDavid du Colombier uchar *p;
6313e12c5d1SDavid du Colombier Chan *c;
6329a747e4fSDavid du Colombier vlong off;
6337dd7cddfSDavid du Colombier
6347dd7cddfSDavid du Colombier n = arg[2];
6357dd7cddfSDavid du Colombier validaddr(arg[1], n, 1);
636dc5a79c1SDavid du Colombier p = (void*)arg[1];
6377dd7cddfSDavid du Colombier c = fdtochan(arg[0], OREAD, 1, 1);
6387dd7cddfSDavid du Colombier
6397dd7cddfSDavid du Colombier if(waserror()){
6407dd7cddfSDavid du Colombier cclose(c);
6417dd7cddfSDavid du Colombier nexterror();
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier
6449a747e4fSDavid du Colombier /*
645dc5a79c1SDavid du Colombier * The offset is passed through on directories, normally.
646dc5a79c1SDavid du Colombier * Sysseek complains, but pread is used by servers like exportfs,
647dc5a79c1SDavid du Colombier * that shouldn't need to worry about this issue.
648dc5a79c1SDavid du Colombier *
649dc5a79c1SDavid du Colombier * Notice that c->devoffset is the offset that c's dev is seeing.
650dc5a79c1SDavid du Colombier * The number of bytes read on this fd (c->offset) may be different
651dc5a79c1SDavid du Colombier * due to rewritings in rockfix.
6529a747e4fSDavid du Colombier */
6539a747e4fSDavid du Colombier if(offp == nil) /* use and maintain channel's offset */
6549a747e4fSDavid du Colombier off = c->offset;
6559a747e4fSDavid du Colombier else
6569a747e4fSDavid du Colombier off = *offp;
6579a747e4fSDavid du Colombier if(off < 0)
6589a747e4fSDavid du Colombier error(Enegoff);
6599a747e4fSDavid du Colombier
660dc5a79c1SDavid du Colombier if(off == 0){ /* rewind to the beginning of the directory */
6619a747e4fSDavid du Colombier if(offp == nil){
662dc5a79c1SDavid du Colombier c->offset = 0;
663dc5a79c1SDavid du Colombier c->devoffset = 0;
6649a747e4fSDavid du Colombier }
665dc5a79c1SDavid du Colombier mountrewind(c);
666dc5a79c1SDavid du Colombier unionrewind(c);
667dc5a79c1SDavid du Colombier }
668dc5a79c1SDavid du Colombier
66960441a25SDavid du Colombier if(c->qid.type & QTDIR){
67060441a25SDavid du Colombier if(mountrockread(c, p, n, &nn)){
671dc5a79c1SDavid du Colombier /* do nothing: mountrockread filled buffer */
67260441a25SDavid du Colombier }else if(c->umh)
673dc5a79c1SDavid du Colombier nn = unionread(c, p, n);
67460441a25SDavid du Colombier else{
67560441a25SDavid du Colombier if(off != c->offset)
67660441a25SDavid du Colombier error(Edirseek);
67760441a25SDavid du Colombier nn = devtab[c->type]->read(c, p, n, c->devoffset);
678dc5a79c1SDavid du Colombier }
679dc5a79c1SDavid du Colombier nnn = mountfix(c, p, nn, n);
68060441a25SDavid du Colombier }else
68160441a25SDavid du Colombier nnn = nn = devtab[c->type]->read(c, p, n, off);
682dc5a79c1SDavid du Colombier
6833aaea915SDavid du Colombier if(c->qid.type & QTDIR || offp == nil){
684dc5a79c1SDavid du Colombier lock(c);
685dc5a79c1SDavid du Colombier c->devoffset += nn;
686dc5a79c1SDavid du Colombier c->offset += nnn;
687dc5a79c1SDavid du Colombier unlock(c);
6883aaea915SDavid du Colombier }
6897dd7cddfSDavid du Colombier
6907dd7cddfSDavid du Colombier poperror();
6917dd7cddfSDavid du Colombier cclose(c);
6927dd7cddfSDavid du Colombier
693dc5a79c1SDavid du Colombier return nnn;
6947dd7cddfSDavid du Colombier }
6957dd7cddfSDavid du Colombier
6967dd7cddfSDavid du Colombier long
sys_read(ulong * arg)6979a747e4fSDavid du Colombier sys_read(ulong *arg)
6989a747e4fSDavid du Colombier {
6999a747e4fSDavid du Colombier return read(arg, nil);
7009a747e4fSDavid du Colombier }
7019a747e4fSDavid du Colombier
7029a747e4fSDavid du Colombier long
syspread(ulong * arg)70380ee5cbfSDavid du Colombier syspread(ulong *arg)
70480ee5cbfSDavid du Colombier {
7059a747e4fSDavid du Colombier vlong v;
7069a747e4fSDavid du Colombier va_list list;
70780ee5cbfSDavid du Colombier
7089a747e4fSDavid du Colombier /* use varargs to guarantee alignment of vlong */
7099a747e4fSDavid du Colombier va_start(list, arg[2]);
7109a747e4fSDavid du Colombier v = va_arg(list, vlong);
7119a747e4fSDavid du Colombier va_end(list);
71280ee5cbfSDavid du Colombier
7139a747e4fSDavid du Colombier if(v == ~0ULL)
7149a747e4fSDavid du Colombier return read(arg, nil);
7159a747e4fSDavid du Colombier
7169a747e4fSDavid du Colombier return read(arg, &v);
71780ee5cbfSDavid du Colombier }
71880ee5cbfSDavid du Colombier
7199a747e4fSDavid du Colombier static long
write(ulong * arg,vlong * offp)7209a747e4fSDavid du Colombier write(ulong *arg, vlong *offp)
7213e12c5d1SDavid du Colombier {
7223e12c5d1SDavid du Colombier Chan *c;
7237dd7cddfSDavid du Colombier long m, n;
7249a747e4fSDavid du Colombier vlong off;
7253e12c5d1SDavid du Colombier
7263e12c5d1SDavid du Colombier validaddr(arg[1], arg[2], 0);
7279a747e4fSDavid du Colombier n = 0;
7283e12c5d1SDavid du Colombier c = fdtochan(arg[0], OWRITE, 1, 1);
7293e12c5d1SDavid du Colombier if(waserror()) {
7309a747e4fSDavid du Colombier if(offp == nil){
7317dd7cddfSDavid du Colombier lock(c);
7327dd7cddfSDavid du Colombier c->offset -= n;
7337dd7cddfSDavid du Colombier unlock(c);
7349a747e4fSDavid du Colombier }
7359a747e4fSDavid du Colombier cclose(c);
7363e12c5d1SDavid du Colombier nexterror();
7373e12c5d1SDavid du Colombier }
7383e12c5d1SDavid du Colombier
7399a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
7403e12c5d1SDavid du Colombier error(Eisdir);
7413e12c5d1SDavid du Colombier
7429a747e4fSDavid du Colombier n = arg[2];
7439a747e4fSDavid du Colombier
7449a747e4fSDavid du Colombier if(offp == nil){ /* use and maintain channel's offset */
7453e12c5d1SDavid du Colombier lock(c);
7469a747e4fSDavid du Colombier off = c->offset;
7473e12c5d1SDavid du Colombier c->offset += n;
7483e12c5d1SDavid du Colombier unlock(c);
7499a747e4fSDavid du Colombier }else
7509a747e4fSDavid du Colombier off = *offp;
7513e12c5d1SDavid du Colombier
7529a747e4fSDavid du Colombier if(off < 0)
7539a747e4fSDavid du Colombier error(Enegoff);
7543e12c5d1SDavid du Colombier
7559a747e4fSDavid du Colombier m = devtab[c->type]->write(c, (void*)arg[1], n, off);
7569a747e4fSDavid du Colombier
7579a747e4fSDavid du Colombier if(offp == nil && m < n){
7587dd7cddfSDavid du Colombier lock(c);
7597dd7cddfSDavid du Colombier c->offset -= n - m;
7607dd7cddfSDavid du Colombier unlock(c);
7617dd7cddfSDavid du Colombier }
7627dd7cddfSDavid du Colombier
7637dd7cddfSDavid du Colombier poperror();
7647dd7cddfSDavid du Colombier cclose(c);
7657dd7cddfSDavid du Colombier
7667dd7cddfSDavid du Colombier return m;
7677dd7cddfSDavid du Colombier }
7687dd7cddfSDavid du Colombier
76980ee5cbfSDavid du Colombier long
sys_write(ulong * arg)7709a747e4fSDavid du Colombier sys_write(ulong *arg)
77180ee5cbfSDavid du Colombier {
7729a747e4fSDavid du Colombier return write(arg, nil);
77380ee5cbfSDavid du Colombier }
77480ee5cbfSDavid du Colombier
7759a747e4fSDavid du Colombier long
syspwrite(ulong * arg)7769a747e4fSDavid du Colombier syspwrite(ulong *arg)
7779a747e4fSDavid du Colombier {
7789a747e4fSDavid du Colombier vlong v;
7799a747e4fSDavid du Colombier va_list list;
78080ee5cbfSDavid du Colombier
7819a747e4fSDavid du Colombier /* use varargs to guarantee alignment of vlong */
7829a747e4fSDavid du Colombier va_start(list, arg[2]);
7839a747e4fSDavid du Colombier v = va_arg(list, vlong);
7849a747e4fSDavid du Colombier va_end(list);
78580ee5cbfSDavid du Colombier
7869a747e4fSDavid du Colombier if(v == ~0ULL)
7879a747e4fSDavid du Colombier return write(arg, nil);
78880ee5cbfSDavid du Colombier
7899a747e4fSDavid du Colombier return write(arg, &v);
79080ee5cbfSDavid du Colombier }
79180ee5cbfSDavid du Colombier
7927dd7cddfSDavid du Colombier static void
sseek(ulong * arg)7937dd7cddfSDavid du Colombier sseek(ulong *arg)
7947dd7cddfSDavid du Colombier {
7957dd7cddfSDavid du Colombier Chan *c;
7969a747e4fSDavid du Colombier uchar buf[sizeof(Dir)+100];
7977dd7cddfSDavid du Colombier Dir dir;
7989a747e4fSDavid du Colombier int n;
7997dd7cddfSDavid du Colombier vlong off;
8007dd7cddfSDavid du Colombier union {
8017dd7cddfSDavid du Colombier vlong v;
8027dd7cddfSDavid du Colombier ulong u[2];
8037dd7cddfSDavid du Colombier } o;
8047dd7cddfSDavid du Colombier
8057dd7cddfSDavid du Colombier c = fdtochan(arg[1], -1, 1, 1);
8067dd7cddfSDavid du Colombier if(waserror()){
8077dd7cddfSDavid du Colombier cclose(c);
8087dd7cddfSDavid du Colombier nexterror();
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier if(devtab[c->type]->dc == '|')
8117dd7cddfSDavid du Colombier error(Eisstream);
8127dd7cddfSDavid du Colombier
8137dd7cddfSDavid du Colombier off = 0;
8147dd7cddfSDavid du Colombier o.u[0] = arg[2];
8157dd7cddfSDavid du Colombier o.u[1] = arg[3];
8167dd7cddfSDavid du Colombier switch(arg[4]){
8177dd7cddfSDavid du Colombier case 0:
8187dd7cddfSDavid du Colombier off = o.v;
8199a747e4fSDavid du Colombier if((c->qid.type & QTDIR) && off != 0)
8209a747e4fSDavid du Colombier error(Eisdir);
8219a747e4fSDavid du Colombier if(off < 0)
8229a747e4fSDavid du Colombier error(Enegoff);
8237dd7cddfSDavid du Colombier c->offset = off;
8247dd7cddfSDavid du Colombier break;
8257dd7cddfSDavid du Colombier
8267dd7cddfSDavid du Colombier case 1:
8279a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
8289a747e4fSDavid du Colombier error(Eisdir);
8297dd7cddfSDavid du Colombier lock(c); /* lock for read/write update */
8307dd7cddfSDavid du Colombier off = o.v + c->offset;
8312a034d96SDavid du Colombier if(off < 0){
8322a034d96SDavid du Colombier unlock(c);
8339a747e4fSDavid du Colombier error(Enegoff);
8342a034d96SDavid du Colombier }
8357dd7cddfSDavid du Colombier c->offset = off;
8367dd7cddfSDavid du Colombier unlock(c);
8377dd7cddfSDavid du Colombier break;
8387dd7cddfSDavid du Colombier
8397dd7cddfSDavid du Colombier case 2:
8409a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
8419a747e4fSDavid du Colombier error(Eisdir);
8429a747e4fSDavid du Colombier n = devtab[c->type]->stat(c, buf, sizeof buf);
8439a747e4fSDavid du Colombier if(convM2D(buf, n, &dir, nil) == 0)
8449a747e4fSDavid du Colombier error("internal error: stat error in seek");
8457dd7cddfSDavid du Colombier off = dir.length + o.v;
8469a747e4fSDavid du Colombier if(off < 0)
8479a747e4fSDavid du Colombier error(Enegoff);
8487dd7cddfSDavid du Colombier c->offset = off;
8497dd7cddfSDavid du Colombier break;
8509a747e4fSDavid du Colombier
8519a747e4fSDavid du Colombier default:
8529a747e4fSDavid du Colombier error(Ebadarg);
8537dd7cddfSDavid du Colombier }
8547dd7cddfSDavid du Colombier *(vlong*)arg[0] = off;
8557dd7cddfSDavid du Colombier c->uri = 0;
8569a747e4fSDavid du Colombier c->dri = 0;
8577dd7cddfSDavid du Colombier cclose(c);
8587dd7cddfSDavid du Colombier poperror();
8593e12c5d1SDavid du Colombier }
8603e12c5d1SDavid du Colombier
8613e12c5d1SDavid du Colombier long
sysseek(ulong * arg)8623e12c5d1SDavid du Colombier sysseek(ulong *arg)
8633e12c5d1SDavid du Colombier {
864fac6300fSDavid du Colombier validaddr(arg[0], sizeof(vlong), 1);
865fac6300fSDavid du Colombier validalign(arg[0], sizeof(vlong));
8667dd7cddfSDavid du Colombier sseek(arg);
8677dd7cddfSDavid du Colombier return 0;
8683e12c5d1SDavid du Colombier }
8697dd7cddfSDavid du Colombier
8707dd7cddfSDavid du Colombier long
sysoseek(ulong * arg)8717dd7cddfSDavid du Colombier sysoseek(ulong *arg)
8727dd7cddfSDavid du Colombier {
8737dd7cddfSDavid du Colombier union {
8747dd7cddfSDavid du Colombier vlong v;
8757dd7cddfSDavid du Colombier ulong u[2];
8767dd7cddfSDavid du Colombier } o;
8777dd7cddfSDavid du Colombier ulong a[5];
8787dd7cddfSDavid du Colombier
87980ee5cbfSDavid du Colombier o.v = (long)arg[1];
8807dd7cddfSDavid du Colombier a[0] = (ulong)&o.v;
8817dd7cddfSDavid du Colombier a[1] = arg[0];
8827dd7cddfSDavid du Colombier a[2] = o.u[0];
8837dd7cddfSDavid du Colombier a[3] = o.u[1];
8847dd7cddfSDavid du Colombier a[4] = arg[2];
8857dd7cddfSDavid du Colombier sseek(a);
8867dd7cddfSDavid du Colombier return o.v;
8873e12c5d1SDavid du Colombier }
8883e12c5d1SDavid du Colombier
8899a747e4fSDavid du Colombier void
validstat(uchar * s,int n)8909a747e4fSDavid du Colombier validstat(uchar *s, int n)
8919a747e4fSDavid du Colombier {
8929a747e4fSDavid du Colombier int m;
8939a747e4fSDavid du Colombier char buf[64];
8949a747e4fSDavid du Colombier
8959a747e4fSDavid du Colombier if(statcheck(s, n) < 0)
8969a747e4fSDavid du Colombier error(Ebadstat);
8979a747e4fSDavid du Colombier /* verify that name entry is acceptable */
8989a747e4fSDavid du Colombier s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
8999a747e4fSDavid du Colombier /*
9009a747e4fSDavid du Colombier * s now points at count for first string.
9019a747e4fSDavid du Colombier * if it's too long, let the server decide; this is
9029a747e4fSDavid du Colombier * only for his protection anyway. otherwise
9039a747e4fSDavid du Colombier * we'd have to allocate and waserror.
9049a747e4fSDavid du Colombier */
9059a747e4fSDavid du Colombier m = GBIT16(s);
9069a747e4fSDavid du Colombier s += BIT16SZ;
9079a747e4fSDavid du Colombier if(m+1 > sizeof buf)
9089a747e4fSDavid du Colombier return;
9099a747e4fSDavid du Colombier memmove(buf, s, m);
9109a747e4fSDavid du Colombier buf[m] = '\0';
9119a747e4fSDavid du Colombier /* name could be '/' */
9129a747e4fSDavid du Colombier if(strcmp(buf, "/") != 0)
9139a747e4fSDavid du Colombier validname(buf, 0);
9149a747e4fSDavid du Colombier }
9159a747e4fSDavid du Colombier
916dc5a79c1SDavid du Colombier static char*
pathlast(Path * p)9174afe124fSDavid du Colombier pathlast(Path *p)
918dc5a79c1SDavid du Colombier {
919dc5a79c1SDavid du Colombier char *s;
920dc5a79c1SDavid du Colombier
9214afe124fSDavid du Colombier if(p == nil)
922dc5a79c1SDavid du Colombier return nil;
9234afe124fSDavid du Colombier if(p->len == 0)
924dc5a79c1SDavid du Colombier return nil;
9254afe124fSDavid du Colombier s = strrchr(p->s, '/');
926dc5a79c1SDavid du Colombier if(s)
927dc5a79c1SDavid du Colombier return s+1;
9284afe124fSDavid du Colombier return p->s;
929dc5a79c1SDavid du Colombier }
930dc5a79c1SDavid du Colombier
9313e12c5d1SDavid du Colombier long
sysfstat(ulong * arg)9323e12c5d1SDavid du Colombier sysfstat(ulong *arg)
9333e12c5d1SDavid du Colombier {
9343e12c5d1SDavid du Colombier Chan *c;
9359a747e4fSDavid du Colombier uint l;
9363e12c5d1SDavid du Colombier
9379a747e4fSDavid du Colombier l = arg[2];
9389a747e4fSDavid du Colombier validaddr(arg[1], l, 1);
9393e12c5d1SDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
9403e12c5d1SDavid du Colombier if(waserror()) {
9417dd7cddfSDavid du Colombier cclose(c);
9423e12c5d1SDavid du Colombier nexterror();
9433e12c5d1SDavid du Colombier }
9449a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
9453e12c5d1SDavid du Colombier poperror();
9467dd7cddfSDavid du Colombier cclose(c);
9479a747e4fSDavid du Colombier return l;
9483e12c5d1SDavid du Colombier }
9493e12c5d1SDavid du Colombier
9503e12c5d1SDavid du Colombier long
sysstat(ulong * arg)9513e12c5d1SDavid du Colombier sysstat(ulong *arg)
9523e12c5d1SDavid du Colombier {
953dc5a79c1SDavid du Colombier char *name;
9543e12c5d1SDavid du Colombier Chan *c;
9559a747e4fSDavid du Colombier uint l;
9563e12c5d1SDavid du Colombier
9579a747e4fSDavid du Colombier l = arg[2];
9589a747e4fSDavid du Colombier validaddr(arg[1], l, 1);
9593e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
9603e12c5d1SDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
9613e12c5d1SDavid du Colombier if(waserror()){
9627dd7cddfSDavid du Colombier cclose(c);
9633e12c5d1SDavid du Colombier nexterror();
9643e12c5d1SDavid du Colombier }
9659a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
9664afe124fSDavid du Colombier name = pathlast(c->path);
967dc5a79c1SDavid du Colombier if(name)
968dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
969dc5a79c1SDavid du Colombier
9703e12c5d1SDavid du Colombier poperror();
9717dd7cddfSDavid du Colombier cclose(c);
9729a747e4fSDavid du Colombier return l;
9733e12c5d1SDavid du Colombier }
9743e12c5d1SDavid du Colombier
9753e12c5d1SDavid du Colombier long
syschdir(ulong * arg)9763e12c5d1SDavid du Colombier syschdir(ulong *arg)
9773e12c5d1SDavid du Colombier {
9783e12c5d1SDavid du Colombier Chan *c;
9793e12c5d1SDavid du Colombier
9803e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
9817dd7cddfSDavid du Colombier
9823e12c5d1SDavid du Colombier c = namec((char*)arg[0], Atodir, 0, 0);
9837dd7cddfSDavid du Colombier cclose(up->dot);
9847dd7cddfSDavid du Colombier up->dot = c;
9853e12c5d1SDavid du Colombier return 0;
9863e12c5d1SDavid du Colombier }
9873e12c5d1SDavid du Colombier
9883e12c5d1SDavid du Colombier long
bindmount(int ismount,int fd,int afd,char * arg0,char * arg1,ulong flag,char * spec)9899a747e4fSDavid du Colombier bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
9903e12c5d1SDavid du Colombier {
9919a747e4fSDavid du Colombier int ret;
9929a747e4fSDavid du Colombier Chan *c0, *c1, *ac, *bc;
9933e12c5d1SDavid du Colombier struct{
9943e12c5d1SDavid du Colombier Chan *chan;
9959a747e4fSDavid du Colombier Chan *authchan;
9963e12c5d1SDavid du Colombier char *spec;
9977dd7cddfSDavid du Colombier int flags;
9983e12c5d1SDavid du Colombier }bogus;
9993e12c5d1SDavid du Colombier
10009a747e4fSDavid du Colombier if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
10013e12c5d1SDavid du Colombier error(Ebadarg);
10027dd7cddfSDavid du Colombier
10033e12c5d1SDavid du Colombier if(ismount){
1004d1be6b08SDavid du Colombier validaddr((ulong)spec, 1, 0);
1005d1be6b08SDavid du Colombier spec = validnamedup(spec, 1);
1006d1be6b08SDavid du Colombier if(waserror()){
1007d1be6b08SDavid du Colombier free(spec);
1008d1be6b08SDavid du Colombier nexterror();
1009d1be6b08SDavid du Colombier }
1010d1be6b08SDavid du Colombier
10117dd7cddfSDavid du Colombier if(up->pgrp->noattach)
10127dd7cddfSDavid du Colombier error(Enoattach);
10137dd7cddfSDavid du Colombier
10149a747e4fSDavid du Colombier ac = nil;
10157dd7cddfSDavid du Colombier bc = fdtochan(fd, ORDWR, 0, 1);
10163e12c5d1SDavid du Colombier if(waserror()) {
10179a747e4fSDavid du Colombier if(ac)
10189a747e4fSDavid du Colombier cclose(ac);
10197dd7cddfSDavid du Colombier cclose(bc);
10203e12c5d1SDavid du Colombier nexterror();
10213e12c5d1SDavid du Colombier }
10229a747e4fSDavid du Colombier
10239a747e4fSDavid du Colombier if(afd >= 0)
10249a747e4fSDavid du Colombier ac = fdtochan(afd, ORDWR, 0, 1);
10259a747e4fSDavid du Colombier
1026d1be6b08SDavid du Colombier bogus.flags = flag & MCACHE;
10273e12c5d1SDavid du Colombier bogus.chan = bc;
10289a747e4fSDavid du Colombier bogus.authchan = ac;
10299a747e4fSDavid du Colombier bogus.spec = spec;
10303e12c5d1SDavid du Colombier ret = devno('M', 0);
10317dd7cddfSDavid du Colombier c0 = devtab[ret]->attach((char*)&bogus);
10322db064f5SDavid du Colombier poperror(); /* ac bc */
10339a747e4fSDavid du Colombier if(ac)
10349a747e4fSDavid du Colombier cclose(ac);
10357dd7cddfSDavid du Colombier cclose(bc);
10369a747e4fSDavid du Colombier }else{
1037d1be6b08SDavid du Colombier spec = 0;
10389a747e4fSDavid du Colombier validaddr((ulong)arg0, 1, 0);
10399a747e4fSDavid du Colombier c0 = namec(arg0, Abind, 0, 0);
10403e12c5d1SDavid du Colombier }
10417dd7cddfSDavid du Colombier
10423e12c5d1SDavid du Colombier if(waserror()){
10437dd7cddfSDavid du Colombier cclose(c0);
10443e12c5d1SDavid du Colombier nexterror();
10453e12c5d1SDavid du Colombier }
10467dd7cddfSDavid du Colombier
10479a747e4fSDavid du Colombier validaddr((ulong)arg1, 1, 0);
10489a747e4fSDavid du Colombier c1 = namec(arg1, Amount, 0, 0);
10493e12c5d1SDavid du Colombier if(waserror()){
10507dd7cddfSDavid du Colombier cclose(c1);
10513e12c5d1SDavid du Colombier nexterror();
10523e12c5d1SDavid du Colombier }
10537dd7cddfSDavid du Colombier
1054d1be6b08SDavid du Colombier ret = cmount(&c0, c1, flag, spec);
10557dd7cddfSDavid du Colombier
10563e12c5d1SDavid du Colombier poperror();
10577dd7cddfSDavid du Colombier cclose(c1);
10583e12c5d1SDavid du Colombier poperror();
10597dd7cddfSDavid du Colombier cclose(c0);
1060d1be6b08SDavid du Colombier if(ismount){
10613e12c5d1SDavid du Colombier fdclose(fd, 0);
1062d1be6b08SDavid du Colombier poperror();
1063d1be6b08SDavid du Colombier free(spec);
1064d1be6b08SDavid du Colombier }
10653e12c5d1SDavid du Colombier return ret;
10663e12c5d1SDavid du Colombier }
10673e12c5d1SDavid du Colombier
10683e12c5d1SDavid du Colombier long
sysbind(ulong * arg)10693e12c5d1SDavid du Colombier sysbind(ulong *arg)
10703e12c5d1SDavid du Colombier {
10719a747e4fSDavid du Colombier return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
10723e12c5d1SDavid du Colombier }
10733e12c5d1SDavid du Colombier
10743e12c5d1SDavid du Colombier long
sysmount(ulong * arg)10753e12c5d1SDavid du Colombier sysmount(ulong *arg)
10763e12c5d1SDavid du Colombier {
10779a747e4fSDavid du Colombier return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
10789a747e4fSDavid du Colombier }
10799a747e4fSDavid du Colombier
10809a747e4fSDavid du Colombier long
sys_mount(ulong * arg)10819a747e4fSDavid du Colombier sys_mount(ulong *arg)
10829a747e4fSDavid du Colombier {
10839a747e4fSDavid du Colombier return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
10843e12c5d1SDavid du Colombier }
10853e12c5d1SDavid du Colombier
10863e12c5d1SDavid du Colombier long
sysunmount(ulong * arg)10873e12c5d1SDavid du Colombier sysunmount(ulong *arg)
10883e12c5d1SDavid du Colombier {
10893e12c5d1SDavid du Colombier Chan *cmount, *cmounted;
10903e12c5d1SDavid du Colombier
10913e12c5d1SDavid du Colombier cmounted = 0;
10923e12c5d1SDavid du Colombier
10933e12c5d1SDavid du Colombier validaddr(arg[1], 1, 0);
10943e12c5d1SDavid du Colombier cmount = namec((char *)arg[1], Amount, 0, 0);
10953e12c5d1SDavid du Colombier if(waserror()) {
10967dd7cddfSDavid du Colombier cclose(cmount);
1097d1be6b08SDavid du Colombier if(cmounted)
1098d1be6b08SDavid du Colombier cclose(cmounted);
10993e12c5d1SDavid du Colombier nexterror();
11003e12c5d1SDavid du Colombier }
1101d1be6b08SDavid du Colombier
1102d1be6b08SDavid du Colombier if(arg[0]) {
11039a747e4fSDavid du Colombier /*
11049a747e4fSDavid du Colombier * This has to be namec(..., Aopen, ...) because
11059a747e4fSDavid du Colombier * if arg[0] is something like /srv/cs or /fd/0,
11069a747e4fSDavid du Colombier * opening it is the only way to get at the real
11079a747e4fSDavid du Colombier * Chan underneath.
11089a747e4fSDavid du Colombier */
1109d1be6b08SDavid du Colombier validaddr(arg[0], 1, 0);
1110219b2ee8SDavid du Colombier cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
11113e12c5d1SDavid du Colombier }
11127dd7cddfSDavid du Colombier cunmount(cmount, cmounted);
1113d1be6b08SDavid du Colombier poperror();
11147dd7cddfSDavid du Colombier cclose(cmount);
11153e12c5d1SDavid du Colombier if(cmounted)
11167dd7cddfSDavid du Colombier cclose(cmounted);
11173e12c5d1SDavid du Colombier return 0;
11183e12c5d1SDavid du Colombier }
11193e12c5d1SDavid du Colombier
11203e12c5d1SDavid du Colombier long
syscreate(ulong * arg)11213e12c5d1SDavid du Colombier syscreate(ulong *arg)
11223e12c5d1SDavid du Colombier {
11233e12c5d1SDavid du Colombier int fd;
1124d1be6b08SDavid du Colombier Chan *c;
11253e12c5d1SDavid du Colombier
11269a747e4fSDavid du Colombier openmode(arg[1]&~OEXCL); /* error check only; OEXCL okay here */
1127d1be6b08SDavid du Colombier validaddr(arg[0], 1, 0);
1128d1be6b08SDavid du Colombier c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
11293e12c5d1SDavid du Colombier if(waserror()) {
11307dd7cddfSDavid du Colombier cclose(c);
11313e12c5d1SDavid du Colombier nexterror();
11323e12c5d1SDavid du Colombier }
11333e12c5d1SDavid du Colombier fd = newfd(c);
11347dd7cddfSDavid du Colombier if(fd < 0)
11357dd7cddfSDavid du Colombier error(Enofd);
11363e12c5d1SDavid du Colombier poperror();
11373e12c5d1SDavid du Colombier return fd;
11383e12c5d1SDavid du Colombier }
11393e12c5d1SDavid du Colombier
11403e12c5d1SDavid du Colombier long
sysremove(ulong * arg)11413e12c5d1SDavid du Colombier sysremove(ulong *arg)
11423e12c5d1SDavid du Colombier {
11433e12c5d1SDavid du Colombier Chan *c;
11443e12c5d1SDavid du Colombier
11453e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
11469a747e4fSDavid du Colombier c = namec((char*)arg[0], Aremove, 0, 0);
1147e288d156SDavid du Colombier /*
1148e288d156SDavid du Colombier * Removing mount points is disallowed to avoid surprises
1149e288d156SDavid du Colombier * (which should be removed: the mount point or the mounted Chan?).
1150e288d156SDavid du Colombier */
1151e288d156SDavid du Colombier if(c->ismtpt){
1152e288d156SDavid du Colombier cclose(c);
1153e288d156SDavid du Colombier error(Eismtpt);
1154e288d156SDavid du Colombier }
11553e12c5d1SDavid du Colombier if(waserror()){
11563e12c5d1SDavid du Colombier c->type = 0; /* see below */
11577dd7cddfSDavid du Colombier cclose(c);
11583e12c5d1SDavid du Colombier nexterror();
11593e12c5d1SDavid du Colombier }
11607dd7cddfSDavid du Colombier devtab[c->type]->remove(c);
11613e12c5d1SDavid du Colombier /*
11623e12c5d1SDavid du Colombier * Remove clunks the fid, but we need to recover the Chan
11633e12c5d1SDavid du Colombier * so fake it up. rootclose() is known to be a nop.
11643e12c5d1SDavid du Colombier */
11653e12c5d1SDavid du Colombier c->type = 0;
11663e12c5d1SDavid du Colombier poperror();
11677dd7cddfSDavid du Colombier cclose(c);
11683e12c5d1SDavid du Colombier return 0;
11693e12c5d1SDavid du Colombier }
11703e12c5d1SDavid du Colombier
1171dc5a79c1SDavid du Colombier static long
wstat(Chan * c,uchar * d,int nd)1172dc5a79c1SDavid du Colombier wstat(Chan *c, uchar *d, int nd)
1173dc5a79c1SDavid du Colombier {
1174dc5a79c1SDavid du Colombier long l;
1175dc5a79c1SDavid du Colombier int namelen;
1176dc5a79c1SDavid du Colombier
1177dc5a79c1SDavid du Colombier if(waserror()){
1178dc5a79c1SDavid du Colombier cclose(c);
1179dc5a79c1SDavid du Colombier nexterror();
1180dc5a79c1SDavid du Colombier }
1181dc5a79c1SDavid du Colombier if(c->ismtpt){
1182dc5a79c1SDavid du Colombier /*
1183dc5a79c1SDavid du Colombier * Renaming mount points is disallowed to avoid surprises
11844afe124fSDavid du Colombier * (which should be renamed? the mount point or the mounted Chan?).
1185dc5a79c1SDavid du Colombier */
1186dc5a79c1SDavid du Colombier dirname(d, &namelen);
1187dc5a79c1SDavid du Colombier if(namelen)
11884afe124fSDavid du Colombier nameerror(chanpath(c), Eismtpt);
1189dc5a79c1SDavid du Colombier }
1190dc5a79c1SDavid du Colombier l = devtab[c->type]->wstat(c, d, nd);
1191dc5a79c1SDavid du Colombier poperror();
1192dc5a79c1SDavid du Colombier cclose(c);
1193dc5a79c1SDavid du Colombier return l;
1194dc5a79c1SDavid du Colombier }
1195dc5a79c1SDavid du Colombier
11963e12c5d1SDavid du Colombier long
syswstat(ulong * arg)11973e12c5d1SDavid du Colombier syswstat(ulong *arg)
11983e12c5d1SDavid du Colombier {
11993e12c5d1SDavid du Colombier Chan *c;
12009a747e4fSDavid du Colombier uint l;
12013e12c5d1SDavid du Colombier
12029a747e4fSDavid du Colombier l = arg[2];
12039a747e4fSDavid du Colombier validaddr(arg[1], l, 0);
12049a747e4fSDavid du Colombier validstat((uchar*)arg[1], l);
12053e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
12063e12c5d1SDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
1207dc5a79c1SDavid du Colombier return wstat(c, (uchar*)arg[1], l);
12083e12c5d1SDavid du Colombier }
12093e12c5d1SDavid du Colombier
12103e12c5d1SDavid du Colombier long
sysfwstat(ulong * arg)12113e12c5d1SDavid du Colombier sysfwstat(ulong *arg)
12123e12c5d1SDavid du Colombier {
12133e12c5d1SDavid du Colombier Chan *c;
12149a747e4fSDavid du Colombier uint l;
12153e12c5d1SDavid du Colombier
12169a747e4fSDavid du Colombier l = arg[2];
12179a747e4fSDavid du Colombier validaddr(arg[1], l, 0);
12189a747e4fSDavid du Colombier validstat((uchar*)arg[1], l);
12193e12c5d1SDavid du Colombier c = fdtochan(arg[0], -1, 1, 1);
1220dc5a79c1SDavid du Colombier return wstat(c, (uchar*)arg[1], l);
12219a747e4fSDavid du Colombier }
12229a747e4fSDavid du Colombier
12239a747e4fSDavid du Colombier static void
packoldstat(uchar * buf,Dir * d)12249a747e4fSDavid du Colombier packoldstat(uchar *buf, Dir *d)
12259a747e4fSDavid du Colombier {
12269a747e4fSDavid du Colombier uchar *p;
12279a747e4fSDavid du Colombier ulong q;
12289a747e4fSDavid du Colombier
12299a747e4fSDavid du Colombier /* lay down old stat buffer - grotty code but it's temporary */
12309a747e4fSDavid du Colombier p = buf;
12319a747e4fSDavid du Colombier strncpy((char*)p, d->name, 28);
12329a747e4fSDavid du Colombier p += 28;
12339a747e4fSDavid du Colombier strncpy((char*)p, d->uid, 28);
12349a747e4fSDavid du Colombier p += 28;
12359a747e4fSDavid du Colombier strncpy((char*)p, d->gid, 28);
12369a747e4fSDavid du Colombier p += 28;
1237*6221fdccSDavid du Colombier q = d->qid.path & ~(uvlong)DMDIR; /* make sure doesn't accidentally look like directory */
1238*6221fdccSDavid du Colombier if(d->qid.type & QTDIR) /* this is the real test of a new directory */
12399a747e4fSDavid du Colombier q |= DMDIR;
12409a747e4fSDavid du Colombier PBIT32(p, q);
12419a747e4fSDavid du Colombier p += BIT32SZ;
12429a747e4fSDavid du Colombier PBIT32(p, d->qid.vers);
12439a747e4fSDavid du Colombier p += BIT32SZ;
12449a747e4fSDavid du Colombier PBIT32(p, d->mode);
12459a747e4fSDavid du Colombier p += BIT32SZ;
12469a747e4fSDavid du Colombier PBIT32(p, d->atime);
12479a747e4fSDavid du Colombier p += BIT32SZ;
12489a747e4fSDavid du Colombier PBIT32(p, d->mtime);
12499a747e4fSDavid du Colombier p += BIT32SZ;
12509a747e4fSDavid du Colombier PBIT64(p, d->length);
12519a747e4fSDavid du Colombier p += BIT64SZ;
12529a747e4fSDavid du Colombier PBIT16(p, d->type);
12539a747e4fSDavid du Colombier p += BIT16SZ;
12549a747e4fSDavid du Colombier PBIT16(p, d->dev);
12559a747e4fSDavid du Colombier }
12569a747e4fSDavid du Colombier
12579a747e4fSDavid du Colombier long
sys_stat(ulong * arg)12589a747e4fSDavid du Colombier sys_stat(ulong *arg)
12599a747e4fSDavid du Colombier {
12609a747e4fSDavid du Colombier Chan *c;
12619a747e4fSDavid du Colombier uint l;
12629a747e4fSDavid du Colombier uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1263dc5a79c1SDavid du Colombier char strs[128], *name;
12649a747e4fSDavid du Colombier Dir d;
12659a747e4fSDavid du Colombier char old[] = "old stat system call - recompile";
12669a747e4fSDavid du Colombier
12679a747e4fSDavid du Colombier validaddr(arg[1], 116, 1);
12689a747e4fSDavid du Colombier validaddr(arg[0], 1, 0);
12699a747e4fSDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
12709a747e4fSDavid du Colombier if(waserror()){
12719a747e4fSDavid du Colombier cclose(c);
12729a747e4fSDavid du Colombier nexterror();
12739a747e4fSDavid du Colombier }
12749a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, buf, sizeof buf);
12759a747e4fSDavid du Colombier /* buf contains a new stat buf; convert to old. yuck. */
12769a747e4fSDavid du Colombier if(l <= BIT16SZ) /* buffer too small; time to face reality */
12779a747e4fSDavid du Colombier error(old);
12784afe124fSDavid du Colombier name = pathlast(c->path);
1279dc5a79c1SDavid du Colombier if(name)
1280dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), buf, l, sizeof buf);
12819a747e4fSDavid du Colombier l = convM2D(buf, l, &d, strs);
12829a747e4fSDavid du Colombier if(l == 0)
12839a747e4fSDavid du Colombier error(old);
12849a747e4fSDavid du Colombier packoldstat((uchar*)arg[1], &d);
12859a747e4fSDavid du Colombier
12863e12c5d1SDavid du Colombier poperror();
12877dd7cddfSDavid du Colombier cclose(c);
12883e12c5d1SDavid du Colombier return 0;
12893e12c5d1SDavid du Colombier }
12909a747e4fSDavid du Colombier
12919a747e4fSDavid du Colombier long
sys_fstat(ulong * arg)12929a747e4fSDavid du Colombier sys_fstat(ulong *arg)
12939a747e4fSDavid du Colombier {
12949a747e4fSDavid du Colombier Chan *c;
1295dc5a79c1SDavid du Colombier char *name;
12969a747e4fSDavid du Colombier uint l;
12979a747e4fSDavid du Colombier uchar buf[128]; /* old DIRLEN plus a little should be plenty */
12989a747e4fSDavid du Colombier char strs[128];
12999a747e4fSDavid du Colombier Dir d;
13009a747e4fSDavid du Colombier char old[] = "old fstat system call - recompile";
13019a747e4fSDavid du Colombier
13029a747e4fSDavid du Colombier validaddr(arg[1], 116, 1);
13039a747e4fSDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
13049a747e4fSDavid du Colombier if(waserror()){
13059a747e4fSDavid du Colombier cclose(c);
13069a747e4fSDavid du Colombier nexterror();
13079a747e4fSDavid du Colombier }
13089a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, buf, sizeof buf);
13099a747e4fSDavid du Colombier /* buf contains a new stat buf; convert to old. yuck. */
13109a747e4fSDavid du Colombier if(l <= BIT16SZ) /* buffer too small; time to face reality */
13119a747e4fSDavid du Colombier error(old);
13124afe124fSDavid du Colombier name = pathlast(c->path);
1313dc5a79c1SDavid du Colombier if(name)
1314dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), buf, l, sizeof buf);
13159a747e4fSDavid du Colombier l = convM2D(buf, l, &d, strs);
13169a747e4fSDavid du Colombier if(l == 0)
13179a747e4fSDavid du Colombier error(old);
13189a747e4fSDavid du Colombier packoldstat((uchar*)arg[1], &d);
13199a747e4fSDavid du Colombier
13209a747e4fSDavid du Colombier poperror();
13219a747e4fSDavid du Colombier cclose(c);
13229a747e4fSDavid du Colombier return 0;
13239a747e4fSDavid du Colombier }
13249a747e4fSDavid du Colombier
13259a747e4fSDavid du Colombier long
sys_wstat(ulong *)13269a747e4fSDavid du Colombier sys_wstat(ulong *)
13279a747e4fSDavid du Colombier {
13289a747e4fSDavid du Colombier error("old wstat system call - recompile");
13299a747e4fSDavid du Colombier return -1;
13309a747e4fSDavid du Colombier }
13319a747e4fSDavid du Colombier
13329a747e4fSDavid du Colombier long
sys_fwstat(ulong *)13339a747e4fSDavid du Colombier sys_fwstat(ulong *)
13349a747e4fSDavid du Colombier {
13359a747e4fSDavid du Colombier error("old fwstat system call - recompile");
13369a747e4fSDavid du Colombier return -1;
13379a747e4fSDavid du Colombier }
1338