Various additions and fixes.
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
new file mode 100644
index 0000000..459bd15
--- /dev/null
+++ b/src/lib9/_p9dir.c
@@ -0,0 +1,121 @@
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+
+int
+_p9dir(struct stat *st, char *name, Dir *d, char **str, char *estr)
+{
+	char *s;
+	char tmp[20];
+	struct group *g;
+	struct passwd *p;
+	int sz;
+
+	sz = 0;
+	if(d)
+		memset(d, 0, sizeof *d);
+
+	/* name */
+	s = strrchr(name, '/');
+	if(s)
+		s++;
+	if(!s || !*s)
+		s = name;
+	if(*s == '/')
+		s++;
+	if(*s == 0)
+		s = "/";
+	if(d){
+		if(*str + strlen(s)+1 > estr)
+			d->name = "oops";
+		else{
+			strcpy(*str, s);
+			d->name = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+	sz += strlen(s)+1;
+
+	/* user */
+	p = getpwuid(st->st_uid);
+	if(p == nil){
+		snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
+		s = tmp;
+	}else
+		s = p->pw_name;
+	sz += strlen(s)+1;
+	if(d){
+		if(*str+strlen(s)+1 > estr)
+			d->uid = "oops";	
+		else{
+			strcpy(*str, s);
+			d->uid = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+
+	/* group */
+	g = getgrgid(st->st_gid);
+	if(g == nil){
+		snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
+		s = tmp;
+	}else
+		s = g->gr_name;
+	sz += strlen(s)+1;
+	if(d){
+		if(*str + strlen(s)+1 > estr)
+			d->gid = "oops";	
+		else{
+			strcpy(*str, s);
+			d->gid = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+
+	if(d){
+		d->type = 'M';
+
+		d->muid = "";
+		d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
+		d->qid.vers = st->st_gen;
+		d->mode = st->st_mode&0777;
+		d->atime = st->st_atime;
+		d->mtime = st->st_mtime;
+		d->length = st->st_size;
+
+		if(S_ISDIR(st->st_mode)){
+			d->length = 0;
+			d->mode |= DMDIR;
+			d->qid.type = QTDIR;
+		}
+
+		/* fetch real size for disks */
+		if(S_ISCHR(st->st_mode)){
+			int fd, n;
+			struct disklabel lab;
+
+			if((fd = open(name, O_RDONLY)) < 0)
+				goto nosize;
+			if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+				goto nosize;
+			n = minor(st->st_rdev)&7;
+			if(n >= lab.d_npartitions)
+				goto nosize;
+
+			d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
+
+		nosize:
+			if(fd >= 0)
+				close(fd);
+		}
+	}
+
+	return sz;
+}
+