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