1d167cf6fSWarner Losh /*- 2*d63027b6SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*d63027b6SPedro F. Giffuni * 4681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 5681a5bbeSBoris Popov * All rights reserved. 6681a5bbeSBoris Popov * 7681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 8681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 9681a5bbeSBoris Popov * are met: 10681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 12681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 13681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 14681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 15681a5bbeSBoris Popov * 16681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26681a5bbeSBoris Popov * SUCH DAMAGE. 27681a5bbeSBoris Popov * 28681a5bbeSBoris Popov * $FreeBSD$ 29681a5bbeSBoris Popov */ 30681a5bbeSBoris Popov #include <sys/param.h> 31681a5bbeSBoris Popov #include <sys/systm.h> 32681a5bbeSBoris Popov #include <sys/kernel.h> 33681a5bbeSBoris Popov #include <sys/malloc.h> 34681a5bbeSBoris Popov #include <sys/proc.h> 35681a5bbeSBoris Popov #include <sys/lock.h> 36681a5bbeSBoris Popov #include <sys/vnode.h> 37681a5bbeSBoris Popov #include <sys/mbuf.h> 38681a5bbeSBoris Popov #include <sys/mount.h> 3941f1dcccSKevin Lo #include <sys/endian.h> 40681a5bbeSBoris Popov 41681a5bbeSBoris Popov #ifdef USE_MD5_HASH 42681a5bbeSBoris Popov #include <sys/md5.h> 43681a5bbeSBoris Popov #endif 44681a5bbeSBoris Popov 45681a5bbeSBoris Popov #include <netsmb/smb.h> 46681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 47681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 48681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 49681a5bbeSBoris Popov 50681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 51681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 52681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 53681a5bbeSBoris Popov 54681a5bbeSBoris Popov /* 55681a5bbeSBoris Popov * Lack of inode numbers leads us to the problem of generating them. 56681a5bbeSBoris Popov * Partially this problem can be solved by having a dir/file cache 57681a5bbeSBoris Popov * with inode numbers generated from the incremented by one counter. 58681a5bbeSBoris Popov * However this way will require too much kernel memory, gives all 59681a5bbeSBoris Popov * sorts of locking and consistency problems, not to mentinon counter overflows. 60681a5bbeSBoris Popov * So, I'm decided to use a hash function to generate pseudo random (and unique) 61681a5bbeSBoris Popov * inode numbers. 62681a5bbeSBoris Popov */ 63681a5bbeSBoris Popov static long 64681a5bbeSBoris Popov smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 65681a5bbeSBoris Popov { 66681a5bbeSBoris Popov #ifdef USE_MD5_HASH 67681a5bbeSBoris Popov MD5_CTX md5; 68681a5bbeSBoris Popov u_int32_t state[4]; 69681a5bbeSBoris Popov long ino; 70681a5bbeSBoris Popov int i; 71681a5bbeSBoris Popov 72681a5bbeSBoris Popov MD5Init(&md5); 73681a5bbeSBoris Popov MD5Update(&md5, name, nmlen); 74681a5bbeSBoris Popov MD5Final((u_char *)state, &md5); 75681a5bbeSBoris Popov for (i = 0, ino = 0; i < 4; i++) 76681a5bbeSBoris Popov ino += state[i]; 77681a5bbeSBoris Popov return dnp->n_ino + ino; 78681a5bbeSBoris Popov #endif 79681a5bbeSBoris Popov u_int32_t ino; 80681a5bbeSBoris Popov 81681a5bbeSBoris Popov ino = dnp->n_ino + smbfs_hash(name, nmlen); 82681a5bbeSBoris Popov if (ino <= 2) 83681a5bbeSBoris Popov ino += 3; 84681a5bbeSBoris Popov return ino; 85681a5bbeSBoris Popov } 86681a5bbeSBoris Popov 87681a5bbeSBoris Popov static int 88681a5bbeSBoris Popov smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, 89681a5bbeSBoris Popov struct smb_cred *scred) 90681a5bbeSBoris Popov { 91681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 92afe09751SDavide Italiano struct smb_rq *rqp; 93681a5bbeSBoris Popov struct mbchain *mbp; 94681a5bbeSBoris Popov u_char ltype = 0; 95681a5bbeSBoris Popov int error; 96681a5bbeSBoris Popov 97681a5bbeSBoris Popov if (op == SMB_LOCK_SHARED) 98681a5bbeSBoris Popov ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 999e9421bcSDavide Italiano 1009e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp); 1019e9421bcSDavide Italiano if (error) 1029e9421bcSDavide Italiano return (error); 103681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 104681a5bbeSBoris Popov smb_rq_wstart(rqp); 105681a5bbeSBoris Popov mb_put_uint8(mbp, 0xff); /* secondary command */ 106681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* MBZ */ 107681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 108681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 109681a5bbeSBoris Popov mb_put_uint8(mbp, ltype); /* locktype */ 110681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 111681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 112681a5bbeSBoris Popov mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 113681a5bbeSBoris Popov mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 114681a5bbeSBoris Popov smb_rq_wend(rqp); 115681a5bbeSBoris Popov smb_rq_bstart(rqp); 116681a5bbeSBoris Popov mb_put_uint16le(mbp, pid); 117681a5bbeSBoris Popov mb_put_uint32le(mbp, start); 118681a5bbeSBoris Popov mb_put_uint32le(mbp, end - start); 119681a5bbeSBoris Popov smb_rq_bend(rqp); 120681a5bbeSBoris Popov error = smb_rq_simple(rqp); 121681a5bbeSBoris Popov smb_rq_done(rqp); 122681a5bbeSBoris Popov return error; 123681a5bbeSBoris Popov } 124681a5bbeSBoris Popov 125681a5bbeSBoris Popov int 126681a5bbeSBoris Popov smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 127681a5bbeSBoris Popov off_t start, off_t end, struct smb_cred *scred) 128681a5bbeSBoris Popov { 129681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 130681a5bbeSBoris Popov 131681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 132681a5bbeSBoris Popov /* 133681a5bbeSBoris Popov * TODO: use LOCK_BYTE_RANGE here. 134681a5bbeSBoris Popov */ 135681a5bbeSBoris Popov return EINVAL; 136681a5bbeSBoris Popov else 13795c2dc84SJohn Baldwin return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred); 138681a5bbeSBoris Popov } 139681a5bbeSBoris Popov 14014b2dc39SAndrey V. Elsukov static int 14114b2dc39SAndrey V. Elsukov smbfs_query_info_fs(struct smb_share *ssp, struct statfs *sbp, 14214b2dc39SAndrey V. Elsukov struct smb_cred *scred) 14314b2dc39SAndrey V. Elsukov { 14414b2dc39SAndrey V. Elsukov struct smb_t2rq *t2p; 14514b2dc39SAndrey V. Elsukov struct mbchain *mbp; 14614b2dc39SAndrey V. Elsukov struct mdchain *mdp; 14714b2dc39SAndrey V. Elsukov uint32_t bsize, bpu; 14814b2dc39SAndrey V. Elsukov int64_t units, funits; 14914b2dc39SAndrey V. Elsukov int error; 15014b2dc39SAndrey V. Elsukov 15114b2dc39SAndrey V. Elsukov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 15214b2dc39SAndrey V. Elsukov scred, &t2p); 15314b2dc39SAndrey V. Elsukov if (error) 15414b2dc39SAndrey V. Elsukov return (error); 15514b2dc39SAndrey V. Elsukov mbp = &t2p->t2_tparam; 15614b2dc39SAndrey V. Elsukov mb_init(mbp); 15714b2dc39SAndrey V. Elsukov mb_put_uint16le(mbp, SMB_QUERY_FS_SIZE_INFO); 15814b2dc39SAndrey V. Elsukov t2p->t2_maxpcount = 2; 15914b2dc39SAndrey V. Elsukov t2p->t2_maxdcount = sizeof(int64_t) * 2 + sizeof(uint32_t) * 2; 16014b2dc39SAndrey V. Elsukov error = smb_t2_request(t2p); 16114b2dc39SAndrey V. Elsukov if (error) { 16214b2dc39SAndrey V. Elsukov smb_t2_done(t2p); 16314b2dc39SAndrey V. Elsukov return (error); 16414b2dc39SAndrey V. Elsukov } 16514b2dc39SAndrey V. Elsukov mdp = &t2p->t2_rdata; 16614b2dc39SAndrey V. Elsukov md_get_int64le(mdp, &units); 16714b2dc39SAndrey V. Elsukov md_get_int64le(mdp, &funits); 16814b2dc39SAndrey V. Elsukov md_get_uint32le(mdp, &bpu); 16914b2dc39SAndrey V. Elsukov md_get_uint32le(mdp, &bsize); 17014b2dc39SAndrey V. Elsukov sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 17114b2dc39SAndrey V. Elsukov sbp->f_blocks= (uint64_t)units; /* total data blocks in filesystem */ 17214b2dc39SAndrey V. Elsukov sbp->f_bfree = (uint64_t)funits;/* free blocks in fs */ 17314b2dc39SAndrey V. Elsukov sbp->f_bavail= (uint64_t)funits;/* free blocks avail to non-superuser */ 17414b2dc39SAndrey V. Elsukov sbp->f_files = 0xffff; /* total file nodes in filesystem */ 17514b2dc39SAndrey V. Elsukov sbp->f_ffree = 0xffff; /* free file nodes in fs */ 17614b2dc39SAndrey V. Elsukov smb_t2_done(t2p); 17714b2dc39SAndrey V. Elsukov return (0); 17814b2dc39SAndrey V. Elsukov } 17914b2dc39SAndrey V. Elsukov 18014b2dc39SAndrey V. Elsukov 18114b2dc39SAndrey V. Elsukov static int 18214b2dc39SAndrey V. Elsukov smbfs_query_info_alloc(struct smb_share *ssp, struct statfs *sbp, 183681a5bbeSBoris Popov struct smb_cred *scred) 184681a5bbeSBoris Popov { 185681a5bbeSBoris Popov struct smb_t2rq *t2p; 186681a5bbeSBoris Popov struct mbchain *mbp; 187681a5bbeSBoris Popov struct mdchain *mdp; 188681a5bbeSBoris Popov u_int16_t bsize; 189681a5bbeSBoris Popov u_int32_t units, bpu, funits; 190681a5bbeSBoris Popov int error; 191681a5bbeSBoris Popov 192681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 193681a5bbeSBoris Popov scred, &t2p); 194681a5bbeSBoris Popov if (error) 195681a5bbeSBoris Popov return error; 196681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 197681a5bbeSBoris Popov mb_init(mbp); 198681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 199681a5bbeSBoris Popov t2p->t2_maxpcount = 4; 200681a5bbeSBoris Popov t2p->t2_maxdcount = 4 * 4 + 2; 201681a5bbeSBoris Popov error = smb_t2_request(t2p); 202681a5bbeSBoris Popov if (error) { 203681a5bbeSBoris Popov smb_t2_done(t2p); 204681a5bbeSBoris Popov return error; 205681a5bbeSBoris Popov } 206681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 207681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* fs id */ 208681a5bbeSBoris Popov md_get_uint32le(mdp, &bpu); 209681a5bbeSBoris Popov md_get_uint32le(mdp, &units); 210681a5bbeSBoris Popov md_get_uint32le(mdp, &funits); 211681a5bbeSBoris Popov md_get_uint16le(mdp, &bsize); 212681a5bbeSBoris Popov sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 213681a5bbeSBoris Popov sbp->f_blocks= units; /* total data blocks in filesystem */ 214681a5bbeSBoris Popov sbp->f_bfree = funits; /* free blocks in fs */ 215681a5bbeSBoris Popov sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 216681a5bbeSBoris Popov sbp->f_files = 0xffff; /* total file nodes in filesystem */ 217681a5bbeSBoris Popov sbp->f_ffree = 0xffff; /* free file nodes in fs */ 218681a5bbeSBoris Popov smb_t2_done(t2p); 219681a5bbeSBoris Popov return 0; 220681a5bbeSBoris Popov } 221681a5bbeSBoris Popov 22214b2dc39SAndrey V. Elsukov static int 22314b2dc39SAndrey V. Elsukov smbfs_query_info_disk(struct smb_share *ssp, struct statfs *sbp, 224681a5bbeSBoris Popov struct smb_cred *scred) 225681a5bbeSBoris Popov { 226afe09751SDavide Italiano struct smb_rq *rqp; 227681a5bbeSBoris Popov struct mdchain *mdp; 228681a5bbeSBoris Popov u_int16_t units, bpu, bsize, funits; 229681a5bbeSBoris Popov int error; 230681a5bbeSBoris Popov 2319e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, 2329e9421bcSDavide Italiano scred, &rqp); 2339e9421bcSDavide Italiano if (error) 2349e9421bcSDavide Italiano return (error); 235681a5bbeSBoris Popov smb_rq_wstart(rqp); 236681a5bbeSBoris Popov smb_rq_wend(rqp); 237681a5bbeSBoris Popov smb_rq_bstart(rqp); 238681a5bbeSBoris Popov smb_rq_bend(rqp); 239681a5bbeSBoris Popov error = smb_rq_simple(rqp); 240681a5bbeSBoris Popov if (error) { 241681a5bbeSBoris Popov smb_rq_done(rqp); 242681a5bbeSBoris Popov return error; 243681a5bbeSBoris Popov } 244681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 245681a5bbeSBoris Popov md_get_uint16le(mdp, &units); 246681a5bbeSBoris Popov md_get_uint16le(mdp, &bpu); 247681a5bbeSBoris Popov md_get_uint16le(mdp, &bsize); 248681a5bbeSBoris Popov md_get_uint16le(mdp, &funits); 249681a5bbeSBoris Popov sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 250681a5bbeSBoris Popov sbp->f_blocks= units; /* total data blocks in filesystem */ 251681a5bbeSBoris Popov sbp->f_bfree = funits; /* free blocks in fs */ 252681a5bbeSBoris Popov sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 253681a5bbeSBoris Popov sbp->f_files = 0xffff; /* total file nodes in filesystem */ 254681a5bbeSBoris Popov sbp->f_ffree = 0xffff; /* free file nodes in fs */ 255681a5bbeSBoris Popov smb_rq_done(rqp); 256681a5bbeSBoris Popov return 0; 257681a5bbeSBoris Popov } 258681a5bbeSBoris Popov 25914b2dc39SAndrey V. Elsukov int 26014b2dc39SAndrey V. Elsukov smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, 26114b2dc39SAndrey V. Elsukov struct smb_cred *scred) 26214b2dc39SAndrey V. Elsukov { 26314b2dc39SAndrey V. Elsukov 26414b2dc39SAndrey V. Elsukov if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) { 26514b2dc39SAndrey V. Elsukov if (smbfs_query_info_fs(ssp, sbp, scred) == 0) 26614b2dc39SAndrey V. Elsukov return (0); 26714b2dc39SAndrey V. Elsukov if (smbfs_query_info_alloc(ssp, sbp, scred) == 0) 26814b2dc39SAndrey V. Elsukov return (0); 26914b2dc39SAndrey V. Elsukov } 27014b2dc39SAndrey V. Elsukov return (smbfs_query_info_disk(ssp, sbp, scred)); 27114b2dc39SAndrey V. Elsukov } 27214b2dc39SAndrey V. Elsukov 2733c2f5c3cSBoris Popov static int 2743c2f5c3cSBoris Popov smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 2753c2f5c3cSBoris Popov { 2763c2f5c3cSBoris Popov struct smb_t2rq *t2p; 2773c2f5c3cSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 2783c2f5c3cSBoris Popov struct mbchain *mbp; 2793c2f5c3cSBoris Popov int error; 2803c2f5c3cSBoris Popov 2813c2f5c3cSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 2823c2f5c3cSBoris Popov scred, &t2p); 2833c2f5c3cSBoris Popov if (error) 2843c2f5c3cSBoris Popov return error; 2853c2f5c3cSBoris Popov mbp = &t2p->t2_tparam; 2863c2f5c3cSBoris Popov mb_init(mbp); 2873c2f5c3cSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 2883c2f5c3cSBoris Popov mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); 2893c2f5c3cSBoris Popov mb_put_uint32le(mbp, 0); 2903c2f5c3cSBoris Popov mbp = &t2p->t2_tdata; 2913c2f5c3cSBoris Popov mb_init(mbp); 2923c2f5c3cSBoris Popov mb_put_int64le(mbp, newsize); 2933c2f5c3cSBoris Popov mb_put_uint32le(mbp, 0); /* padding */ 2943c2f5c3cSBoris Popov mb_put_uint16le(mbp, 0); 2953c2f5c3cSBoris Popov t2p->t2_maxpcount = 2; 2963c2f5c3cSBoris Popov t2p->t2_maxdcount = 0; 2973c2f5c3cSBoris Popov error = smb_t2_request(t2p); 2983c2f5c3cSBoris Popov smb_t2_done(t2p); 2993c2f5c3cSBoris Popov return error; 3003c2f5c3cSBoris Popov } 3013c2f5c3cSBoris Popov 3023c2f5c3cSBoris Popov static int 3033c2f5c3cSBoris Popov smb_smb_flush(struct smbnode *np, struct smb_cred *scred) 3043c2f5c3cSBoris Popov { 3053c2f5c3cSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 306afe09751SDavide Italiano struct smb_rq *rqp; 3073c2f5c3cSBoris Popov struct mbchain *mbp; 3083c2f5c3cSBoris Popov int error; 3093c2f5c3cSBoris Popov 31008fe4bfbSTim J. Robbins if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) || 3112a4ad258STim J. Robbins SMBTOV(np)->v_type != VREG) 312d64ada50SJens Schweikhardt return 0; /* not a regular open file */ 3139e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_FLUSH, scred, &rqp); 3149e9421bcSDavide Italiano if (error) 3153c2f5c3cSBoris Popov return (error); 3163c2f5c3cSBoris Popov smb_rq_getrequest(rqp, &mbp); 3173c2f5c3cSBoris Popov smb_rq_wstart(rqp); 3183c2f5c3cSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 3193c2f5c3cSBoris Popov smb_rq_wend(rqp); 3203c2f5c3cSBoris Popov smb_rq_bstart(rqp); 3213c2f5c3cSBoris Popov smb_rq_bend(rqp); 3223c2f5c3cSBoris Popov error = smb_rq_simple(rqp); 3233c2f5c3cSBoris Popov smb_rq_done(rqp); 3243c2f5c3cSBoris Popov if (!error) 3253c2f5c3cSBoris Popov np->n_flag &= ~NFLUSHWIRE; 3263c2f5c3cSBoris Popov return (error); 3273c2f5c3cSBoris Popov } 3283c2f5c3cSBoris Popov 3293c2f5c3cSBoris Popov int 3303c2f5c3cSBoris Popov smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) 3313c2f5c3cSBoris Popov { 3323c2f5c3cSBoris Popov if (np->n_flag & NFLUSHWIRE) 3333c2f5c3cSBoris Popov return (smb_smb_flush(np, scred)); 3343c2f5c3cSBoris Popov return (0); 3353c2f5c3cSBoris Popov } 3363c2f5c3cSBoris Popov 337681a5bbeSBoris Popov int 338c829016eSAndrey V. Elsukov smbfs_smb_setfsize(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 339681a5bbeSBoris Popov { 340681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 341afe09751SDavide Italiano struct smb_rq *rqp; 342681a5bbeSBoris Popov struct mbchain *mbp; 343681a5bbeSBoris Popov int error; 344681a5bbeSBoris Popov 345c829016eSAndrey V. Elsukov if (!smbfs_smb_seteof(np, newsize, scred)) { 3463c2f5c3cSBoris Popov np->n_flag |= NFLUSHWIRE; 3473c2f5c3cSBoris Popov return (0); 3483c2f5c3cSBoris Popov } 349c829016eSAndrey V. Elsukov /* XXX: We should use SMB_COM_WRITE_ANDX to support large offsets */ 3509e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 3519e9421bcSDavide Italiano if (error) 3529e9421bcSDavide Italiano return (error); 353681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 354681a5bbeSBoris Popov smb_rq_wstart(rqp); 355681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 356681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 357c829016eSAndrey V. Elsukov mb_put_uint32le(mbp, (uint32_t)newsize); 358681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 359681a5bbeSBoris Popov smb_rq_wend(rqp); 360681a5bbeSBoris Popov smb_rq_bstart(rqp); 361681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_DATA); 362681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 363681a5bbeSBoris Popov smb_rq_bend(rqp); 364681a5bbeSBoris Popov error = smb_rq_simple(rqp); 365681a5bbeSBoris Popov smb_rq_done(rqp); 366681a5bbeSBoris Popov return error; 367681a5bbeSBoris Popov } 368681a5bbeSBoris Popov 3693c2f5c3cSBoris Popov int 3703c2f5c3cSBoris Popov smbfs_smb_query_info(struct smbnode *np, const char *name, int len, 3713c2f5c3cSBoris Popov struct smbfattr *fap, struct smb_cred *scred) 3723c2f5c3cSBoris Popov { 373afe09751SDavide Italiano struct smb_rq *rqp; 3743c2f5c3cSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 3753c2f5c3cSBoris Popov struct mbchain *mbp; 3763c2f5c3cSBoris Popov struct mdchain *mdp; 3773c2f5c3cSBoris Popov u_int8_t wc; 3783c2f5c3cSBoris Popov int error; 3793c2f5c3cSBoris Popov u_int16_t wattr; 3803c2f5c3cSBoris Popov u_int32_t lint; 3813c2f5c3cSBoris Popov 3829e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred, 3839e9421bcSDavide Italiano &rqp); 3849e9421bcSDavide Italiano if (error) 3859e9421bcSDavide Italiano return (error); 3863c2f5c3cSBoris Popov smb_rq_getrequest(rqp, &mbp); 3873c2f5c3cSBoris Popov smb_rq_wstart(rqp); 3883c2f5c3cSBoris Popov smb_rq_wend(rqp); 3893c2f5c3cSBoris Popov smb_rq_bstart(rqp); 3903c2f5c3cSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 3913c2f5c3cSBoris Popov do { 3923c2f5c3cSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); 3933c2f5c3cSBoris Popov if (error) 3943c2f5c3cSBoris Popov break; 3953c2f5c3cSBoris Popov smb_rq_bend(rqp); 3963c2f5c3cSBoris Popov error = smb_rq_simple(rqp); 3973c2f5c3cSBoris Popov if (error) 3983c2f5c3cSBoris Popov break; 3993c2f5c3cSBoris Popov smb_rq_getreply(rqp, &mdp); 4003c2f5c3cSBoris Popov if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 4013c2f5c3cSBoris Popov error = EBADRPC; 4023c2f5c3cSBoris Popov break; 4033c2f5c3cSBoris Popov } 4043c2f5c3cSBoris Popov md_get_uint16le(mdp, &wattr); 4053c2f5c3cSBoris Popov fap->fa_attr = wattr; 4063c2f5c3cSBoris Popov /* 4073c2f5c3cSBoris Popov * Be careful using the time returned here, as 4083c2f5c3cSBoris Popov * with FAT on NT4SP6, at least, the time returned is low 4093c2f5c3cSBoris Popov * 32 bits of 100s of nanoseconds (since 1601) so it rolls 4103c2f5c3cSBoris Popov * over about every seven minutes! 4113c2f5c3cSBoris Popov */ 4123c2f5c3cSBoris Popov md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ 4133c2f5c3cSBoris Popov if (lint) /* avoid bogus zero returns */ 4143c2f5c3cSBoris Popov smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, 4153c2f5c3cSBoris Popov &fap->fa_mtime); 4163c2f5c3cSBoris Popov md_get_uint32le(mdp, &lint); 4173c2f5c3cSBoris Popov fap->fa_size = lint; 4183c2f5c3cSBoris Popov } while(0); 4193c2f5c3cSBoris Popov smb_rq_done(rqp); 4203c2f5c3cSBoris Popov return error; 4213c2f5c3cSBoris Popov } 422681a5bbeSBoris Popov 423681a5bbeSBoris Popov /* 424681a5bbeSBoris Popov * Set DOS file attributes. mtime should be NULL for dialects above lm10 425681a5bbeSBoris Popov */ 426681a5bbeSBoris Popov int 427681a5bbeSBoris Popov smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 428681a5bbeSBoris Popov struct smb_cred *scred) 429681a5bbeSBoris Popov { 430afe09751SDavide Italiano struct smb_rq *rqp; 431681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 432681a5bbeSBoris Popov struct mbchain *mbp; 433681a5bbeSBoris Popov u_long time; 434681a5bbeSBoris Popov int error, svtz; 435681a5bbeSBoris Popov 4369e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred, 4379e9421bcSDavide Italiano &rqp); 4389e9421bcSDavide Italiano if (error) 4399e9421bcSDavide Italiano return (error); 440681a5bbeSBoris Popov svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 441681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 442681a5bbeSBoris Popov smb_rq_wstart(rqp); 443681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); 444681a5bbeSBoris Popov if (mtime) { 445681a5bbeSBoris Popov smb_time_local2server(mtime, svtz, &time); 446681a5bbeSBoris Popov } else 447681a5bbeSBoris Popov time = 0; 448681a5bbeSBoris Popov mb_put_uint32le(mbp, time); /* mtime */ 449681a5bbeSBoris Popov mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 450681a5bbeSBoris Popov smb_rq_wend(rqp); 451681a5bbeSBoris Popov smb_rq_bstart(rqp); 452681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 453681a5bbeSBoris Popov do { 454681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 455681a5bbeSBoris Popov if (error) 456681a5bbeSBoris Popov break; 457681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 45841f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { 45941f1dcccSKevin Lo mb_put_padbyte(mbp); 46041f1dcccSKevin Lo mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */ 46141f1dcccSKevin Lo } 462681a5bbeSBoris Popov mb_put_uint8(mbp, 0); 463681a5bbeSBoris Popov smb_rq_bend(rqp); 464681a5bbeSBoris Popov error = smb_rq_simple(rqp); 465fb8e9eadSBoris Popov if (error) { 466fb8e9eadSBoris Popov SMBERROR("smb_rq_simple(rqp) => error %d\n", error); 467681a5bbeSBoris Popov break; 468fb8e9eadSBoris Popov } 469681a5bbeSBoris Popov } while(0); 470681a5bbeSBoris Popov smb_rq_done(rqp); 471681a5bbeSBoris Popov return error; 472681a5bbeSBoris Popov } 473681a5bbeSBoris Popov 474681a5bbeSBoris Popov /* 475681a5bbeSBoris Popov * Note, win95 doesn't support this call. 476681a5bbeSBoris Popov */ 477681a5bbeSBoris Popov int 478681a5bbeSBoris Popov smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 479681a5bbeSBoris Popov struct timespec *atime, int attr, struct smb_cred *scred) 480681a5bbeSBoris Popov { 481681a5bbeSBoris Popov struct smb_t2rq *t2p; 482681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 483681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 484681a5bbeSBoris Popov struct mbchain *mbp; 485681a5bbeSBoris Popov u_int16_t date, time; 486681a5bbeSBoris Popov int error, tzoff; 487681a5bbeSBoris Popov 488681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 489681a5bbeSBoris Popov scred, &t2p); 490681a5bbeSBoris Popov if (error) 491681a5bbeSBoris Popov return error; 492681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 493681a5bbeSBoris Popov mb_init(mbp); 494681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_INFO_STANDARD); 495681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* MBZ */ 4963c2f5c3cSBoris Popov /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 497681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 498681a5bbeSBoris Popov if (error) { 499681a5bbeSBoris Popov smb_t2_done(t2p); 500681a5bbeSBoris Popov return error; 501681a5bbeSBoris Popov } 502681a5bbeSBoris Popov tzoff = vcp->vc_sopt.sv_tz; 503681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 504681a5bbeSBoris Popov mb_init(mbp); 505681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* creation time */ 506681a5bbeSBoris Popov if (atime) 507681a5bbeSBoris Popov smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 508681a5bbeSBoris Popov else 509681a5bbeSBoris Popov time = date = 0; 510681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 511681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 512681a5bbeSBoris Popov if (mtime) 513681a5bbeSBoris Popov smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 514681a5bbeSBoris Popov else 515681a5bbeSBoris Popov time = date = 0; 516681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 517681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 518681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* file size */ 519681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* allocation unit size */ 520681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); /* DOS attr */ 521681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* EA size */ 522681a5bbeSBoris Popov t2p->t2_maxpcount = 5 * 2; 523681a5bbeSBoris Popov t2p->t2_maxdcount = vcp->vc_txmax; 524681a5bbeSBoris Popov error = smb_t2_request(t2p); 525681a5bbeSBoris Popov smb_t2_done(t2p); 526681a5bbeSBoris Popov return error; 527681a5bbeSBoris Popov } 528681a5bbeSBoris Popov 529681a5bbeSBoris Popov /* 530681a5bbeSBoris Popov * NT level. Specially for win9x 531681a5bbeSBoris Popov */ 532681a5bbeSBoris Popov int 533681a5bbeSBoris Popov smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 534681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 535681a5bbeSBoris Popov { 536681a5bbeSBoris Popov struct smb_t2rq *t2p; 537681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 538681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 539681a5bbeSBoris Popov struct mbchain *mbp; 540681a5bbeSBoris Popov int64_t tm; 541681a5bbeSBoris Popov int error, tzoff; 542681a5bbeSBoris Popov 543681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 544681a5bbeSBoris Popov scred, &t2p); 545681a5bbeSBoris Popov if (error) 546681a5bbeSBoris Popov return error; 547681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 548681a5bbeSBoris Popov mb_init(mbp); 549681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 550681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* MBZ */ 5513c2f5c3cSBoris Popov /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 552681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 553681a5bbeSBoris Popov if (error) { 554681a5bbeSBoris Popov smb_t2_done(t2p); 555681a5bbeSBoris Popov return error; 556681a5bbeSBoris Popov } 557681a5bbeSBoris Popov tzoff = vcp->vc_sopt.sv_tz; 558681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 559681a5bbeSBoris Popov mb_init(mbp); 560681a5bbeSBoris Popov mb_put_int64le(mbp, 0); /* creation time */ 561681a5bbeSBoris Popov if (atime) { 562681a5bbeSBoris Popov smb_time_local2NT(atime, tzoff, &tm); 563681a5bbeSBoris Popov } else 564681a5bbeSBoris Popov tm = 0; 565681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 566681a5bbeSBoris Popov if (mtime) { 567681a5bbeSBoris Popov smb_time_local2NT(mtime, tzoff, &tm); 568681a5bbeSBoris Popov } else 569681a5bbeSBoris Popov tm = 0; 570681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 571681a5bbeSBoris Popov mb_put_int64le(mbp, tm); /* change time */ 572681a5bbeSBoris Popov mb_put_uint32le(mbp, attr); /* attr */ 573681a5bbeSBoris Popov t2p->t2_maxpcount = 24; 574681a5bbeSBoris Popov t2p->t2_maxdcount = 56; 575681a5bbeSBoris Popov error = smb_t2_request(t2p); 576681a5bbeSBoris Popov smb_t2_done(t2p); 577681a5bbeSBoris Popov return error; 578681a5bbeSBoris Popov } 579681a5bbeSBoris Popov 580681a5bbeSBoris Popov /* 581681a5bbeSBoris Popov * Set file atime and mtime. Doesn't supported by core dialect. 582681a5bbeSBoris Popov */ 583681a5bbeSBoris Popov int 584681a5bbeSBoris Popov smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 585681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 586681a5bbeSBoris Popov { 587afe09751SDavide Italiano struct smb_rq *rqp; 588681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 589681a5bbeSBoris Popov struct mbchain *mbp; 590681a5bbeSBoris Popov u_int16_t date, time; 591681a5bbeSBoris Popov int error, tzoff; 592681a5bbeSBoris Popov 5939e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred, 5949e9421bcSDavide Italiano &rqp); 5959e9421bcSDavide Italiano if (error) 5969e9421bcSDavide Italiano return (error); 597681a5bbeSBoris Popov tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 598681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 599681a5bbeSBoris Popov smb_rq_wstart(rqp); 600681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 601681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* creation time */ 602681a5bbeSBoris Popov 603681a5bbeSBoris Popov if (atime) 604681a5bbeSBoris Popov smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 605681a5bbeSBoris Popov else 606681a5bbeSBoris Popov time = date = 0; 607681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 608681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 609681a5bbeSBoris Popov if (mtime) 610681a5bbeSBoris Popov smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 611681a5bbeSBoris Popov else 612681a5bbeSBoris Popov time = date = 0; 613681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 614681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 615681a5bbeSBoris Popov smb_rq_wend(rqp); 616681a5bbeSBoris Popov smb_rq_bstart(rqp); 617681a5bbeSBoris Popov smb_rq_bend(rqp); 618681a5bbeSBoris Popov error = smb_rq_simple(rqp); 619681a5bbeSBoris Popov SMBSDEBUG("%d\n", error); 620681a5bbeSBoris Popov smb_rq_done(rqp); 621681a5bbeSBoris Popov return error; 622681a5bbeSBoris Popov } 623681a5bbeSBoris Popov 624681a5bbeSBoris Popov /* 625681a5bbeSBoris Popov * Set DOS file attributes. 626cd6dac7dSJonathan Anderson * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on. 627681a5bbeSBoris Popov */ 628681a5bbeSBoris Popov int 629681a5bbeSBoris Popov smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 630681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 631681a5bbeSBoris Popov { 632681a5bbeSBoris Popov struct smb_t2rq *t2p; 633681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 634681a5bbeSBoris Popov struct mbchain *mbp; 635681a5bbeSBoris Popov int64_t tm; 636681a5bbeSBoris Popov int error, svtz; 637681a5bbeSBoris Popov 638681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 639681a5bbeSBoris Popov scred, &t2p); 640681a5bbeSBoris Popov if (error) 641681a5bbeSBoris Popov return error; 642681a5bbeSBoris Popov svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 643681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 644681a5bbeSBoris Popov mb_init(mbp); 645681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 646681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 647681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); 648681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 649681a5bbeSBoris Popov mb_init(mbp); 650681a5bbeSBoris Popov mb_put_int64le(mbp, 0); /* creation time */ 651681a5bbeSBoris Popov if (atime) { 652681a5bbeSBoris Popov smb_time_local2NT(atime, svtz, &tm); 653681a5bbeSBoris Popov } else 654681a5bbeSBoris Popov tm = 0; 655681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 656681a5bbeSBoris Popov if (mtime) { 657681a5bbeSBoris Popov smb_time_local2NT(mtime, svtz, &tm); 658681a5bbeSBoris Popov } else 659681a5bbeSBoris Popov tm = 0; 660681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 661681a5bbeSBoris Popov mb_put_int64le(mbp, tm); /* change time */ 662681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); 663681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* padding */ 664681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 665681a5bbeSBoris Popov t2p->t2_maxpcount = 2; 666681a5bbeSBoris Popov t2p->t2_maxdcount = 0; 667681a5bbeSBoris Popov error = smb_t2_request(t2p); 668681a5bbeSBoris Popov smb_t2_done(t2p); 669681a5bbeSBoris Popov return error; 670681a5bbeSBoris Popov } 671681a5bbeSBoris Popov 672681a5bbeSBoris Popov 673681a5bbeSBoris Popov int 674681a5bbeSBoris Popov smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 675681a5bbeSBoris Popov { 676afe09751SDavide Italiano struct smb_rq *rqp; 677681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 678681a5bbeSBoris Popov struct mbchain *mbp; 679681a5bbeSBoris Popov struct mdchain *mdp; 680681a5bbeSBoris Popov u_int8_t wc; 681681a5bbeSBoris Popov u_int16_t fid, wattr, grantedmode; 682681a5bbeSBoris Popov int error; 683681a5bbeSBoris Popov 6849e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp); 6859e9421bcSDavide Italiano if (error) 6869e9421bcSDavide Italiano return (error); 687681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 688681a5bbeSBoris Popov smb_rq_wstart(rqp); 689681a5bbeSBoris Popov mb_put_uint16le(mbp, accmode); 690681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 691681a5bbeSBoris Popov smb_rq_wend(rqp); 692681a5bbeSBoris Popov smb_rq_bstart(rqp); 693681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 694681a5bbeSBoris Popov do { 695681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 696681a5bbeSBoris Popov if (error) 697681a5bbeSBoris Popov break; 698681a5bbeSBoris Popov smb_rq_bend(rqp); 699681a5bbeSBoris Popov error = smb_rq_simple(rqp); 700681a5bbeSBoris Popov if (error) 701681a5bbeSBoris Popov break; 702681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 703681a5bbeSBoris Popov if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 704681a5bbeSBoris Popov error = EBADRPC; 705681a5bbeSBoris Popov break; 706681a5bbeSBoris Popov } 707681a5bbeSBoris Popov md_get_uint16(mdp, &fid); 708681a5bbeSBoris Popov md_get_uint16le(mdp, &wattr); 709681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* mtime */ 710681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* fsize */ 711681a5bbeSBoris Popov md_get_uint16le(mdp, &grantedmode); 712681a5bbeSBoris Popov /* 713681a5bbeSBoris Popov * TODO: refresh attributes from this reply 714681a5bbeSBoris Popov */ 715681a5bbeSBoris Popov } while(0); 716681a5bbeSBoris Popov smb_rq_done(rqp); 717681a5bbeSBoris Popov if (error) 718681a5bbeSBoris Popov return error; 719681a5bbeSBoris Popov np->n_fid = fid; 720681a5bbeSBoris Popov np->n_rwstate = grantedmode; 721681a5bbeSBoris Popov return 0; 722681a5bbeSBoris Popov } 723681a5bbeSBoris Popov 724681a5bbeSBoris Popov 725681a5bbeSBoris Popov int 726681a5bbeSBoris Popov smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 727681a5bbeSBoris Popov struct smb_cred *scred) 728681a5bbeSBoris Popov { 729afe09751SDavide Italiano struct smb_rq *rqp; 730681a5bbeSBoris Popov struct mbchain *mbp; 731681a5bbeSBoris Popov u_long time; 732681a5bbeSBoris Popov int error; 733681a5bbeSBoris Popov 7349e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp); 7359e9421bcSDavide Italiano if (error) 7369e9421bcSDavide Italiano return (error); 737681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 738681a5bbeSBoris Popov smb_rq_wstart(rqp); 739681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 740681a5bbeSBoris Popov if (mtime) { 741681a5bbeSBoris Popov smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 742681a5bbeSBoris Popov } else 743681a5bbeSBoris Popov time = 0; 744681a5bbeSBoris Popov mb_put_uint32le(mbp, time); 745681a5bbeSBoris Popov smb_rq_wend(rqp); 746681a5bbeSBoris Popov smb_rq_bstart(rqp); 747681a5bbeSBoris Popov smb_rq_bend(rqp); 748681a5bbeSBoris Popov error = smb_rq_simple(rqp); 749681a5bbeSBoris Popov smb_rq_done(rqp); 750681a5bbeSBoris Popov return error; 751681a5bbeSBoris Popov } 752681a5bbeSBoris Popov 753681a5bbeSBoris Popov int 754681a5bbeSBoris Popov smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 755681a5bbeSBoris Popov struct smb_cred *scred) 756681a5bbeSBoris Popov { 757afe09751SDavide Italiano struct smb_rq *rqp; 758681a5bbeSBoris Popov struct smb_share *ssp = dnp->n_mount->sm_share; 759681a5bbeSBoris Popov struct mbchain *mbp; 760681a5bbeSBoris Popov struct mdchain *mdp; 761681a5bbeSBoris Popov struct timespec ctime; 762681a5bbeSBoris Popov u_int8_t wc; 763681a5bbeSBoris Popov u_int16_t fid; 764681a5bbeSBoris Popov u_long tm; 765681a5bbeSBoris Popov int error; 766681a5bbeSBoris Popov 7679e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE, scred, &rqp); 7689e9421bcSDavide Italiano if (error) 7699e9421bcSDavide Italiano return (error); 770681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 771681a5bbeSBoris Popov smb_rq_wstart(rqp); 772681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 773681a5bbeSBoris Popov nanotime(&ctime); 774681a5bbeSBoris Popov smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 775681a5bbeSBoris Popov mb_put_uint32le(mbp, tm); 776681a5bbeSBoris Popov smb_rq_wend(rqp); 777681a5bbeSBoris Popov smb_rq_bstart(rqp); 778681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 779681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 780681a5bbeSBoris Popov if (!error) { 781681a5bbeSBoris Popov smb_rq_bend(rqp); 782681a5bbeSBoris Popov error = smb_rq_simple(rqp); 783681a5bbeSBoris Popov if (!error) { 784681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 785681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 786681a5bbeSBoris Popov if (wc == 1) 787681a5bbeSBoris Popov md_get_uint16(mdp, &fid); 788681a5bbeSBoris Popov else 789681a5bbeSBoris Popov error = EBADRPC; 790681a5bbeSBoris Popov } 791681a5bbeSBoris Popov } 792681a5bbeSBoris Popov smb_rq_done(rqp); 793681a5bbeSBoris Popov if (error) 794681a5bbeSBoris Popov return error; 795681a5bbeSBoris Popov smbfs_smb_close(ssp, fid, &ctime, scred); 796681a5bbeSBoris Popov return error; 797681a5bbeSBoris Popov } 798681a5bbeSBoris Popov 799681a5bbeSBoris Popov int 800681a5bbeSBoris Popov smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 801681a5bbeSBoris Popov { 802afe09751SDavide Italiano struct smb_rq *rqp; 803681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 804681a5bbeSBoris Popov struct mbchain *mbp; 805681a5bbeSBoris Popov int error; 806681a5bbeSBoris Popov 8079e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp); 8089e9421bcSDavide Italiano if (error) 8099e9421bcSDavide Italiano return (error); 810681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 811681a5bbeSBoris Popov smb_rq_wstart(rqp); 812681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 813681a5bbeSBoris Popov smb_rq_wend(rqp); 814681a5bbeSBoris Popov smb_rq_bstart(rqp); 815681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 816681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 817681a5bbeSBoris Popov if (!error) { 818681a5bbeSBoris Popov smb_rq_bend(rqp); 819681a5bbeSBoris Popov error = smb_rq_simple(rqp); 820681a5bbeSBoris Popov } 821681a5bbeSBoris Popov smb_rq_done(rqp); 822681a5bbeSBoris Popov return error; 823681a5bbeSBoris Popov } 824681a5bbeSBoris Popov 825681a5bbeSBoris Popov int 826681a5bbeSBoris Popov smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 827681a5bbeSBoris Popov const char *tname, int tnmlen, struct smb_cred *scred) 828681a5bbeSBoris Popov { 829afe09751SDavide Italiano struct smb_rq *rqp; 830681a5bbeSBoris Popov struct smb_share *ssp = src->n_mount->sm_share; 831681a5bbeSBoris Popov struct mbchain *mbp; 832681a5bbeSBoris Popov int error; 833681a5bbeSBoris Popov 8349e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp); 8359e9421bcSDavide Italiano if (error) 8369e9421bcSDavide Italiano return (error); 837681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 838681a5bbeSBoris Popov smb_rq_wstart(rqp); 839681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 840681a5bbeSBoris Popov smb_rq_wend(rqp); 841681a5bbeSBoris Popov smb_rq_bstart(rqp); 842681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 843681a5bbeSBoris Popov do { 844681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 845681a5bbeSBoris Popov if (error) 846681a5bbeSBoris Popov break; 847681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 848681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 849681a5bbeSBoris Popov if (error) 850681a5bbeSBoris Popov break; 851681a5bbeSBoris Popov smb_rq_bend(rqp); 852681a5bbeSBoris Popov error = smb_rq_simple(rqp); 853681a5bbeSBoris Popov } while(0); 854681a5bbeSBoris Popov smb_rq_done(rqp); 855681a5bbeSBoris Popov return error; 856681a5bbeSBoris Popov } 857681a5bbeSBoris Popov 858681a5bbeSBoris Popov int 859681a5bbeSBoris Popov smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 860681a5bbeSBoris Popov const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 861681a5bbeSBoris Popov { 862afe09751SDavide Italiano struct smb_rq *rqp; 863681a5bbeSBoris Popov struct smb_share *ssp = src->n_mount->sm_share; 864681a5bbeSBoris Popov struct mbchain *mbp; 865681a5bbeSBoris Popov int error; 866681a5bbeSBoris Popov 8679e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp); 8689e9421bcSDavide Italiano if (error) 8699e9421bcSDavide Italiano return (error); 870681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 871681a5bbeSBoris Popov smb_rq_wstart(rqp); 872681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 873681a5bbeSBoris Popov mb_put_uint16le(mbp, 0x20); /* delete target file */ 874681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 875681a5bbeSBoris Popov smb_rq_wend(rqp); 876681a5bbeSBoris Popov smb_rq_bstart(rqp); 877681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 878681a5bbeSBoris Popov do { 879681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 880681a5bbeSBoris Popov if (error) 881681a5bbeSBoris Popov break; 882681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 883681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 884681a5bbeSBoris Popov if (error) 885681a5bbeSBoris Popov break; 886681a5bbeSBoris Popov smb_rq_bend(rqp); 887681a5bbeSBoris Popov error = smb_rq_simple(rqp); 888681a5bbeSBoris Popov } while(0); 889681a5bbeSBoris Popov smb_rq_done(rqp); 890681a5bbeSBoris Popov return error; 891681a5bbeSBoris Popov } 892681a5bbeSBoris Popov 893681a5bbeSBoris Popov int 894681a5bbeSBoris Popov smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 895681a5bbeSBoris Popov struct smb_cred *scred) 896681a5bbeSBoris Popov { 897afe09751SDavide Italiano struct smb_rq *rqp; 898681a5bbeSBoris Popov struct smb_share *ssp = dnp->n_mount->sm_share; 899681a5bbeSBoris Popov struct mbchain *mbp; 900681a5bbeSBoris Popov int error; 901681a5bbeSBoris Popov 9029e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred, 9039e9421bcSDavide Italiano &rqp); 9049e9421bcSDavide Italiano if (error) 9059e9421bcSDavide Italiano return (error); 906681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 907681a5bbeSBoris Popov smb_rq_wstart(rqp); 908681a5bbeSBoris Popov smb_rq_wend(rqp); 909681a5bbeSBoris Popov smb_rq_bstart(rqp); 910681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 911681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 912681a5bbeSBoris Popov if (!error) { 913681a5bbeSBoris Popov smb_rq_bend(rqp); 914681a5bbeSBoris Popov error = smb_rq_simple(rqp); 915681a5bbeSBoris Popov } 916681a5bbeSBoris Popov smb_rq_done(rqp); 917681a5bbeSBoris Popov return error; 918681a5bbeSBoris Popov } 919681a5bbeSBoris Popov 920681a5bbeSBoris Popov int 921681a5bbeSBoris Popov smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 922681a5bbeSBoris Popov { 923afe09751SDavide Italiano struct smb_rq *rqp; 924681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 925681a5bbeSBoris Popov struct mbchain *mbp; 926681a5bbeSBoris Popov int error; 927681a5bbeSBoris Popov 9289e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred, 9299e9421bcSDavide Italiano &rqp); 9309e9421bcSDavide Italiano if (error) 9319e9421bcSDavide Italiano return (error); 932681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 933681a5bbeSBoris Popov smb_rq_wstart(rqp); 934681a5bbeSBoris Popov smb_rq_wend(rqp); 935681a5bbeSBoris Popov smb_rq_bstart(rqp); 936681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 937681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 938681a5bbeSBoris Popov if (!error) { 939681a5bbeSBoris Popov smb_rq_bend(rqp); 940681a5bbeSBoris Popov error = smb_rq_simple(rqp); 941681a5bbeSBoris Popov } 942681a5bbeSBoris Popov smb_rq_done(rqp); 943681a5bbeSBoris Popov return error; 944681a5bbeSBoris Popov } 945681a5bbeSBoris Popov 946681a5bbeSBoris Popov static int 947681a5bbeSBoris Popov smbfs_smb_search(struct smbfs_fctx *ctx) 948681a5bbeSBoris Popov { 949681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 950681a5bbeSBoris Popov struct smb_rq *rqp; 951681a5bbeSBoris Popov struct mbchain *mbp; 952681a5bbeSBoris Popov struct mdchain *mdp; 953681a5bbeSBoris Popov u_int8_t wc, bt; 954681a5bbeSBoris Popov u_int16_t ec, dlen, bc; 955681a5bbeSBoris Popov int maxent, error, iseof = 0; 956681a5bbeSBoris Popov 957681a5bbeSBoris Popov maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 958681a5bbeSBoris Popov if (ctx->f_rq) { 959681a5bbeSBoris Popov smb_rq_done(ctx->f_rq); 960681a5bbeSBoris Popov ctx->f_rq = NULL; 961681a5bbeSBoris Popov } 962681a5bbeSBoris Popov error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 963681a5bbeSBoris Popov if (error) 9649e9421bcSDavide Italiano return (error); 965681a5bbeSBoris Popov ctx->f_rq = rqp; 966681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 967681a5bbeSBoris Popov smb_rq_wstart(rqp); 968681a5bbeSBoris Popov mb_put_uint16le(mbp, maxent); /* max entries to return */ 969681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_attrmask); 970681a5bbeSBoris Popov smb_rq_wend(rqp); 971681a5bbeSBoris Popov smb_rq_bstart(rqp); 972681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 973681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 974681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 975681a5bbeSBoris Popov if (error) 976681a5bbeSBoris Popov return error; 977681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_VARIABLE); 978681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); /* context length */ 979681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 980681a5bbeSBoris Popov } else { 98141f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) { 98241f1dcccSKevin Lo mb_put_padbyte(mbp); 98341f1dcccSKevin Lo mb_put_uint8(mbp, 0); 98441f1dcccSKevin Lo } 985681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* file name length */ 986681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_VARIABLE); 987681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SKEYLEN); 988681a5bbeSBoris Popov mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 989681a5bbeSBoris Popov } 990681a5bbeSBoris Popov smb_rq_bend(rqp); 991681a5bbeSBoris Popov error = smb_rq_simple(rqp); 992681a5bbeSBoris Popov if (error) { 993681a5bbeSBoris Popov if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 994681a5bbeSBoris Popov error = 0; 995681a5bbeSBoris Popov iseof = 1; 996681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_EOF; 997681a5bbeSBoris Popov } else 998681a5bbeSBoris Popov return error; 999681a5bbeSBoris Popov } 1000681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 1001681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 1002681a5bbeSBoris Popov if (wc != 1) 1003681a5bbeSBoris Popov return iseof ? ENOENT : EBADRPC; 1004681a5bbeSBoris Popov md_get_uint16le(mdp, &ec); 1005681a5bbeSBoris Popov if (ec == 0) 1006681a5bbeSBoris Popov return ENOENT; 1007681a5bbeSBoris Popov ctx->f_ecnt = ec; 1008681a5bbeSBoris Popov md_get_uint16le(mdp, &bc); 1009681a5bbeSBoris Popov if (bc < 3) 1010681a5bbeSBoris Popov return EBADRPC; 1011681a5bbeSBoris Popov bc -= 3; 1012681a5bbeSBoris Popov md_get_uint8(mdp, &bt); 1013681a5bbeSBoris Popov if (bt != SMB_DT_VARIABLE) 1014681a5bbeSBoris Popov return EBADRPC; 1015681a5bbeSBoris Popov md_get_uint16le(mdp, &dlen); 1016681a5bbeSBoris Popov if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 1017681a5bbeSBoris Popov return EBADRPC; 1018681a5bbeSBoris Popov return 0; 1019681a5bbeSBoris Popov } 1020681a5bbeSBoris Popov 1021681a5bbeSBoris Popov static int 1022681a5bbeSBoris Popov smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 1023681a5bbeSBoris Popov const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1024681a5bbeSBoris Popov { 1025681a5bbeSBoris Popov ctx->f_attrmask = attr; 1026681a5bbeSBoris Popov if (wildcard) { 1027681a5bbeSBoris Popov if (wclen == 1 && wildcard[0] == '*') { 1028681a5bbeSBoris Popov ctx->f_wildcard = "*.*"; 1029681a5bbeSBoris Popov ctx->f_wclen = 3; 1030681a5bbeSBoris Popov } else { 1031681a5bbeSBoris Popov ctx->f_wildcard = wildcard; 1032681a5bbeSBoris Popov ctx->f_wclen = wclen; 1033681a5bbeSBoris Popov } 1034681a5bbeSBoris Popov } else { 1035681a5bbeSBoris Popov ctx->f_wildcard = NULL; 1036681a5bbeSBoris Popov ctx->f_wclen = 0; 1037681a5bbeSBoris Popov } 1038681a5bbeSBoris Popov ctx->f_name = ctx->f_fname; 1039681a5bbeSBoris Popov return 0; 1040681a5bbeSBoris Popov } 1041681a5bbeSBoris Popov 1042681a5bbeSBoris Popov static int 1043681a5bbeSBoris Popov smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 1044681a5bbeSBoris Popov { 1045681a5bbeSBoris Popov struct mdchain *mbp; 1046681a5bbeSBoris Popov struct smb_rq *rqp; 1047681a5bbeSBoris Popov char *cp; 1048681a5bbeSBoris Popov u_int8_t battr; 1049681a5bbeSBoris Popov u_int16_t date, time; 1050681a5bbeSBoris Popov u_int32_t size; 1051681a5bbeSBoris Popov int error; 1052681a5bbeSBoris Popov 1053681a5bbeSBoris Popov if (ctx->f_ecnt == 0) { 1054681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_EOF) 1055681a5bbeSBoris Popov return ENOENT; 1056681a5bbeSBoris Popov ctx->f_left = ctx->f_limit = limit; 1057681a5bbeSBoris Popov error = smbfs_smb_search(ctx); 1058681a5bbeSBoris Popov if (error) 1059681a5bbeSBoris Popov return error; 1060681a5bbeSBoris Popov } 1061681a5bbeSBoris Popov rqp = ctx->f_rq; 1062681a5bbeSBoris Popov smb_rq_getreply(rqp, &mbp); 1063681a5bbeSBoris Popov md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1064681a5bbeSBoris Popov md_get_uint8(mbp, &battr); 1065681a5bbeSBoris Popov md_get_uint16le(mbp, &time); 1066681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1067681a5bbeSBoris Popov md_get_uint32le(mbp, &size); 1068681a5bbeSBoris Popov cp = ctx->f_name; 1069681a5bbeSBoris Popov md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 1070681a5bbeSBoris Popov cp[sizeof(ctx->f_fname) - 1] = 0; 1071681a5bbeSBoris Popov cp += strlen(cp) - 1; 1072681a5bbeSBoris Popov while (*cp == ' ' && cp >= ctx->f_name) 1073681a5bbeSBoris Popov *cp-- = 0; 1074681a5bbeSBoris Popov ctx->f_attr.fa_attr = battr; 1075681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 1076681a5bbeSBoris Popov &ctx->f_attr.fa_mtime); 1077681a5bbeSBoris Popov ctx->f_attr.fa_size = size; 1078681a5bbeSBoris Popov ctx->f_nmlen = strlen(ctx->f_name); 1079681a5bbeSBoris Popov ctx->f_ecnt--; 1080681a5bbeSBoris Popov ctx->f_left--; 1081681a5bbeSBoris Popov return 0; 1082681a5bbeSBoris Popov } 1083681a5bbeSBoris Popov 1084681a5bbeSBoris Popov static int 1085681a5bbeSBoris Popov smbfs_findcloseLM1(struct smbfs_fctx *ctx) 1086681a5bbeSBoris Popov { 1087681a5bbeSBoris Popov if (ctx->f_rq) 1088681a5bbeSBoris Popov smb_rq_done(ctx->f_rq); 1089681a5bbeSBoris Popov return 0; 1090681a5bbeSBoris Popov } 1091681a5bbeSBoris Popov 1092681a5bbeSBoris Popov /* 1093681a5bbeSBoris Popov * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 1094681a5bbeSBoris Popov */ 1095681a5bbeSBoris Popov static int 1096681a5bbeSBoris Popov smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 1097681a5bbeSBoris Popov { 1098681a5bbeSBoris Popov struct smb_t2rq *t2p; 1099681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1100681a5bbeSBoris Popov struct mbchain *mbp; 1101681a5bbeSBoris Popov struct mdchain *mdp; 1102681a5bbeSBoris Popov u_int16_t tw, flags; 1103681a5bbeSBoris Popov int error; 1104681a5bbeSBoris Popov 1105681a5bbeSBoris Popov if (ctx->f_t2) { 1106681a5bbeSBoris Popov smb_t2_done(ctx->f_t2); 1107681a5bbeSBoris Popov ctx->f_t2 = NULL; 1108681a5bbeSBoris Popov } 1109681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 1110681a5bbeSBoris Popov flags = 8 | 2; /* <resume> | <close if EOS> */ 1111681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 1112681a5bbeSBoris Popov flags |= 1; /* close search after this request */ 1113681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_NOCLOSE; 1114681a5bbeSBoris Popov } 1115681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1116681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 1117681a5bbeSBoris Popov ctx->f_scred, &t2p); 1118681a5bbeSBoris Popov if (error) 1119681a5bbeSBoris Popov return error; 1120681a5bbeSBoris Popov ctx->f_t2 = t2p; 1121681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 1122681a5bbeSBoris Popov mb_init(mbp); 1123681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_attrmask); 1124681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_limit); 1125681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 1126681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_infolevel); 1127681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); 1128681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1129681a5bbeSBoris Popov if (error) 1130681a5bbeSBoris Popov return error; 1131681a5bbeSBoris Popov } else { 1132681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 1133681a5bbeSBoris Popov ctx->f_scred, &t2p); 1134681a5bbeSBoris Popov if (error) 1135681a5bbeSBoris Popov return error; 1136681a5bbeSBoris Popov ctx->f_t2 = t2p; 1137681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 1138681a5bbeSBoris Popov mb_init(mbp); 1139681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1140681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_limit); 1141681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_infolevel); 1142681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* resume key */ 1143681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 1144681a5bbeSBoris Popov if (ctx->f_rname) 114541f1dcccSKevin Lo mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM); 1146681a5bbeSBoris Popov else 1147681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* resume file name */ 1148681a5bbeSBoris Popov #if 0 1149681a5bbeSBoris Popov struct timeval tv; 1150681a5bbeSBoris Popov tv.tv_sec = 0; 1151681a5bbeSBoris Popov tv.tv_usec = 200 * 1000; /* 200ms */ 1152681a5bbeSBoris Popov if (vcp->vc_flags & SMBC_WIN95) { 1153681a5bbeSBoris Popov /* 1154681a5bbeSBoris Popov * some implementations suggests to sleep here 1155681a5bbeSBoris Popov * for 200ms, due to the bug in the Win95. 1156681a5bbeSBoris Popov * I've didn't notice any problem, but put code 1157681a5bbeSBoris Popov * for it. 1158681a5bbeSBoris Popov */ 11594d70511aSJohn Baldwin pause("fix95", tvtohz(&tv)); 1160681a5bbeSBoris Popov } 1161681a5bbeSBoris Popov #endif 1162681a5bbeSBoris Popov } 1163681a5bbeSBoris Popov t2p->t2_maxpcount = 5 * 2; 1164681a5bbeSBoris Popov t2p->t2_maxdcount = vcp->vc_txmax; 1165681a5bbeSBoris Popov error = smb_t2_request(t2p); 1166681a5bbeSBoris Popov if (error) 1167681a5bbeSBoris Popov return error; 1168681a5bbeSBoris Popov mdp = &t2p->t2_rparam; 1169681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1170681a5bbeSBoris Popov if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 1171681a5bbeSBoris Popov return error; 1172681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1173681a5bbeSBoris Popov } 1174681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 1175681a5bbeSBoris Popov return error; 1176681a5bbeSBoris Popov ctx->f_ecnt = tw; 1177681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 1178681a5bbeSBoris Popov return error; 1179681a5bbeSBoris Popov if (tw) 1180681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1181681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 1182681a5bbeSBoris Popov return error; 1183681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 1184681a5bbeSBoris Popov return error; 1185cc518d3bSBoris Popov if (ctx->f_ecnt == 0) { 1186cc518d3bSBoris Popov ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1187681a5bbeSBoris Popov return ENOENT; 1188cc518d3bSBoris Popov } 1189681a5bbeSBoris Popov ctx->f_rnameofs = tw; 1190681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 1191681a5bbeSBoris Popov if (mdp->md_top == NULL) { 1192681a5bbeSBoris Popov printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 1193681a5bbeSBoris Popov return ENOENT; 1194681a5bbeSBoris Popov } 1195681a5bbeSBoris Popov if (mdp->md_top->m_len == 0) { 1196681a5bbeSBoris Popov printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 1197681a5bbeSBoris Popov return ENOENT; 1198681a5bbeSBoris Popov } 1199681a5bbeSBoris Popov ctx->f_eofs = 0; 1200681a5bbeSBoris Popov return 0; 1201681a5bbeSBoris Popov } 1202681a5bbeSBoris Popov 1203681a5bbeSBoris Popov static int 1204681a5bbeSBoris Popov smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1205681a5bbeSBoris Popov { 1206afe09751SDavide Italiano struct smb_rq *rqp; 1207681a5bbeSBoris Popov struct mbchain *mbp; 1208681a5bbeSBoris Popov int error; 1209681a5bbeSBoris Popov 12109e9421bcSDavide Italiano error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, 12119e9421bcSDavide Italiano ctx->f_scred, &rqp); 12129e9421bcSDavide Italiano if (error) 12139e9421bcSDavide Italiano return (error); 1214681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 1215681a5bbeSBoris Popov smb_rq_wstart(rqp); 1216681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1217681a5bbeSBoris Popov smb_rq_wend(rqp); 1218681a5bbeSBoris Popov smb_rq_bstart(rqp); 1219681a5bbeSBoris Popov smb_rq_bend(rqp); 1220681a5bbeSBoris Popov error = smb_rq_simple(rqp); 1221681a5bbeSBoris Popov smb_rq_done(rqp); 1222681a5bbeSBoris Popov return error; 1223681a5bbeSBoris Popov } 1224681a5bbeSBoris Popov 1225681a5bbeSBoris Popov static int 1226681a5bbeSBoris Popov smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1227681a5bbeSBoris Popov const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1228681a5bbeSBoris Popov { 122941f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 123041f1dcccSKevin Lo ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK); 123141f1dcccSKevin Lo } else 1232a163d034SWarner Losh ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 1233681a5bbeSBoris Popov ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1234681a5bbeSBoris Popov SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1235681a5bbeSBoris Popov ctx->f_attrmask = attr; 1236681a5bbeSBoris Popov ctx->f_wildcard = wildcard; 1237681a5bbeSBoris Popov ctx->f_wclen = wclen; 1238681a5bbeSBoris Popov return 0; 1239681a5bbeSBoris Popov } 1240681a5bbeSBoris Popov 1241681a5bbeSBoris Popov static int 1242681a5bbeSBoris Popov smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1243681a5bbeSBoris Popov { 1244681a5bbeSBoris Popov struct mdchain *mbp; 1245681a5bbeSBoris Popov struct smb_t2rq *t2p; 1246681a5bbeSBoris Popov char *cp; 1247681a5bbeSBoris Popov u_int8_t tb; 1248681a5bbeSBoris Popov u_int16_t date, time, wattr; 1249681a5bbeSBoris Popov u_int32_t size, next, dattr; 1250681a5bbeSBoris Popov int64_t lint; 1251681a5bbeSBoris Popov int error, svtz, cnt, fxsz, nmlen, recsz; 1252681a5bbeSBoris Popov 1253681a5bbeSBoris Popov if (ctx->f_ecnt == 0) { 1254681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_EOF) 1255681a5bbeSBoris Popov return ENOENT; 1256681a5bbeSBoris Popov ctx->f_left = ctx->f_limit = limit; 1257681a5bbeSBoris Popov error = smbfs_smb_trans2find2(ctx); 1258681a5bbeSBoris Popov if (error) 1259681a5bbeSBoris Popov return error; 1260681a5bbeSBoris Popov } 1261681a5bbeSBoris Popov t2p = ctx->f_t2; 1262681a5bbeSBoris Popov mbp = &t2p->t2_rdata; 1263681a5bbeSBoris Popov svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1264681a5bbeSBoris Popov switch (ctx->f_infolevel) { 1265681a5bbeSBoris Popov case SMB_INFO_STANDARD: 1266681a5bbeSBoris Popov next = 0; 1267681a5bbeSBoris Popov fxsz = 0; 1268681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1269681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* creation time */ 1270681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1271681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* access time */ 1272681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 1273681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1274681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* access time */ 1275681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 1276681a5bbeSBoris Popov md_get_uint32le(mbp, &size); 1277681a5bbeSBoris Popov ctx->f_attr.fa_size = size; 1278681a5bbeSBoris Popov md_get_uint32(mbp, NULL); /* allocation size */ 1279681a5bbeSBoris Popov md_get_uint16le(mbp, &wattr); 1280681a5bbeSBoris Popov ctx->f_attr.fa_attr = wattr; 1281681a5bbeSBoris Popov md_get_uint8(mbp, &tb); 1282681a5bbeSBoris Popov size = nmlen = tb; 1283681a5bbeSBoris Popov fxsz = 23; 1284681a5bbeSBoris Popov recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1285681a5bbeSBoris Popov break; 1286681a5bbeSBoris Popov case SMB_FIND_FILE_DIRECTORY_INFO: 1287681a5bbeSBoris Popov md_get_uint32le(mbp, &next); 1288681a5bbeSBoris Popov md_get_uint32(mbp, NULL); /* file index */ 1289681a5bbeSBoris Popov md_get_int64(mbp, NULL); /* creation time */ 1290681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1291681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 1292681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1293681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 1294681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1295681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 1296681a5bbeSBoris Popov md_get_int64le(mbp, &lint); /* file size */ 1297681a5bbeSBoris Popov ctx->f_attr.fa_size = lint; 1298681a5bbeSBoris Popov md_get_int64(mbp, NULL); /* real size (should use) */ 1299798bb23eSBoris Popov md_get_uint32le(mbp, &dattr); /* EA */ 1300681a5bbeSBoris Popov ctx->f_attr.fa_attr = dattr; 1301681a5bbeSBoris Popov md_get_uint32le(mbp, &size); /* name len */ 1302681a5bbeSBoris Popov fxsz = 64; 1303681a5bbeSBoris Popov recsz = next ? next : fxsz + size; 1304681a5bbeSBoris Popov break; 1305681a5bbeSBoris Popov default: 1306681a5bbeSBoris Popov SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 1307681a5bbeSBoris Popov return EINVAL; 1308681a5bbeSBoris Popov } 130941f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 131041f1dcccSKevin Lo nmlen = min(size, SMB_MAXFNAMELEN * 2); 131141f1dcccSKevin Lo } else 1312681a5bbeSBoris Popov nmlen = min(size, SMB_MAXFNAMELEN); 1313681a5bbeSBoris Popov cp = ctx->f_name; 1314681a5bbeSBoris Popov error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1315681a5bbeSBoris Popov if (error) 1316681a5bbeSBoris Popov return error; 1317681a5bbeSBoris Popov if (next) { 1318681a5bbeSBoris Popov cnt = next - nmlen - fxsz; 1319681a5bbeSBoris Popov if (cnt > 0) 1320681a5bbeSBoris Popov md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1321681a5bbeSBoris Popov else if (cnt < 0) { 1322681a5bbeSBoris Popov SMBERROR("out of sync\n"); 1323681a5bbeSBoris Popov return EBADRPC; 1324681a5bbeSBoris Popov } 1325681a5bbeSBoris Popov } 132641f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 132741f1dcccSKevin Lo if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) 132841f1dcccSKevin Lo nmlen -= 2; 132941f1dcccSKevin Lo } else 1330681a5bbeSBoris Popov if (nmlen && cp[nmlen - 1] == 0) 1331681a5bbeSBoris Popov nmlen--; 1332681a5bbeSBoris Popov if (nmlen == 0) 1333681a5bbeSBoris Popov return EBADRPC; 1334681a5bbeSBoris Popov 1335681a5bbeSBoris Popov next = ctx->f_eofs + recsz; 1336681a5bbeSBoris Popov if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1337681a5bbeSBoris Popov (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1338681a5bbeSBoris Popov /* 1339681a5bbeSBoris Popov * Server needs a resume filename. 1340681a5bbeSBoris Popov */ 1341681a5bbeSBoris Popov if (ctx->f_rnamelen <= nmlen) { 1342681a5bbeSBoris Popov if (ctx->f_rname) 1343681a5bbeSBoris Popov free(ctx->f_rname, M_SMBFSDATA); 1344a163d034SWarner Losh ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1345681a5bbeSBoris Popov ctx->f_rnamelen = nmlen; 1346681a5bbeSBoris Popov } 1347681a5bbeSBoris Popov bcopy(ctx->f_name, ctx->f_rname, nmlen); 1348681a5bbeSBoris Popov ctx->f_rname[nmlen] = 0; 1349681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1350681a5bbeSBoris Popov } 1351681a5bbeSBoris Popov ctx->f_nmlen = nmlen; 1352681a5bbeSBoris Popov ctx->f_eofs = next; 1353681a5bbeSBoris Popov ctx->f_ecnt--; 1354681a5bbeSBoris Popov ctx->f_left--; 1355681a5bbeSBoris Popov return 0; 1356681a5bbeSBoris Popov } 1357681a5bbeSBoris Popov 1358681a5bbeSBoris Popov static int 1359681a5bbeSBoris Popov smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1360681a5bbeSBoris Popov { 1361681a5bbeSBoris Popov if (ctx->f_name) 1362681a5bbeSBoris Popov free(ctx->f_name, M_SMBFSDATA); 1363681a5bbeSBoris Popov if (ctx->f_t2) 1364681a5bbeSBoris Popov smb_t2_done(ctx->f_t2); 1365681a5bbeSBoris Popov if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1366681a5bbeSBoris Popov smbfs_smb_findclose2(ctx); 1367681a5bbeSBoris Popov return 0; 1368681a5bbeSBoris Popov } 1369681a5bbeSBoris Popov 1370681a5bbeSBoris Popov int 1371681a5bbeSBoris Popov smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1372681a5bbeSBoris Popov struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1373681a5bbeSBoris Popov { 1374681a5bbeSBoris Popov struct smbfs_fctx *ctx; 1375681a5bbeSBoris Popov int error; 1376681a5bbeSBoris Popov 13778d9495bbSDavide Italiano ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO); 1378681a5bbeSBoris Popov ctx->f_ssp = dnp->n_mount->sm_share; 1379681a5bbeSBoris Popov ctx->f_dnp = dnp; 1380681a5bbeSBoris Popov ctx->f_flags = SMBFS_RDD_FINDFIRST; 1381681a5bbeSBoris Popov ctx->f_scred = scred; 1382681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1383d14c8441SPoul-Henning Kamp (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 1384681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_USESEARCH; 1385681a5bbeSBoris Popov error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1386681a5bbeSBoris Popov } else 1387681a5bbeSBoris Popov error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1388681a5bbeSBoris Popov if (error) 1389681a5bbeSBoris Popov smbfs_findclose(ctx, scred); 1390681a5bbeSBoris Popov else 1391681a5bbeSBoris Popov *ctxpp = ctx; 1392681a5bbeSBoris Popov return error; 1393681a5bbeSBoris Popov } 1394681a5bbeSBoris Popov 1395681a5bbeSBoris Popov int 1396681a5bbeSBoris Popov smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1397681a5bbeSBoris Popov { 1398681a5bbeSBoris Popov int error; 1399681a5bbeSBoris Popov 1400681a5bbeSBoris Popov if (limit == 0) 1401681a5bbeSBoris Popov limit = 1000000; 1402681a5bbeSBoris Popov else if (limit > 1) 1403681a5bbeSBoris Popov limit *= 4; /* imperical */ 1404681a5bbeSBoris Popov ctx->f_scred = scred; 1405681a5bbeSBoris Popov for (;;) { 1406681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1407681a5bbeSBoris Popov error = smbfs_findnextLM1(ctx, limit); 1408681a5bbeSBoris Popov } else 1409681a5bbeSBoris Popov error = smbfs_findnextLM2(ctx, limit); 1410681a5bbeSBoris Popov if (error) 1411681a5bbeSBoris Popov return error; 141241f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 141341f1dcccSKevin Lo if ((ctx->f_nmlen == 2 && 141441f1dcccSKevin Lo *(u_int16_t *)ctx->f_name == htole16(0x002e)) || 141541f1dcccSKevin Lo (ctx->f_nmlen == 4 && 141641f1dcccSKevin Lo *(u_int32_t *)ctx->f_name == htole32(0x002e002e))) 141741f1dcccSKevin Lo continue; 141841f1dcccSKevin Lo } else 1419681a5bbeSBoris Popov if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1420681a5bbeSBoris Popov (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1421681a5bbeSBoris Popov ctx->f_name[1] == '.')) 1422681a5bbeSBoris Popov continue; 1423681a5bbeSBoris Popov break; 1424681a5bbeSBoris Popov } 14254ebd3ea1STakanori Watanabe smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, 1426681a5bbeSBoris Popov ctx->f_dnp->n_mount->sm_caseopt); 1427681a5bbeSBoris Popov ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1428681a5bbeSBoris Popov return 0; 1429681a5bbeSBoris Popov } 1430681a5bbeSBoris Popov 1431681a5bbeSBoris Popov int 1432681a5bbeSBoris Popov smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1433681a5bbeSBoris Popov { 1434681a5bbeSBoris Popov ctx->f_scred = scred; 1435681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1436681a5bbeSBoris Popov smbfs_findcloseLM1(ctx); 1437681a5bbeSBoris Popov } else 1438681a5bbeSBoris Popov smbfs_findcloseLM2(ctx); 1439681a5bbeSBoris Popov if (ctx->f_rname) 1440681a5bbeSBoris Popov free(ctx->f_rname, M_SMBFSDATA); 1441681a5bbeSBoris Popov free(ctx, M_SMBFSDATA); 1442681a5bbeSBoris Popov return 0; 1443681a5bbeSBoris Popov } 1444681a5bbeSBoris Popov 1445681a5bbeSBoris Popov int 1446681a5bbeSBoris Popov smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1447681a5bbeSBoris Popov struct smbfattr *fap, struct smb_cred *scred) 1448681a5bbeSBoris Popov { 1449681a5bbeSBoris Popov struct smbfs_fctx *ctx; 1450681a5bbeSBoris Popov int error; 1451681a5bbeSBoris Popov 1452681a5bbeSBoris Popov if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1453681a5bbeSBoris Popov bzero(fap, sizeof(*fap)); 1454681a5bbeSBoris Popov fap->fa_attr = SMB_FA_DIR; 1455681a5bbeSBoris Popov fap->fa_ino = 2; 1456681a5bbeSBoris Popov return 0; 1457681a5bbeSBoris Popov } 1458ce589ae2SDavide Italiano MPASS(!(nmlen == 2 && name[0] == '.' && name[1] == '.')); 1459ce589ae2SDavide Italiano MPASS(!(nmlen == 1 && name[0] == '.')); 1460ce589ae2SDavide Italiano ASSERT_VOP_ELOCKED(dnp->n_vnode, "smbfs_smb_lookup"); 1461681a5bbeSBoris Popov error = smbfs_findopen(dnp, name, nmlen, 1462681a5bbeSBoris Popov SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1463681a5bbeSBoris Popov if (error) 1464681a5bbeSBoris Popov return error; 1465681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1466681a5bbeSBoris Popov error = smbfs_findnext(ctx, 1, scred); 1467681a5bbeSBoris Popov if (error == 0) { 1468681a5bbeSBoris Popov *fap = ctx->f_attr; 1469681a5bbeSBoris Popov if (name == NULL) 1470681a5bbeSBoris Popov fap->fa_ino = dnp->n_ino; 1471681a5bbeSBoris Popov } 1472681a5bbeSBoris Popov smbfs_findclose(ctx, scred); 1473681a5bbeSBoris Popov return error; 1474681a5bbeSBoris Popov } 1475