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