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 } 303 304 /* 305 * fill in a directory entry for a new file 306 */ 307 static int 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 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 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 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 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 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 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 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 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 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