]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/fs/smbfs/smbfs_smb.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / fs / smbfs / smbfs_smb.c
1 /*-
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
32 #include <sys/proc.h>
33 #include <sys/lock.h>
34 #include <sys/vnode.h>
35 #include <sys/mbuf.h>
36 #include <sys/mount.h>
37 #include <sys/endian.h>
38
39 #ifdef USE_MD5_HASH
40 #include <sys/md5.h>
41 #endif
42
43 #include <netsmb/smb.h>
44 #include <netsmb/smb_subr.h>
45 #include <netsmb/smb_rq.h>
46 #include <netsmb/smb_conn.h>
47
48 #include <fs/smbfs/smbfs.h>
49 #include <fs/smbfs/smbfs_node.h>
50 #include <fs/smbfs/smbfs_subr.h>
51
52 /*
53  * Lack of inode numbers leads us to the problem of generating them.
54  * Partially this problem can be solved by having a dir/file cache
55  * with inode numbers generated from the incremented by one counter.
56  * However this way will require too much kernel memory, gives all
57  * sorts of locking and consistency problems, not to mentinon counter overflows.
58  * So, I'm decided to use a hash function to generate pseudo random (and unique)
59  * inode numbers.
60  */
61 static long
62 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
63 {
64 #ifdef USE_MD5_HASH
65         MD5_CTX md5;
66         u_int32_t state[4];
67         long ino;
68         int i;
69
70         MD5Init(&md5);
71         MD5Update(&md5, name, nmlen);
72         MD5Final((u_char *)state, &md5);
73         for (i = 0, ino = 0; i < 4; i++)
74                 ino += state[i];
75         return dnp->n_ino + ino;
76 #endif
77         u_int32_t ino;
78
79         ino = dnp->n_ino + smbfs_hash(name, nmlen);
80         if (ino <= 2)
81                 ino += 3;
82         return ino;
83 }
84
85 static int
86 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
87         struct smb_cred *scred)
88 {
89         struct smb_share *ssp = np->n_mount->sm_share;
90         struct smb_rq rq, *rqp = &rq;
91         struct mbchain *mbp;
92         u_char ltype = 0;
93         int error;
94
95         if (op == SMB_LOCK_SHARED)
96                 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
97         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
98         if (error)
99                 return error;
100         smb_rq_getrequest(rqp, &mbp);
101         smb_rq_wstart(rqp);
102         mb_put_uint8(mbp, 0xff);        /* secondary command */
103         mb_put_uint8(mbp, 0);           /* MBZ */
104         mb_put_uint16le(mbp, 0);
105         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
106         mb_put_uint8(mbp, ltype);       /* locktype */
107         mb_put_uint8(mbp, 0);           /* oplocklevel - 0 seems is NO_OPLOCK */
108         mb_put_uint32le(mbp, 0);        /* timeout - break immediately */
109         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
110         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
111         smb_rq_wend(rqp);
112         smb_rq_bstart(rqp);
113         mb_put_uint16le(mbp, pid);
114         mb_put_uint32le(mbp, start);
115         mb_put_uint32le(mbp, end - start);
116         smb_rq_bend(rqp);
117         error = smb_rq_simple(rqp);
118         smb_rq_done(rqp);
119         return error;
120 }
121
122 int
123 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
124         off_t start, off_t end, struct smb_cred *scred)
125 {
126         struct smb_share *ssp = np->n_mount->sm_share;
127
128         if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
129                 /*
130                  * TODO: use LOCK_BYTE_RANGE here.
131                  */
132                 return EINVAL;
133         else
134                 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
135 }
136
137 int
138 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
139         struct smb_cred *scred)
140 {
141         struct smb_t2rq *t2p;
142         struct mbchain *mbp;
143         struct mdchain *mdp;
144         u_int16_t bsize;
145         u_int32_t units, bpu, funits;
146         int error;
147
148         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
149             scred, &t2p);
150         if (error)
151                 return error;
152         mbp = &t2p->t2_tparam;
153         mb_init(mbp);
154         mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
155         t2p->t2_maxpcount = 4;
156         t2p->t2_maxdcount = 4 * 4 + 2;
157         error = smb_t2_request(t2p);
158         if (error) {
159                 smb_t2_done(t2p);
160                 return error;
161         }
162         mdp = &t2p->t2_rdata;
163         md_get_uint32(mdp, NULL);       /* fs id */
164         md_get_uint32le(mdp, &bpu);
165         md_get_uint32le(mdp, &units);
166         md_get_uint32le(mdp, &funits);
167         md_get_uint16le(mdp, &bsize);
168         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
169         sbp->f_blocks= units;           /* total data blocks in filesystem */
170         sbp->f_bfree = funits;          /* free blocks in fs */
171         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
172         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
173         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
174         smb_t2_done(t2p);
175         return 0;
176 }
177
178 int
179 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
180         struct smb_cred *scred)
181 {
182         struct smb_rq rq, *rqp = &rq;
183         struct mdchain *mdp;
184         u_int16_t units, bpu, bsize, funits;
185         int error;
186
187         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
188         if (error)
189                 return error;
190         smb_rq_wstart(rqp);
191         smb_rq_wend(rqp);
192         smb_rq_bstart(rqp);
193         smb_rq_bend(rqp);
194         error = smb_rq_simple(rqp);
195         if (error) {
196                 smb_rq_done(rqp);
197                 return error;
198         }
199         smb_rq_getreply(rqp, &mdp);
200         md_get_uint16le(mdp, &units);
201         md_get_uint16le(mdp, &bpu);
202         md_get_uint16le(mdp, &bsize);
203         md_get_uint16le(mdp, &funits);
204         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
205         sbp->f_blocks= units;           /* total data blocks in filesystem */
206         sbp->f_bfree = funits;          /* free blocks in fs */
207         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
208         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
209         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
210         smb_rq_done(rqp);
211         return 0;
212 }
213
214 static int
215 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
216 {
217         struct smb_t2rq *t2p;
218         struct smb_share *ssp = np->n_mount->sm_share;
219         struct mbchain *mbp;
220         int error;
221
222         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
223             scred, &t2p);
224         if (error)
225                 return error;
226         mbp = &t2p->t2_tparam;
227         mb_init(mbp);
228         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
229         mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
230         mb_put_uint32le(mbp, 0);
231         mbp = &t2p->t2_tdata;
232         mb_init(mbp);
233         mb_put_int64le(mbp, newsize);
234         mb_put_uint32le(mbp, 0);                        /* padding */
235         mb_put_uint16le(mbp, 0);
236         t2p->t2_maxpcount = 2;
237         t2p->t2_maxdcount = 0;
238         error = smb_t2_request(t2p);
239         smb_t2_done(t2p);
240         return error;
241 }
242
243 static int
244 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
245 {
246         struct smb_share *ssp = np->n_mount->sm_share;
247         struct smb_rq rq, *rqp = &rq;
248         struct mbchain *mbp;
249         int error;
250
251         if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
252             SMBTOV(np)->v_type != VREG)
253                 return 0; /* not a regular open file */
254         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
255         if (error)
256                 return (error);
257         smb_rq_getrequest(rqp, &mbp);
258         smb_rq_wstart(rqp);
259         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
260         smb_rq_wend(rqp);
261         smb_rq_bstart(rqp);
262         smb_rq_bend(rqp);
263         error = smb_rq_simple(rqp);
264         smb_rq_done(rqp);
265         if (!error)
266                 np->n_flag &= ~NFLUSHWIRE;
267         return (error);
268 }
269
270 int
271 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
272 {
273         if (np->n_flag & NFLUSHWIRE)
274                 return (smb_smb_flush(np, scred));
275         return (0);
276 }
277
278 int
279 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
280 {
281         struct smb_share *ssp = np->n_mount->sm_share;
282         struct smb_rq rq, *rqp = &rq;
283         struct mbchain *mbp;
284         int error;
285
286         if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
287                 np->n_flag |= NFLUSHWIRE;
288                 return (0);
289         }
290
291         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
292         if (error)
293                 return error;
294         smb_rq_getrequest(rqp, &mbp);
295         smb_rq_wstart(rqp);
296         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
297         mb_put_uint16le(mbp, 0);
298         mb_put_uint32le(mbp, newsize);
299         mb_put_uint16le(mbp, 0);
300         smb_rq_wend(rqp);
301         smb_rq_bstart(rqp);
302         mb_put_uint8(mbp, SMB_DT_DATA);
303         mb_put_uint16le(mbp, 0);
304         smb_rq_bend(rqp);
305         error = smb_rq_simple(rqp);
306         smb_rq_done(rqp);
307         return error;
308 }
309
310 int
311 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
312                      struct smbfattr *fap, struct smb_cred *scred)
313 {
314         struct smb_rq rq, *rqp = &rq;
315         struct smb_share *ssp = np->n_mount->sm_share;
316         struct mbchain *mbp;
317         struct mdchain *mdp;
318         u_int8_t wc;
319         int error;
320         u_int16_t wattr;
321         u_int32_t lint;
322
323         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
324         if (error)
325                 return error;
326         smb_rq_getrequest(rqp, &mbp);
327         smb_rq_wstart(rqp);
328         smb_rq_wend(rqp);
329         smb_rq_bstart(rqp);
330         mb_put_uint8(mbp, SMB_DT_ASCII);
331         do {
332                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
333                 if (error)
334                         break;
335                 smb_rq_bend(rqp);
336                 error = smb_rq_simple(rqp);
337                 if (error)
338                         break;
339                 smb_rq_getreply(rqp, &mdp);
340                 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
341                         error = EBADRPC;
342                         break;
343                 }
344                 md_get_uint16le(mdp, &wattr);
345                 fap->fa_attr = wattr;
346                 /*
347                  * Be careful using the time returned here, as
348                  * with FAT on NT4SP6, at least, the time returned is low
349                  * 32 bits of 100s of nanoseconds (since 1601) so it rolls
350                  * over about every seven minutes!
351                  */
352                 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
353                 if (lint)       /* avoid bogus zero returns */
354                         smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
355                                               &fap->fa_mtime);
356                 md_get_uint32le(mdp, &lint);
357                 fap->fa_size = lint;
358         } while(0);
359         smb_rq_done(rqp);
360         return error;
361 }
362
363 /*
364  * Set DOS file attributes. mtime should be NULL for dialects above lm10
365  */
366 int
367 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
368         struct smb_cred *scred)
369 {
370         struct smb_rq rq, *rqp = &rq;
371         struct smb_share *ssp = np->n_mount->sm_share;
372         struct mbchain *mbp;
373         u_long time;
374         int error, svtz;
375
376         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
377         if (error)
378                 return error;
379         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
380         smb_rq_getrequest(rqp, &mbp);
381         smb_rq_wstart(rqp);
382         mb_put_uint16le(mbp, attr);
383         if (mtime) {
384                 smb_time_local2server(mtime, svtz, &time);
385         } else
386                 time = 0;
387         mb_put_uint32le(mbp, time);             /* mtime */
388         mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
389         smb_rq_wend(rqp);
390         smb_rq_bstart(rqp);
391         mb_put_uint8(mbp, SMB_DT_ASCII);
392         do {
393                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
394                 if (error)
395                         break;
396                 mb_put_uint8(mbp, SMB_DT_ASCII);
397                 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
398                         mb_put_padbyte(mbp);
399                         mb_put_uint8(mbp, 0);   /* 1st byte of NULL Unicode char */
400                 }
401                 mb_put_uint8(mbp, 0);
402                 smb_rq_bend(rqp);
403                 error = smb_rq_simple(rqp);
404                 if (error) {
405                         SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
406                         break;
407                 }
408         } while(0);
409         smb_rq_done(rqp);
410         return error;
411 }
412
413 /*
414  * Note, win95 doesn't support this call.
415  */
416 int
417 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
418         struct timespec *atime, int attr, struct smb_cred *scred)
419 {
420         struct smb_t2rq *t2p;
421         struct smb_share *ssp = np->n_mount->sm_share;
422         struct smb_vc *vcp = SSTOVC(ssp);
423         struct mbchain *mbp;
424         u_int16_t date, time;
425         int error, tzoff;
426
427         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
428             scred, &t2p);
429         if (error)
430                 return error;
431         mbp = &t2p->t2_tparam;
432         mb_init(mbp);
433         mb_put_uint16le(mbp, SMB_INFO_STANDARD);
434         mb_put_uint32le(mbp, 0);                /* MBZ */
435         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
436         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
437         if (error) {
438                 smb_t2_done(t2p);
439                 return error;
440         }
441         tzoff = vcp->vc_sopt.sv_tz;
442         mbp = &t2p->t2_tdata;
443         mb_init(mbp);
444         mb_put_uint32le(mbp, 0);                /* creation time */
445         if (atime)
446                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
447         else
448                 time = date = 0;
449         mb_put_uint16le(mbp, date);
450         mb_put_uint16le(mbp, time);
451         if (mtime)
452                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
453         else
454                 time = date = 0;
455         mb_put_uint16le(mbp, date);
456         mb_put_uint16le(mbp, time);
457         mb_put_uint32le(mbp, 0);                /* file size */
458         mb_put_uint32le(mbp, 0);                /* allocation unit size */
459         mb_put_uint16le(mbp, attr);     /* DOS attr */
460         mb_put_uint32le(mbp, 0);                /* EA size */
461         t2p->t2_maxpcount = 5 * 2;
462         t2p->t2_maxdcount = vcp->vc_txmax;
463         error = smb_t2_request(t2p);
464         smb_t2_done(t2p);
465         return error;
466 }
467
468 /*
469  * NT level. Specially for win9x
470  */
471 int
472 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
473         struct timespec *atime, struct smb_cred *scred)
474 {
475         struct smb_t2rq *t2p;
476         struct smb_share *ssp = np->n_mount->sm_share;
477         struct smb_vc *vcp = SSTOVC(ssp);
478         struct mbchain *mbp;
479         int64_t tm;
480         int error, tzoff;
481
482         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
483             scred, &t2p);
484         if (error)
485                 return error;
486         mbp = &t2p->t2_tparam;
487         mb_init(mbp);
488         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
489         mb_put_uint32le(mbp, 0);                /* MBZ */
490         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
491         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
492         if (error) {
493                 smb_t2_done(t2p);
494                 return error;
495         }
496         tzoff = vcp->vc_sopt.sv_tz;
497         mbp = &t2p->t2_tdata;
498         mb_init(mbp);
499         mb_put_int64le(mbp, 0);         /* creation time */
500         if (atime) {
501                 smb_time_local2NT(atime, tzoff, &tm);
502         } else
503                 tm = 0;
504         mb_put_int64le(mbp, tm);
505         if (mtime) {
506                 smb_time_local2NT(mtime, tzoff, &tm);
507         } else
508                 tm = 0;
509         mb_put_int64le(mbp, tm);
510         mb_put_int64le(mbp, tm);                /* change time */
511         mb_put_uint32le(mbp, attr);             /* attr */
512         t2p->t2_maxpcount = 24;
513         t2p->t2_maxdcount = 56;
514         error = smb_t2_request(t2p);
515         smb_t2_done(t2p);
516         return error;
517 }
518
519 /*
520  * Set file atime and mtime. Doesn't supported by core dialect.
521  */
522 int
523 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
524         struct timespec *atime, struct smb_cred *scred)
525 {
526         struct smb_rq rq, *rqp = &rq;
527         struct smb_share *ssp = np->n_mount->sm_share;
528         struct mbchain *mbp;
529         u_int16_t date, time;
530         int error, tzoff;
531
532         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
533         if (error)
534                 return error;
535         tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
536         smb_rq_getrequest(rqp, &mbp);
537         smb_rq_wstart(rqp);
538         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
539         mb_put_uint32le(mbp, 0);                /* creation time */
540
541         if (atime)
542                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
543         else
544                 time = date = 0;
545         mb_put_uint16le(mbp, date);
546         mb_put_uint16le(mbp, time);
547         if (mtime)
548                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
549         else
550                 time = date = 0;
551         mb_put_uint16le(mbp, date);
552         mb_put_uint16le(mbp, time);
553         smb_rq_wend(rqp);
554         smb_rq_bstart(rqp);
555         smb_rq_bend(rqp);
556         error = smb_rq_simple(rqp);
557         SMBSDEBUG("%d\n", error);
558         smb_rq_done(rqp);
559         return error;
560 }
561
562 /*
563  * Set DOS file attributes.
564  * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
565  */
566 int
567 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
568         struct timespec *atime, struct smb_cred *scred)
569 {
570         struct smb_t2rq *t2p;
571         struct smb_share *ssp = np->n_mount->sm_share;
572         struct mbchain *mbp;
573         int64_t tm;
574         int error, svtz;
575
576         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
577             scred, &t2p);
578         if (error)
579                 return error;
580         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
581         mbp = &t2p->t2_tparam;
582         mb_init(mbp);
583         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
584         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
585         mb_put_uint32le(mbp, 0);
586         mbp = &t2p->t2_tdata;
587         mb_init(mbp);
588         mb_put_int64le(mbp, 0);         /* creation time */
589         if (atime) {
590                 smb_time_local2NT(atime, svtz, &tm);
591         } else
592                 tm = 0;
593         mb_put_int64le(mbp, tm);
594         if (mtime) {
595                 smb_time_local2NT(mtime, svtz, &tm);
596         } else
597                 tm = 0;
598         mb_put_int64le(mbp, tm);
599         mb_put_int64le(mbp, tm);                /* change time */
600         mb_put_uint16le(mbp, attr);
601         mb_put_uint32le(mbp, 0);                        /* padding */
602         mb_put_uint16le(mbp, 0);
603         t2p->t2_maxpcount = 2;
604         t2p->t2_maxdcount = 0;
605         error = smb_t2_request(t2p);
606         smb_t2_done(t2p);
607         return error;
608 }
609
610
611 int
612 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
613 {
614         struct smb_rq rq, *rqp = &rq;
615         struct smb_share *ssp = np->n_mount->sm_share;
616         struct mbchain *mbp;
617         struct mdchain *mdp;
618         u_int8_t wc;
619         u_int16_t fid, wattr, grantedmode;
620         int error;
621
622         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
623         if (error)
624                 return error;
625         smb_rq_getrequest(rqp, &mbp);
626         smb_rq_wstart(rqp);
627         mb_put_uint16le(mbp, accmode);
628         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
629         smb_rq_wend(rqp);
630         smb_rq_bstart(rqp);
631         mb_put_uint8(mbp, SMB_DT_ASCII);
632         do {
633                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
634                 if (error)
635                         break;
636                 smb_rq_bend(rqp);
637                 error = smb_rq_simple(rqp);
638                 if (error)
639                         break;
640                 smb_rq_getreply(rqp, &mdp);
641                 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
642                         error = EBADRPC;
643                         break;
644                 }
645                 md_get_uint16(mdp, &fid);
646                 md_get_uint16le(mdp, &wattr);
647                 md_get_uint32(mdp, NULL);       /* mtime */
648                 md_get_uint32(mdp, NULL);       /* fsize */
649                 md_get_uint16le(mdp, &grantedmode);
650                 /*
651                  * TODO: refresh attributes from this reply
652                  */
653         } while(0);
654         smb_rq_done(rqp);
655         if (error)
656                 return error;
657         np->n_fid = fid;
658         np->n_rwstate = grantedmode;
659         return 0;
660 }
661
662
663 int
664 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
665         struct smb_cred *scred)
666 {
667         struct smb_rq rq, *rqp = &rq;
668         struct mbchain *mbp;
669         u_long time;
670         int error;
671
672         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
673         if (error)
674                 return error;
675         smb_rq_getrequest(rqp, &mbp);
676         smb_rq_wstart(rqp);
677         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
678         if (mtime) {
679                 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
680         } else
681                 time = 0;
682         mb_put_uint32le(mbp, time);
683         smb_rq_wend(rqp);
684         smb_rq_bstart(rqp);
685         smb_rq_bend(rqp);
686         error = smb_rq_simple(rqp);
687         smb_rq_done(rqp);
688         return error;
689 }
690
691 int
692 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
693         struct smb_cred *scred)
694 {
695         struct smb_rq rq, *rqp = &rq;
696         struct smb_share *ssp = dnp->n_mount->sm_share;
697         struct mbchain *mbp;
698         struct mdchain *mdp;
699         struct timespec ctime;
700         u_int8_t wc;
701         u_int16_t fid;
702         u_long tm;
703         int error;
704
705         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
706         if (error)
707                 return error;
708         smb_rq_getrequest(rqp, &mbp);
709         smb_rq_wstart(rqp);
710         mb_put_uint16le(mbp, SMB_FA_ARCHIVE);           /* attributes  */
711         nanotime(&ctime);
712         smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
713         mb_put_uint32le(mbp, tm);
714         smb_rq_wend(rqp);
715         smb_rq_bstart(rqp);
716         mb_put_uint8(mbp, SMB_DT_ASCII);
717         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
718         if (!error) {
719                 smb_rq_bend(rqp);
720                 error = smb_rq_simple(rqp);
721                 if (!error) {
722                         smb_rq_getreply(rqp, &mdp);
723                         md_get_uint8(mdp, &wc);
724                         if (wc == 1)
725                                 md_get_uint16(mdp, &fid);
726                         else
727                                 error = EBADRPC;
728                 }
729         }
730         smb_rq_done(rqp);
731         if (error)
732                 return error;
733         smbfs_smb_close(ssp, fid, &ctime, scred);
734         return error;
735 }
736
737 int
738 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
739 {
740         struct smb_rq rq, *rqp = &rq;
741         struct smb_share *ssp = np->n_mount->sm_share;
742         struct mbchain *mbp;
743         int error;
744
745         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
746         if (error)
747                 return error;
748         smb_rq_getrequest(rqp, &mbp);
749         smb_rq_wstart(rqp);
750         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
751         smb_rq_wend(rqp);
752         smb_rq_bstart(rqp);
753         mb_put_uint8(mbp, SMB_DT_ASCII);
754         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
755         if (!error) {
756                 smb_rq_bend(rqp);
757                 error = smb_rq_simple(rqp);
758         }
759         smb_rq_done(rqp);
760         return error;
761 }
762
763 int
764 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
765         const char *tname, int tnmlen, struct smb_cred *scred)
766 {
767         struct smb_rq rq, *rqp = &rq;
768         struct smb_share *ssp = src->n_mount->sm_share;
769         struct mbchain *mbp;
770         int error;
771
772         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
773         if (error)
774                 return error;
775         smb_rq_getrequest(rqp, &mbp);
776         smb_rq_wstart(rqp);
777         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
778         smb_rq_wend(rqp);
779         smb_rq_bstart(rqp);
780         mb_put_uint8(mbp, SMB_DT_ASCII);
781         do {
782                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
783                 if (error)
784                         break;
785                 mb_put_uint8(mbp, SMB_DT_ASCII);
786                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
787                 if (error)
788                         break;
789                 smb_rq_bend(rqp);
790                 error = smb_rq_simple(rqp);
791         } while(0);
792         smb_rq_done(rqp);
793         return error;
794 }
795
796 int
797 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
798         const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
799 {
800         struct smb_rq rq, *rqp = &rq;
801         struct smb_share *ssp = src->n_mount->sm_share;
802         struct mbchain *mbp;
803         int error;
804
805         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
806         if (error)
807                 return error;
808         smb_rq_getrequest(rqp, &mbp);
809         smb_rq_wstart(rqp);
810         mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
811         mb_put_uint16le(mbp, 0x20);     /* delete target file */
812         mb_put_uint16le(mbp, flags);
813         smb_rq_wend(rqp);
814         smb_rq_bstart(rqp);
815         mb_put_uint8(mbp, SMB_DT_ASCII);
816         do {
817                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
818                 if (error)
819                         break;
820                 mb_put_uint8(mbp, SMB_DT_ASCII);
821                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
822                 if (error)
823                         break;
824                 smb_rq_bend(rqp);
825                 error = smb_rq_simple(rqp);
826         } while(0);
827         smb_rq_done(rqp);
828         return error;
829 }
830
831 int
832 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
833         struct smb_cred *scred)
834 {
835         struct smb_rq rq, *rqp = &rq;
836         struct smb_share *ssp = dnp->n_mount->sm_share;
837         struct mbchain *mbp;
838         int error;
839
840         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
841         if (error)
842                 return error;
843         smb_rq_getrequest(rqp, &mbp);
844         smb_rq_wstart(rqp);
845         smb_rq_wend(rqp);
846         smb_rq_bstart(rqp);
847         mb_put_uint8(mbp, SMB_DT_ASCII);
848         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
849         if (!error) {
850                 smb_rq_bend(rqp);
851                 error = smb_rq_simple(rqp);
852         }
853         smb_rq_done(rqp);
854         return error;
855 }
856
857 int
858 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
859 {
860         struct smb_rq rq, *rqp = &rq;
861         struct smb_share *ssp = np->n_mount->sm_share;
862         struct mbchain *mbp;
863         int error;
864
865         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
866         if (error)
867                 return error;
868         smb_rq_getrequest(rqp, &mbp);
869         smb_rq_wstart(rqp);
870         smb_rq_wend(rqp);
871         smb_rq_bstart(rqp);
872         mb_put_uint8(mbp, SMB_DT_ASCII);
873         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
874         if (!error) {
875                 smb_rq_bend(rqp);
876                 error = smb_rq_simple(rqp);
877         }
878         smb_rq_done(rqp);
879         return error;
880 }
881
882 static int
883 smbfs_smb_search(struct smbfs_fctx *ctx)
884 {
885         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
886         struct smb_rq *rqp;
887         struct mbchain *mbp;
888         struct mdchain *mdp;
889         u_int8_t wc, bt;
890         u_int16_t ec, dlen, bc;
891         int maxent, error, iseof = 0;
892
893         maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
894         if (ctx->f_rq) {
895                 smb_rq_done(ctx->f_rq);
896                 ctx->f_rq = NULL;
897         }
898         error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
899         if (error)
900                 return error;
901         ctx->f_rq = rqp;
902         smb_rq_getrequest(rqp, &mbp);
903         smb_rq_wstart(rqp);
904         mb_put_uint16le(mbp, maxent);   /* max entries to return */
905         mb_put_uint16le(mbp, ctx->f_attrmask);
906         smb_rq_wend(rqp);
907         smb_rq_bstart(rqp);
908         mb_put_uint8(mbp, SMB_DT_ASCII);        /* buffer format */
909         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
910                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
911                 if (error)
912                         return error;
913                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
914                 mb_put_uint16le(mbp, 0);        /* context length */
915                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
916         } else {
917                 if (SMB_UNICODE_STRINGS(vcp)) {
918                         mb_put_padbyte(mbp);
919                         mb_put_uint8(mbp, 0);
920                 }
921                 mb_put_uint8(mbp, 0);   /* file name length */
922                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
923                 mb_put_uint16le(mbp, SMB_SKEYLEN);
924                 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
925         }
926         smb_rq_bend(rqp);
927         error = smb_rq_simple(rqp);
928         if (error) {
929                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
930                         error = 0;
931                         iseof = 1;
932                         ctx->f_flags |= SMBFS_RDD_EOF;
933                 } else
934                         return error;
935         }
936         smb_rq_getreply(rqp, &mdp);
937         md_get_uint8(mdp, &wc);
938         if (wc != 1) 
939                 return iseof ? ENOENT : EBADRPC;
940         md_get_uint16le(mdp, &ec);
941         if (ec == 0)
942                 return ENOENT;
943         ctx->f_ecnt = ec;
944         md_get_uint16le(mdp, &bc);
945         if (bc < 3)
946                 return EBADRPC;
947         bc -= 3;
948         md_get_uint8(mdp, &bt);
949         if (bt != SMB_DT_VARIABLE)
950                 return EBADRPC;
951         md_get_uint16le(mdp, &dlen);
952         if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
953                 return EBADRPC;
954         return 0;
955 }
956
957 static int
958 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
959         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
960 {
961         ctx->f_attrmask = attr;
962         if (wildcard) {
963                 if (wclen == 1 && wildcard[0] == '*') {
964                         ctx->f_wildcard = "*.*";
965                         ctx->f_wclen = 3;
966                 } else {
967                         ctx->f_wildcard = wildcard;
968                         ctx->f_wclen = wclen;
969                 }
970         } else {
971                 ctx->f_wildcard = NULL;
972                 ctx->f_wclen = 0;
973         }
974         ctx->f_name = ctx->f_fname;
975         return 0;
976 }
977
978 static int
979 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
980 {
981         struct mdchain *mbp;
982         struct smb_rq *rqp;
983         char *cp;
984         u_int8_t battr;
985         u_int16_t date, time;
986         u_int32_t size;
987         int error;
988
989         if (ctx->f_ecnt == 0) {
990                 if (ctx->f_flags & SMBFS_RDD_EOF)
991                         return ENOENT;
992                 ctx->f_left = ctx->f_limit = limit;
993                 error = smbfs_smb_search(ctx);
994                 if (error)
995                         return error;
996         }
997         rqp = ctx->f_rq;
998         smb_rq_getreply(rqp, &mbp);
999         md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1000         md_get_uint8(mbp, &battr);
1001         md_get_uint16le(mbp, &time);
1002         md_get_uint16le(mbp, &date);
1003         md_get_uint32le(mbp, &size);
1004         cp = ctx->f_name;
1005         md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
1006         cp[sizeof(ctx->f_fname) - 1] = 0;
1007         cp += strlen(cp) - 1;
1008         while (*cp == ' ' && cp >= ctx->f_name)
1009                 *cp-- = 0;
1010         ctx->f_attr.fa_attr = battr;
1011         smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1012             &ctx->f_attr.fa_mtime);
1013         ctx->f_attr.fa_size = size;
1014         ctx->f_nmlen = strlen(ctx->f_name);
1015         ctx->f_ecnt--;
1016         ctx->f_left--;
1017         return 0;
1018 }
1019
1020 static int
1021 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
1022 {
1023         if (ctx->f_rq)
1024                 smb_rq_done(ctx->f_rq);
1025         return 0;
1026 }
1027
1028 /*
1029  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1030  */
1031 static int
1032 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1033 {
1034         struct smb_t2rq *t2p;
1035         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1036         struct mbchain *mbp;
1037         struct mdchain *mdp;
1038         u_int16_t tw, flags;
1039         int error;
1040
1041         if (ctx->f_t2) {
1042                 smb_t2_done(ctx->f_t2);
1043                 ctx->f_t2 = NULL;
1044         }
1045         ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1046         flags = 8 | 2;                  /* <resume> | <close if EOS> */
1047         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1048                 flags |= 1;             /* close search after this request */
1049                 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1050         }
1051         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1052                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1053                     ctx->f_scred, &t2p);
1054                 if (error)
1055                         return error;
1056                 ctx->f_t2 = t2p;
1057                 mbp = &t2p->t2_tparam;
1058                 mb_init(mbp);
1059                 mb_put_uint16le(mbp, ctx->f_attrmask);
1060                 mb_put_uint16le(mbp, ctx->f_limit);
1061                 mb_put_uint16le(mbp, flags);
1062                 mb_put_uint16le(mbp, ctx->f_infolevel);
1063                 mb_put_uint32le(mbp, 0);
1064                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1065                 if (error)
1066                         return error;
1067         } else  {
1068                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1069                     ctx->f_scred, &t2p);
1070                 if (error)
1071                         return error;
1072                 ctx->f_t2 = t2p;
1073                 mbp = &t2p->t2_tparam;
1074                 mb_init(mbp);
1075                 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1076                 mb_put_uint16le(mbp, ctx->f_limit);
1077                 mb_put_uint16le(mbp, ctx->f_infolevel);
1078                 mb_put_uint32le(mbp, 0);                /* resume key */
1079                 mb_put_uint16le(mbp, flags);
1080                 if (ctx->f_rname)
1081                         mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
1082                 else
1083                         mb_put_uint8(mbp, 0);   /* resume file name */
1084 #if 0
1085         struct timeval tv;
1086         tv.tv_sec = 0;
1087         tv.tv_usec = 200 * 1000;        /* 200ms */
1088                 if (vcp->vc_flags & SMBC_WIN95) {
1089                         /*
1090                          * some implementations suggests to sleep here
1091                          * for 200ms, due to the bug in the Win95.
1092                          * I've didn't notice any problem, but put code
1093                          * for it.
1094                          */
1095                          pause("fix95", tvtohz(&tv));
1096                 }
1097 #endif
1098         }
1099         t2p->t2_maxpcount = 5 * 2;
1100         t2p->t2_maxdcount = vcp->vc_txmax;
1101         error = smb_t2_request(t2p);
1102         if (error)
1103                 return error;
1104         mdp = &t2p->t2_rparam;
1105         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1106                 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1107                         return error;
1108                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1109         }
1110         if ((error = md_get_uint16le(mdp, &tw)) != 0)
1111                 return error;
1112         ctx->f_ecnt = tw;
1113         if ((error = md_get_uint16le(mdp, &tw)) != 0)
1114                 return error;
1115         if (tw)
1116                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1117         if ((error = md_get_uint16le(mdp, &tw)) != 0)
1118                 return error;
1119         if ((error = md_get_uint16le(mdp, &tw)) != 0)
1120                 return error;
1121         if (ctx->f_ecnt == 0) {
1122                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1123                 return ENOENT;
1124         }
1125         ctx->f_rnameofs = tw;
1126         mdp = &t2p->t2_rdata;
1127         if (mdp->md_top == NULL) {
1128                 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
1129                 return ENOENT;
1130         }
1131         if (mdp->md_top->m_len == 0) {
1132                 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
1133                 return ENOENT;
1134         }
1135         ctx->f_eofs = 0;
1136         return 0;
1137 }
1138
1139 static int
1140 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1141 {
1142         struct smb_rq rq, *rqp = &rq;
1143         struct mbchain *mbp;
1144         int error;
1145
1146         error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
1147         if (error)
1148                 return error;
1149         smb_rq_getrequest(rqp, &mbp);
1150         smb_rq_wstart(rqp);
1151         mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1152         smb_rq_wend(rqp);
1153         smb_rq_bstart(rqp);
1154         smb_rq_bend(rqp);
1155         error = smb_rq_simple(rqp);
1156         smb_rq_done(rqp);
1157         return error;
1158 }
1159
1160 static int
1161 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1162         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1163 {
1164         if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1165                 ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
1166         } else
1167                 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1168         if (ctx->f_name == NULL)
1169                 return ENOMEM;
1170         ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1171             SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1172         ctx->f_attrmask = attr;
1173         ctx->f_wildcard = wildcard;
1174         ctx->f_wclen = wclen;
1175         return 0;
1176 }
1177
1178 static int
1179 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1180 {
1181         struct mdchain *mbp;
1182         struct smb_t2rq *t2p;
1183         char *cp;
1184         u_int8_t tb;
1185         u_int16_t date, time, wattr;
1186         u_int32_t size, next, dattr;
1187         int64_t lint;
1188         int error, svtz, cnt, fxsz, nmlen, recsz;
1189
1190         if (ctx->f_ecnt == 0) {
1191                 if (ctx->f_flags & SMBFS_RDD_EOF)
1192                         return ENOENT;
1193                 ctx->f_left = ctx->f_limit = limit;
1194                 error = smbfs_smb_trans2find2(ctx);
1195                 if (error)
1196                         return error;
1197         }
1198         t2p = ctx->f_t2;
1199         mbp = &t2p->t2_rdata;
1200         svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1201         switch (ctx->f_infolevel) {
1202             case SMB_INFO_STANDARD:
1203                 next = 0;
1204                 fxsz = 0;
1205                 md_get_uint16le(mbp, &date);
1206                 md_get_uint16le(mbp, &time);    /* creation time */
1207                 md_get_uint16le(mbp, &date);
1208                 md_get_uint16le(mbp, &time);    /* access time */
1209                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
1210                 md_get_uint16le(mbp, &date);
1211                 md_get_uint16le(mbp, &time);    /* access time */
1212                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
1213                 md_get_uint32le(mbp, &size);
1214                 ctx->f_attr.fa_size = size;
1215                 md_get_uint32(mbp, NULL);       /* allocation size */
1216                 md_get_uint16le(mbp, &wattr);
1217                 ctx->f_attr.fa_attr = wattr;
1218                 md_get_uint8(mbp, &tb);
1219                 size = nmlen = tb;
1220                 fxsz = 23;
1221                 recsz = next = 24 + nmlen;      /* docs misses zero byte at end */
1222                 break;
1223             case SMB_FIND_FILE_DIRECTORY_INFO:
1224                 md_get_uint32le(mbp, &next);
1225                 md_get_uint32(mbp, NULL);       /* file index */
1226                 md_get_int64(mbp, NULL);        /* creation time */
1227                 md_get_int64le(mbp, &lint);
1228                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
1229                 md_get_int64le(mbp, &lint);
1230                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
1231                 md_get_int64le(mbp, &lint);
1232                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
1233                 md_get_int64le(mbp, &lint);     /* file size */
1234                 ctx->f_attr.fa_size = lint;
1235                 md_get_int64(mbp, NULL);        /* real size (should use) */
1236                 md_get_uint32le(mbp, &dattr);   /* EA */
1237                 ctx->f_attr.fa_attr = dattr;
1238                 md_get_uint32le(mbp, &size);    /* name len */
1239                 fxsz = 64;
1240                 recsz = next ? next : fxsz + size;
1241                 break;
1242             default:
1243                 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
1244                 return EINVAL;
1245         }
1246         if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1247                 nmlen = min(size, SMB_MAXFNAMELEN * 2);
1248         } else
1249                 nmlen = min(size, SMB_MAXFNAMELEN);
1250         cp = ctx->f_name;
1251         error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1252         if (error)
1253                 return error;
1254         if (next) {
1255                 cnt = next - nmlen - fxsz;
1256                 if (cnt > 0)
1257                         md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1258                 else if (cnt < 0) {
1259                         SMBERROR("out of sync\n");
1260                         return EBADRPC;
1261                 }
1262         }
1263         if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1264                 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
1265                         nmlen -= 2;
1266         } else
1267                 if (nmlen && cp[nmlen - 1] == 0)
1268                         nmlen--;
1269         if (nmlen == 0)
1270                 return EBADRPC;
1271
1272         next = ctx->f_eofs + recsz;
1273         if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1274             (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1275                 /*
1276                  * Server needs a resume filename.
1277                  */
1278                 if (ctx->f_rnamelen <= nmlen) {
1279                         if (ctx->f_rname)
1280                                 free(ctx->f_rname, M_SMBFSDATA);
1281                         ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1282                         ctx->f_rnamelen = nmlen;
1283                 }
1284                 bcopy(ctx->f_name, ctx->f_rname, nmlen);
1285                 ctx->f_rname[nmlen] = 0;
1286                 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1287         }
1288         ctx->f_nmlen = nmlen;
1289         ctx->f_eofs = next;
1290         ctx->f_ecnt--;
1291         ctx->f_left--;
1292         return 0;
1293 }
1294
1295 static int
1296 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1297 {
1298         if (ctx->f_name)
1299                 free(ctx->f_name, M_SMBFSDATA);
1300         if (ctx->f_t2)
1301                 smb_t2_done(ctx->f_t2);
1302         if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1303                 smbfs_smb_findclose2(ctx);
1304         return 0;
1305 }
1306
1307 int
1308 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1309         struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1310 {
1311         struct smbfs_fctx *ctx;
1312         int error;
1313
1314         ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
1315         if (ctx == NULL)
1316                 return ENOMEM;
1317         bzero(ctx, sizeof(*ctx));
1318         ctx->f_ssp = dnp->n_mount->sm_share;
1319         ctx->f_dnp = dnp;
1320         ctx->f_flags = SMBFS_RDD_FINDFIRST;
1321         ctx->f_scred = scred;
1322         if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1323             (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
1324                 ctx->f_flags |= SMBFS_RDD_USESEARCH;
1325                 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1326         } else
1327                 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1328         if (error)
1329                 smbfs_findclose(ctx, scred);
1330         else
1331                 *ctxpp = ctx;
1332         return error;
1333 }
1334
1335 int
1336 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1337 {
1338         int error;
1339
1340         if (limit == 0)
1341                 limit = 1000000;
1342         else if (limit > 1)
1343                 limit *= 4;     /* imperical */
1344         ctx->f_scred = scred;
1345         for (;;) {
1346                 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1347                         error = smbfs_findnextLM1(ctx, limit);
1348                 } else
1349                         error = smbfs_findnextLM2(ctx, limit);
1350                 if (error)
1351                         return error;
1352                 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1353                         if ((ctx->f_nmlen == 2 &&
1354                              *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
1355                             (ctx->f_nmlen == 4 &&
1356                              *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
1357                                 continue;
1358                 } else
1359                         if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1360                             (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1361                              ctx->f_name[1] == '.'))
1362                                 continue;
1363                 break;
1364         }
1365         smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1366                             ctx->f_dnp->n_mount->sm_caseopt);
1367         ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1368         return 0;
1369 }
1370
1371 int
1372 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1373 {
1374         ctx->f_scred = scred;
1375         if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1376                 smbfs_findcloseLM1(ctx);
1377         } else
1378                 smbfs_findcloseLM2(ctx);
1379         if (ctx->f_rname)
1380                 free(ctx->f_rname, M_SMBFSDATA);
1381         free(ctx, M_SMBFSDATA);
1382         return 0;
1383 }
1384
1385 int
1386 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1387         struct smbfattr *fap, struct smb_cred *scred)
1388 {
1389         struct smbfs_fctx *ctx;
1390         int error;
1391
1392         if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1393                 bzero(fap, sizeof(*fap));
1394                 fap->fa_attr = SMB_FA_DIR;
1395                 fap->fa_ino = 2;
1396                 return 0;
1397         }
1398         if (nmlen == 1 && name[0] == '.') {
1399                 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
1400                 return error;
1401         } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1402                 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
1403                     scred);
1404                 printf("%s: knows NOTHING about '..'\n", __func__);
1405                 return error;
1406         }
1407         error = smbfs_findopen(dnp, name, nmlen,
1408             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1409         if (error)
1410                 return error;
1411         ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1412         error = smbfs_findnext(ctx, 1, scred);
1413         if (error == 0) {
1414                 *fap = ctx->f_attr;
1415                 if (name == NULL)
1416                         fap->fa_ino = dnp->n_ino;
1417         }
1418         smbfs_findclose(ctx, scred);
1419         return error;
1420 }