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.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
34 #include <sys/vnode.h>
36 #include <sys/mount.h>
37 #include <sys/endian.h>
43 #include <netsmb/smb.h>
44 #include <netsmb/smb_subr.h>
45 #include <netsmb/smb_rq.h>
46 #include <netsmb/smb_conn.h>
48 #include <fs/smbfs/smbfs.h>
49 #include <fs/smbfs/smbfs_node.h>
50 #include <fs/smbfs/smbfs_subr.h>
53 * Lack of inode numbers leads us to the problem of generating them.
54 * Partially this problem can be solved by having a dir/file cache
55 * with inode numbers generated from the incremented by one counter.
56 * However this way will require too much kernel memory, gives all
57 * sorts of locking and consistency problems, not to mentinon counter overflows.
58 * So, I'm decided to use a hash function to generate pseudo random (and unique)
62 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
71 MD5Update(&md5, name, nmlen);
72 MD5Final((u_char *)state, &md5);
73 for (i = 0, ino = 0; i < 4; i++)
75 return dnp->n_ino + ino;
79 ino = dnp->n_ino + smbfs_hash(name, nmlen);
86 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
87 struct smb_cred *scred)
89 struct smb_share *ssp = np->n_mount->sm_share;
90 struct smb_rq rq, *rqp = &rq;
95 if (op == SMB_LOCK_SHARED)
96 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
97 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
100 smb_rq_getrequest(rqp, &mbp);
102 mb_put_uint8(mbp, 0xff); /* secondary command */
103 mb_put_uint8(mbp, 0); /* MBZ */
104 mb_put_uint16le(mbp, 0);
105 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
106 mb_put_uint8(mbp, ltype); /* locktype */
107 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
108 mb_put_uint32le(mbp, 0); /* timeout - break immediately */
109 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
110 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
113 mb_put_uint16le(mbp, pid);
114 mb_put_uint32le(mbp, start);
115 mb_put_uint32le(mbp, end - start);
117 error = smb_rq_simple(rqp);
123 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
124 off_t start, off_t end, struct smb_cred *scred)
126 struct smb_share *ssp = np->n_mount->sm_share;
128 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
130 * TODO: use LOCK_BYTE_RANGE here.
134 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
138 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
139 struct smb_cred *scred)
141 struct smb_t2rq *t2p;
145 u_int32_t units, bpu, funits;
148 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
152 mbp = &t2p->t2_tparam;
154 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
155 t2p->t2_maxpcount = 4;
156 t2p->t2_maxdcount = 4 * 4 + 2;
157 error = smb_t2_request(t2p);
162 mdp = &t2p->t2_rdata;
163 md_get_uint32(mdp, NULL); /* fs id */
164 md_get_uint32le(mdp, &bpu);
165 md_get_uint32le(mdp, &units);
166 md_get_uint32le(mdp, &funits);
167 md_get_uint16le(mdp, &bsize);
168 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */
169 sbp->f_blocks= units; /* total data blocks in filesystem */
170 sbp->f_bfree = funits; /* free blocks in fs */
171 sbp->f_bavail= funits; /* free blocks avail to non-superuser */
172 sbp->f_files = 0xffff; /* total file nodes in filesystem */
173 sbp->f_ffree = 0xffff; /* free file nodes in fs */
179 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
180 struct smb_cred *scred)
182 struct smb_rq rq, *rqp = &rq;
184 u_int16_t units, bpu, bsize, funits;
187 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
194 error = smb_rq_simple(rqp);
199 smb_rq_getreply(rqp, &mdp);
200 md_get_uint16le(mdp, &units);
201 md_get_uint16le(mdp, &bpu);
202 md_get_uint16le(mdp, &bsize);
203 md_get_uint16le(mdp, &funits);
204 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */
205 sbp->f_blocks= units; /* total data blocks in filesystem */
206 sbp->f_bfree = funits; /* free blocks in fs */
207 sbp->f_bavail= funits; /* free blocks avail to non-superuser */
208 sbp->f_files = 0xffff; /* total file nodes in filesystem */
209 sbp->f_ffree = 0xffff; /* free file nodes in fs */
215 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
217 struct smb_t2rq *t2p;
218 struct smb_share *ssp = np->n_mount->sm_share;
222 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
226 mbp = &t2p->t2_tparam;
228 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
229 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
230 mb_put_uint32le(mbp, 0);
231 mbp = &t2p->t2_tdata;
233 mb_put_int64le(mbp, newsize);
234 mb_put_uint32le(mbp, 0); /* padding */
235 mb_put_uint16le(mbp, 0);
236 t2p->t2_maxpcount = 2;
237 t2p->t2_maxdcount = 0;
238 error = smb_t2_request(t2p);
244 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
246 struct smb_share *ssp = np->n_mount->sm_share;
247 struct smb_rq rq, *rqp = &rq;
251 if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
252 SMBTOV(np)->v_type != VREG)
253 return 0; /* not a regular open file */
254 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
257 smb_rq_getrequest(rqp, &mbp);
259 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
263 error = smb_rq_simple(rqp);
266 np->n_flag &= ~NFLUSHWIRE;
271 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
273 if (np->n_flag & NFLUSHWIRE)
274 return (smb_smb_flush(np, scred));
279 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
281 struct smb_share *ssp = np->n_mount->sm_share;
282 struct smb_rq rq, *rqp = &rq;
286 if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
287 np->n_flag |= NFLUSHWIRE;
291 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
294 smb_rq_getrequest(rqp, &mbp);
296 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
297 mb_put_uint16le(mbp, 0);
298 mb_put_uint32le(mbp, newsize);
299 mb_put_uint16le(mbp, 0);
302 mb_put_uint8(mbp, SMB_DT_DATA);
303 mb_put_uint16le(mbp, 0);
305 error = smb_rq_simple(rqp);
311 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
312 struct smbfattr *fap, struct smb_cred *scred)
314 struct smb_rq rq, *rqp = &rq;
315 struct smb_share *ssp = np->n_mount->sm_share;
323 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
326 smb_rq_getrequest(rqp, &mbp);
330 mb_put_uint8(mbp, SMB_DT_ASCII);
332 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
336 error = smb_rq_simple(rqp);
339 smb_rq_getreply(rqp, &mdp);
340 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
344 md_get_uint16le(mdp, &wattr);
345 fap->fa_attr = wattr;
347 * Be careful using the time returned here, as
348 * with FAT on NT4SP6, at least, the time returned is low
349 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
350 * over about every seven minutes!
352 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
353 if (lint) /* avoid bogus zero returns */
354 smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
356 md_get_uint32le(mdp, &lint);
364 * Set DOS file attributes. mtime should be NULL for dialects above lm10
367 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
368 struct smb_cred *scred)
370 struct smb_rq rq, *rqp = &rq;
371 struct smb_share *ssp = np->n_mount->sm_share;
376 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
379 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
380 smb_rq_getrequest(rqp, &mbp);
382 mb_put_uint16le(mbp, attr);
384 smb_time_local2server(mtime, svtz, &time);
387 mb_put_uint32le(mbp, time); /* mtime */
388 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
391 mb_put_uint8(mbp, SMB_DT_ASCII);
393 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
396 mb_put_uint8(mbp, SMB_DT_ASCII);
397 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
399 mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */
401 mb_put_uint8(mbp, 0);
403 error = smb_rq_simple(rqp);
405 SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
414 * Note, win95 doesn't support this call.
417 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
418 struct timespec *atime, int attr, struct smb_cred *scred)
420 struct smb_t2rq *t2p;
421 struct smb_share *ssp = np->n_mount->sm_share;
422 struct smb_vc *vcp = SSTOVC(ssp);
424 u_int16_t date, time;
427 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
431 mbp = &t2p->t2_tparam;
433 mb_put_uint16le(mbp, SMB_INFO_STANDARD);
434 mb_put_uint32le(mbp, 0); /* MBZ */
435 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
436 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
441 tzoff = vcp->vc_sopt.sv_tz;
442 mbp = &t2p->t2_tdata;
444 mb_put_uint32le(mbp, 0); /* creation time */
446 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
449 mb_put_uint16le(mbp, date);
450 mb_put_uint16le(mbp, time);
452 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
455 mb_put_uint16le(mbp, date);
456 mb_put_uint16le(mbp, time);
457 mb_put_uint32le(mbp, 0); /* file size */
458 mb_put_uint32le(mbp, 0); /* allocation unit size */
459 mb_put_uint16le(mbp, attr); /* DOS attr */
460 mb_put_uint32le(mbp, 0); /* EA size */
461 t2p->t2_maxpcount = 5 * 2;
462 t2p->t2_maxdcount = vcp->vc_txmax;
463 error = smb_t2_request(t2p);
469 * NT level. Specially for win9x
472 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
473 struct timespec *atime, struct smb_cred *scred)
475 struct smb_t2rq *t2p;
476 struct smb_share *ssp = np->n_mount->sm_share;
477 struct smb_vc *vcp = SSTOVC(ssp);
482 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
486 mbp = &t2p->t2_tparam;
488 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
489 mb_put_uint32le(mbp, 0); /* MBZ */
490 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
491 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
496 tzoff = vcp->vc_sopt.sv_tz;
497 mbp = &t2p->t2_tdata;
499 mb_put_int64le(mbp, 0); /* creation time */
501 smb_time_local2NT(atime, tzoff, &tm);
504 mb_put_int64le(mbp, tm);
506 smb_time_local2NT(mtime, tzoff, &tm);
509 mb_put_int64le(mbp, tm);
510 mb_put_int64le(mbp, tm); /* change time */
511 mb_put_uint32le(mbp, attr); /* attr */
512 t2p->t2_maxpcount = 24;
513 t2p->t2_maxdcount = 56;
514 error = smb_t2_request(t2p);
520 * Set file atime and mtime. Doesn't supported by core dialect.
523 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
524 struct timespec *atime, struct smb_cred *scred)
526 struct smb_rq rq, *rqp = &rq;
527 struct smb_share *ssp = np->n_mount->sm_share;
529 u_int16_t date, time;
532 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
535 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
536 smb_rq_getrequest(rqp, &mbp);
538 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
539 mb_put_uint32le(mbp, 0); /* creation time */
542 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
545 mb_put_uint16le(mbp, date);
546 mb_put_uint16le(mbp, time);
548 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
551 mb_put_uint16le(mbp, date);
552 mb_put_uint16le(mbp, time);
556 error = smb_rq_simple(rqp);
557 SMBSDEBUG("%d\n", error);
563 * Set DOS file attributes.
564 * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
567 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
568 struct timespec *atime, struct smb_cred *scred)
570 struct smb_t2rq *t2p;
571 struct smb_share *ssp = np->n_mount->sm_share;
576 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
580 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
581 mbp = &t2p->t2_tparam;
583 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
584 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
585 mb_put_uint32le(mbp, 0);
586 mbp = &t2p->t2_tdata;
588 mb_put_int64le(mbp, 0); /* creation time */
590 smb_time_local2NT(atime, svtz, &tm);
593 mb_put_int64le(mbp, tm);
595 smb_time_local2NT(mtime, svtz, &tm);
598 mb_put_int64le(mbp, tm);
599 mb_put_int64le(mbp, tm); /* change time */
600 mb_put_uint16le(mbp, attr);
601 mb_put_uint32le(mbp, 0); /* padding */
602 mb_put_uint16le(mbp, 0);
603 t2p->t2_maxpcount = 2;
604 t2p->t2_maxdcount = 0;
605 error = smb_t2_request(t2p);
612 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
614 struct smb_rq rq, *rqp = &rq;
615 struct smb_share *ssp = np->n_mount->sm_share;
619 u_int16_t fid, wattr, grantedmode;
622 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
625 smb_rq_getrequest(rqp, &mbp);
627 mb_put_uint16le(mbp, accmode);
628 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
631 mb_put_uint8(mbp, SMB_DT_ASCII);
633 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
637 error = smb_rq_simple(rqp);
640 smb_rq_getreply(rqp, &mdp);
641 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
645 md_get_uint16(mdp, &fid);
646 md_get_uint16le(mdp, &wattr);
647 md_get_uint32(mdp, NULL); /* mtime */
648 md_get_uint32(mdp, NULL); /* fsize */
649 md_get_uint16le(mdp, &grantedmode);
651 * TODO: refresh attributes from this reply
658 np->n_rwstate = grantedmode;
664 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
665 struct smb_cred *scred)
667 struct smb_rq rq, *rqp = &rq;
672 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
675 smb_rq_getrequest(rqp, &mbp);
677 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
679 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
682 mb_put_uint32le(mbp, time);
686 error = smb_rq_simple(rqp);
692 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
693 struct smb_cred *scred)
695 struct smb_rq rq, *rqp = &rq;
696 struct smb_share *ssp = dnp->n_mount->sm_share;
699 struct timespec ctime;
705 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
708 smb_rq_getrequest(rqp, &mbp);
710 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */
712 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
713 mb_put_uint32le(mbp, tm);
716 mb_put_uint8(mbp, SMB_DT_ASCII);
717 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
720 error = smb_rq_simple(rqp);
722 smb_rq_getreply(rqp, &mdp);
723 md_get_uint8(mdp, &wc);
725 md_get_uint16(mdp, &fid);
733 smbfs_smb_close(ssp, fid, &ctime, scred);
738 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
740 struct smb_rq rq, *rqp = &rq;
741 struct smb_share *ssp = np->n_mount->sm_share;
745 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
748 smb_rq_getrequest(rqp, &mbp);
750 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
753 mb_put_uint8(mbp, SMB_DT_ASCII);
754 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
757 error = smb_rq_simple(rqp);
764 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
765 const char *tname, int tnmlen, struct smb_cred *scred)
767 struct smb_rq rq, *rqp = &rq;
768 struct smb_share *ssp = src->n_mount->sm_share;
772 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
775 smb_rq_getrequest(rqp, &mbp);
777 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
780 mb_put_uint8(mbp, SMB_DT_ASCII);
782 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
785 mb_put_uint8(mbp, SMB_DT_ASCII);
786 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
790 error = smb_rq_simple(rqp);
797 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
798 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
800 struct smb_rq rq, *rqp = &rq;
801 struct smb_share *ssp = src->n_mount->sm_share;
805 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
808 smb_rq_getrequest(rqp, &mbp);
810 mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
811 mb_put_uint16le(mbp, 0x20); /* delete target file */
812 mb_put_uint16le(mbp, flags);
815 mb_put_uint8(mbp, SMB_DT_ASCII);
817 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
820 mb_put_uint8(mbp, SMB_DT_ASCII);
821 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
825 error = smb_rq_simple(rqp);
832 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
833 struct smb_cred *scred)
835 struct smb_rq rq, *rqp = &rq;
836 struct smb_share *ssp = dnp->n_mount->sm_share;
840 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
843 smb_rq_getrequest(rqp, &mbp);
847 mb_put_uint8(mbp, SMB_DT_ASCII);
848 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
851 error = smb_rq_simple(rqp);
858 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
860 struct smb_rq rq, *rqp = &rq;
861 struct smb_share *ssp = np->n_mount->sm_share;
865 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
868 smb_rq_getrequest(rqp, &mbp);
872 mb_put_uint8(mbp, SMB_DT_ASCII);
873 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
876 error = smb_rq_simple(rqp);
883 smbfs_smb_search(struct smbfs_fctx *ctx)
885 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
890 u_int16_t ec, dlen, bc;
891 int maxent, error, iseof = 0;
893 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
895 smb_rq_done(ctx->f_rq);
898 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
902 smb_rq_getrequest(rqp, &mbp);
904 mb_put_uint16le(mbp, maxent); /* max entries to return */
905 mb_put_uint16le(mbp, ctx->f_attrmask);
908 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
909 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
910 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
913 mb_put_uint8(mbp, SMB_DT_VARIABLE);
914 mb_put_uint16le(mbp, 0); /* context length */
915 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
917 if (SMB_UNICODE_STRINGS(vcp)) {
919 mb_put_uint8(mbp, 0);
921 mb_put_uint8(mbp, 0); /* file name length */
922 mb_put_uint8(mbp, SMB_DT_VARIABLE);
923 mb_put_uint16le(mbp, SMB_SKEYLEN);
924 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
927 error = smb_rq_simple(rqp);
929 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
932 ctx->f_flags |= SMBFS_RDD_EOF;
936 smb_rq_getreply(rqp, &mdp);
937 md_get_uint8(mdp, &wc);
939 return iseof ? ENOENT : EBADRPC;
940 md_get_uint16le(mdp, &ec);
944 md_get_uint16le(mdp, &bc);
948 md_get_uint8(mdp, &bt);
949 if (bt != SMB_DT_VARIABLE)
951 md_get_uint16le(mdp, &dlen);
952 if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
958 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
959 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
961 ctx->f_attrmask = attr;
963 if (wclen == 1 && wildcard[0] == '*') {
964 ctx->f_wildcard = "*.*";
967 ctx->f_wildcard = wildcard;
968 ctx->f_wclen = wclen;
971 ctx->f_wildcard = NULL;
974 ctx->f_name = ctx->f_fname;
979 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
985 u_int16_t date, time;
989 if (ctx->f_ecnt == 0) {
990 if (ctx->f_flags & SMBFS_RDD_EOF)
992 ctx->f_left = ctx->f_limit = limit;
993 error = smbfs_smb_search(ctx);
998 smb_rq_getreply(rqp, &mbp);
999 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1000 md_get_uint8(mbp, &battr);
1001 md_get_uint16le(mbp, &time);
1002 md_get_uint16le(mbp, &date);
1003 md_get_uint32le(mbp, &size);
1005 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
1006 cp[sizeof(ctx->f_fname) - 1] = 0;
1007 cp += strlen(cp) - 1;
1008 while (*cp == ' ' && cp >= ctx->f_name)
1010 ctx->f_attr.fa_attr = battr;
1011 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1012 &ctx->f_attr.fa_mtime);
1013 ctx->f_attr.fa_size = size;
1014 ctx->f_nmlen = strlen(ctx->f_name);
1021 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
1024 smb_rq_done(ctx->f_rq);
1029 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1032 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1034 struct smb_t2rq *t2p;
1035 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1036 struct mbchain *mbp;
1037 struct mdchain *mdp;
1038 u_int16_t tw, flags;
1042 smb_t2_done(ctx->f_t2);
1045 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1046 flags = 8 | 2; /* <resume> | <close if EOS> */
1047 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1048 flags |= 1; /* close search after this request */
1049 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1051 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1052 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1053 ctx->f_scred, &t2p);
1057 mbp = &t2p->t2_tparam;
1059 mb_put_uint16le(mbp, ctx->f_attrmask);
1060 mb_put_uint16le(mbp, ctx->f_limit);
1061 mb_put_uint16le(mbp, flags);
1062 mb_put_uint16le(mbp, ctx->f_infolevel);
1063 mb_put_uint32le(mbp, 0);
1064 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1068 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1069 ctx->f_scred, &t2p);
1073 mbp = &t2p->t2_tparam;
1075 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1076 mb_put_uint16le(mbp, ctx->f_limit);
1077 mb_put_uint16le(mbp, ctx->f_infolevel);
1078 mb_put_uint32le(mbp, 0); /* resume key */
1079 mb_put_uint16le(mbp, flags);
1081 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
1083 mb_put_uint8(mbp, 0); /* resume file name */
1087 tv.tv_usec = 200 * 1000; /* 200ms */
1088 if (vcp->vc_flags & SMBC_WIN95) {
1090 * some implementations suggests to sleep here
1091 * for 200ms, due to the bug in the Win95.
1092 * I've didn't notice any problem, but put code
1095 pause("fix95", tvtohz(&tv));
1099 t2p->t2_maxpcount = 5 * 2;
1100 t2p->t2_maxdcount = vcp->vc_txmax;
1101 error = smb_t2_request(t2p);
1104 mdp = &t2p->t2_rparam;
1105 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1106 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1108 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1110 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1113 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1116 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1117 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1119 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1121 if (ctx->f_ecnt == 0) {
1122 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1125 ctx->f_rnameofs = tw;
1126 mdp = &t2p->t2_rdata;
1127 if (mdp->md_top == NULL) {
1128 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
1131 if (mdp->md_top->m_len == 0) {
1132 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
1140 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1142 struct smb_rq rq, *rqp = &rq;
1143 struct mbchain *mbp;
1146 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
1149 smb_rq_getrequest(rqp, &mbp);
1151 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1155 error = smb_rq_simple(rqp);
1161 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1162 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1164 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1165 ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
1167 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1168 if (ctx->f_name == NULL)
1170 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1171 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1172 ctx->f_attrmask = attr;
1173 ctx->f_wildcard = wildcard;
1174 ctx->f_wclen = wclen;
1179 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1181 struct mdchain *mbp;
1182 struct smb_t2rq *t2p;
1185 u_int16_t date, time, wattr;
1186 u_int32_t size, next, dattr;
1188 int error, svtz, cnt, fxsz, nmlen, recsz;
1190 if (ctx->f_ecnt == 0) {
1191 if (ctx->f_flags & SMBFS_RDD_EOF)
1193 ctx->f_left = ctx->f_limit = limit;
1194 error = smbfs_smb_trans2find2(ctx);
1199 mbp = &t2p->t2_rdata;
1200 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1201 switch (ctx->f_infolevel) {
1202 case SMB_INFO_STANDARD:
1205 md_get_uint16le(mbp, &date);
1206 md_get_uint16le(mbp, &time); /* creation time */
1207 md_get_uint16le(mbp, &date);
1208 md_get_uint16le(mbp, &time); /* access time */
1209 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
1210 md_get_uint16le(mbp, &date);
1211 md_get_uint16le(mbp, &time); /* access time */
1212 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
1213 md_get_uint32le(mbp, &size);
1214 ctx->f_attr.fa_size = size;
1215 md_get_uint32(mbp, NULL); /* allocation size */
1216 md_get_uint16le(mbp, &wattr);
1217 ctx->f_attr.fa_attr = wattr;
1218 md_get_uint8(mbp, &tb);
1221 recsz = next = 24 + nmlen; /* docs misses zero byte at end */
1223 case SMB_FIND_FILE_DIRECTORY_INFO:
1224 md_get_uint32le(mbp, &next);
1225 md_get_uint32(mbp, NULL); /* file index */
1226 md_get_int64(mbp, NULL); /* creation time */
1227 md_get_int64le(mbp, &lint);
1228 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
1229 md_get_int64le(mbp, &lint);
1230 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
1231 md_get_int64le(mbp, &lint);
1232 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
1233 md_get_int64le(mbp, &lint); /* file size */
1234 ctx->f_attr.fa_size = lint;
1235 md_get_int64(mbp, NULL); /* real size (should use) */
1236 md_get_uint32le(mbp, &dattr); /* EA */
1237 ctx->f_attr.fa_attr = dattr;
1238 md_get_uint32le(mbp, &size); /* name len */
1240 recsz = next ? next : fxsz + size;
1243 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
1246 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1247 nmlen = min(size, SMB_MAXFNAMELEN * 2);
1249 nmlen = min(size, SMB_MAXFNAMELEN);
1251 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1255 cnt = next - nmlen - fxsz;
1257 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1259 SMBERROR("out of sync\n");
1263 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1264 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
1267 if (nmlen && cp[nmlen - 1] == 0)
1272 next = ctx->f_eofs + recsz;
1273 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1274 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1276 * Server needs a resume filename.
1278 if (ctx->f_rnamelen <= nmlen) {
1280 free(ctx->f_rname, M_SMBFSDATA);
1281 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1282 ctx->f_rnamelen = nmlen;
1284 bcopy(ctx->f_name, ctx->f_rname, nmlen);
1285 ctx->f_rname[nmlen] = 0;
1286 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1288 ctx->f_nmlen = nmlen;
1296 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1299 free(ctx->f_name, M_SMBFSDATA);
1301 smb_t2_done(ctx->f_t2);
1302 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1303 smbfs_smb_findclose2(ctx);
1308 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1309 struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1311 struct smbfs_fctx *ctx;
1314 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
1317 bzero(ctx, sizeof(*ctx));
1318 ctx->f_ssp = dnp->n_mount->sm_share;
1320 ctx->f_flags = SMBFS_RDD_FINDFIRST;
1321 ctx->f_scred = scred;
1322 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1323 (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
1324 ctx->f_flags |= SMBFS_RDD_USESEARCH;
1325 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1327 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1329 smbfs_findclose(ctx, scred);
1336 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1343 limit *= 4; /* imperical */
1344 ctx->f_scred = scred;
1346 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1347 error = smbfs_findnextLM1(ctx, limit);
1349 error = smbfs_findnextLM2(ctx, limit);
1352 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1353 if ((ctx->f_nmlen == 2 &&
1354 *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
1355 (ctx->f_nmlen == 4 &&
1356 *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
1359 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1360 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1361 ctx->f_name[1] == '.'))
1365 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1366 ctx->f_dnp->n_mount->sm_caseopt);
1367 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1372 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1374 ctx->f_scred = scred;
1375 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1376 smbfs_findcloseLM1(ctx);
1378 smbfs_findcloseLM2(ctx);
1380 free(ctx->f_rname, M_SMBFSDATA);
1381 free(ctx, M_SMBFSDATA);
1386 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1387 struct smbfattr *fap, struct smb_cred *scred)
1389 struct smbfs_fctx *ctx;
1392 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1393 bzero(fap, sizeof(*fap));
1394 fap->fa_attr = SMB_FA_DIR;
1398 if (nmlen == 1 && name[0] == '.') {
1399 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
1401 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1402 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
1404 printf("%s: knows NOTHING about '..'\n", __func__);
1407 error = smbfs_findopen(dnp, name, nmlen,
1408 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1411 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1412 error = smbfs_findnext(ctx, 1, scred);
1416 fap->fa_ino = dnp->n_ino;
1418 smbfs_findclose(ctx, scred);