shithub: riscv

Download patch

ref: 01b6aa0f9f756639fc437af62585c4bfa77319ba
parent: a2abe177e4ec99e3ca22d96fd472c68a19ffe152
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Feb 5 18:10:03 EST 2019

cifs: merge with steve simons latest version. thank you very much!

--- a/sys/src/cmd/cifs/README.Vista
+++ b/sys/src/cmd/cifs/README.Vista
@@ -9,3 +9,8 @@
 -Steve
 
 Tue Sep 21 17:05:48 BST 2010
+
+---------------------------------
+FYI This hot-fix also works for Windows 2k8
+
+Mon Jun 25 10:38:57 BST 2012
--- a/sys/src/cmd/cifs/cifs.c
+++ b/sys/src/cmd/cifs/cifs.c
@@ -39,7 +39,7 @@
 	s->seq = 0;
 	s->seqrun = 0;
 	s->secmode = SECMODE_SIGN_ENABLED;	/* hope for the best */
-	s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO;
+	s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO | FL2_UNICODE;
 
 	s->macidx = -1;
 
@@ -125,6 +125,20 @@
 	p->bytebase = pl16(p, 0);	/* filled in by cifsrpc() */
 }
 
+static void
+dmp(int seq, uchar *buf)
+{
+	int i;
+
+	if(seq == 99)
+		print("\n   ");
+	else
+		print("%+2d ", seq);
+	for(i = 0; i < 8; i++)
+		print("%02x ", buf[i] & 0xff);
+	print("\n");
+}
+
 int
 cifsrpc(Pkt *p)
 {
@@ -233,32 +247,10 @@
 {
 	int d, i;
 	char *ispeak = "NT LM 0.12";
-	static char *dialects[] = {
-//		{ "PC NETWORK PROGRAM 1.0"},
-//		{ "MICROSOFT NETWORKS 1.03"},
-//		{ "MICROSOFT NETWORKS 3.0"},
-//		{ "LANMAN1.0"},
-//		{ "LM1.2X002"},
-//		{ "NT LANMAN 1.0"},
-		{ "NT LM 0.12" },
-	};
+	static char *dialects[] = { { "NT LM 0.12" } };
 	Pkt *p;
 
-	/*
-	 * This should not be necessary, however the XP seems to use
-	 * Unicode strings in its Negoiate response, but not set the
-	 * Flags2 UNICODE flag.
-	 *
-	 * It does however echo back the FL_UNICODE flag we set in the
-	 * flags2 negoiate request.
-	 *
-	 * The bodge is to force FL_UNICODE for this single request, 
-	 * clearing it after. Later we set FL2_UNICODE if the server 
-	 * agrees to CAP_UNICODE as it "should" be done.
-	 */
-	s->flags2 |= FL2_UNICODE;
 	p = cifshdr(s, nil, SMB_COM_NEGOTIATE);
-	s->flags2 &= ~FL2_UNICODE;
 
 	pbytes(p);
 	for(i = 0; i < nelem(dialects); i++){
@@ -284,25 +276,28 @@
 		return -1;
 	}
 
-	s->secmode = g8(p);			/* Security mode */
+	s->secmode = g8(p);				/* Security mode */
 
-	gl16(p);				/* Max outstanding requests */
-	gl16(p);				/* Max VCs */
-	s->mtu = gl32(p);			/* Max buffer size */
-	gl32(p);				/* Max raw buffer size (depricated) */
-	gl32(p);				/* Session key */
-	s->caps = gl32(p);			/* Server capabilities */
+	gl16(p);						/* Max outstanding requests */
+	gl16(p);						/* Max VCs */
+	s->mtu = gl32(p);				/* Max buffer size */
+	gl32(p);						/* Max raw buffer size (depricated) */
+	gl32(p);						/* Session key */
+	s->caps = gl32(p);				/* Server capabilities */
 	*svrtime = gvtime(p);			/* fileserver time */
-	s->tz = (short)gl16(p) * 60; 		/* TZ in mins, is signed (SNIA doc is wrong) */
-	s->challen = g8(p);			/* Encryption key length */
+	s->tz = (short)gl16(p) * 60; 	/* TZ in mins, is signed (SNIA doc is wrong) */
+	s->challen = g8(p);				/* Encryption key length */
 	gl16(p);
-	gmem(p, s->chal, s->challen);		/* Get the challenge */
-	gstr(p, domain, domlen);		/* source domain */
+	gmem(p, s->chal, s->challen);	/* Get the challenge */
 
-	{		/* NetApp Filer seem not to report its called name */
+	/*
+	 * for some weird reason the following two string always seem to be in unicode,
+	 * however they are NOT byte aligned, every other packet is correctly aligned
+	 */
+	gstr_noalign(p, domain, domlen);		/* source domain */
+	{	/* NetApp Filer seem not to report its called name */
 		char *cn = emalloc9p(cnamlen);
-
-		gstr(p, cn, cnamlen);		/* their name */
+		gstr_noalign(p, cn, cnamlen);		/* their name */
 		if(strlen(cn) > 0)
 			memcpy(cname, cn, cnamlen);
 		free(cn);
@@ -310,6 +305,8 @@
 
 	if(s->caps & CAP_UNICODE)
 		s->flags2 |= FL2_UNICODE;
+	else
+		s->flags2 &= ~FL2_UNICODE;
 
 	free(p);
 	return 0;
@@ -329,24 +326,31 @@
 	s->seqrun = 1;	/* activate the sequence number generation/checking */
 
 	p = cifshdr(s, nil, SMB_COM_SESSION_SETUP_ANDX);
-	p8(p, 0xFF);			/* No secondary command */
-	p8(p, 0);			/* Reserved (must be zero) */
-	pl16(p, 0);			/* Offset to next command */
-	pl16(p, MTU);			/* my max buffer size */
-	pl16(p, 1);			/* my max multiplexed pending requests */
-	pl16(p, 0);			/* Virtual connection # */
-	pl32(p, 0);			/* Session key (if vc != 0) */
+	p8(p, 0xFF);				/* No secondary command */
+	p8(p, 0);					/* Reserved (must be zero) */
+	pl16(p, 0);					/* Offset to next command */
+	pl16(p, MTU);				/* my max buffer size */
+	pl16(p, 1);					/* my max multiplexed pending requests */
+	pl16(p, 0);					/* Virtual connection # */
+	pl32(p, 0);					/* Session key (if vc != 0) */
 
+	if(Debug && strstr(Debug, "auth") != nil)
+		fprint(2, "mycaps=%x\n", mycaps);
 
 	if((s->secmode & SECMODE_PW_ENCRYPT) == 0) {
+		if(Debug && strstr(Debug, "auth") != nil)
+			fprint(2, "user=%d %q\npass=%d %q\n", Sess->auth->len[0], Sess->auth->resp[0], Sess->auth->len[1], Sess->auth->resp[1]);
+
 		pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size */
 		pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size (UPPER CASE) */
-		pl32(p, 0);			/* Reserved */
+		pl32(p, 0);				/* Reserved */
 		pl32(p, mycaps);
 		pbytes(p);
 
 		for(q = Sess->auth->resp[0]; *q; ){
 			q += chartorune(&r, q);
+			if(r > Bits16)
+				sysfatal("CIFSsession: '%C' utf too wide for windows\n", r);
 			pl16(p, toupperrune(r));
 		}
 		pl16(p, 0);
@@ -353,13 +357,18 @@
 
 		for(q = Sess->auth->resp[0]; *q; ){
 			q += chartorune(&r, q);
+			if(r > Bits16)
+				sysfatal("CIFSsession: '%C' utf too wide for windows\n", r);
 			pl16(p, r);
 		}
 		pl16(p, 0);
 	}else{
+		if(Debug && strstr(Debug, "auth") != nil)
+			fprint(2, "encrypted len=%d,%d\n", Sess->auth->len[0], Sess->auth->len[1]);
+
 		pl16(p, Sess->auth->len[0]);	/* LM passwd size */
 		pl16(p, Sess->auth->len[1]);	/* NTLM passwd size */
-		pl32(p, 0);			/* Reserved  */
+		pl32(p, 0);						/* Reserved  */
 		pl32(p, mycaps);
 		pbytes(p);
 
@@ -367,10 +376,13 @@
 		pmem(p, Sess->auth->resp[1], Sess->auth->len[1]);
 	}
 
-	pstr(p, Sess->auth->user);	/* Account name */
+	if(Debug && strstr(Debug, "auth") != nil)
+		fprint(2, "user=%q\nwindom=%q\nos=%s\nmanager=%s\n", Sess->auth->user, Sess->auth->windom, "plan9", argv0);
+
+	pstr(p, Sess->auth->user);		/* Account name */
 	pstr(p, Sess->auth->windom);	/* Primary domain */
-	pstr(p, "plan9");		/* Client OS */
-	pstr(p, argv0);			/* Client LAN Manager type */
+	pstr(p, "plan9");				/* Client OS */
+	pstr(p, argv0);					/* Client LAN Manager type */
 
 	if(cifsrpc(p) == -1){
 		free(p);
@@ -377,8 +389,8 @@
 		return -1;
 	}
 
-	g8(p);				/* Reserved (0) */
-	gl16(p);			/* Offset to next command wordcount */
+	g8(p);							/* Reserved (0) */
+	gl16(p);						/* Offset to next command wordcount */
 	Sess->isguest = gl16(p) & 1;	/* logged in as guest */
 
 	gl16(p);
--- a/sys/src/cmd/cifs/cifs.h
+++ b/sys/src/cmd/cifs/cifs.h
@@ -18,6 +18,7 @@
 	MAX_SHARES	= 4096,		/* static table of shares attached */
 	RAP_ERR_MOREINFO= 234,		/* non-error code, more info to be fetched */
 	MAX_DFS_PATH	= 512,		/* MS says never more than 250 chars... */
+	Bits16 = 0xFFFF,			/* max Unicode value Windows supports */
 };
 
 enum {
@@ -451,7 +452,6 @@
 	int	type;	/* o=unknown, 1=CIFS, 2=netware 3=domain */
 	int	flags;	/* 1 == strip off consumed chars before resubmitting */
 	int	ttl;	/* time to live of this info in secs */
-	int	prox;	/* lower value is preferred */
 	char	*path;	/* new path */
 	char	*addr;	/* new server */
 } Refer;
@@ -584,6 +584,7 @@
 extern void *pdatetime(Pkt *p, long utc);
 extern void gmem(Pkt *p, void *v, int n);
 extern void gstr(Pkt *p, char *str, int n);
+extern void gstr_noalign(Pkt *p, char *str, int n);
 extern void gascii(Pkt *p, char *str, int n);
 extern uvlong gl64(Pkt *p);
 extern uvlong gb48(Pkt *p);
@@ -629,6 +630,7 @@
 extern int T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno, char *label, int labellen);
 extern int T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused);
 extern int T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used, Refer *re, int nent);
