13 if(req->msize > Maxiosize)
14 rep->msize = Maxiosize;
16 rep->msize = req->msize;
17 rep->version = "9P2000";
38 root = xfile(req->fid, Clean);
43 root->xf = xf = getxfs(req->uname, req->aname);
46 if(xf->fmt == 0 && dosfs(xf) < 0){
50 root->qid.type = QTDIR;
53 root->xf->rootqid = root->qid;
54 dp = malloc(sizeof(Dosptr));
65 xfile(req->fid, Clunk);
69 doclone(Xfile *of, int newfid)
74 nf = xfile(newfid, Clean);
79 dp = malloc(sizeof(Dosptr));
87 nf->fid = req->newfid;
90 memmove(dp, of->ptr, sizeof(Dosptr));
100 Dosptr dp[1], savedp[1];
106 f = xfile(req->fid, Asis);
108 chat("\tno xfile\n");
111 if(req->fid != req->newfid){
112 nf = doclone(f, req->newfid);
114 chat("\tclone failed\n");
121 memmove(savedp, f->ptr, sizeof(Dosptr));
122 for(; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
123 chat("\twalking %s\n", req->wname[rep->nwqid]);
124 if(!(f->qid.type & QTDIR)){
125 chat("\tnot dir: type=%#x\n", f->qid.type);
128 if(strcmp(req->wname[rep->nwqid], ".") == 0){
130 }else if(strcmp(req->wname[rep->nwqid], "..") == 0){
131 if(f->qid.path != f->xf->rootqid.path){
135 memmove(f->ptr, dp, sizeof(Dosptr));
137 f->qid.path = f->xf->rootqid.path;
139 f->qid.path = QIDPATH(dp);
142 fixname(req->wname[rep->nwqid]);
143 longtype = classifyname(req->wname[rep->nwqid]);
144 if(longtype==Invalid || getfile(f) < 0)
148 * always do a search for the long name,
149 * because it could be filed as such
151 r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
155 memmove(f->ptr, dp, sizeof(Dosptr));
156 f->qid.path = QIDPATH(dp);
157 f->qid.type = QTFILE;
159 f->qid.path = f->xf->rootqid.path;
160 else if(dp->d->attr & DDIR)
162 else if(dp->d->attr & DSYSTEM){
163 f->qid.type |= QTEXCL;
164 if(iscontig(f->xf, dp->d))
165 f->qid.type |= QTAPPEND;
167 //ZZZ maybe use other bits than qtexcl & qtapppend
170 rep->wqid[rep->nwqid] = f->qid;
175 memmove(f->ptr, savedp, sizeof(Dosptr));
177 xfile(req->newfid, Clunk);
179 if(!errno && !rep->nwqid)
191 f = xfile(req->fid, Asis);
192 if(!f || (f->flags&Omodes)){
198 if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
200 * check on parent directory of file to be deleted
202 p = getsect(f->xf, dp->paddr);
207 attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
214 }else if(req->mode & ORCLOSE)
220 if(!isroot(dp->addr))
224 switch(req->mode & 7){
243 if(req->mode & OTRUNC){
244 if(attr & DDIR || attr & DRONLY){
248 if(truncfile(f, 0) < 0){
261 mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
266 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
270 * always do a search for the long name,
271 * because it could be filed as such
274 longtype = classifyname(name);
275 if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
281 if(longtype==ShortLower){
283 * alias is the upper-case version, which we
284 * already know does not exist.
287 for(i=0; sname[i]; i++)
288 if('a' <= sname[i] && sname[i] <= 'z')
294 * find alias for the long name
297 mkalias(name, sname, i);
298 if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
305 * fill in a directory entry for a new file
308 mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, ulong length)
315 ndp->p = getsect(xf, ndp->addr);
317 || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
322 ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
324 memset(nd, 0, DOSDIRSIZE);
332 PSHORT(nd->cdate, GSHORT(nd->date));
333 PSHORT(nd->ctime, GSHORT(nd->time));
335 putstart(xf, nd, start);
336 PLONG(nd->length, length);
338 ndp->p->flags |= BMOD;
353 int longtype, attr, omode, nattr;
355 f = xfile(req->fid, Asis);
356 if(!f || (f->flags&Omodes) || getfile(f)<0){
365 if(isroot(pdp->addr) && pd != nil)
366 panic("root pd != nil");
367 attr = pd ? pd->attr : DDIR;
368 if(!(attr & DDIR) || (attr & DRONLY)){
375 if(req->mode & ORCLOSE)
377 switch(req->mode & 7){
387 if(req->perm & DMDIR)
395 * check the name, find the slot for the dentry,
396 * and find a good alias for a long name
398 ndp = malloc(sizeof(Dosptr));
404 longtype = mk8dot3name(f, ndp, req->name, sname);
405 chat("rcreate %s longtype %d...\n", req->name, longtype);
406 if(longtype == Invalid){
412 * allocate first cluster, if making directory
416 if(req->perm & DMDIR){
419 start = falloc(f->xf);
433 if((req->perm & 0222) == 0)
435 if(req->perm & DMDIR)
438 if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
450 pdp->p->flags |= BMOD;
457 f->qid.type = QTFILE;
458 f->qid.path = QIDPATH(ndp);
460 //ZZZ set type for excl, append?
461 if(req->perm & DMDIR){
463 xp = getsect(f->xf, clust2sect(bp, start));
468 xd = (Dosdir *)&xp->iobuf[0];
469 memmove(xd, ndp->d, DOSDIRSIZE);
470 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
472 xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
474 memmove(xd, pd, DOSDIRSIZE);
476 memset(xd, 0, DOSDIRSIZE);
480 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
503 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
505 if(req->count > sizeof repdata)
506 req->count = sizeof repdata;
509 if(f->qid.type & QTDIR)
510 r = readdir(f, repdata, req->offset, req->count);
512 r = readfile(f, repdata, req->offset, req->count);
519 rep->data = (char*)repdata;
529 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
533 r = writefile(f, req->data, req->offset, req->count);
546 xfile(req->fid, Clunk);
551 * wipe out a dos directory entry
554 doremove(Xfs *xf, Dosptr *dp)
559 dp->p->iobuf[dp->offset] = DOSEMPTY;
560 dp->p->flags |= BMOD;
561 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
562 if(dp->p->iobuf[prevdo+11] != 0xf)
564 dp->p->iobuf[prevdo] = DOSEMPTY;
566 if(prevdo < 0 && dp->prevaddr != -1){
567 p = getsect(xf, dp->prevaddr);
568 for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
569 if(p->iobuf[prevdo+11] != 0xf)
571 p->iobuf[prevdo] = DOSEMPTY;
586 f = xfile(req->fid, Asis);
593 if(isroot(dp->addr)){
599 * can't remove if parent is read only,
600 * it's a non-empty directory,
601 * or it's a read only file in the root directory
603 parp = getsect(f->xf, dp->paddr);
609 pard = (Dosdir *)&parp->iobuf[dp->poffset];
610 if(!isroot(dp->paddr) && (pard->attr & DRONLY)
611 || (dp->d->attr & DDIR) && emptydir(f) < 0
612 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
616 if(truncfile(f, 0) < 0){
620 doremove(f->xf, f->ptr);
621 if(!isroot(dp->paddr)){
630 xfile(req->fid, Clunk);
635 dostat(Xfile *f, Dir *d)
639 char *name, namebuf[DOSNAMELEN];
640 int islong, sum, prevdo;
643 if(isroot(dp->addr)){
644 memset(d, 0, sizeof(Dir));
647 d->qid.path = f->xf->rootqid.path;
648 d->mode = DMDIR|0777;
654 * assemble any long file name
656 sum = aliassum(dp->d);
659 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
660 if(dp->p->iobuf[prevdo+11] != 0xf)
662 name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
664 if(prevdo < 0 && dp->prevaddr != -1){
665 p = getsect(f->xf, dp->prevaddr);
668 for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
669 if(p->iobuf[prevdo+11] != 0xf)
671 name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
675 getdir(f->xf, d, dp->d, dp->addr, dp->offset);
676 if(islong && sum == -1 && nameok(namebuf))
677 strcpy(d->name, namebuf);
688 f = xfile(req->fid, Asis);
689 if(!f || getfile(f) < 0){
694 if(dostat(f, &dir) < 0)
697 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
708 Dosptr *dp, ndp, pdp;
710 Dosdir *pard, *d, od;
712 ulong ooffset, length;
715 int i, longtype, changes, attr;
717 f = xfile(req->fid, Asis);
718 if(!f || getfile(f) < 0){
724 if(isroot(dp->addr)){
731 if(dostat(f, &dir) < 0){
736 if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
742 * To change length, must have write permission on file.
743 * we only allow truncates for now.
745 if(wdir.length!=~0 && wdir.length!=dir.length){
746 if(wdir.length > dir.length || !dir.mode & 0222){
755 if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
756 || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
764 if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
768 * Setting DMAPPEND (make system file contiguous)
769 * requires setting DMEXCL (system file).
772 if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
773 || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
777 if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
779 if((dir.mode^wdir.mode) & DMAPPEND) {
780 if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
784 if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
794 * 1) make up a fake clone
796 * 3) remove the old entry
797 * 4) create entry with new name
798 * 5) write correct mode/mtime info
799 * we need to remove the old entry before creating the new one
800 * to avoid a lock loop.
802 if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
803 if(utflen(wdir.name) >= DOSNAMELEN){
809 * grab parent directory of file to be changed and check for write perm
810 * rename also disallowed for read-only files in root directory
812 parp = getsect(f->xf, dp->paddr);
817 pard = (Dosdir *)&parp->iobuf[dp->poffset];
818 if(!isroot(dp->paddr) && (pard->attr & DRONLY)
819 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
826 * retrieve info from old entry
829 ooffset = dp->offset;
832 start = getstart(f->xf, d);
833 length = GLONG(d->length);
837 * temporarily release file to allow other directory ops:
838 * walk to parent, validate new name
839 * then remove old entry
843 memset(&pdp, 0, sizeof(Dosptr));
846 pdp.addr = dp->paddr;
847 pdp.offset = dp->poffset;
849 if(!isroot(pdp.addr))
850 pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
852 longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
853 if(longtype==Invalid){
867 * search for dir entry again, since we may be able to use the old slot,
868 * and we need to set up the naddr field if a long name spans the block.
871 if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
872 || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
879 * copy invisible fields
882 d->ctimetenth = od.ctimetenth;
883 for(i = 0; i < nelem(od.ctime); i++)
884 d->ctime[i] = od.ctime[i];
885 for(i = 0; i < nelem(od.cdate); i++)
886 d->cdate[i] = od.cdate[i];
887 for(i = 0; i < nelem(od.adate); i++)
888 d->adate[i] = od.adate[i];
893 * relocate up other fids to the same file, if it moved
895 f->qid.path = QIDPATH(dp);
896 if(oaddr != dp->addr || ooffset != dp->offset)
897 dosptrreloc(f, dp, oaddr, ooffset);
900 * copy fields that are not supposed to change
903 wdir.mtime = dir.mtime;
905 wdir.mode = dir.mode;
910 * do the actual truncate
912 if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
916 putdir(dp->d, &wdir);
917 dp->p->flags |= BMOD;