xref: /plan9/sys/src/cmd/cifs/main.c (revision 4ac58c07183c445f67bd3f184ee8741461ecc4cb)
1671dfc47SDavid du Colombier #include <u.h>
2671dfc47SDavid du Colombier #include <libc.h>
3671dfc47SDavid du Colombier #include <fcall.h>
4671dfc47SDavid du Colombier #include <thread.h>
5671dfc47SDavid du Colombier #include <libsec.h>
6671dfc47SDavid du Colombier #include <9p.h>
7671dfc47SDavid du Colombier #include "cifs.h"
8671dfc47SDavid du Colombier 
9671dfc47SDavid du Colombier #define max(a,b)	(((a) > (b))? (a): (b))
10671dfc47SDavid du Colombier #define min(a,b)	(((a) < (b))? (a): (b))
11671dfc47SDavid du Colombier 
12671dfc47SDavid du Colombier typedef struct Aux Aux;
13671dfc47SDavid du Colombier struct Aux {
14671dfc47SDavid du Colombier 	Aux	*next;
15671dfc47SDavid du Colombier 	Aux	*prev;
16671dfc47SDavid du Colombier 	char	*path;		/* full path fo file */
17671dfc47SDavid du Colombier 	Share	*sp;		/* this share's info */
18671dfc47SDavid du Colombier 	long	expire;		/* expiration time of cache */
19671dfc47SDavid du Colombier 	long	off;		/* file pos of start of cache */
20671dfc47SDavid du Colombier 	long	end;		/* file pos of end of cache */
21671dfc47SDavid du Colombier 	char	*cache;
22671dfc47SDavid du Colombier 	int	fh;		/* file handle */
23671dfc47SDavid du Colombier 	int	sh;		/* search handle */
24671dfc47SDavid du Colombier 	long	srch;		/* find first's internal state */
25671dfc47SDavid du Colombier };
26671dfc47SDavid du Colombier 
27671dfc47SDavid du Colombier extern int chatty9p;
28671dfc47SDavid du Colombier 
29912e5f54SDavid du Colombier int Checkcase = 1;		/* enforce case significance on filenames */
30671dfc47SDavid du Colombier int Dfstout = 100;		/* timeout (in ms) for ping of dfs servers (assume they are local)  */
31671dfc47SDavid du Colombier int Billtrog = 1;		/* enable file owner/group resolution */
32671dfc47SDavid du Colombier int Attachpid;			/* pid of proc that attaches (ugh !) */
33671dfc47SDavid du Colombier char *Debug = nil;		/* messages */
34671dfc47SDavid du Colombier Qid Root;			/* root of remote system */
35671dfc47SDavid du Colombier Share Ipc;			/* Share info of IPC$ share */
36671dfc47SDavid du Colombier Session *Sess;			/* current session */
37671dfc47SDavid du Colombier int Active = IDLE_TIME;		/* secs until next keepalive is sent */
38671dfc47SDavid du Colombier static int Keeppid;		/* process ID of keepalive thread */
39671dfc47SDavid du Colombier Share Shares[MAX_SHARES]; 	/* table of connected shares */
40671dfc47SDavid du Colombier int Nshares = 0;		/* number of Shares connected */
41671dfc47SDavid du Colombier Aux *Auxroot = nil;		/* linked list of Aux structs */
42671dfc47SDavid du Colombier char *Host = nil;		/* host we are connected to */
43671dfc47SDavid du Colombier 
44912e5f54SDavid du Colombier static char *Ipcname = "IPC$";
45912e5f54SDavid du Colombier 
46671dfc47SDavid du Colombier #define ptype(x)	(((x) & 0xf))
47671dfc47SDavid du Colombier #define pindex(x)	(((x) & 0xff0) >> 4)
48671dfc47SDavid du Colombier 
49671dfc47SDavid du Colombier void
setup(void)50671dfc47SDavid du Colombier setup(void)
51671dfc47SDavid du Colombier {
52671dfc47SDavid du Colombier 	int fd;
53671dfc47SDavid du Colombier 	char buf[32];
54671dfc47SDavid du Colombier 
55671dfc47SDavid du Colombier 	/*
56671dfc47SDavid du Colombier 	 * This is revolting but I cannot see any other way to get
57671dfc47SDavid du Colombier 	 * the pid of the server.  We need this as Windows doesn't
58671dfc47SDavid du Colombier 	 * drop the TCP connection when it closes a connection.
59671dfc47SDavid du Colombier 	 * Thus we keepalive() to detect when/if we are thrown off.
60671dfc47SDavid du Colombier 	 */
61671dfc47SDavid du Colombier 	Attachpid = getpid();
62671dfc47SDavid du Colombier 
63671dfc47SDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
64671dfc47SDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
65671dfc47SDavid du Colombier 		fprint(fd, "%s network", Host);
66671dfc47SDavid du Colombier 		close(fd);
67671dfc47SDavid du Colombier 	}
68671dfc47SDavid du Colombier }
69671dfc47SDavid du Colombier 
70671dfc47SDavid du Colombier int
filetableinfo(Fmt * f)71671dfc47SDavid du Colombier filetableinfo(Fmt *f)
72671dfc47SDavid du Colombier {
73671dfc47SDavid du Colombier 	Aux *ap;
74671dfc47SDavid du Colombier 	char *type;
75671dfc47SDavid du Colombier 
76671dfc47SDavid du Colombier 	if((ap = Auxroot) != nil)
77671dfc47SDavid du Colombier 		do{
78671dfc47SDavid du Colombier 			type = "walked";
79671dfc47SDavid du Colombier 			if(ap->sh != -1)
80671dfc47SDavid du Colombier 				type = "opendir";
81671dfc47SDavid du Colombier 			if(ap->fh != -1)
82671dfc47SDavid du Colombier 				type = "openfile";
83671dfc47SDavid du Colombier 			fmtprint(f, "%-9s %s\n", type, ap->path);
84671dfc47SDavid du Colombier 			ap = ap->next;
85671dfc47SDavid du Colombier 		}while(ap != Auxroot);
86671dfc47SDavid du Colombier 	return 0;
87671dfc47SDavid du Colombier }
88671dfc47SDavid du Colombier 
89671dfc47SDavid du Colombier Qid
mkqid(char * s,int is_dir,long vers,int subtype,long path)90671dfc47SDavid du Colombier mkqid(char *s, int is_dir, long vers, int subtype, long path)
91671dfc47SDavid du Colombier {
92671dfc47SDavid du Colombier 	Qid q;
93*4ac58c07SDavid du Colombier 	union {				/* align digest suitably */
94671dfc47SDavid du Colombier 		uchar	digest[SHA1dlen];
95*4ac58c07SDavid du Colombier 		uvlong	uvl;
96*4ac58c07SDavid du Colombier 	} u;
97671dfc47SDavid du Colombier 
98*4ac58c07SDavid du Colombier 	sha1((uchar *)s, strlen(s), u.digest, nil);
99912e5f54SDavid du Colombier 	q.type = (is_dir)? QTDIR: 0;
100671dfc47SDavid du Colombier 	q.vers = vers;
101671dfc47SDavid du Colombier 	if(subtype){
102*4ac58c07SDavid du Colombier 		q.path = *((uvlong *)u.digest) & ~0xfffL;
103912e5f54SDavid du Colombier 		q.path |= ((path & 0xff) << 4);
104912e5f54SDavid du Colombier 		q.path |= (subtype & 0xf);
105912e5f54SDavid du Colombier 	}
106912e5f54SDavid du Colombier 	else
107*4ac58c07SDavid du Colombier 		q.path = *((uvlong *)u.digest) & ~0xfL;
108671dfc47SDavid du Colombier 	return q;
109671dfc47SDavid du Colombier }
110671dfc47SDavid du Colombier 
111671dfc47SDavid du Colombier /*
112671dfc47SDavid du Colombier  * used only for root dir and shares
113671dfc47SDavid du Colombier  */
114671dfc47SDavid du Colombier static void
V2D(Dir * d,Qid qid,char * name)115671dfc47SDavid du Colombier V2D(Dir *d, Qid qid, char *name)
116671dfc47SDavid du Colombier {
117671dfc47SDavid du Colombier 	memset(d, 0, sizeof(Dir));
118671dfc47SDavid du Colombier 	d->type = 'C';
119671dfc47SDavid du Colombier 	d->dev = 1;
120912e5f54SDavid du Colombier 	d->name = estrdup9p(name);
121671dfc47SDavid du Colombier 	d->uid = estrdup9p("bill");
122671dfc47SDavid du Colombier 	d->muid = estrdup9p("boyd");
123671dfc47SDavid du Colombier 	d->gid = estrdup9p("trog");
124671dfc47SDavid du Colombier 	d->mode = 0755 | DMDIR;
125671dfc47SDavid du Colombier 	d->atime = time(nil);
126671dfc47SDavid du Colombier 	d->mtime = d->atime;
127671dfc47SDavid du Colombier 	d->length = 0;
128671dfc47SDavid du Colombier 	d->qid = qid;
129671dfc47SDavid du Colombier }
130671dfc47SDavid du Colombier 
131671dfc47SDavid du Colombier static void
I2D(Dir * d,Share * sp,char * path,FInfo * fi)132671dfc47SDavid du Colombier I2D(Dir *d, Share *sp, char *path, FInfo *fi)
133671dfc47SDavid du Colombier {
134671dfc47SDavid du Colombier 	char *name;
135671dfc47SDavid du Colombier 
136671dfc47SDavid du Colombier 	if((name = strrchr(fi->name, '\\')) != nil)
137671dfc47SDavid du Colombier 		name++;
138671dfc47SDavid du Colombier 	else
139671dfc47SDavid du Colombier 		name = fi->name;
140671dfc47SDavid du Colombier 	d->name = estrdup9p(name);
141671dfc47SDavid du Colombier 	d->type = 'C';
142671dfc47SDavid du Colombier 	d->dev = sp->tid;
143671dfc47SDavid du Colombier 	d->uid = estrdup9p("bill");
144671dfc47SDavid du Colombier 	d->gid = estrdup9p("trog");
145671dfc47SDavid du Colombier 	d->muid = estrdup9p("boyd");
146671dfc47SDavid du Colombier 	d->atime = fi->accessed;
147671dfc47SDavid du Colombier 	d->mtime = fi->written;
148671dfc47SDavid du Colombier 
149671dfc47SDavid du Colombier 	if(fi->attribs & ATTR_READONLY)
150671dfc47SDavid du Colombier 		d->mode = 0444;
151671dfc47SDavid du Colombier 	else
152671dfc47SDavid du Colombier 		d->mode = 0666;
153671dfc47SDavid du Colombier 
154671dfc47SDavid du Colombier 	d->length = fi->size;
155671dfc47SDavid du Colombier 	d->qid = mkqid(path, fi->attribs & ATTR_DIRECTORY, fi->changed, 0, 0);
156671dfc47SDavid du Colombier 
157671dfc47SDavid du Colombier 	if(fi->attribs & ATTR_DIRECTORY){
158671dfc47SDavid du Colombier 		d->length = 0;
159671dfc47SDavid du Colombier 		d->mode |= DMDIR|0111;
160671dfc47SDavid du Colombier 	}
161671dfc47SDavid du Colombier }
162671dfc47SDavid du Colombier 
163671dfc47SDavid du Colombier static void
responderrstr(Req * r)164671dfc47SDavid du Colombier responderrstr(Req *r)
165671dfc47SDavid du Colombier {
166671dfc47SDavid du Colombier 	char e[ERRMAX];
167671dfc47SDavid du Colombier 
168671dfc47SDavid du Colombier 	*e = 0;
169671dfc47SDavid du Colombier 	rerrstr(e, sizeof e);
170671dfc47SDavid du Colombier 	respond(r, e);
171671dfc47SDavid du Colombier }
172671dfc47SDavid du Colombier 
173671dfc47SDavid du Colombier static char *
newpath(char * path,char * name)174671dfc47SDavid du Colombier newpath(char *path, char *name)
175671dfc47SDavid du Colombier {
176671dfc47SDavid du Colombier 	char *p, *q;
177671dfc47SDavid du Colombier 
178671dfc47SDavid du Colombier 	assert((p = strrchr(path, '/')) != nil);
179671dfc47SDavid du Colombier 
180671dfc47SDavid du Colombier 	if(strcmp(name, "..") == 0){
181671dfc47SDavid du Colombier 		if(p == path)
182671dfc47SDavid du Colombier 			return estrdup9p("/");
183671dfc47SDavid du Colombier 		q = emalloc9p((p-path)+1);
184671dfc47SDavid du Colombier 		strecpy(q, q+(p-path)+1, path);
185671dfc47SDavid du Colombier 		return q;
186671dfc47SDavid du Colombier 	}
187671dfc47SDavid du Colombier 	if(strcmp(path, "/") == 0)
188671dfc47SDavid du Colombier 		return smprint("/%s", name);
189671dfc47SDavid du Colombier 	return smprint("%s/%s", path, name);
190671dfc47SDavid du Colombier }
191671dfc47SDavid du Colombier 
192671dfc47SDavid du Colombier static int
dirgen(int slot,Dir * d,void * aux)193671dfc47SDavid du Colombier dirgen(int slot, Dir *d, void *aux)
194671dfc47SDavid du Colombier {
195671dfc47SDavid du Colombier 	long off;
196671dfc47SDavid du Colombier 	FInfo *fi;
197912e5f54SDavid du Colombier 	int rc, got;
198912e5f54SDavid du Colombier 	Aux *a = aux;
199912e5f54SDavid du Colombier 	char *npath;
200912e5f54SDavid du Colombier 	int numinf = numinfo();
201912e5f54SDavid du Colombier 	int slots = min(Sess->mtu, MTU) / sizeof(FInfo);
202671dfc47SDavid du Colombier 
203671dfc47SDavid du Colombier 	if(strcmp(a->path, "/") == 0){
204671dfc47SDavid du Colombier 		if(slot < numinf){
205671dfc47SDavid du Colombier 			dirgeninfo(slot, d);
206671dfc47SDavid du Colombier 			return 0;
207671dfc47SDavid du Colombier 		} else
208671dfc47SDavid du Colombier 			slot -= numinf;
209671dfc47SDavid du Colombier 
210671dfc47SDavid du Colombier 		if(slot >= Nshares)
211671dfc47SDavid du Colombier 			return -1;
212671dfc47SDavid du Colombier 		V2D(d, mkqid(Shares[slot].name, 1, 1, Pshare, slot),
213671dfc47SDavid du Colombier 			Shares[slot].name);
214671dfc47SDavid du Colombier 		return 0;
215671dfc47SDavid du Colombier 	}
216671dfc47SDavid du Colombier 
217671dfc47SDavid du Colombier 	off = slot * sizeof(FInfo);
218671dfc47SDavid du Colombier 	if(off >= a->off && off < a->end && time(nil) < a->expire)
219671dfc47SDavid du Colombier 		goto from_cache;
220671dfc47SDavid du Colombier 
221671dfc47SDavid du Colombier 	if(off == 0){
222671dfc47SDavid du Colombier 		fi = (FInfo *)a->cache;
223671dfc47SDavid du Colombier 		npath = smprint("%s/*", mapfile(a->path));
224671dfc47SDavid du Colombier 		a->sh = T2findfirst(Sess, a->sp, slots, npath, &got, &a->srch,
225671dfc47SDavid du Colombier 			(FInfo *)a->cache);
226671dfc47SDavid du Colombier 		free(npath);
227671dfc47SDavid du Colombier 		if(a->sh == -1)
228671dfc47SDavid du Colombier 			return -1;
229671dfc47SDavid du Colombier 
230671dfc47SDavid du Colombier 		a->off = 0;
231671dfc47SDavid du Colombier 		a->end = got * sizeof(FInfo);
232671dfc47SDavid du Colombier 
233671dfc47SDavid du Colombier 		if(got >= 2 && strcmp(fi[0].name, ".") == 0 &&
234671dfc47SDavid du Colombier 		    strcmp(fi[1].name, "..") == 0){
235671dfc47SDavid du Colombier 			a->end = (got - 2) * sizeof(FInfo);
236671dfc47SDavid du Colombier 			memmove(a->cache, a->cache + sizeof(FInfo)*2,
237671dfc47SDavid du Colombier 				a->end - a->off);
238671dfc47SDavid du Colombier 		}
239671dfc47SDavid du Colombier 	}
240671dfc47SDavid du Colombier 
241671dfc47SDavid du Colombier 	while(off >= a->end && a->sh != -1){
242671dfc47SDavid du Colombier 		fi = (FInfo *)(a->cache + (a->end - a->off) - sizeof(FInfo));
243671dfc47SDavid du Colombier 		a->off = a->end;
244671dfc47SDavid du Colombier 		npath = smprint("%s/%s", mapfile(a->path), fi->name);
245671dfc47SDavid du Colombier 		rc = T2findnext(Sess, a->sp, slots, npath,
246671dfc47SDavid du Colombier 			&got, &a->srch, (FInfo *)a->cache, a->sh);
247671dfc47SDavid du Colombier 		free(npath);
248671dfc47SDavid du Colombier 		if(rc == -1 || got == 0)
249671dfc47SDavid du Colombier 			break;
250671dfc47SDavid du Colombier 		a->end = a->off + got * sizeof(FInfo);
251671dfc47SDavid du Colombier 	}
252671dfc47SDavid du Colombier 	a->expire = time(nil) + CACHETIME;
253671dfc47SDavid du Colombier 
254671dfc47SDavid du Colombier 	if(got < slots){
255671dfc47SDavid du Colombier 		if(a->sh != -1)
256671dfc47SDavid du Colombier 			CIFSfindclose2(Sess, a->sp, a->sh);
257671dfc47SDavid du Colombier 		a->sh = -1;
258671dfc47SDavid du Colombier 	}
259671dfc47SDavid du Colombier 
260671dfc47SDavid du Colombier 	if(off >= a->end)
261671dfc47SDavid du Colombier 		return -1;
262671dfc47SDavid du Colombier 
263671dfc47SDavid du Colombier from_cache:
264671dfc47SDavid du Colombier 	fi = (FInfo *)(a->cache + (off - a->off));
265671dfc47SDavid du Colombier 	npath = smprint("%s/%s", mapfile(a->path), fi->name);
266671dfc47SDavid du Colombier 	I2D(d, a->sp, npath, fi);
267671dfc47SDavid du Colombier 	if(Billtrog == 0)
268671dfc47SDavid du Colombier 		upd_names(Sess, a->sp, npath, d);
269671dfc47SDavid du Colombier 	free(npath);
270671dfc47SDavid du Colombier 	return 0;
271671dfc47SDavid du Colombier }
272671dfc47SDavid du Colombier 
273671dfc47SDavid du Colombier static void
fsattach(Req * r)274671dfc47SDavid du Colombier fsattach(Req *r)
275671dfc47SDavid du Colombier {
276671dfc47SDavid du Colombier 	Aux *a;
277671dfc47SDavid du Colombier 	static int first = 1;
278912e5f54SDavid du Colombier 	char *spec = r->ifcall.aname;
279671dfc47SDavid du Colombier 
280671dfc47SDavid du Colombier 	if(first)
281671dfc47SDavid du Colombier 		setup();
282671dfc47SDavid du Colombier 
283671dfc47SDavid du Colombier 	if(spec && *spec){
284671dfc47SDavid du Colombier 		respond(r, "invalid attach specifier");
285671dfc47SDavid du Colombier 		return;
286671dfc47SDavid du Colombier 	}
287671dfc47SDavid du Colombier 
288671dfc47SDavid du Colombier 	r->ofcall.qid = mkqid("/", 1, 1, Proot, 0);
289671dfc47SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
290671dfc47SDavid du Colombier 
291671dfc47SDavid du Colombier 	a = r->fid->aux = emalloc9p(sizeof(Aux));
292671dfc47SDavid du Colombier 	memset(a, 0, sizeof(Aux));
293671dfc47SDavid du Colombier 	a->path = estrdup9p("/");
294671dfc47SDavid du Colombier 	a->sp = nil;
295671dfc47SDavid du Colombier 	a->fh = -1;
296671dfc47SDavid du Colombier 	a->sh = -1;
297671dfc47SDavid du Colombier 
298671dfc47SDavid du Colombier 	if(Auxroot){
299671dfc47SDavid du Colombier 		a->prev = Auxroot;
300671dfc47SDavid du Colombier 		a->next = Auxroot->next;
301671dfc47SDavid du Colombier 		Auxroot->next->prev = a;
302671dfc47SDavid du Colombier 		Auxroot->next = a;
303671dfc47SDavid du Colombier 	} else {
304671dfc47SDavid du Colombier 		Auxroot = a;
305671dfc47SDavid du Colombier 		a->next = a;
306671dfc47SDavid du Colombier 		a->prev = a;
307671dfc47SDavid du Colombier 	}
308671dfc47SDavid du Colombier 	respond(r, nil);
309671dfc47SDavid du Colombier }
310671dfc47SDavid du Colombier 
311671dfc47SDavid du Colombier static char*
fsclone(Fid * ofid,Fid * fid)312671dfc47SDavid du Colombier fsclone(Fid *ofid, Fid *fid)
313671dfc47SDavid du Colombier {
314671dfc47SDavid du Colombier 	Aux *oa = ofid->aux;
315671dfc47SDavid du Colombier 	Aux *a = emalloc9p(sizeof(Aux));
316671dfc47SDavid du Colombier 
317671dfc47SDavid du Colombier 	fid->aux = a;
318671dfc47SDavid du Colombier 
319671dfc47SDavid du Colombier 	memset(a, 0, sizeof(Aux));
320671dfc47SDavid du Colombier 	a->sh = -1;
321671dfc47SDavid du Colombier 	a->fh = -1;
322671dfc47SDavid du Colombier 	a->sp = oa->sp;
323671dfc47SDavid du Colombier 	a->path = estrdup9p(oa->path);
324671dfc47SDavid du Colombier 
325671dfc47SDavid du Colombier 	if(Auxroot){
326671dfc47SDavid du Colombier 		a->prev = Auxroot;
327671dfc47SDavid du Colombier 		a->next = Auxroot->next;
328671dfc47SDavid du Colombier 		Auxroot->next->prev = a;
329671dfc47SDavid du Colombier 		Auxroot->next = a;
330671dfc47SDavid du Colombier 	} else {
331671dfc47SDavid du Colombier 		Auxroot = a;
332671dfc47SDavid du Colombier 		a->next = a;
333671dfc47SDavid du Colombier 		a->prev = a;
334671dfc47SDavid du Colombier 	}
335671dfc47SDavid du Colombier 	return nil;
336671dfc47SDavid du Colombier }
337671dfc47SDavid du Colombier 
338912e5f54SDavid du Colombier /*
339912e5f54SDavid du Colombier  * for some weird reason T2queryall() returns share names
340912e5f54SDavid du Colombier  * in lower case so we have to do an extra test against
341912e5f54SDavid du Colombier  * our share table to validate filename case.
342912e5f54SDavid du Colombier  *
343912e5f54SDavid du Colombier  * on top of this here (snell & Wilcox) most of our
344912e5f54SDavid du Colombier  * redirections point to a share of the same name,
345912e5f54SDavid du Colombier  * but some do not, thus the tail of the filename
346912e5f54SDavid du Colombier  * returned by T2queryall() is not the same as
347912e5f54SDavid du Colombier  * the name we wanted.
348912e5f54SDavid du Colombier  *
349912e5f54SDavid du Colombier  * We work around this by not validating the names
350912e5f54SDavid du Colombier  * or files which resolve to share names as they must
351912e5f54SDavid du Colombier  * be correct, having been enforced in the dfs layer.
352912e5f54SDavid du Colombier  */
353912e5f54SDavid du Colombier static int
validfile(char * found,char * want,char * winpath,Share * sp)354912e5f54SDavid du Colombier validfile(char *found, char *want, char *winpath, Share *sp)
355912e5f54SDavid du Colombier {
356912e5f54SDavid du Colombier 	char *share;
357912e5f54SDavid du Colombier 
358912e5f54SDavid du Colombier 	if(strcmp(want, "..") == 0)
359912e5f54SDavid du Colombier 		return 1;
360912e5f54SDavid du Colombier 	if(strcmp(winpath, "/") == 0){
361912e5f54SDavid du Colombier 		share = trimshare(sp->name);
362912e5f54SDavid du Colombier 		if(cistrcmp(want, share) == 0)
363912e5f54SDavid du Colombier 			return strcmp(want, share) == 0;
364912e5f54SDavid du Colombier 		/*
365912e5f54SDavid du Colombier 		 * OK, a DFS redirection points us from a directory XXX
366912e5f54SDavid du Colombier 		 * to a share named YYY.  There is no case checking we can
367912e5f54SDavid du Colombier 		 * do so we allow either case - it's all we can do.
368912e5f54SDavid du Colombier 		 */
369912e5f54SDavid du Colombier 		return 1;
370912e5f54SDavid du Colombier 	}
371912e5f54SDavid du Colombier 	if(cistrcmp(found, want) != 0)
372912e5f54SDavid du Colombier 		return 0;
373912e5f54SDavid du Colombier 	if(!Checkcase)
374912e5f54SDavid du Colombier 		return 1;
375912e5f54SDavid du Colombier 	if(strcmp(found, want) == 0)
376912e5f54SDavid du Colombier 		return 1;
377912e5f54SDavid du Colombier 	return 0;
378912e5f54SDavid du Colombier }
379912e5f54SDavid du Colombier 
380912e5f54SDavid du Colombier 
381671dfc47SDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)382671dfc47SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
383671dfc47SDavid du Colombier {
384671dfc47SDavid du Colombier 	FInfo fi;
385912e5f54SDavid du Colombier 	int rc, n, i;
386912e5f54SDavid du Colombier 	Aux *a = fid->aux;
387671dfc47SDavid du Colombier 	static char e[ERRMAX];
388912e5f54SDavid du Colombier 	char *p, *npath, *winpath;
389671dfc47SDavid du Colombier 
390671dfc47SDavid du Colombier 	*e = 0;
391671dfc47SDavid du Colombier 	npath = newpath(a->path, name);
392912e5f54SDavid du Colombier 	if(strcmp(npath, "/") == 0){			/* root dir */
393671dfc47SDavid du Colombier 		*qid = mkqid("/", 1, 1, Proot, 0);
394912e5f54SDavid du Colombier 		free(a->path);
395912e5f54SDavid du Colombier 		a->path = npath;
396912e5f54SDavid du Colombier 		fid->qid = *qid;
397912e5f54SDavid du Colombier 		return nil;
398912e5f54SDavid du Colombier 	}
399912e5f54SDavid du Colombier 
400912e5f54SDavid du Colombier 	if(strrchr(npath, '/') == npath){		/* top level dir */
401912e5f54SDavid du Colombier 		if((n = walkinfo(name)) != -1){		/* info file */
402671dfc47SDavid du Colombier 			*qid = mkqid(npath, 0, 1, Pinfo, n);
403912e5f54SDavid du Colombier 		}
404912e5f54SDavid du Colombier 		else {					/* volume name */
405671dfc47SDavid du Colombier 			for(i = 0; i < Nshares; i++){
406671dfc47SDavid du Colombier 				n = strlen(Shares[i].name);
407912e5f54SDavid du Colombier 				if(cistrncmp(npath+1, Shares[i].name, n) != 0)
408912e5f54SDavid du Colombier 					continue;
409912e5f54SDavid du Colombier 				if(Checkcase && strncmp(npath+1, Shares[i].name, n) != 0)
410912e5f54SDavid du Colombier 					continue;
411912e5f54SDavid du Colombier 				if(npath[n+1] != 0 && npath[n+1] != '/')
412671dfc47SDavid du Colombier 					continue;
413671dfc47SDavid du Colombier 				break;
414671dfc47SDavid du Colombier 			}
415912e5f54SDavid du Colombier 			if(i >= Nshares){
416912e5f54SDavid du Colombier 				free(npath);
417912e5f54SDavid du Colombier 				return "not found";
418912e5f54SDavid du Colombier 			}
419671dfc47SDavid du Colombier 			a->sp = Shares+i;
420671dfc47SDavid du Colombier 			*qid = mkqid(npath, 1, 1, Pshare, i);
421671dfc47SDavid du Colombier 		}
422912e5f54SDavid du Colombier 		free(a->path);
423912e5f54SDavid du Colombier 		a->path = npath;
424912e5f54SDavid du Colombier 		fid->qid = *qid;
425912e5f54SDavid du Colombier 		return nil;
426671dfc47SDavid du Colombier 	}
427912e5f54SDavid du Colombier 
428912e5f54SDavid du Colombier 	/* must be a vanilla file or directory */
429671dfc47SDavid du Colombier again:
430671dfc47SDavid du Colombier 	if(mapshare(npath, &a->sp) == -1){
431912e5f54SDavid du Colombier 		rerrstr(e, sizeof(e));
432671dfc47SDavid du Colombier 		free(npath);
433912e5f54SDavid du Colombier 		return e;
434671dfc47SDavid du Colombier 	}
435671dfc47SDavid du Colombier 
436912e5f54SDavid du Colombier 	winpath = mapfile(npath);
437671dfc47SDavid du Colombier 	memset(&fi, 0, sizeof fi);
438671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
439912e5f54SDavid du Colombier 		rc = T2queryall(Sess, a->sp, winpath, &fi);
440671dfc47SDavid du Colombier 	else
441912e5f54SDavid du Colombier 		rc = T2querystandard(Sess, a->sp, winpath, &fi);
442671dfc47SDavid du Colombier 
443671dfc47SDavid du Colombier 	if(rc == -1){
444671dfc47SDavid du Colombier 		rerrstr(e, sizeof(e));
445671dfc47SDavid du Colombier 		free(npath);
446671dfc47SDavid du Colombier 		return e;
447671dfc47SDavid du Colombier 	}
448912e5f54SDavid du Colombier 
449912e5f54SDavid du Colombier 	if((a->sp->options & SMB_SHARE_IS_IN_DFS) != 0 &&
450912e5f54SDavid du Colombier 	    (fi.attribs & ATTR_REPARSE) != 0){
451912e5f54SDavid du Colombier 		if(redirect(Sess, a->sp, npath) != -1)
452912e5f54SDavid du Colombier 			goto again;
453671dfc47SDavid du Colombier 	}
454671dfc47SDavid du Colombier 
455912e5f54SDavid du Colombier 	if((p = strrchr(fi.name, '/')) == nil && (p = strrchr(fi.name, '\\')) == nil)
456912e5f54SDavid du Colombier 		p = fi.name;
457912e5f54SDavid du Colombier 	else
458912e5f54SDavid du Colombier 		p++;
459912e5f54SDavid du Colombier 
460912e5f54SDavid du Colombier 	if(! validfile(p, name, winpath, a->sp)){
461912e5f54SDavid du Colombier 		free(npath);
462912e5f54SDavid du Colombier 		return "not found";
463912e5f54SDavid du Colombier 
464912e5f54SDavid du Colombier 	}
465912e5f54SDavid du Colombier 	*qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0);
466912e5f54SDavid du Colombier 
467671dfc47SDavid du Colombier 	free(a->path);
468671dfc47SDavid du Colombier 	a->path = npath;
469671dfc47SDavid du Colombier 	fid->qid = *qid;
470671dfc47SDavid du Colombier 	return nil;
471671dfc47SDavid du Colombier }
472671dfc47SDavid du Colombier 
473671dfc47SDavid du Colombier static void
fsstat(Req * r)474671dfc47SDavid du Colombier fsstat(Req *r)
475671dfc47SDavid du Colombier {
476671dfc47SDavid du Colombier 	int rc;
477671dfc47SDavid du Colombier 	FInfo fi;
478671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
479671dfc47SDavid du Colombier 
480671dfc47SDavid du Colombier 	if(ptype(r->fid->qid.path) == Proot)
481671dfc47SDavid du Colombier 		V2D(&r->d, r->fid->qid, "");
482671dfc47SDavid du Colombier 	else if(ptype(r->fid->qid.path) == Pinfo)
483671dfc47SDavid du Colombier 		dirgeninfo(pindex(r->fid->qid.path), &r->d);
484671dfc47SDavid du Colombier 	else if(ptype(r->fid->qid.path) == Pshare)
485671dfc47SDavid du Colombier 		V2D(&r->d, r->fid->qid, a->path +1);
486671dfc47SDavid du Colombier 	else{
487671dfc47SDavid du Colombier 		memset(&fi, 0, sizeof fi);
488671dfc47SDavid du Colombier 		if(Sess->caps & CAP_NT_SMBS)
489671dfc47SDavid du Colombier 			rc = T2queryall(Sess, a->sp, mapfile(a->path), &fi);
490671dfc47SDavid du Colombier 		else
491671dfc47SDavid du Colombier 			rc = T2querystandard(Sess, a->sp, mapfile(a->path), &fi);
492671dfc47SDavid du Colombier 		if(rc == -1){
493671dfc47SDavid du Colombier 			responderrstr(r);
494671dfc47SDavid du Colombier 			return;
495671dfc47SDavid du Colombier 		}
496671dfc47SDavid du Colombier 		I2D(&r->d, a->sp, a->path, &fi);
497671dfc47SDavid du Colombier 		if(Billtrog == 0)
498671dfc47SDavid du Colombier 			upd_names(Sess, a->sp, mapfile(a->path), &r->d);
499671dfc47SDavid du Colombier 	}
500671dfc47SDavid du Colombier 	respond(r, nil);
501671dfc47SDavid du Colombier }
502671dfc47SDavid du Colombier 
503671dfc47SDavid du Colombier static int
smbcreateopen(Aux * a,char * path,int mode,int perm,int is_create,int is_dir,FInfo * fip)504671dfc47SDavid du Colombier smbcreateopen(Aux *a, char *path, int mode, int perm, int is_create,
505671dfc47SDavid du Colombier 	int is_dir, FInfo *fip)
506671dfc47SDavid du Colombier {
507671dfc47SDavid du Colombier 	int rc, action, attrs, access, result;
508671dfc47SDavid du Colombier 
509671dfc47SDavid du Colombier 	if(is_create && is_dir){
510671dfc47SDavid du Colombier 		if(CIFScreatedirectory(Sess, a->sp, path) == -1)
511671dfc47SDavid du Colombier 			return -1;
512671dfc47SDavid du Colombier 		return 0;
513671dfc47SDavid du Colombier 	}
514671dfc47SDavid du Colombier 
515671dfc47SDavid du Colombier 	if(mode & DMAPPEND) {
516671dfc47SDavid du Colombier 		werrstr("filesystem does not support DMAPPEND");
517671dfc47SDavid du Colombier 		return -1;
518671dfc47SDavid du Colombier 	}
519671dfc47SDavid du Colombier 
520671dfc47SDavid du Colombier 	if(is_create)
521671dfc47SDavid du Colombier 		action = 0x12;
522671dfc47SDavid du Colombier 	else if(mode & OTRUNC)
523671dfc47SDavid du Colombier 		action = 0x02;
524671dfc47SDavid du Colombier 	else
525671dfc47SDavid du Colombier 		action = 0x01;
526671dfc47SDavid du Colombier 
527671dfc47SDavid du Colombier 	if(perm & 0222)
528671dfc47SDavid du Colombier 		attrs = ATTR_NORMAL;
529671dfc47SDavid du Colombier 	else
530671dfc47SDavid du Colombier 		attrs = ATTR_NORMAL|ATTR_READONLY;
531671dfc47SDavid du Colombier 
532671dfc47SDavid du Colombier 	switch (mode & OMASK){
533671dfc47SDavid du Colombier 	case OREAD:
534671dfc47SDavid du Colombier 		access = 0;
535671dfc47SDavid du Colombier 		break;
536671dfc47SDavid du Colombier 	case OWRITE:
537671dfc47SDavid du Colombier 		access = 1;
538671dfc47SDavid du Colombier 		break;
539671dfc47SDavid du Colombier 	case ORDWR:
540671dfc47SDavid du Colombier 		access = 2;
541671dfc47SDavid du Colombier 		break;
542671dfc47SDavid du Colombier 	case OEXEC:
543671dfc47SDavid du Colombier 		access = 3;
544671dfc47SDavid du Colombier 		break;
545671dfc47SDavid du Colombier 	default:
546671dfc47SDavid du Colombier 		werrstr("%d bad open mode", mode & OMASK);
547671dfc47SDavid du Colombier 		return -1;
548671dfc47SDavid du Colombier 		break;
549671dfc47SDavid du Colombier 	}
550671dfc47SDavid du Colombier 
551671dfc47SDavid du Colombier 	if(mode & DMEXCL == 0)
552671dfc47SDavid du Colombier 		access |= 0x10;
553671dfc47SDavid du Colombier 	else
554671dfc47SDavid du Colombier 		access |= 0x40;
555671dfc47SDavid du Colombier 
556671dfc47SDavid du Colombier 	if((a->fh = CIFS_SMB_opencreate(Sess, a->sp, path, access, attrs,
557671dfc47SDavid du Colombier 	    action, &result)) == -1)
558671dfc47SDavid du Colombier 		return -1;
559671dfc47SDavid du Colombier 
560671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
561671dfc47SDavid du Colombier 		rc = T2queryall(Sess, a->sp, mapfile(a->path), fip);
562671dfc47SDavid du Colombier 	else
563671dfc47SDavid du Colombier 		rc = T2querystandard(Sess, a->sp, mapfile(a->path), fip);
564671dfc47SDavid du Colombier 	if(rc == -1){
565671dfc47SDavid du Colombier 		fprint(2, "internal error: stat of newly open/created file failed\n");
566671dfc47SDavid du Colombier 		return -1;
567671dfc47SDavid du Colombier 	}
568671dfc47SDavid du Colombier 
569671dfc47SDavid du Colombier 	if((mode & OEXCL) && (result & 0x8000) == 0){
570671dfc47SDavid du Colombier 		werrstr("%d bad open mode", mode & OMASK);
571671dfc47SDavid du Colombier 		return -1;
572671dfc47SDavid du Colombier 	}
573671dfc47SDavid du Colombier 	return 0;
574671dfc47SDavid du Colombier }
575671dfc47SDavid du Colombier 
576671dfc47SDavid du Colombier /* Uncle Bill, you have a lot to answer for... */
577671dfc47SDavid du Colombier static int
ntcreateopen(Aux * a,char * path,int mode,int perm,int is_create,int is_dir,FInfo * fip)578671dfc47SDavid du Colombier ntcreateopen(Aux *a, char *path, int mode, int perm, int is_create,
579671dfc47SDavid du Colombier 	int is_dir, FInfo *fip)
580671dfc47SDavid du Colombier {
581671dfc47SDavid du Colombier 	int options, result, attrs, flags, access, action, share;
582671dfc47SDavid du Colombier 
583671dfc47SDavid du Colombier 	if(mode & DMAPPEND){
584671dfc47SDavid du Colombier 		werrstr("CIFSopen, DMAPPEND not supported");
585671dfc47SDavid du Colombier 		return -1;
586671dfc47SDavid du Colombier 	}
587671dfc47SDavid du Colombier 
588671dfc47SDavid du Colombier 	if(is_create){
589671dfc47SDavid du Colombier 		if(mode & OEXCL)
590671dfc47SDavid du Colombier 			action = FILE_OPEN;
591671dfc47SDavid du Colombier 		else if(mode & OTRUNC)
592671dfc47SDavid du Colombier 			action = FILE_CREATE;
593671dfc47SDavid du Colombier 		else
594671dfc47SDavid du Colombier 			action = FILE_OVERWRITE_IF;
595671dfc47SDavid du Colombier 	} else {
596671dfc47SDavid du Colombier 		if(mode & OTRUNC)
597671dfc47SDavid du Colombier 			action = FILE_OVERWRITE_IF;
598671dfc47SDavid du Colombier 		else
599671dfc47SDavid du Colombier 			action = FILE_OPEN_IF;
600671dfc47SDavid du Colombier 	}
601671dfc47SDavid du Colombier 
602671dfc47SDavid du Colombier 	flags = 0;		/* FIXME: really not sure */
603671dfc47SDavid du Colombier 
604671dfc47SDavid du Colombier 	if(mode & OEXCL)
605671dfc47SDavid du Colombier 		share = FILE_NO_SHARE;
606671dfc47SDavid du Colombier 	else
607671dfc47SDavid du Colombier 		share = FILE_SHARE_ALL;
608671dfc47SDavid du Colombier 
609671dfc47SDavid du Colombier 	switch (mode & OMASK){
610671dfc47SDavid du Colombier 	case OREAD:
611671dfc47SDavid du Colombier 		access = GENERIC_READ;
612671dfc47SDavid du Colombier 		break;
613671dfc47SDavid du Colombier 	case OWRITE:
614671dfc47SDavid du Colombier 		access = GENERIC_WRITE;
615671dfc47SDavid du Colombier 		break;
616671dfc47SDavid du Colombier 	case ORDWR:
617671dfc47SDavid du Colombier 		access = GENERIC_ALL;
618671dfc47SDavid du Colombier 		break;
619671dfc47SDavid du Colombier 	case OEXEC:
620671dfc47SDavid du Colombier 		access = GENERIC_EXECUTE;
621671dfc47SDavid du Colombier 		break;
622671dfc47SDavid du Colombier 	default:
623671dfc47SDavid du Colombier 		werrstr("%d bad open mode", mode & OMASK);
624671dfc47SDavid du Colombier 		return -1;
625671dfc47SDavid du Colombier 		break;
626671dfc47SDavid du Colombier 	}
627671dfc47SDavid du Colombier 
628671dfc47SDavid du Colombier 	if(is_dir){
629671dfc47SDavid du Colombier 		action = FILE_CREATE;
630671dfc47SDavid du Colombier 		options = FILE_DIRECTORY_FILE;
631671dfc47SDavid du Colombier 		if(perm & 0222)
632671dfc47SDavid du Colombier 			attrs = ATTR_DIRECTORY;
633671dfc47SDavid du Colombier 		else
634671dfc47SDavid du Colombier 			attrs = ATTR_DIRECTORY|ATTR_READONLY;
635671dfc47SDavid du Colombier 	} else {
636671dfc47SDavid du Colombier 		options = FILE_NON_DIRECTORY_FILE;
637671dfc47SDavid du Colombier 		if(perm & 0222)
638671dfc47SDavid du Colombier 			attrs = ATTR_NORMAL;
639671dfc47SDavid du Colombier 		else
640671dfc47SDavid du Colombier 			attrs = ATTR_NORMAL|ATTR_READONLY;
641671dfc47SDavid du Colombier 	}
642671dfc47SDavid du Colombier 
643671dfc47SDavid du Colombier 	if(mode & ORCLOSE){
644671dfc47SDavid du Colombier 		options |= FILE_DELETE_ON_CLOSE;
645671dfc47SDavid du Colombier 		attrs |= ATTR_DELETE_ON_CLOSE;
646671dfc47SDavid du Colombier 	}
647671dfc47SDavid du Colombier 
648671dfc47SDavid du Colombier 	if((a->fh = CIFS_NT_opencreate(Sess, a->sp, path, flags, options,
649671dfc47SDavid du Colombier 	    attrs, access, share, action, &result, fip)) == -1)
650671dfc47SDavid du Colombier 		return -1;
651671dfc47SDavid du Colombier 
652671dfc47SDavid du Colombier 	if((mode & OEXCL) && (result & 0x8000) == 0){
653671dfc47SDavid du Colombier 		werrstr("%d bad open mode", mode & OMASK);
654671dfc47SDavid du Colombier 		return -1;
655671dfc47SDavid du Colombier 	}
656671dfc47SDavid du Colombier 
657671dfc47SDavid du Colombier 	return 0;
658671dfc47SDavid du Colombier }
659671dfc47SDavid du Colombier 
660671dfc47SDavid du Colombier static void
fscreate(Req * r)661671dfc47SDavid du Colombier fscreate(Req *r)
662671dfc47SDavid du Colombier {
663912e5f54SDavid du Colombier 	FInfo fi;
664671dfc47SDavid du Colombier 	int rc, is_dir;
665671dfc47SDavid du Colombier 	char *npath;
666671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
667671dfc47SDavid du Colombier 
668671dfc47SDavid du Colombier 	a->end = a->off = 0;
669671dfc47SDavid du Colombier 	a->cache = emalloc9p(max(Sess->mtu, MTU));
670671dfc47SDavid du Colombier 
671671dfc47SDavid du Colombier 	is_dir = (r->ifcall.perm & DMDIR) == DMDIR;
672671dfc47SDavid du Colombier 	npath = smprint("%s/%s", a->path, r->ifcall.name);
673671dfc47SDavid du Colombier 
674671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
675671dfc47SDavid du Colombier 		rc = ntcreateopen(a, mapfile(npath), r->ifcall.mode,
676671dfc47SDavid du Colombier 			r->ifcall.perm, 1, is_dir, &fi);
677671dfc47SDavid du Colombier 	else
678671dfc47SDavid du Colombier 		rc = smbcreateopen(a, mapfile(npath), r->ifcall.mode,
679671dfc47SDavid du Colombier 			r->ifcall.perm, 1, is_dir, &fi);
680671dfc47SDavid du Colombier 	if(rc == -1){
681671dfc47SDavid du Colombier 		free(npath);
682671dfc47SDavid du Colombier 		responderrstr(r);
683671dfc47SDavid du Colombier 		return;
684671dfc47SDavid du Colombier 	}
685671dfc47SDavid du Colombier 
686671dfc47SDavid du Colombier 	r->fid->qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0);
687671dfc47SDavid du Colombier 
688671dfc47SDavid du Colombier 	r->ofcall.qid = r->fid->qid;
689671dfc47SDavid du Colombier 	free(a->path);
690671dfc47SDavid du Colombier 	a->path = npath;
691671dfc47SDavid du Colombier 
692671dfc47SDavid du Colombier 	respond(r, nil);
693671dfc47SDavid du Colombier }
694671dfc47SDavid du Colombier 
695671dfc47SDavid du Colombier static void
fsopen(Req * r)696671dfc47SDavid du Colombier fsopen(Req *r)
697671dfc47SDavid du Colombier {
698671dfc47SDavid du Colombier 	int rc;
699671dfc47SDavid du Colombier 	FInfo fi;
700671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
701671dfc47SDavid du Colombier 
702671dfc47SDavid du Colombier 	a->end = a->off = 0;
703671dfc47SDavid du Colombier 	a->cache = emalloc9p(max(Sess->mtu, MTU));
704671dfc47SDavid du Colombier 
705671dfc47SDavid du Colombier 	if(ptype(r->fid->qid.path) == Pinfo){
706671dfc47SDavid du Colombier 		if(makeinfo(pindex(r->fid->qid.path)) != -1)
707671dfc47SDavid du Colombier 			respond(r, nil);
708671dfc47SDavid du Colombier 		else
709671dfc47SDavid du Colombier 			respond(r, "cannot generate info");
710671dfc47SDavid du Colombier 		return;
711671dfc47SDavid du Colombier 	}
712671dfc47SDavid du Colombier 
713671dfc47SDavid du Colombier 	if(r->fid->qid.type & QTDIR){
714671dfc47SDavid du Colombier 		respond(r, nil);
715671dfc47SDavid du Colombier 		return;
716671dfc47SDavid du Colombier 	}
717671dfc47SDavid du Colombier 
718671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
719671dfc47SDavid du Colombier 		rc = ntcreateopen(a, mapfile(a->path), r->ifcall.mode, 0777,
720671dfc47SDavid du Colombier 			0, 0, &fi);
721671dfc47SDavid du Colombier 	else
722671dfc47SDavid du Colombier 		rc = smbcreateopen(a, mapfile(a->path), r->ifcall.mode, 0777,
723671dfc47SDavid du Colombier 			0, 0, &fi);
724671dfc47SDavid du Colombier 	if(rc == -1){
725671dfc47SDavid du Colombier 		responderrstr(r);
726671dfc47SDavid du Colombier 		return;
727671dfc47SDavid du Colombier 	}
728671dfc47SDavid du Colombier 	respond(r, nil);
729671dfc47SDavid du Colombier }
730671dfc47SDavid du Colombier 
731671dfc47SDavid du Colombier static void
fswrite(Req * r)732671dfc47SDavid du Colombier fswrite(Req *r)
733671dfc47SDavid du Colombier {
734912e5f54SDavid du Colombier 	vlong n, m, got;
735671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
736912e5f54SDavid du Colombier 	vlong len = r->ifcall.count;
737912e5f54SDavid du Colombier 	vlong off = r->ifcall.offset;
738912e5f54SDavid du Colombier 	char *buf = r->ifcall.data;
739671dfc47SDavid du Colombier 
740671dfc47SDavid du Colombier 	got = 0;
741671dfc47SDavid du Colombier 	n = Sess->mtu -OVERHEAD;
742671dfc47SDavid du Colombier 	do{
743671dfc47SDavid du Colombier 		if(len - got < n)
744671dfc47SDavid du Colombier 			n = len - got;
745671dfc47SDavid du Colombier 		m = CIFSwrite(Sess, a->sp, a->fh, off + got, buf + got, n);
746671dfc47SDavid du Colombier 		if(m != -1)
747671dfc47SDavid du Colombier 			got += m;
748671dfc47SDavid du Colombier 	} while(got < len && m >= n);
749671dfc47SDavid du Colombier 
750671dfc47SDavid du Colombier 	r->ofcall.count = got;
751671dfc47SDavid du Colombier 	if(m == -1)
752671dfc47SDavid du Colombier 		responderrstr(r);
753671dfc47SDavid du Colombier 	else
754671dfc47SDavid du Colombier 		respond(r, nil);
755671dfc47SDavid du Colombier }
756671dfc47SDavid du Colombier 
757671dfc47SDavid du Colombier static void
fsread(Req * r)758671dfc47SDavid du Colombier fsread(Req *r)
759671dfc47SDavid du Colombier {
760912e5f54SDavid du Colombier 	vlong n, m, got;
761671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
762912e5f54SDavid du Colombier 	char *buf = r->ofcall.data;
763912e5f54SDavid du Colombier 	vlong len = r->ifcall.count;
764912e5f54SDavid du Colombier 	vlong off = r->ifcall.offset;
765671dfc47SDavid du Colombier 
766671dfc47SDavid du Colombier 	if(ptype(r->fid->qid.path) == Pinfo){
767671dfc47SDavid du Colombier 		r->ofcall.count = readinfo(pindex(r->fid->qid.path), buf, len,
768671dfc47SDavid du Colombier 			off);
769671dfc47SDavid du Colombier 		respond(r, nil);
770671dfc47SDavid du Colombier 		return;
771671dfc47SDavid du Colombier 	}
772671dfc47SDavid du Colombier 
773671dfc47SDavid du Colombier 	if(r->fid->qid.type & QTDIR){
774671dfc47SDavid du Colombier 		dirread9p(r, dirgen, a);
775671dfc47SDavid du Colombier 		respond(r, nil);
776671dfc47SDavid du Colombier 		return;
777671dfc47SDavid du Colombier 	}
778671dfc47SDavid du Colombier 
779671dfc47SDavid du Colombier 	got = 0;
780671dfc47SDavid du Colombier 	n = Sess->mtu -OVERHEAD;
781671dfc47SDavid du Colombier 	do{
782671dfc47SDavid du Colombier 		if(len - got < n)
783671dfc47SDavid du Colombier 			n = len - got;
784671dfc47SDavid du Colombier 		m = CIFSread(Sess, a->sp, a->fh, off + got, buf + got, n, len);
785671dfc47SDavid du Colombier 		if(m != -1)
786671dfc47SDavid du Colombier 			got += m;
787671dfc47SDavid du Colombier 	} while(got < len && m >= n);
788671dfc47SDavid du Colombier 
789671dfc47SDavid du Colombier 	r->ofcall.count = got;
790671dfc47SDavid du Colombier 	if(m == -1)
791671dfc47SDavid du Colombier 		responderrstr(r);
792671dfc47SDavid du Colombier 	else
793671dfc47SDavid du Colombier 		respond(r, nil);
794671dfc47SDavid du Colombier }
795671dfc47SDavid du Colombier 
796671dfc47SDavid du Colombier static void
fsdestroyfid(Fid * f)797671dfc47SDavid du Colombier fsdestroyfid(Fid *f)
798671dfc47SDavid du Colombier {
799671dfc47SDavid du Colombier 	Aux *a = f->aux;
800671dfc47SDavid du Colombier 
801671dfc47SDavid du Colombier 	if(ptype(f->qid.path) == Pinfo)
802671dfc47SDavid du Colombier 		freeinfo(pindex(f->qid.path));
803671dfc47SDavid du Colombier 	f->omode = -1;
804671dfc47SDavid du Colombier 	if(! a)
805671dfc47SDavid du Colombier 		return;
806671dfc47SDavid du Colombier 	if(a->fh != -1)
807671dfc47SDavid du Colombier 		if(CIFSclose(Sess, a->sp, a->fh) == -1)
808671dfc47SDavid du Colombier 			fprint(2, "%s: close failed fh=%d %r\n", argv0, a->fh);
809671dfc47SDavid du Colombier 	if(a->sh != -1)
810671dfc47SDavid du Colombier 		if(CIFSfindclose2(Sess, a->sp, a->sh) == -1)
811671dfc47SDavid du Colombier 			fprint(2, "%s: findclose failed sh=%d %r\n",
812671dfc47SDavid du Colombier 				argv0, a->sh);
813671dfc47SDavid du Colombier 	if(a->path)
814671dfc47SDavid du Colombier 		free(a->path);
815671dfc47SDavid du Colombier 	if(a->cache)
816671dfc47SDavid du Colombier 		free(a->cache);
817671dfc47SDavid du Colombier 
818671dfc47SDavid du Colombier 	if(a == Auxroot)
819671dfc47SDavid du Colombier 		Auxroot = a->next;
820671dfc47SDavid du Colombier 	a->prev->next = a->next;
821671dfc47SDavid du Colombier 	a->next->prev = a->prev;
822671dfc47SDavid du Colombier 	if(a->next == a->prev)
823671dfc47SDavid du Colombier 		Auxroot = nil;
824671dfc47SDavid du Colombier 	if(a)
825671dfc47SDavid du Colombier 		free(a);
826671dfc47SDavid du Colombier }
827671dfc47SDavid du Colombier 
828671dfc47SDavid du Colombier int
rdonly(Session * s,Share * sp,char * path,int rdonly)829671dfc47SDavid du Colombier rdonly(Session *s, Share *sp, char *path, int rdonly)
830671dfc47SDavid du Colombier {
831671dfc47SDavid du Colombier 	int rc;
832671dfc47SDavid du Colombier 	FInfo fi;
833671dfc47SDavid du Colombier 
834671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
835671dfc47SDavid du Colombier 		rc = T2queryall(s, sp, path, &fi);
836671dfc47SDavid du Colombier 	else
837671dfc47SDavid du Colombier 		rc = T2querystandard(s, sp, path, &fi);
838671dfc47SDavid du Colombier 	if(rc == -1)
839671dfc47SDavid du Colombier 		return -1;
840671dfc47SDavid du Colombier 
841671dfc47SDavid du Colombier 	if((rdonly && !(fi.attribs & ATTR_READONLY)) ||
842671dfc47SDavid du Colombier 	    (!rdonly && (fi.attribs & ATTR_READONLY))){
843671dfc47SDavid du Colombier 		fi.attribs &= ~ATTR_READONLY;
844671dfc47SDavid du Colombier 		fi.attribs |= rdonly? ATTR_READONLY: 0;
845671dfc47SDavid du Colombier 		rc = CIFSsetinfo(s, sp, path, &fi);
846671dfc47SDavid du Colombier 	}
847671dfc47SDavid du Colombier 	return rc;
848671dfc47SDavid du Colombier }
849671dfc47SDavid du Colombier 
850671dfc47SDavid du Colombier static void
fsremove(Req * r)851671dfc47SDavid du Colombier fsremove(Req *r)
852671dfc47SDavid du Colombier {
853671dfc47SDavid du Colombier 	int try, rc;
854671dfc47SDavid du Colombier 	char e[ERRMAX];
855671dfc47SDavid du Colombier 	Aux *ap, *a = r->fid->aux;
856671dfc47SDavid du Colombier 
857671dfc47SDavid du Colombier 	*e = 0;
858671dfc47SDavid du Colombier 	if(ptype(r->fid->qid.path) == Proot ||
859671dfc47SDavid du Colombier 	   ptype(r->fid->qid.path) == Pshare){
860671dfc47SDavid du Colombier 		respond(r, "illegal operation");
861671dfc47SDavid du Colombier 		return;
862671dfc47SDavid du Colombier 	}
863671dfc47SDavid du Colombier 
864671dfc47SDavid du Colombier 	/* close all instences of this file/dir */
865671dfc47SDavid du Colombier 	if((ap = Auxroot) != nil)
866671dfc47SDavid du Colombier 		do{
867671dfc47SDavid du Colombier 			if(strcmp(ap->path, a->path) == 0){
868671dfc47SDavid du Colombier 				if(ap->sh != -1)
869671dfc47SDavid du Colombier 					CIFSfindclose2(Sess, ap->sp, ap->sh);
870671dfc47SDavid du Colombier 				ap->sh = -1;
871671dfc47SDavid du Colombier 				if(ap->fh != -1)
872671dfc47SDavid du Colombier 					CIFSclose(Sess, ap->sp, ap->fh);
873671dfc47SDavid du Colombier 				ap->fh = -1;
874671dfc47SDavid du Colombier 			}
875671dfc47SDavid du Colombier 			ap = ap->next;
876671dfc47SDavid du Colombier 		}while(ap != Auxroot);
877671dfc47SDavid du Colombier 	try = 0;
878671dfc47SDavid du Colombier again:
879671dfc47SDavid du Colombier 	if(r->fid->qid.type & QTDIR)
880671dfc47SDavid du Colombier 		rc = CIFSdeletedirectory(Sess, a->sp, mapfile(a->path));
881671dfc47SDavid du Colombier 	else
882671dfc47SDavid du Colombier 		rc = CIFSdeletefile(Sess, a->sp, mapfile(a->path));
883671dfc47SDavid du Colombier 
884671dfc47SDavid du Colombier 	rerrstr(e, sizeof(e));
885671dfc47SDavid du Colombier 	if(rc == -1 && try++ == 0 && strcmp(e, "permission denied") == 0 &&
886671dfc47SDavid du Colombier 	    rdonly(Sess, a->sp, mapfile(a->path), 0) == 0)
887671dfc47SDavid du Colombier 		goto again;
888671dfc47SDavid du Colombier 	if(rc == -1)
889671dfc47SDavid du Colombier 		responderrstr(r);
890671dfc47SDavid du Colombier 	else
891671dfc47SDavid du Colombier 		respond(r, nil);
892671dfc47SDavid du Colombier }
893671dfc47SDavid du Colombier 
894671dfc47SDavid du Colombier static void
fswstat(Req * r)895671dfc47SDavid du Colombier fswstat(Req *r)
896671dfc47SDavid du Colombier {
897671dfc47SDavid du Colombier 	int fh, result, rc;
898912e5f54SDavid du Colombier 	FInfo fi, tmpfi;
899671dfc47SDavid du Colombier 	char *p, *from, *npath;
900671dfc47SDavid du Colombier 	Aux *a = r->fid->aux;
901671dfc47SDavid du Colombier 
902671dfc47SDavid du Colombier 	if(ptype(r->fid->qid.path) == Proot ||
903671dfc47SDavid du Colombier 	   ptype(r->fid->qid.path) == Pshare){
904671dfc47SDavid du Colombier 		respond(r, "illegal operation");
905671dfc47SDavid du Colombier 		return;
906671dfc47SDavid du Colombier 	}
907671dfc47SDavid du Colombier 
908671dfc47SDavid du Colombier 	if((r->d.uid && r->d.uid[0]) || (r->d.gid && r->d.gid[0])){
909671dfc47SDavid du Colombier 		respond(r, "cannot change ownership");
910671dfc47SDavid du Colombier 		return;
911671dfc47SDavid du Colombier 	}
912671dfc47SDavid du Colombier 
913671dfc47SDavid du Colombier 	/*
914671dfc47SDavid du Colombier 	 * get current info
915671dfc47SDavid du Colombier 	 */
916671dfc47SDavid du Colombier 	if(Sess->caps & CAP_NT_SMBS)
917671dfc47SDavid du Colombier 		rc = T2queryall(Sess, a->sp, mapfile(a->path), &fi);
918671dfc47SDavid du Colombier 	else
919671dfc47SDavid du Colombier 		rc = T2querystandard(Sess, a->sp, mapfile(a->path), &fi);
920671dfc47SDavid du Colombier 	if(rc == -1){
921671dfc47SDavid du Colombier 		werrstr("(query) - %r");
922671dfc47SDavid du Colombier 		responderrstr(r);
923671dfc47SDavid du Colombier 		return;
924671dfc47SDavid du Colombier 	}
925671dfc47SDavid du Colombier 
926671dfc47SDavid du Colombier 	/*
927671dfc47SDavid du Colombier 	 * always clear the readonly attribute if set,
928671dfc47SDavid du Colombier 	 * before trying to set any other fields.
929671dfc47SDavid du Colombier 	 * wstat() fails if the file/dir is readonly
930671dfc47SDavid du Colombier 	 * and this function is so full of races - who cares about one more?
931671dfc47SDavid du Colombier 	 */
932671dfc47SDavid du Colombier 	rdonly(Sess, a->sp, mapfile(a->path), 0);
933671dfc47SDavid du Colombier 
934671dfc47SDavid du Colombier 	/*
935671dfc47SDavid du Colombier 	 * rename - one piece of joy, renaming open files
936671dfc47SDavid du Colombier 	 * is legal (sharing permitting).
937671dfc47SDavid du Colombier 	 */
938671dfc47SDavid du Colombier 	if(r->d.name && r->d.name[0]){
939671dfc47SDavid du Colombier 		if((p = strrchr(a->path, '/')) == nil){
940671dfc47SDavid du Colombier 			respond(r, "illegal path");
941671dfc47SDavid du Colombier 			return;
942671dfc47SDavid du Colombier 		}
943671dfc47SDavid du Colombier 		npath = emalloc9p((p-a->path)+strlen(r->d.name)+2);
944671dfc47SDavid du Colombier 		strecpy(npath, npath+(p- a->path)+2, a->path);
945671dfc47SDavid du Colombier 		strcat(npath, r->d.name);
946671dfc47SDavid du Colombier 
947671dfc47SDavid du Colombier 		from = estrdup9p(mapfile(a->path));
948671dfc47SDavid du Colombier 		if(CIFSrename(Sess, a->sp, from, mapfile(npath)) == -1){
949671dfc47SDavid du Colombier 			werrstr("(rename) - %r");
950671dfc47SDavid du Colombier 			responderrstr(r);
951671dfc47SDavid du Colombier 			free(npath);
952671dfc47SDavid du Colombier 			free(from);
953671dfc47SDavid du Colombier 			return;
954671dfc47SDavid du Colombier 		}
955671dfc47SDavid du Colombier 		free(from);
956671dfc47SDavid du Colombier 		free(a->path);
957671dfc47SDavid du Colombier 		a->path = npath;
958671dfc47SDavid du Colombier 	}
959671dfc47SDavid du Colombier 
960671dfc47SDavid du Colombier 	/*
961671dfc47SDavid du Colombier 	 * set the files length, do this before setting
962671dfc47SDavid du Colombier 	 * the file times as open() will alter them
963671dfc47SDavid du Colombier 	 */
964671dfc47SDavid du Colombier 	if(~r->d.length){
965671dfc47SDavid du Colombier 		fi.size = r->d.length;
966671dfc47SDavid du Colombier 
967671dfc47SDavid du Colombier 		if(Sess->caps & CAP_NT_SMBS){
968671dfc47SDavid du Colombier 			if((fh = CIFS_NT_opencreate(Sess, a->sp, mapfile(a->path),
969671dfc47SDavid du Colombier 			    0, FILE_NON_DIRECTORY_FILE,
970671dfc47SDavid du Colombier 	    		    ATTR_NORMAL, GENERIC_WRITE, FILE_SHARE_ALL,
971671dfc47SDavid du Colombier 			    FILE_OPEN_IF, &result, &tmpfi)) == -1){
972671dfc47SDavid du Colombier 				werrstr("(set length, open) - %r");
973671dfc47SDavid du Colombier 				responderrstr(r);
974671dfc47SDavid du Colombier 				return;
975671dfc47SDavid du Colombier 			}
976671dfc47SDavid du Colombier 			rc = T2setfilelength(Sess, a->sp, fh, &fi);
977671dfc47SDavid du Colombier 			CIFSclose(Sess, a->sp, fh);
978671dfc47SDavid du Colombier 			if(rc == -1){
979671dfc47SDavid du Colombier 				werrstr("(set length), set) - %r");
980671dfc47SDavid du Colombier 				responderrstr(r);
981671dfc47SDavid du Colombier 				return;
982671dfc47SDavid du Colombier 			}
983671dfc47SDavid du Colombier 		} else {
984671dfc47SDavid du Colombier 			if((fh = CIFS_SMB_opencreate(Sess, a->sp, mapfile(a->path),
985671dfc47SDavid du Colombier 			    1, ATTR_NORMAL, 1, &result)) == -1){
986671dfc47SDavid du Colombier 				werrstr("(set length, open) failed - %r");
987671dfc47SDavid du Colombier 				responderrstr(r);
988671dfc47SDavid du Colombier 				return;
989671dfc47SDavid du Colombier 			}
990671dfc47SDavid du Colombier 			rc = CIFSwrite(Sess, a->sp, fh, fi.size, 0, 0);
991671dfc47SDavid du Colombier 			CIFSclose(Sess, a->sp, fh);
992671dfc47SDavid du Colombier 			if(rc == -1){
993671dfc47SDavid du Colombier 				werrstr("(set length, write) - %r");
994671dfc47SDavid du Colombier 				responderrstr(r);
995671dfc47SDavid du Colombier 				return;
996671dfc47SDavid du Colombier 			}
997671dfc47SDavid du Colombier 		}
998671dfc47SDavid du Colombier 	}
999671dfc47SDavid du Colombier 
1000671dfc47SDavid du Colombier 	/*
1001671dfc47SDavid du Colombier 	 * This doesn't appear to set length or
1002671dfc47SDavid du Colombier 	 * attributes, no idea why, so I do those seperately
1003671dfc47SDavid du Colombier 	 */
1004671dfc47SDavid du Colombier 	if(~r->d.mtime || ~r->d.atime){
1005671dfc47SDavid du Colombier 		if(~r->d.mtime)
1006671dfc47SDavid du Colombier 			fi.written = r->d.mtime;
1007671dfc47SDavid du Colombier 		if(~r->d.atime)
1008671dfc47SDavid du Colombier 			fi.accessed = r->d.atime;
1009671dfc47SDavid du Colombier 		if(T2setpathinfo(Sess, a->sp, mapfile(a->path), &fi) == -1){
1010671dfc47SDavid du Colombier 			werrstr("(set path info) - %r");
1011671dfc47SDavid du Colombier 			responderrstr(r);
1012671dfc47SDavid du Colombier 			return;
1013671dfc47SDavid du Colombier 		}
1014671dfc47SDavid du Colombier 	}
1015671dfc47SDavid du Colombier 
1016671dfc47SDavid du Colombier 	/*
1017671dfc47SDavid du Colombier 	 * always update the readonly flag as
1018671dfc47SDavid du Colombier 	 * we may have cleared it above.
1019671dfc47SDavid du Colombier 	 */
1020912e5f54SDavid du Colombier 	if(~r->d.mode){
1021671dfc47SDavid du Colombier 		if(r->d.mode & 0222)
1022671dfc47SDavid du Colombier 			fi.attribs &= ~ATTR_READONLY;
1023671dfc47SDavid du Colombier 		else
1024671dfc47SDavid du Colombier 			fi.attribs |= ATTR_READONLY;
1025912e5f54SDavid du Colombier 	}
1026671dfc47SDavid du Colombier 	if(rdonly(Sess, a->sp, mapfile(a->path), fi.attribs & ATTR_READONLY) == -1){
1027671dfc47SDavid du Colombier 		werrstr("(set info) - %r");
1028671dfc47SDavid du Colombier 		responderrstr(r);
1029671dfc47SDavid du Colombier 		return;
1030671dfc47SDavid du Colombier 	}
1031671dfc47SDavid du Colombier 
1032671dfc47SDavid du Colombier 	/*
1033671dfc47SDavid du Colombier 	 * Win95 has a broken write-behind cache for metadata
1034671dfc47SDavid du Colombier 	 * on open files (writes go to the cache, reads bypass
1035671dfc47SDavid du Colombier 	 * the cache), so we must flush the file.
1036671dfc47SDavid du Colombier 	 */
1037671dfc47SDavid du Colombier 	if(r->fid->omode != -1 && CIFSflush(Sess, a->sp, a->fh) == -1){
1038671dfc47SDavid du Colombier 		werrstr("(flush) %r");
1039671dfc47SDavid du Colombier 		responderrstr(r);
1040671dfc47SDavid du Colombier 		return;
1041671dfc47SDavid du Colombier 	}
1042671dfc47SDavid du Colombier 	respond(r, nil);
1043671dfc47SDavid du Colombier }
1044671dfc47SDavid du Colombier 
1045671dfc47SDavid du Colombier static void
fsend(Srv * srv)1046671dfc47SDavid du Colombier fsend(Srv *srv)
1047671dfc47SDavid du Colombier {
1048671dfc47SDavid du Colombier 	int i;
1049671dfc47SDavid du Colombier 	USED(srv);
1050671dfc47SDavid du Colombier 
1051671dfc47SDavid du Colombier 	for(i = 0; i < Nshares; i++)
1052671dfc47SDavid du Colombier 		CIFStreedisconnect(Sess, Shares+i);
1053671dfc47SDavid du Colombier 	CIFSlogoff(Sess);
1054671dfc47SDavid du Colombier 	postnote(PNPROC, Keeppid, "die");
1055671dfc47SDavid du Colombier }
1056671dfc47SDavid du Colombier 
1057671dfc47SDavid du Colombier Srv fs = {
1058671dfc47SDavid du Colombier 	.destroyfid =	fsdestroyfid,
1059671dfc47SDavid du Colombier 	.attach=	fsattach,
1060671dfc47SDavid du Colombier 	.open=		fsopen,
1061671dfc47SDavid du Colombier 	.create=	fscreate,
1062671dfc47SDavid du Colombier 	.read=		fsread,
1063671dfc47SDavid du Colombier 	.write=		fswrite,
1064671dfc47SDavid du Colombier 	.remove=	fsremove,
1065671dfc47SDavid du Colombier 	.stat=		fsstat,
1066671dfc47SDavid du Colombier 	.wstat=		fswstat,
1067671dfc47SDavid du Colombier 	.clone= 	fsclone,
1068671dfc47SDavid du Colombier 	.walk1= 	fswalk1,
1069671dfc47SDavid du Colombier 	.end=		fsend,
1070671dfc47SDavid du Colombier };
1071671dfc47SDavid du Colombier 
1072671dfc47SDavid du Colombier void
usage(void)1073671dfc47SDavid du Colombier usage(void)
1074671dfc47SDavid du Colombier {
1075671dfc47SDavid du Colombier 	fprint(2, "usage: %s [-d name] [-Dvb] [-a auth-method] [-s srvname] "
1076671dfc47SDavid du Colombier 		"[-n called-name] [-k factotum-params] [-m mntpnt] "
1077671dfc47SDavid du Colombier 		"host [share...]\n", argv0);
1078671dfc47SDavid du Colombier 	exits("usage");
1079671dfc47SDavid du Colombier }
1080671dfc47SDavid du Colombier 
1081671dfc47SDavid du Colombier /*
1082671dfc47SDavid du Colombier  * SMBecho looks like the function to use for keepalives,
1083671dfc47SDavid du Colombier  * sadly the echo packet does not seem to reload the
1084671dfc47SDavid du Colombier  * idle timer in Microsoft's servers.  Instead we use
1085671dfc47SDavid du Colombier  * "get file system size" on each share until we get one that succeeds.
1086671dfc47SDavid du Colombier  */
1087671dfc47SDavid du Colombier static void
keepalive(void)1088671dfc47SDavid du Colombier keepalive(void)
1089671dfc47SDavid du Colombier {
1090671dfc47SDavid du Colombier 	char buf[32];
1091912e5f54SDavid du Colombier 	uvlong tot, fre;
1092912e5f54SDavid du Colombier 	int fd, i, slot, rc;
1093671dfc47SDavid du Colombier 
1094671dfc47SDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
1095671dfc47SDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
1096671dfc47SDavid du Colombier 		fprint(fd, "%s keepalive", Host);
1097671dfc47SDavid du Colombier 		close(fd);
1098671dfc47SDavid du Colombier 	}
1099671dfc47SDavid du Colombier 
1100912e5f54SDavid du Colombier 	rc = 0;
1101912e5f54SDavid du Colombier 	slot = 0;
1102671dfc47SDavid du Colombier 	do{
1103671dfc47SDavid du Colombier 		sleep(6000);
1104671dfc47SDavid du Colombier 		if(Active-- != 0)
1105671dfc47SDavid du Colombier 			continue;
1106912e5f54SDavid du Colombier 		for(i = 0; i < Nshares; i++){
1107912e5f54SDavid du Colombier 			if((rc = T2fssizeinfo(Sess, &Shares[slot], &tot, &fre)) == 0)
1108671dfc47SDavid du Colombier 				break;
1109912e5f54SDavid du Colombier 			if(++slot >= Nshares)
1110912e5f54SDavid du Colombier 				slot = 0;
1111912e5f54SDavid du Colombier 		}
1112671dfc47SDavid du Colombier 	}while(rc != -1);
1113671dfc47SDavid du Colombier 	postnote(PNPROC, Attachpid, "die");
1114671dfc47SDavid du Colombier }
1115671dfc47SDavid du Colombier 
1116671dfc47SDavid du Colombier 
1117671dfc47SDavid du Colombier static void
ding(void * u,char * msg)1118671dfc47SDavid du Colombier ding(void *u, char *msg)
1119671dfc47SDavid du Colombier {
1120671dfc47SDavid du Colombier 	USED(u);
1121671dfc47SDavid du Colombier 	if(strstr(msg, "alarm") != nil)
1122671dfc47SDavid du Colombier 		noted(NCONT);
1123671dfc47SDavid du Colombier 	noted(NDFLT);
1124671dfc47SDavid du Colombier }
1125671dfc47SDavid du Colombier 
1126671dfc47SDavid du Colombier void
dmpkey(char * s,void * v,int n)1127671dfc47SDavid du Colombier dmpkey(char *s, void *v, int n)
1128671dfc47SDavid du Colombier {
1129671dfc47SDavid du Colombier 	int i;
1130912e5f54SDavid du Colombier 	unsigned char *p = (unsigned char *)v;
1131671dfc47SDavid du Colombier 
1132671dfc47SDavid du Colombier 	print("%s", s);
1133671dfc47SDavid du Colombier 	for(i = 0; i < n; i++)
1134671dfc47SDavid du Colombier 		print("%02ux ", *p++);
1135671dfc47SDavid du Colombier 	print("\n");
1136671dfc47SDavid du Colombier }
1137671dfc47SDavid du Colombier 
1138671dfc47SDavid du Colombier void
main(int argc,char ** argv)1139671dfc47SDavid du Colombier main(int argc, char **argv)
1140671dfc47SDavid du Colombier {
1141671dfc47SDavid du Colombier 	int i, n;
1142671dfc47SDavid du Colombier 	long svrtime;
1143671dfc47SDavid du Colombier 	char windom[64], cname[64];
1144671dfc47SDavid du Colombier 	char *method, *sysname, *keyp, *mtpt, *svs;
1145671dfc47SDavid du Colombier 	static char *sh[1024];
1146671dfc47SDavid du Colombier 
1147671dfc47SDavid du Colombier 	*cname = 0;
1148671dfc47SDavid du Colombier 	keyp = "";
1149671dfc47SDavid du Colombier 	method = nil;
1150671dfc47SDavid du Colombier 	strcpy(windom, "unknown");
1151671dfc47SDavid du Colombier 	mtpt = svs = nil;
1152671dfc47SDavid du Colombier 
1153671dfc47SDavid du Colombier 	notify(ding);
1154671dfc47SDavid du Colombier 
1155671dfc47SDavid du Colombier 	ARGBEGIN{
1156671dfc47SDavid du Colombier 	case 'a':
1157671dfc47SDavid du Colombier 		method = EARGF(autherr());
1158671dfc47SDavid du Colombier 		break;
1159671dfc47SDavid du Colombier 	case 'b':
1160671dfc47SDavid du Colombier 		Billtrog ^= 1;
1161671dfc47SDavid du Colombier 		break;
1162671dfc47SDavid du Colombier 	case 'D':
1163671dfc47SDavid du Colombier 		chatty9p++;
1164671dfc47SDavid du Colombier 		break;
1165671dfc47SDavid du Colombier 	case 'd':
1166671dfc47SDavid du Colombier 		Debug = EARGF(usage());
1167671dfc47SDavid du Colombier 		break;
1168912e5f54SDavid du Colombier 	case 'i':
1169912e5f54SDavid du Colombier 		Checkcase = 0;
1170912e5f54SDavid du Colombier 		break;
1171671dfc47SDavid du Colombier 	case 'k':
1172671dfc47SDavid du Colombier 		keyp = EARGF(usage());
1173671dfc47SDavid du Colombier 		break;
1174671dfc47SDavid du Colombier 	case 'm':
1175671dfc47SDavid du Colombier 		mtpt = EARGF(usage());
1176671dfc47SDavid du Colombier 		break;
1177671dfc47SDavid du Colombier 	case 'n':
1178671dfc47SDavid du Colombier 		strncpy(cname, EARGF(usage()), sizeof(cname));
1179671dfc47SDavid du Colombier 		cname[sizeof(cname) - 1] = 0;
1180671dfc47SDavid du Colombier 		break;
1181671dfc47SDavid du Colombier 	case 's':
1182671dfc47SDavid du Colombier 		svs = EARGF(usage());
1183671dfc47SDavid du Colombier 		break;
1184671dfc47SDavid du Colombier 	case 't':
1185671dfc47SDavid du Colombier 		Dfstout = atoi(EARGF(usage()));
1186671dfc47SDavid du Colombier 		break;
1187671dfc47SDavid du Colombier 	default:
1188671dfc47SDavid du Colombier 		usage();
1189671dfc47SDavid du Colombier 		break;
1190671dfc47SDavid du Colombier 	}ARGEND
1191671dfc47SDavid du Colombier 
1192671dfc47SDavid du Colombier 	if(argc < 1)
1193671dfc47SDavid du Colombier 		usage();
1194671dfc47SDavid du Colombier 
1195671dfc47SDavid du Colombier 	Host = argv[0];
1196671dfc47SDavid du Colombier 
1197671dfc47SDavid du Colombier 	if(mtpt == nil && svs == nil)
1198671dfc47SDavid du Colombier 		mtpt = smprint("/n/%s", Host);
1199671dfc47SDavid du Colombier 
1200671dfc47SDavid du Colombier 	if((sysname = getenv("sysname")) == nil)
1201671dfc47SDavid du Colombier 		sysname = "unknown";
1202671dfc47SDavid du Colombier 
1203671dfc47SDavid du Colombier 	if(*cname && (Sess = cifsdial(Host, cname, sysname)) != nil)
1204671dfc47SDavid du Colombier 		goto connected;
1205671dfc47SDavid du Colombier 
1206671dfc47SDavid du Colombier 	if(calledname(Host, cname) == 0 &&
1207671dfc47SDavid du Colombier 	    (Sess = cifsdial(Host, cname, sysname)) != nil)
1208671dfc47SDavid du Colombier 		goto connected;
1209671dfc47SDavid du Colombier 
1210671dfc47SDavid du Colombier 	strcpy(cname, Host);
1211671dfc47SDavid du Colombier 	if((Sess = cifsdial(Host, Host, sysname)) != nil ||
1212671dfc47SDavid du Colombier 	   (Sess = cifsdial(Host, "*SMBSERVER", sysname)) != nil)
1213671dfc47SDavid du Colombier 		goto connected;
1214912e5f54SDavid du Colombier 
1215671dfc47SDavid du Colombier 	sysfatal("%s - cannot dial, %r\n", Host);
1216671dfc47SDavid du Colombier connected:
1217671dfc47SDavid du Colombier 	if(CIFSnegotiate(Sess, &svrtime, windom, sizeof windom, cname, sizeof cname) == -1)
1218671dfc47SDavid du Colombier 		sysfatal("%s - cannot negioate common protocol, %r\n", Host);
1219671dfc47SDavid du Colombier 
1220671dfc47SDavid du Colombier #ifndef DEBUG_MAC
1221671dfc47SDavid du Colombier 	Sess->secmode &= ~SECMODE_SIGN_ENABLED;
1222671dfc47SDavid du Colombier #endif
1223671dfc47SDavid du Colombier 
1224671dfc47SDavid du Colombier 	Sess->auth = getauth(method, windom, keyp, Sess->secmode, Sess->chal,
1225671dfc47SDavid du Colombier 		Sess->challen);
1226671dfc47SDavid du Colombier 
1227671dfc47SDavid du Colombier 	if(CIFSsession(Sess) < 0)
1228671dfc47SDavid du Colombier 		sysfatal("session authentication failed, %r\n");
1229671dfc47SDavid du Colombier 
1230671dfc47SDavid du Colombier 	Sess->slip = svrtime - time(nil);
1231912e5f54SDavid du Colombier 	Sess->cname = estrdup9p(cname);
1232671dfc47SDavid du Colombier 
1233912e5f54SDavid du Colombier 	if(CIFStreeconnect(Sess, cname, Ipcname, &Ipc) == -1)
1234912e5f54SDavid du Colombier 		fprint(2, "%s, %r - can't connect\n", Ipcname);
1235671dfc47SDavid du Colombier 
1236671dfc47SDavid du Colombier 	Nshares = 0;
1237671dfc47SDavid du Colombier 	if(argc == 1){
1238671dfc47SDavid du Colombier 		Share *sip;
1239671dfc47SDavid du Colombier 
1240671dfc47SDavid du Colombier 		if((n = RAPshareenum(Sess, &Ipc, &sip)) < 1)
1241671dfc47SDavid du Colombier 			sysfatal("can't enumerate shares: %r - specify share "
1242671dfc47SDavid du Colombier 				"names on command line\n");
1243671dfc47SDavid du Colombier 
1244671dfc47SDavid du Colombier 		for(i = 0; i < n; i++){
1245671dfc47SDavid du Colombier #ifdef NO_HIDDEN_SHARES
1246671dfc47SDavid du Colombier 			int l = strlen(sip[i].name);
1247671dfc47SDavid du Colombier 
1248671dfc47SDavid du Colombier 			if(l > 1 && sip[i].name[l-1] == '$'){
1249671dfc47SDavid du Colombier 				free(sip[i].name);
1250671dfc47SDavid du Colombier 				continue;
1251671dfc47SDavid du Colombier 			}
1252671dfc47SDavid du Colombier #endif
1253671dfc47SDavid du Colombier 			memcpy(Shares+Nshares, sip+i, sizeof(Share));
1254671dfc47SDavid du Colombier 			if(CIFStreeconnect(Sess, Sess->cname,
1255671dfc47SDavid du Colombier 			    Shares[Nshares].name, Shares+Nshares) == -1){
1256671dfc47SDavid du Colombier 				free(Shares[Nshares].name);
1257671dfc47SDavid du Colombier 				continue;
1258671dfc47SDavid du Colombier 			}
1259671dfc47SDavid du Colombier 			Nshares++;
1260671dfc47SDavid du Colombier 		}
1261671dfc47SDavid du Colombier 		free(sip);
1262671dfc47SDavid du Colombier 	} else
1263671dfc47SDavid du Colombier 		for(i = 1; i < argc; i++){
1264671dfc47SDavid du Colombier 			if(CIFStreeconnect(Sess, Sess->cname, argv[i],
1265671dfc47SDavid du Colombier 			    Shares+Nshares) == -1){
1266671dfc47SDavid du Colombier 				fprint(2, "%s: %s  %q - can't connect to share"
1267671dfc47SDavid du Colombier 					", %r\n", argv0, Host, argv[i]);
1268671dfc47SDavid du Colombier 				continue;
1269671dfc47SDavid du Colombier 			}
1270671dfc47SDavid du Colombier 			Shares[Nshares].name = strlwr(estrdup9p(argv[i]));
1271671dfc47SDavid du Colombier 			Nshares++;
1272671dfc47SDavid du Colombier 		}
1273671dfc47SDavid du Colombier 
1274671dfc47SDavid du Colombier 	if(Nshares == 0)
1275671dfc47SDavid du Colombier 		fprint(2, "no available shares\n");
1276671dfc47SDavid du Colombier 
1277671dfc47SDavid du Colombier 	if((Keeppid = rfork(RFPROC|RFMEM|RFNOTEG|RFFDG|RFNAMEG)) == 0){
1278671dfc47SDavid du Colombier 		keepalive();
1279671dfc47SDavid du Colombier 		exits(nil);
1280671dfc47SDavid du Colombier 	}
1281671dfc47SDavid du Colombier 	postmountsrv(&fs, svs, mtpt, MREPL|MCREATE);
1282671dfc47SDavid du Colombier 	exits(nil);
1283671dfc47SDavid du Colombier }
1284