1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "iotrack.h"
6 #include "dat.h"
7 #include "dosfs.h"
8 #include "fns.h"
9
10 void
rversion(void)11 rversion(void)
12 {
13 if(req->msize > Maxiosize)
14 rep->msize = Maxiosize;
15 else
16 rep->msize = req->msize;
17 rep->version = "9P2000";
18 }
19
20 void
rauth(void)21 rauth(void)
22 {
23 errno = Enoauth;
24 }
25
26 void
rflush(void)27 rflush(void)
28 {
29 }
30
31 void
rattach(void)32 rattach(void)
33 {
34 Xfs *xf;
35 Xfile *root;
36 Dosptr *dp;
37
38 root = xfile(req->fid, Clean);
39 if(!root){
40 errno = Enomem;
41 goto error;
42 }
43 root->xf = xf = getxfs(req->uname, req->aname);
44 if(!xf)
45 goto error;
46 if(xf->fmt == 0 && dosfs(xf) < 0){
47 errno = Eformat;
48 goto error;
49 }
50 root->qid.type = QTDIR;
51 root->qid.path = 0;
52 root->qid.vers = 0;
53 root->xf->rootqid = root->qid;
54 dp = malloc(sizeof(Dosptr));
55 if(dp == nil){
56 errno = Enomem;
57 goto error;
58 }
59 root->ptr = dp;
60 rootfile(root);
61 rep->qid = root->qid;
62 return;
63 error:
64 if(root)
65 xfile(req->fid, Clunk);
66 }
67
68 Xfile*
doclone(Xfile * of,int newfid)69 doclone(Xfile *of, int newfid)
70 {
71 Xfile *nf, *next;
72 Dosptr *dp;
73
74 nf = xfile(newfid, Clean);
75 if(!nf){
76 errno = Enomem;
77 return nil;
78 }
79 dp = malloc(sizeof(Dosptr));
80 if(dp == nil){
81 errno = Enomem;
82 return nil;
83 }
84 next = nf->next;
85 *nf = *of;
86 nf->next = next;
87 nf->fid = req->newfid;
88 nf->ptr = dp;
89 refxfs(nf->xf, 1);
90 memmove(dp, of->ptr, sizeof(Dosptr));
91 dp->p = nil;
92 dp->d = nil;
93 return nf;
94 }
95
96 void
rwalk(void)97 rwalk(void)
98 {
99 Xfile *f, *nf;
100 Dosptr dp[1], savedp[1];
101 int r, longtype;
102 Qid saveqid;
103
104 rep->nwqid = 0;
105 nf = nil;
106 f = xfile(req->fid, Asis);
107 if(f == nil){
108 chat("\tno xfile\n");
109 goto error2;
110 }
111 if(req->fid != req->newfid){
112 nf = doclone(f, req->newfid);
113 if(nf == nil){
114 chat("\tclone failed\n");
115 goto error2;
116 }
117 f = nf;
118 }
119
120 saveqid = f->qid;
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);
126 goto error;
127 }
128 if(strcmp(req->wname[rep->nwqid], ".") == 0){
129 ;
130 }else if(strcmp(req->wname[rep->nwqid], "..") == 0){
131 if(f->qid.path != f->xf->rootqid.path){
132 r = walkup(f, dp);
133 if(r < 0)
134 goto error;
135 memmove(f->ptr, dp, sizeof(Dosptr));
136 if(isroot(dp->addr))
137 f->qid.path = f->xf->rootqid.path;
138 else
139 f->qid.path = QIDPATH(dp);
140 }
141 }else{
142 fixname(req->wname[rep->nwqid]);
143 longtype = classifyname(req->wname[rep->nwqid]);
144 if(longtype==Invalid || getfile(f) < 0)
145 goto error;
146
147 /*
148 * always do a search for the long name,
149 * because it could be filed as such
150 */
151 r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
152 putfile(f);
153 if(r < 0)
154 goto error;
155 memmove(f->ptr, dp, sizeof(Dosptr));
156 f->qid.path = QIDPATH(dp);
157 f->qid.type = QTFILE;
158 if(isroot(dp->addr))
159 f->qid.path = f->xf->rootqid.path;
160 else if(dp->d->attr & DDIR)
161 f->qid.type = QTDIR;
162 else if(dp->d->attr & DSYSTEM){
163 f->qid.type |= QTEXCL;
164 if(iscontig(f->xf, dp->d))
165 f->qid.type |= QTAPPEND;
166 }
167 //ZZZ maybe use other bits than qtexcl & qtapppend
168 putfile(f);
169 }
170 rep->wqid[rep->nwqid] = f->qid;
171 }
172 return;
173 error:
174 f->qid = saveqid;
175 memmove(f->ptr, savedp, sizeof(Dosptr));
176 if(nf != nil)
177 xfile(req->newfid, Clunk);
178 error2:
179 if(!errno && !rep->nwqid)
180 errno = Enonexist;
181 }
182
183 void
ropen(void)184 ropen(void)
185 {
186 Xfile *f;
187 Iosect *p;
188 Dosptr *dp;
189 int attr, omode;
190
191 f = xfile(req->fid, Asis);
192 if(!f || (f->flags&Omodes)){
193 errno = Eio;
194 return;
195 }
196 dp = f->ptr;
197 omode = 0;
198 if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
199 /*
200 * check on parent directory of file to be deleted
201 */
202 p = getsect(f->xf, dp->paddr);
203 if(p == nil){
204 errno = Eio;
205 return;
206 }
207 attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
208 putsect(p);
209 if(attr & DRONLY){
210 errno = Eperm;
211 return;
212 }
213 omode |= Orclose;
214 }else if(req->mode & ORCLOSE)
215 omode |= Orclose;
216 if(getfile(f) < 0){
217 errno = Enonexist;
218 return;
219 }
220 if(!isroot(dp->addr))
221 attr = dp->d->attr;
222 else
223 attr = DDIR;
224 switch(req->mode & 7){
225 case OREAD:
226 case OEXEC:
227 omode |= Oread;
228 break;
229 case ORDWR:
230 omode |= Oread;
231 /* fall through */
232 case OWRITE:
233 omode |= Owrite;
234 if(attr & DRONLY){
235 errno = Eperm;
236 goto out;
237 }
238 break;
239 default:
240 errno = Eio;
241 goto out;
242 }
243 if(req->mode & OTRUNC){
244 if(attr & DDIR || attr & DRONLY){
245 errno = Eperm;
246 goto out;
247 }
248 if(truncfile(f, 0) < 0){
249 errno = Eio;
250 goto out;
251 }
252 }
253 f->flags |= omode;
254 rep->qid = f->qid;
255 rep->iounit = 0;
256 out:
257 putfile(f);
258 }
259
260 static int
mk8dot3name(Xfile * f,Dosptr * ndp,char * name,char * sname)261 mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
262 {
263 Dosptr tmpdp;
264 int i, longtype;
265
266 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
267 return Invalid;
268
269 /*
270 * always do a search for the long name,
271 * because it could be filed as such
272 */
273 fixname(name);
274 longtype = classifyname(name);
275 if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
276 return Invalid;
277
278 if(longtype==Short)
279 return Short;
280
281 if(longtype==ShortLower){
282 /*
283 * alias is the upper-case version, which we
284 * already know does not exist.
285 */
286 strcpy(sname, name);
287 for(i=0; sname[i]; i++)
288 if('a' <= sname[i] && sname[i] <= 'z')
289 sname[i] += 'A'-'a';
290 return ShortLower;
291 }
292
293 /*
294 * find alias for the long name
295 */
296 for(i=1;; i++){
297 mkalias(name, sname, i);
298 if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
299 return Long;
300 putsect(tmpdp.p);
301 }
302 }
303
304 /*
305 * fill in a directory entry for a new file
306 */
307 static int
mkdentry(Xfs * xf,Dosptr * ndp,char * name,char * sname,int longtype,int nattr,long start,long length)308 mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length)
309 {
310 Dosdir *nd;
311
312 /*
313 * fill in the entry
314 */
315 ndp->p = getsect(xf, ndp->addr);
316 if(ndp->p == nil
317 || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
318 errno = Eio;
319 return -1;
320 }
321
322 ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
323 nd = ndp->d;
324 memset(nd, 0, DOSDIRSIZE);
325
326 if(longtype!=Short)
327 name = sname;
328 putname(name, nd);
329
330 nd->attr = nattr;
331 puttime(nd, 0);
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;
337
338 ndp->p->flags |= BMOD;
339
340 return 0;
341 }
342
343 void
rcreate(void)344 rcreate(void)
345 {
346 Dosbpb *bp;
347 Xfile *f;
348 Dosptr *pdp, *ndp;
349 Iosect *xp;
350 Dosdir *pd, *xd;
351 char sname[13];
352 long start;
353 int longtype, attr, omode, nattr;
354
355 f = xfile(req->fid, Asis);
356 if(!f || (f->flags&Omodes) || getfile(f)<0){
357 errno = Eio;
358 return;
359 }
360 pdp = f->ptr;
361 pd = pdp->d;
362 /*
363 * perm check
364 */
365 if(isroot(pdp->addr) && pd != nil)
366 panic("root pd != nil");
367 attr = pd ? pd->attr : DDIR;
368 if(!(attr & DDIR) || (attr & DRONLY)){
369 badperm:
370 putfile(f);
371 errno = Eperm;
372 return;
373 }
374 omode = 0;
375 if(req->mode & ORCLOSE)
376 omode |= Orclose;
377 switch(req->mode & 7){
378 case OREAD:
379 case OEXEC:
380 omode |= Oread;
381 break;
382 case ORDWR:
383 omode |= Oread;
384 /* fall through */
385 case OWRITE:
386 omode |= Owrite;
387 if(req->perm & DMDIR)
388 goto badperm;
389 break;
390 default:
391 goto badperm;
392 }
393
394 /*
395 * check the name, find the slot for the dentry,
396 * and find a good alias for a long name
397 */
398 ndp = malloc(sizeof(Dosptr));
399 if(ndp == nil){
400 putfile(f);
401 errno = Enomem;
402 return;
403 }
404 longtype = mk8dot3name(f, ndp, req->name, sname);
405 chat("rcreate %s longtype %d...\n", req->name, longtype);
406 if(longtype == Invalid){
407 free(ndp);
408 goto badperm;
409 }
410
411 /*
412 * allocate first cluster, if making directory
413 */
414 start = 0;
415 bp = nil;
416 if(req->perm & DMDIR){
417 bp = f->xf->ptr;
418 mlock(bp);
419 start = falloc(f->xf);
420 unmlock(bp);
421 if(start <= 0){
422 free(ndp);
423 putfile(f);
424 errno = Eio;
425 return;
426 }
427 }
428
429 /*
430 * make the entry
431 */
432 nattr = 0;
433 if((req->perm & 0222) == 0)
434 nattr |= DRONLY;
435 if(req->perm & DMDIR)
436 nattr |= DDIR;
437
438 if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
439 if(ndp->p != nil)
440 putsect(ndp->p);
441 free(ndp);
442 if(start > 0)
443 ffree(f->xf, start);
444 putfile(f);
445 return;
446 }
447
448 if(pd != nil){
449 puttime(pd, 0);
450 pdp->p->flags |= BMOD;
451 }
452
453 /*
454 * fix up the fid
455 */
456 f->ptr = ndp;
457 f->qid.type = QTFILE;
458 f->qid.path = QIDPATH(ndp);
459
460 //ZZZ set type for excl, append?
461 if(req->perm & DMDIR){
462 f->qid.type = QTDIR;
463 xp = getsect(f->xf, clust2sect(bp, start));
464 if(xp == nil){
465 errno = Eio;
466 goto badio;
467 }
468 xd = (Dosdir *)&xp->iobuf[0];
469 memmove(xd, ndp->d, DOSDIRSIZE);
470 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
471 xd->name[0] = '.';
472 xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
473 if(pd)
474 memmove(xd, pd, DOSDIRSIZE);
475 else{
476 memset(xd, 0, DOSDIRSIZE);
477 puttime(xd, 0);
478 xd->attr = DDIR;
479 }
480 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
481 xd->name[0] = '.';
482 xd->name[1] = '.';
483 xp->flags |= BMOD;
484 putsect(xp);
485 }
486
487 f->flags |= omode;
488 rep->qid = f->qid;
489 rep->iounit = 0;
490
491 badio:
492 putfile(f);
493 putsect(pdp->p);
494 free(pdp);
495 }
496
497 void
rread(void)498 rread(void)
499 {
500 Xfile *f;
501 int r;
502
503 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
504 goto error;
505 if(req->count > sizeof repdata)
506 req->count = sizeof repdata;
507 if(f->qid.type & QTDIR){
508 if(getfile(f) < 0)
509 goto error;
510 r = readdir(f, repdata, req->offset, req->count);
511 }else{
512 if(getfile(f) < 0)
513 goto error;
514 r = readfile(f, repdata, req->offset, req->count);
515 }
516 putfile(f);
517 if(r < 0){
518 error:
519 errno = Eio;
520 }else{
521 rep->count = r;
522 rep->data = (char*)repdata;
523 }
524 }
525
526 void
rwrite(void)527 rwrite(void)
528 {
529 Xfile *f;
530 int r;
531
532 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
533 goto error;
534 if(getfile(f) < 0)
535 goto error;
536 r = writefile(f, req->data, req->offset, req->count);
537 putfile(f);
538 if(r < 0){
539 error:
540 errno = Eio;
541 }else{
542 rep->count = r;
543 }
544 }
545
546 void
rclunk(void)547 rclunk(void)
548 {
549 xfile(req->fid, Clunk);
550 sync();
551 }
552
553 /*
554 * wipe out a dos directory entry
555 */
556 static void
doremove(Xfs * xf,Dosptr * dp)557 doremove(Xfs *xf, Dosptr *dp)
558 {
559 Iosect *p;
560 int prevdo;
561
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)
566 break;
567 dp->p->iobuf[prevdo] = DOSEMPTY;
568 }
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)
573 break;
574 p->iobuf[prevdo] = DOSEMPTY;
575 p->flags |= BMOD;
576 }
577 putsect(p);
578 }
579 }
580
581 void
rremove(void)582 rremove(void)
583 {
584 Xfile *f;
585 Dosptr *dp;
586 Iosect *parp;
587 Dosdir *pard;
588
589 f = xfile(req->fid, Asis);
590 parp = nil;
591 if(f == nil){
592 errno = Eio;
593 goto out;
594 }
595 dp = f->ptr;
596 if(isroot(dp->addr)){
597 errno = Eperm;
598 goto out;
599 }
600
601 /*
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
605 */
606 parp = getsect(f->xf, dp->paddr);
607 if(parp == nil
608 || getfile(f) < 0){
609 errno = Eio;
610 goto out;
611 }
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)){
616 errno = Eperm;
617 goto out;
618 }
619 if(truncfile(f, 0) < 0){
620 errno = Eio;
621 goto out;
622 }
623 doremove(f->xf, f->ptr);
624 if(!isroot(dp->paddr)){
625 puttime(pard, 0);
626 parp->flags |= BMOD;
627 }
628 out:
629 if(parp != nil)
630 putsect(parp);
631 if(f != nil)
632 putfile(f);
633 xfile(req->fid, Clunk);
634 sync();
635 }
636
637 static void
dostat(Xfile * f,Dir * d)638 dostat(Xfile *f, Dir *d)
639 {
640 Dosptr *dp;
641 Iosect *p;
642 char *name, namebuf[DOSNAMELEN];
643 int islong, sum, prevdo;
644
645 dp = f->ptr;
646 if(isroot(dp->addr)){
647 memset(d, 0, sizeof(Dir));
648 d->name = "/";
649 d->qid.type = QTDIR;
650 d->qid.path = f->xf->rootqid.path;
651 d->mode = DMDIR|0777;
652 d->uid = "bill";
653 d->muid = "bill";
654 d->gid = "trog";
655 }else{
656 /*
657 * assemble any long file name
658 */
659 sum = aliassum(dp->d);
660 islong = 0;
661 name = namebuf;
662 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
663 if(dp->p->iobuf[prevdo+11] != 0xf)
664 break;
665 name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
666 }
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)
671 break;
672 name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
673 }
674 putsect(p);
675 }
676 getdir(f->xf, d, dp->d, dp->addr, dp->offset);
677 if(islong && sum == -1 && nameok(namebuf))
678 strcpy(d->name, namebuf);
679 }
680 }
681
682 void
rstat(void)683 rstat(void)
684 {
685 Dir dir;
686 Xfile *f;
687
688 f = xfile(req->fid, Asis);
689 if(!f || getfile(f) < 0){
690 errno = Eio;
691 return;
692 }
693
694 dir.name = repdata;
695 dostat(f, &dir);
696
697 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
698 rep->stat = statbuf;
699 putfile(f);
700 }
701
702 void
rwstat(void)703 rwstat(void)
704 {
705 Dir dir, wdir;
706 Xfile *f, pf;
707 Dosptr *dp, ndp, pdp;
708 Iosect *parp;
709 Dosdir *pard, *d, od;
710 char sname[13];
711 ulong oaddr, ooffset;
712 long start, length;
713 int i, longtype, changes, attr;
714
715 f = xfile(req->fid, Asis);
716 if(!f || getfile(f) < 0){
717 errno = Eio;
718 return;
719 }
720 dp = f->ptr;
721
722 if(isroot(dp->addr)){
723 errno = Eperm;
724 goto out;
725 }
726
727 changes = 0;
728 dir.name = repdata;
729 dostat(f, &dir);
730 if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
731 errno = Ebadstat;
732 goto out;
733 }
734
735 /*
736 * To change length, must have write permission on file.
737 * we only allow truncates for now.
738 */
739 if(wdir.length!=~0 && wdir.length!=dir.length){
740 if(wdir.length > dir.length || !dir.mode & 0222){
741 errno = Eperm;
742 goto out;
743 }
744 }
745
746 /*
747 * no chown or chgrp
748 */
749 if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
750 || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
751 errno = Eperm;
752 goto out;
753 }
754
755 /*
756 * mode/mtime allowed
757 */
758 if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
759 changes = 1;
760
761 /*
762 * Setting DMAPPEND (make system file contiguous)
763 * requires setting DMEXCL (system file).
764 */
765 if(wdir.mode != ~0){
766 if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
767 || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
768 errno = Eperm;
769 goto out;
770 }
771 if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
772 changes = 1;
773 if((dir.mode^wdir.mode) & DMAPPEND) {
774 if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
775 errno = Eperm;
776 goto out;
777 }
778 if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
779 errno = Econtig;
780 goto out;
781 }
782 }
783 }
784
785
786 /*
787 * to rename:
788 * 1) make up a fake clone
789 * 2) walk to parent
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.
795 */
796 if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
797 if(utflen(wdir.name) >= DOSNAMELEN){
798 errno = Etoolong;
799 goto out;
800 }
801
802 /*
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
805 */
806 parp = getsect(f->xf, dp->paddr);
807 if(parp == nil){
808 errno = Eio;
809 goto out;
810 }
811 pard = (Dosdir *)&parp->iobuf[dp->poffset];
812 if(!isroot(dp->paddr) && (pard->attr & DRONLY)
813 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
814 putsect(parp);
815 errno = Eperm;
816 goto out;
817 }
818
819 /*
820 * retrieve info from old entry
821 */
822 oaddr = dp->addr;
823 ooffset = dp->offset;
824 d = dp->d;
825 od = *d;
826 start = getstart(f->xf, d);
827 length = GLONG(d->length);
828 attr = d->attr;
829
830 /*
831 * temporarily release file to allow other directory ops:
832 * walk to parent, validate new name
833 * then remove old entry
834 */
835 putfile(f);
836 pf = *f;
837 memset(&pdp, 0, sizeof(Dosptr));
838 pdp.prevaddr = -1;
839 pdp.naddr = -1;
840 pdp.addr = dp->paddr;
841 pdp.offset = dp->poffset;
842 pdp.p = parp;
843 if(!isroot(pdp.addr))
844 pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
845 pf.ptr = &pdp;
846 longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
847 if(longtype==Invalid){
848 putsect(parp);
849 errno = Eperm;
850 return;
851 }
852 if(getfile(f) < 0){
853 putsect(parp);
854 errno = Eio;
855 return;
856 }
857 doremove(f->xf, dp);
858 putfile(f);
859
860 /*
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.
863 * create new entry.
864 */
865 if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
866 || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
867 putsect(parp);
868 errno = Eio;
869 goto out;
870 }
871
872 /*
873 * copy invisible fields
874 */
875 d = dp->d;
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];
882
883 putsect(parp);
884
885 /*
886 * relocate up other fids to the same file, if it moved
887 */
888 f->qid.path = QIDPATH(dp);
889 if(oaddr != dp->addr || ooffset != dp->offset)
890 dosptrreloc(f, dp, oaddr, ooffset);
891
892 /*
893 * copy fields that are not supposed to change
894 */
895 if(wdir.mtime == ~0)
896 wdir.mtime = dir.mtime;
897 if(wdir.mode == ~0)
898 wdir.mode = dir.mode;
899 changes = 1;
900 }
901
902 /*
903 * do the actual truncate
904 */
905 if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
906 errno = Eio;
907
908 if(changes){
909 putdir(dp->d, &wdir);
910 dp->p->flags |= BMOD;
911 }
912
913 out:
914 putfile(f);
915 sync();
916 }
917