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