shithub: drawterm

Download patch

ref: 9731b2c5e105e92d14a7899fddd7142f6f99fc3f
parent: 39347ab47dab6c556bb37ced7526bfcc8de4cf9b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Feb 25 03:31:01 EST 2016

fix devfs-*.c to not use cname hack to get file path, get rid of MAXPATH limit, make root accessible under /mnt/term/root

under linux, it was not possible to access the clients /mnt directory as it
gets hidden by #/mnt, to solve this, we first bind #U to /root, and then
let cpumain() bind any subdirectory (-r option) in there and finally bind
/root after /. for this to work, i had to get rid of the dreadfull cname hack,
where the c->name is used to derive the unix file path. this did not work when
the device was accessed form a different bind... and it also leaked memory in
cclone() as the c->name's where doubly maintained in fswalk().

also get rid of the fixed MAXPATH sized stack buffers. each devfs now maintains
a dynamic buffer in ther Ufsinfo structure. under windows, this is a wide string.

remove the #ifdef UNICODE maze from devfs-posix.c, we always assume unicode
now with wide strings.

--- a/cpu.c
+++ b/cpu.c
@@ -29,7 +29,6 @@
 static char	*system;
 static int	cflag;
 extern int	dbg;
-extern char*   base;   // fs base for devroot 
 
 static char	*srvname = "ncpu";
 static char	*ealgs = "rc4_256 sha1";
@@ -69,7 +68,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");
+	fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user] [-r root]\n");
 	exits("usage");
 }
 int fdd;
@@ -168,6 +167,12 @@
 		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
 			ealgs = nil;
 		break;
+	case 'r':
+		snprint(buf, sizeof(buf), "/root/%s", EARGF(usage()));
+		cleanname(buf);
+		if(bind(buf, "/root", MREPL) < 0)
+			panic("bind /root: %r");
+		break;
 	case 'C':
 		cflag++;
 		cmd[0] = '!';
@@ -180,9 +185,6 @@
 	case 'k':
 		keyspec = EARGF(usage());
 		break;
-	case 'r':
-		base = EARGF(usage());
-		break;
 	case 's':
 		secstoreserver = EARGF(usage());
 		break;
@@ -195,6 +197,9 @@
 
 	if(argc != 0)
 		usage();
+
+	if(bind("/root", "/", MAFTER) < 0)
+		panic("bind /root: %r");
 
 	if(system == nil)
 		system = readcons("cpu", "cpu", 0);
--- a/kern/devfs-posix.c
+++ b/kern/devfs-posix.c
@@ -15,17 +15,7 @@
 #include	"fns.h"
 #include	"error.h"
 
-
 typedef	struct Ufsinfo	Ufsinfo;
-
-enum
-{
-	NUID	= 256,
-	NGID	= 256,
-	MAXPATH	= 1024,
-	MAXCOMP	= 128
-};
-
 struct Ufsinfo
 {
 	int	mode;
@@ -35,36 +25,20 @@
 	DIR*	dir;
 	vlong	offset;
 	QLock	oq;
+	char*	path;
 	char nextname[NAME_MAX];
 };
 
-char	*base = "/";
-
 static	Qid	fsqid(struct stat *);
-static	void	fspath(Chan*, char*, char*);
+static	char*	catpath(char*, char*);
 static	ulong	fsdirread(Chan*, uchar*, int, ulong);
 static	int	fsomode(int);
 
-/* clumsy hack, but not worse than the Path stuff in the last one */
 static char*
