No empty .Rs/.Re
[netbsd-mini2440.git] / sys / fs / smbfs / smbfs_smb.c
blobef453129c4af20856502a0a58681ab40989f9bbd
1 /* $NetBSD: smbfs_smb.c,v 1.40 2009/04/18 14:58:04 tsutsui Exp $ */
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jaromir Dolecek.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 2000-2001 Boris Popov
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by Boris Popov.
47 * 4. Neither the name of the author nor the names of any co-contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
63 * FreeBSD: src/sys/fs/smbfs/smbfs_smb.c,v 1.3 2001/12/10 08:09:46 obrien Exp
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: smbfs_smb.c,v 1.40 2009/04/18 14:58:04 tsutsui Exp $");
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/malloc.h>
73 #include <sys/proc.h>
74 #include <sys/lock.h>
75 #include <sys/vnode.h>
76 #include <sys/mbuf.h>
77 #include <sys/mount.h>
79 #ifdef USE_MD5_HASH
80 #include <sys/md5.h>
81 #endif
83 #include <netsmb/smb.h>
84 #include <netsmb/smb_subr.h>
85 #include <netsmb/smb_rq.h>
86 #include <netsmb/smb_conn.h>
88 #include <fs/smbfs/smbfs.h>
89 #include <fs/smbfs/smbfs_node.h>
90 #include <fs/smbfs/smbfs_subr.h>
93 * Lack of inode numbers leads us to the problem of generating them.
94 * Partially this problem can be solved by having a dir/file cache
95 * with inode numbers generated from the incremented by one counter.
96 * However this way will require too much kernel memory, gives all
97 * sorts of locking and consistency problems, not to mentinon counter overflows.
98 * So, I'm decided to use a hash function to generate pseudo random (and unique)
99 * inode numbers.
101 static long
102 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
104 #ifdef USE_MD5_HASH
105 MD5_CTX md5;
106 u_int32_t state[4];
107 long ino;
108 int i;
110 MD5Init(&md5);
111 MD5Update(&md5, name, nmlen);
112 MD5Final((u_char *)state, &md5);
113 for (i = 0, ino = 0; i < 4; i++)
114 ino += state[i];
115 return dnp->n_ino + ino;
116 #endif
117 u_int32_t ino;
119 ino = dnp->n_ino + smbfs_hash(name, nmlen);
120 if (ino <= 2)
121 ino += 3;
122 return ino;
125 static int
126 smbfs_smb_lockandx(struct smbnode *np, int op, void *id, off_t start, off_t end,
127 struct smb_cred *scred)
129 struct smb_share *ssp = np->n_mount->sm_share;
130 struct smb_rq *rqp;
131 struct mbchain *mbp;
132 u_char ltype = 0;
133 int error;
135 if (op == SMB_LOCK_SHARED)
136 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
137 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
138 if (error)
139 return error;
140 smb_rq_getrequest(rqp, &mbp);
141 smb_rq_wstart(rqp);
142 mb_put_uint8(mbp, 0xff); /* secondary command */
143 mb_put_uint8(mbp, 0); /* MBZ */
144 mb_put_uint16le(mbp, 0);
145 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
146 mb_put_uint8(mbp, ltype); /* locktype */
147 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
148 mb_put_uint32le(mbp, 0); /* timeout - break immediately */
149 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
150 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
151 smb_rq_wend(rqp);
152 smb_rq_bstart(rqp);
153 mb_put_uint16le(mbp, (((long) id) & 0xffff)); /* process ID */
154 mb_put_uint32le(mbp, start);
155 mb_put_uint32le(mbp, end - start);
156 smb_rq_bend(rqp);
157 error = smb_rq_simple(rqp);
158 smb_rq_done(rqp);
159 return error;
163 smbfs_smb_lock(struct smbnode *np, int op, void *id,
164 off_t start, off_t end, struct smb_cred *scred)
166 struct smb_share *ssp = np->n_mount->sm_share;
168 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
170 * TODO: use LOCK_BYTE_RANGE here.
172 return EINVAL;
173 else
174 return smbfs_smb_lockandx(np, op, id, start, end, scred);
178 smbfs_smb_statvfs(struct smb_share *ssp, struct statvfs *sbp,
179 struct smb_cred *scred)
181 unsigned long bsize; /* Block (allocation unit) size */
182 unsigned long bavail, bfree;
185 * The SMB request work with notion of sector size and
186 * allocation units. Allocation unit is what 'block'
187 * means in Unix context, sector size might be HW sector size.
190 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
191 struct smb_t2rq *t2p;
192 struct mbchain *mbp;
193 struct mdchain *mdp;
194 u_int16_t secsz;
195 u_int32_t units, bpu, funits;
196 int error;
198 error = smb_t2_alloc(SSTOCP(ssp),
199 SMB_TRANS2_QUERY_FS_INFORMATION, scred, &t2p);
200 if (error)
201 return error;
202 mbp = &t2p->t2_tparam;
203 mb_init(mbp);
204 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
205 t2p->t2_maxpcount = 4;
206 t2p->t2_maxdcount = 4 * 4 + 2;
207 error = smb_t2_request(t2p);
208 if (error) {
209 smb_t2_done(t2p);
210 return error;
212 mdp = &t2p->t2_rdata;
213 md_get_uint32(mdp, NULL); /* fs id */
214 md_get_uint32le(mdp, &bpu); /* Number of sectors per unit */
215 md_get_uint32le(mdp, &units); /* Total number of units */
216 md_get_uint32le(mdp, &funits); /* Number of available units */
217 md_get_uint16le(mdp, &secsz); /* Number of bytes per sector */
218 smb_t2_done(t2p);
220 bsize = bpu * secsz;
221 bavail = units;
222 bfree = funits;
223 } else {
224 struct smb_rq *rqp;
225 struct mdchain *mdp;
226 u_int16_t units, bpu, secsz, funits;
227 int error;
229 error = smb_rq_alloc(SSTOCP(ssp),
230 SMB_COM_QUERY_INFORMATION_DISK, scred, &rqp);
231 if (error)
232 return error;
233 smb_rq_wstart(rqp);
234 smb_rq_wend(rqp);
235 smb_rq_bstart(rqp);
236 smb_rq_bend(rqp);
237 error = smb_rq_simple(rqp);
238 if (error) {
239 smb_rq_done(rqp);
240 return error;
242 smb_rq_getreply(rqp, &mdp);
243 md_get_uint16le(mdp, &units); /* Total units per server */
244 md_get_uint16le(mdp, &bpu); /* Blocks per allocation unit */
245 md_get_uint16le(mdp, &secsz); /* Block size (in bytes) */
246 md_get_uint16le(mdp, &funits); /* Number of free units */
247 smb_rq_done(rqp);
249 bsize = bpu * secsz;
250 bavail = units;
251 bfree = funits;
254 sbp->f_bsize = bsize; /* fundamental file system block size */
255 sbp->f_frsize = bsize; /* fundamental file system frag size */
256 sbp->f_iosize = bsize; /* optimal I/O size */
257 sbp->f_blocks = bavail; /* total data blocks in file system */
258 sbp->f_bfree = bfree; /* free blocks in fs */
259 sbp->f_bresvd = 0; /* reserved blocks in fs */
260 sbp->f_bavail= bfree; /* free blocks avail to non-superuser */
261 sbp->f_files = 0xffff; /* total file nodes in file system */
262 sbp->f_ffree = 0xffff; /* free file nodes to non-superuser */
263 sbp->f_favail = 0xffff; /* free file nodes in fs */
264 sbp->f_fresvd = 0; /* reserved file nodes in fs */
265 return 0;
268 static int
269 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
271 struct smb_t2rq *t2p;
272 struct smb_share *ssp = np->n_mount->sm_share;
273 struct mbchain *mbp;
274 int error;
276 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
277 scred, &t2p);
278 if (error)
279 return error;
280 mbp = &t2p->t2_tparam;
281 mb_init(mbp);
282 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
283 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
284 mb_put_uint32le(mbp, 0);
285 mbp = &t2p->t2_tdata;
286 mb_init(mbp);
287 mb_put_int64le(mbp, newsize);
288 mb_put_uint32le(mbp, 0); /* padding */
289 mb_put_uint16le(mbp, 0);
290 t2p->t2_maxpcount = 2;
291 t2p->t2_maxdcount = 0;
292 error = smb_t2_request(t2p);
293 smb_t2_done(t2p);
294 return error;
298 smbfs_smb_setfsize(struct smbnode *np, u_quad_t newsize,
299 struct smb_cred *scred)
301 struct smb_share *ssp = np->n_mount->sm_share;
302 struct smb_rq *rqp;
303 struct mbchain *mbp;
304 int error;
306 if (newsize >= (1LL << 32)) {
307 if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES))
308 return EFBIG;
309 return smbfs_smb_seteof(np, (int64_t)newsize, scred);
312 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
313 if (error)
314 return error;
315 smb_rq_getrequest(rqp, &mbp);
316 smb_rq_wstart(rqp);
317 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
318 mb_put_uint16le(mbp, 0);
319 mb_put_uint32le(mbp, newsize);
320 mb_put_uint16le(mbp, 0);
321 smb_rq_wend(rqp);
322 smb_rq_bstart(rqp);
323 mb_put_uint8(mbp, SMB_DT_DATA);
324 mb_put_uint16le(mbp, 0);
325 smb_rq_bend(rqp);
326 error = smb_rq_simple(rqp);
327 smb_rq_done(rqp);
328 return error;
333 * Set DOS file attributes. mtime should be NULL for dialects above lm10
336 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
337 struct smb_cred *scred)
339 struct smb_rq *rqp;
340 struct smb_share *ssp = np->n_mount->sm_share;
341 struct mbchain *mbp;
342 u_long xtime;
343 int error, svtz;
345 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred, &rqp);
346 if (error)
347 return error;
348 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
349 smb_rq_getrequest(rqp, &mbp);
350 smb_rq_wstart(rqp);
351 mb_put_uint16le(mbp, attr);
352 if (mtime) {
353 smb_time_local2server(mtime, svtz, &xtime);
354 } else
355 xtime = 0;
356 mb_put_uint32le(mbp, xtime); /* mtime */
357 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
358 smb_rq_wend(rqp);
359 smb_rq_bstart(rqp);
360 mb_put_uint8(mbp, SMB_DT_ASCII);
361 do {
362 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
363 if (error)
364 break;
365 mb_put_uint8(mbp, SMB_DT_ASCII);
366 mb_put_uint8(mbp, 0);
367 smb_rq_bend(rqp);
368 error = smb_rq_simple(rqp);
369 if (error)
370 break;
371 } while(0);
372 smb_rq_done(rqp);
373 return error;
377 * Note, win95 doesn't support this call.
380 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
381 struct timespec *atime, int attr, struct smb_cred *scred)
383 struct smb_t2rq *t2p;
384 struct smb_share *ssp = np->n_mount->sm_share;
385 struct smb_vc *vcp = SSTOVC(ssp);
386 struct mbchain *mbp;
387 u_int16_t xdate, xtime;
388 int error, tzoff;
390 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
391 scred, &t2p);
392 if (error)
393 return error;
394 mbp = &t2p->t2_tparam;
395 mb_init(mbp);
396 mb_put_uint16le(mbp, SMB_INFO_STANDARD);
397 mb_put_uint32le(mbp, 0); /* MBZ */
398 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
399 if (error) {
400 smb_t2_done(t2p);
401 return error;
403 tzoff = vcp->vc_sopt.sv_tz;
404 mbp = &t2p->t2_tdata;
405 mb_init(mbp);
406 mb_put_uint32le(mbp, 0); /* creation time */
407 if (atime)
408 smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL);
409 else
410 xtime = xdate = 0;
411 mb_put_uint16le(mbp, xdate);
412 mb_put_uint16le(mbp, xtime);
413 if (mtime)
414 smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL);
415 else
416 xtime = xdate = 0;
417 mb_put_uint16le(mbp, xdate);
418 mb_put_uint16le(mbp, xtime);
419 mb_put_uint32le(mbp, 0); /* file size */
420 mb_put_uint32le(mbp, 0); /* allocation unit size */
421 mb_put_uint16le(mbp, attr); /* DOS attr */
422 mb_put_uint32le(mbp, 0); /* EA size */
423 t2p->t2_maxpcount = 5 * 2;
424 t2p->t2_maxdcount = vcp->vc_txmax;
425 error = smb_t2_request(t2p);
426 smb_t2_done(t2p);
427 return error;
431 * NT level. Specially for win9x
433 #if 0
435 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
436 struct timespec *atime, struct smb_cred *scred)
438 struct smb_t2rq *t2p;
439 struct smb_share *ssp = np->n_mount->sm_share;
440 struct smb_vc *vcp = SSTOVC(ssp);
441 struct mbchain *mbp;
442 int64_t tm;
443 int error, tzoff;
445 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
446 scred, &t2p);
447 if (error)
448 return error;
449 mbp = &t2p->t2_tparam;
450 mb_init(mbp);
451 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
452 mb_put_uint32le(mbp, 0); /* MBZ */
453 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
454 if (error) {
455 smb_t2_done(t2p);
456 return error;
458 tzoff = vcp->vc_sopt.sv_tz;
459 mbp = &t2p->t2_tdata;
460 mb_init(mbp);
461 mb_put_int64le(mbp, 0); /* creation time */
462 if (atime) {
463 smb_time_local2NT(atime, tzoff, &tm);
464 } else
465 tm = 0;
466 mb_put_int64le(mbp, tm);
467 if (mtime) {
468 smb_time_local2NT(mtime, tzoff, &tm);
469 } else
470 tm = 0;
471 mb_put_int64le(mbp, tm);
472 mb_put_int64le(mbp, tm); /* change time */
473 mb_put_uint32le(mbp, attr); /* attr */
474 t2p->t2_maxpcount = 24;
475 t2p->t2_maxdcount = 56;
476 error = smb_t2_request(t2p);
477 smb_t2_done(t2p);
478 return error;
480 #endif
483 * Set file atime and mtime. Doesn't supported by core dialect.
486 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
487 struct timespec *atime, struct smb_cred *scred)
489 struct smb_rq *rqp;
490 struct smb_share *ssp = np->n_mount->sm_share;
491 struct mbchain *mbp;
492 u_int16_t xdate, xtime;
493 int error, tzoff;
495 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred, &rqp);
496 if (error)
497 return error;
498 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
499 smb_rq_getrequest(rqp, &mbp);
500 smb_rq_wstart(rqp);
501 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
502 mb_put_uint32le(mbp, 0); /* creation time */
504 if (atime)
505 smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL);
506 else
507 xtime = xdate = 0;
508 mb_put_uint16le(mbp, xdate);
509 mb_put_uint16le(mbp, xtime);
510 if (mtime)
511 smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL);
512 else
513 xtime = xdate = 0;
514 mb_put_uint16le(mbp, xdate);
515 mb_put_uint16le(mbp, xtime);
516 smb_rq_wend(rqp);
517 smb_rq_bstart(rqp);
518 smb_rq_bend(rqp);
519 error = smb_rq_simple(rqp);
520 SMBSDEBUG(("%d\n", error));
521 smb_rq_done(rqp);
522 return error;
526 * Set DOS file attributes.
527 * Looks like this call can be used only if CAP_NT_SMBS bit is on.
530 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
531 struct timespec *atime, struct smb_cred *scred)
533 struct smb_t2rq *t2p;
534 struct smb_share *ssp = np->n_mount->sm_share;
535 struct mbchain *mbp;
536 int64_t tm;
537 int error, svtz;
539 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
540 scred, &t2p);
541 if (error)
542 return error;
543 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
544 mbp = &t2p->t2_tparam;
545 mb_init(mbp);
546 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); /* FID */
547 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); /* info level */
548 mb_put_uint32le(mbp, 0); /* reserved */
549 mbp = &t2p->t2_tdata;
550 mb_init(mbp);
551 mb_put_int64le(mbp, 0); /* creation time */
552 if (atime) {
553 smb_time_local2NT(atime, svtz, &tm);
554 } else
555 tm = 0;
556 mb_put_int64le(mbp, tm);
557 if (mtime) {
558 smb_time_local2NT(mtime, svtz, &tm);
559 } else
560 tm = 0;
561 mb_put_int64le(mbp, tm);
562 mb_put_int64le(mbp, tm); /* change time */
563 mb_put_uint16le(mbp, attr);
564 mb_put_uint32le(mbp, 0); /* padding */
565 mb_put_uint16le(mbp, 0);
566 t2p->t2_maxpcount = 2;
567 t2p->t2_maxdcount = 0;
568 error = smb_t2_request(t2p);
569 smb_t2_done(t2p);
570 return error;
575 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
577 struct smb_rq *rqp;
578 struct smb_share *ssp = np->n_mount->sm_share;
579 struct mbchain *mbp;
580 struct mdchain *mdp;
581 u_int8_t wc;
582 u_int16_t fid, wattr, grantedmode;
583 int error;
585 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
586 if (error)
587 return error;
588 smb_rq_getrequest(rqp, &mbp);
589 smb_rq_wstart(rqp);
590 mb_put_uint16le(mbp, accmode);
591 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
592 smb_rq_wend(rqp);
593 smb_rq_bstart(rqp);
594 mb_put_uint8(mbp, SMB_DT_ASCII);
595 do {
596 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
597 if (error)
598 break;
599 smb_rq_bend(rqp);
600 error = smb_rq_simple(rqp);
601 if (error)
602 break;
603 smb_rq_getreply(rqp, &mdp);
604 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
605 error = EBADRPC;
606 break;
608 md_get_uint16(mdp, &fid);
609 md_get_uint16le(mdp, &wattr);
610 md_get_uint32(mdp, NULL); /* mtime */
611 md_get_uint32(mdp, NULL); /* fsize */
612 md_get_uint16le(mdp, &grantedmode);
614 * TODO: refresh attributes from this reply
616 } while(0);
617 smb_rq_done(rqp);
618 if (error)
619 return error;
620 np->n_fid = fid;
621 np->n_rwstate = grantedmode;
622 return 0;
627 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
628 struct smb_cred *scred)
630 struct smb_rq *rqp;
631 struct mbchain *mbp;
632 u_long xtime;
633 int error;
635 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
636 if (error)
637 return error;
638 smb_rq_getrequest(rqp, &mbp);
639 smb_rq_wstart(rqp);
640 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM);
641 if (mtime) {
642 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &xtime);
643 } else
644 xtime = 0;
645 mb_put_uint32le(mbp, xtime);
646 smb_rq_wend(rqp);
647 smb_rq_bstart(rqp);
648 smb_rq_bend(rqp);
649 error = smb_rq_simple(rqp);
650 smb_rq_done(rqp);
651 return error;
655 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
656 struct smb_cred *scred)
658 struct smb_rq *rqp;
659 struct smb_share *ssp = dnp->n_mount->sm_share;
660 struct mbchain *mbp;
661 struct mdchain *mdp;
662 struct timespec ctime;
663 u_int8_t wc;
664 u_int16_t fid;
665 u_long tm;
666 int error;
668 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_NEW, scred, &rqp);
669 if (error)
670 return error;
671 smb_rq_getrequest(rqp, &mbp);
673 /* get current time */
674 getnanotime(&ctime);
675 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
677 smb_rq_wstart(rqp);
678 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */
679 mb_put_uint32le(mbp, tm);
680 smb_rq_wend(rqp);
682 smb_rq_bstart(rqp);
683 mb_put_uint8(mbp, SMB_DT_ASCII);
684 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
685 if (!error) {
686 smb_rq_bend(rqp);
687 error = smb_rq_simple(rqp);
688 if (!error) {
689 smb_rq_getreply(rqp, &mdp);
690 md_get_uint8(mdp, &wc);
691 if (wc == 1)
692 md_get_uint16le(mdp, &fid);
693 else
694 error = EBADRPC;
698 smb_rq_done(rqp);
699 if (!error)
700 smbfs_smb_close(ssp, fid, &ctime, scred);
702 return (error);
706 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
708 struct smb_rq *rqp;
709 struct smb_share *ssp = np->n_mount->sm_share;
710 struct mbchain *mbp;
711 int error;
713 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
714 if (error)
715 return error;
716 smb_rq_getrequest(rqp, &mbp);
717 smb_rq_wstart(rqp);
718 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
719 smb_rq_wend(rqp);
720 smb_rq_bstart(rqp);
721 mb_put_uint8(mbp, SMB_DT_ASCII);
722 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
723 if (!error) {
724 smb_rq_bend(rqp);
725 error = smb_rq_simple(rqp);
727 smb_rq_done(rqp);
728 return error;
732 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
733 const char *tname, int tnmlen, struct smb_cred *scred)
735 struct smb_rq *rqp;
736 struct smb_share *ssp = src->n_mount->sm_share;
737 struct mbchain *mbp;
738 int error;
740 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
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 do {
750 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
751 if (error)
752 break;
753 mb_put_uint8(mbp, SMB_DT_ASCII);
754 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
755 if (error)
756 break;
757 smb_rq_bend(rqp);
758 error = smb_rq_simple(rqp);
759 } while(0);
760 smb_rq_done(rqp);
761 return error;
764 #ifdef notnow
766 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
767 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
769 struct smb_rq *rqp;
770 struct smb_share *ssp = src->n_mount->sm_share;
771 struct mbchain *mbp;
772 int error;
774 error = smb_rq_alloc(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
775 if (error)
776 return error;
777 smb_rq_getrequest(rqp, &mbp);
778 smb_rq_wstart(rqp);
779 mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
780 mb_put_uint16le(mbp, 0x20); /* delete target file */
781 mb_put_uint16le(mbp, flags);
782 smb_rq_wend(rqp);
783 smb_rq_bstart(rqp);
784 mb_put_uint8(mbp, SMB_DT_ASCII);
785 do {
786 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
787 if (error)
788 break;
789 mb_put_uint8(mbp, SMB_DT_ASCII);
790 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
791 if (error)
792 break;
793 smb_rq_bend(rqp);
794 error = smb_rq_simple(rqp);
795 } while(0);
796 smb_rq_done(rqp);
797 return error;
799 #endif
802 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
803 struct smb_cred *scred)
805 struct smb_rq *rqp;
806 struct smb_share *ssp = dnp->n_mount->sm_share;
807 struct mbchain *mbp;
808 int error;
810 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred, &rqp);
811 if (error)
812 return error;
813 smb_rq_getrequest(rqp, &mbp);
814 smb_rq_wstart(rqp);
815 smb_rq_wend(rqp);
816 smb_rq_bstart(rqp);
817 mb_put_uint8(mbp, SMB_DT_ASCII);
818 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
819 if (!error) {
820 smb_rq_bend(rqp);
821 error = smb_rq_simple(rqp);
823 smb_rq_done(rqp);
824 return error;
828 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
830 struct smb_rq *rqp;
831 struct smb_share *ssp = np->n_mount->sm_share;
832 struct mbchain *mbp;
833 int error;
835 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred, &rqp);
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), np, NULL, 0);
844 if (!error) {
845 smb_rq_bend(rqp);
846 error = smb_rq_simple(rqp);
848 smb_rq_done(rqp);
849 return error;
852 static int
853 smbfs_smb_search(struct smbfs_fctx *ctx)
855 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
856 struct smb_rq *rqp;
857 struct mbchain *mbp;
858 struct mdchain *mdp;
859 u_int8_t wc, bt;
860 u_int16_t ec, dlen, bc;
861 int maxent, error;
863 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
864 if (ctx->f_rq) {
865 smb_rq_done(ctx->f_rq);
866 ctx->f_rq = NULL;
868 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
869 if (error)
870 return error;
871 ctx->f_rq = rqp;
872 smb_rq_getrequest(rqp, &mbp);
873 smb_rq_wstart(rqp);
874 mb_put_uint16le(mbp, maxent); /* max entries to return */
875 mb_put_uint16le(mbp, ctx->f_attrmask);
876 smb_rq_wend(rqp);
877 smb_rq_bstart(rqp);
878 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
879 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
880 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
881 if (error)
882 return error;
883 mb_put_uint8(mbp, SMB_DT_VARIABLE);
884 mb_put_uint16le(mbp, 0); /* context length */
885 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
886 } else {
887 mb_put_uint8(mbp, 0); /* file name length */
888 mb_put_uint8(mbp, SMB_DT_VARIABLE);
889 mb_put_uint16le(mbp, SMB_SKEYLEN);
890 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
892 smb_rq_bend(rqp);
893 error = smb_rq_simple(rqp);
894 if (error) {
895 if (error == ENOENT)
896 ctx->f_flags |= SMBFS_RDD_EOF;
898 return error;
900 smb_rq_getreply(rqp, &mdp);
901 md_get_uint8(mdp, &wc);
902 if (wc != 1)
903 return EBADRPC;
904 md_get_uint16le(mdp, &ec);
905 if (ec == 0)
906 return ENOENT;
907 ctx->f_ecnt = ec;
908 md_get_uint16le(mdp, &bc);
909 if (bc < 3)
910 return EBADRPC;
911 bc -= 3;
912 md_get_uint8(mdp, &bt);
913 if (bt != SMB_DT_VARIABLE)
914 return EBADRPC;
915 md_get_uint16le(mdp, &dlen);
916 if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
917 return EBADRPC;
918 return 0;
921 static int
922 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
923 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
925 ctx->f_attrmask = attr;
926 if (wildcard) {
927 if (wclen == 1 && wildcard[0] == '*') {
928 ctx->f_wildcard = "*.*";
929 ctx->f_wclen = 3;
930 } else {
931 ctx->f_wildcard = wildcard;
932 ctx->f_wclen = wclen;
934 } else {
935 ctx->f_wildcard = NULL;
936 ctx->f_wclen = 0;
938 ctx->f_name = ctx->f_fname;
939 return 0;
942 static int
943 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
945 struct mdchain *mbp;
946 struct smb_rq *rqp;
947 char *cp;
948 u_int8_t battr;
949 u_int16_t xdate, xtime;
950 u_int32_t size;
951 int error;
953 if (ctx->f_ecnt == 0) {
954 if (ctx->f_flags & SMBFS_RDD_EOF)
955 return ENOENT;
956 ctx->f_left = ctx->f_limit = limit;
957 error = smbfs_smb_search(ctx);
958 if (error)
959 return error;
961 rqp = ctx->f_rq;
962 smb_rq_getreply(rqp, &mbp);
963 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
964 md_get_uint8(mbp, &battr);
965 md_get_uint16le(mbp, &xtime);
966 md_get_uint16le(mbp, &xdate);
967 md_get_uint32le(mbp, &size);
968 KASSERT(ctx->f_name == ctx->f_fname);
969 cp = ctx->f_name;
970 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
971 cp[sizeof(ctx->f_fname) - 1] = '\0';
972 cp += strlen(cp) - 1;
973 while(*cp == ' ' && cp > ctx->f_name)
974 *cp-- = '\0';
975 ctx->f_attr.fa_attr = battr;
976 smb_dos2unixtime(xdate, xtime, 0, rqp->sr_vc->vc_sopt.sv_tz,
977 &ctx->f_attr.fa_mtime);
978 ctx->f_attr.fa_size = size;
979 ctx->f_nmlen = strlen(ctx->f_name);
980 ctx->f_ecnt--;
981 ctx->f_left--;
982 return 0;
985 static int
986 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
988 if (ctx->f_rq)
989 smb_rq_done(ctx->f_rq);
990 return 0;
994 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
996 static int
997 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
999 struct smb_t2rq *t2p;
1000 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1001 struct mbchain *mbp;
1002 struct mdchain *mdp;
1003 u_int16_t tw, flags;
1004 int error;
1006 if (ctx->f_t2) {
1007 smb_t2_done(ctx->f_t2);
1008 ctx->f_t2 = NULL;
1010 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1011 flags = 8 | 2; /* <resume> | <close if EOS> */
1012 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1013 flags |= 1; /* close search after this request */
1014 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1016 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1017 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1018 ctx->f_scred, &t2p);
1019 if (error)
1020 return error;
1021 ctx->f_t2 = t2p;
1022 mbp = &t2p->t2_tparam;
1023 mb_init(mbp);
1024 mb_put_uint16le(mbp, ctx->f_attrmask);
1025 mb_put_uint16le(mbp, ctx->f_limit);
1026 mb_put_uint16le(mbp, flags);
1027 mb_put_uint16le(mbp, ctx->f_infolevel);
1028 mb_put_uint32le(mbp, 0);
1029 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1030 if (error)
1031 return error;
1032 } else {
1033 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1034 ctx->f_scred, &t2p);
1035 if (error)
1036 return error;
1037 ctx->f_t2 = t2p;
1038 mbp = &t2p->t2_tparam;
1039 mb_init(mbp);
1040 mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM);
1041 mb_put_uint16le(mbp, ctx->f_limit);
1042 mb_put_uint16le(mbp, ctx->f_infolevel);
1043 mb_put_uint32le(mbp, 0); /* resume key */
1044 mb_put_uint16le(mbp, flags);
1045 if (ctx->f_rname)
1046 mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
1047 else
1048 mb_put_uint8(mbp, 0); /* resume file name */
1049 #if 0
1050 struct timeval tv;
1051 tv.tv_sec = 0;
1052 tv.tv_usec = 200 * 1000; /* 200ms */
1053 if (vcp->vc_flags & SMBC_WIN95) {
1055 * some implementations suggests to sleep here
1056 * for 200ms, due to the bug in the Win95.
1057 * I've didn't notice any problem, but put code
1058 * for it.
1060 tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
1062 #endif
1064 t2p->t2_maxpcount = 5 * 2;
1065 t2p->t2_maxdcount = vcp->vc_txmax;
1066 error = smb_t2_request(t2p);
1067 if (error)
1068 return error;
1069 mdp = &t2p->t2_rparam;
1070 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1071 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1072 return error;
1073 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1075 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1076 return error;
1077 ctx->f_ecnt = tw;
1078 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1079 return error;
1080 if (tw)
1081 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1082 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1083 return error;
1084 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1085 return error;
1086 if (ctx->f_ecnt == 0) {
1087 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1088 return ENOENT;
1090 ctx->f_rnameofs = tw;
1091 mdp = &t2p->t2_rdata;
1093 KASSERT(mdp->md_top != NULL);
1094 KASSERT(mdp->md_top->m_len != 0);
1096 ctx->f_eofs = 0;
1097 return 0;
1100 static int
1101 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1103 struct smb_rq *rqp;
1104 struct mbchain *mbp;
1105 int error;
1107 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred, &rqp);
1108 if (error)
1109 return error;
1110 smb_rq_getrequest(rqp, &mbp);
1111 smb_rq_wstart(rqp);
1112 mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM);
1113 smb_rq_wend(rqp);
1114 smb_rq_bstart(rqp);
1115 smb_rq_bend(rqp);
1116 error = smb_rq_simple(rqp);
1117 smb_rq_done(rqp);
1118 return error;
1121 static int
1122 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1123 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1125 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1126 if (ctx->f_name == NULL)
1127 return ENOMEM;
1128 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1129 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1130 ctx->f_attrmask = attr;
1131 ctx->f_wildcard = wildcard;
1132 ctx->f_wclen = wclen;
1133 return 0;
1136 static int
1137 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1139 struct mdchain *mbp;
1140 struct smb_t2rq *t2p;
1141 char *cp;
1142 u_int8_t tb;
1143 u_int16_t xdate, xtime, wattr;
1144 u_int32_t size, next, dattr;
1145 int64_t tmp;
1146 int error, svtz, cnt, fxsz, nmlen, recsz;
1148 if (ctx->f_ecnt == 0) {
1149 if (ctx->f_flags & SMBFS_RDD_EOF)
1150 return ENOENT;
1151 ctx->f_left = ctx->f_limit = limit;
1152 error = smbfs_smb_trans2find2(ctx);
1153 if (error)
1154 return error;
1156 t2p = ctx->f_t2;
1157 mbp = &t2p->t2_rdata;
1158 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1159 switch (ctx->f_infolevel) {
1160 case SMB_INFO_STANDARD:
1161 next = 0;
1162 fxsz = 0;
1163 md_get_uint16le(mbp, &xdate);
1164 md_get_uint16le(mbp, &xtime); /* creation time */
1165 md_get_uint16le(mbp, &xdate);
1166 md_get_uint16le(mbp, &xtime); /* access time */
1167 smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_atime);
1168 md_get_uint16le(mbp, &xdate);
1169 md_get_uint16le(mbp, &xtime); /* access time */
1170 smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_mtime);
1171 md_get_uint32le(mbp, &size);
1172 ctx->f_attr.fa_size = size;
1173 md_get_uint32(mbp, NULL); /* allocation size */
1174 md_get_uint16le(mbp, &wattr);
1175 ctx->f_attr.fa_attr = wattr;
1176 md_get_uint8(mbp, &tb);
1177 size = nmlen = tb;
1178 fxsz = 23;
1179 recsz = next = 24 + nmlen; /* docs misses zero byte at end */
1180 break;
1181 case SMB_FIND_FILE_DIRECTORY_INFO:
1182 md_get_uint32le(mbp, &next);
1183 md_get_uint32(mbp, NULL); /* file index */
1184 md_get_int64(mbp, NULL); /* creation time */
1185 md_get_int64le(mbp, &tmp);
1186 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_atime);
1187 md_get_int64le(mbp, &tmp);
1188 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_mtime);
1189 md_get_int64le(mbp, &tmp);
1190 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_ctime);
1191 md_get_int64le(mbp, &tmp); /* file size */
1192 ctx->f_attr.fa_size = tmp;
1193 md_get_int64(mbp, NULL); /* real size (should use) */
1194 md_get_uint32le(mbp, &dattr); /* EA */
1195 ctx->f_attr.fa_attr = dattr;
1196 md_get_uint32le(mbp, &size); /* name len */
1197 fxsz = 64;
1198 recsz = next ? next : fxsz + size;
1199 break;
1200 default:
1201 #ifdef DIAGNOSTIC
1202 panic("smbfs_findnextLM2: unexpected info level %d\n",
1203 ctx->f_infolevel);
1204 #else
1205 return EINVAL;
1206 #endif
1208 nmlen = min(size, SMB_MAXFNAMELEN);
1209 cp = ctx->f_name;
1210 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1211 if (error)
1212 return error;
1213 if (next) {
1214 cnt = next - nmlen - fxsz;
1215 if (cnt > 0)
1216 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1217 #ifdef DIAGNOSTIC
1218 else if (cnt < 0)
1219 panic("smbfs_findnextLM2: out of sync");
1220 #endif
1222 if (nmlen && cp[nmlen - 1] == 0)
1223 nmlen--;
1224 if (nmlen == 0)
1225 return EBADRPC;
1227 next = ctx->f_eofs + recsz;
1228 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1229 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1231 * Server needs a resume filename.
1233 if (ctx->f_rnamelen <= nmlen) {
1234 if (ctx->f_rname)
1235 free(ctx->f_rname, M_SMBFSDATA);
1236 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1237 ctx->f_rnamelen = nmlen;
1239 memcpy(ctx->f_rname, ctx->f_name, nmlen);
1240 ctx->f_rname[nmlen] = 0;
1241 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1243 ctx->f_nmlen = nmlen;
1244 ctx->f_eofs = next;
1245 ctx->f_ecnt--;
1246 ctx->f_left--;
1247 return 0;
1250 static int
1251 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1253 if (ctx->f_name)
1254 free(ctx->f_name, M_SMBFSDATA);
1255 if (ctx->f_t2)
1256 smb_t2_done(ctx->f_t2);
1257 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1258 smbfs_smb_findclose2(ctx);
1259 return 0;
1263 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1264 struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1266 struct smbfs_fctx *ctx;
1267 int error;
1269 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK|M_ZERO);
1270 ctx->f_ssp = dnp->n_mount->sm_share;
1271 ctx->f_dnp = dnp;
1272 ctx->f_flags = SMBFS_RDD_FINDFIRST;
1273 ctx->f_scred = scred;
1274 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1275 (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) {
1276 ctx->f_flags |= SMBFS_RDD_USESEARCH;
1277 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1278 } else
1279 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1280 if (error)
1281 smbfs_findclose(ctx, scred);
1282 else
1283 *ctxpp = ctx;
1284 return error;
1288 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1290 int error;
1292 if (limit == 0)
1293 limit = 1000000;
1294 else if (limit > 1)
1295 limit *= 4; /* empirical */
1296 ctx->f_scred = scred;
1297 for (;;) {
1298 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1299 error = smbfs_findnextLM1(ctx, limit);
1300 } else
1301 error = smbfs_findnextLM2(ctx, limit);
1302 if (error)
1303 return error;
1305 /* Skip '.' and '..' */
1306 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1307 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1308 ctx->f_name[1] == '.'))
1309 continue;
1310 break;
1312 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen,
1313 ctx->f_dnp->n_mount->sm_caseopt);
1314 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1315 return 0;
1319 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1321 ctx->f_scred = scred;
1322 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1323 smbfs_findcloseLM1(ctx);
1324 } else
1325 smbfs_findcloseLM2(ctx);
1326 if (ctx->f_rname)
1327 free(ctx->f_rname, M_SMBFSDATA);
1328 free(ctx, M_SMBFSDATA);
1329 return 0;
1333 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1334 struct smbfattr *fap, struct smb_cred *scred)
1336 struct smbfs_fctx *ctx;
1337 int error;
1339 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1340 memset(fap, 0, sizeof(*fap));
1341 fap->fa_attr = SMB_FA_DIR;
1342 fap->fa_ino = 2;
1343 return 0;
1345 if (nmlen == 1 && name[0] == '.') {
1346 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
1347 return error;
1348 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1349 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0,
1350 fap, scred);
1351 printf("%s: knows NOTHING about '..'\n", __func__);
1352 return error;
1354 error = smbfs_findopen(dnp, name, nmlen,
1355 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1356 if (error)
1357 return error;
1358 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1359 error = smbfs_findnext(ctx, 1, scred);
1360 if (error == 0) {
1361 *fap = ctx->f_attr;
1362 if (name == NULL)
1363 fap->fa_ino = dnp->n_ino;
1366 * Check the returned file name case exactly
1367 * matches requested file name. ctx->f_nmlen is
1368 * guaranteed to always match nmlen.
1370 if (nmlen > 0 && strncmp(name, ctx->f_name, nmlen) != 0)
1371 error = ENOENT;
1373 smbfs_findclose(ctx, scred);
1374 return error;
1378 * This call is used to fetch FID for directories. For normal files,
1379 * SMB_COM_OPEN is used.
1382 smbfs_smb_ntcreatex(struct smbnode *np, int accmode,
1383 struct smb_cred *scred)
1385 struct smb_rq *rqp;
1386 struct smb_share *ssp = np->n_mount->sm_share;
1387 struct mbchain *mbp;
1388 struct mdchain *mdp;
1389 int error;
1390 u_int8_t wc;
1391 u_int8_t *nmlen;
1392 u_int16_t flen;
1394 KASSERT(SMBTOV(np)->v_type == VDIR);
1396 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp);
1397 if (error)
1398 return error;
1399 smb_rq_getrequest(rqp, &mbp);
1400 smb_rq_wstart(rqp);
1401 mb_put_uint8(mbp, 0xff); /* Secondary command; 0xFF = None */
1402 mb_put_uint8(mbp, 0); /* Reserved (must be 0) */
1403 mb_put_uint16le(mbp, 0); /* Off to next cmd WordCount */
1404 mb_put_uint8(mbp, 0); /* Reserved (must be 0) */
1405 nmlen = mb_reserve(mbp, sizeof(u_int16_t));
1406 /* Length of Name[] in bytes */
1407 mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES);
1408 /* Flags - Create bit set */
1409 mb_put_uint32le(mbp, 0); /* If nonzero, open relative to this */
1410 mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY); /* Access mask */
1411 mb_put_uint32le(mbp, 0); /* Low 32bit */
1412 mb_put_uint32le(mbp, 0); /* Hi 32bit */
1413 /* Initial allocation size */
1414 mb_put_uint32le(mbp, 0); /* File attributes */
1415 mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE);
1416 /* Type of share access */
1417 mb_put_uint32le(mbp, NT_OPEN_EXISTING);
1418 /* Create disposition - just open */
1419 mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE);
1420 /* Options to use if creating a file */
1421 mb_put_uint32le(mbp, 0); /* Security QOS information */
1422 mb_put_uint8(mbp, 0); /* Security tracking mode flags */
1423 smb_rq_wend(rqp);
1424 smb_rq_bstart(rqp);
1425 smb_rq_bend(rqp);
1426 mbp->mb_count = 0;
1428 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
1429 if (error)
1430 return error;
1432 /* Windows XP seems to include the final zero. Better do that too. */
1433 mb_put_uint8(mbp, 0);
1435 flen = mbp->mb_count;
1436 SMBRQ_PUTLE16(nmlen, flen);
1438 error = smb_rq_simple(rqp);
1439 if (error)
1440 goto bad;
1442 smb_rq_getreply(rqp, &mdp);
1443 md_get_uint8(mdp, &wc); /* WordCount - check? */
1444 md_get_uint8(mdp, NULL); /* AndXCommand */
1445 md_get_uint8(mdp, NULL); /* Reserved - must be zero */
1446 md_get_uint16(mdp, NULL); /* Offset to next cmd WordCount */
1447 md_get_uint8(mdp, NULL); /* Oplock level granted */
1448 md_get_uint16(mdp, &np->n_fid); /* FID */
1449 /* ignore rest */
1451 bad:
1452 smb_rq_done(rqp);
1453 return (error);
1457 * Setup a request for NT DIRECTORY CHANGE NOTIFY.
1460 smbfs_smb_nt_dirnotify_setup(struct smbnode *dnp, struct smb_rq **rqpp, struct smb_cred *scred, void (*notifyhook)(void *), void *notifyarg)
1462 struct smb_rq *rqp;
1463 struct smb_share *ssp = dnp->n_mount->sm_share;
1464 struct mbchain *mbp;
1465 int error;
1467 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_TRANSACT, scred, &rqp);
1468 if (error)
1469 return error;
1470 smb_rq_getrequest(rqp, &mbp);
1471 smb_rq_wstart(rqp);
1472 mb_put_uint8(mbp, 0xff); /* Max setup words to return */
1473 mb_put_uint16le(mbp, 0); /* Flags (according to Samba) */
1474 mb_put_uint32le(mbp, 0); /* Total parameter bytes being sent*/
1475 mb_put_uint32le(mbp, 0); /* Total data bytes being sent */
1476 mb_put_uint32le(mbp, 10*1024); /* Max parameter bytes to return */
1477 mb_put_uint32le(mbp, 0); /* Max data bytes to return */
1478 mb_put_uint32le(mbp, 0); /* Parameter bytes sent this buffer */
1479 mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Param */
1480 mb_put_uint32le(mbp, 0); /* Data bytes sent this buffer */
1481 mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Data */
1482 mb_put_uint8(mbp, 4); /* Count of setup words */
1483 mb_put_uint16le(mbp, SMB_NTTRANS_NOTIFY_CHANGE); /* Trans func code */
1485 /* NT TRANSACT NOTIFY CHANGE: Request Change Notification */
1486 mb_put_uint32le(mbp,
1487 FILE_NOTIFY_CHANGE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|
1488 FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE|
1489 FILE_NOTIFY_CHANGE_CREATION); /* CompletionFilter */
1490 mb_put_mem(mbp, (void *)&dnp->n_fid, 2, MB_MSYSTEM); /* FID */
1491 mb_put_uint8(mbp, 0); /* WatchTree - Watch all subdirs too */
1492 mb_put_uint8(mbp, 0); /* Reserved - must be zero */
1493 smb_rq_wend(rqp);
1494 smb_rq_bstart(rqp);
1495 smb_rq_bend(rqp);
1497 /* No timeout */
1498 rqp->sr_timo = -1;
1499 smb_rq_setcallback(rqp, notifyhook, notifyarg);
1501 error = smb_rq_enqueue(rqp);
1502 if (!error)
1503 *rqpp = rqp;
1504 else
1505 smb_rq_done(rqp);
1507 return (error);
1511 smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint)
1513 int error;
1514 struct mdchain *mdp;
1515 u_int8_t sc;
1516 u_int32_t nextentry;
1518 error = smb_rq_reply(rqp);
1519 if (error) {
1521 * If we get EMSGSIZE, there is already too many notifications
1522 * available for the directory, and the internal buffer
1523 * overflew. Just flag any possible relevant change.
1525 if (error == EMSGSIZE) {
1526 *hint = NOTE_ATTRIB | NOTE_WRITE;
1527 error = 0;
1530 goto bad;
1533 smb_rq_getreply(rqp, &mdp);
1535 /* Parse reply */
1536 error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO); /* skip */
1537 if (error)
1538 goto bad;
1540 md_get_uint8(mdp, &sc); /* SetupCount */
1541 if (sc > 0)
1542 md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO);
1543 md_get_uint16(mdp, NULL); /* ByteCount */
1544 md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO); /* Pad */
1547 * The notify data are blocks of
1548 * ULONG nextentry - offset of next entry from start of this one
1549 * ULONG action - type of notification
1550 * ULONG filenamelen - length of filename in bytes
1551 * WCHAR filename[filenamelen/2] - Unicode filename
1552 * nexentry == 0 means last notification, filename is in 16bit LE
1553 * unicode
1555 *hint = 0;
1556 do {
1557 u_int32_t action;
1558 #if 0
1559 u_int32_t fnlen;
1560 u_int16_t fnc;
1561 #endif
1563 md_get_uint32le(mdp, &nextentry);
1564 md_get_uint32le(mdp, &action);
1565 if (nextentry)
1566 md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO);
1567 #if 0
1568 md_get_uint32le(mdp, &fnlen);
1570 printf("notify: next %u act %u fnlen %u fname '",
1571 nextentry, action, fnlen);
1572 for(; fnlen > 0; fnlen -= 2) {
1573 md_get_uint16le(mdp, &fnc);
1574 printf("%c", fnc&0xff);
1576 printf("'\n");
1577 #endif
1579 switch(action) {
1580 case FILE_ACTION_ADDED:
1581 case FILE_ACTION_REMOVED:
1582 case FILE_ACTION_RENAMED_OLD_NAME:
1583 case FILE_ACTION_RENAMED_NEW_NAME:
1584 *hint |= NOTE_ATTRIB | NOTE_WRITE;
1585 break;
1587 case FILE_ACTION_MODIFIED:
1588 *hint |= NOTE_ATTRIB;
1589 break;
1591 } while(nextentry > 0);
1593 bad:
1594 smb_rq_done(rqp);
1595 return error;
1599 * Cancel previous SMB, with message ID mid. No reply is generated
1600 * to this one (only the previous message returns with error).
1603 smbfs_smb_ntcancel(struct smb_connobj *layer, u_int16_t mid, struct smb_cred *scred)
1605 struct smb_rq *rqp;
1606 struct mbchain *mbp;
1607 struct mbuf *m;
1608 u_int8_t *mp;
1609 int error;
1611 error = smb_rq_alloc(layer, SMB_COM_NT_CANCEL, scred, &rqp);
1612 if (error)
1613 return (error);
1614 rqp->sr_flags |= SMBR_NOWAIT; /* do not wait for reply */
1615 smb_rq_getrequest(rqp, &mbp);
1618 * This is nonstandard. We need to rewrite the just written
1619 * mid to different one. Access underlying mbuf directly.
1620 * We assume mid is the last thing written smb_rq_alloc()
1621 * to request buffer.
1623 m = mbp->mb_cur;
1624 mp = mtod(m, u_int8_t *) + m->m_len - 2;
1625 SMBRQ_PUTLE16(mp, mid);
1626 rqp->sr_mid = mid;
1628 smb_rq_wstart(rqp);
1629 smb_rq_wend(rqp);
1630 smb_rq_bstart(rqp);
1631 smb_rq_bend(rqp);
1633 error = (smb_rq_simple(rqp));
1635 /* Discard, there is no real reply */
1636 smb_rq_done(rqp);
1638 return (error);