ffs.c (19246B)
1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <sunrpc.h> 5 #include <nfs3.h> 6 #include <diskfs.h> 7 #include "ffs.h" 8 9 #define BADBNO ((u64int)~0ULL) 10 11 #define checkcg 0 12 #define debug 0 13 14 static int checkfsblk(Fsblk*); 15 static int checkcgblk(Cgblk*); 16 static Block *ffsblockread(Fsys*, u64int); 17 static int ffssync(Fsys*); 18 static void ffsclose(Fsys*); 19 20 static u64int ffsxfileblock(Fsys *fs, Nfs3Handle *h, u64int offset); 21 static Nfs3Status ffsroot(Fsys*, Nfs3Handle*); 22 static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*); 23 static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*); 24 static Nfs3Status ffsreadfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*); 25 static Nfs3Status ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link); 26 static Nfs3Status ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*); 27 static Nfs3Status ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr); 28 29 Fsys* 30 fsysopenffs(Disk *disk) 31 { 32 Ffs *fs; 33 Fsys *fsys; 34 35 fsys = emalloc(sizeof(Fsys)); 36 fs = emalloc(sizeof(Ffs)); 37 fs->disk = disk; 38 fsys->priv = fs; 39 fsys->type = "ffs"; 40 fsys->_readblock = ffsblockread; 41 fsys->_sync = ffssync; 42 fsys->_root = ffsroot; 43 fsys->_getattr = ffsgetattr; 44 fsys->_access = ffsaccess; 45 fsys->_lookup = ffslookup; 46 fsys->_readfile = ffsreadfile; 47 fsys->_readlink = ffsreadlink; 48 fsys->_readdir = ffsreaddir; 49 fsys->_close = ffsclose; 50 fsys->fileblock = ffsxfileblock; 51 52 if(ffssync(fsys) < 0) 53 goto error; 54 55 return fsys; 56 57 error: 58 ffsclose(fsys); 59 return nil; 60 } 61 62 static Cgblk* 63 ffscylgrp(Ffs *fs, u32int i, Block **pb) 64 { 65 Block *b; 66 Cgblk *cg; 67 68 if(i >= fs->ncg) 69 return nil; 70 71 b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize); 72 if(b == nil) 73 return nil; 74 cg = (Cgblk*)b->data; 75 if(checkcgblk(cg) < 0){ 76 fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno); 77 blockput(b); 78 return nil; 79 } 80 *pb = b; 81 return cg; 82 } 83 84 static int 85 ffssync(Fsys *fsys) 86 { 87 int i; 88 int off[] = { SBOFF, SBOFF2, SBOFFPIGGY }; 89 Block *b, *cgb; 90 Cgblk *cgblk; 91 Cylgrp *cg; 92 Disk *disk; 93 Ffs *fs; 94 Fsblk *fsblk; 95 96 fs = fsys->priv; 97 disk = fs->disk; 98 99 /* 100 * Read super block. 101 */ 102 b = nil; 103 for(i=0; i<nelem(off); i++){ 104 if((b = diskread(disk, SBSIZE, off[i])) == nil) 105 goto error; 106 fsblk = (Fsblk*)b->data; 107 // fprint(2, "offset of magic: %ld\n", offsetof(Fsblk, magic)); 108 if((fs->ufs = checkfsblk(fsblk)) > 0) 109 goto okay; 110 blockput(b); 111 b = nil; 112 } 113 goto error; 114 115 okay: 116 fs->blocksize = fsblk->blocksize; 117 fs->nblock = (fsblk->nfrag+fsblk->fragsperblock-1) / fsblk->fragsperblock; 118 fs->fragsize = fsblk->fragsize; 119 fs->fragspergroup = fsblk->fragspergroup; 120 fs->fragsperblock = fsblk->fragsperblock; 121 fs->inosperblock = fsblk->inosperblock; 122 fs->inospergroup = fsblk->inospergroup; 123 124 fs->nfrag = fsblk->nfrag; 125 fs->ndfrag = fsblk->ndfrag; 126 /* 127 * used to use 128 * fs->blockspergroup = (u64int)fsblk->_cylspergroup * 129 * fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize; 130 * for UFS1, but this should work for both UFS1 and UFS2 131 */ 132 fs->blockspergroup = (u64int)fsblk->fragspergroup / fsblk->fragsperblock; 133 fs->ncg = fsblk->ncg; 134 135 fsys->blocksize = fs->blocksize; 136 fsys->nblock = fs->nblock; 137 138 if(debug) fprint(2, "ffs %lld %d-byte blocks, %d cylinder groups\n", 139 fs->nblock, fs->blocksize, fs->ncg); 140 if(debug) fprint(2, "\tinospergroup %d perblock %d blockspergroup %lld\n", 141 fs->inospergroup, fs->inosperblock, fs->blockspergroup); 142 143 if(fs->cg == nil) 144 fs->cg = emalloc(fs->ncg*sizeof(Cylgrp)); 145 for(i=0; i<fs->ncg; i++){ 146 cg = &fs->cg[i]; 147 if(fs->ufs == 2) 148 cg->bno = (u64int)fs->blockspergroup*i; 149 else 150 cg->bno = fs->blockspergroup*i + fsblk->_cgoffset * (i & ~fsblk->_cgmask); 151 cg->cgblkno = cg->bno + fsblk->cfragno/fs->fragsperblock; 152 cg->ibno = cg->bno + fsblk->ifragno/fs->fragsperblock; 153 cg->dbno = cg->bno + fsblk->dfragno/fs->fragsperblock; 154 155 if(checkcg){ 156 if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil) 157 goto error; 158 159 cgblk = (Cgblk*)cgb->data; 160 if(checkcgblk(cgblk) < 0){ 161 blockput(cgb); 162 goto error; 163 } 164 if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){ 165 werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag); 166 blockput(cgb); 167 goto error; 168 } 169 /* cg->nfrag = cgblk->nfrag; */ 170 /* cg->nblock = (cgblk->nfrag+fs->fragsperblock-1) / fs->fragsperblock; */ 171 /* fprint(2, "cg #%d: cgblk %lud, %d blocks, %d inodes\n", cgblk->num, (ulong)cg->cgblkno, cg->nblock, cg->nino); */ 172 } 173 } 174 blockput(b); 175 return 0; 176 177 error: 178 blockput(b); 179 return -1; 180 } 181 182 static void 183 ffsclose(Fsys *fsys) 184 { 185 Ffs *fs; 186 187 fs = fsys->priv; 188 if(fs->cg) 189 free(fs->cg); 190 free(fs); 191 free(fsys); 192 } 193 194 static int 195 checkfsblk(Fsblk *super) 196 { 197 // fprint(2, "ffs magic 0x%ux\n", super->magic); 198 if(super->magic == FSMAGIC){ 199 super->time = super->_time; 200 super->nfrag = super->_nfrag; 201 super->ndfrag = super->_ndfrag; 202 super->flags = super->_flags; 203 return 1; 204 } 205 if(super->magic == FSMAGIC2){ 206 return 2; 207 } 208 209 werrstr("bad super block"); 210 return -1; 211 } 212 213 static int 214 checkcgblk(Cgblk *cg) 215 { 216 if(cg->magic != CGMAGIC){ 217 werrstr("bad cylinder group block"); 218 return -1; 219 } 220 return 0; 221 } 222 223 /* 224 * Read block #bno from the disk, zeroing unused data. 225 * If there is no data whatsoever, it's okay to return nil. 226 */ 227 int nskipx; 228 static Block* 229 ffsblockread(Fsys *fsys, u64int bno) 230 { 231 int i, o; 232 u8int *fmap; 233 int frag, fsize, avail; 234 Block *b; 235 Cgblk *cgblk; 236 Ffs *fs; 237 238 fs = fsys->priv; 239 i = bno / fs->blockspergroup; 240 o = bno % fs->blockspergroup; 241 if(i >= fs->ncg) 242 return nil; 243 244 if((cgblk = ffscylgrp(fs, i, &b)) == nil) 245 return nil; 246 247 fmap = (u8int*)cgblk+cgblk->fmapoff; 248 frag = fs->fragsperblock; 249 switch(frag){ 250 default: 251 sysfatal("bad frag"); 252 case 8: 253 avail = fmap[o]; 254 break; 255 case 4: 256 avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF; 257 break; 258 case 2: 259 avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3; 260 break; 261 case 1: 262 avail = (fmap[o>>3] >> (o&7)) & 0x1; 263 break; 264 } 265 blockput(b); 266 267 if(avail == ((1<<frag)-1)) 268 { 269 nskipx++; 270 return nil; 271 } 272 if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){ 273 fprint(2, "diskread failed!!!\n"); 274 return nil; 275 } 276 277 fsize = fs->fragsize; 278 for(i=0; i<frag; i++) 279 if(avail & (1<<i)) 280 memset(b->data + fsize*i, 0, fsize); 281 return b; 282 } 283 284 static Block* 285 ffsdatablock(Ffs *fs, u64int bno, int size) 286 { 287 int fsize; 288 u64int diskaddr; 289 Block *b; 290 291 if(bno == 0) 292 return nil; 293 294 fsize = size; 295 if(fsize < fs->fragsize) 296 fsize = fs->fragsize; 297 298 if(bno >= fs->nfrag){ 299 fprint(2, "ffs: request for block %#lux; nfrag %#llux\n", (ulong)bno, fs->nfrag); 300 return nil; 301 } 302 diskaddr = (u64int)bno*fs->fragsize; 303 b = diskread(fs->disk, fsize, diskaddr); 304 if(b == nil){ 305 fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize); 306 return nil; 307 } 308 if(b->len < fsize){ 309 fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize, 310 b->len); 311 blockput(b); 312 return nil; 313 } 314 315 return b; 316 } 317 318 static u64int 319 ifetch(Ffs *fs, u64int bno, u32int off) 320 { 321 Block *b; 322 323 if(bno == BADBNO) 324 return BADBNO; 325 b = ffsdatablock(fs, bno, fs->blocksize); 326 if(b == nil) 327 return BADBNO; 328 if(fs->ufs == 2) 329 bno = ((u64int*)b->data)[off]; 330 else 331 bno = ((u32int*)b->data)[off]; 332 blockput(b); 333 return bno; 334 } 335 336 static u64int 337 ffsfileblockno(Ffs *fs, Inode *ino, u64int bno) 338 { 339 int ppb; 340 341 if(bno < NDADDR){ 342 if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]); 343 return ino->db[bno]; 344 } 345 bno -= NDADDR; 346 ppb = fs->blocksize/4; 347 348 if(bno < ppb) /* single indirect */ 349 return ifetch(fs, ino->ib[0], bno); 350 bno -= ppb; 351 352 if(bno < ppb*ppb) 353 return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb); 354 bno -= ppb*ppb; 355 356 if(bno/ppb/ppb/ppb == 0) /* bno < ppb*ppb*ppb w/o overflow */ 357 return ifetch(fs, ifetch(fs, ifetch(fs, ino->ib[2], bno/ppb/ppb), (bno/ppb)%ppb), bno%ppb); 358 359 fprint(2, "ffsfileblock %llud: way too big\n", bno+NDADDR+ppb+ppb*ppb); 360 return BADBNO; 361 } 362 363 static Block* 364 ffsfileblock(Ffs *fs, Inode *ino, u64int bno, int size) 365 { 366 u64int b; 367 368 b = ffsfileblockno(fs, ino, bno); 369 if(b == ~0) 370 return nil; 371 return ffsdatablock(fs, b, size); 372 } 373 374 /* 375 * NFS handles are 4-byte inode number. 376 */ 377 static void 378 mkhandle(Nfs3Handle *h, u64int ino) 379 { 380 h->h[0] = ino >> 24; 381 h->h[1] = ino >> 16; 382 h->h[2] = ino >> 8; 383 h->h[3] = ino; 384 h->len = 4; 385 } 386 387 static u32int 388 byte2u32(uchar *p) 389 { 390 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; 391 } 392 393 static u64int lastiaddr; /* debugging */ 394 395 static void 396 inode1to2(Inode1 *i1, Inode *i2) 397 { 398 int i; 399 400 memset(i2, 0, sizeof *i2); 401 i2->mode = i1->mode; 402 i2->nlink = i1->nlink; 403 i2->size = i1->size; 404 i2->atime = i1->atime; 405 i2->atimensec = i1->atimensec; 406 i2->mtime = i1->mtime; 407 i2->mtimensec = i1->mtimensec; 408 i2->ctime = i1->ctime; 409 i2->ctimensec = i1->ctimensec; 410 for(i=0; i<NDADDR; i++) 411 i2->db[i] = i1->db[i]; 412 for(i=0; i<NIADDR; i++) 413 i2->ib[i] = i1->ib[i]; 414 i2->flags = i1->flags; 415 i2->nblock = i1->nblock; 416 i2->gen = i1->gen; 417 i2->uid = i1->uid; 418 i2->gid = i1->gid; 419 } 420 421 static Nfs3Status 422 handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino) 423 { 424 int i; 425 u32int ioff; 426 u32int inum; 427 u64int iaddr; 428 Block *b; 429 Cylgrp *cg; 430 Inode1 ino1; 431 432 if(h->len != 4) 433 return Nfs3ErrBadHandle; 434 inum = byte2u32(h->h); 435 if(pinum) 436 *pinum = inum; 437 if(debug) print("inum %d...", (int)inum); 438 439 /* fetch inode from disk */ 440 i = inum / fs->inospergroup; 441 ioff = inum % fs->inospergroup; 442 if(debug)print("cg %d off %d...", i, (int)ioff); 443 if(i >= fs->ncg) 444 return Nfs3ErrBadHandle; 445 cg = &fs->cg[i]; 446 447 if(debug) print("cg->ibno %lld ufs %d...", cg->ibno, fs->ufs); 448 iaddr = (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize; 449 ioff = ioff%fs->inosperblock; 450 if((b = diskread(fs->disk, fs->blocksize, iaddr)) == nil) 451 return Nfs3ErrIo; 452 if(fs->ufs == 2){ 453 *ino = ((Inode*)b->data)[ioff]; 454 lastiaddr = iaddr+ioff*sizeof(Inode); 455 }else{ 456 ino1 = ((Inode1*)b->data)[ioff]; 457 inode1to2(&ino1, ino); 458 lastiaddr = iaddr+ioff*sizeof(Inode1); 459 } 460 blockput(b); 461 return Nfs3Ok; 462 } 463 464 static Nfs3Status 465 ffsroot(Fsys *fsys, Nfs3Handle *h) 466 { 467 USED(fsys); 468 mkhandle(h, 2); 469 return Nfs3Ok; 470 } 471 472 static Nfs3Status 473 ino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr) 474 { 475 u32int rdev; 476 477 attr->type = -1; 478 switch(ino->mode&IFMT){ 479 case IFIFO: 480 attr->type = Nfs3FileFifo; 481 break; 482 case IFCHR: 483 attr->type = Nfs3FileChar; 484 break; 485 case IFDIR: 486 attr->type = Nfs3FileDir; 487 break; 488 case IFBLK: 489 attr->type = Nfs3FileBlock; 490 break; 491 case IFREG: 492 attr->type = Nfs3FileReg; 493 break; 494 case IFLNK: 495 attr->type = Nfs3FileSymlink; 496 break; 497 case IFSOCK: 498 attr->type = Nfs3FileSocket; 499 break; 500 case IFWHT: 501 default: 502 return Nfs3ErrBadHandle; 503 } 504 505 attr->mode = ino->mode&07777; 506 attr->nlink = ino->nlink; 507 attr->uid = ino->uid; 508 attr->gid = ino->gid; 509 attr->size = ino->size; 510 attr->used = ino->nblock*fs->blocksize; 511 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){ 512 rdev = ino->db[0]; 513 attr->major = (rdev>>8)&0xFF; 514 attr->minor = rdev & 0xFFFF00FF; 515 }else{ 516 attr->major = 0; 517 attr->minor = 0; 518 } 519 attr->fsid = 0; 520 attr->fileid = inum; 521 attr->atime.sec = ino->atime; 522 attr->atime.nsec = ino->atimensec; 523 attr->mtime.sec = ino->mtime; 524 attr->mtime.nsec = ino->mtimensec; 525 attr->ctime.sec = ino->ctime; 526 attr->ctime.nsec = ino->ctimensec; 527 return Nfs3Ok; 528 } 529 530 static int 531 ingroup(SunAuthUnix *au, uint gid) 532 { 533 int i; 534 535 for(i=0; i<au->ng; i++) 536 if(au->g[i] == gid) 537 return 1; 538 return 0; 539 } 540 541 static Nfs3Status 542 inoperm(Inode *ino, SunAuthUnix *au, int need) 543 { 544 int have; 545 546 if(au == nil) 547 return Nfs3Ok; 548 549 have = ino->mode&0777; 550 if(ino->uid == au->uid) 551 have >>= 6; 552 else if(ino->gid == au->gid || ingroup(au, ino->gid)) 553 have >>= 3; 554 555 if((have&need) != need) 556 return Nfs3ErrNotOwner; /* really EPERM */ 557 return Nfs3Ok; 558 } 559 560 static Nfs3Status 561 ffsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr) 562 { 563 Inode ino; 564 u32int inum; 565 Ffs *fs; 566 Nfs3Status ok; 567 568 fs = fsys->priv; 569 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok) 570 return ok; 571 572 USED(au); /* anyone can getattr */ 573 574 return ino2attr(fs, &ino, inum, attr); 575 } 576 577 static Nfs3Status 578 ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr) 579 { 580 int have; 581 Inode ino; 582 u32int inum; 583 Ffs *fs; 584 Nfs3Status ok; 585 586 fs = fsys->priv; 587 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok) 588 return ok; 589 590 have = ino.mode&0777; 591 if(ino.uid == au->uid) 592 have >>= 6; 593 else if(ino.gid == au->gid || ingroup(au, ino.gid)) 594 have >>= 3; 595 596 *got = 0; 597 if((want&Nfs3AccessRead) && (have&AREAD)) 598 *got |= Nfs3AccessRead; 599 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC)) 600 *got |= Nfs3AccessLookup; 601 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC)) 602 *got |= Nfs3AccessExecute; 603 604 return ino2attr(fs, &ino, inum, attr); 605 } 606 607 static Nfs3Status 608 ffslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh) 609 { 610 u32int nblock; 611 u32int i; 612 uchar *p, *ep; 613 Dirent *de; 614 Inode ino; 615 Block *b; 616 Ffs *fs; 617 Nfs3Status ok; 618 int len, want; 619 620 fs = fsys->priv; 621 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 622 return ok; 623 624 if((ino.mode&IFMT) != IFDIR) 625 return Nfs3ErrNotDir; 626 627 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok) 628 return ok; 629 630 len = strlen(name); 631 nblock = (ino.size+fs->blocksize-1) / fs->blocksize; 632 for(i=0; i<nblock; i++){ 633 if(i==nblock-1) 634 want = ino.size % fs->blocksize; 635 else 636 want = fs->blocksize; 637 b = ffsfileblock(fs, &ino, i, want); 638 if(b == nil) 639 continue; 640 p = b->data; 641 ep = p+b->len; 642 while(p < ep){ 643 de = (Dirent*)p; 644 if(de->reclen == 0){ 645 if(debug) 646 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len); 647 break; 648 } 649 p += de->reclen; 650 if(p > ep){ 651 if(debug) 652 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len); 653 break; 654 } 655 if(de->ino == 0) 656 continue; 657 if(4+2+2+de->namlen > de->reclen){ 658 if(debug) 659 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len); 660 break; 661 } 662 if(de->namlen == len && memcmp(de->name, name, len) == 0){ 663 mkhandle(nh, de->ino); 664 blockput(b); 665 return Nfs3Ok; 666 } 667 } 668 blockput(b); 669 } 670 return Nfs3ErrNoEnt; 671 } 672 673 static Nfs3Status 674 ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof) 675 { 676 u32int nblock; 677 u32int i; 678 int off, done; 679 uchar *data, *dp, *dep, *p, *ep, *ndp; 680 Dirent *de; 681 Inode ino; 682 Block *b; 683 Ffs *fs; 684 Nfs3Status ok; 685 Nfs3Entry e; 686 int want; 687 688 fs = fsys->priv; 689 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 690 return ok; 691 692 if((ino.mode&IFMT) != IFDIR) 693 return Nfs3ErrNotDir; 694 695 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 696 return ok; 697 698 if(cookie >= ino.size){ 699 *peof = 1; 700 *pcount = 0; 701 *pdata = 0; 702 return Nfs3Ok; 703 } 704 705 dp = malloc(count); 706 data = dp; 707 if(dp == nil) 708 return Nfs3ErrNoMem; 709 dep = dp+count; 710 *peof = 0; 711 nblock = (ino.size+fs->blocksize-1) / fs->blocksize; 712 i = cookie/fs->blocksize; 713 off = cookie%fs->blocksize; 714 done = 0; 715 for(; i<nblock && !done; i++){ 716 if(i==nblock-1) 717 want = ino.size % fs->blocksize; 718 else 719 want = fs->blocksize; 720 b = ffsfileblock(fs, &ino, i, want); 721 if(b == nil) 722 continue; 723 p = b->data; 724 ep = p+b->len; 725 memset(&e, 0, sizeof e); 726 while(p < ep){ 727 de = (Dirent*)p; 728 if(de->reclen == 0){ 729 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len); 730 break; 731 } 732 p += de->reclen; 733 if(p > ep){ 734 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len); 735 break; 736 } 737 if(de->ino == 0){ 738 if(debug) fprint(2, "zero inode\n"); 739 continue; 740 } 741 if(4+2+2+de->namlen > de->reclen){ 742 if(debug) fprint(2, "bad namlen %d reclen %d at offset %d of %d\n", de->namlen, de->reclen, (int)(p-b->data), b->len); 743 break; 744 } 745 if(de->name[de->namlen] != 0){ 746 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name); 747 continue; 748 } 749 if(debug) print("%s/%d ", de->name, (int)de->ino); 750 if((uchar*)de - b->data < off) 751 continue; 752 e.fileid = de->ino; 753 e.name = de->name; 754 e.namelen = de->namlen; 755 e.cookie = (u64int)i*fs->blocksize + (p - b->data); 756 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){ 757 done = 1; 758 break; 759 } 760 dp = ndp; 761 } 762 off = 0; 763 blockput(b); 764 } 765 if(i==nblock) 766 *peof = 1; 767 768 *pcount = dp - data; 769 *pdata = data; 770 return Nfs3Ok; 771 } 772 773 static u64int 774 ffsxfileblock(Fsys *fsys, Nfs3Handle *h, u64int offset) 775 { 776 u64int bno; 777 Inode ino; 778 Nfs3Status ok; 779 Ffs *fs; 780 781 fs = fsys->priv; 782 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok){ 783 nfs3errstr(ok); 784 return 0; 785 } 786 if(offset == 1) /* clumsy hack for debugging */ 787 return lastiaddr; 788 if(offset >= ino.size){ 789 werrstr("beyond end of file"); 790 return 0; 791 } 792 bno = offset/fs->blocksize; 793 bno = ffsfileblockno(fs, &ino, bno); 794 if(bno == ~0) 795 return 0; 796 return bno*(u64int)fs->fragsize; 797 } 798 799 static Nfs3Status 800 ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, 801 u64int offset, uchar **pdata, u32int *pcount, u1int *peof) 802 { 803 uchar *data; 804 Block *b; 805 Ffs *fs; 806 int off, want, fragcount; 807 Inode ino; 808 Nfs3Status ok; 809 810 fs = fsys->priv; 811 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 812 return ok; 813 814 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 815 return ok; 816 817 if(offset >= ino.size){ 818 *pdata = 0; 819 *pcount = 0; 820 *peof = 1; 821 return Nfs3Ok; 822 } 823 if(offset+count > ino.size) 824 count = ino.size-offset; 825 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize) 826 count = fs->blocksize - offset%fs->blocksize; 827 828 data = malloc(count); 829 if(data == nil) 830 return Nfs3ErrNoMem; 831 832 want = offset%fs->blocksize+count; 833 if(want%fs->fragsize) 834 want += fs->fragsize - want%fs->fragsize; 835 836 b = ffsfileblock(fs, &ino, offset/fs->blocksize, want); 837 if(b == nil){ 838 /* BUG: distinguish sparse file from I/O error */ 839 memset(data, 0, count); 840 }else{ 841 off = offset%fs->blocksize; 842 fragcount = count; /* need signed variable */ 843 if(off+fragcount > b->len){ 844 fragcount = b->len - off; 845 if(fragcount < 0) 846 fragcount = 0; 847 } 848 if(fragcount > 0) 849 memmove(data, b->data+off, fragcount); 850 count = fragcount; 851 blockput(b); 852 } 853 *peof = (offset+count == ino.size); 854 *pcount = count; 855 *pdata = data; 856 return Nfs3Ok; 857 } 858 859 static Nfs3Status 860 ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link) 861 { 862 Ffs *fs; 863 Nfs3Status ok; 864 int len; 865 Inode ino; 866 Block *b; 867 868 fs = fsys->priv; 869 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 870 return ok; 871 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 872 return ok; 873 874 if(ino.size > 1024) 875 return Nfs3ErrIo; 876 len = ino.size; 877 878 if(ino.nblock != 0){ 879 /* assumes symlink fits in one block */ 880 b = ffsfileblock(fs, &ino, 0, len); 881 if(b == nil) 882 return Nfs3ErrIo; 883 if(memchr(b->data, 0, len) != nil){ 884 blockput(b); 885 return Nfs3ErrIo; 886 } 887 *link = malloc(len+1); 888 if(*link == 0){ 889 blockput(b); 890 return Nfs3ErrNoMem; 891 } 892 memmove(*link, b->data, len); 893 (*link)[len] = 0; 894 blockput(b); 895 return Nfs3Ok; 896 } 897 898 if(len > sizeof ino.db + sizeof ino.ib) 899 return Nfs3ErrIo; 900 901 *link = malloc(len+1); 902 if(*link == 0) 903 return Nfs3ErrNoMem; 904 memmove(*link, ino.db, ino.size); 905 (*link)[len] = 0; 906 return Nfs3Ok; 907 }