2 * Copyright (c) 2000-2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $FreeBSD: src/sys/fs/smbfs/smbfs_smb.c,v 1.1.2.2 2003/01/17 08:20:26 tjr Exp $
33 * $DragonFly: src/sys/vfs/smbfs/smbfs_smb.c,v 1.11 2008/01/06 16:55:53 swildner Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
41 #include <sys/vnode.h>
43 #include <sys/mount.h>
49 #include <netproto/smb/smb.h>
50 #include <netproto/smb/smb_subr.h>
51 #include <netproto/smb/smb_rq.h>
52 #include <netproto/smb/smb_conn.h>
55 #include "smbfs_node.h"
56 #include "smbfs_subr.h"
59 * Lack of inode numbers leads us to the problem of generating them.
60 * Partially this problem can be solved by having a dir/file cache
61 * with inode numbers generated from the incremented by one counter.
62 * However this way will require too much kernel memory, gives all
63 * sorts of locking and consistency problems, not to mentinon counter overflows.
64 * So, I'm decided to use a hash function to generate pseudo random (and unique)
68 smbfs_getino(struct smbnode
*dnp
, const char *name
, int nmlen
)
77 MD5Update(&md5
, name
, nmlen
);
78 MD5Final((u_char
*)state
, &md5
);
79 for (i
= 0, ino
= 0; i
< 4; i
++)
81 return dnp
->n_ino
+ ino
;
85 ino
= dnp
->n_ino
+ smbfs_hash(name
, nmlen
);
92 smbfs_smb_lockandx(struct smbnode
*np
, int op
, u_int32_t pid
, off_t start
, off_t end
,
93 struct smb_cred
*scred
)
95 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
96 struct smb_rq rq
, *rqp
= &rq
;
101 if (op
== SMB_LOCK_SHARED
)
102 ltype
|= SMB_LOCKING_ANDX_SHARED_LOCK
;
103 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_LOCKING_ANDX
, scred
);
106 smb_rq_getrequest(rqp
, &mbp
);
108 mb_put_uint8(mbp
, 0xff); /* secondary command */
109 mb_put_uint8(mbp
, 0); /* MBZ */
110 mb_put_uint16le(mbp
, 0);
111 mb_put_mem(mbp
, (caddr_t
)&np
->n_fid
, 2, MB_MSYSTEM
);
112 mb_put_uint8(mbp
, ltype
); /* locktype */
113 mb_put_uint8(mbp
, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
114 mb_put_uint32le(mbp
, 0); /* timeout - break immediately */
115 mb_put_uint16le(mbp
, op
== SMB_LOCK_RELEASE
? 1 : 0);
116 mb_put_uint16le(mbp
, op
== SMB_LOCK_RELEASE
? 0 : 1);
119 mb_put_uint16le(mbp
, pid
);
120 mb_put_uint32le(mbp
, start
);
121 mb_put_uint32le(mbp
, end
- start
);
123 error
= smb_rq_simple(rqp
);
129 smbfs_smb_lock(struct smbnode
*np
, int op
, caddr_t id
,
130 off_t start
, off_t end
, struct smb_cred
*scred
)
132 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
134 if (SMB_DIALECT(SSTOVC(ssp
)) < SMB_DIALECT_LANMAN1_0
)
136 * TODO: use LOCK_BYTE_RANGE here.
140 return smbfs_smb_lockandx(np
, op
, (u_int32_t
)(uintptr_t)id
,
145 smbfs_smb_statfs2(struct smb_share
*ssp
, struct statfs
*sbp
,
146 struct smb_cred
*scred
)
148 struct smb_t2rq
*t2p
;
152 u_int32_t units
, bpu
, funits
;
155 error
= smb_t2_alloc(SSTOCP(ssp
), SMB_TRANS2_QUERY_FS_INFORMATION
,
159 mbp
= &t2p
->t2_tparam
;
161 mb_put_uint16le(mbp
, SMB_INFO_ALLOCATION
);
162 t2p
->t2_maxpcount
= 4;
163 t2p
->t2_maxdcount
= 4 * 4 + 2;
164 error
= smb_t2_request(t2p
);
169 mdp
= &t2p
->t2_rdata
;
170 md_get_uint32(mdp
, NULL
); /* fs id */
171 md_get_uint32le(mdp
, &bpu
);
172 md_get_uint32le(mdp
, &units
);
173 md_get_uint32le(mdp
, &funits
);
174 md_get_uint16le(mdp
, &bsize
);
175 sbp
->f_bsize
= bpu
* bsize
; /* fundamental file system block size */
176 sbp
->f_blocks
= units
; /* total data blocks in file system */
177 sbp
->f_bfree
= funits
; /* free blocks in fs */
178 sbp
->f_bavail
= funits
; /* free blocks avail to non-superuser */
179 sbp
->f_files
= 0xffff; /* total file nodes in file system */
180 sbp
->f_ffree
= 0xffff; /* free file nodes in fs */
186 smbfs_smb_statfs(struct smb_share
*ssp
, struct statfs
*sbp
,
187 struct smb_cred
*scred
)
189 struct smb_rq rq
, *rqp
= &rq
;
191 u_int16_t units
, bpu
, bsize
, funits
;
194 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_QUERY_INFORMATION_DISK
, scred
);
201 error
= smb_rq_simple(rqp
);
206 smb_rq_getreply(rqp
, &mdp
);
207 md_get_uint16le(mdp
, &units
);
208 md_get_uint16le(mdp
, &bpu
);
209 md_get_uint16le(mdp
, &bsize
);
210 md_get_uint16le(mdp
, &funits
);
211 sbp
->f_bsize
= bpu
* bsize
; /* fundamental file system block size */
212 sbp
->f_blocks
= units
; /* total data blocks in file system */
213 sbp
->f_bfree
= funits
; /* free blocks in fs */
214 sbp
->f_bavail
= funits
; /* free blocks avail to non-superuser */
215 sbp
->f_files
= 0xffff; /* total file nodes in file system */
216 sbp
->f_ffree
= 0xffff; /* free file nodes in fs */
222 smbfs_smb_setfsize(struct smbnode
*np
, int newsize
, struct smb_cred
*scred
)
224 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
225 struct smb_rq rq
, *rqp
= &rq
;
229 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_WRITE
, scred
);
232 smb_rq_getrequest(rqp
, &mbp
);
234 mb_put_mem(mbp
, (caddr_t
)&np
->n_fid
, 2, MB_MSYSTEM
);
235 mb_put_uint16le(mbp
, 0);
236 mb_put_uint32le(mbp
, newsize
);
237 mb_put_uint16le(mbp
, 0);
240 mb_put_uint8(mbp
, SMB_DT_DATA
);
241 mb_put_uint16le(mbp
, 0);
243 error
= smb_rq_simple(rqp
);
250 * Set DOS file attributes. mtime should be NULL for dialects above lm10
253 smbfs_smb_setpattr(struct smbnode
*np
, u_int16_t attr
, struct timespec
*mtime
,
254 struct smb_cred
*scred
)
256 struct smb_rq rq
, *rqp
= &rq
;
257 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
262 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_SET_INFORMATION
, scred
);
265 svtz
= SSTOVC(ssp
)->vc_sopt
.sv_tz
;
266 smb_rq_getrequest(rqp
, &mbp
);
268 mb_put_uint16le(mbp
, attr
);
270 smb_time_local2server(mtime
, svtz
, &time
);
273 mb_put_uint32le(mbp
, time
); /* mtime */
274 mb_put_mem(mbp
, NULL
, 5 * 2, MB_MZERO
);
277 mb_put_uint8(mbp
, SMB_DT_ASCII
);
279 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), np
, NULL
, 0);
282 mb_put_uint8(mbp
, SMB_DT_ASCII
);
283 mb_put_uint8(mbp
, 0);
285 error
= smb_rq_simple(rqp
);
286 SMBERROR("%d\n", error
);
295 * Note, win95 doesn't support this call.
298 smbfs_smb_setptime2(struct smbnode
*np
, struct timespec
*mtime
,
299 struct timespec
*atime
, int attr
, struct smb_cred
*scred
)
301 struct smb_t2rq
*t2p
;
302 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
303 struct smb_vc
*vcp
= SSTOVC(ssp
);
305 u_int16_t date
, time
;
308 error
= smb_t2_alloc(SSTOCP(ssp
), SMB_TRANS2_SET_PATH_INFORMATION
,
312 mbp
= &t2p
->t2_tparam
;
314 mb_put_uint16le(mbp
, SMB_INFO_STANDARD
);
315 mb_put_uint32le(mbp
, 0); /* MBZ */
316 error
= smbfs_fullpath(mbp
, vcp
, np
, NULL
, 0);
321 tzoff
= vcp
->vc_sopt
.sv_tz
;
322 mbp
= &t2p
->t2_tdata
;
324 mb_put_uint32le(mbp
, 0); /* creation time */
326 smb_time_unix2dos(atime
, tzoff
, &date
, &time
, NULL
);
329 mb_put_uint16le(mbp
, date
);
330 mb_put_uint16le(mbp
, time
);
332 smb_time_unix2dos(mtime
, tzoff
, &date
, &time
, NULL
);
335 mb_put_uint16le(mbp
, date
);
336 mb_put_uint16le(mbp
, time
);
337 mb_put_uint32le(mbp
, 0); /* file size */
338 mb_put_uint32le(mbp
, 0); /* allocation unit size */
339 mb_put_uint16le(mbp
, attr
); /* DOS attr */
340 mb_put_uint32le(mbp
, 0); /* EA size */
341 t2p
->t2_maxpcount
= 5 * 2;
342 t2p
->t2_maxdcount
= vcp
->vc_txmax
;
343 error
= smb_t2_request(t2p
);
349 * NT level. Specially for win9x
352 smbfs_smb_setpattrNT(struct smbnode
*np
, u_short attr
, struct timespec
*mtime
,
353 struct timespec
*atime
, struct smb_cred
*scred
)
355 struct smb_t2rq
*t2p
;
356 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
357 struct smb_vc
*vcp
= SSTOVC(ssp
);
362 error
= smb_t2_alloc(SSTOCP(ssp
), SMB_TRANS2_SET_PATH_INFORMATION
,
366 mbp
= &t2p
->t2_tparam
;
368 mb_put_uint16le(mbp
, SMB_SET_FILE_BASIC_INFO
);
369 mb_put_uint32le(mbp
, 0); /* MBZ */
370 error
= smbfs_fullpath(mbp
, vcp
, np
, NULL
, 0);
375 tzoff
= vcp
->vc_sopt
.sv_tz
;
376 mbp
= &t2p
->t2_tdata
;
378 mb_put_int64le(mbp
, 0); /* creation time */
380 smb_time_local2NT(atime
, tzoff
, &tm
);
383 mb_put_int64le(mbp
, tm
);
385 smb_time_local2NT(mtime
, tzoff
, &tm
);
388 mb_put_int64le(mbp
, tm
);
389 mb_put_int64le(mbp
, tm
); /* change time */
390 mb_put_uint32le(mbp
, attr
); /* attr */
391 t2p
->t2_maxpcount
= 24;
392 t2p
->t2_maxdcount
= 56;
393 error
= smb_t2_request(t2p
);
399 * Set file atime and mtime. Doesn't supported by core dialect.
402 smbfs_smb_setftime(struct smbnode
*np
, struct timespec
*mtime
,
403 struct timespec
*atime
, struct smb_cred
*scred
)
405 struct smb_rq rq
, *rqp
= &rq
;
406 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
408 u_int16_t date
, time
;
411 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_SET_INFORMATION2
, scred
);
414 tzoff
= SSTOVC(ssp
)->vc_sopt
.sv_tz
;
415 smb_rq_getrequest(rqp
, &mbp
);
417 mb_put_mem(mbp
, (caddr_t
)&np
->n_fid
, 2, MB_MSYSTEM
);
418 mb_put_uint32le(mbp
, 0); /* creation time */
421 smb_time_unix2dos(atime
, tzoff
, &date
, &time
, NULL
);
424 mb_put_uint16le(mbp
, date
);
425 mb_put_uint16le(mbp
, time
);
427 smb_time_unix2dos(mtime
, tzoff
, &date
, &time
, NULL
);
430 mb_put_uint16le(mbp
, date
);
431 mb_put_uint16le(mbp
, time
);
435 error
= smb_rq_simple(rqp
);
436 SMBSDEBUG("%d\n", error
);
442 * Set DOS file attributes.
443 * Looks like this call can be used only if CAP_NT_SMBS bit is on.
446 smbfs_smb_setfattrNT(struct smbnode
*np
, u_int16_t attr
, struct timespec
*mtime
,
447 struct timespec
*atime
, struct smb_cred
*scred
)
449 struct smb_t2rq
*t2p
;
450 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
455 error
= smb_t2_alloc(SSTOCP(ssp
), SMB_TRANS2_SET_FILE_INFORMATION
,
459 svtz
= SSTOVC(ssp
)->vc_sopt
.sv_tz
;
460 mbp
= &t2p
->t2_tparam
;
462 mb_put_mem(mbp
, (caddr_t
)&np
->n_fid
, 2, MB_MSYSTEM
);
463 mb_put_uint16le(mbp
, SMB_SET_FILE_BASIC_INFO
);
464 mb_put_uint32le(mbp
, 0);
465 mbp
= &t2p
->t2_tdata
;
467 mb_put_int64le(mbp
, 0); /* creation time */
469 smb_time_local2NT(atime
, svtz
, &tm
);
472 mb_put_int64le(mbp
, tm
);
474 smb_time_local2NT(mtime
, svtz
, &tm
);
477 mb_put_int64le(mbp
, tm
);
478 mb_put_int64le(mbp
, tm
); /* change time */
479 mb_put_uint16le(mbp
, attr
);
480 mb_put_uint32le(mbp
, 0); /* padding */
481 mb_put_uint16le(mbp
, 0);
482 t2p
->t2_maxpcount
= 2;
483 t2p
->t2_maxdcount
= 0;
484 error
= smb_t2_request(t2p
);
491 smbfs_smb_open(struct smbnode
*np
, int accmode
, struct smb_cred
*scred
)
493 struct smb_rq rq
, *rqp
= &rq
;
494 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
498 u_int16_t fid
, wattr
, grantedmode
;
501 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_OPEN
, scred
);
504 smb_rq_getrequest(rqp
, &mbp
);
506 mb_put_uint16le(mbp
, accmode
);
507 mb_put_uint16le(mbp
, SMB_FA_SYSTEM
| SMB_FA_HIDDEN
);
510 mb_put_uint8(mbp
, SMB_DT_ASCII
);
512 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), np
, NULL
, 0);
516 error
= smb_rq_simple(rqp
);
519 smb_rq_getreply(rqp
, &mdp
);
520 if (md_get_uint8(mdp
, &wc
) != 0 || wc
!= 7) {
524 md_get_uint16(mdp
, &fid
);
525 md_get_uint16le(mdp
, &wattr
);
526 md_get_uint32(mdp
, NULL
); /* mtime */
527 md_get_uint32(mdp
, NULL
); /* fsize */
528 md_get_uint16le(mdp
, &grantedmode
);
530 * TODO: refresh attributes from this reply
537 np
->n_rwstate
= grantedmode
;
543 smbfs_smb_close(struct smb_share
*ssp
, u_int16_t fid
, struct timespec
*mtime
,
544 struct smb_cred
*scred
)
546 struct smb_rq rq
, *rqp
= &rq
;
551 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_CLOSE
, scred
);
554 smb_rq_getrequest(rqp
, &mbp
);
556 mb_put_mem(mbp
, (caddr_t
)&fid
, sizeof(fid
), MB_MSYSTEM
);
558 smb_time_local2server(mtime
, SSTOVC(ssp
)->vc_sopt
.sv_tz
, &time
);
561 mb_put_uint32le(mbp
, time
);
565 error
= smb_rq_simple(rqp
);
571 smbfs_smb_create(struct smbnode
*dnp
, const char *name
, int nmlen
,
572 struct smb_cred
*scred
)
574 struct smb_rq rq
, *rqp
= &rq
;
575 struct smb_share
*ssp
= dnp
->n_mount
->sm_share
;
578 struct timespec ctime
;
584 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_CREATE
, scred
);
587 smb_rq_getrequest(rqp
, &mbp
);
589 mb_put_uint16le(mbp
, SMB_FA_ARCHIVE
); /* attributes */
591 smb_time_local2server(&ctime
, SSTOVC(ssp
)->vc_sopt
.sv_tz
, &tm
);
592 mb_put_uint32le(mbp
, tm
);
595 mb_put_uint8(mbp
, SMB_DT_ASCII
);
596 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), dnp
, name
, nmlen
);
599 error
= smb_rq_simple(rqp
);
601 smb_rq_getreply(rqp
, &mdp
);
602 md_get_uint8(mdp
, &wc
);
604 md_get_uint16(mdp
, &fid
);
612 smbfs_smb_close(ssp
, fid
, &ctime
, scred
);
617 smbfs_smb_delete(struct smbnode
*np
, struct smb_cred
*scred
)
619 struct smb_rq rq
, *rqp
= &rq
;
620 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
624 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_DELETE
, scred
);
627 smb_rq_getrequest(rqp
, &mbp
);
629 mb_put_uint16le(mbp
, SMB_FA_SYSTEM
| SMB_FA_HIDDEN
);
632 mb_put_uint8(mbp
, SMB_DT_ASCII
);
633 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), np
, NULL
, 0);
636 error
= smb_rq_simple(rqp
);
643 smbfs_smb_rename(struct smbnode
*src
, struct smbnode
*tdnp
,
644 const char *tname
, int tnmlen
, struct smb_cred
*scred
)
646 struct smb_rq rq
, *rqp
= &rq
;
647 struct smb_share
*ssp
= src
->n_mount
->sm_share
;
651 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_RENAME
, scred
);
654 smb_rq_getrequest(rqp
, &mbp
);
656 mb_put_uint16le(mbp
, SMB_FA_SYSTEM
| SMB_FA_HIDDEN
);
659 mb_put_uint8(mbp
, SMB_DT_ASCII
);
661 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), src
, NULL
, 0);
664 mb_put_uint8(mbp
, SMB_DT_ASCII
);
665 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), tdnp
, tname
, tnmlen
);
669 error
= smb_rq_simple(rqp
);
676 smbfs_smb_move(struct smbnode
*src
, struct smbnode
*tdnp
,
677 const char *tname
, int tnmlen
, u_int16_t flags
, struct smb_cred
*scred
)
679 struct smb_rq rq
, *rqp
= &rq
;
680 struct smb_share
*ssp
= src
->n_mount
->sm_share
;
684 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_MOVE
, scred
);
687 smb_rq_getrequest(rqp
, &mbp
);
689 mb_put_uint16le(mbp
, SMB_TID_UNKNOWN
);
690 mb_put_uint16le(mbp
, 0x20); /* delete target file */
691 mb_put_uint16le(mbp
, flags
);
694 mb_put_uint8(mbp
, SMB_DT_ASCII
);
696 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), src
, NULL
, 0);
699 mb_put_uint8(mbp
, SMB_DT_ASCII
);
700 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), tdnp
, tname
, tnmlen
);
704 error
= smb_rq_simple(rqp
);
711 smbfs_smb_mkdir(struct smbnode
*dnp
, const char *name
, int len
,
712 struct smb_cred
*scred
)
714 struct smb_rq rq
, *rqp
= &rq
;
715 struct smb_share
*ssp
= dnp
->n_mount
->sm_share
;
719 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_CREATE_DIRECTORY
, scred
);
722 smb_rq_getrequest(rqp
, &mbp
);
726 mb_put_uint8(mbp
, SMB_DT_ASCII
);
727 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), dnp
, name
, len
);
730 error
= smb_rq_simple(rqp
);
737 smbfs_smb_rmdir(struct smbnode
*np
, struct smb_cred
*scred
)
739 struct smb_rq rq
, *rqp
= &rq
;
740 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
744 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_DELETE_DIRECTORY
, scred
);
747 smb_rq_getrequest(rqp
, &mbp
);
751 mb_put_uint8(mbp
, SMB_DT_ASCII
);
752 error
= smbfs_fullpath(mbp
, SSTOVC(ssp
), np
, NULL
, 0);
755 error
= smb_rq_simple(rqp
);
762 smbfs_smb_search(struct smbfs_fctx
*ctx
)
764 struct smb_vc
*vcp
= SSTOVC(ctx
->f_ssp
);
769 u_int16_t ec
, dlen
, bc
;
770 int maxent
, error
, iseof
= 0;
772 maxent
= min(ctx
->f_left
, (vcp
->vc_txmax
- SMB_HDRLEN
- 3) / SMB_DENTRYLEN
);
774 smb_rq_done(ctx
->f_rq
);
777 error
= smb_rq_alloc(SSTOCP(ctx
->f_ssp
), SMB_COM_SEARCH
, ctx
->f_scred
, &rqp
);
781 smb_rq_getrequest(rqp
, &mbp
);
783 mb_put_uint16le(mbp
, maxent
); /* max entries to return */
784 mb_put_uint16le(mbp
, ctx
->f_attrmask
);
787 mb_put_uint8(mbp
, SMB_DT_ASCII
); /* buffer format */
788 if (ctx
->f_flags
& SMBFS_RDD_FINDFIRST
) {
789 error
= smbfs_fullpath(mbp
, vcp
, ctx
->f_dnp
, ctx
->f_wildcard
, ctx
->f_wclen
);
792 mb_put_uint8(mbp
, SMB_DT_VARIABLE
);
793 mb_put_uint16le(mbp
, 0); /* context length */
794 ctx
->f_flags
&= ~SMBFS_RDD_FINDFIRST
;
796 mb_put_uint8(mbp
, 0); /* file name length */
797 mb_put_uint8(mbp
, SMB_DT_VARIABLE
);
798 mb_put_uint16le(mbp
, SMB_SKEYLEN
);
799 mb_put_mem(mbp
, ctx
->f_skey
, SMB_SKEYLEN
, MB_MSYSTEM
);
802 error
= smb_rq_simple(rqp
);
804 if (rqp
->sr_errclass
== ERRDOS
&& rqp
->sr_serror
== ERRnofiles
) {
807 ctx
->f_flags
|= SMBFS_RDD_EOF
;
811 smb_rq_getreply(rqp
, &mdp
);
812 md_get_uint8(mdp
, &wc
);
814 return iseof
? ENOENT
: EBADRPC
;
815 md_get_uint16le(mdp
, &ec
);
819 md_get_uint16le(mdp
, &bc
);
823 md_get_uint8(mdp
, &bt
);
824 if (bt
!= SMB_DT_VARIABLE
)
826 md_get_uint16le(mdp
, &dlen
);
827 if (dlen
!= bc
|| dlen
% SMB_DENTRYLEN
!= 0)
833 smbfs_findopenLM1(struct smbfs_fctx
*ctx
, struct smbnode
*dnp
,
834 const char *wildcard
, int wclen
, int attr
, struct smb_cred
*scred
)
836 ctx
->f_attrmask
= attr
;
838 if (wclen
== 1 && wildcard
[0] == '*') {
839 ctx
->f_wildcard
= "*.*";
842 ctx
->f_wildcard
= wildcard
;
843 ctx
->f_wclen
= wclen
;
846 ctx
->f_wildcard
= NULL
;
849 ctx
->f_name
= ctx
->f_fname
;
854 smbfs_findnextLM1(struct smbfs_fctx
*ctx
, int limit
)
860 u_int16_t date
, time
;
864 if (ctx
->f_ecnt
== 0) {
865 if (ctx
->f_flags
& SMBFS_RDD_EOF
)
867 ctx
->f_left
= ctx
->f_limit
= limit
;
868 error
= smbfs_smb_search(ctx
);
873 smb_rq_getreply(rqp
, &mbp
);
874 md_get_mem(mbp
, ctx
->f_skey
, SMB_SKEYLEN
, MB_MSYSTEM
);
875 md_get_uint8(mbp
, &battr
);
876 md_get_uint16le(mbp
, &time
);
877 md_get_uint16le(mbp
, &date
);
878 md_get_uint32le(mbp
, &size
);
880 md_get_mem(mbp
, cp
, sizeof(ctx
->f_fname
), MB_MSYSTEM
);
881 cp
[sizeof(ctx
->f_fname
) - 1] = 0;
882 cp
+= strlen(cp
) - 1;
883 while (*cp
== ' ' && cp
>= ctx
->f_name
)
885 ctx
->f_attr
.fa_attr
= battr
;
886 smb_dos2unixtime(date
, time
, 0, rqp
->sr_vc
->vc_sopt
.sv_tz
,
887 &ctx
->f_attr
.fa_mtime
);
888 ctx
->f_attr
.fa_size
= size
;
889 ctx
->f_nmlen
= strlen(ctx
->f_name
);
896 smbfs_findcloseLM1(struct smbfs_fctx
*ctx
)
899 smb_rq_done(ctx
->f_rq
);
904 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
907 smbfs_smb_trans2find2(struct smbfs_fctx
*ctx
)
909 struct smb_t2rq
*t2p
;
910 struct smb_vc
*vcp
= SSTOVC(ctx
->f_ssp
);
917 smb_t2_done(ctx
->f_t2
);
920 ctx
->f_flags
&= ~SMBFS_RDD_GOTRNAME
;
921 flags
= 8 | 2; /* <resume> | <close if EOS> */
922 if (ctx
->f_flags
& SMBFS_RDD_FINDSINGLE
) {
923 flags
|= 1; /* close search after this request */
924 ctx
->f_flags
|= SMBFS_RDD_NOCLOSE
;
926 if (ctx
->f_flags
& SMBFS_RDD_FINDFIRST
) {
927 error
= smb_t2_alloc(SSTOCP(ctx
->f_ssp
), SMB_TRANS2_FIND_FIRST2
,
932 mbp
= &t2p
->t2_tparam
;
934 mb_put_uint16le(mbp
, ctx
->f_attrmask
);
935 mb_put_uint16le(mbp
, ctx
->f_limit
);
936 mb_put_uint16le(mbp
, flags
);
937 mb_put_uint16le(mbp
, ctx
->f_infolevel
);
938 mb_put_uint32le(mbp
, 0);
939 error
= smbfs_fullpath(mbp
, vcp
, ctx
->f_dnp
, ctx
->f_wildcard
, ctx
->f_wclen
);
943 error
= smb_t2_alloc(SSTOCP(ctx
->f_ssp
), SMB_TRANS2_FIND_NEXT2
,
948 mbp
= &t2p
->t2_tparam
;
950 mb_put_mem(mbp
, (caddr_t
)&ctx
->f_Sid
, 2, MB_MSYSTEM
);
951 mb_put_uint16le(mbp
, ctx
->f_limit
);
952 mb_put_uint16le(mbp
, ctx
->f_infolevel
);
953 mb_put_uint32le(mbp
, 0); /* resume key */
954 mb_put_uint16le(mbp
, flags
);
956 mb_put_mem(mbp
, ctx
->f_rname
, strlen(ctx
->f_rname
) + 1, MB_MSYSTEM
);
958 mb_put_uint8(mbp
, 0); /* resume file name */
962 tv
.tv_usec
= 200 * 1000; /* 200ms */
963 if (vcp
->vc_flags
& SMBC_WIN95
) {
965 * some implementations suggests to sleep here
966 * for 200ms, due to the bug in the Win95.
967 * I've didn't notice any problem, but put code
970 tsleep(&flags
, 0, "fix95", tvtohz_high(&tv
));
974 t2p
->t2_maxpcount
= 5 * 2;
975 t2p
->t2_maxdcount
= vcp
->vc_txmax
;
976 error
= smb_t2_request(t2p
);
979 mdp
= &t2p
->t2_rparam
;
980 if (ctx
->f_flags
& SMBFS_RDD_FINDFIRST
) {
981 if ((error
= md_get_uint16(mdp
, &ctx
->f_Sid
)) != 0)
983 ctx
->f_flags
&= ~SMBFS_RDD_FINDFIRST
;
985 if ((error
= md_get_uint16le(mdp
, &tw
)) != 0)
988 if ((error
= md_get_uint16le(mdp
, &tw
)) != 0)
991 ctx
->f_flags
|= SMBFS_RDD_EOF
| SMBFS_RDD_NOCLOSE
;
992 if ((error
= md_get_uint16le(mdp
, &tw
)) != 0)
994 if ((error
= md_get_uint16le(mdp
, &tw
)) != 0)
996 if (ctx
->f_ecnt
== 0) {
997 ctx
->f_flags
|= SMBFS_RDD_EOF
| SMBFS_RDD_NOCLOSE
;
1000 ctx
->f_rnameofs
= tw
;
1001 mdp
= &t2p
->t2_rdata
;
1002 if (mdp
->md_top
== NULL
) {
1003 kprintf("bug: ecnt = %d, but data is NULL (please report)\n", ctx
->f_ecnt
);
1006 if (mdp
->md_top
->m_len
== 0) {
1007 kprintf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx
->f_ecnt
,mbp
->mb_top
->m_next
);
1015 smbfs_smb_findclose2(struct smbfs_fctx
*ctx
)
1017 struct smb_rq rq
, *rqp
= &rq
;
1018 struct mbchain
*mbp
;
1021 error
= smb_rq_init(rqp
, SSTOCP(ctx
->f_ssp
), SMB_COM_FIND_CLOSE2
, ctx
->f_scred
);
1024 smb_rq_getrequest(rqp
, &mbp
);
1026 mb_put_mem(mbp
, (caddr_t
)&ctx
->f_Sid
, 2, MB_MSYSTEM
);
1030 error
= smb_rq_simple(rqp
);
1036 smbfs_findopenLM2(struct smbfs_fctx
*ctx
, struct smbnode
*dnp
,
1037 const char *wildcard
, int wclen
, int attr
, struct smb_cred
*scred
)
1039 ctx
->f_name
= kmalloc(SMB_MAXFNAMELEN
, M_SMBFSDATA
, M_WAITOK
);
1040 ctx
->f_infolevel
= SMB_DIALECT(SSTOVC(ctx
->f_ssp
)) < SMB_DIALECT_NTLM0_12
?
1041 SMB_INFO_STANDARD
: SMB_FIND_FILE_DIRECTORY_INFO
;
1042 ctx
->f_attrmask
= attr
;
1043 ctx
->f_wildcard
= wildcard
;
1044 ctx
->f_wclen
= wclen
;
1049 smbfs_findnextLM2(struct smbfs_fctx
*ctx
, int limit
)
1051 struct mdchain
*mbp
;
1052 struct smb_t2rq
*t2p
;
1055 u_int16_t date
, time
, wattr
;
1056 u_int32_t size
, next
, dattr
;
1058 int error
, svtz
, cnt
, fxsz
, nmlen
, recsz
;
1060 if (ctx
->f_ecnt
== 0) {
1061 if (ctx
->f_flags
& SMBFS_RDD_EOF
)
1063 ctx
->f_left
= ctx
->f_limit
= limit
;
1064 error
= smbfs_smb_trans2find2(ctx
);
1069 mbp
= &t2p
->t2_rdata
;
1070 svtz
= SSTOVC(ctx
->f_ssp
)->vc_sopt
.sv_tz
;
1071 switch (ctx
->f_infolevel
) {
1072 case SMB_INFO_STANDARD
:
1075 md_get_uint16le(mbp
, &date
);
1076 md_get_uint16le(mbp
, &time
); /* creation time */
1077 md_get_uint16le(mbp
, &date
);
1078 md_get_uint16le(mbp
, &time
); /* access time */
1079 smb_dos2unixtime(date
, time
, 0, svtz
, &ctx
->f_attr
.fa_atime
);
1080 md_get_uint16le(mbp
, &date
);
1081 md_get_uint16le(mbp
, &time
); /* access time */
1082 smb_dos2unixtime(date
, time
, 0, svtz
, &ctx
->f_attr
.fa_mtime
);
1083 md_get_uint32le(mbp
, &size
);
1084 ctx
->f_attr
.fa_size
= size
;
1085 md_get_uint32(mbp
, NULL
); /* allocation size */
1086 md_get_uint16le(mbp
, &wattr
);
1087 ctx
->f_attr
.fa_attr
= wattr
;
1088 md_get_uint8(mbp
, &tb
);
1091 recsz
= next
= 24 + nmlen
; /* docs misses zero byte at end */
1093 case SMB_FIND_FILE_DIRECTORY_INFO
:
1094 md_get_uint32le(mbp
, &next
);
1095 md_get_uint32(mbp
, NULL
); /* file index */
1096 md_get_int64(mbp
, NULL
); /* creation time */
1097 md_get_int64le(mbp
, &lint
);
1098 smb_time_NT2local(lint
, svtz
, &ctx
->f_attr
.fa_atime
);
1099 md_get_int64le(mbp
, &lint
);
1100 smb_time_NT2local(lint
, svtz
, &ctx
->f_attr
.fa_mtime
);
1101 md_get_int64le(mbp
, &lint
);
1102 smb_time_NT2local(lint
, svtz
, &ctx
->f_attr
.fa_ctime
);
1103 md_get_int64le(mbp
, &lint
); /* file size */
1104 ctx
->f_attr
.fa_size
= lint
;
1105 md_get_int64(mbp
, NULL
); /* real size (should use) */
1106 md_get_uint32(mbp
, &dattr
); /* EA */
1107 ctx
->f_attr
.fa_attr
= dattr
;
1108 md_get_uint32le(mbp
, &size
); /* name len */
1110 recsz
= next
? next
: fxsz
+ size
;
1113 SMBERROR("unexpected info level %d\n", ctx
->f_infolevel
);
1116 nmlen
= min(size
, SMB_MAXFNAMELEN
);
1118 error
= md_get_mem(mbp
, cp
, nmlen
, MB_MSYSTEM
);
1122 cnt
= next
- nmlen
- fxsz
;
1124 md_get_mem(mbp
, NULL
, cnt
, MB_MSYSTEM
);
1126 SMBERROR("out of sync\n");
1130 if (nmlen
&& cp
[nmlen
- 1] == 0)
1135 next
= ctx
->f_eofs
+ recsz
;
1136 if (ctx
->f_rnameofs
&& (ctx
->f_flags
& SMBFS_RDD_GOTRNAME
) == 0 &&
1137 (ctx
->f_rnameofs
>= ctx
->f_eofs
&& ctx
->f_rnameofs
< next
)) {
1139 * Server needs a resume filename.
1141 if (ctx
->f_rnamelen
<= nmlen
) {
1143 kfree(ctx
->f_rname
, M_SMBFSDATA
);
1144 ctx
->f_rname
= kmalloc(nmlen
+ 1, M_SMBFSDATA
, M_WAITOK
);
1145 ctx
->f_rnamelen
= nmlen
;
1147 bcopy(ctx
->f_name
, ctx
->f_rname
, nmlen
);
1148 ctx
->f_rname
[nmlen
] = 0;
1149 ctx
->f_flags
|= SMBFS_RDD_GOTRNAME
;
1151 ctx
->f_nmlen
= nmlen
;
1159 smbfs_findcloseLM2(struct smbfs_fctx
*ctx
)
1162 kfree(ctx
->f_name
, M_SMBFSDATA
);
1164 smb_t2_done(ctx
->f_t2
);
1165 if ((ctx
->f_flags
& SMBFS_RDD_NOCLOSE
) == 0)
1166 smbfs_smb_findclose2(ctx
);
1171 smbfs_findopen(struct smbnode
*dnp
, const char *wildcard
, int wclen
, int attr
,
1172 struct smb_cred
*scred
, struct smbfs_fctx
**ctxpp
)
1174 struct smbfs_fctx
*ctx
;
1177 ctx
= kmalloc(sizeof(*ctx
), M_SMBFSDATA
, M_WAITOK
| M_ZERO
);
1178 ctx
->f_ssp
= dnp
->n_mount
->sm_share
;
1180 ctx
->f_flags
= SMBFS_RDD_FINDFIRST
;
1181 ctx
->f_scred
= scred
;
1182 if (SMB_DIALECT(SSTOVC(ctx
->f_ssp
)) < SMB_DIALECT_LANMAN2_0
||
1183 (dnp
->n_mount
->sm_args
.flags
& SMBFS_MOUNT_NO_LONG
)) {
1184 ctx
->f_flags
|= SMBFS_RDD_USESEARCH
;
1185 error
= smbfs_findopenLM1(ctx
, dnp
, wildcard
, wclen
, attr
, scred
);
1187 error
= smbfs_findopenLM2(ctx
, dnp
, wildcard
, wclen
, attr
, scred
);
1189 smbfs_findclose(ctx
, scred
);
1196 smbfs_findnext(struct smbfs_fctx
*ctx
, int limit
, struct smb_cred
*scred
)
1203 limit
*= 4; /* imperical */
1204 ctx
->f_scred
= scred
;
1206 if (ctx
->f_flags
& SMBFS_RDD_USESEARCH
) {
1207 error
= smbfs_findnextLM1(ctx
, limit
);
1209 error
= smbfs_findnextLM2(ctx
, limit
);
1212 if ((ctx
->f_nmlen
== 1 && ctx
->f_name
[0] == '.') ||
1213 (ctx
->f_nmlen
== 2 && ctx
->f_name
[0] == '.' &&
1214 ctx
->f_name
[1] == '.'))
1218 smbfs_fname_tolocal(SSTOVC(ctx
->f_ssp
), ctx
->f_name
, ctx
->f_nmlen
,
1219 ctx
->f_dnp
->n_mount
->sm_caseopt
);
1220 ctx
->f_attr
.fa_ino
= smbfs_getino(ctx
->f_dnp
, ctx
->f_name
, ctx
->f_nmlen
);
1225 smbfs_findclose(struct smbfs_fctx
*ctx
, struct smb_cred
*scred
)
1227 ctx
->f_scred
= scred
;
1228 if (ctx
->f_flags
& SMBFS_RDD_USESEARCH
) {
1229 smbfs_findcloseLM1(ctx
);
1231 smbfs_findcloseLM2(ctx
);
1233 kfree(ctx
->f_rname
, M_SMBFSDATA
);
1234 kfree(ctx
, M_SMBFSDATA
);
1239 smbfs_smb_lookup(struct smbnode
*dnp
, const char *name
, int nmlen
,
1240 struct smbfattr
*fap
, struct smb_cred
*scred
)
1242 struct smbfs_fctx
*ctx
;
1245 if (dnp
== NULL
|| (dnp
->n_ino
== 2 && name
== NULL
)) {
1246 bzero(fap
, sizeof(*fap
));
1247 fap
->fa_attr
= SMB_FA_DIR
;
1251 if (nmlen
== 1 && name
[0] == '.') {
1252 error
= smbfs_smb_lookup(dnp
, NULL
, 0, fap
, scred
);
1254 } else if (nmlen
== 2 && name
[0] == '.' && name
[1] == '.') {
1255 error
= smbfs_smb_lookup(VTOSMB(dnp
->n_parent
), NULL
, 0, fap
,
1257 kprintf("%s: knows NOTHING about '..'\n", __func__
);
1260 error
= smbfs_findopen(dnp
, name
, nmlen
,
1261 SMB_FA_SYSTEM
| SMB_FA_HIDDEN
| SMB_FA_DIR
, scred
, &ctx
);
1264 ctx
->f_flags
|= SMBFS_RDD_FINDSINGLE
;
1265 error
= smbfs_findnext(ctx
, 1, scred
);
1269 fap
->fa_ino
= dnp
->n_ino
;
1271 smbfs_findclose(ctx
, scred
);