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
193*fac6300fSDavid du Colombier validaddr(arg[0], sizeof(fd), 1);
194*fac6300fSDavid 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
218*fac6300fSDavid du Colombier ((int*)arg[0])[0] = fd[0];
219*fac6300fSDavid 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
683dc5a79c1SDavid du Colombier lock(c);
684dc5a79c1SDavid du Colombier c->devoffset += nn;
685dc5a79c1SDavid du Colombier c->offset += nnn;
686dc5a79c1SDavid du Colombier unlock(c);
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier poperror();
6897dd7cddfSDavid du Colombier cclose(c);
6907dd7cddfSDavid du Colombier
691dc5a79c1SDavid du Colombier return nnn;
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier
6947dd7cddfSDavid du Colombier long
sys_read(ulong * arg)6959a747e4fSDavid du Colombier sys_read(ulong *arg)
6969a747e4fSDavid du Colombier {
6979a747e4fSDavid du Colombier return read(arg, nil);
6989a747e4fSDavid du Colombier }
6999a747e4fSDavid du Colombier
7009a747e4fSDavid du Colombier long
syspread(ulong * arg)70180ee5cbfSDavid du Colombier syspread(ulong *arg)
70280ee5cbfSDavid du Colombier {
7039a747e4fSDavid du Colombier vlong v;
7049a747e4fSDavid du Colombier va_list list;
70580ee5cbfSDavid du Colombier
7069a747e4fSDavid du Colombier /* use varargs to guarantee alignment of vlong */
7079a747e4fSDavid du Colombier va_start(list, arg[2]);
7089a747e4fSDavid du Colombier v = va_arg(list, vlong);
7099a747e4fSDavid du Colombier va_end(list);
71080ee5cbfSDavid du Colombier
7119a747e4fSDavid du Colombier if(v == ~0ULL)
7129a747e4fSDavid du Colombier return read(arg, nil);
7139a747e4fSDavid du Colombier
7149a747e4fSDavid du Colombier return read(arg, &v);
71580ee5cbfSDavid du Colombier }
71680ee5cbfSDavid du Colombier
7179a747e4fSDavid du Colombier static long
write(ulong * arg,vlong * offp)7189a747e4fSDavid du Colombier write(ulong *arg, vlong *offp)
7193e12c5d1SDavid du Colombier {
7203e12c5d1SDavid du Colombier Chan *c;
7217dd7cddfSDavid du Colombier long m, n;
7229a747e4fSDavid du Colombier vlong off;
7233e12c5d1SDavid du Colombier
7243e12c5d1SDavid du Colombier validaddr(arg[1], arg[2], 0);
7259a747e4fSDavid du Colombier n = 0;
7263e12c5d1SDavid du Colombier c = fdtochan(arg[0], OWRITE, 1, 1);
7273e12c5d1SDavid du Colombier if(waserror()) {
7289a747e4fSDavid du Colombier if(offp == nil){
7297dd7cddfSDavid du Colombier lock(c);
7307dd7cddfSDavid du Colombier c->offset -= n;
7317dd7cddfSDavid du Colombier unlock(c);
7329a747e4fSDavid du Colombier }
7339a747e4fSDavid du Colombier cclose(c);
7343e12c5d1SDavid du Colombier nexterror();
7353e12c5d1SDavid du Colombier }
7363e12c5d1SDavid du Colombier
7379a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
7383e12c5d1SDavid du Colombier error(Eisdir);
7393e12c5d1SDavid du Colombier
7409a747e4fSDavid du Colombier n = arg[2];
7419a747e4fSDavid du Colombier
7429a747e4fSDavid du Colombier if(offp == nil){ /* use and maintain channel's offset */
7433e12c5d1SDavid du Colombier lock(c);
7449a747e4fSDavid du Colombier off = c->offset;
7453e12c5d1SDavid du Colombier c->offset += n;
7463e12c5d1SDavid du Colombier unlock(c);
7479a747e4fSDavid du Colombier }else
7489a747e4fSDavid du Colombier off = *offp;
7493e12c5d1SDavid du Colombier
7509a747e4fSDavid du Colombier if(off < 0)
7519a747e4fSDavid du Colombier error(Enegoff);
7523e12c5d1SDavid du Colombier
7539a747e4fSDavid du Colombier m = devtab[c->type]->write(c, (void*)arg[1], n, off);
7549a747e4fSDavid du Colombier
7559a747e4fSDavid du Colombier if(offp == nil && m < n){
7567dd7cddfSDavid du Colombier lock(c);
7577dd7cddfSDavid du Colombier c->offset -= n - m;
7587dd7cddfSDavid du Colombier unlock(c);
7597dd7cddfSDavid du Colombier }
7607dd7cddfSDavid du Colombier
7617dd7cddfSDavid du Colombier poperror();
7627dd7cddfSDavid du Colombier cclose(c);
7637dd7cddfSDavid du Colombier
7647dd7cddfSDavid du Colombier return m;
7657dd7cddfSDavid du Colombier }
7667dd7cddfSDavid du Colombier
76780ee5cbfSDavid du Colombier long
sys_write(ulong * arg)7689a747e4fSDavid du Colombier sys_write(ulong *arg)
76980ee5cbfSDavid du Colombier {
7709a747e4fSDavid du Colombier return write(arg, nil);
77180ee5cbfSDavid du Colombier }
77280ee5cbfSDavid du Colombier
7739a747e4fSDavid du Colombier long
syspwrite(ulong * arg)7749a747e4fSDavid du Colombier syspwrite(ulong *arg)
7759a747e4fSDavid du Colombier {
7769a747e4fSDavid du Colombier vlong v;
7779a747e4fSDavid du Colombier va_list list;
77880ee5cbfSDavid du Colombier
7799a747e4fSDavid du Colombier /* use varargs to guarantee alignment of vlong */
7809a747e4fSDavid du Colombier va_start(list, arg[2]);
7819a747e4fSDavid du Colombier v = va_arg(list, vlong);
7829a747e4fSDavid du Colombier va_end(list);
78380ee5cbfSDavid du Colombier
7849a747e4fSDavid du Colombier if(v == ~0ULL)
7859a747e4fSDavid du Colombier return write(arg, nil);
78680ee5cbfSDavid du Colombier
7879a747e4fSDavid du Colombier return write(arg, &v);
78880ee5cbfSDavid du Colombier }
78980ee5cbfSDavid du Colombier
7907dd7cddfSDavid du Colombier static void
sseek(ulong * arg)7917dd7cddfSDavid du Colombier sseek(ulong *arg)
7927dd7cddfSDavid du Colombier {
7937dd7cddfSDavid du Colombier Chan *c;
7949a747e4fSDavid du Colombier uchar buf[sizeof(Dir)+100];
7957dd7cddfSDavid du Colombier Dir dir;
7969a747e4fSDavid du Colombier int n;
7977dd7cddfSDavid du Colombier vlong off;
7987dd7cddfSDavid du Colombier union {
7997dd7cddfSDavid du Colombier vlong v;
8007dd7cddfSDavid du Colombier ulong u[2];
8017dd7cddfSDavid du Colombier } o;
8027dd7cddfSDavid du Colombier
8037dd7cddfSDavid du Colombier c = fdtochan(arg[1], -1, 1, 1);
8047dd7cddfSDavid du Colombier if(waserror()){
8057dd7cddfSDavid du Colombier cclose(c);
8067dd7cddfSDavid du Colombier nexterror();
8077dd7cddfSDavid du Colombier }
8087dd7cddfSDavid du Colombier if(devtab[c->type]->dc == '|')
8097dd7cddfSDavid du Colombier error(Eisstream);
8107dd7cddfSDavid du Colombier
8117dd7cddfSDavid du Colombier off = 0;
8127dd7cddfSDavid du Colombier o.u[0] = arg[2];
8137dd7cddfSDavid du Colombier o.u[1] = arg[3];
8147dd7cddfSDavid du Colombier switch(arg[4]){
8157dd7cddfSDavid du Colombier case 0:
8167dd7cddfSDavid du Colombier off = o.v;
8179a747e4fSDavid du Colombier if((c->qid.type & QTDIR) && off != 0)
8189a747e4fSDavid du Colombier error(Eisdir);
8199a747e4fSDavid du Colombier if(off < 0)
8209a747e4fSDavid du Colombier error(Enegoff);
8217dd7cddfSDavid du Colombier c->offset = off;
8227dd7cddfSDavid du Colombier break;
8237dd7cddfSDavid du Colombier
8247dd7cddfSDavid du Colombier case 1:
8259a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
8269a747e4fSDavid du Colombier error(Eisdir);
8277dd7cddfSDavid du Colombier lock(c); /* lock for read/write update */
8287dd7cddfSDavid du Colombier off = o.v + c->offset;
8292a034d96SDavid du Colombier if(off < 0){
8302a034d96SDavid du Colombier unlock(c);
8319a747e4fSDavid du Colombier error(Enegoff);
8322a034d96SDavid du Colombier }
8337dd7cddfSDavid du Colombier c->offset = off;
8347dd7cddfSDavid du Colombier unlock(c);
8357dd7cddfSDavid du Colombier break;
8367dd7cddfSDavid du Colombier
8377dd7cddfSDavid du Colombier case 2:
8389a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
8399a747e4fSDavid du Colombier error(Eisdir);
8409a747e4fSDavid du Colombier n = devtab[c->type]->stat(c, buf, sizeof buf);
8419a747e4fSDavid du Colombier if(convM2D(buf, n, &dir, nil) == 0)
8429a747e4fSDavid du Colombier error("internal error: stat error in seek");
8437dd7cddfSDavid du Colombier off = dir.length + o.v;
8449a747e4fSDavid du Colombier if(off < 0)
8459a747e4fSDavid du Colombier error(Enegoff);
8467dd7cddfSDavid du Colombier c->offset = off;
8477dd7cddfSDavid du Colombier break;
8489a747e4fSDavid du Colombier
8499a747e4fSDavid du Colombier default:
8509a747e4fSDavid du Colombier error(Ebadarg);
8517dd7cddfSDavid du Colombier }
8527dd7cddfSDavid du Colombier *(vlong*)arg[0] = off;
8537dd7cddfSDavid du Colombier c->uri = 0;
8549a747e4fSDavid du Colombier c->dri = 0;
8557dd7cddfSDavid du Colombier cclose(c);
8567dd7cddfSDavid du Colombier poperror();
8573e12c5d1SDavid du Colombier }
8583e12c5d1SDavid du Colombier
8593e12c5d1SDavid du Colombier long
sysseek(ulong * arg)8603e12c5d1SDavid du Colombier sysseek(ulong *arg)
8613e12c5d1SDavid du Colombier {
862*fac6300fSDavid du Colombier validaddr(arg[0], sizeof(vlong), 1);
863*fac6300fSDavid du Colombier validalign(arg[0], sizeof(vlong));
8647dd7cddfSDavid du Colombier sseek(arg);
8657dd7cddfSDavid du Colombier return 0;
8663e12c5d1SDavid du Colombier }
8677dd7cddfSDavid du Colombier
8687dd7cddfSDavid du Colombier long
sysoseek(ulong * arg)8697dd7cddfSDavid du Colombier sysoseek(ulong *arg)
8707dd7cddfSDavid du Colombier {
8717dd7cddfSDavid du Colombier union {
8727dd7cddfSDavid du Colombier vlong v;
8737dd7cddfSDavid du Colombier ulong u[2];
8747dd7cddfSDavid du Colombier } o;
8757dd7cddfSDavid du Colombier ulong a[5];
8767dd7cddfSDavid du Colombier
87780ee5cbfSDavid du Colombier o.v = (long)arg[1];
8787dd7cddfSDavid du Colombier a[0] = (ulong)&o.v;
8797dd7cddfSDavid du Colombier a[1] = arg[0];
8807dd7cddfSDavid du Colombier a[2] = o.u[0];
8817dd7cddfSDavid du Colombier a[3] = o.u[1];
8827dd7cddfSDavid du Colombier a[4] = arg[2];
8837dd7cddfSDavid du Colombier sseek(a);
8847dd7cddfSDavid du Colombier return o.v;
8853e12c5d1SDavid du Colombier }
8863e12c5d1SDavid du Colombier
8879a747e4fSDavid du Colombier void
validstat(uchar * s,int n)8889a747e4fSDavid du Colombier validstat(uchar *s, int n)
8899a747e4fSDavid du Colombier {
8909a747e4fSDavid du Colombier int m;
8919a747e4fSDavid du Colombier char buf[64];
8929a747e4fSDavid du Colombier
8939a747e4fSDavid du Colombier if(statcheck(s, n) < 0)
8949a747e4fSDavid du Colombier error(Ebadstat);
8959a747e4fSDavid du Colombier /* verify that name entry is acceptable */
8969a747e4fSDavid du Colombier s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
8979a747e4fSDavid du Colombier /*
8989a747e4fSDavid du Colombier * s now points at count for first string.
8999a747e4fSDavid du Colombier * if it's too long, let the server decide; this is
9009a747e4fSDavid du Colombier * only for his protection anyway. otherwise
9019a747e4fSDavid du Colombier * we'd have to allocate and waserror.
9029a747e4fSDavid du Colombier */
9039a747e4fSDavid du Colombier m = GBIT16(s);
9049a747e4fSDavid du Colombier s += BIT16SZ;
9059a747e4fSDavid du Colombier if(m+1 > sizeof buf)
9069a747e4fSDavid du Colombier return;
9079a747e4fSDavid du Colombier memmove(buf, s, m);
9089a747e4fSDavid du Colombier buf[m] = '\0';
9099a747e4fSDavid du Colombier /* name could be '/' */
9109a747e4fSDavid du Colombier if(strcmp(buf, "/") != 0)
9119a747e4fSDavid du Colombier validname(buf, 0);
9129a747e4fSDavid du Colombier }
9139a747e4fSDavid du Colombier
914dc5a79c1SDavid du Colombier static char*
pathlast(Path * p)9154afe124fSDavid du Colombier pathlast(Path *p)
916dc5a79c1SDavid du Colombier {
917dc5a79c1SDavid du Colombier char *s;
918dc5a79c1SDavid du Colombier
9194afe124fSDavid du Colombier if(p == nil)
920dc5a79c1SDavid du Colombier return nil;
9214afe124fSDavid du Colombier if(p->len == 0)
922dc5a79c1SDavid du Colombier return nil;
9234afe124fSDavid du Colombier s = strrchr(p->s, '/');
924dc5a79c1SDavid du Colombier if(s)
925dc5a79c1SDavid du Colombier return s+1;
9264afe124fSDavid du Colombier return p->s;
927dc5a79c1SDavid du Colombier }
928dc5a79c1SDavid du Colombier
9293e12c5d1SDavid du Colombier long
sysfstat(ulong * arg)9303e12c5d1SDavid du Colombier sysfstat(ulong *arg)
9313e12c5d1SDavid du Colombier {
9323e12c5d1SDavid du Colombier Chan *c;
9339a747e4fSDavid du Colombier uint l;
9343e12c5d1SDavid du Colombier
9359a747e4fSDavid du Colombier l = arg[2];
9369a747e4fSDavid du Colombier validaddr(arg[1], l, 1);
9373e12c5d1SDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
9383e12c5d1SDavid du Colombier if(waserror()) {
9397dd7cddfSDavid du Colombier cclose(c);
9403e12c5d1SDavid du Colombier nexterror();
9413e12c5d1SDavid du Colombier }
9429a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
9433e12c5d1SDavid du Colombier poperror();
9447dd7cddfSDavid du Colombier cclose(c);
9459a747e4fSDavid du Colombier return l;
9463e12c5d1SDavid du Colombier }
9473e12c5d1SDavid du Colombier
9483e12c5d1SDavid du Colombier long
sysstat(ulong * arg)9493e12c5d1SDavid du Colombier sysstat(ulong *arg)
9503e12c5d1SDavid du Colombier {
951dc5a79c1SDavid du Colombier char *name;
9523e12c5d1SDavid du Colombier Chan *c;
9539a747e4fSDavid du Colombier uint l;
9543e12c5d1SDavid du Colombier
9559a747e4fSDavid du Colombier l = arg[2];
9569a747e4fSDavid du Colombier validaddr(arg[1], l, 1);
9573e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
9583e12c5d1SDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
9593e12c5d1SDavid du Colombier if(waserror()){
9607dd7cddfSDavid du Colombier cclose(c);
9613e12c5d1SDavid du Colombier nexterror();
9623e12c5d1SDavid du Colombier }
9639a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
9644afe124fSDavid du Colombier name = pathlast(c->path);
965dc5a79c1SDavid du Colombier if(name)
966dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
967dc5a79c1SDavid du Colombier
9683e12c5d1SDavid du Colombier poperror();
9697dd7cddfSDavid du Colombier cclose(c);
9709a747e4fSDavid du Colombier return l;
9713e12c5d1SDavid du Colombier }
9723e12c5d1SDavid du Colombier
9733e12c5d1SDavid du Colombier long
syschdir(ulong * arg)9743e12c5d1SDavid du Colombier syschdir(ulong *arg)
9753e12c5d1SDavid du Colombier {
9763e12c5d1SDavid du Colombier Chan *c;
9773e12c5d1SDavid du Colombier
9783e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
9797dd7cddfSDavid du Colombier
9803e12c5d1SDavid du Colombier c = namec((char*)arg[0], Atodir, 0, 0);
9817dd7cddfSDavid du Colombier cclose(up->dot);
9827dd7cddfSDavid du Colombier up->dot = c;
9833e12c5d1SDavid du Colombier return 0;
9843e12c5d1SDavid du Colombier }
9853e12c5d1SDavid du Colombier
9863e12c5d1SDavid du Colombier long
bindmount(int ismount,int fd,int afd,char * arg0,char * arg1,ulong flag,char * spec)9879a747e4fSDavid du Colombier bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
9883e12c5d1SDavid du Colombier {
9899a747e4fSDavid du Colombier int ret;
9909a747e4fSDavid du Colombier Chan *c0, *c1, *ac, *bc;
9913e12c5d1SDavid du Colombier struct{
9923e12c5d1SDavid du Colombier Chan *chan;
9939a747e4fSDavid du Colombier Chan *authchan;
9943e12c5d1SDavid du Colombier char *spec;
9957dd7cddfSDavid du Colombier int flags;
9963e12c5d1SDavid du Colombier }bogus;
9973e12c5d1SDavid du Colombier
9989a747e4fSDavid du Colombier if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
9993e12c5d1SDavid du Colombier error(Ebadarg);
10007dd7cddfSDavid du Colombier
10013e12c5d1SDavid du Colombier if(ismount){
1002d1be6b08SDavid du Colombier validaddr((ulong)spec, 1, 0);
1003d1be6b08SDavid du Colombier spec = validnamedup(spec, 1);
1004d1be6b08SDavid du Colombier if(waserror()){
1005d1be6b08SDavid du Colombier free(spec);
1006d1be6b08SDavid du Colombier nexterror();
1007d1be6b08SDavid du Colombier }
1008d1be6b08SDavid du Colombier
10097dd7cddfSDavid du Colombier if(up->pgrp->noattach)
10107dd7cddfSDavid du Colombier error(Enoattach);
10117dd7cddfSDavid du Colombier
10129a747e4fSDavid du Colombier ac = nil;
10137dd7cddfSDavid du Colombier bc = fdtochan(fd, ORDWR, 0, 1);
10143e12c5d1SDavid du Colombier if(waserror()) {
10159a747e4fSDavid du Colombier if(ac)
10169a747e4fSDavid du Colombier cclose(ac);
10177dd7cddfSDavid du Colombier cclose(bc);
10183e12c5d1SDavid du Colombier nexterror();
10193e12c5d1SDavid du Colombier }
10209a747e4fSDavid du Colombier
10219a747e4fSDavid du Colombier if(afd >= 0)
10229a747e4fSDavid du Colombier ac = fdtochan(afd, ORDWR, 0, 1);
10239a747e4fSDavid du Colombier
1024d1be6b08SDavid du Colombier bogus.flags = flag & MCACHE;
10253e12c5d1SDavid du Colombier bogus.chan = bc;
10269a747e4fSDavid du Colombier bogus.authchan = ac;
10279a747e4fSDavid du Colombier bogus.spec = spec;
10283e12c5d1SDavid du Colombier ret = devno('M', 0);
10297dd7cddfSDavid du Colombier c0 = devtab[ret]->attach((char*)&bogus);
10302db064f5SDavid du Colombier poperror(); /* ac bc */
10319a747e4fSDavid du Colombier if(ac)
10329a747e4fSDavid du Colombier cclose(ac);
10337dd7cddfSDavid du Colombier cclose(bc);
10349a747e4fSDavid du Colombier }else{
1035d1be6b08SDavid du Colombier spec = 0;
10369a747e4fSDavid du Colombier validaddr((ulong)arg0, 1, 0);
10379a747e4fSDavid du Colombier c0 = namec(arg0, Abind, 0, 0);
10383e12c5d1SDavid du Colombier }
10397dd7cddfSDavid du Colombier
10403e12c5d1SDavid du Colombier if(waserror()){
10417dd7cddfSDavid du Colombier cclose(c0);
10423e12c5d1SDavid du Colombier nexterror();
10433e12c5d1SDavid du Colombier }
10447dd7cddfSDavid du Colombier
10459a747e4fSDavid du Colombier validaddr((ulong)arg1, 1, 0);
10469a747e4fSDavid du Colombier c1 = namec(arg1, Amount, 0, 0);
10473e12c5d1SDavid du Colombier if(waserror()){
10487dd7cddfSDavid du Colombier cclose(c1);
10493e12c5d1SDavid du Colombier nexterror();
10503e12c5d1SDavid du Colombier }
10517dd7cddfSDavid du Colombier
1052d1be6b08SDavid du Colombier ret = cmount(&c0, c1, flag, spec);
10537dd7cddfSDavid du Colombier
10543e12c5d1SDavid du Colombier poperror();
10557dd7cddfSDavid du Colombier cclose(c1);
10563e12c5d1SDavid du Colombier poperror();
10577dd7cddfSDavid du Colombier cclose(c0);
1058d1be6b08SDavid du Colombier if(ismount){
10593e12c5d1SDavid du Colombier fdclose(fd, 0);
1060d1be6b08SDavid du Colombier poperror();
1061d1be6b08SDavid du Colombier free(spec);
1062d1be6b08SDavid du Colombier }
10633e12c5d1SDavid du Colombier return ret;
10643e12c5d1SDavid du Colombier }
10653e12c5d1SDavid du Colombier
10663e12c5d1SDavid du Colombier long
sysbind(ulong * arg)10673e12c5d1SDavid du Colombier sysbind(ulong *arg)
10683e12c5d1SDavid du Colombier {
10699a747e4fSDavid du Colombier return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
10703e12c5d1SDavid du Colombier }
10713e12c5d1SDavid du Colombier
10723e12c5d1SDavid du Colombier long
sysmount(ulong * arg)10733e12c5d1SDavid du Colombier sysmount(ulong *arg)
10743e12c5d1SDavid du Colombier {
10759a747e4fSDavid du Colombier return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
10769a747e4fSDavid du Colombier }
10779a747e4fSDavid du Colombier
10789a747e4fSDavid du Colombier long
sys_mount(ulong * arg)10799a747e4fSDavid du Colombier sys_mount(ulong *arg)
10809a747e4fSDavid du Colombier {
10819a747e4fSDavid du Colombier return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
10823e12c5d1SDavid du Colombier }
10833e12c5d1SDavid du Colombier
10843e12c5d1SDavid du Colombier long
sysunmount(ulong * arg)10853e12c5d1SDavid du Colombier sysunmount(ulong *arg)
10863e12c5d1SDavid du Colombier {
10873e12c5d1SDavid du Colombier Chan *cmount, *cmounted;
10883e12c5d1SDavid du Colombier
10893e12c5d1SDavid du Colombier cmounted = 0;
10903e12c5d1SDavid du Colombier
10913e12c5d1SDavid du Colombier validaddr(arg[1], 1, 0);
10923e12c5d1SDavid du Colombier cmount = namec((char *)arg[1], Amount, 0, 0);
10933e12c5d1SDavid du Colombier if(waserror()) {
10947dd7cddfSDavid du Colombier cclose(cmount);
1095d1be6b08SDavid du Colombier if(cmounted)
1096d1be6b08SDavid du Colombier cclose(cmounted);
10973e12c5d1SDavid du Colombier nexterror();
10983e12c5d1SDavid du Colombier }
1099d1be6b08SDavid du Colombier
1100d1be6b08SDavid du Colombier if(arg[0]) {
11019a747e4fSDavid du Colombier /*
11029a747e4fSDavid du Colombier * This has to be namec(..., Aopen, ...) because
11039a747e4fSDavid du Colombier * if arg[0] is something like /srv/cs or /fd/0,
11049a747e4fSDavid du Colombier * opening it is the only way to get at the real
11059a747e4fSDavid du Colombier * Chan underneath.
11069a747e4fSDavid du Colombier */
1107d1be6b08SDavid du Colombier validaddr(arg[0], 1, 0);
1108219b2ee8SDavid du Colombier cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
11093e12c5d1SDavid du Colombier }
11107dd7cddfSDavid du Colombier cunmount(cmount, cmounted);
1111d1be6b08SDavid du Colombier poperror();
11127dd7cddfSDavid du Colombier cclose(cmount);
11133e12c5d1SDavid du Colombier if(cmounted)
11147dd7cddfSDavid du Colombier cclose(cmounted);
11153e12c5d1SDavid du Colombier return 0;
11163e12c5d1SDavid du Colombier }
11173e12c5d1SDavid du Colombier
11183e12c5d1SDavid du Colombier long
syscreate(ulong * arg)11193e12c5d1SDavid du Colombier syscreate(ulong *arg)
11203e12c5d1SDavid du Colombier {
11213e12c5d1SDavid du Colombier int fd;
1122d1be6b08SDavid du Colombier Chan *c;
11233e12c5d1SDavid du Colombier
11249a747e4fSDavid du Colombier openmode(arg[1]&~OEXCL); /* error check only; OEXCL okay here */
1125d1be6b08SDavid du Colombier validaddr(arg[0], 1, 0);
1126d1be6b08SDavid du Colombier c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
11273e12c5d1SDavid du Colombier if(waserror()) {
11287dd7cddfSDavid du Colombier cclose(c);
11293e12c5d1SDavid du Colombier nexterror();
11303e12c5d1SDavid du Colombier }
11313e12c5d1SDavid du Colombier fd = newfd(c);
11327dd7cddfSDavid du Colombier if(fd < 0)
11337dd7cddfSDavid du Colombier error(Enofd);
11343e12c5d1SDavid du Colombier poperror();
11353e12c5d1SDavid du Colombier return fd;
11363e12c5d1SDavid du Colombier }
11373e12c5d1SDavid du Colombier
11383e12c5d1SDavid du Colombier long
sysremove(ulong * arg)11393e12c5d1SDavid du Colombier sysremove(ulong *arg)
11403e12c5d1SDavid du Colombier {
11413e12c5d1SDavid du Colombier Chan *c;
11423e12c5d1SDavid du Colombier
11433e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
11449a747e4fSDavid du Colombier c = namec((char*)arg[0], Aremove, 0, 0);
1145e288d156SDavid du Colombier /*
1146e288d156SDavid du Colombier * Removing mount points is disallowed to avoid surprises
1147e288d156SDavid du Colombier * (which should be removed: the mount point or the mounted Chan?).
1148e288d156SDavid du Colombier */
1149e288d156SDavid du Colombier if(c->ismtpt){
1150e288d156SDavid du Colombier cclose(c);
1151e288d156SDavid du Colombier error(Eismtpt);
1152e288d156SDavid du Colombier }
11533e12c5d1SDavid du Colombier if(waserror()){
11543e12c5d1SDavid du Colombier c->type = 0; /* see below */
11557dd7cddfSDavid du Colombier cclose(c);
11563e12c5d1SDavid du Colombier nexterror();
11573e12c5d1SDavid du Colombier }
11587dd7cddfSDavid du Colombier devtab[c->type]->remove(c);
11593e12c5d1SDavid du Colombier /*
11603e12c5d1SDavid du Colombier * Remove clunks the fid, but we need to recover the Chan
11613e12c5d1SDavid du Colombier * so fake it up. rootclose() is known to be a nop.
11623e12c5d1SDavid du Colombier */
11633e12c5d1SDavid du Colombier c->type = 0;
11643e12c5d1SDavid du Colombier poperror();
11657dd7cddfSDavid du Colombier cclose(c);
11663e12c5d1SDavid du Colombier return 0;
11673e12c5d1SDavid du Colombier }
11683e12c5d1SDavid du Colombier
1169dc5a79c1SDavid du Colombier static long
wstat(Chan * c,uchar * d,int nd)1170dc5a79c1SDavid du Colombier wstat(Chan *c, uchar *d, int nd)
1171dc5a79c1SDavid du Colombier {
1172dc5a79c1SDavid du Colombier long l;
1173dc5a79c1SDavid du Colombier int namelen;
1174dc5a79c1SDavid du Colombier
1175dc5a79c1SDavid du Colombier if(waserror()){
1176dc5a79c1SDavid du Colombier cclose(c);
1177dc5a79c1SDavid du Colombier nexterror();
1178dc5a79c1SDavid du Colombier }
1179dc5a79c1SDavid du Colombier if(c->ismtpt){
1180dc5a79c1SDavid du Colombier /*
1181dc5a79c1SDavid du Colombier * Renaming mount points is disallowed to avoid surprises
11824afe124fSDavid du Colombier * (which should be renamed? the mount point or the mounted Chan?).
1183dc5a79c1SDavid du Colombier */
1184dc5a79c1SDavid du Colombier dirname(d, &namelen);
1185dc5a79c1SDavid du Colombier if(namelen)
11864afe124fSDavid du Colombier nameerror(chanpath(c), Eismtpt);
1187dc5a79c1SDavid du Colombier }
1188dc5a79c1SDavid du Colombier l = devtab[c->type]->wstat(c, d, nd);
1189dc5a79c1SDavid du Colombier poperror();
1190dc5a79c1SDavid du Colombier cclose(c);
1191dc5a79c1SDavid du Colombier return l;
1192dc5a79c1SDavid du Colombier }
1193dc5a79c1SDavid du Colombier
11943e12c5d1SDavid du Colombier long
syswstat(ulong * arg)11953e12c5d1SDavid du Colombier syswstat(ulong *arg)
11963e12c5d1SDavid du Colombier {
11973e12c5d1SDavid du Colombier Chan *c;
11989a747e4fSDavid du Colombier uint l;
11993e12c5d1SDavid du Colombier
12009a747e4fSDavid du Colombier l = arg[2];
12019a747e4fSDavid du Colombier validaddr(arg[1], l, 0);
12029a747e4fSDavid du Colombier validstat((uchar*)arg[1], l);
12033e12c5d1SDavid du Colombier validaddr(arg[0], 1, 0);
12043e12c5d1SDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
1205dc5a79c1SDavid du Colombier return wstat(c, (uchar*)arg[1], l);
12063e12c5d1SDavid du Colombier }
12073e12c5d1SDavid du Colombier
12083e12c5d1SDavid du Colombier long
sysfwstat(ulong * arg)12093e12c5d1SDavid du Colombier sysfwstat(ulong *arg)
12103e12c5d1SDavid du Colombier {
12113e12c5d1SDavid du Colombier Chan *c;
12129a747e4fSDavid du Colombier uint l;
12133e12c5d1SDavid du Colombier
12149a747e4fSDavid du Colombier l = arg[2];
12159a747e4fSDavid du Colombier validaddr(arg[1], l, 0);
12169a747e4fSDavid du Colombier validstat((uchar*)arg[1], l);
12173e12c5d1SDavid du Colombier c = fdtochan(arg[0], -1, 1, 1);
1218dc5a79c1SDavid du Colombier return wstat(c, (uchar*)arg[1], l);
12199a747e4fSDavid du Colombier }
12209a747e4fSDavid du Colombier
12219a747e4fSDavid du Colombier static void
packoldstat(uchar * buf,Dir * d)12229a747e4fSDavid du Colombier packoldstat(uchar *buf, Dir *d)
12239a747e4fSDavid du Colombier {
12249a747e4fSDavid du Colombier uchar *p;
12259a747e4fSDavid du Colombier ulong q;
12269a747e4fSDavid du Colombier
12279a747e4fSDavid du Colombier /* lay down old stat buffer - grotty code but it's temporary */
12289a747e4fSDavid du Colombier p = buf;
12299a747e4fSDavid du Colombier strncpy((char*)p, d->name, 28);
12309a747e4fSDavid du Colombier p += 28;
12319a747e4fSDavid du Colombier strncpy((char*)p, d->uid, 28);
12329a747e4fSDavid du Colombier p += 28;
12339a747e4fSDavid du Colombier strncpy((char*)p, d->gid, 28);
12349a747e4fSDavid du Colombier p += 28;
12359a747e4fSDavid du Colombier q = d->qid.path & ~DMDIR; /* make sure doesn't accidentally look like directory */
12369a747e4fSDavid du Colombier if(d->qid.type & QTDIR) /* this is the real test of a new directory */
12379a747e4fSDavid du Colombier q |= DMDIR;
12389a747e4fSDavid du Colombier PBIT32(p, q);
12399a747e4fSDavid du Colombier p += BIT32SZ;
12409a747e4fSDavid du Colombier PBIT32(p, d->qid.vers);
12419a747e4fSDavid du Colombier p += BIT32SZ;
12429a747e4fSDavid du Colombier PBIT32(p, d->mode);
12439a747e4fSDavid du Colombier p += BIT32SZ;
12449a747e4fSDavid du Colombier PBIT32(p, d->atime);
12459a747e4fSDavid du Colombier p += BIT32SZ;
12469a747e4fSDavid du Colombier PBIT32(p, d->mtime);
12479a747e4fSDavid du Colombier p += BIT32SZ;
12489a747e4fSDavid du Colombier PBIT64(p, d->length);
12499a747e4fSDavid du Colombier p += BIT64SZ;
12509a747e4fSDavid du Colombier PBIT16(p, d->type);
12519a747e4fSDavid du Colombier p += BIT16SZ;
12529a747e4fSDavid du Colombier PBIT16(p, d->dev);
12539a747e4fSDavid du Colombier }
12549a747e4fSDavid du Colombier
12559a747e4fSDavid du Colombier long
sys_stat(ulong * arg)12569a747e4fSDavid du Colombier sys_stat(ulong *arg)
12579a747e4fSDavid du Colombier {
12589a747e4fSDavid du Colombier Chan *c;
12599a747e4fSDavid du Colombier uint l;
12609a747e4fSDavid du Colombier uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1261dc5a79c1SDavid du Colombier char strs[128], *name;
12629a747e4fSDavid du Colombier Dir d;
12639a747e4fSDavid du Colombier char old[] = "old stat system call - recompile";
12649a747e4fSDavid du Colombier
12659a747e4fSDavid du Colombier validaddr(arg[1], 116, 1);
12669a747e4fSDavid du Colombier validaddr(arg[0], 1, 0);
12679a747e4fSDavid du Colombier c = namec((char*)arg[0], Aaccess, 0, 0);
12689a747e4fSDavid du Colombier if(waserror()){
12699a747e4fSDavid du Colombier cclose(c);
12709a747e4fSDavid du Colombier nexterror();
12719a747e4fSDavid du Colombier }
12729a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, buf, sizeof buf);
12739a747e4fSDavid du Colombier /* buf contains a new stat buf; convert to old. yuck. */
12749a747e4fSDavid du Colombier if(l <= BIT16SZ) /* buffer too small; time to face reality */
12759a747e4fSDavid du Colombier error(old);
12764afe124fSDavid du Colombier name = pathlast(c->path);
1277dc5a79c1SDavid du Colombier if(name)
1278dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), buf, l, sizeof buf);
12799a747e4fSDavid du Colombier l = convM2D(buf, l, &d, strs);
12809a747e4fSDavid du Colombier if(l == 0)
12819a747e4fSDavid du Colombier error(old);
12829a747e4fSDavid du Colombier packoldstat((uchar*)arg[1], &d);
12839a747e4fSDavid du Colombier
12843e12c5d1SDavid du Colombier poperror();
12857dd7cddfSDavid du Colombier cclose(c);
12863e12c5d1SDavid du Colombier return 0;
12873e12c5d1SDavid du Colombier }
12889a747e4fSDavid du Colombier
12899a747e4fSDavid du Colombier long
sys_fstat(ulong * arg)12909a747e4fSDavid du Colombier sys_fstat(ulong *arg)
12919a747e4fSDavid du Colombier {
12929a747e4fSDavid du Colombier Chan *c;
1293dc5a79c1SDavid du Colombier char *name;
12949a747e4fSDavid du Colombier uint l;
12959a747e4fSDavid du Colombier uchar buf[128]; /* old DIRLEN plus a little should be plenty */
12969a747e4fSDavid du Colombier char strs[128];
12979a747e4fSDavid du Colombier Dir d;
12989a747e4fSDavid du Colombier char old[] = "old fstat system call - recompile";
12999a747e4fSDavid du Colombier
13009a747e4fSDavid du Colombier validaddr(arg[1], 116, 1);
13019a747e4fSDavid du Colombier c = fdtochan(arg[0], -1, 0, 1);
13029a747e4fSDavid du Colombier if(waserror()){
13039a747e4fSDavid du Colombier cclose(c);
13049a747e4fSDavid du Colombier nexterror();
13059a747e4fSDavid du Colombier }
13069a747e4fSDavid du Colombier l = devtab[c->type]->stat(c, buf, sizeof buf);
13079a747e4fSDavid du Colombier /* buf contains a new stat buf; convert to old. yuck. */
13089a747e4fSDavid du Colombier if(l <= BIT16SZ) /* buffer too small; time to face reality */
13099a747e4fSDavid du Colombier error(old);
13104afe124fSDavid du Colombier name = pathlast(c->path);
1311dc5a79c1SDavid du Colombier if(name)
1312dc5a79c1SDavid du Colombier l = dirsetname(name, strlen(name), buf, l, sizeof buf);
13139a747e4fSDavid du Colombier l = convM2D(buf, l, &d, strs);
13149a747e4fSDavid du Colombier if(l == 0)
13159a747e4fSDavid du Colombier error(old);
13169a747e4fSDavid du Colombier packoldstat((uchar*)arg[1], &d);
13179a747e4fSDavid du Colombier
13189a747e4fSDavid du Colombier poperror();
13199a747e4fSDavid du Colombier cclose(c);
13209a747e4fSDavid du Colombier return 0;
13219a747e4fSDavid du Colombier }
13229a747e4fSDavid du Colombier
13239a747e4fSDavid du Colombier long
sys_wstat(ulong *)13249a747e4fSDavid du Colombier sys_wstat(ulong *)
13259a747e4fSDavid du Colombier {
13269a747e4fSDavid du Colombier error("old wstat system call - recompile");
13279a747e4fSDavid du Colombier return -1;
13289a747e4fSDavid du Colombier }
13299a747e4fSDavid du Colombier
13309a747e4fSDavid du Colombier long
sys_fwstat(ulong *)13319a747e4fSDavid du Colombier sys_fwstat(ulong *)
13329a747e4fSDavid du Colombier {
13339a747e4fSDavid du Colombier error("old fwstat system call - recompile");
13349a747e4fSDavid du Colombier return -1;
13359a747e4fSDavid du Colombier }
1336