| text2.c - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| text2.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*, Nfs3A… | |
| 22 static Nfs3Status ext2lookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*,… | |
| 23 static Nfs3Status ext2readfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32i… | |
| 24 static Nfs3Status ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *… | |
| 25 static Nfs3Status ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h… | |
| 26 static Nfs3Status ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h,… | |
| 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-… | |
| 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… | |
| 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->blockspergr… | |
| 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: b… | |
| 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->blocksi… | |
| 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->blocksiz… | |
| 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->blocksi… | |
| 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->blocksi… | |
| 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, SU… | |
| 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… | |
| 293 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, f… | |
| 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.… | |
| 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->block… | |
| 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, u32i… | |
| 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&AE… | |
| 494 *got |= Nfs3AccessLookup; | |
| 495 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&A… | |
| 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, Nfs3H… | |
| 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… | |
| 544 break; | |
| 545 } | |
| 546 p += de.reclen; | |
| 547 if(p > ep){ | |
| 548 if(debug) | |
| 549 fprint(2, "bad len %d at offset … | |
| 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 off… | |
| 557 break; | |
| 558 } | |
| 559 if(de.namlen == len && memcmp(de.name, name, len… | |
| 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, u6… | |
| 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 … | |
| 630 break; | |
| 631 } | |
| 632 p += de.reclen; | |
| 633 if(p > ep){ | |
| 634 if(debug) fprint(2, "reclen %d at offset… | |
| 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 recle… | |
| 643 break; | |
| 644 } | |
| 645 if(debug) print("%.*s/%d ", de.namlen, de.name, … | |
| 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->dat… | |
| 652 if(debug) print("%.*s %#llux\n", utfnlen(e.name,… | |
| 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 … | |
| 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, … | |
| 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 } |