merge
diff --git a/.cvsignore b/.cvsignore
index 3e7aeac..2b794af 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,2 +1,3 @@
+9pm
 config
 install.log
diff --git a/bin/9fs b/bin/9fs
index a89a8f6..fffdc35 100755
--- a/bin/9fs
+++ b/bin/9fs
@@ -6,18 +6,23 @@
 }
 
 fn srv1 {
+	flag=()
+	if(~ $1 -*){
+		flag=$1
+		shift
+	}
 	if(! 9p stat $1 >/dev/null >[2=1]){
 		rm -f $ns/$1
-		srv -a $2 $1
+		srv $flag $2 $1
 	}
 }
 
 ns=`{namespace}
 switch($1){
 case tip
-	srv1 tip utumno.tip9ug.jp
+	srv1 -a tip utumno.tip9ug.jp
 case sources
-	srv1 sources sources.cs.bell-labs.com
+	srv1 -n sources sources.cs.bell-labs.com
 case *
 	srv1 $1 $1
 }
diff --git a/lib/moveplan9.files b/lib/moveplan9.files
index 7b2d285..1b0d8b7 100644
--- a/lib/moveplan9.files
+++ b/lib/moveplan9.files
@@ -24,5 +24,6 @@
 bin/vmount
 bin/yesterday
 man/mkindex
+tmac/tmac.an
 tmac/tmac.anhtml
 tmac/tmac.pm
diff --git a/mail/lib/validateattachment b/mail/lib/validateattachment
index d21044f..74018d0 100755
--- a/mail/lib/validateattachment
+++ b/mail/lib/validateattachment
@@ -54,6 +54,10 @@
 	# but the errors look like
 	# unzip: reading data for philw.doc.scr failed: ...
 	# so we can still catch these.
+	if(! unzip -tsf $file >[2=1] >/dev/null){
+		echo corrupt zip file!
+		exit $discard
+	}
 	if(unzip -tsf $file >[2=1] | grep -si '      |\.(scr|exe|pif|bat|com)$'){
 		echo executables inside zip file!
 		exit $discard
diff --git a/src/cmd/9p.c b/src/cmd/9p.c
index 1befa6b..2e70399 100644
--- a/src/cmd/9p.c
+++ b/src/cmd/9p.c
@@ -538,7 +538,7 @@
 			}
 			if(sort)
 				qsort(d, n, sizeof d[0], dircmp);
-			for(j=0; j<5; j++)
+			for(j=0; j<4; j++)
 				len[j] = 0;
 			for(i=0; i<n; i++){
 				d[i].type = 'M';
diff --git a/src/cmd/9pfuse/fuse.c b/src/cmd/9pfuse/fuse.c
index b1210b7..e78bae8 100644
--- a/src/cmd/9pfuse/fuse.c
+++ b/src/cmd/9pfuse/fuse.c
@@ -804,6 +804,8 @@
 			"/Contents/Resources/load_fusefs", 0) < 0 &&
 		   access(f="/Library/Extensions/fusefs.kext"
 		   	"/Contents/Resources/load_fusefs", 0) < 0 &&
+		   access(f="/Library/Filesystems"
+				  "/fusefs.fs/Support/load_fusefs", 0) < 0 &&
 		   access(f="/System/Library/Filesystems"
 		         "/fusefs.fs/Support/load_fusefs", 0) < 0){
 		   	werrstr("cannot find load_fusefs");
@@ -843,8 +845,15 @@
 		/*
 		 * Different versions of MacFUSE put the
 		 * mount_fusefs binary in different places.
-		 * Try both.
+		 * Try all.
 		 */
+		/* Leopard location */
+		putenv("MOUNT_FUSEFS_DAEMON_PATH",
+			   "/Library/Filesystems/fusefs.fs/Support/mount_fusefs");
+		execl("/Library/Filesystems/fusefs.fs/Support/mount_fusefs",
+			  "mount_fusefs", buf, mtpt, nil);
+
+		/* possible Tiger locations */
 		execl("/System/Library/Filesystems/fusefs.fs/mount_fusefs",
 			"mount_fusefs", buf, mtpt, nil);
 		execl("/System/Library/Filesystems/fusefs.fs/Support/mount_fusefs",
diff --git a/src/cmd/9pfuse/main.c b/src/cmd/9pfuse/main.c
index 82d7b1f..50c835b 100644
--- a/src/cmd/9pfuse/main.c
+++ b/src/cmd/9pfuse/main.c
@@ -22,12 +22,21 @@
 #ifndef O_DIRECTORY
 #define O_DIRECTORY 0
 #endif
+
 #ifndef O_LARGEFILE
-#if defined(__linux__)
-#define O_LARGEFILE 0100000  /* Sigh */
-#else
-#define O_LARGEFILE 0
+#  if defined(__linux__)
+#    define O_LARGEFILE 0100000  /* Sigh */
+#  else
+#    define O_LARGEFILE 0
+#  endif
 #endif
+
+#ifndef O_CLOEXEC
+#  if defined(__linux__)
+#    define O_CLOEXEC 02000000  /* Sigh */
+#  else
+#    define O_CLOEXEC 0
+#  endif
 #endif
 
 
@@ -552,7 +561,7 @@
 	flags = in->flags;
 	openmode = flags&3;
 	flags &= ~3;
-	flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE);
+	flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC);
 	if(flags & O_TRUNC){
 		openmode |= OTRUNC;
 		flags &= ~O_TRUNC;
diff --git a/src/cmd/acme/cols.c b/src/cmd/acme/cols.c
index 3ac780b..31b2780 100644
--- a/src/cmd/acme/cols.c
+++ b/src/cmd/acme/cols.c
@@ -534,11 +534,12 @@
 	for(i=0; i<c->nw; i++){
 		w = c->w[i];
 		if(ptinrect(p, w->r)){
-			if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.fr.r))
+			if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all))
 				return &w->tag;
-			if(ptinrect(p, w->body.scrollr) || ptinrect(p, w->body.fr.r))
-				return &w->body;
-			return nil;
+			/* exclude partial line at bottom */
+			if(p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y)
+				return nil;
+			return &w->body;
 		}
 	}
 	return nil;
diff --git a/src/cmd/acme/look.c b/src/cmd/acme/look.c
index db69927..66c6c66 100644
--- a/src/cmd/acme/look.c
+++ b/src/cmd/acme/look.c
@@ -365,11 +365,11 @@
 			fbuffree(s);
 			return TRUE;
 		}
-		if(around && q>=ct->q1)
-			break;
 		--nb;
 		b++;
 		q++;
+		if(around && q>=ct->q1)
+			break;
 	}
 	fbuffree(s);
 	return FALSE;
diff --git a/src/cmd/upas/nfs/imap.c b/src/cmd/upas/nfs/imap.c
index 0a93b6b..64ffeb1 100644
--- a/src/cmd/upas/nfs/imap.c
+++ b/src/cmd/upas/nfs/imap.c
@@ -569,13 +569,19 @@
 imapcopylist(Imap *z, char *nbox, Msg **m, uint nm)
 {
 	int rv;
-	char *name;
+	char *name, *p;
 	
 	if(nm == 0)
 		return 0;
 
 	qlock(&z->lk);
-	name = esmprint("%Z", nbox);
+	if(strcmp(nbox, "mbox") == 0)
+		name = estrdup("INBOX");
+	else{
+		p = esmprint("%s%s", z->root, nbox);
+		name = esmprint("%Z", p);
+		free(p);
+	}
 	rv = imaplistcmd(z, m[0]->box, "UID COPY", m, nm, name);
 	free(name);
 	qunlock(&z->lk);
diff --git a/src/cmd/upas/vf/unvf.c b/src/cmd/upas/vf/unvf.c
index 92af6bf..aecbca6 100644
--- a/src/cmd/upas/vf/unvf.c
+++ b/src/cmd/upas/vf/unvf.c
@@ -24,7 +24,7 @@
 	while((p = Brdstr(&b, '\n', 1)) != nil){
 		if(p[0] == 0)
 			break;
-		if(strncmp(p, "Content-Transfer-Encoding: ", 27) == 0)
+		if(cistrncmp(p, "Content-Transfer-Encoding: ", 27) == 0)
 			encoding = strdup(p+27);
 		free(p);
 	}
diff --git a/src/cmd/vbackup/diskcat.c b/src/cmd/vbackup/diskcat.c
index 9258689..bab1176 100644
--- a/src/cmd/vbackup/diskcat.c
+++ b/src/cmd/vbackup/diskcat.c
@@ -33,7 +33,7 @@
 	if((disk = diskcache(disk, 16384, 16)) == nil)
 		sysfatal("diskcache: %r");
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	zero = emalloc(fsys->blocksize);
 	fprint(2, "%d blocks total\n", fsys->nblock);
diff --git a/src/cmd/vbackup/diskftp.c b/src/cmd/vbackup/diskftp.c
index bf58662..33d278b 100644
--- a/src/cmd/vbackup/diskftp.c
+++ b/src/cmd/vbackup/diskftp.c
@@ -72,7 +72,7 @@
 	if((disk = diskcache(disk, 16384, 16)) == nil)
 		sysfatal("diskcache: %r");
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	allowall = 1;
 	memset(&au, 0, sizeof au);
diff --git a/src/cmd/vbackup/disknfs.c b/src/cmd/vbackup/disknfs.c
index 8ad4ffb..b51d0a3 100644
--- a/src/cmd/vbackup/disknfs.c
+++ b/src/cmd/vbackup/disknfs.c
@@ -67,7 +67,7 @@
 		sysfatal("diskcache: %r");
 
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	nfs3chan = chancreate(sizeof(SunMsg*), 0);
 	mountchan = chancreate(sizeof(SunMsg*), 0);
diff --git a/src/cmd/vbackup/vbackup.c b/src/cmd/vbackup/vbackup.c
index 67d2b9b..d027f35 100644
--- a/src/cmd/vbackup/vbackup.c
+++ b/src/cmd/vbackup/vbackup.c
@@ -164,7 +164,7 @@
 	if((disk = diskcache(disk, 32768, 2*MAXQ+16)) == nil)
 		sysfatal("diskcache: %r");
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	/*
 	 * connect to venti
diff --git a/src/cmd/vbackup/vcat.c b/src/cmd/vbackup/vcat.c
index 01320fb..0346963 100644
--- a/src/cmd/vbackup/vcat.c
+++ b/src/cmd/vbackup/vcat.c
@@ -52,7 +52,7 @@
 	if((disk = diskopenventi(c, score)) == nil)
 		sysfatal("diskopenventi: %r");
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	zero = emalloc(fsys->blocksize);
 	fprint(2, "%d blocks total\n", fsys->nblock);
diff --git a/src/cmd/vbackup/vftp.c b/src/cmd/vbackup/vftp.c
index c9dd494..90af42e 100644
--- a/src/cmd/vbackup/vftp.c
+++ b/src/cmd/vbackup/vftp.c
@@ -418,7 +418,7 @@
 			sysfatal("diskopenventi: %r");
 	}
 	if((fsys = fsysopen(disk)) == nil)
-		sysfatal("ffsopen: %r");
+		sysfatal("fsysopen: %r");
 
 	fprint(2, "block size %d\n", fsys->blocksize);
 	buf = emalloc(fsys->blocksize);
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
index 60c9b10..05f4db9 100644
--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -252,7 +252,7 @@
 			close(fd);
 		}
 #endif
-#if defined(__FreeBSD__)
+#if defined(DIOCGMEDIASIZE)
 		if(isdisk(st)){
 			int fd;
 			off_t mediasize;
diff --git a/src/lib9/getns.c b/src/lib9/getns.c
index 923efc7..6c221ee 100644
--- a/src/lib9/getns.c
+++ b/src/lib9/getns.c
@@ -42,6 +42,11 @@
 		if(strcmp(p, ".0") == 0)
 			*p = 0;
 	}
+	
+	/* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */
+	for(p=disp; *p; p++)
+		if(*p == '/')
+			*p = '_';
 
 	p = smprint("/tmp/ns.%s.%s", getuser(), disp);
 	free(disp);
diff --git a/src/libdiskfs/ext2.c b/src/libdiskfs/ext2.c
index 5212965..d0ea65e 100644
--- a/src/libdiskfs/ext2.c
+++ b/src/libdiskfs/ext2.c
@@ -6,6 +6,11 @@
 #include <diskfs.h>
 #include "ext2.h"
 
+static void parsedirent(Dirent*, uchar*);
+static void parseinode(Inode*, uchar*);
+static void parsegroup(Group*, uchar*);
+static void parsesuper(Super*, uchar*);
+
 #define debug 0
 
 static int ext2sync(Fsys*);
@@ -63,31 +68,29 @@
 	free(fsys);
 }
 
-static Group*
-ext2group(Ext2 *fs, u32int i, Block **pb)
+static int
+ext2group(Ext2 *fs, u32int i, Group *g)
 {
 	Block *b;
 	u64int addr;
-	Group *g;
 
 	if(i >= fs->ngroup)
-		return nil;
+		return -1;
 
 	addr = fs->groupaddr + i/fs->descperblock;
 	b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
 	if(b == nil)
-		return nil;
-	g = (Group*)(b->data+i%fs->descperblock*GroupSize);
-	*pb = b;
-	return g;
+		return -1;
+	parsegroup(g, b->data+i%fs->descperblock*GroupSize);
+	blockput(b);
+	return 0;
 }
 
 static Block*
 ext2blockread(Fsys *fsys, u64int vbno)
 {
 	Block *bitb;
-	Group *g;
-	Block *gb;
+	Group g;
 	uchar *bits;
 	u32int bno, boff, bitblock;
 	u64int bitpos;
@@ -108,7 +111,7 @@
 		return nil;
 
 	bno -= fs->firstblock;
-	if((g = ext2group(fs, bno/fs->blockspergroup, &gb)) == nil){
+	if(ext2group(fs, bno/fs->blockspergroup, &g) < 0){
 		if(debug)
 			fprint(2, "loading group: %r...");
 		return nil;
@@ -117,18 +120,17 @@
 	if(debug)
 		fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n",
 			(int)(bno/fs->blockspergroup),
-			g->bitblock,
-			g->inodebitblock,
-			g->inodeaddr,
-			g->freeblockscount,
-			g->freeinodescount,
-			g->useddirscount);
+			g.bitblock,
+			g.inodebitblock,
+			g.inodeaddr,
+			g.freeblockscount,
+			g.freeinodescount,
+			g.useddirscount);
 	if(debug)
-		fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g->bitblock);
+		fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g.bitblock);
 */
-	bitblock = g->bitblock;
+	bitblock = g.bitblock;
 	bitpos = (u64int)bitblock*fs->blocksize;
-	blockput(gb);
 
 	if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){
 		if(debug)
@@ -253,33 +255,33 @@
 ext2sync(Fsys *fsys)
 {
 	int i;
-	Group *g;
+	Group g;
 	Block *b;
-	Super *super;
+	Super super;
 	Ext2 *fs;
 	Disk *disk;
 
 	fs = fsys->priv;
 	disk = fs->disk;
 	if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
-		goto error;
-	super = (Super*)b->data;
-	if(checksuper(super) < 0)
-		goto error;
-	fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
-	fs->nblock = super->nblock;
-	fs->ngroup = (super->nblock+super->blockspergroup-1)
-		/ super->blockspergroup;
-	fs->inospergroup = super->inospergroup;
-	fs->blockspergroup = super->blockspergroup;
+		return -1;
+	parsesuper(&super, b->data);
+	blockput(b);
+	if(checksuper(&super) < 0)
+		return -1;
+	fs->blocksize = MINBLOCKSIZE<<super.logblocksize;
+	fs->nblock = super.nblock;
+	fs->ngroup = (super.nblock+super.blockspergroup-1)
+		/ super.blockspergroup;
+	fs->inospergroup = super.inospergroup;
+	fs->blockspergroup = super.blockspergroup;
 	fs->inosperblock = fs->blocksize / InodeSize;
 	if(fs->blocksize == SBOFF)
 		fs->groupaddr = 2;
 	else
 		fs->groupaddr = 1;
 	fs->descperblock = fs->blocksize / GroupSize;
-	fs->firstblock = super->firstdatablock;
-	blockput(b);
+	fs->firstblock = super.firstdatablock;
 
 	fsys->blocksize = fs->blocksize;
 	fsys->nblock = fs->nblock;
@@ -288,16 +290,10 @@
 
 	if(0){
 		for(i=0; i<fs->ngroup; i++)
-			if((g = ext2group(fs, i, &b)) != nil){
-				fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
-				blockput(b);
-			}
+			if(ext2group(fs, i, &g) >= 0)
+				fprint(2, "grp %d: bitblock=%d\n", i, g.bitblock);
 	}
 	return 0;
-
-error:
-	blockput(b);
-	return -1;
 }
 
 static void
@@ -323,8 +319,8 @@
 	uint ioff;
 	u32int inum;
 	u32int addr;
-	Block *gb, *b;
-	Group *g;
+	Block *b;
+	Group g;
 
 	if(h->len != 4)
 		return Nfs3ErrBadHandle;
@@ -335,13 +331,12 @@
 	if(i >= fs->ngroup)
 		return Nfs3ErrBadHandle;
 	ioff = (inum-1) % fs->inospergroup;
-	if((g = ext2group(fs, i, &gb)) == nil)
+	if(ext2group(fs, i, &g) < 0)
 		return Nfs3ErrIo;
-	addr = g->inodeaddr + ioff/fs->inosperblock;
-	blockput(gb);
+	addr = g.inodeaddr + ioff/fs->inosperblock;
 	if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
 		return Nfs3ErrIo;
-	*ino = ((Inode*)b->data)[ioff%fs->inosperblock];
+	parseinode(ino, b->data+InodeSize*(ioff%fs->inosperblock));
 	blockput(b);
 	return Nfs3Ok;
 }
@@ -505,7 +500,7 @@
 	u32int nblock;
 	u32int i;
 	uchar *p, *ep;
-	Dirent *de;
+	Dirent de;
 	Inode ino;
 	Block *b;
 	Ext2 *fs;
@@ -538,27 +533,27 @@
 		p = b->data;
 		ep = p+b->len;
 		while(p < ep){
-			de = (Dirent*)p;
-			if(de->reclen == 0){
+			parsedirent(&de, p);
+			if(de.reclen == 0){
 				if(debug)
 					fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
 				break;
 			}
-			p += de->reclen;
+			p += de.reclen;
 			if(p > ep){
 				if(debug)
-					fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
+					fprint(2, "bad len %d at offset %d of %d\n", de.reclen, (int)(p-b->data), b->len);
 				break;
 			}
-			if(de->ino == 0)
+			if(de.ino == 0)
 				continue;
-			if(4+2+2+de->namlen > de->reclen){
+			if(4+2+2+de.namlen > de.reclen){
 				if(debug)
-					fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
+					fprint(2, "bad namelen %d at offset %d of %d\n", de.namlen, (int)(p-b->data), b->len);
 				break;
 			}
-			if(de->namlen == len && memcmp(de->name, name, len) == 0){
-				mkhandle(nh, de->ino);
+			if(de.namlen == len && memcmp(de.name, name, len) == 0){
+				mkhandle(nh, de.ino);
 				blockput(b);
 				return Nfs3Ok;
 			}
@@ -575,7 +570,7 @@
 	u32int i;
 	int off, done;
 	uchar *data, *dp, *dep, *p, *ep, *ndp;
-	Dirent *de;
+	Dirent de;
 	Inode ino;
 	Block *b;
 	Ext2 *fs;
@@ -622,30 +617,30 @@
 		ep = p+b->len;
 		memset(&e, 0, sizeof e);
 		while(p < ep){
-			de = (Dirent*)p;
-			if(de->reclen == 0){
+			parsedirent(&de, p);
+			if(de.reclen == 0){
 				if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
 				break;
 			}
-			p += de->reclen;
+			p += de.reclen;
 			if(p > ep){
-				if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
+				if(debug) fprint(2, "reclen %d at offset %d of %d\n", de.reclen, (int)(p-b->data), b->len);
 				break;
 			}
-			if(de->ino == 0){
+			if(de.ino == 0){
 				if(debug) fprint(2, "zero inode\n");
 				continue;
 			}
-			if(4+2+2+de->namlen > de->reclen){
-				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);
+			if(4+2+2+de.namlen > de.reclen){
+				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);
 				break;
 			}
-			if(debug) print("%.*s/%d ", de->namlen, de->name, (int)de->ino);
-			if((uchar*)de - b->data < off)
+			if(debug) print("%.*s/%d ", de.namlen, de.name, (int)de.ino);
+			if(p-de.reclen - b->data < off)
 				continue;
-			e.fileid = de->ino;
-			e.name = de->name;
-			e.namelen = de->namlen;
+			e.fileid = de.ino;
+			e.name = de.name;
+			e.namelen = de.namlen;
 			e.cookie = (u64int)i*fs->blocksize + (p - b->data);
 			if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
 				done = 1;
@@ -778,3 +773,104 @@
 	return Nfs3Ok;
 }
 
+/*
+ * Ext2 is always little-endian, even on big-endian machines.
+ */
+
+static u32int
+l32(uchar *p)
+{
+	return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+}
+
+static u16int
+l16(uchar *p)
+{
+	return p[0] | (p[1]<<8);
+}
+
+static u8int
+l8(uchar *p)
+{
+	return p[0];
+}
+
+static void
+parsedirent(Dirent *de, uchar *p)
+{
+	de->ino = l32(p);
+	de->reclen = l16(p+4);
+	de->namlen = l8(p+6);
+	/* 1 byte pad */
+	de->name = (char*)p+8;
+}
+
+static void
+parseinode(Inode *ino, uchar *p)
+{
+	int i;
+
+	ino->mode = l16(p);
+	ino->uid = l16(p+2);
+	ino->size = l32(p+4);
+	ino->atime = l32(p+8);
+	ino->ctime = l32(p+12);
+	ino->mtime = l32(p+16);
+	ino->dtime = l32(p+20);
+	ino->gid = l16(p+24);
+	ino->nlink = l16(p+26);
+	ino->nblock = l32(p+28);
+	ino->flags = l32(p+32);
+	/* 4 byte osd1 */
+	for(i=0; i<NBLOCKS; i++)
+		ino->block[i] = l32(p+40+i*4);
+	ino->version = l32(p+100);
+	ino->fileacl = l32(p+104);
+	ino->diracl = l32(p+108);
+	ino->faddr = l32(p+112);
+	/* 12 byte osd2 */
+}
+
+static void
+parsegroup(Group *g, uchar *p)
+{
+	g->bitblock = l32(p);
+	g->inodebitblock = l32(p+4);
+	g->inodeaddr = l32(p+8);
+	g->freeblockscount = l16(p+12);
+	g->freeinodescount = l16(p+14);
+	g->useddirscount = l16(p+16);
+	/* 2 byte pad */
+	/* 12 byte reserved */
+}
+
+static void
+parsesuper(Super *s, uchar *p)
+{
+	s->ninode = l32(p);
+	s->nblock = l32(p+4);
+	s->rblockcount = l32(p+8);
+	s->freeblockcount = l32(p+12);
+	s->freeinodecount = l32(p+16);
+	s->firstdatablock = l32(p+20);
+	s->logblocksize = l32(p+24);
+	s->logfragsize = l32(p+28);
+	s->blockspergroup = l32(p+32);
+	s->fragpergroup = l32(p+36);
+	s->inospergroup = l32(p+40);
+	s->mtime = l32(p+44);
+	s->wtime = l32(p+48);
+	s->mntcount = l16(p+52);
+	s->maxmntcount = l16(p+54);
+	s->magic = l16(p+56);
+	s->state = l16(p+58);
+	s->errors = l16(p+60);
+	/* 2 byte pad */
+	s->lastcheck = l32(p+64);
+	s->checkinterval = l32(p+68);
+	s->creatoros = l32(p+72);
+	s->revlevel = l32(p+76);
+	s->defresuid = l16(p+80);
+	s->defresgid = l16(p+82);
+	/* 940 byte reserved */
+}
diff --git a/src/libdiskfs/ext2.h b/src/libdiskfs/ext2.h
index 159a243..6109974 100644
--- a/src/libdiskfs/ext2.h
+++ b/src/libdiskfs/ext2.h
@@ -51,7 +51,7 @@
 
 
 /*
- * Super block on-disk format.
+ * Super block
  */
 struct Super
 {
@@ -84,7 +84,7 @@
 };
 
 /*
- * Block group on-disk format.
+ * Block group
  */
 struct Group
 {
@@ -94,8 +94,6 @@
 	u16int	freeblockscount;	/* Free blocks count */
 	u16int	freeinodescount;	/* Free inodes count */
 	u16int	useddirscount;	/* Directories count */
-	u16int	pad;
-	u32int	reserved[3];
 };
 enum
 {
@@ -103,7 +101,7 @@
 };
 
 /*
- * Structure of an inode on the disk
+ * Inode
  */
 struct Inode
 {
@@ -118,13 +116,11 @@
 	u16int	nlink;	/* Links count */
 	u32int	nblock;	/* Blocks count */
 	u32int	flags;		/* File flags */
-	u32int	osd1;				
 	u32int	block[NBLOCKS];/* Pointers to blocks */
 	u32int	version;	/* File version (for NFS) */
 	u32int	fileacl;	/* File ACL */
 	u32int	diracl;	/* Directory ACL or high size bits */
 	u32int	faddr;		/* Fragment address */
-	uchar	osd2[12];
 };
 enum
 {
@@ -132,15 +128,14 @@
 };
 
 /*
- * Directory entry on-disk structure.
+ * Directory entry
  */
 struct Dirent
 {
 	u32int	ino;			/* Inode number */
 	u16int	reclen;		/* Directory entry length */
 	u8int	namlen;		/* Name length */
-	u8int	pad;
-	char	name[NAMELEN];	/* File name */
+	char	*name;	/* File name */
 };
 enum
 {