-uc2name(Chan *c)
+lastelem(char *s)
 {
-	char *s;
+	char *t;
 
-	if(c->name == nil)
-		return "/";
-	s = c2name(c);
-	if(s[0]=='#' && s[1]=='U')
-		return s+2;
-	return s;
-}
-
-static char*
-lastelem(Chan *c)
-{
-	char *s, *t;
-
-	s = uc2name(c);
 	if((t = strrchr(s, '/')) == nil)
 		return s;
 	if(t[1] == 0)
@@ -80,9 +54,6 @@
 	static int devno;
 	Ufsinfo *uif;
 
-	if(stat(base, &stbuf) < 0)
-		error(strerror(errno));
-
 	c = devattach('U', spec);
 
 	uif = mallocz(sizeof(Ufsinfo), 1);
@@ -89,6 +60,7 @@
 	uif->mode = stbuf.st_mode;
 	uif->uid = stbuf.st_uid;
 	uif->gid = stbuf.st_gid;
+	uif->path = strdup("/");
 
 	c->aux = uif;
 	c->dev = devno++;
@@ -105,6 +77,7 @@
 
 	uif = mallocz(sizeof(Ufsinfo), 1);
 	*uif = *(Ufsinfo*)c->aux;
+	uif->path = strdup(uif->path);
 	nc->aux = uif;
 
 	return nc;
@@ -114,18 +87,20 @@
 fswalk1(Chan *c, char *name)
 {
 	struct stat stbuf;
-	char path[MAXPATH];
 	Ufsinfo *uif;
+	char *path;
 
-	fspath(c, name, path);
-
 	/*print("** fs walk '%s' -> %s\n", path, name);  */
 
-	if(stat(path, &stbuf) < 0)
+	uif = c->aux;
+	path = catpath(uif->path, name);
+	if(stat(path, &stbuf) < 0){
+		free(path);
 		return 0;
+	}
+	free(uif->path);
+	uif->path = path;
 
-	uif = c->aux;
-
 	uif->mode = stbuf.st_mode;
 	uif->uid = stbuf.st_uid;
 	uif->gid = stbuf.st_gid;
@@ -135,13 +110,10 @@
 	return 1;
 }
 
-extern Cname* addelem(Cname*, char*);
-
 static Walkqid*
 fswalk(Chan *c, Chan *nc, char **name, int nname)
 {
 	int i;
-	Cname *cname;
 	Walkqid *wq;
 
 	if(nc != nil)
@@ -148,19 +120,13 @@
 		panic("fswalk: nc != nil");
 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
 	nc = devclone(c);
-	cname = c->name;
-	incref(&cname->ref);
-
 	fsclone(c, nc);
 	wq->clone = nc;
 	for(i=0; i<nname; i++){
-		nc->name = cname;
 		if(fswalk1(nc, name[i]) == 0)
 			break;
-		cname = addelem(cname, name[i]);
 		wq->qid[i] = nc->qid;
 	}
-	nc->name = cname;
 	if(i != nname){
 		cclose(nc);
 		wq->clone = nil;
@@ -174,19 +140,19 @@
 {
 	Dir d;
 	struct stat stbuf;
-	char path[MAXPATH];
+	Ufsinfo *uif;
 
 	if(n < BIT16SZ)
 		error(Eshortstat);
 
-	fspath(c, 0, path);
-	if(stat(path, &stbuf) < 0)
+	uif = c->aux;
+	if(stat(uif->path, &stbuf) < 0)
 		error(strerror(errno));
 
-	d.name = lastelem(c);
-	d.uid = "unknown";
-	d.gid = "unknown";
-	d.muid = "unknown";
+	d.name = lastelem(uif->path);
+	d.uid = eve;
+	d.gid = eve;
+	d.muid = eve;
 	d.qid = c->qid;
 	d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
 	d.atime = stbuf.st_atime;
@@ -200,7 +166,6 @@
 static Chan*
 fsopen(Chan *c, int mode)
 {
-	char path[MAXPATH];
 	int m, isdir;
 	Ufsinfo *uif;
 
@@ -231,10 +196,8 @@
 	c->mode = openmode(mode);
 
 	uif = c->aux;
-
-	fspath(c, 0, path);
 	if(isdir) {
-		uif->dir = opendir(path);
+		uif->dir = opendir(uif->path);
 		if(uif->dir == 0)
 			error(strerror(errno));
 	}	
@@ -241,8 +204,7 @@
 	else {
 		if(mode & OTRUNC)
 			m |= O_TRUNC;
-		uif->fd = open(path, m, 0666);
-
+		uif->fd = open(uif->path, m, 0666);
 		if(uif->fd < 0)
 			error(strerror(errno));
 	}
@@ -257,16 +219,18 @@
 fscreate(Chan *c, char *name, int mode, ulong perm)
 {
 	int fd, m;
-	char path[MAXPATH];
+	char *path;
 	struct stat stbuf;
 	Ufsinfo *uif;
 
 	m = fsomode(mode&3);
 
-	fspath(c, name, path);
-
 	uif = c->aux;
-
+	path = catpath(uif->path, name);
+	if(waserror()){
+		free(path);
+		nexterror();
+	}
 	if(perm & DMDIR) {
 		if(m)
 			error(Eperm);
@@ -299,9 +263,13 @@
 			error(strerror(errno));
 		uif->fd = fd;
 	}
-
 	if(stat(path, &stbuf) < 0)
 		error(strerror(errno));
+
+	free(uif->path);
+	uif->path = path;
+	poperror();
+
 	c->qid = fsqid(&stbuf);
 	c->offset = 0;
 	c->flag |= COPEN;
@@ -314,7 +282,6 @@
 	Ufsinfo *uif;
 
 	uif = c->aux;
-
 	if(c->flag & COPEN) {
 		if(c->qid.type & QTDIR)
 			closedir(uif->dir);
@@ -321,7 +288,7 @@
 		else
 			close(uif->fd);
 	}
-
+	free(uif->path);
 	free(uif);
 }
 
@@ -367,7 +334,6 @@
 	Ufsinfo *uif;
 
 	uif = c->aux;
-
 	qlock(&uif->oq);
 	if(waserror()) {
 		qunlock(&uif->oq);
@@ -396,13 +362,13 @@
 fsremove(Chan *c)
 {
 	int n;
-	char path[MAXPATH];
+	Ufsinfo *uif;
 
-	fspath(c, 0, path);
+	uif = c->aux;
 	if(c->qid.type & QTDIR)
-		n = rmdir(path);
+		n = rmdir(uif->path);
 	else
-		n = remove(path);
+		n = remove(uif->path);
 	if(n < 0)
 		error(strerror(errno));
 }
@@ -412,34 +378,39 @@
 {
 	Dir d;
 	struct stat stbuf;
-	char old[MAXPATH], new[MAXPATH];
-	char strs[MAXPATH*3], *p;
+	char strs[NAME_MAX*3];
 	Ufsinfo *uif;
 
 	if(convM2D(buf, n, &d, strs) != n)
 		error(Ebadstat);
 	
-	fspath(c, 0, old);
-	if(stat(old, &stbuf) < 0)
+	uif = c->aux;
+	if(stat(uif->path, &stbuf) < 0)
 		error(strerror(errno));
 
-	uif = c->aux;
-
-	fspath(c, 0, old);
 	if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
-		if(chmod(old, d.mode&0777) < 0)
+		if(chmod(uif->path, d.mode&0777) < 0)
 			error(strerror(errno));
 		uif->mode &= ~0777;
 		uif->mode |= d.mode&0777;
 	}
 
-	if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
-		fspath(c, 0, old);
-		strcpy(new, old);
-		p = strrchr(new, '/');
-		strcpy(p+1, d.name);
-		if(rename(old, new) < 0)
+	if(d.name[0] && strcmp(d.name, lastelem(uif->path)) != 0) {
+		char *base, *newpath;
+
+		base = strdup(uif->path);
+		if(waserror()){
+			free(base);
+			nexterror();
+		}
+		*lastelem(base) = 0;
+		newpath = catpath(base, d.name);
+		free(base), base = newpath;
+		if(rename(uif->path, newpath) < 0)
 			error(strerror(errno));
+		free(uif->path);
+		uif->path = newpath;
+		poperror();
 	}
 
 /*
@@ -472,17 +443,20 @@
 	return q;
 }
 
-static void
-fspath(Chan *c, char *ext, char *path)
+static char*
+catpath(char *base, char *ext)
 {
-	strcpy(path, base);
-	strcat(path, "/");
-	strcat(path, uc2name(c));
-	if(ext){
-		strcat(path, "/");
-		strcat(path, ext);
-	}
-	cleanname(path);
+	char *path;
+	int n, m;
+
+	n = strlen(base);
+	m = strlen(ext);
+	path = malloc(n+m+2);
+	memmove(path, base, n);
+	if(n > 0 && path[n-1] != '/')
+		path[n++] = '/';
+	memmove(path+n, ext, m+1);
+	return path;
 }
 
 static int
@@ -526,7 +500,6 @@
 	long n;
 	char de[NAME_MAX];
 	struct stat stbuf;
-	char path[MAXPATH], dirpath[MAXPATH];
 	Ufsinfo *uif;
 
 /*print("fsdirread %s\n", c2name(c));*/
@@ -542,9 +515,9 @@
 		rewinddir(uif->dir);
 	}
 
-	fspath(c, 0, dirpath);
-
 	while(i+BIT16SZ < count) {
+		char *p;
+
 		if(!p9readdir(de, uif))
 			break;
 
@@ -552,17 +525,17 @@
 			continue;
 
 		d.name = de;
-		sprint(path, "%s/%s", dirpath, de);
-		memset(&stbuf, 0, sizeof stbuf);
-
-		if(stat(path, &stbuf) < 0) {
+		p = catpath(uif->path, de);
+		if(stat(p, &stbuf) < 0) {
 			/* fprint(2, "dir: bad path %s\n", path); */
 			/* but continue... probably a bad symlink */
+			memset(&stbuf, 0, sizeof stbuf);
 		}
+		free(p);
 
-		d.uid = "unknown";
-		d.gid = "unknown";
-		d.muid = "unknown";
+		d.uid = eve;
+		d.gid = eve;
+		d.muid = eve;
 		d.qid = fsqid(&stbuf);
 		d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
 		d.atime = stbuf.st_atime;
--- a/kern/devfs-win32.c
+++ b/kern/devfs-win32.c
@@ -14,10 +14,8 @@
 typedef struct DIR	DIR;
 typedef	struct Ufsinfo	Ufsinfo;
 
-
 enum
 {
-	MAXPATH	= 1024,
 	TPATH_ROOT	= 0,	// ""
 	TPATH_VOLUME	= 1,	// "C:"
 	TPATH_FILE	= 2,	// "C:\bla"
@@ -30,8 +28,8 @@
 	WIN32_FIND_DATA	wfd;
 
 	// for GetLogicalDriveStrings()
-	TCHAR		*drivebuf;
-	TCHAR		*drivep;
+	wchar_t		*drivebuf;
+	wchar_t		*drivep;
 
 	// dont move to the next item
 	int		keep;
@@ -44,17 +42,16 @@
 	DIR*	dir;
 	vlong	offset;
 	QLock	oq;
+	wchar_t	*path;
 };
 
-static	void	fspath(Chan *, char *, TCHAR *, int);
+static	wchar_t *catpath(wchar_t *, char *, wchar_t *);
 static	ulong	fsdirread(Chan*, uchar*, int, vlong);
 static	int	fsomode(int);
 static	ulong	fsaccess(int);
-static	ulong	pathtype(TCHAR *);
-static	int	checkvolume(TCHAR *);
+static	ulong	pathtype(wchar_t *);
+static	int	checkvolume(wchar_t *);
 
-char *base = "";
-
 static ulong
 unixtime(FILETIME *ft)
 {
@@ -65,12 +62,10 @@
 }
 
 static uvlong
-pathhash(TCHAR *p)
+pathhash(wchar_t *p)
 {
 	uchar digest[SHA1dlen];
-	int n;
-	for(n=0; p[n] != 0; n++);
-	sha1((uchar*)p, n*sizeof(TCHAR), digest, nil);
+	sha1((uchar*)p, wcslen(p)*sizeof(wchar_t), digest, nil);
 	return *(uvlong*)digest;
 }
 
@@ -89,7 +84,7 @@
 }
 
 static Qid
-wfdtoqid(TCHAR *path, WIN32_FIND_DATA *wfd)
+wfdtoqid(wchar_t *path, WIN32_FIND_DATA *wfd)
 {
 	ulong t;
 	WIN32_FIND_DATA f;
@@ -96,7 +91,6 @@
 	Qid q;
 
 	t = pathtype(path);
-
 	switch(t){
 	case TPATH_VOLUME:
 	case TPATH_ROOT:
@@ -122,14 +116,10 @@
 }
 
 static void
-wfdtodir(TCHAR *path, Dir *d, WIN32_FIND_DATA *wfd)
+wfdtodir(wchar_t *path, Dir *d, WIN32_FIND_DATA *wfd)
 {
 	WIN32_FIND_DATA f;
 
-	d->uid	= "nul";
-	d->gid	= "nul";
-	d->muid	= "nul";
-
 	switch(pathtype(path)){
 	case TPATH_VOLUME:
 	case TPATH_ROOT:
@@ -141,7 +131,7 @@
 		break;
 
 	case TPATH_FILE:
-		if(!wfd){
+		if(wfd == nil){
 			HANDLE h;
 			if((h = FindFirstFile(path, &f))==INVALID_HANDLE_VALUE)
 				oserror();
@@ -155,30 +145,17 @@
 		break;
 	}
 	d->qid = wfdtoqid(path, wfd);
+	d->uid = eve;
+	d->gid = eve;
+	d->muid = eve;
 }
 
-/* clumsy hack, but not worse than the Path stuff in the last one */
 static char*
-uc2name(Chan *c)
-{
-	char *s;
-
-	if(c->name == nil)
-		return "";
-	s = c2name(c);
-	if(s[0]=='#' && s[1]=='U')
-		s += 2;
-	if(*s=='/')
-		s++;
-	return s;
-}
-
-static char*
 lastelem(Chan *c)
 {
 	char *s, *t;
 
-	s = uc2name(c);
+	s = c2name(c);
 	if((t = strrchr(s, '/')) == nil)
 		return s;
 	if(t[1] == 0)
@@ -187,35 +164,26 @@
 }
 
 static ulong
-pathtype(TCHAR *path)
+pathtype(wchar_t *path)
 {
-	int n;
-	n = wcslen(path);
-	if(n < 2){
+	if(path[0] == 0 || path[1] == 0)
 		return TPATH_ROOT;
-	}
-	if(n==2){
+	if(path[1] == ':' && path[2] == 0)
 		return TPATH_VOLUME;
-	}
 	return TPATH_FILE;
 }
 
 static int
-checkvolume(TCHAR *path)
+checkvolume(wchar_t *path)
 {
-	TCHAR vol[MAX_PATH];
-	TCHAR volname[MAX_PATH];
-	TCHAR fsysname[MAX_PATH];
+	wchar_t vol[MAX_PATH];
+	wchar_t volname[MAX_PATH];
+	wchar_t fsysname[MAX_PATH];
 	DWORD complen;
 	DWORD flags;
 
-	wcsncpy(vol, path, MAX_PATH);
-#ifdef UNICODE
-	wcsncat(vol, L"\\", MAXPATH);
-#else
-	wcsncat(vol, "\\", MAXPATH);
-#endif
-
+	wcscpy(vol, path);
+	wcscat(vol, L"\\");
 	if(!GetVolumeInformation(
 		vol,
 		volname,
@@ -224,27 +192,35 @@
 		&complen,
 		&flags,
 		fsysname,
-		MAX_PATH)){
+		MAX_PATH))
 		return 0;
-	}
+
 	return 1;	
 }
 
-static int
-getfileowner(TCHAR *path, char *owner, int nowner)
+static wchar_t*
+wstrdup(wchar_t *s)
 {
-	strncpy(owner, "Bill", nowner);
-	return 1;
+	wchar_t *d;
+	long n;
+
+	n = (wcslen(s)+1)*sizeof(wchar_t);
+	d = mallocz(n, 0);
+	memmove(d, s, n);
+	return d;
 }
 	
 static Chan*
 fsattach(char *spec)
 {
-	Chan *c;
 	static int devno;
 	Ufsinfo *uif;
-	c = devattach('U', spec);
+	Chan *c;
+
 	uif = mallocz(sizeof(Ufsinfo), 1);
+	uif->path = wstrdup(L"");
+
+	c = devattach('U', spec);
 	c->aux = uif;
 	c->dev = devno++;
 	c->qid.type = QTDIR;
@@ -259,6 +235,7 @@
 
 	uif = mallocz(sizeof(Ufsinfo), 1);
 	*uif = *(Ufsinfo*)c->aux;
+	uif->path = wstrdup(uif->path);
 	nc->aux = uif;
 
 	return nc;
@@ -267,37 +244,41 @@
 static int
 fswalk1(Chan *c, char *name)
 {
-	HANDLE h;
 	WIN32_FIND_DATA wfd;
-	TCHAR path[MAXPATH];
-
-	fspath(c, name, path, MAXPATH);
-
-	switch(pathtype(path)){
+	HANDLE h;
+	wchar_t *p;
+	Ufsinfo *uif;
+	
+	uif = c->aux;
+	p = catpath(uif->path, name, nil);
+	switch(pathtype(p)){
 	case TPATH_VOLUME:
-		if(!checkvolume(path))
+		if(!checkvolume(p)){
+			free(p);
 			return 0;
+		}
 	case TPATH_ROOT:
-		c->qid = wfdtoqid(path, nil);
+		c->qid = wfdtoqid(p, nil);
 		break;
 
 	case TPATH_FILE:
-		if((h = FindFirstFile(path, &wfd)) == INVALID_HANDLE_VALUE)
+		if((h = FindFirstFile(p, &wfd)) == INVALID_HANDLE_VALUE){
+			free(p);
 			return 0;
+		}
 		FindClose(h);
-		c->qid = wfdtoqid(path, &wfd);
+		c->qid = wfdtoqid(p, &wfd);
 		break;
 	}
+	free(uif->path);
+	uif->path = p;
 	return 1;
 }
 
-extern Cname* addelem(Cname*, char*);
-
 static Walkqid*
 fswalk(Chan *c, Chan *nc, char **name, int nname)
 {
 	int i;
-	Cname *cname;
 	Walkqid *wq;
 
 	if(nc != nil)
@@ -304,19 +285,13 @@
 		panic("fswalk: nc != nil");
 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
 	nc = devclone(c);
-	cname = c->name;
-	incref(&cname->ref);
-
 	fsclone(c, nc);
 	wq->clone = nc;
 	for(i=0; i<nname; i++){
-		nc->name = cname;
 		if(fswalk1(nc, name[i]) == 0)
 			break;
-		cname = addelem(cname, name[i]);
 		wq->qid[i] = nc->qid;
 	}
-	nc->name = cname;
 	if(i != nname){
 		cclose(nc);
 		wq->clone = nil;
@@ -329,21 +304,13 @@
 fsstat(Chan *c, uchar *buf, int n)
 {
 	Dir d;
-	TCHAR path[MAXPATH];
-	char owner[MAXPATH];
+	Ufsinfo *uif;
 
 	if(n < BIT16SZ)
 		error(Eshortstat);
-	fspath(c, 0, path, MAXPATH);
+	uif = c->aux;
 	d.name = lastelem(c);
-	wfdtodir(path, &d, nil);
-
-	if(getfileowner(path, owner, MAXPATH)){
-		d.uid = owner;
-		d.gid = owner;
-		d.muid = owner;
-	}
-
+	wfdtodir(uif->path, &d, nil);
 	d.type = 'U';
 	d.dev = c->dev;
 	return convD2M(&d, buf, n);
@@ -352,9 +319,9 @@
 static Chan*
 fsopen(Chan *c, int mode)
 {
-	TCHAR path[MAXPATH];
 	ulong t;
 	int m, isdir;
+	wchar_t *p;
 	Ufsinfo *uif;
 
 	m = mode & (OTRUNC|3);
@@ -381,14 +348,13 @@
 	c->mode = openmode(mode);
 	uif = c->aux;
 	uif->offset = 0;
-	fspath(c, 0, path, MAXPATH);
-	t = pathtype(path);
+	t = pathtype(uif->path);
 	if(isdir){
 		DIR *d;
 		d = malloc(sizeof(*d));
 		switch(t){
 		case TPATH_ROOT:
-			d->drivebuf = malloc(sizeof(TCHAR)*MAX_PATH);
+			d->drivebuf = malloc(sizeof(wchar_t)*MAX_PATH);
 			if(GetLogicalDriveStrings(MAX_PATH-1, d->drivebuf) == 0){
 				free(d->drivebuf);
 				d->drivebuf = nil;
@@ -398,12 +364,10 @@
 			break;
 		case TPATH_VOLUME:
 		case TPATH_FILE:
-#ifdef UNICODE
-			wcsncat(path, L"\\*.*", MAXPATH);
-#else
-			wcsncat(path, "\\*.*", MAXPATH);
-#endif
-			if((d->handle = FindFirstFile(path, &d->wfd)) == INVALID_HANDLE_VALUE){
+			p = catpath(uif->path, "*.*", nil);
+			d->handle = FindFirstFile(p, &d->wfd);
+			free(p);
+			if(d->handle == INVALID_HANDLE_VALUE){
 				free(d);
 				oserror();
 			}
@@ -414,15 +378,14 @@
 	} else {
 		uif->dir = nil;
 		if((uif->fh = CreateFile(
-			path,
+			uif->path,
 			fsaccess(mode),
 			FILE_SHARE_READ | FILE_SHARE_WRITE,
 			NULL,
 			(mode & OTRUNC) ? TRUNCATE_EXISTING : OPEN_EXISTING,
 			FILE_ATTRIBUTE_NORMAL,
-			0)) == INVALID_HANDLE_VALUE){
+			0)) == INVALID_HANDLE_VALUE)
 			oserror();
-		}	
 	}
 	c->offset = 0;
 	c->flag |= COPEN;
@@ -433,52 +396,51 @@
 fscreate(Chan *c, char *name, int mode, ulong perm)
 {
 	int m;
-	TCHAR path[MAXPATH];
-	Ufsinfo *uif;
 	ulong t;
+	wchar_t *newpath;
+	Ufsinfo *uif;
 
 	m = fsomode(mode&3);
-
-	fspath(c, name, path, MAXPATH);
-	t = pathtype(path);
-
 	uif = c->aux;
-
+	t = pathtype(uif->path);
+	newpath = catpath(uif->path, name, nil);
+	if(waserror()){
+		free(newpath);
+		nexterror();
+	}
 	if(perm & DMDIR) {
-		TCHAR *p;
+		wchar_t *p;
 		DIR *d;
 		if(m || t!=TPATH_FILE)
 			error(Eperm);
-		if(!CreateDirectory(path, NULL))
+		if(!CreateDirectory(newpath, NULL))
 			oserror();
 		d = malloc(sizeof(*d));
-		p = &path[wcslen(path)];
-#ifdef UNICODE
-		wcsncat(path, L"\\*.*", MAXPATH);
-#else
-		wcsncat(path, "\\*.*", MAXPATH);
-#endif
-		if((d->handle = FindFirstFile(path, &d->wfd)) == INVALID_HANDLE_VALUE){
+		p = catpath(newpath, "*.*", nil);
+		d->handle = FindFirstFile(p, &d->wfd);
+		free(p);
+		if(d->handle == INVALID_HANDLE_VALUE){
 			free(d);
 			oserror();
 		}
-		*p = 0;
 		d->keep = 1;
 		uif->dir = d;
 	} else {
 		uif->dir = nil;
 		if((uif->fh = CreateFile(
-			path,
+			newpath,
 			fsaccess(mode),
 			FILE_SHARE_READ | FILE_SHARE_WRITE,
 			NULL,
 			CREATE_NEW,
 			FILE_ATTRIBUTE_NORMAL,
-			0)) == INVALID_HANDLE_VALUE){
+			0)) == INVALID_HANDLE_VALUE)
 			oserror();
-		}	
 	}
-	c->qid = wfdtoqid(path, nil);
+	free(uif->path);
+	uif->path = newpath;
+	poperror();
+	c->qid = wfdtoqid(newpath, nil);
 	c->offset = 0;
 	c->flag |= COPEN;
 	c->mode = openmode(mode);
@@ -492,8 +454,8 @@
 
 	uif = c->aux;
 	if(c->flag & COPEN) {
-		if(uif->dir){
-			if(uif->dir->drivebuf){
+		if(uif->dir != nil){
+			if(uif->dir->drivebuf != nil){
 				free(uif->dir->drivebuf);
 				uif->dir->drivebuf = nil;
 			} else {
@@ -504,6 +466,7 @@
 			CloseHandle(uif->fh);
 		}
 	}
+	free(uif->path);
 	free(uif);
 }
 
@@ -532,9 +495,8 @@
 		uif->offset = offset;
 	}
 	r = 0;
-	if(!ReadFile(fh, va, (DWORD)n, &r, NULL)){
+	if(!ReadFile(fh, va, (DWORD)n, &r, NULL))
 		oserror();
-	}
 	n = r;
 	uif->offset += n;
 	qunlock(&uif->oq);
@@ -567,9 +529,8 @@
 		uif->offset = offset;
 	}
 	w = 0;
-	if(!WriteFile(fh, va, (DWORD)n, &w, NULL)){
+	if(!WriteFile(fh, va, (DWORD)n, &w, NULL))
 		oserror();
-	}
 	n = w;
 	uif->offset += n;
 	qunlock(&uif->oq);
@@ -580,15 +541,15 @@
 static void
 fsremove(Chan *c)
 {
-	TCHAR path[MAXPATH];
+	Ufsinfo *uif;
 
-	fspath(c, 0, path, MAXPATH);
+	uif = c->aux;
 	if(c->qid.type & QTDIR){
-		if(!RemoveDirectory(path))
-			error("RemoveDirectory...");
+		if(!RemoveDirectory(uif->path))
+			oserror();
 	} else {
-		if(!DeleteFile(path))
-			error("DeleteFile...");
+		if(!DeleteFile(uif->path))
+			oserror();
 	}
 }
 
@@ -595,86 +556,69 @@
 static int
 fswstat(Chan *c, uchar *buf, int n)
 {
-	TCHAR path[MAXPATH];
-	char strs[MAXPATH*3];
+	char strs[MAX_PATH*3];
+	Ufsinfo *uif;
 	Dir d;
-	ulong t;
 
 	if (convM2D(buf, n, &d, strs) != n)
 		error(Ebadstat);
-	fspath(c, 0, path, MAXPATH);
-	t = pathtype(path);
-	if(t != TPATH_FILE)
+	uif = c->aux;
+	if(pathtype(uif->path) != TPATH_FILE)
 		error(Ebadstat);
 	/* change name */
 	if(d.name[0]){
+		wchar_t *base, *newpath;
 		int l;
-		TCHAR newpath[MAXPATH];
-		wcsncpy(newpath, path, MAXPATH);
 
+		base = wstrdup(uif->path);
+		if(waserror()){
+			free(base);
+			nexterror();
+		}
 		/* replace last path-element with d.name */
-		l = wcslen(newpath)-1;
+		l = wcslen(base)-1;
 		if(l <= 0)
 			error(Ebadstat);
 		for(;l>0; l--){
-			if(newpath[l-1]=='\\')
+			if(base[l-1]=='\\')
 				break;
 		}
 		if(l <= 0)
 			error(Ebadstat);
-		newpath[l] = 0;
-#ifdef UNICODE
-		if(!MultiByteToWideChar(CP_UTF8,0,d.name,-1,&newpath[l],MAXPATH-l-1))
-			oserror();
-#else
-		wcsncpy(&newpath[l], d.name, MAXPATH-l-1);
-#endif
-		if(wcscmp(path, newpath)!=0){
-			if(!MoveFile(path, newpath))
+		base[l] = 0;
+		newpath = catpath(base, d.name, nil);
+		free(base), base = newpath;
+		if(wcscmp(uif->path, newpath)!=0){
+			if(!MoveFile(uif->path, newpath))
 				oserror();
-			wcsncpy(path, newpath, MAXPATH);
 		}
+		free(uif->path);
+		uif->path = newpath;
+		poperror();
 	}
 
 	/* fixme: change attributes */
-	c->qid = wfdtoqid(path, nil);
+	c->qid = wfdtoqid(uif->path, nil);
 	return n;	
 }
 
-
-static void
-_fspath(Chan *c, char *ext, char *path, int npath)
+static wchar_t*
+catpath(wchar_t *base, char *cext, wchar_t *wext)
 {
-	*path = 0;
-	strncat(path, uc2name(c), npath);
-	if(ext) {
-		if(*path)
-			strncat(path, "/", npath);
-		strncat(path, ext, npath);
-	}
-	cleanname(path);
-	if(*path == '.')
-		*path = 0;
-}
+	wchar_t *path;
+	long n, m;
 
-static void
-fspath(Chan *c, char *ext, TCHAR *path, int npath)
-{
-	TCHAR *p;
-#ifdef UNICODE
-	char buf[MAXPATH];
-	_fspath(c, ext, buf, sizeof(buf));
-	if(!MultiByteToWideChar(CP_UTF8,0,buf,-1,path,npath)){
-		oserror();
-	}
-#else
-	_fspath(c, ext, path, npath);
-#endif
-	/* make a DOS path */
-	for(p=path; *p; p++){
-		if(*p == '/')
-			*p = '\\';
-	}
+	n = wcslen(base);
+	m = wext!=nil ? wcslen(wext) : strlen(cext)*4;
+	path = malloc((n+m+2)*sizeof(wchar_t));
+	memmove(path, base, n*sizeof(wchar_t));
+	if(n > 0 && path[n-1] != '\\') path[n++] = '\\';
+	if(wext != nil)
+		memmove(path+n, wext, m*sizeof(wchar_t));
+	else
+		m = MultiByteToWideChar(CP_UTF8,0,cext,-1,path+n,m);
+	path[n+m] = 0;
+	return path;
 }
 
 static int
@@ -700,17 +644,13 @@
 	long n;
 	Ufsinfo *uif;
 	char de[MAX_PATH*3];
-	int ndirpath;
-	TCHAR dirpath[MAXPATH];
+	wchar_t *p;
 
 	i = 0;
 	uif = c->aux;
 	errno = 0;
 
-	fspath(c, 0, dirpath, MAXPATH);
-	ndirpath = wcslen(dirpath);
-	t = pathtype(dirpath);
-
+	t = pathtype(uif->path);
 	if(uif->offset != offset) {
 		if(offset != 0)
 			error("bad offset in fsdirread");
@@ -722,14 +662,11 @@
 		case TPATH_VOLUME:
 		case TPATH_FILE:
 			FindClose(uif->dir->handle);
-#ifdef UNICODE
-			wcsncat(dirpath, L"\\*.*", MAXPATH);
-#else
-			wcsncat(dirpath, "\\*.*", MAXPATH);
-#endif
-			if((uif->dir->handle = FindFirstFile(dirpath, &uif->dir->wfd))==INVALID_HANDLE_VALUE){
+			p = catpath(uif->path, "*.*", nil);
+			uif->dir->handle = FindFirstFile(p, &uif->dir->wfd);
+			free(p);
+			if(uif->dir->handle == INVALID_HANDLE_VALUE)
 				oserror();
-			}
 			break;
 		}
 		uif->dir->keep = 1;
@@ -736,8 +673,6 @@
 	}
 
 	while(i+BIT16SZ < count) {
-		char owner[MAXPATH];
-
 		if(!uif->dir->keep) {
 			switch(t){
 			case TPATH_ROOT:
@@ -756,41 +691,21 @@
 		}
 		if(t == TPATH_ROOT){
 			uif->dir->drivep[2] = 0;
-#ifdef UNICODE
 			WideCharToMultiByte(CP_UTF8,0,uif->dir->drivep,-1,de,sizeof(de),0,0);
-#else
-			strncpy(de, uif->dir->drivep, sizeof(de));
-#endif
 		} else {
-#ifdef UNICODE
 			WideCharToMultiByte(CP_UTF8,0,uif->dir->wfd.cFileName,-1,de,sizeof(de),0,0);
-#else
-			strncpy(de, uif->dir->wfd.cFileName, sizeof(de));
-#endif
 		}
 		if(de[0]==0 || isdots(de))
 			continue;
 		d.name = de;
-		dirpath[ndirpath] = 0;		
 		if(t == TPATH_ROOT){
-			wcsncat(dirpath, uif->dir->drivep, MAXPATH);
-			wfdtodir(dirpath, &d, nil);
+			p = catpath(uif->path, nil, uif->dir->drivep);
+			wfdtodir(p, &d, nil);
 		} else {
-#ifdef UNICODE
-			wcsncat(dirpath, L"\\", MAXPATH);
-#else
-			wcsncat(dirpath, "\\", MAXPATH);
-#endif
-			wcsncat(dirpath, uif->dir->wfd.cFileName, MAXPATH);
-			wfdtodir(dirpath, &d, &uif->dir->wfd);
+			p = catpath(uif->path, nil, uif->dir->wfd.cFileName);
+			wfdtodir(p, &d, &uif->dir->wfd);
 		}
-
-		if(getfileowner(dirpath, owner, MAXPATH)){
-			d.uid = owner;
-			d.gid = owner;
-			d.muid = owner;
-		}
-
+		free(p);
 		d.type = 'U';
 		d.dev = c->dev;
 		n = convD2M(&d, (uchar*)va+i, count-i);
--- a/kern/devroot.c
+++ b/kern/devroot.c
@@ -27,7 +27,7 @@
 };
 
 static Dirtab rootdir[Nrootfiles] = {
-	"#/",		{Qdir, 0, QTDIR},	0,		DMDIR|0555,
+	"#/",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
 	"boot",	{Qboot, 0, QTDIR},	0,		DMDIR|0555,
 	"mnt",	{Qmnt, 0, QTDIR},	0,		DMDIR|0555,
 };
--- a/main.c
+++ b/main.c
@@ -55,10 +55,8 @@
 		panic("bind #i: %r");
 	if(bind("#I", "/net", MBEFORE) < 0)
 		panic("bind #I: %r");
-	if(bind("#U", "/", MAFTER) < 0)
+	if(bind("#U", "/root", MREPL) < 0)
 		panic("bind #U: %r");
-	bind("#A", "/dev", MAFTER);
-
 	if(open("/dev/cons", OREAD) != 0)
 		panic("open0: %r");
 	if(open("/dev/cons", OWRITE) != 1)