Browse Source

Plan 9 from Bell Labs 2010-10-03

David du Colombier 13 years ago
parent
commit
ae217d23b2
6 changed files with 230 additions and 117 deletions
  1. 51 31
      sys/src/cmd/cifs/dfs.c
  2. 11 4
      sys/src/cmd/cifs/fs.c
  3. 152 64
      sys/src/cmd/cifs/main.c
  4. 14 16
      sys/src/cmd/cifs/trans.c
  5. 1 1
      sys/src/cmd/cifs/trans2.c
  6. 1 1
      sys/src/cmd/ip/pptp.c

+ 51 - 31
sys/src/cmd/cifs/dfs.c

@@ -53,6 +53,12 @@
 #include <9p.h>
 #include "cifs.h"
 
+enum {
+	Nomatch,	/* not found in cache */
+	Exactmatch,	/* perfect match found */
+	Badmatch	/* matched but wrong case */
+};
+
 #define SINT_MAX	0x7fffffff
 
 typedef struct Dfscache Dfscache;
@@ -100,27 +106,30 @@ trimshare(char *s)
 }
 
 static Dfscache *
-lookup(char *opath, int *exact)
+lookup(char *path, int *match)
 {
-	char *path;
 	int len, n, m;
 	Dfscache *cp, *best;
 
-	*exact = 0;
+	if(match)
+		*match = Nomatch;
 
 	len = 0;
 	best = nil;
-	path = opath;
-	m = strlen(opath);
+	m = strlen(path);
 	for(cp = Cache; cp; cp = cp->next){
 		n = strlen(cp->src);
-		if(n < len || cistrncmp(path, cp->src, n) != 0 ||
-		    path[n] != 0 && path[n] != '/')
+		if(n < len)
+			continue;
+		if(strncmp(path, cp->src, n) != 0)
+			continue;
+		if(path[n] != 0 && path[n] != '/')
 			continue;
 		best = cp;
 		len = n;
 		if(n == m){
-			*exact = 1;
+			if(match)
+				*match = Exactmatch;
 			break;
 		}
 	}
@@ -131,8 +140,8 @@ char *
 mapfile(char *opath)
 {
 	int exact;
-	char *p, *path;
 	Dfscache *cp;
+	char *p, *path;
 	static char npath[MAX_DFS_PATH];
 
 	path = opath;
@@ -152,22 +161,26 @@ mapfile(char *opath)
 int
 mapshare(char *path, Share **osp)
 {
-	int i, exact;
-	char *try, *tail[] = { "", "$" };
-	Dfscache *cp;
+	int i;
 	Share *sp;
+	Dfscache *cp;
+	char *s, *try;
+	char *tail[] = { "", "$" };
 
-	if((cp = lookup(path, &exact)) == nil)
+	if((cp = lookup(path, nil)) == nil)
 		return 0;
 
-	for(sp = Shares; sp < Shares+Nshares; sp++)
-		if(cistrcmp(cp->share, trimshare(sp->name)) == 0){
-			if(Debug && strstr(Debug, "dfs") != nil)
-				print("mapshare, already connected, src=%q => dst=%q\n",
-					path, sp->name);
-			*osp = sp;
-			return 0;
-		}
+	for(sp = Shares; sp < Shares+Nshares; sp++){
+		s = trimshare(sp->name);
+		if(cistrcmp(cp->share, s) != 0)
+			continue;
+		if(Checkcase && strcmp(cp->share, s) != 0)
+			continue;
+		if(Debug && strstr(Debug, "dfs") != nil)
+			print("mapshare, already connected, src=%q => dst=%q\n", path, sp->name);
+		*osp = sp;
+		return 0;
+	}
 	/*
 	 * Try to autoconnect to share if it is not known.  Note even if you
 	 * didn't specify any shares and let the system autoconnect you may
@@ -193,6 +206,7 @@ mapshare(char *path, Share **osp)
 
 	if(Debug && strstr(Debug, "dfs") != nil)
 		print("mapshare failed src=%s\n", path);
+	werrstr("not found");
 	return -1;
 }
 
@@ -212,9 +226,10 @@ remap(Dfscache *cp, Refer *re)
 	char *p, *a[4];
 	enum {
 		Hostname = 1,
-		Shre = 2,
-		Path = 3,
-		Rtt_tol = 10,
+		Sharename = 2,
+		Pathname = 3,
+
+		Rtt_tol = 10
 	};
 
 	if(Debug && strstr(Debug, "dfs") != nil)
@@ -247,7 +262,7 @@ remap(Dfscache *cp, Refer *re)
 	}
 
 	if(n < 4)
-		a[Path] = "";
+		a[Pathname] = "";
 	if(re->ttl == 0)
 		re->ttl = 60*5;
 
@@ -258,8 +273,8 @@ remap(Dfscache *cp, Refer *re)
 	cp->prox = re->prox;
 	cp->expiry = time(nil)+re->ttl;
 	cp->host = estrdup9p(a[Hostname]);
-	cp->share = estrdup9p(trimshare(a[Shre]));
-	cp->path = estrdup9p(a[Path]);
+	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);
@@ -315,16 +330,19 @@ redir1(Session *s, char *path, Dfscache *cp, int level)
 int
 redirect(Session *s, Share *sp, char *path)
 {
-	int exact;
+	int match;
 	char *unc;
 	Dfscache *cp;
 
 	if(Debug && strstr(Debug, "dfs") != nil)
 		print("redirect name=%q path=%q\n", sp->name, path);
 
-	cp = lookup(path, &exact);
-	if(cp && exact){
-		if(cp->expiry >= time(nil)){	/* cache hit */
+	cp = lookup(path, &match);
+	if(match == Badmatch)
+		return -1;
+
+	if(cp && match == Exactmatch){
+		if(cp->expiry >= time(nil)){		/* cache hit */
 			if(Debug && strstr(Debug, "dfs") != nil)
 				print("redirect cache=hit src=%q => share=%q path=%q\n",
 					cp->src, cp->share, cp->path);
@@ -354,6 +372,7 @@ redirect(Session *s, Share *sp, char *path)
 		}
 	}
 
+
 	/* in-exact match or complete miss */
 	if(cp)
 		unc = smprint("//%s/%s/%s%s%s", s->auth->windom, cp->share,
@@ -385,3 +404,4 @@ redirect(Session *s, Share *sp, char *path)
 			cp->src, cp->share, cp->path);
 	return 0;
 }
+

+ 11 - 4
sys/src/cmd/cifs/fs.c

@@ -30,7 +30,8 @@ shareinfo(Fmt *f)
 				sp = &Shares[j];
 				break;
 			}
-		sp->tid = Ipc.tid;
+		if(j >= Nshares)
+			sp->tid = Ipc.tid;
 
 		if(RAPshareinfo(Sess, sp, sp->name, &si2) != -1){
 			switch(si2.type){
@@ -43,7 +44,8 @@ shareinfo(Fmt *f)
 			default:		type = "unknown"; break;
 			}
 
-			fmtprint(f, "%-8s %s", type, si2.comment);
+			fmtprint(f, "%-8s %5d/%-5d %s", type,
+				si2.activeusrs, si2.maxusrs, si2.comment);
 			free(si2.name);
 			free(si2.comment);
 			free(si2.path);
@@ -64,12 +66,15 @@ openfileinfo(Fmt *f)
 
 	fi = nil;
 	if((got = RAPFileenum2(Sess, &Ipc, "", "", &fi)) == -1){
-		fmtprint(f, "RAPfileenum: %r (Only Administrator has permission)\n");
+		fmtprint(f, "RAPfileenum: %r\n");
 		return 0;
 	}
 
 	for(i = 0; i < got; i++){
-		fmtprint(f, "0x%02x %-4d %-24q %q ", fi[i].perms,
+		fmtprint(f, "%c%c%c %-4d %-24q %q ",
+			(fi[i].perms & 1)? 'r': '-',
+			(fi[i].perms & 2)? 'w': '-',
+			(fi[i].perms & 4)? 'c': '-',
 			fi[i].locks, fi[i].user, fi[i].path);
 		free(fi[i].path);
 		free(fi[i].user);
@@ -173,6 +178,7 @@ sessioninfo(Fmt *f)
  * containing a dot ('.') must be a DNS name, as the NetBios
  * name munging cannot encode one.  Thus names which contain no
  * dots must be netbios names.
+ *
  */
 static void
 dfsredir(Fmt *f, char *path, int depth)
@@ -188,6 +194,7 @@ dfsredir(Fmt *f, char *path, int depth)
 			dfsredir(f, re->path, depth+1);
 		else
 			fmtprint(f, "%-32q %q\n", re->path, re->addr);
+
 		free(re->addr);
 		free(re->path);
 	}

+ 152 - 64
sys/src/cmd/cifs/main.c

@@ -26,7 +26,8 @@ struct Aux {
 
 extern int chatty9p;
 
-int Dfstout = 100; /* timeout (in ms) for ping of dfs servers (assume they are local) */
+int Checkcase = 1;		/* enforce case significance on filenames */
+int Dfstout = 100;		/* timeout (in ms) for ping of dfs servers (assume they are local)  */
 int Billtrog = 1;		/* enable file owner/group resolution */
 int Attachpid;			/* pid of proc that attaches (ugh !) */
 char *Debug = nil;		/* messages */
@@ -40,6 +41,8 @@ int Nshares = 0;		/* number of Shares connected */
 Aux *Auxroot = nil;		/* linked list of Aux structs */
 char *Host = nil;		/* host we are connected to */
 
+static char *Ipcname = "IPC$";
+
 #define ptype(x)	(((x) & 0xf))
 #define pindex(x)	(((x) & 0xff0) >> 4)
 
@@ -87,19 +90,18 @@ Qid
 mkqid(char *s, int is_dir, long vers, int subtype, long path)
 {
 	Qid q;
-	union {				/* align digest suitably */
-		uchar	digest[SHA1dlen];
-		uvlong	uvl;
-	} u;
+	uchar digest[SHA1dlen];
 
-	sha1((uchar *)s, strlen(s), u.digest, nil);
-	q.type = is_dir? QTDIR: 0;
+	sha1((uchar *)s, strlen(s), digest, nil);
+	q.type = (is_dir)? QTDIR: 0;
 	q.vers = vers;
 	if(subtype){
-		q.path = *((uvlong *)u.digest) & ~0xfffL;
-		q.path |= (path & 0xff) << 4 | (subtype & 0xf);
-	}else
-		q.path = *((uvlong *)u.digest) & ~0xfL;
+		q.path = *((uvlong *)digest) & ~0xfffL;
+		q.path |= ((path & 0xff) << 4);
+		q.path |= (subtype & 0xf);
+	}
+	else
+		q.path = *((uvlong *)digest) & ~0xfL;
 	return q;
 }
 
@@ -112,7 +114,7 @@ V2D(Dir *d, Qid qid, char *name)
 	memset(d, 0, sizeof(Dir));
 	d->type = 'C';
 	d->dev = 1;
-	d->name = strlwr(estrdup9p(name));
+	d->name = estrdup9p(name);
 	d->uid = estrdup9p("bill");
 	d->muid = estrdup9p("boyd");
 	d->gid = estrdup9p("trog");
@@ -187,12 +189,13 @@ newpath(char *path, char *name)
 static int
 dirgen(int slot, Dir *d, void *aux)
 {
-	int numinf = numinfo(), rc, got;
-	int slots = min(Sess->mtu, MTU) / sizeof(FInfo);
 	long off;
-	char *npath;
-	Aux *a = aux;
 	FInfo *fi;
+	int rc, got;
+	Aux *a = aux;
+	char *npath;
+	int numinf = numinfo();
+	int slots = min(Sess->mtu, MTU) / sizeof(FInfo);
 
 	if(strcmp(a->path, "/") == 0){
 		if(slot < numinf){
@@ -267,9 +270,9 @@ from_cache:
 static void
 fsattach(Req *r)
 {
-	char *spec = r->ifcall.aname;
 	Aux *a;
 	static int first = 1;
+	char *spec = r->ifcall.aname;
 
 	if(first)
 		setup();
@@ -329,64 +332,135 @@ fsclone(Fid *ofid, Fid *fid)
 	return nil;
 }
 
+/*
+ * for some weird reason T2queryall() returns share names
+ * in lower case so we have to do an extra test against
+ * our share table to validate filename case.
+ *
+ * on top of this here (snell & Wilcox) most of our
+ * redirections point to a share of the same name,
+ * but some do not, thus the tail of the filename
+ * returned by T2queryall() is not the same as
+ * the name we wanted.
+ *
+ * We work around this by not validating the names
+ * or files which resolve to share names as they must
+ * be correct, having been enforced in the dfs layer.
+ */
+static int
+validfile(char *found, char *want, char *winpath, Share *sp)
+{
+	char *share;
+
+	if(strcmp(want, "..") == 0)
+		return 1;
+	if(strcmp(winpath, "/") == 0){
+		share = trimshare(sp->name);
+		if(cistrcmp(want, share) == 0)
+			return strcmp(want, share) == 0;
+		/*
+		 * OK, a DFS redirection points us from a directory XXX
+		 * to a share named YYY.  There is no case checking we can
+		 * do so we allow either case - it's all we can do.
+		 */
+		return 1;
+	}
+	if(cistrcmp(found, want) != 0)
+		return 0;
+	if(!Checkcase)
+		return 1;
+	if(strcmp(found, want) == 0)
+		return 1;
+	return 0;
+}
+
+
 static char*
 fswalk1(Fid *fid, char *name, Qid *qid)
 {
+	FInfo fi;
 	int rc, n, i;
-	char *npath;
 	Aux *a = fid->aux;
-	FInfo fi;
 	static char e[ERRMAX];
+	char *p, *npath, *winpath;
 
 	*e = 0;
 	npath = newpath(a->path, name);
-	if(strcmp(npath, "/") == 0)
+	if(strcmp(npath, "/") == 0){			/* root dir */
 		*qid = mkqid("/", 1, 1, Proot, 0);
-	else if(strrchr(npath, '/') == npath){
-		if((n = walkinfo(name)) != -1)
+		free(a->path);
+		a->path = npath;
+		fid->qid = *qid;
+		return nil;
+	}
+
+	if(strrchr(npath, '/') == npath){		/* top level dir */
+		if((n = walkinfo(name)) != -1){		/* info file */
 			*qid = mkqid(npath, 0, 1, Pinfo, n);
-		else {
+		}
+		else {					/* volume name */
 			for(i = 0; i < Nshares; i++){
 				n = strlen(Shares[i].name);
-				if(cistrncmp(npath+1, Shares[i].name, n) != 0 ||
-				    npath[n+1] != 0 && npath[n+1] != '/')
+				if(cistrncmp(npath+1, Shares[i].name, n) != 0)
+					continue;
+				if(Checkcase && strncmp(npath+1, Shares[i].name, n) != 0)
+					continue;
+				if(npath[n+1] != 0 && npath[n+1] != '/')
 					continue;
 				break;
 			}
-			if(i < Nshares){
-				a->sp = Shares+i;
-				*qid = mkqid(npath, 1, 1, Pshare, i);
-			} else {
+			if(i >= Nshares){
 				free(npath);
 				return "not found";
 			}
+			a->sp = Shares+i;
+			*qid = mkqid(npath, 1, 1, Pshare, i);
 		}
-	} else {
+		free(a->path);
+		a->path = npath;
+		fid->qid = *qid;
+		return nil;
+	}
+
+	/* must be a vanilla file or directory */
 again:
-		if(mapshare(npath, &a->sp) == -1){
-			free(npath);
-			return "not found";
-		}
+	if(mapshare(npath, &a->sp) == -1){
+		rerrstr(e, sizeof(e));
+		free(npath);
+		return e;
+	}
 
-		memset(&fi, 0, sizeof fi);
+	winpath = mapfile(npath);
+	memset(&fi, 0, sizeof fi);
+	if(Sess->caps & CAP_NT_SMBS)
+		rc = T2queryall(Sess, a->sp, winpath, &fi);
+	else
+		rc = T2querystandard(Sess, a->sp, winpath, &fi);
 
-		if(Sess->caps & CAP_NT_SMBS)
-			rc = T2queryall(Sess, a->sp, mapfile(npath), &fi);
-		else
-			rc = T2querystandard(Sess, a->sp, mapfile(npath), &fi);
+	if(rc == -1){
+		rerrstr(e, sizeof(e));
+		free(npath);
+		return e;
+	}
 
-		if((a->sp->options & SMB_SHARE_IS_IN_DFS) != 0 &&
-		    (fi.attribs & ATTR_REPARSE) != 0 &&
-		    redirect(Sess, a->sp, npath) != -1)
+	if((a->sp->options & SMB_SHARE_IS_IN_DFS) != 0 &&
+	    (fi.attribs & ATTR_REPARSE) != 0){
+		if(redirect(Sess, a->sp, npath) != -1)
 			goto again;
-		if(rc == -1){
-			rerrstr(e, sizeof(e));
-			free(npath);
-			return e;
-		}
-		*qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0);
 	}
 
+	if((p = strrchr(fi.name, '/')) == nil && (p = strrchr(fi.name, '\\')) == nil)
+		p = fi.name;
+	else
+		p++;
+
+	if(! validfile(p, name, winpath, a->sp)){
+		free(npath);
+		return "not found";
+
+	}
+	*qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0);
+
 	free(a->path);
 	a->path = npath;
 	fid->qid = *qid;
@@ -583,10 +657,10 @@ ntcreateopen(Aux *a, char *path, int mode, int perm, int is_create,
 static void
 fscreate(Req *r)
 {
+	FInfo fi;
 	int rc, is_dir;
 	char *npath;
 	Aux *a = r->fid->aux;
-	FInfo fi;
 
 	a->end = a->off = 0;
 	a->cache = emalloc9p(max(Sess->mtu, MTU));
@@ -654,9 +728,11 @@ fsopen(Req *r)
 static void
 fswrite(Req *r)
 {
-	vlong n, m, got, len = r->ifcall.count, off = r->ifcall.offset;
-	char *buf = r->ifcall.data;
+	vlong n, m, got;
 	Aux *a = r->fid->aux;
+	vlong len = r->ifcall.count;
+	vlong off = r->ifcall.offset;
+	char *buf = r->ifcall.data;
 
 	got = 0;
 	n = Sess->mtu -OVERHEAD;
@@ -678,9 +754,11 @@ fswrite(Req *r)
 static void
 fsread(Req *r)
 {
-	vlong n, m, got, len = r->ifcall.count, off = r->ifcall.offset;
-	char *buf = r->ofcall.data;
+	vlong n, m, got;
 	Aux *a = r->fid->aux;
+	char *buf = r->ofcall.data;
+	vlong len = r->ifcall.count;
+	vlong off = r->ifcall.offset;
 
 	if(ptype(r->fid->qid.path) == Pinfo){
 		r->ofcall.count = readinfo(pindex(r->fid->qid.path), buf, len,
@@ -814,9 +892,9 @@ static void
 fswstat(Req *r)
 {
 	int fh, result, rc;
+	FInfo fi, tmpfi;
 	char *p, *from, *npath;
 	Aux *a = r->fid->aux;
-	FInfo fi, tmpfi;
 
 	if(ptype(r->fid->qid.path) == Proot ||
 	   ptype(r->fid->qid.path) == Pshare){
@@ -936,11 +1014,12 @@ fswstat(Req *r)
 	 * always update the readonly flag as
 	 * we may have cleared it above.
 	 */
-	if(~r->d.mode)
+	if(~r->d.mode){
 		if(r->d.mode & 0222)
 			fi.attribs &= ~ATTR_READONLY;
 		else
 			fi.attribs |= ATTR_READONLY;
+	}
 	if(rdonly(Sess, a->sp, mapfile(a->path), fi.attribs & ATTR_READONLY) == -1){
 		werrstr("(set info) - %r");
 		responderrstr(r);
@@ -1005,9 +1084,9 @@ usage(void)
 static void
 keepalive(void)
 {
-	int fd, i, rc = 0;
-	uvlong tot, fre;
 	char buf[32];
+	uvlong tot, fre;
+	int fd, i, slot, rc;
 
 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
 	if((fd = open(buf, OWRITE)) >= 0){
@@ -1015,13 +1094,18 @@ keepalive(void)
 		close(fd);
 	}
 
+	rc = 0;
+	slot = 0;
 	do{
 		sleep(6000);
 		if(Active-- != 0)
 			continue;
-		for(i = 0; i < Nshares; i++)
-			if((rc = T2fssizeinfo(Sess, Shares+i, &tot, &fre)) != -1)
+		for(i = 0; i < Nshares; i++){
+			if((rc = T2fssizeinfo(Sess, &Shares[slot], &tot, &fre)) == 0)
 				break;
+			if(++slot >= Nshares)
+				slot = 0;
+		}
 	}while(rc != -1);
 	postnote(PNPROC, Attachpid, "die");
 }
@@ -1040,7 +1124,7 @@ void
 dmpkey(char *s, void *v, int n)
 {
 	int i;
-	uchar *p = (uchar *)v;
+	unsigned char *p = (unsigned char *)v;
 
 	print("%s", s);
 	for(i = 0; i < n; i++)
@@ -1078,6 +1162,9 @@ main(int argc, char **argv)
 	case 'd':
 		Debug = EARGF(usage());
 		break;
+	case 'i':
+		Checkcase = 0;
+		break;
 	case 'k':
 		keyp = EARGF(usage());
 		break;
@@ -1086,7 +1173,7 @@ main(int argc, char **argv)
 		break;
 	case 'n':
 		strncpy(cname, EARGF(usage()), sizeof(cname));
-		cname[sizeof(cname) -1] = 0;
+		cname[sizeof(cname) - 1] = 0;
 		break;
 	case 's':
 		svs = EARGF(usage());
@@ -1121,6 +1208,7 @@ main(int argc, char **argv)
 	if((Sess = cifsdial(Host, Host, sysname)) != nil ||
 	   (Sess = cifsdial(Host, "*SMBSERVER", sysname)) != nil)
 		goto connected;
+
 	sysfatal("%s - cannot dial, %r\n", Host);
 connected:
 	if(CIFSnegotiate(Sess, &svrtime, windom, sizeof windom, cname, sizeof cname) == -1)
@@ -1137,10 +1225,10 @@ connected:
 		sysfatal("session authentication failed, %r\n");
 
 	Sess->slip = svrtime - time(nil);
-	Sess->cname = strlwr(estrdup9p(cname));
+	Sess->cname = estrdup9p(cname);
 
-	if(CIFStreeconnect(Sess, cname, "IPC$", &Ipc) == -1)
-		fprint(2, "IPC$, %r - can't connect\n");
+	if(CIFStreeconnect(Sess, cname, Ipcname, &Ipc) == -1)
+		fprint(2, "%s, %r - can't connect\n", Ipcname);
 
 	Nshares = 0;
 	if(argc == 1){

+ 14 - 16
sys/src/cmd/cifs/trans.c

@@ -160,8 +160,7 @@ RAPshareenum(Session *s, Share *sp, Share **ent)
 	}
 
 	if(ngot < navail)
-		fprint(2, "%s: %d share names too long for RAP (>13 chars)\n",
-			argv0, navail - ngot);
+		fprint(2, "%s: %d/%d - share list incomplete\n", argv0, ngot, navail);
 
 	free(p);
 	return ngot;
@@ -286,12 +285,11 @@ RAPsessionenum(Session *s, Share *sp, Sessinfo **sip)
 		q->user = estrdup9p(tmp);
 		q->sesstime = gl32(p);
 		q->idletime = gl32(p);
-		q++;
 		ngot++;
+		q++;
 	}
 	if(ngot < navail)
-		fprint(2, "warning: %d/%d - incomplete session list sent\n",
-			ngot, navail);
+		fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail);
 	free(p);
 	return ngot;
 }
@@ -342,9 +340,9 @@ RAPgroupenum(Session *s, Share *sp, Namelist **nlp)
  		gmem(p, tmp, 21);
 		tmp[21] = 0;
 		q->name = estrdup9p(tmp);
-		q++;
 		ngot++;
-		if(p->pos >= p->eop)	/* Windows seems to lie sometimes */
+		q++;
+		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
 			break;
 	}
 	free(p);
@@ -398,9 +396,9 @@ RAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp)
  		gmem(p, tmp, 21);
 		tmp[21] = 0;
 		q->name = estrdup9p(tmp);
-		q++;
 		ngot++;
-		if(p->pos >= p->eop)	/* Windows seems to lie sometimes */
+		q++;
+		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
 			break;
 	}
 	free(p);
@@ -452,9 +450,9 @@ RAPuserenum(Session *s, Share *sp, Namelist **nlp)
  		gmem(p, tmp, 21);
 		tmp[21] = 0;
 		q->name = estrdup9p(tmp);
-		q++;
 		ngot++;
-		if(p->pos >= p->eop)	/* Windows seems to lie sometimes */
+		q++;
+		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
 			break;
 	}
 	free(p);
@@ -511,9 +509,9 @@ more:
  		gmem(p, tmp, 21);
 		tmp[21] = 0;
 		q->name = estrdup9p(tmp);
-		q++;
 		ngot++;
-		if(p->pos >= p->eop)	/* Windows seems to lie sometimes */
+		q++;
+		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
 			break;
 	}
 	free(p);
@@ -702,8 +700,8 @@ more:
 			free(q->comment);
 			continue;
 		}
-		q++;
 		ngot++;
+		q++;
 	}
 	free(p);
 	if(ngot < navail)
@@ -729,10 +727,10 @@ more:
 	ptparam(p);
 	pl16(p, API_WFileEnum2);
 	pascii(p, REMSmb_NetFileEnum2_P);	/* request descriptor */
-	pascii(p, REMSmb_file_info_3);		/* reply descriptor */
+	pascii(p, REMSmb_file_info_1);		/* reply descriptor */
 	pascii(p, path);
 	pascii(p, user);
-	pl16(p, 3);				/* detail level */
+	pl16(p, 1);				/* detail level */
 	pl16(p, MTU - 200);			/* receive buffer length */
 	pl32(p, resume);			/* resume key */
 /* FIXME: maybe the padding and resume key are the wrong way around? */

+ 1 - 1
sys/src/cmd/cifs/trans2.c

@@ -187,9 +187,9 @@ int
 T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
 	long *resume, FInfo *fip, int sh)
 {
+	Pkt *p;
 	int i, n;
 	uchar *next;
-	Pkt *p;
 
 	/*
 	 * So I believe from comp.protocols.smb if you send

+ 1 - 1
sys/src/cmd/ip/pptp.c

@@ -54,7 +54,7 @@ void	waitacks(void);
 void
 usage(void)
 {
-	fprint(2, "usage: ip/pptp [-Pd] [-s user:secret] [-x pppnetmntpt] [-w window] server\n");
+	fprint(2, "usage: ip/pptp [-Pd] [-k keyspec] [-x pppnetmntpt] [-w window] server\n");
 	exits("usage");
 }