ext2.c (18673B)
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 "ext2.h" 8 9 static void parsedirent(Dirent*, uchar*); 10 static void parseinode(Inode*, uchar*); 11 static void parsegroup(Group*, uchar*); 12 static void parsesuper(Super*, uchar*); 13 14 #define debug 0 15 16 static int ext2sync(Fsys*); 17 static void ext2close(Fsys*); 18 static Block* ext2blockread(Fsys*, u64int); 19 20 static Nfs3Status ext2root(Fsys*, Nfs3Handle*); 21 static Nfs3Status ext2getattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*); 22 static Nfs3Status ext2lookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*); 23 static Nfs3Status ext2readfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*); 24 static Nfs3Status ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link); 25 static Nfs3Status ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*); 26 static Nfs3Status ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr); 27 28 Fsys* 29 fsysopenext2(Disk *disk) 30 { 31 Ext2 *fs; 32 Fsys *fsys; 33 34 fsys = emalloc(sizeof(Fsys)); 35 fs = emalloc(sizeof(Ext2)); 36 fs->disk = disk; 37 fsys->priv = fs; 38 fs->fsys = fsys; 39 fsys->type = "ext2"; 40 fsys->_readblock = ext2blockread; 41 fsys->_sync = ext2sync; 42 fsys->_root = ext2root; 43 fsys->_getattr = ext2getattr; 44 fsys->_access = ext2access; 45 fsys->_lookup = ext2lookup; 46 fsys->_readfile = ext2readfile; 47 fsys->_readlink = ext2readlink; 48 fsys->_readdir = ext2readdir; 49 fsys->_close = ext2close; 50 51 if(ext2sync(fsys) < 0) 52 goto error; 53 54 return fsys; 55 56 error: 57 ext2close(fsys); 58 return nil; 59 } 60 61 static void 62 ext2close(Fsys *fsys) 63 { 64 Ext2 *fs; 65 66 fs = fsys->priv; 67 free(fs); 68 free(fsys); 69 } 70 71 static int 72 ext2group(Ext2 *fs, u32int i, Group *g) 73 { 74 Block *b; 75 u64int addr; 76 77 if(i >= fs->ngroup) 78 return -1; 79 80 addr = fs->groupaddr + i/fs->descperblock; 81 b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize); 82 if(b == nil) 83 return -1; 84 parsegroup(g, b->data+i%fs->descperblock*GroupSize); 85 blockput(b); 86 return 0; 87 } 88 89 static Block* 90 ext2blockread(Fsys *fsys, u64int vbno) 91 { 92 Block *bitb; 93 Group g; 94 uchar *bits; 95 u32int bno, boff, bitblock; 96 u64int bitpos; 97 Ext2 *fs; 98 99 fs = fsys->priv; 100 if(vbno >= fs->nblock) 101 return nil; 102 bno = vbno; 103 if(bno != vbno) 104 return nil; 105 106 /* 107 if(bno < fs->firstblock) 108 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize); 109 */ 110 if(bno < fs->firstblock) 111 return nil; 112 113 bno -= fs->firstblock; 114 if(ext2group(fs, bno/fs->blockspergroup, &g) < 0){ 115 if(debug) 116 fprint(2, "loading group: %r..."); 117 return nil; 118 } 119 /* 120 if(debug) 121 fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n", 122 (int)(bno/fs->blockspergroup), 123 g.bitblock, 124 g.inodebitblock, 125 g.inodeaddr, 126 g.freeblockscount, 127 g.freeinodescount, 128 g.useddirscount); 129 if(debug) 130 fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g.bitblock); 131 */ 132 bitblock = g.bitblock; 133 bitpos = (u64int)bitblock*fs->blocksize; 134 135 if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){ 136 if(debug) 137 fprint(2, "loading bitblock: %r..."); 138 return nil; 139 } 140 bits = bitb->data; 141 boff = bno%fs->blockspergroup; 142 if((bits[boff>>3] & (1<<(boff&7))) == 0){ 143 if(debug) 144 fprint(2, "block %d not allocated in group %d: bitblock %d/%lld bits[%d] = %#x\n", 145 boff, bno/fs->blockspergroup, 146 (int)bitblock, 147 bitpos, 148 boff>>3, 149 bits[boff>>3]); 150 blockput(bitb); 151 return nil; 152 } 153 blockput(bitb); 154 155 bno += fs->firstblock; 156 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize); 157 } 158 159 static Block* 160 ext2datablock(Ext2 *fs, u32int bno, int size) 161 { 162 USED(size); 163 return ext2blockread(fs->fsys, bno); 164 } 165 166 static Block* 167 ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size) 168 { 169 int ppb; 170 Block *b; 171 u32int *a; 172 u32int obno, pbno; 173 174 obno = bno; 175 if(bno < NDIRBLOCKS){ 176 if(debug) 177 fprint(2, "fileblock %d -> %d...", 178 bno, ino->block[bno]); 179 return ext2datablock(fs, ino->block[bno], size); 180 } 181 bno -= NDIRBLOCKS; 182 ppb = fs->blocksize/4; 183 184 /* one indirect */ 185 if(bno < ppb){ 186 b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize); 187 if(b == nil) 188 return nil; 189 a = (u32int*)b->data; 190 bno = a[bno]; 191 blockput(b); 192 return ext2datablock(fs, bno, size); 193 } 194 bno -= ppb; 195 196 /* one double indirect */ 197 if(bno < ppb*ppb){ 198 b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize); 199 if(b == nil) 200 return nil; 201 a = (u32int*)b->data; 202 pbno = a[bno/ppb]; 203 bno = bno%ppb; 204 blockput(b); 205 b = ext2datablock(fs, pbno, fs->blocksize); 206 if(b == nil) 207 return nil; 208 a = (u32int*)b->data; 209 bno = a[bno]; 210 blockput(b); 211 return ext2datablock(fs, bno, size); 212 } 213 bno -= ppb*ppb; 214 215 /* one triple indirect */ 216 if(bno < ppb*ppb*ppb){ 217 b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize); 218 if(b == nil) 219 return nil; 220 a = (u32int*)b->data; 221 pbno = a[bno/(ppb*ppb)]; 222 bno = bno%(ppb*ppb); 223 blockput(b); 224 b = ext2datablock(fs, pbno, fs->blocksize); 225 if(b == nil) 226 return nil; 227 a = (u32int*)b->data; 228 pbno = a[bno/ppb]; 229 bno = bno%ppb; 230 blockput(b); 231 b = ext2datablock(fs, pbno, fs->blocksize); 232 if(b == nil) 233 return nil; 234 a = (u32int*)b->data; 235 bno = a[bno]; 236 blockput(b); 237 return ext2datablock(fs, bno, size); 238 } 239 240 fprint(2, "ext2fileblock %ud: too big\n", obno); 241 return nil; 242 } 243 244 static int 245 checksuper(Super *super) 246 { 247 if(super->magic != SUPERMAGIC){ 248 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC); 249 return -1; 250 } 251 return 0; 252 } 253 254 static int 255 ext2sync(Fsys *fsys) 256 { 257 int i; 258 Group g; 259 Block *b; 260 Super super; 261 Ext2 *fs; 262 Disk *disk; 263 264 fs = fsys->priv; 265 disk = fs->disk; 266 if((b = diskread(disk, SBSIZE, SBOFF)) == nil) 267 return -1; 268 parsesuper(&super, b->data); 269 blockput(b); 270 if(checksuper(&super) < 0) 271 return -1; 272 fs->blocksize = MINBLOCKSIZE<<super.logblocksize; 273 fs->nblock = super.nblock; 274 fs->ngroup = (super.nblock+super.blockspergroup-1) 275 / super.blockspergroup; 276 fs->inospergroup = super.inospergroup; 277 fs->blockspergroup = super.blockspergroup; 278 if(super.revlevel >= 1) 279 fs->inosize = super.inosize; 280 else 281 fs->inosize = 128; 282 fs->inosperblock = fs->blocksize / fs->inosize; 283 if(fs->blocksize == SBOFF) 284 fs->groupaddr = 2; 285 else 286 fs->groupaddr = 1; 287 fs->descperblock = fs->blocksize / GroupSize; 288 fs->firstblock = super.firstdatablock; 289 290 fsys->blocksize = fs->blocksize; 291 fsys->nblock = fs->nblock; 292 if(debug) fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n", 293 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup); 294 295 if(0){ 296 for(i=0; i<fs->ngroup; i++) 297 if(ext2group(fs, i, &g) >= 0) 298 fprint(2, "grp %d: bitblock=%d\n", i, g.bitblock); 299 } 300 return 0; 301 } 302 303 static void 304 mkhandle(Nfs3Handle *h, u64int ino) 305 { 306 h->h[0] = ino>>24; 307 h->h[1] = ino>>16; 308 h->h[2] = ino>>8; 309 h->h[3] = ino; 310 h->len = 4; 311 } 312 313 static u32int 314 byte2u32(uchar *p) 315 { 316 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; 317 } 318 319 static Nfs3Status 320 handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino) 321 { 322 int i; 323 uint ioff; 324 u32int inum; 325 u32int addr; 326 Block *b; 327 Group g; 328 329 if(h->len != 4) 330 return Nfs3ErrBadHandle; 331 inum = byte2u32(h->h); 332 if(pinum) 333 *pinum = inum; 334 i = (inum-1) / fs->inospergroup; 335 if(i >= fs->ngroup) 336 return Nfs3ErrBadHandle; 337 ioff = (inum-1) % fs->inospergroup; 338 if(ext2group(fs, i, &g) < 0) 339 return Nfs3ErrIo; 340 addr = g.inodeaddr + ioff/fs->inosperblock; 341 if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil) 342 return Nfs3ErrIo; 343 parseinode(ino, b->data+fs->inosize*(ioff%fs->inosperblock)); 344 blockput(b); 345 return Nfs3Ok; 346 } 347 348 static Nfs3Status 349 ext2root(Fsys *fsys, Nfs3Handle *h) 350 { 351 USED(fsys); 352 mkhandle(h, ROOTINODE); 353 return Nfs3Ok; 354 } 355 356 static u64int 357 inosize(Inode* ino) 358 { 359 u64int size; 360 361 size = ino->size; 362 if((ino->mode&IFMT)==IFREG) 363 size |= (u64int)ino->diracl << 32; 364 return size; 365 } 366 367 static Nfs3Status 368 ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr) 369 { 370 u32int rdev; 371 372 attr->type = -1; 373 switch(ino->mode&IFMT){ 374 case IFIFO: 375 attr->type = Nfs3FileFifo; 376 break; 377 case IFCHR: 378 attr->type = Nfs3FileChar; 379 break; 380 case IFDIR: 381 attr->type = Nfs3FileDir; 382 break; 383 case IFBLK: 384 attr->type = Nfs3FileBlock; 385 break; 386 case IFREG: 387 attr->type = Nfs3FileReg; 388 break; 389 case IFLNK: 390 attr->type = Nfs3FileSymlink; 391 break; 392 case IFSOCK: 393 attr->type = Nfs3FileSocket; 394 break; 395 case IFWHT: 396 default: 397 return Nfs3ErrBadHandle; 398 } 399 400 attr->mode = ino->mode&07777; 401 attr->nlink = ino->nlink; 402 attr->uid = ino->uid; 403 attr->gid = ino->gid; 404 attr->size = inosize(ino); 405 attr->used = (u64int)ino->nblock*fs->blocksize; 406 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){ 407 rdev = ino->block[0]; 408 attr->major = (rdev>>8)&0xFF; 409 attr->minor = rdev & 0xFFFF00FF; 410 }else{ 411 attr->major = 0; 412 attr->minor = 0; 413 } 414 attr->fsid = 0; 415 attr->fileid = inum; 416 attr->atime.sec = ino->atime; 417 attr->atime.nsec = 0; 418 attr->mtime.sec = ino->mtime; 419 attr->mtime.nsec = 0; 420 attr->ctime.sec = ino->ctime; 421 attr->ctime.nsec = 0; 422 return Nfs3Ok; 423 } 424 425 static int 426 ingroup(SunAuthUnix *au, uint gid) 427 { 428 int i; 429 430 for(i=0; i<au->ng; i++) 431 if(au->g[i] == gid) 432 return 1; 433 return 0; 434 } 435 436 static Nfs3Status 437 inoperm(Inode *ino, SunAuthUnix *au, int need) 438 { 439 int have; 440 441 if(allowall) 442 return Nfs3Ok; 443 444 have = ino->mode&0777; 445 if(ino->uid == au->uid) 446 have >>= 6; 447 else if(ino->gid == au->gid || ingroup(au, ino->gid)) 448 have >>= 3; 449 450 if((have&need) != need) 451 return Nfs3ErrNotOwner; /* really EPERM */ 452 return Nfs3Ok; 453 } 454 455 static Nfs3Status 456 ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr) 457 { 458 Inode ino; 459 u32int inum; 460 Ext2 *fs; 461 Nfs3Status ok; 462 463 fs = fsys->priv; 464 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok) 465 return ok; 466 467 USED(au); /* anyone can getattr */ 468 return ino2attr(fs, &ino, inum, attr); 469 } 470 471 static Nfs3Status 472 ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr) 473 { 474 int have; 475 Inode ino; 476 u32int inum; 477 Ext2 *fs; 478 Nfs3Status ok; 479 480 fs = fsys->priv; 481 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok) 482 return ok; 483 484 have = ino.mode&0777; 485 if(ino.uid == au->uid) 486 have >>= 6; 487 else if(ino.gid == au->gid || ingroup(au, ino.gid)) 488 have >>= 3; 489 490 *got = 0; 491 if((want&Nfs3AccessRead) && (have&AREAD)) 492 *got |= Nfs3AccessRead; 493 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC)) 494 *got |= Nfs3AccessLookup; 495 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC)) 496 *got |= Nfs3AccessExecute; 497 498 return ino2attr(fs, &ino, inum, attr); 499 } 500 501 static Nfs3Status 502 ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh) 503 { 504 u32int nblock; 505 u32int i; 506 uchar *p, *ep; 507 Dirent de; 508 Inode ino; 509 Block *b; 510 Ext2 *fs; 511 Nfs3Status ok; 512 int len, want; 513 514 fs = fsys->priv; 515 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 516 return ok; 517 518 if((ino.mode&IFMT) != IFDIR) 519 return Nfs3ErrNotDir; 520 521 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok) 522 return ok; 523 524 len = strlen(name); 525 nblock = (ino.size+fs->blocksize-1) / fs->blocksize; 526 if(debug) fprint(2, "%d blocks in dir...", nblock); 527 for(i=0; i<nblock; i++){ 528 if(i==nblock-1) 529 want = ino.size % fs->blocksize; 530 else 531 want = fs->blocksize; 532 b = ext2fileblock(fs, &ino, i, want); 533 if(b == nil){ 534 if(debug) fprint(2, "empty block..."); 535 continue; 536 } 537 p = b->data; 538 ep = p+b->len; 539 while(p < ep){ 540 parsedirent(&de, p); 541 if(de.reclen == 0){ 542 if(debug) 543 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len); 544 break; 545 } 546 p += de.reclen; 547 if(p > ep){ 548 if(debug) 549 fprint(2, "bad len %d at offset %d of %d\n", de.reclen, (int)(p-b->data), b->len); 550 break; 551 } 552 if(de.ino == 0) 553 continue; 554 if(4+2+2+de.namlen > de.reclen){ 555 if(debug) 556 fprint(2, "bad namelen %d at offset %d of %d\n", de.namlen, (int)(p-b->data), b->len); 557 break; 558 } 559 if(de.namlen == len && memcmp(de.name, name, len) == 0){ 560 mkhandle(nh, de.ino); 561 blockput(b); 562 return Nfs3Ok; 563 } 564 } 565 blockput(b); 566 } 567 return Nfs3ErrNoEnt; 568 } 569 570 static Nfs3Status 571 ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof) 572 { 573 u32int nblock; 574 u32int i; 575 int off, outofspace; 576 uchar *data, *dp, *dep, *p, *ep, *ndp; 577 Dirent de; 578 Inode ino; 579 Block *b; 580 Ext2 *fs; 581 Nfs3Status ok; 582 Nfs3Entry e; 583 int want; 584 585 fs = fsys->priv; 586 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 587 return ok; 588 589 if((ino.mode&IFMT) != IFDIR) 590 return Nfs3ErrNotDir; 591 592 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 593 return ok; 594 595 if(debug) print("readdir cookie %#llux ino.size %#llux\n", 596 (u64int)cookie, (u64int)ino.size); 597 598 if(cookie >= ino.size){ 599 *peof = 1; 600 *pcount = 0; 601 *pdata = 0; 602 return Nfs3Ok; 603 } 604 605 dp = malloc(count); 606 data = dp; 607 if(dp == nil) 608 return Nfs3ErrNoMem; 609 dep = dp+count; 610 *peof = 0; 611 nblock = (ino.size+fs->blocksize-1) / fs->blocksize; 612 i = cookie/fs->blocksize; 613 off = cookie%fs->blocksize; 614 outofspace = 0; 615 for(; i<nblock && !outofspace; i++, off=0){ 616 if(i==nblock-1) 617 want = ino.size % fs->blocksize; 618 else 619 want = fs->blocksize; 620 b = ext2fileblock(fs, &ino, i, want); 621 if(b == nil) 622 continue; 623 p = b->data; 624 ep = p+b->len; 625 memset(&e, 0, sizeof e); 626 while(p < ep){ 627 parsedirent(&de, p); 628 if(de.reclen == 0){ 629 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len); 630 break; 631 } 632 p += de.reclen; 633 if(p > ep){ 634 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de.reclen, (int)(p-b->data), b->len); 635 break; 636 } 637 if(de.ino == 0){ 638 if(debug) fprint(2, "zero inode\n"); 639 continue; 640 } 641 if(4+2+2+de.namlen > de.reclen){ 642 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); 643 break; 644 } 645 if(debug) print("%.*s/%d ", de.namlen, de.name, (int)de.ino); 646 if(p-de.reclen - b->data < off) 647 continue; 648 e.fileid = de.ino; 649 e.name = de.name; 650 e.namelen = de.namlen; 651 e.cookie = (u64int)i*fs->blocksize + (p - b->data); 652 if(debug) print("%.*s %#llux\n", utfnlen(e.name, e.namelen), e.name, (u64int)e.cookie); 653 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){ 654 outofspace = 1; 655 break; 656 } 657 dp = ndp; 658 } 659 blockput(b); 660 } 661 if(i==nblock && !outofspace) 662 *peof = 1; 663 664 *pcount = dp - data; 665 *pdata = data; 666 return Nfs3Ok; 667 } 668 669 static Nfs3Status 670 ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, 671 u64int offset, uchar **pdata, u32int *pcount, u1int *peof) 672 { 673 uchar *data; 674 Block *b; 675 Ext2 *fs; 676 int skip1, tot, want, fragcount; 677 Inode ino; 678 Nfs3Status ok; 679 u64int size; 680 681 fs = fsys->priv; 682 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 683 return ok; 684 685 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 686 return ok; 687 688 size = inosize(&ino); 689 if(offset >= size){ 690 *pdata = 0; 691 *pcount = 0; 692 *peof = 1; 693 return Nfs3Ok; 694 } 695 if(offset+count > size) 696 count = size-offset; 697 698 data = malloc(count); 699 if(data == nil) 700 return Nfs3ErrNoMem; 701 memset(data, 0, count); 702 703 skip1 = offset%fs->blocksize; 704 offset -= skip1; 705 want = skip1+count; 706 707 /* 708 * have to read multiple blocks if we get asked for a big read. 709 * Linux NFS client assumes that if you ask for 8k and only get 4k 710 * back, the remaining 4k is zeros. 711 */ 712 for(tot=0; tot<want; tot+=fragcount){ 713 b = ext2fileblock(fs, &ino, (offset+tot)/fs->blocksize, fs->blocksize); 714 fragcount = fs->blocksize; 715 if(b == nil) 716 continue; 717 if(tot+fragcount > want) 718 fragcount = want - tot; 719 if(tot == 0) 720 memmove(data, b->data+skip1, fragcount-skip1); 721 else 722 memmove(data+tot-skip1, b->data, fragcount); 723 blockput(b); 724 } 725 count = tot - skip1; 726 727 *peof = (offset+count == size); 728 *pcount = count; 729 *pdata = data; 730 return Nfs3Ok; 731 } 732 733 static Nfs3Status 734 ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link) 735 { 736 Ext2 *fs; 737 Nfs3Status ok; 738 int len; 739 Inode ino; 740 Block *b; 741 742 fs = fsys->priv; 743 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok) 744 return ok; 745 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok) 746 return ok; 747 748 if(ino.size > 1024) 749 return Nfs3ErrIo; 750 len = ino.size; 751 752 if(ino.nblock != 0){ 753 /* BUG: assumes symlink fits in one block */ 754 b = ext2fileblock(fs, &ino, 0, len); 755 if(b == nil) 756 return Nfs3ErrIo; 757 if(memchr(b->data, 0, len) != nil){ 758 blockput(b); 759 return Nfs3ErrIo; 760 } 761 *link = malloc(len+1); 762 if(*link == 0){ 763 blockput(b); 764 return Nfs3ErrNoMem; 765 } 766 memmove(*link, b->data, len); 767 (*link)[len] = 0; 768 blockput(b); 769 return Nfs3Ok; 770 } 771 772 if(len > sizeof ino.block) 773 return Nfs3ErrIo; 774 775 *link = malloc(len+1); 776 if(*link == 0) 777 return Nfs3ErrNoMem; 778 memmove(*link, ino.block, ino.size); 779 (*link)[len] = 0; 780 return Nfs3Ok; 781 } 782 783 /* 784 * Ext2 is always little-endian, even on big-endian machines. 785 */ 786 787 static u32int 788 l32(uchar *p) 789 { 790 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); 791 } 792 793 static u16int 794 l16(uchar *p) 795 { 796 return p[0] | (p[1]<<8); 797 } 798 799 static u8int 800 l8(uchar *p) 801 { 802 return p[0]; 803 } 804 805 static void 806 parsedirent(Dirent *de, uchar *p) 807 { 808 de->ino = l32(p); 809 de->reclen = l16(p+4); 810 de->namlen = l8(p+6); 811 /* 1 byte pad */ 812 de->name = (char*)p+8; 813 } 814 815 static void 816 parseinode(Inode *ino, uchar *p) 817 { 818 int i; 819 820 ino->mode = l16(p); 821 ino->uid = l16(p+2); 822 ino->size = l32(p+4); 823 ino->atime = l32(p+8); 824 ino->ctime = l32(p+12); 825 ino->mtime = l32(p+16); 826 ino->dtime = l32(p+20); 827 ino->gid = l16(p+24); 828 ino->nlink = l16(p+26); 829 ino->nblock = l32(p+28); 830 ino->flags = l32(p+32); 831 /* 4 byte osd1 */ 832 for(i=0; i<NBLOCKS; i++) 833 ino->block[i] = l32(p+40+i*4); 834 ino->version = l32(p+100); 835 ino->fileacl = l32(p+104); 836 ino->diracl = l32(p+108); 837 ino->faddr = l32(p+112); 838 /* 12 byte osd2 */ 839 } 840 841 static void 842 parsegroup(Group *g, uchar *p) 843 { 844 g->bitblock = l32(p); 845 g->inodebitblock = l32(p+4); 846 g->inodeaddr = l32(p+8); 847 g->freeblockscount = l16(p+12); 848 g->freeinodescount = l16(p+14); 849 g->useddirscount = l16(p+16); 850 /* 2 byte pad */ 851 /* 12 byte reserved */ 852 } 853 854 static void 855 parsesuper(Super *s, uchar *p) 856 { 857 s->ninode = l32(p); 858 s->nblock = l32(p+4); 859 s->rblockcount = l32(p+8); 860 s->freeblockcount = l32(p+12); 861 s->freeinodecount = l32(p+16); 862 s->firstdatablock = l32(p+20); 863 s->logblocksize = l32(p+24); 864 s->logfragsize = l32(p+28); 865 s->blockspergroup = l32(p+32); 866 s->fragpergroup = l32(p+36); 867 s->inospergroup = l32(p+40); 868 s->mtime = l32(p+44); 869 s->wtime = l32(p+48); 870 s->mntcount = l16(p+52); 871 s->maxmntcount = l16(p+54); 872 s->magic = l16(p+56); 873 s->state = l16(p+58); 874 s->errors = l16(p+60); 875 /* 2 byte pad */ 876 s->lastcheck = l32(p+64); 877 s->checkinterval = l32(p+68); 878 s->creatoros = l32(p+72); 879 s->revlevel = l32(p+76); 880 s->defresuid = l16(p+80); 881 s->defresgid = l16(p+82); 882 s->firstino = l32(p+84); 883 s->inosize = l32(p+88); 884 s->blockgroupnr = l16(p+60); 885 /* 932 byte reserved */ 886 }