+extern int T2fsdeviceinfo(Session *s, Share *sp, int *type, int *flags);
 
 /* transnt.c */
 extern int TNTquerysecurity(Session *s, Share *sp, int fh, char **usid, char **gsid);
--- a/sys/src/cmd/cifs/dfs.c
+++ b/sys/src/cmd/cifs/dfs.c
@@ -18,9 +18,8 @@
  * this is not a problem for me and I think it hides a load
  * of problems of its own wrt plan9's private namespaces.
  *
- * The proximity of my test server (AD enabled) is always 0 but some
- * systems may report more meaningful values.  The expiry time is
- * similarly zero, so I guess at 5 mins.
+ * The expiry of my test server (AD enabled) is always 0 but some
+ * systems may report more meaningful values.
  *
  * If the redirection points to a "hidden" share (i.e., its name
  * ends in a $) then the type of the redirection is 0 (unknown) even
@@ -70,7 +69,6 @@
 	char	*path;
 	long	expiry;		/* expiry time in sec */
 	long	rtt;		/* round trip time, nsec */
-	int	prox;		/* proximity, lower = closer */
 };
 
 Dfscache *Cache;
@@ -85,8 +83,8 @@
 		ex = cp->expiry - time(nil);
 		if(ex < 0)
 			ex = -1;
