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, long 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 putstart(xf, nd, start);
333 nd->length[0] = length;
334 nd->length[1] = length>>8;
335 nd->length[2] = length>>16;
336 nd->length[3] = length>>24;
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;
507 if(f->qid.type & QTDIR){
510 r = readdir(f, repdata, req->offset, req->count);
514 r = readfile(f, repdata, req->offset, req->count);
522 rep->data = (char*)repdata;
532 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
536 r = writefile(f, req->data, req->offset, req->count);
549 xfile(req->fid, Clunk);
554 * wipe out a dos directory entry
557 doremove(Xfs *xf, Dosptr *dp)
562 dp->p->iobuf[dp->offset] = DOSEMPTY;
563 dp->p->flags |= BMOD;
564 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
565 if(dp->p->iobuf[prevdo+11] != 0xf)
567 dp->p->iobuf[prevdo] = DOSEMPTY;
569 if(prevdo < 0 && dp->prevaddr != -1){
570 p = getsect(xf, dp->prevaddr);
571 for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
572 if(p->iobuf[prevdo+11] != 0xf)
574 p->iobuf[prevdo] = DOSEMPTY;
589 f = xfile(req->fid, Asis);
596 if(isroot(dp->addr)){
602 * can't remove if parent is read only,
603 * it's a non-empty directory,
604 * or it's a read only file in the root directory
606 parp = getsect(f->xf, dp->paddr);
612 pard = (Dosdir *)&parp->iobuf[dp->poffset];
613 if(!isroot(dp->paddr) && (pard->attr & DRONLY)
614 || (dp->d->attr & DDIR) && emptydir(f) < 0
615 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
619 if(truncfile(f, 0) < 0){
623 doremove(f->xf, f->ptr);
624 if(!isroot(dp->paddr)){
633 xfile(req->fid, Clunk);
638 dostat(Xfile *f, Dir *d)
642 char *name, namebuf[DOSNAMELEN];
643 int islong, sum, prevdo;
646 if(isroot(dp->addr)){
647 memset(d, 0, sizeof(Dir));
650 d->qid.path = f->xf->rootqid.path;
651 d->mode = DMDIR|0777;
657 * assemble any long file name
659 sum = aliassum(dp->d);
662 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
663 if(dp->p->iobuf[prevdo+11] != 0xf)
665 name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
667 if(prevdo < 0 && dp->prevaddr != -1){
668 p = getsect(f->xf, dp->prevaddr);
669 for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
670 if(p->iobuf[prevdo+11] != 0xf)
672 name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
676 getdir(f->xf, d, dp->d, dp->addr, dp->offset);
677 if(islong && sum == -1 && nameok(namebuf))
678 strcpy(d->name, namebuf);
688 f = xfile(req->fid, Asis);
689 if(!f || getfile(f) < 0){
697 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
707 Dosptr *dp, ndp, pdp;
709 Dosdir *pard, *d, od;
711 ulong oaddr, ooffset;
713 int i, longtype, changes, attr;
715 f = xfile(req->fid, Asis);
716 if(!f || getfile(f) < 0){
722 if(isroot(dp->addr)){
730 if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
736 * To change length, must have write permission on file.
737 * we only allow truncates for now.
739 if(wdir.length!=~0 && wdir.length!=dir.length){
740 if(wdir.length > dir.length || !dir.mode & 0222){
749 if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
750 || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
758 if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
762 * Setting DMAPPEND (make system file contiguous)
763 * requires setting DMEXCL (system file).
766 if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
767 || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
771 if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
773 if((dir.mode^wdir.mode) & DMAPPEND) {
774 if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
778 if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
788 * 1) make up a fake clone
790 * 3) remove the old entry
791 * 4) create entry with new name
792 * 5) write correct mode/mtime info
793 * we need to remove the old entry before creating the new one
794 * to avoid a lock loop.
796 if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
797 if(utflen(wdir.name) >= DOSNAMELEN){
803 * grab parent directory of file to be changed and check for write perm
804 * rename also disallowed for read-only files in root directory
806 parp = getsect(f->xf, dp->paddr);
811 pard = (Dosdir *)&parp->iobuf[dp->poffset];
812 if(!isroot(dp->paddr) && (pard->attr & DRONLY)
813 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
820 * retrieve info from old entry
823 ooffset = dp->offset;
826 start = getstart(f->xf, d);
827 length = GLONG(d->length);
831 * temporarily release file to allow other directory ops:
832 * walk to parent, validate new name
833 * then remove old entry
837 memset(&pdp, 0, sizeof(Dosptr));
840 pdp.addr = dp->paddr;
841 pdp.offset = dp->poffset;
843 if(!isroot(pdp.addr))
844 pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
846 longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
847 if(longtype==Invalid){
861 * search for dir entry again, since we may be able to use the old slot,
862 * and we need to set up the naddr field if a long name spans the block.
865 if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
866 || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
873 * copy invisible fields
876 for(i = 0; i < 2; i++)
877 d->ctime[i] = od.ctime[i];
878 for(i = 0; i < nelem(od.cdate); i++)
879 d->cdate[i] = od.cdate[i];
880 for(i = 0; i < nelem(od.adate); i++)
881 d->adate[i] = od.adate[i];
886 * relocate up other fids to the same file, if it moved
888 f->qid.path = QIDPATH(dp);
889 if(oaddr != dp->addr || ooffset != dp->offset)
890 dosptrreloc(f, dp, oaddr, ooffset);
893 * copy fields that are not supposed to change
896 wdir.mtime = dir.mtime;
898 wdir.mode = dir.mode;
903 * do the actual truncate
905 if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
909 putdir(dp->d, &wdir);
910 dp->p->flags |= BMOD;