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