-		fmtprint(f, "%-42s %6ld %8.1f %4d %-16s %-24s %s\n",
-			cp->src, ex, (double)cp->rtt/1000.0L, cp->prox,
+		fmtprint(f, "%-42s %6ld %8.1f %-16s %-24s %s\n",
+			cp->src, ex, (double)cp->rtt/1000.0L, 
 			cp->host, cp->share, cp->path);
 	}
 	return 0;
@@ -239,11 +237,6 @@
 		if(*p == '\\')
 			*p = '/';
 
-	if(cp->prox < re->prox){
-		if(Debug && strstr(Debug, "dfs") != nil)
-			print("	remap %d < %d\n", cp->prox, re->prox);
-		return -1;
-	}
 	if((n = getfields(re->addr, a, sizeof(a), 0, "/")) < 3){
 		if(Debug && strstr(Debug, "dfs") != nil)
 			print("	remap nfields=%d\n", n);
@@ -270,14 +263,13 @@
 	free(cp->share);
 	free(cp->path);
 	cp->rtt = rtt;
-	cp->prox = re->prox;
 	cp->expiry = time(nil)+re->ttl;
 	cp->host = estrdup9p(a[Hostname]);
 	cp->share = estrdup9p(trimshare(a[Sharename]));
 	cp->path = estrdup9p(a[Pathname]);
 	if(Debug && strstr(Debug, "dfs") != nil)
-		print("	remap ping OK prox=%d host=%s share=%s path=%s\n",
-			cp->prox, cp->host, cp->share, cp->path);
+		print("	remap ping OK host=%s share=%s path=%s\n",
+			cp->host, cp->share, cp->path);
 	return 0;
 }
 
