Blob


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"
9 static void parsedirent(Dirent*, uchar*);
10 static void parseinode(Inode*, uchar*);
11 static void parsegroup(Group*, uchar*);
12 static void parsesuper(Super*, uchar*);
14 #define debug 0
16 static int ext2sync(Fsys*);
17 static void ext2close(Fsys*);
18 static Block* ext2blockread(Fsys*, u64int);
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);
28 Fsys*
29 fsysopenext2(Disk *disk)
30 {
31 Ext2 *fs;
32 Fsys *fsys;
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;
51 if(ext2sync(fsys) < 0)
52 goto error;
54 return fsys;
56 error:
57 ext2close(fsys);
58 return nil;
59 }
61 static void
62 ext2close(Fsys *fsys)
63 {
64 Ext2 *fs;
66 fs = fsys->priv;
67 free(fs);
68 free(fsys);
69 }
71 static int
72 ext2group(Ext2 *fs, u32int i, Group *g)
73 {
74 Block *b;
75 u64int addr;
77 if(i >= fs->ngroup)
78 return -1;
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 }
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;
99 fs = fsys->priv;
100 if(vbno >= fs->nblock)
101 return nil;
102 bno = vbno;
103 if(bno != vbno)
104 return nil;
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;
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;
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;
135 if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){
136 if(debug)
137 fprint(2, "loading bitblock: %r...");
138 return nil;
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;
153 blockput(bitb);
155 bno += fs->firstblock;
156 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
159 static Block*
160 ext2datablock(Ext2 *fs, u32int bno, int size)
162 USED(size);
163 return ext2blockread(fs->fsys, bno);
166 static Block*
167 ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
169 int ppb;
170 Block *b;
171 u32int *a;
172 u32int obno, pbno;
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);
181 bno -= NDIRBLOCKS;
182 ppb = fs->blocksize/4;
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);
194 bno -= ppb;
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);
213 bno -= ppb*ppb;
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);
240 fprint(2, "ext2fileblock %ud: too big\n", obno);
241 return nil;
244 static int
245 checksuper(Super *super)
247 if(super->magic != SUPERMAGIC){
248 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
249 return -1;
251 return 0;
254 static int
255 ext2sync(Fsys *fsys)
257 int i;
258 Group g;
259 Block *b;
260 Super super;
261 Ext2 *fs;
262 Disk *disk;
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;
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);
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);
300 return 0;
303 static void
304 mkhandle(Nfs3Handle *h, u64int ino)
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;
313 static u32int
314 byte2u32(uchar *p)
316 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
319 static Nfs3Status
320 handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
322 int i;
323 uint ioff;
324 u32int inum;
325 u32int addr;
326 Block *b;
327 Group g;
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;
348 static Nfs3Status
349 ext2root(Fsys *fsys, Nfs3Handle *h)
351 USED(fsys);
352 mkhandle(h, ROOTINODE);
353 return Nfs3Ok;
356 static u64int
357 inosize(Inode* ino)
359 u64int size;
361 size = ino->size;
362 if((ino->mode&IFMT)==IFREG)
363 size |= (u64int)ino->diracl << 32;
364 return size;
367 static Nfs3Status
368 ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
370 u32int rdev;
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;
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;
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;
425 static int
426 ingroup(SunAuthUnix *au, uint gid)
428 int i;
430 for(i=0; i<au->ng; i++)
431 if(au->g[i] == gid)
432 return 1;
433 return 0;
436 static Nfs3Status
437 inoperm(Inode *ino, SunAuthUnix *au, int need)
439 int have;
441 if(allowall)
442 return Nfs3Ok;
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;
450 if((have&need) != need)
451 return Nfs3ErrNotOwner; /* really EPERM */
452 return Nfs3Ok;
455 static Nfs3Status
456 ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
458 Inode ino;
459 u32int inum;
460 Ext2 *fs;
461 Nfs3Status ok;
463 fs = fsys->priv;
464 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
465 return ok;
467 USED(au); /* anyone can getattr */
468 return ino2attr(fs, &ino, inum, attr);
471 static Nfs3Status
472 ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
474 int have;
475 Inode ino;
476 u32int inum;
477 Ext2 *fs;
478 Nfs3Status ok;
480 fs = fsys->priv;
481 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
482 return ok;
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;
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;
498 return ino2attr(fs, &ino, inum, attr);
501 static Nfs3Status
502 ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
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;
514 fs = fsys->priv;
515 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
516 return ok;
518 if((ino.mode&IFMT) != IFDIR)
519 return Nfs3ErrNotDir;
521 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
522 return ok;
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;
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;
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;
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;
559 if(de.namlen == len && memcmp(de.name, name, len) == 0){
560 mkhandle(nh, de.ino);
561 blockput(b);
562 return Nfs3Ok;
565 blockput(b);
567 return Nfs3ErrNoEnt;
570 static Nfs3Status
571 ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
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;
585 fs = fsys->priv;
586 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
587 return ok;
589 if((ino.mode&IFMT) != IFDIR)
590 return Nfs3ErrNotDir;
592 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
593 return ok;
595 if(debug) print("readdir cookie %#llux ino.size %#llux\n",
596 (u64int)cookie, (u64int)ino.size);
598 if(cookie >= ino.size){
599 *peof = 1;
600 *pcount = 0;
601 *pdata = 0;
602 return Nfs3Ok;
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;
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;
637 if(de.ino == 0){
638 if(debug) fprint(2, "zero inode\n");
639 continue;
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;
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;
657 dp = ndp;
659 blockput(b);
661 if(i==nblock && !outofspace)
662 *peof = 1;
664 *pcount = dp - data;
665 *pdata = data;
666 return Nfs3Ok;
669 static Nfs3Status
670 ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
671 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
673 uchar *data;
674 Block *b;
675 Ext2 *fs;
676 int skip1, tot, want, fragcount;
677 Inode ino;
678 Nfs3Status ok;
679 u64int size;
681 fs = fsys->priv;
682 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
683 return ok;
685 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
686 return ok;
688 size = inosize(&ino);
689 if(offset >= size){
690 *pdata = 0;
691 *pcount = 0;
692 *peof = 1;
693 return Nfs3Ok;
695 if(offset+count > size)
696 count = size-offset;
698 data = malloc(count);
699 if(data == nil)
700 return Nfs3ErrNoMem;
701 memset(data, 0, count);
703 skip1 = offset%fs->blocksize;
704 offset -= skip1;
705 want = skip1+count;
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);
725 count = tot - skip1;
727 *peof = (offset+count == size);
728 *pcount = count;
729 *pdata = data;
730 return Nfs3Ok;
733 static Nfs3Status
734 ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
736 Ext2 *fs;
737 Nfs3Status ok;
738 int len;
739 Inode ino;
740 Block *b;
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;
748 if(ino.size > 1024)
749 return Nfs3ErrIo;
750 len = ino.size;
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;
761 *link = malloc(len+1);
762 if(*link == 0){
763 blockput(b);
764 return Nfs3ErrNoMem;
766 memmove(*link, b->data, len);
767 (*link)[len] = 0;
768 blockput(b);
769 return Nfs3Ok;
772 if(len > sizeof ino.block)
773 return Nfs3ErrIo;
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;
783 /*
784 * Ext2 is always little-endian, even on big-endian machines.
785 */
787 static u32int
788 l32(uchar *p)
790 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
793 static u16int
794 l16(uchar *p)
796 return p[0] | (p[1]<<8);
799 static u8int
800 l8(uchar *p)
802 return p[0];
805 static void
806 parsedirent(Dirent *de, uchar *p)
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;
815 static void
816 parseinode(Inode *ino, uchar *p)
818 int i;
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 */
841 static void
842 parsegroup(Group *g, uchar *p)
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 */
854 static void
855 parsesuper(Super *s, uchar *p)
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 */