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