@@ -286,8 +278,7 @@
 {
 	Refer retab[16], *re;
 	int n, gflags, used, found;
-
-	if(level > 8)
+	if(level > 16)
 		return -1;
 
 	if((n = T2getdfsreferral(s, &Ipc, path, &gflags, &used, retab,
@@ -295,14 +286,20 @@
 		return -1;
 
 	if(! (gflags & DFS_HEADER_ROOT))
-		used = SINT_MAX;
+		used = 9999;
 
 	found = 0;
 	for(re = retab; re < retab+n; re++){
 		if(Debug && strstr(Debug, "dfs") != nil)
-			print("referal level=%d prox=%d path=%q addr=%q\n",
-				level, re->prox, re->path, re->addr);
+			print("referal level=%d path=%q addr=%q\n",
+				level, re->path, re->addr);
 
+		if(*re->path == 0 || *re->addr == 0){
+			free(re->addr);
+			free(re->path);
+			continue;
+		}
+			
 		if(gflags & DFS_HEADER_STORAGE){
 			if(remap(cp, re) == 0)
 				found = 1;
@@ -350,7 +347,6 @@
 
 		} else{				/* cache hit, but entry stale */
 			cp->rtt = SINT_MAX;
-			cp->prox = SINT_MAX;
 
 			unc = smprint("//%s/%s/%s%s%s", s->auth->windom,
 				cp->share, cp->path, *cp->path? "/": "",
@@ -385,7 +381,6 @@
 	cp = emalloc9p(sizeof(Dfscache));
 	memset(cp, 0, sizeof(Dfscache));
 	cp->rtt = SINT_MAX;
-	cp->prox = SINT_MAX;
 
 	if(redir1(s, unc, cp, 1) == -1){
 		if(Debug && strstr(Debug, "dfs") != nil)
--- a/sys/src/cmd/cifs/fs.c
+++ b/sys/src/cmd/cifs/fs.c
@@ -8,44 +8,40 @@
 
 static char *period(long sec);
 
+static char *devtypes[] = {
+	"beep", "cd", "cdfs", "datalink", "dfs", "disk", "diskfs", "fs", "inport",
+	"kbd", "mailslot", "midi-in", "midi-out", "mouse", "unc", "named-pipe", "net", "net",
+	"browser", "netfs", "null", "lpt", "nic", "lpr", "scanner", "eia-mouse",
+	"eia", "screen", "sound", "streams", "tape", "tapefs", "transport", "unknown",
+	"video", "virt-disk", "wav-in", "wav-out", "8042", "battery", "bus-exp", "modem", "vdm"
+};
+	
+
+static double
+togb(uvlong n)
+{
+	return (double)n / (1024.0 * 1024.0 * 1024.0);
+}
+
 int
 shareinfo(Fmt *f)
 {
-	int i, j, n;
-	char *type;
+	int type;
+	Share *sp;
 	Shareinfo2 si2;
-	Share *sp, *sip;
+	uvlong total, unused;
 
-	if((n = RAPshareenum(Sess, &Ipc, &sip)) < 1){
-		fmtprint(f, "can't enumerate shares: %r\n");
-		return 0;
-	}
+	for(sp = Shares; sp < &Shares[Nshares]; sp++){
+		fmtprint(f, "%-24q ", sp->name);
 
-	for(i = 0; i < n; i++){
-		fmtprint(f, "%-13q ", sip[i].name);
+		if(T2fsdeviceinfo(Sess, sp, &type, nil) != -1)
+			fmtprint(f, "%-16s ", devtypes[type]);
 
-		sp = &sip[i];
-		for(j = 0; j < Nshares; j++)
-			if(strcmp(Shares[j].name, sip[i].name) == 0){
-				sp = &Shares[j];
-				break;
-			}
-		if(j >= Nshares)
-			sp->tid = Ipc.tid;
+		if(T2fssizeinfo(Sess, sp, &total, &unused) != -1)
+			fmtprint(f, "%6.1f/%-6.1f ", togb(total-unused), togb(total));
 
 		if(RAPshareinfo(Sess, sp, sp->name, &si2) != -1){
-			switch(si2.type){
-			case STYPE_DISKTREE:	type = "disk"; break;
-			case STYPE_PRINTQ:	type = "printq"; break;
-			case STYPE_DEVICE:	type = "device"; break;
-			case STYPE_IPC:		type = "ipc"; break;
-			case STYPE_SPECIAL:	type = "special"; break;
-			case STYPE_TEMP:	type = "temp"; break;
-			default:		type = "unknown"; break;
-			}
-
-			fmtprint(f, "%-8s %5d/%-5d %s", type,
-				si2.activeusrs, si2.maxusrs, si2.comment);
+			fmtprint(f, "%5d/%-5d %s", si2.activeusrs, si2.maxusrs, si2.comment);
 			free(si2.name);
 			free(si2.comment);
 			free(si2.path);
@@ -54,7 +50,6 @@
 		fmtprint(f, "\n");
 
 	}
-	free(sip);
 	return 0;
 }
 
@@ -359,7 +354,7 @@
 	min  = sec / 60L;
 	sec -= min * 60L;
 	if(days)
-		snprint(when, sizeof(when), "%d %d:%d:%ld ", days, hrs, min, sec);
+		snprint(when, sizeof(when), "%d,%d:%d:%ld ", days, hrs, min, sec);
 	else
 		snprint(when, sizeof(when), "%d:%d:%ld ", hrs, min, sec);
 	return when;
--- a/sys/src/cmd/cifs/main.c
+++ b/sys/src/cmd/cifs/main.c
@@ -18,6 +18,7 @@
 	long	expire;		/* expiration time of cache */
 	long	off;		/* file pos of start of cache */
 	long	end;		/* file pos of end of cache */
+	long	mtime;		/* last modification time - windows updates it only on close */
 	char	*cache;
 	int	fh;		/* file handle */
 	int	sh;		/* search handle */
@@ -38,7 +39,7 @@
 static int Keeppid;		/* process ID of keepalive thread */
 Share Shares[MAX_SHARES]; 	/* table of connected shares */
 int Nshares = 0;		/* number of Shares connected */
-Aux *Auxroot = nil;		/* linked list of Aux structs */
+Aux *Openfiles = nil;		/* linked list of Aux structs */
 char *Host = nil;		/* host we are connected to */
 
 static char *Ipcname = "IPC$";
@@ -73,7 +74,7 @@
 	Aux *ap;
 	char *type;
 
-	if((ap = Auxroot) != nil)
+	if((ap = Openfiles) != nil)
 		do{
 			type = "walked";
 			if(ap->sh != -1)
@@ -82,7 +83,7 @@
 				type = "openfile";
 			fmtprint(f, "%-9s %s\n", type, ap->path);
 			ap = ap->next;
-		}while(ap != Auxroot);
+		}while(ap != Openfiles);
 	return 0;
 }
 
@@ -129,7 +130,7 @@
 }
 
 static void
-I2D(Dir *d, Share *sp, char *path, FInfo *fi)
+I2D(Dir *d, Share *sp, char *path, long mtime, FInfo *fi)
 {
 	char *name;
 
@@ -144,7 +145,10 @@
 	d->gid = estrdup9p("trog");
 	d->muid = estrdup9p("boyd");
 	d->atime = fi->accessed;
-	d->mtime = fi->written;
+	if(mtime > fi->written)
+		d->mtime = mtime;
+	else
+		d->mtime = fi->written;
 
 	if(fi->attribs & ATTR_READONLY)
 		d->mode = 0444;
@@ -189,6 +193,27 @@
 	return smprint("%s/%s", path, name);
 }
 
+/*
+ * get the last write time if the file is open -
+ * windows only updates mtime when the file is closed
+ * which is not good enough for acme.
+ */
+static long
+realmtime(char *path)
+{
+	Aux *a;
+
+	if((a = Openfiles) == nil)
+		return 0;
+
+	do{
+		if(a->fh != -1 && cistrcmp(path, a->path) == 0)
+			return a->mtime;
+		a = a->next;
+	}while(a != Openfiles);
+	return 0;
+}
+
 /* remove "." and ".." from the cache */
 static int
 rmdots(Aux *a, int got)
@@ -282,7 +307,7 @@
 
 	fi = (FInfo *)(a->cache + (off - a->off));
 	npath = smprint("%s/%s", mapfile(a->path), fi->name);
-	I2D(d, a->sp, npath, fi);
+	I2D(d, a->sp, npath, realmtime(npath), fi);
 	if(Billtrog == 0)
 		upd_names(Sess, a->sp, npath, d);
 	free(npath);
@@ -314,13 +339,13 @@
 	a->fh = -1;
 	a->sh = -1;
 
-	if(Auxroot){
-		a->prev = Auxroot;
-		a->next = Auxroot->next;
-		Auxroot->next->prev = a;
-		Auxroot->next = a;
+	if(Openfiles){
+		a->prev = Openfiles;
+		a->next = Openfiles->next;
+		Openfiles->next->prev = a;
+		Openfiles->next = a;
 	} else {
-		Auxroot = a;
+		Openfiles = a;
 		a->next = a;
 		a->prev = a;
 	}
@@ -341,13 +366,13 @@
 	a->sp = oa->sp;
 	a->path = estrdup9p(oa->path);
 
-	if(Auxroot){
-		a->prev = Auxroot;
-		a->next = Auxroot->next;
-		Auxroot->next->prev = a;
-		Auxroot->next = a;
+	if(Openfiles){
+		a->prev = Openfiles;
+		a->next = Openfiles->next;
+		Openfiles->next->prev = a;
+		Openfiles->next = a;
 	} else {
-		Auxroot = a;
+		Openfiles = a;
 		a->next = a;
 		a->prev = a;
 	}
@@ -483,6 +508,8 @@
 	}
 	*qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0);
 
+	a->mtime = realmtime(npath);
+
 	free(a->path);
 	a->path = npath;
 	fid->qid = *qid;
@@ -512,7 +539,7 @@
 			responderrstr(r);
 			return;
 		}
-		I2D(&r->d, a->sp, a->path, &fi);
+		I2D(&r->d, a->sp, a->path, a->mtime, &fi);
 		if(Billtrog == 0)
 			upd_names(Sess, a->sp, mapfile(a->path), &r->d);
 	}
@@ -767,6 +794,8 @@
 	} while(got < len && m >= n);
 
 	r->ofcall.count = got;
+	a->mtime = time(nil);
+
 	if(m == -1)
 		responderrstr(r);
 	else
@@ -834,12 +863,12 @@
 	if(a->cache)
 		free(a->cache);
 
-	if(a == Auxroot)
-		Auxroot = a->next;
+	if(a == Openfiles)
+		Openfiles = a->next;
 	a->prev->next = a->next;
 	a->next->prev = a->prev;
 	if(a->next == a->prev)
-		Auxroot = nil;
+		Openfiles = nil;
 	if(a)
 		free(a);
 }
@@ -881,7 +910,7 @@
 	}
 
 	/* close all instences of this file/dir */
-	if((ap = Auxroot) != nil)
+	if((ap = Openfiles) != nil)
 		do{
 			if(strcmp(ap->path, a->path) == 0){
 				if(ap->sh != -1)
@@ -892,7 +921,7 @@
 				ap->fh = -1;
 			}
 			ap = ap->next;
-		}while(ap != Auxroot);
+		}while(ap != Openfiles);
 	try = 0;
 again:
 	if(r->fid->qid.type & QTDIR)
@@ -1158,11 +1187,13 @@
 void
 main(int argc, char **argv)
 {
-	int i, n;
+	int i, n, local;
 	long svrtime;
 	char windom[64], cname[64];
-	char *method, *sysname, *keyp, *mtpt, *svs;
+	char *p, *method, *sysname, *keyp, *mtpt, *svs;
+	static char *sh[1024];
 
+	local = 0;
 	*cname = 0;
 	keyp = "";
 	method = nil;
@@ -1190,6 +1221,9 @@
 	case 'k':
 		keyp = EARGF(usage());
 		break;
+	case 'l':
+		local++;
+		break;
 	case 'm':
 		mtpt = EARGF(usage());
 		break;
@@ -1213,8 +1247,12 @@
 
 	Host = argv[0];
 
-	if(mtpt == nil && svs == nil)
-		mtpt = smprint("/n/%s", Host);
+	if(mtpt == nil && svs == nil){
+		if((p = strchr(Host, '!')) != nil)
+			mtpt = smprint("/n/%s", p+1);
+		else
+			mtpt = smprint("/n/%s", Host);
+	}
 
 	if((sysname = getenv("sysname")) == nil)
 		sysname = "unknown";
@@ -1227,7 +1265,10 @@
 		goto connected;
 
 	strcpy(cname, Host);
-	if((Sess = cifsdial(Host, Host, sysname)) != nil ||
+	if((p = strchr(cname, '!')) != nil)
+		strcpy(cname, p+1);
+
+	if((Sess = cifsdial(Host, cname, sysname)) != nil ||
 	   (Sess = cifsdial(Host, "*SMBSERVER", sysname)) != nil)
 		goto connected;
 
@@ -1239,6 +1280,9 @@
 #ifndef DEBUG_MAC
 	Sess->secmode &= ~SECMODE_SIGN_ENABLED;
 #endif
+
+	if(local)
+		strcpy(windom, ".");
 
 	Sess->auth = getauth(method, windom, keyp, Sess->secmode, Sess->chal,
 		Sess->challen);
--- a/sys/src/cmd/cifs/netbios.c
+++ b/sys/src/cmd/cifs/netbios.c
@@ -68,6 +68,19 @@
 		*str++ = *(*p)++;
 }
 
+
+static ulong
+GB32(uchar **p)
+{
+	ulong n;
+
+	n  = *(*p)++ << 24;
+	n |= *(*p)++ << 16;
+	n |= *(*p)++ << 8;
+	n |= *(*p)++;
+	return n;
+}
+
 static ushort
 GB16(uchar **p)
 {
--- a/sys/src/cmd/cifs/pack.c
+++ b/sys/src/cmd/cifs/pack.c
@@ -32,6 +32,8 @@
 			p8(p, 0);
 		while(*str){
 			str += chartorune(&r, str);
+			if(r > Bits16)
+				sysfatal("ppath: %C/%x utf too wide for windows\n", r, r);
 			if(r == L'/')
 				r = L'\\';
 			pl16(p, r);
@@ -62,6 +64,8 @@
 			p8(p, 0);		/* pad to even offset */
 		while(*str){
 			str += chartorune(&r, str);
+			if(r > Bits16)
+				sysfatal("pstr: %C/%x utf too wide for windows\n", r, r);
 			pl16(p, r);
 		}
 		pl16(p, 0);
@@ -229,8 +233,8 @@
  * in runes or bytes, in ASCII mode this is also the size
  * of the output buffer but this is not so in Unicode mode!
  */
-void
-gstr(Pkt *p, char *str, int n)
+static void
+_gstr(Pkt *p, char *str, int n, int align)
 {
 	int i;
 	Rune r;
@@ -239,9 +243,10 @@
 		return;
 
 	if(p->flags2 & FL2_UNICODE){
-		if(((p->pos - p->buf) % 2) != 0)
-			g8(p);		/* strip padding to even offset */
-
+		if(((p->pos - p->buf) % 2) != 0){
+			if(align)
+				abort();
+		}
 		i = 0;
 		while(*p->pos && n && p->pos < p->eop){
 			r = gl16(p);
@@ -249,7 +254,6 @@
 			n -= 2;
 		}
 		*(str + i) = 0;
-
 		while(*p->pos && p->pos < p->eop)
 			gl16(p);
 		/*
@@ -270,6 +274,40 @@
 }
 
 void
+gstr(Pkt *p, char *str, int n)
+{
+	_gstr(p, str, n, 1);
+}
+
+void
+gstr_noalign(Pkt *p, char *str, int n)
+{
+	_gstr(p, str, n, 0);
+}
+
+/*
+ * Because DFS uses a string heap rather than strings embedded in the
+ * data packet, experience (rather than any spec) tells, us we must
+ * turn off the 16bit alignment for unicode strings.
+ */
+void
+goff(Pkt *p, uchar *base, char *str, int n)
+{
+	int off;
+	uchar *pos;
+
+	off = gl16(p);
+	if(off == 0 || base + off > p->eop){
+		memset(str, 0, n);
+		return;
+	}
+	pos = p->pos;
+	p->pos = base + off;
+	gstr_noalign(p, str, n);
+	p->pos = pos;
+}
+
+void
 gascii(Pkt *p, char *str, int n)
 {
 	if(!n || !str)
@@ -401,17 +439,17 @@
 		d = gl16(p);
 	}
 
-	memset(&tm, 0, sizeof(tm));
 	tm.year = 80 + (d >> 9);
 	tm.mon = ((d >> 5) & 017) - 1;
 	tm.mday = d & 037;
+	tm.zone[0] = 0;
+	tm.tzoff = p->s->tz;
 
 	tm.hour = t >> 11;
 	tm.min = (t >> 5) & 63;
 	tm.sec = (t & 31) << 1;
-	strcpy(tm.zone, "GMT");
 
-	return tm2sec(&tm) + p->s->tz;
+	return tm2sec(&tm);
 }
 
 long
@@ -448,19 +486,3 @@
 	p->pos = pos;
 }
 
-void
-goff(Pkt *p, uchar *base, char *str, int n)
-{
-	int off;
-	uchar *pos;
-
-	off = gl16(p);
-	if(off == 0 || base + off > p->eop){
-		memset(str, 0, n);
-		return;
-	}
-	pos = p->pos;
-	p->pos = base + off;
-	gstr(p, str, n);
-	p->pos = pos;
-}
--- a/sys/src/cmd/cifs/trans.c
+++ b/sys/src/cmd/cifs/trans.c
@@ -103,6 +103,13 @@
 	p->pos = p->tparam;
 }
 
+static void
+gtdata(Pkt *p)
+{
+	p->pos = p->tdata;
+}
+
+
 int
 RAPshareenum(Session *s, Share *sp, Share **ent)
 {
@@ -281,8 +288,8 @@
 		ngot++;
 		q++;
 	}
-	if(ngot < navail)
-		fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail);
+//	if(ngot < navail)
+//		fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail);
 	free(p);
 	return ngot;
 }
--- a/sys/src/cmd/cifs/trans2.c
+++ b/sys/src/cmd/cifs/trans2.c
@@ -402,8 +402,8 @@
 	ct = gvtime(p);			/* creation time */
 	sn = gl32(p);			/* serial number */
 	n = gl32(p);			/* label name length */
-	g8(p);				/* reserved */
-	g8(p);				/* reserved */
+	g8(p);					/* reserved */
+	g8(p);					/* reserved */
 
 	memset(label, 0, labellen);
 	if(n < labellen && n > 0)
@@ -418,6 +418,35 @@
 }
 
 int
