123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include "iotrack.h"
- #include "dat.h"
- #include "dosfs.h"
- #include "fns.h"
- void
- rversion(void)
- {
- if(req->msize > Maxiosize)
- rep->msize = Maxiosize;
- else
- rep->msize = req->msize;
- rep->version = "9P2000";
- }
- void
- rauth(void)
- {
- errno = Enoauth;
- }
- void
- rflush(void)
- {
- }
- void
- rattach(void)
- {
- Xfs *xf;
- Xfile *root;
- Dosptr *dp;
- root = xfile(req->fid, Clean);
- if(!root){
- errno = Enomem;
- goto error;
- }
- root->xf = xf = getxfs(req->uname, req->aname);
- if(!xf)
- goto error;
- if(xf->fmt == 0 && dosfs(xf) < 0){
- errno = Eformat;
- goto error;
- }
- root->qid.type = QTDIR;
- root->qid.path = 0;
- root->qid.vers = 0;
- root->xf->rootqid = root->qid;
- dp = malloc(sizeof(Dosptr));
- if(dp == nil){
- errno = Enomem;
- goto error;
- }
- root->ptr = dp;
- rootfile(root);
- rep->qid = root->qid;
- return;
- error:
- if(root)
- xfile(req->fid, Clunk);
- }
- Xfile*
- doclone(Xfile *of, int newfid)
- {
- Xfile *nf, *next;
- Dosptr *dp;
- nf = xfile(newfid, Clean);
- if(!nf){
- errno = Enomem;
- return nil;
- }
- dp = malloc(sizeof(Dosptr));
- if(dp == nil){
- errno = Enomem;
- return nil;
- }
- next = nf->next;
- *nf = *of;
- nf->next = next;
- nf->fid = req->newfid;
- nf->ptr = dp;
- refxfs(nf->xf, 1);
- memmove(dp, of->ptr, sizeof(Dosptr));
- dp->p = nil;
- dp->d = nil;
- return nf;
- }
- void
- rwalk(void)
- {
- Xfile *f, *nf;
- Dosptr dp[1], savedp[1];
- int r, longtype;
- Qid saveqid;
- rep->nwqid = 0;
- nf = nil;
- f = xfile(req->fid, Asis);
- if(f == nil){
- chat("\tno xfile\n");
- goto error2;
- }
- if(req->fid != req->newfid){
- nf = doclone(f, req->newfid);
- if(nf == nil){
- chat("\tclone failed\n");
- goto error2;
- }
- f = nf;
- }
- saveqid = f->qid;
- memmove(savedp, f->ptr, sizeof(Dosptr));
- for(; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
- chat("\twalking %s\n", req->wname[rep->nwqid]);
- if(!(f->qid.type & QTDIR)){
- chat("\tnot dir: type=%#x\n", f->qid.type);
- goto error;
- }
- if(strcmp(req->wname[rep->nwqid], ".") == 0){
- ;
- }else if(strcmp(req->wname[rep->nwqid], "..") == 0){
- if(f->qid.path != f->xf->rootqid.path){
- r = walkup(f, dp);
- if(r < 0)
- goto error;
- memmove(f->ptr, dp, sizeof(Dosptr));
- if(isroot(dp->addr))
- f->qid.path = f->xf->rootqid.path;
- else
- f->qid.path = QIDPATH(dp);
- }
- }else{
- fixname(req->wname[rep->nwqid]);
- longtype = classifyname(req->wname[rep->nwqid]);
- if(longtype==Invalid || getfile(f) < 0)
- goto error;
- /*
- * always do a search for the long name,
- * because it could be filed as such
- */
- r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
- putfile(f);
- if(r < 0)
- goto error;
- memmove(f->ptr, dp, sizeof(Dosptr));
- f->qid.path = QIDPATH(dp);
- f->qid.type = QTFILE;
- if(isroot(dp->addr))
- f->qid.path = f->xf->rootqid.path;
- else if(dp->d->attr & DDIR)
- f->qid.type = QTDIR;
- else if(dp->d->attr & DSYSTEM){
- f->qid.type |= QTEXCL;
- if(iscontig(f->xf, dp->d))
- f->qid.type |= QTAPPEND;
- }
- //ZZZ maybe use other bits than qtexcl & qtapppend
- putfile(f);
- }
- rep->wqid[rep->nwqid] = f->qid;
- }
- return;
- error:
- f->qid = saveqid;
- memmove(f->ptr, savedp, sizeof(Dosptr));
- if(nf != nil)
- xfile(req->newfid, Clunk);
- error2:
- if(!errno && !rep->nwqid)
- errno = Enonexist;
- }
- void
- ropen(void)
- {
- Xfile *f;
- Iosect *p;
- Dosptr *dp;
- int attr, omode;
- f = xfile(req->fid, Asis);
- if(!f || (f->flags&Omodes)){
- errno = Eio;
- return;
- }
- dp = f->ptr;
- omode = 0;
- if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
- /*
- * check on parent directory of file to be deleted
- */
- p = getsect(f->xf, dp->paddr);
- if(p == nil){
- errno = Eio;
- return;
- }
- attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
- putsect(p);
- if(attr & DRONLY){
- errno = Eperm;
- return;
- }
- omode |= Orclose;
- }else if(req->mode & ORCLOSE)
- omode |= Orclose;
- if(getfile(f) < 0){
- errno = Enonexist;
- return;
- }
- if(!isroot(dp->addr))
- attr = dp->d->attr;
- else
- attr = DDIR;
- switch(req->mode & 7){
- case OREAD:
- case OEXEC:
- omode |= Oread;
- break;
- case ORDWR:
- omode |= Oread;
- /* fall through */
- case OWRITE:
- omode |= Owrite;
- if(attr & DRONLY){
- errno = Eperm;
- goto out;
- }
- break;
- default:
- errno = Eio;
- goto out;
- }
- if(req->mode & OTRUNC){
- if(attr & DDIR || attr & DRONLY){
- errno = Eperm;
- goto out;
- }
- if(truncfile(f, 0) < 0){
- errno = Eio;
- goto out;
- }
- }
- f->flags |= omode;
- rep->qid = f->qid;
- rep->iounit = 0;
- out:
- putfile(f);
- }
- static int
- mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
- {
- Dosptr tmpdp;
- int i, longtype;
- if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
- return Invalid;
- /*
- * always do a search for the long name,
- * because it could be filed as such
- */
- fixname(name);
- longtype = classifyname(name);
- if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
- return Invalid;
- if(longtype==Short)
- return Short;
- if(longtype==ShortLower){
- /*
- * alias is the upper-case version, which we
- * already know does not exist.
- */
- strcpy(sname, name);
- for(i=0; sname[i]; i++)
- if('a' <= sname[i] && sname[i] <= 'z')
- sname[i] += 'A'-'a';
- return ShortLower;
- }
- /*
- * find alias for the long name
- */
- for(i=1;; i++){
- mkalias(name, sname, i);
- if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
- return Long;
- putsect(tmpdp.p);
- }
- }
- /*
- * fill in a directory entry for a new file
- */
- static int
- mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length)
- {
- Dosdir *nd;
- /*
- * fill in the entry
- */
- ndp->p = getsect(xf, ndp->addr);
- if(ndp->p == nil
- || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
- errno = Eio;
- return -1;
- }
- ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
- nd = ndp->d;
- memset(nd, 0, DOSDIRSIZE);
- if(longtype!=Short)
- name = sname;
- putname(name, nd);
- nd->attr = nattr;
- puttime(nd, 0);
- putstart(xf, nd, start);
- nd->length[0] = length;
- nd->length[1] = length>>8;
- nd->length[2] = length>>16;
- nd->length[3] = length>>24;
- ndp->p->flags |= BMOD;
- return 0;
- }
- void
- rcreate(void)
- {
- Dosbpb *bp;
- Xfile *f;
- Dosptr *pdp, *ndp;
- Iosect *xp;
- Dosdir *pd, *xd;
- char sname[13];
- long start;
- int longtype, attr, omode, nattr;
- f = xfile(req->fid, Asis);
- if(!f || (f->flags&Omodes) || getfile(f)<0){
- errno = Eio;
- return;
- }
- pdp = f->ptr;
- pd = pdp->d;
- /*
- * perm check
- */
- if(isroot(pdp->addr) && pd != nil)
- panic("root pd != nil");
- attr = pd ? pd->attr : DDIR;
- if(!(attr & DDIR) || (attr & DRONLY)){
- badperm:
- putfile(f);
- errno = Eperm;
- return;
- }
- omode = 0;
- if(req->mode & ORCLOSE)
- omode |= Orclose;
- switch(req->mode & 7){
- case OREAD:
- case OEXEC:
- omode |= Oread;
- break;
- case ORDWR:
- omode |= Oread;
- /* fall through */
- case OWRITE:
- omode |= Owrite;
- if(req->perm & DMDIR)
- goto badperm;
- break;
- default:
- goto badperm;
- }
- /*
- * check the name, find the slot for the dentry,
- * and find a good alias for a long name
- */
- ndp = malloc(sizeof(Dosptr));
- if(ndp == nil){
- putfile(f);
- errno = Enomem;
- return;
- }
- longtype = mk8dot3name(f, ndp, req->name, sname);
- chat("rcreate %s longtype %d...\n", req->name, longtype);
- if(longtype == Invalid){
- free(ndp);
- goto badperm;
- }
- /*
- * allocate first cluster, if making directory
- */
- start = 0;
- bp = nil;
- if(req->perm & DMDIR){
- bp = f->xf->ptr;
- mlock(bp);
- start = falloc(f->xf);
- unmlock(bp);
- if(start <= 0){
- free(ndp);
- putfile(f);
- errno = Eio;
- return;
- }
- }
- /*
- * make the entry
- */
- nattr = 0;
- if((req->perm & 0222) == 0)
- nattr |= DRONLY;
- if(req->perm & DMDIR)
- nattr |= DDIR;
- if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
- if(ndp->p != nil)
- putsect(ndp->p);
- free(ndp);
- if(start > 0)
- ffree(f->xf, start);
- putfile(f);
- return;
- }
- if(pd != nil){
- puttime(pd, 0);
- pdp->p->flags |= BMOD;
- }
- /*
- * fix up the fid
- */
- f->ptr = ndp;
- f->qid.type = QTFILE;
- f->qid.path = QIDPATH(ndp);
- //ZZZ set type for excl, append?
- if(req->perm & DMDIR){
- f->qid.type = QTDIR;
- xp = getsect(f->xf, clust2sect(bp, start));
- if(xp == nil){
- errno = Eio;
- goto badio;
- }
- xd = (Dosdir *)&xp->iobuf[0];
- memmove(xd, ndp->d, DOSDIRSIZE);
- memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
- xd->name[0] = '.';
- xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
- if(pd)
- memmove(xd, pd, DOSDIRSIZE);
- else{
- memset(xd, 0, DOSDIRSIZE);
- puttime(xd, 0);
- xd->attr = DDIR;
- }
- memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
- xd->name[0] = '.';
- xd->name[1] = '.';
- xp->flags |= BMOD;
- putsect(xp);
- }
- f->flags |= omode;
- rep->qid = f->qid;
- rep->iounit = 0;
- badio:
- putfile(f);
- putsect(pdp->p);
- free(pdp);
- }
- void
- rread(void)
- {
- Xfile *f;
- int r;
- if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
- goto error;
- if(req->count > sizeof repdata)
- req->count = sizeof repdata;
- if(f->qid.type & QTDIR){
- if(getfile(f) < 0)
- goto error;
- r = readdir(f, repdata, req->offset, req->count);
- }else{
- if(getfile(f) < 0)
- goto error;
- r = readfile(f, repdata, req->offset, req->count);
- }
- putfile(f);
- if(r < 0){
- error:
- errno = Eio;
- }else{
- rep->count = r;
- rep->data = (char*)repdata;
- }
- }
- void
- rwrite(void)
- {
- Xfile *f;
- int r;
- if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
- goto error;
- if(getfile(f) < 0)
- goto error;
- r = writefile(f, req->data, req->offset, req->count);
- putfile(f);
- if(r < 0){
- error:
- errno = Eio;
- }else{
- rep->count = r;
- }
- }
- void
- rclunk(void)
- {
- xfile(req->fid, Clunk);
- sync();
- }
- /*
- * wipe out a dos directory entry
- */
- static void
- doremove(Xfs *xf, Dosptr *dp)
- {
- Iosect *p;
- int prevdo;
- dp->p->iobuf[dp->offset] = DOSEMPTY;
- dp->p->flags |= BMOD;
- for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
- if(dp->p->iobuf[prevdo+11] != 0xf)
- break;
- dp->p->iobuf[prevdo] = DOSEMPTY;
- }
- if(prevdo < 0 && dp->prevaddr != -1){
- p = getsect(xf, dp->prevaddr);
- for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
- if(p->iobuf[prevdo+11] != 0xf)
- break;
- p->iobuf[prevdo] = DOSEMPTY;
- p->flags |= BMOD;
- }
- putsect(p);
- }
- }
- void
- rremove(void)
- {
- Xfile *f;
- Dosptr *dp;
- Iosect *parp;
- Dosdir *pard;
- f = xfile(req->fid, Asis);
- parp = nil;
- if(f == nil){
- errno = Eio;
- goto out;
- }
- dp = f->ptr;
- if(isroot(dp->addr)){
- errno = Eperm;
- goto out;
- }
- /*
- * can't remove if parent is read only,
- * it's a non-empty directory,
- * or it's a read only file in the root directory
- */
- parp = getsect(f->xf, dp->paddr);
- if(parp == nil
- || getfile(f) < 0){
- errno = Eio;
- goto out;
- }
- pard = (Dosdir *)&parp->iobuf[dp->poffset];
- if(!isroot(dp->paddr) && (pard->attr & DRONLY)
- || (dp->d->attr & DDIR) && emptydir(f) < 0
- || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
- errno = Eperm;
- goto out;
- }
- if(truncfile(f, 0) < 0){
- errno = Eio;
- goto out;
- }
- doremove(f->xf, f->ptr);
- if(!isroot(dp->paddr)){
- puttime(pard, 0);
- parp->flags |= BMOD;
- }
- out:
- if(parp != nil)
- putsect(parp);
- if(f != nil)
- putfile(f);
- xfile(req->fid, Clunk);
- sync();
- }
- static void
- dostat(Xfile *f, Dir *d)
- {
- Dosptr *dp;
- Iosect *p;
- char *name, namebuf[DOSNAMELEN];
- int islong, sum, prevdo;
- dp = f->ptr;
- if(isroot(dp->addr)){
- memset(d, 0, sizeof(Dir));
- d->name = "/";
- d->qid.type = QTDIR;
- d->qid.path = f->xf->rootqid.path;
- d->mode = DMDIR|0777;
- d->uid = "bill";
- d->muid = "bill";
- d->gid = "trog";
- }else{
- /*
- * assemble any long file name
- */
- sum = aliassum(dp->d);
- islong = 0;
- name = namebuf;
- for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
- if(dp->p->iobuf[prevdo+11] != 0xf)
- break;
- name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
- }
- if(prevdo < 0 && dp->prevaddr != -1){
- p = getsect(f->xf, dp->prevaddr);
- for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
- if(p->iobuf[prevdo+11] != 0xf)
- break;
- name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
- }
- putsect(p);
- }
- getdir(f->xf, d, dp->d, dp->addr, dp->offset);
- if(islong && sum == -1 && nameok(namebuf))
- strcpy(d->name, namebuf);
- }
- }
- void
- rstat(void)
- {
- Dir dir;
- Xfile *f;
- f = xfile(req->fid, Asis);
- if(!f || getfile(f) < 0){
- errno = Eio;
- return;
- }
- dir.name = repdata;
- dostat(f, &dir);
- rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
- rep->stat = statbuf;
- putfile(f);
- }
- void
- rwstat(void)
- {
- Dir dir, wdir;
- Xfile *f, pf;
- Dosptr *dp, ndp, pdp;
- Iosect *parp;
- Dosdir *pard, *d, od;
- char sname[13];
- ulong oaddr, ooffset;
- long start, length;
- int i, longtype, changes, attr;
- f = xfile(req->fid, Asis);
- if(!f || getfile(f) < 0){
- errno = Eio;
- return;
- }
- dp = f->ptr;
- if(isroot(dp->addr)){
- errno = Eperm;
- goto out;
- }
- changes = 0;
- dir.name = repdata;
- dostat(f, &dir);
- if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
- errno = Ebadstat;
- goto out;
- }
- /*
- * To change length, must have write permission on file.
- * we only allow truncates for now.
- */
- if(wdir.length!=~0 && wdir.length!=dir.length){
- if(wdir.length > dir.length || !dir.mode & 0222){
- errno = Eperm;
- goto out;
- }
- }
- /*
- * no chown or chgrp
- */
- if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
- || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
- errno = Eperm;
- goto out;
- }
- /*
- * mode/mtime allowed
- */
- if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
- changes = 1;
- /*
- * Setting DMAPPEND (make system file contiguous)
- * requires setting DMEXCL (system file).
- */
- if(wdir.mode != ~0){
- if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
- || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
- errno = Eperm;
- goto out;
- }
- if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
- changes = 1;
- if((dir.mode^wdir.mode) & DMAPPEND) {
- if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
- errno = Eperm;
- goto out;
- }
- if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
- errno = Econtig;
- goto out;
- }
- }
- }
- /*
- * to rename:
- * 1) make up a fake clone
- * 2) walk to parent
- * 3) remove the old entry
- * 4) create entry with new name
- * 5) write correct mode/mtime info
- * we need to remove the old entry before creating the new one
- * to avoid a lock loop.
- */
- if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
- if(utflen(wdir.name) >= DOSNAMELEN){
- errno = Etoolong;
- goto out;
- }
- /*
- * grab parent directory of file to be changed and check for write perm
- * rename also disallowed for read-only files in root directory
- */
- parp = getsect(f->xf, dp->paddr);
- if(parp == nil){
- errno = Eio;
- goto out;
- }
- pard = (Dosdir *)&parp->iobuf[dp->poffset];
- if(!isroot(dp->paddr) && (pard->attr & DRONLY)
- || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
- putsect(parp);
- errno = Eperm;
- goto out;
- }
- /*
- * retrieve info from old entry
- */
- oaddr = dp->addr;
- ooffset = dp->offset;
- d = dp->d;
- od = *d;
- start = getstart(f->xf, d);
- length = GLONG(d->length);
- attr = d->attr;
- /*
- * temporarily release file to allow other directory ops:
- * walk to parent, validate new name
- * then remove old entry
- */
- putfile(f);
- pf = *f;
- memset(&pdp, 0, sizeof(Dosptr));
- pdp.prevaddr = -1;
- pdp.naddr = -1;
- pdp.addr = dp->paddr;
- pdp.offset = dp->poffset;
- pdp.p = parp;
- if(!isroot(pdp.addr))
- pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
- pf.ptr = &pdp;
- longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
- if(longtype==Invalid){
- putsect(parp);
- errno = Eperm;
- return;
- }
- if(getfile(f) < 0){
- putsect(parp);
- errno = Eio;
- return;
- }
- doremove(f->xf, dp);
- putfile(f);
- /*
- * search for dir entry again, since we may be able to use the old slot,
- * and we need to set up the naddr field if a long name spans the block.
- * create new entry.
- */
- if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
- || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
- putsect(parp);
- errno = Eio;
- goto out;
- }
- /*
- * copy invisible fields
- */
- d = dp->d;
- for(i = 0; i < 2; i++)
- d->ctime[i] = od.ctime[i];
- for(i = 0; i < nelem(od.cdate); i++)
- d->cdate[i] = od.cdate[i];
- for(i = 0; i < nelem(od.adate); i++)
- d->adate[i] = od.adate[i];
- putsect(parp);
- /*
- * relocate up other fids to the same file, if it moved
- */
- f->qid.path = QIDPATH(dp);
- if(oaddr != dp->addr || ooffset != dp->offset)
- dosptrreloc(f, dp, oaddr, ooffset);
- /*
- * copy fields that are not supposed to change
- */
- if(wdir.mtime == ~0)
- wdir.mtime = dir.mtime;
- if(wdir.mode == ~0)
- wdir.mode = dir.mode;
- changes = 1;
- }
- /*
- * do the actual truncate
- */
- if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
- errno = Eio;
- if(changes){
- putdir(dp->d, &wdir);
- dp->p->flags |= BMOD;
- }
- out:
- putfile(f);
- sync();
- }
|