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 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 21 rauth(void) 22 { 23 errno = Enoauth; 24 } 25 26 void 27 rflush(void) 28 { 29 } 30 31 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* 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 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 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 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 abort(); 303 return -1; 304 } 305 306 /* 307 * fill in a directory entry for a new file 308 */ 309 static int 310 mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length) 311 { 312 Dosdir *nd; 313 314 /* 315 * fill in the entry 316 */ 317 ndp->p = getsect(xf, ndp->addr); 318 if(ndp->p == nil 319 || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){ 320 errno = Eio; 321 return -1; 322 } 323 324 ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset]; 325 nd = ndp->d; 326 memset(nd, 0, DOSDIRSIZE); 327 328 if(longtype!=Short) 329 name = sname; 330 putname(name, nd); 331 332 nd->attr = nattr; 333 puttime(nd, 0); 334 putstart(xf, nd, start); 335 nd->length[0] = length; 336 nd->length[1] = length>>8; 337 nd->length[2] = length>>16; 338 nd->length[3] = length>>24; 339 340 ndp->p->flags |= BMOD; 341 342 return 0; 343 } 344 345 void 346 rcreate(void) 347 { 348 Dosbpb *bp; 349 Xfile *f; 350 Dosptr *pdp, *ndp; 351 Iosect *xp; 352 Dosdir *pd, *xd; 353 char sname[13]; 354 long start; 355 int longtype, attr, omode, nattr; 356 357 f = xfile(req->fid, Asis); 358 if(!f || (f->flags&Omodes) || getfile(f)<0){ 359 errno = Eio; 360 return; 361 } 362 pdp = f->ptr; 363 pd = pdp->d; 364 /* 365 * perm check 366 */ 367 if(isroot(pdp->addr) && pd != nil) 368 panic("root pd != nil"); 369 attr = pd ? pd->attr : DDIR; 370 if(!(attr & DDIR) || (attr & DRONLY)){ 371 badperm: 372 putfile(f); 373 errno = Eperm; 374 return; 375 } 376 omode = 0; 377 if(req->mode & ORCLOSE) 378 omode |= Orclose; 379 switch(req->mode & 7){ 380 case OREAD: 381 case OEXEC: 382 omode |= Oread; 383 break; 384 case ORDWR: 385 omode |= Oread; 386 /* fall through */ 387 case OWRITE: 388 omode |= Owrite; 389 if(req->perm & DMDIR) 390 goto badperm; 391 break; 392 default: 393 goto badperm; 394 } 395 396 /* 397 * check the name, find the slot for the dentry, 398 * and find a good alias for a long name 399 */ 400 ndp = malloc(sizeof(Dosptr)); 401 if(ndp == nil){ 402 putfile(f); 403 errno = Enomem; 404 return; 405 } 406 longtype = mk8dot3name(f, ndp, req->name, sname); 407 chat("rcreate %s longtype %d...\n", req->name, longtype); 408 if(longtype == Invalid){ 409 free(ndp); 410 goto badperm; 411 } 412 413 /* 414 * allocate first cluster, if making directory 415 */ 416 start = 0; 417 bp = nil; 418 if(req->perm & DMDIR){ 419 bp = f->xf->ptr; 420 mlock(bp); 421 start = falloc(f->xf); 422 unmlock(bp); 423 if(start <= 0){ 424 free(ndp); 425 putfile(f); 426 errno = Eio; 427 return; 428 } 429 } 430 431 /* 432 * make the entry 433 */ 434 nattr = 0; 435 if((req->perm & 0222) == 0) 436 nattr |= DRONLY; 437 if(req->perm & DMDIR) 438 nattr |= DDIR; 439 440 if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){ 441 if(ndp->p != nil) 442 putsect(ndp->p); 443 free(ndp); 444 if(start > 0) 445 ffree(f->xf, start); 446 putfile(f); 447 return; 448 } 449 450 if(pd != nil){ 451 puttime(pd, 0); 452 pdp->p->flags |= BMOD; 453 } 454 455 /* 456 * fix up the fid 457 */ 458 f->ptr = ndp; 459 f->qid.type = QTFILE; 460 f->qid.path = QIDPATH(ndp); 461 462 //ZZZ set type for excl, append? 463 if(req->perm & DMDIR){ 464 f->qid.type = QTDIR; 465 xp = getsect(f->xf, clust2sect(bp, start)); 466 if(xp == nil){ 467 errno = Eio; 468 goto badio; 469 } 470 xd = (Dosdir *)&xp->iobuf[0]; 471 memmove(xd, ndp->d, DOSDIRSIZE); 472 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext); 473 xd->name[0] = '.'; 474 xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE]; 475 if(pd) 476 memmove(xd, pd, DOSDIRSIZE); 477 else{ 478 memset(xd, 0, DOSDIRSIZE); 479 puttime(xd, 0); 480 xd->attr = DDIR; 481 } 482 memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext); 483 xd->name[0] = '.'; 484 xd->name[1] = '.'; 485 xp->flags |= BMOD; 486 putsect(xp); 487 } 488 489 f->flags |= omode; 490 rep->qid = f->qid; 491 rep->iounit = 0; 492 493 badio: 494 putfile(f); 495 putsect(pdp->p); 496 free(pdp); 497 } 498 499 void 500 rread(void) 501 { 502 Xfile *f; 503 int r; 504 505 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread)) 506 goto error; 507 if(req->count > sizeof repdata) 508 req->count = sizeof repdata; 509 if(f->qid.type & QTDIR){ 510 if(getfile(f) < 0) 511 goto error; 512 r = readdir(f, repdata, req->offset, req->count); 513 }else{ 514 if(getfile(f) < 0) 515 goto error; 516 r = readfile(f, repdata, req->offset, req->count); 517 } 518 putfile(f); 519 if(r < 0){ 520 error: 521 errno = Eio; 522 }else{ 523 rep->count = r; 524 rep->data = (char*)repdata; 525 } 526 } 527 528 void 529 rwrite(void) 530 { 531 Xfile *f; 532 int r; 533 534 if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite)) 535 goto error; 536 if(getfile(f) < 0) 537 goto error; 538 r = writefile(f, req->data, req->offset, req->count); 539 putfile(f); 540 if(r < 0){ 541 error: 542 errno = Eio; 543 }else{ 544 rep->count = r; 545 } 546 } 547 548 void 549 rclunk(void) 550 { 551 xfile(req->fid, Clunk); 552 sync(); 553 } 554 555 /* 556 * wipe out a dos directory entry 557 */ 558 static void 559 doremove(Xfs *xf, Dosptr *dp) 560 { 561 Iosect *p; 562 int prevdo; 563 564 dp->p->iobuf[dp->offset] = DOSEMPTY; 565 dp->p->flags |= BMOD; 566 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){ 567 if(dp->p->iobuf[prevdo+11] != 0xf) 568 break; 569 dp->p->iobuf[prevdo] = DOSEMPTY; 570 } 571 if(prevdo < 0 && dp->prevaddr != -1){ 572 p = getsect(xf, dp->prevaddr); 573 for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){ 574 if(p->iobuf[prevdo+11] != 0xf) 575 break; 576 p->iobuf[prevdo] = DOSEMPTY; 577 p->flags |= BMOD; 578 } 579 putsect(p); 580 } 581 } 582 583 void 584 rremove(void) 585 { 586 Xfile *f; 587 Dosptr *dp; 588 Iosect *parp; 589 Dosdir *pard; 590 591 f = xfile(req->fid, Asis); 592 parp = nil; 593 if(f == nil){ 594 errno = Eio; 595 goto out; 596 } 597 dp = f->ptr; 598 if(isroot(dp->addr)){ 599 errno = Eperm; 600 goto out; 601 } 602 603 /* 604 * can't remove if parent is read only, 605 * it's a non-empty directory, 606 * or it's a read only file in the root directory 607 */ 608 parp = getsect(f->xf, dp->paddr); 609 if(parp == nil 610 || getfile(f) < 0){ 611 errno = Eio; 612 goto out; 613 } 614 pard = (Dosdir *)&parp->iobuf[dp->poffset]; 615 if(!isroot(dp->paddr) && (pard->attr & DRONLY) 616 || (dp->d->attr & DDIR) && emptydir(f) < 0 617 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){ 618 errno = Eperm; 619 goto out; 620 } 621 if(truncfile(f, 0) < 0){ 622 errno = Eio; 623 goto out; 624 } 625 doremove(f->xf, f->ptr); 626 if(!isroot(dp->paddr)){ 627 puttime(pard, 0); 628 parp->flags |= BMOD; 629 } 630 out: 631 if(parp != nil) 632 putsect(parp); 633 if(f != nil) 634 putfile(f); 635 xfile(req->fid, Clunk); 636 sync(); 637 } 638 639 static void 640 dostat(Xfile *f, Dir *d) 641 { 642 Dosptr *dp; 643 Iosect *p; 644 char *name, namebuf[DOSNAMELEN]; 645 int islong, sum, prevdo; 646 647 dp = f->ptr; 648 if(isroot(dp->addr)){ 649 memset(d, 0, sizeof(Dir)); 650 d->name = "/"; 651 d->qid.type = QTDIR; 652 d->qid.path = f->xf->rootqid.path; 653 d->mode = DMDIR|0777; 654 d->uid = "bill"; 655 d->muid = "bill"; 656 d->gid = "trog"; 657 }else{ 658 /* 659 * assemble any long file name 660 */ 661 sum = aliassum(dp->d); 662 islong = 0; 663 name = namebuf; 664 for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){ 665 if(dp->p->iobuf[prevdo+11] != 0xf) 666 break; 667 name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1); 668 } 669 if(prevdo < 0 && dp->prevaddr != -1){ 670 p = getsect(f->xf, dp->prevaddr); 671 for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){ 672 if(p->iobuf[prevdo+11] != 0xf) 673 break; 674 name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1); 675 } 676 putsect(p); 677 } 678 getdir(f->xf, d, dp->d, dp->addr, dp->offset); 679 if(islong && sum == -1 && nameok(namebuf)) 680 strcpy(d->name, namebuf); 681 } 682 } 683 684 void 685 rstat(void) 686 { 687 Dir dir; 688 Xfile *f; 689 690 f = xfile(req->fid, Asis); 691 if(!f || getfile(f) < 0){ 692 errno = Eio; 693 return; 694 } 695 696 dir.name = repdata; 697 dostat(f, &dir); 698 699 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf); 700 rep->stat = statbuf; 701 putfile(f); 702 } 703 704 void 705 rwstat(void) 706 { 707 Dir dir, wdir; 708 Xfile *f, pf; 709 Dosptr *dp, ndp, pdp; 710 Iosect *parp; 711 Dosdir *pard, *d, od; 712 char sname[13]; 713 ulong oaddr, ooffset; 714 long start, length; 715 int i, longtype, changes, attr; 716 717 f = xfile(req->fid, Asis); 718 if(!f || getfile(f) < 0){ 719 errno = Eio; 720 return; 721 } 722 dp = f->ptr; 723 724 if(isroot(dp->addr)){ 725 errno = Eperm; 726 goto out; 727 } 728 729 changes = 0; 730 dir.name = repdata; 731 dostat(f, &dir); 732 if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){ 733 errno = Ebadstat; 734 goto out; 735 } 736 737 /* 738 * To change length, must have write permission on file. 739 * we only allow truncates for now. 740 */ 741 if(wdir.length!=~0 && wdir.length!=dir.length){ 742 if(wdir.length > dir.length || !dir.mode & 0222){ 743 errno = Eperm; 744 goto out; 745 } 746 } 747 748 /* 749 * no chown or chgrp 750 */ 751 if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0 752 || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){ 753 errno = Eperm; 754 goto out; 755 } 756 757 /* 758 * mode/mtime allowed 759 */ 760 if(wdir.mtime != ~0 && dir.mtime != wdir.mtime) 761 changes = 1; 762 763 /* 764 * Setting DMAPPEND (make system file contiguous) 765 * requires setting DMEXCL (system file). 766 */ 767 if(wdir.mode != ~0){ 768 if((wdir.mode & 7) != ((wdir.mode >> 3) & 7) 769 || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){ 770 errno = Eperm; 771 goto out; 772 } 773 if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777)) 774 changes = 1; 775 if((dir.mode^wdir.mode) & DMAPPEND) { 776 if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) { 777 errno = Eperm; 778 goto out; 779 } 780 if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) { 781 errno = Econtig; 782 goto out; 783 } 784 } 785 } 786 787 788 /* 789 * to rename: 790 * 1) make up a fake clone 791 * 2) walk to parent 792 * 3) remove the old entry 793 * 4) create entry with new name 794 * 5) write correct mode/mtime info 795 * we need to remove the old entry before creating the new one 796 * to avoid a lock loop. 797 */ 798 if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){ 799 if(utflen(wdir.name) >= DOSNAMELEN){ 800 errno = Etoolong; 801 goto out; 802 } 803 804 /* 805 * grab parent directory of file to be changed and check for write perm 806 * rename also disallowed for read-only files in root directory 807 */ 808 parp = getsect(f->xf, dp->paddr); 809 if(parp == nil){ 810 errno = Eio; 811 goto out; 812 } 813 pard = (Dosdir *)&parp->iobuf[dp->poffset]; 814 if(!isroot(dp->paddr) && (pard->attr & DRONLY) 815 || isroot(dp->paddr) && (dp->d->attr&DRONLY)){ 816 putsect(parp); 817 errno = Eperm; 818 goto out; 819 } 820 821 /* 822 * retrieve info from old entry 823 */ 824 oaddr = dp->addr; 825 ooffset = dp->offset; 826 d = dp->d; 827 od = *d; 828 start = getstart(f->xf, d); 829 length = GLONG(d->length); 830 attr = d->attr; 831 832 /* 833 * temporarily release file to allow other directory ops: 834 * walk to parent, validate new name 835 * then remove old entry 836 */ 837 putfile(f); 838 pf = *f; 839 memset(&pdp, 0, sizeof(Dosptr)); 840 pdp.prevaddr = -1; 841 pdp.naddr = -1; 842 pdp.addr = dp->paddr; 843 pdp.offset = dp->poffset; 844 pdp.p = parp; 845 if(!isroot(pdp.addr)) 846 pdp.d = (Dosdir *)&parp->iobuf[pdp.offset]; 847 pf.ptr = &pdp; 848 longtype = mk8dot3name(&pf, &ndp, wdir.name, sname); 849 if(longtype==Invalid){ 850 putsect(parp); 851 errno = Eperm; 852 return; 853 } 854 if(getfile(f) < 0){ 855 putsect(parp); 856 errno = Eio; 857 return; 858 } 859 doremove(f->xf, dp); 860 putfile(f); 861 862 /* 863 * search for dir entry again, since we may be able to use the old slot, 864 * and we need to set up the naddr field if a long name spans the block. 865 * create new entry. 866 */ 867 if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0 868 || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){ 869 putsect(parp); 870 errno = Eio; 871 goto out; 872 } 873 874 /* 875 * copy invisible fields 876 */ 877 d = dp->d; 878 for(i = 0; i < 2; i++) 879 d->ctime[i] = od.ctime[i]; 880 for(i = 0; i < nelem(od.cdate); i++) 881 d->cdate[i] = od.cdate[i]; 882 for(i = 0; i < nelem(od.adate); i++) 883 d->adate[i] = od.adate[i]; 884 885 putsect(parp); 886 887 /* 888 * relocate up other fids to the same file, if it moved 889 */ 890 f->qid.path = QIDPATH(dp); 891 if(oaddr != dp->addr || ooffset != dp->offset) 892 dosptrreloc(f, dp, oaddr, ooffset); 893 894 /* 895 * copy fields that are not supposed to change 896 */ 897 if(wdir.mtime == ~0) 898 wdir.mtime = dir.mtime; 899 if(wdir.mode == ~0) 900 wdir.mode = dir.mode; 901 changes = 1; 902 } 903 904 /* 905 * do the actual truncate 906 */ 907 if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0) 908 errno = Eio; 909 910 if(changes){ 911 putdir(dp->d, &wdir); 912 dp->p->flags |= BMOD; 913 } 914 915 out: 916 putfile(f); 917 sync(); 918 } 919