+T2fsdeviceinfo(Session *s, Share *sp, int *type, int *flags)
+{
+	Pkt *p;
+	long t, f;
+
+	p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
+	pt2param(p);
+	pl16(p, SMB_QUERY_FS_DEVICE_INFO);	/* Information level */
+
+	pt2data(p);
+
+	if(t2rpc(p) == -1){
+		free(p);
+		return -1;
+	}
+
+	gt2data(p);
+	t = gl32(p);			/* device type */
+	f = gl32(p);			/* device characteristics */
+
+	if(type)
+		*type = t;
+	if(flags)
+		*flags = f;
+	free(p);
+	return 0;
+}
+
+int
 T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused)
 {
 	Pkt *p;
@@ -485,15 +514,15 @@
 		re[i].flags = gl16(p);	/* referal flags */
 		switch(vers){
 		case 1:
-			re[i].prox = 0;	/* nearby */
-			re[i].ttl = 5*60;	/* 5 mins */
+			re[i].ttl = 300;		/* 30 mins */
 			gstr(p, tmp, sizeof tmp);
 			re[i].addr = estrdup9p(tmp);
 			re[i].path = estrdup9p(tmp);
 			break;
 		case 2:
-			re[i].prox = gl32(p);	/* not implemented in v2 */
 			re[i].ttl = gl32(p);
+			if(re[i].ttl == 0)
+				re[i].ttl = 1800;
 			goff(p, base, re[i].path, sizeof tmp);
 			re[i].path = estrdup9p(tmp);
 			goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
@@ -501,9 +530,10 @@
 			re[i].addr = estrdup9p(tmp);
 			break;
 		case 3:
-			if(re[i].flags & DFS_REFERAL_LIST){
-				re[i].prox = 0;
+			if(re[i].flags & DFS_REFERAL_LIST){	/* normal referal */
 				re[i].ttl = gl32(p);
+				if(re[i].ttl == 0)
+					re[i].ttl = 1800;
 				goff(p, base, tmp, sizeof tmp);
 				re[i].path = estrdup9p(tmp);
 				gl16(p);
@@ -510,15 +540,16 @@
 				goff(p, base, tmp, sizeof tmp);
 				re[i].addr = estrdup9p(tmp);
 			}
-			else{
-				re[i].prox = 0;
+			else{					/* domain root */
 				re[i].ttl = gl32(p);
+				if(re[i].ttl == 0)
+					re[i].ttl = 300;
 				goff(p, base, tmp, sizeof tmp);
 				re[i].path = estrdup9p(tmp);
 				gl16(p);	/* spurious 8.3 path */
 				goff(p, base, tmp, sizeof tmp);
 				re[i].addr = estrdup9p(tmp);
-				gl16(p);	/* GUID (historic) */
+				/* GUID (historic) here, skipped below as we know the record length */
 			}
 			break;
 		default:
--- a/sys/src/cmd/cifs/transnt.c
+++ b/sys/src/cmd/cifs/transnt.c
@@ -96,6 +96,12 @@
 }
 
 static void
+gtntparam(Pkt *p)
+{
+	p->pos = p->tparam;
+}
+
+static void
 gtntdata(Pkt *p)
 {
 	p->pos = p->tdata;