expose unix mode bits
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
index 4f95932..8a748b9 100644
--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -181,6 +181,20 @@
 			d->qid.type = QTDIR;
 		}
 
+		if(S_ISLNK(st->st_mode))
+			d->mode |= DMSYMLINK;
+		if(S_ISFIFO(st->st_mode))
+			d->mode |= DMNAMEDPIPE;
+		if(S_ISSOCK(st->st_mode))
+			d->mode |= DMSOCKET;
+		if(S_ISBLK(st->st_mode)){
+			d->mode |= DMDEVICE;
+			d->qid.path = ('b'<<16)|st->st_rdev;
+		}
+		if(S_ISCHR(st->st_mode)){
+			d->mode |= DMDEVICE;
+			d->qid.path = ('c'<<16)|st->st_rdev;
+		}
 		/* fetch real size for disks */
 #ifdef _HAVEDISKSIZE
 		if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
index 6842791..d1922bf 100644
--- a/src/lib9/dirfstat.c
+++ b/src/lib9/dirfstat.c
@@ -4,7 +4,7 @@
 
 #include <sys/stat.h>
 
-extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
 
 Dir*
 dirfstat(int fd)
@@ -18,7 +18,7 @@
 		return nil;
 
 	snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
-	nstr = _p9dir(&st, tmp, nil, nil, nil);
+	nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
 	d = mallocz(sizeof(Dir)+nstr, 1);
 	if(d == nil)
 		return nil;
diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
index e4ab3e5..44307ed 100644
--- a/src/lib9/dirread.c
+++ b/src/lib9/dirread.c
@@ -4,7 +4,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 
-extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
 
 #if defined(__linux__)
 static int
@@ -63,7 +63,7 @@
 	char *p, *str, *estr;
 	int i, nstr, m;
 	struct dirent *de;
-	struct stat st;
+	struct stat st, lst;
 	Dir *d;
 
 	n = countde(buf, n);
@@ -86,7 +86,7 @@
 			de->d_name[0] = 0;
 		else{
 			st = lst;
-			if((lst.st_mode&S_IFMT) == S_ISLNK)
+			if((lst.st_mode&S_IFMT) == S_IFLNK)
 				stat(de->d_name, &st);
 			nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
 		}
@@ -106,8 +106,12 @@
 	m = 0;
 	for(i=0; i<n; i++){
 		de = (struct dirent*)p;
-		if(de->d_name[0] != 0 && stat(de->d_name, &st) >= 0)
-			_p9dir(&st, de->d_name, &d[m++], &str, estr);
+		if(de->d_name[0] != 0 && lstat(de->d_name, &st) >= 0){
+			st = lst;
+			if((lst.st_mode&S_IFMT) == S_IFLNK)
+				stat(de->d_name, &st);
+			_p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
+		}
 		p += de->d_reclen;
 	}
 
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
index b46831c..187dea7 100644
--- a/src/lib9/dirstat.c
+++ b/src/lib9/dirstat.c
@@ -4,12 +4,12 @@
 
 #include <sys/stat.h>
 
-extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
 
 Dir*
 dirstat(char *file)
 {
-	struct lstat lst;
+	struct stat lst;
 	struct stat st;
 	int nstr;
 	Dir *d;
@@ -18,7 +18,7 @@
 	if(lstat(file, &lst) < 0)
 		return nil;
 	st = lst;
-	if((lst.mode&S_IFMT) == S_ISLNK)
+	if((lst.st_mode&S_IFMT) == S_IFLNK)
 		stat(file, &st);
 
 	nstr = _p9dir(&lst, &st, file, nil, nil, nil);