smbfs_smb.c revision 163993
1139776Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 3. All advertising materials mentioning features or use of this software 1475374Sbp * must display the following acknowledgement: 1575374Sbp * This product includes software developed by Boris Popov. 1675374Sbp * 4. Neither the name of the author nor the names of any co-contributors 1775374Sbp * may be used to endorse or promote products derived from this software 1875374Sbp * without specific prior written permission. 1975374Sbp * 2075374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2175374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2275374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2375374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2475374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2575374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2675374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2775374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2875374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2975374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3075374Sbp * SUCH DAMAGE. 3175374Sbp * 3275374Sbp * $FreeBSD: head/sys/fs/smbfs/smbfs_smb.c 163993 2006-11-05 06:38:42Z bp $ 3375374Sbp */ 3475374Sbp#include <sys/param.h> 3575374Sbp#include <sys/systm.h> 3675374Sbp#include <sys/kernel.h> 3775374Sbp#include <sys/malloc.h> 3875374Sbp#include <sys/proc.h> 3975374Sbp#include <sys/lock.h> 4075374Sbp#include <sys/vnode.h> 4175374Sbp#include <sys/mbuf.h> 4275374Sbp#include <sys/mount.h> 4375374Sbp 4475374Sbp#ifdef USE_MD5_HASH 4575374Sbp#include <sys/md5.h> 4675374Sbp#endif 4775374Sbp 4875374Sbp#include <netsmb/smb.h> 4975374Sbp#include <netsmb/smb_subr.h> 5075374Sbp#include <netsmb/smb_rq.h> 5175374Sbp#include <netsmb/smb_conn.h> 5275374Sbp 5375374Sbp#include <fs/smbfs/smbfs.h> 5475374Sbp#include <fs/smbfs/smbfs_node.h> 5575374Sbp#include <fs/smbfs/smbfs_subr.h> 5675374Sbp 5775374Sbp/* 5875374Sbp * Lack of inode numbers leads us to the problem of generating them. 5975374Sbp * Partially this problem can be solved by having a dir/file cache 6075374Sbp * with inode numbers generated from the incremented by one counter. 6175374Sbp * However this way will require too much kernel memory, gives all 6275374Sbp * sorts of locking and consistency problems, not to mentinon counter overflows. 6375374Sbp * So, I'm decided to use a hash function to generate pseudo random (and unique) 6475374Sbp * inode numbers. 6575374Sbp */ 6675374Sbpstatic long 6775374Sbpsmbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 6875374Sbp{ 6975374Sbp#ifdef USE_MD5_HASH 7075374Sbp MD5_CTX md5; 7175374Sbp u_int32_t state[4]; 7275374Sbp long ino; 7375374Sbp int i; 7475374Sbp 7575374Sbp MD5Init(&md5); 7675374Sbp MD5Update(&md5, name, nmlen); 7775374Sbp MD5Final((u_char *)state, &md5); 7875374Sbp for (i = 0, ino = 0; i < 4; i++) 7975374Sbp ino += state[i]; 8075374Sbp return dnp->n_ino + ino; 8175374Sbp#endif 8275374Sbp u_int32_t ino; 8375374Sbp 8475374Sbp ino = dnp->n_ino + smbfs_hash(name, nmlen); 8575374Sbp if (ino <= 2) 8675374Sbp ino += 3; 8775374Sbp return ino; 8875374Sbp} 8975374Sbp 9075374Sbpstatic int 9175374Sbpsmbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, 9275374Sbp struct smb_cred *scred) 9375374Sbp{ 9475374Sbp struct smb_share *ssp = np->n_mount->sm_share; 9575374Sbp struct smb_rq rq, *rqp = &rq; 9675374Sbp struct mbchain *mbp; 9775374Sbp u_char ltype = 0; 9875374Sbp int error; 9975374Sbp 10075374Sbp if (op == SMB_LOCK_SHARED) 10175374Sbp ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 10275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred); 10375374Sbp if (error) 10475374Sbp return error; 10575374Sbp smb_rq_getrequest(rqp, &mbp); 10675374Sbp smb_rq_wstart(rqp); 107103533Sbp mb_put_uint8(mbp, 0xff); /* secondary command */ 10875374Sbp mb_put_uint8(mbp, 0); /* MBZ */ 10975374Sbp mb_put_uint16le(mbp, 0); 11075374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 11175374Sbp mb_put_uint8(mbp, ltype); /* locktype */ 11275374Sbp mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 113103533Sbp mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 11475374Sbp mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 11575374Sbp mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 11675374Sbp smb_rq_wend(rqp); 11775374Sbp smb_rq_bstart(rqp); 11875374Sbp mb_put_uint16le(mbp, pid); 11975374Sbp mb_put_uint32le(mbp, start); 12075374Sbp mb_put_uint32le(mbp, end - start); 12175374Sbp smb_rq_bend(rqp); 12275374Sbp error = smb_rq_simple(rqp); 12375374Sbp smb_rq_done(rqp); 12475374Sbp return error; 12575374Sbp} 12675374Sbp 12775374Sbpint 12875374Sbpsmbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 12975374Sbp off_t start, off_t end, struct smb_cred *scred) 13075374Sbp{ 13175374Sbp struct smb_share *ssp = np->n_mount->sm_share; 13275374Sbp 13375374Sbp if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 13475374Sbp /* 13575374Sbp * TODO: use LOCK_BYTE_RANGE here. 13675374Sbp */ 13775374Sbp return EINVAL; 13875374Sbp else 139106595Sjhb return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred); 14075374Sbp} 14175374Sbp 142103533Sbpstatic int 143103533Sbpsmbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, 144103533Sbp struct smb_cred *scred, short infolevel) 145103533Sbp{ 146103533Sbp struct smb_share *ssp = np->n_mount->sm_share; 147103533Sbp struct smb_vc *vcp = SSTOVC(ssp); 148103533Sbp struct smb_t2rq *t2p; 149103533Sbp int error, svtz, timesok = 1; 150103533Sbp struct mbchain *mbp; 151103533Sbp struct mdchain *mdp; 152103533Sbp u_int16_t date, time, wattr; 153103533Sbp int64_t lint; 154103533Sbp u_int32_t size, dattr; 155103533Sbp 156103533Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, 157103533Sbp scred, &t2p); 158103533Sbp if (error) 159103533Sbp return error; 160103533Sbp mbp = &t2p->t2_tparam; 161103533Sbp mb_init(mbp); 162103533Sbp if (!infolevel) { 163103533Sbp if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) 164103533Sbp infolevel = SMB_QUERY_FILE_STANDARD; 165103533Sbp else 166103533Sbp infolevel = SMB_QUERY_FILE_BASIC_INFO; 167103533Sbp } 168103533Sbp mb_put_uint16le(mbp, infolevel); 169103533Sbp mb_put_uint32le(mbp, 0); 170103533Sbp /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ 171103533Sbp error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 172103533Sbp if (error) { 173103533Sbp smb_t2_done(t2p); 174103533Sbp return error; 175103533Sbp } 176103533Sbp t2p->t2_maxpcount = 2; 177103533Sbp t2p->t2_maxdcount = vcp->vc_txmax; 178103533Sbp error = smb_t2_request(t2p); 179103533Sbp if (error) { 180103533Sbp smb_t2_done(t2p); 181103533Sbp if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL) 182103533Sbp return error; 183103533Sbp return smbfs_smb_qpathinfo(np, fap, scred, 184103533Sbp SMB_QUERY_FILE_STANDARD); 185103533Sbp } 186103533Sbp mdp = &t2p->t2_rdata; 187103533Sbp svtz = vcp->vc_sopt.sv_tz; 188103533Sbp switch (infolevel) { 189103533Sbp case SMB_QUERY_FILE_STANDARD: 190103533Sbp timesok = 0; 191103533Sbp md_get_uint16le(mdp, NULL); 192103533Sbp md_get_uint16le(mdp, NULL); /* creation time */ 193103533Sbp md_get_uint16le(mdp, &date); 194103533Sbp md_get_uint16le(mdp, &time); /* access time */ 195103533Sbp if (date || time) { 196103533Sbp timesok++; 197103533Sbp smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); 198103533Sbp } 199103533Sbp md_get_uint16le(mdp, &date); 200103533Sbp md_get_uint16le(mdp, &time); /* modify time */ 201103533Sbp if (date || time) { 202103533Sbp timesok++; 203103533Sbp smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); 204103533Sbp } 205103533Sbp md_get_uint32le(mdp, &size); 206103533Sbp fap->fa_size = size; 207103533Sbp md_get_uint32(mdp, NULL); /* allocation size */ 208103533Sbp md_get_uint16le(mdp, &wattr); 209103533Sbp fap->fa_attr = wattr; 210103533Sbp break; 211103533Sbp case SMB_QUERY_FILE_BASIC_INFO: 212103533Sbp timesok = 0; 213103533Sbp md_get_int64(mdp, NULL); /* creation time */ 214103533Sbp md_get_int64le(mdp, &lint); 215103533Sbp if (lint) { 216103533Sbp timesok++; 217103533Sbp smb_time_NT2local(lint, svtz, &fap->fa_atime); 218103533Sbp } 219103533Sbp md_get_int64le(mdp, &lint); 220103533Sbp if (lint) { 221103533Sbp timesok++; 222103533Sbp smb_time_NT2local(lint, svtz, &fap->fa_mtime); 223103533Sbp } 224103533Sbp md_get_int64le(mdp, &lint); 225103533Sbp if (lint) { 226103533Sbp timesok++; 227103533Sbp smb_time_NT2local(lint, svtz, &fap->fa_ctime); 228103533Sbp } 229103533Sbp md_get_uint32le(mdp, &dattr); 230103533Sbp fap->fa_attr = dattr; 231103533Sbp md_get_uint32(mdp, NULL); 232103533Sbp /* XXX could use ALL_INFO to get size */ 233103533Sbp break; 234103533Sbp default: 235103533Sbp SMBERROR("unexpected info level %d\n", infolevel); 236103533Sbp error = EINVAL; 237103533Sbp } 238103533Sbp smb_t2_done(t2p); 239103533Sbp /* 240103533Sbp * if all times are zero (observed with FAT on NT4SP6) 241103533Sbp * then fall back to older info level 242103533Sbp */ 243103533Sbp if (!timesok) { 244103533Sbp if (infolevel != SMB_QUERY_FILE_STANDARD) 245103533Sbp return smbfs_smb_qpathinfo(np, fap, scred, 246103533Sbp SMB_QUERY_FILE_STANDARD); 247103533Sbp error = EINVAL; 248103533Sbp } 249103533Sbp return error; 250103533Sbp} 251103533Sbp 25275374Sbpint 25375374Sbpsmbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp, 25475374Sbp struct smb_cred *scred) 25575374Sbp{ 25675374Sbp struct smb_t2rq *t2p; 25775374Sbp struct mbchain *mbp; 25875374Sbp struct mdchain *mdp; 25975374Sbp u_int16_t bsize; 26075374Sbp u_int32_t units, bpu, funits; 26175374Sbp int error; 26275374Sbp 26375374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 26475374Sbp scred, &t2p); 26575374Sbp if (error) 26675374Sbp return error; 26775374Sbp mbp = &t2p->t2_tparam; 26875374Sbp mb_init(mbp); 26975374Sbp mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 27075374Sbp t2p->t2_maxpcount = 4; 27175374Sbp t2p->t2_maxdcount = 4 * 4 + 2; 27275374Sbp error = smb_t2_request(t2p); 27375374Sbp if (error) { 27475374Sbp smb_t2_done(t2p); 27575374Sbp return error; 27675374Sbp } 27775374Sbp mdp = &t2p->t2_rdata; 27875374Sbp md_get_uint32(mdp, NULL); /* fs id */ 27975374Sbp md_get_uint32le(mdp, &bpu); 28075374Sbp md_get_uint32le(mdp, &units); 28175374Sbp md_get_uint32le(mdp, &funits); 28275374Sbp md_get_uint16le(mdp, &bsize); 28396755Strhodes sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 28496755Strhodes sbp->f_blocks= units; /* total data blocks in filesystem */ 28575374Sbp sbp->f_bfree = funits; /* free blocks in fs */ 28675374Sbp sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 28796755Strhodes sbp->f_files = 0xffff; /* total file nodes in filesystem */ 28875374Sbp sbp->f_ffree = 0xffff; /* free file nodes in fs */ 28975374Sbp smb_t2_done(t2p); 29075374Sbp return 0; 29175374Sbp} 29275374Sbp 29375374Sbpint 29475374Sbpsmbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, 29575374Sbp struct smb_cred *scred) 29675374Sbp{ 29775374Sbp struct smb_rq rq, *rqp = &rq; 29875374Sbp struct mdchain *mdp; 29975374Sbp u_int16_t units, bpu, bsize, funits; 30075374Sbp int error; 30175374Sbp 30275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); 30375374Sbp if (error) 30475374Sbp return error; 30575374Sbp smb_rq_wstart(rqp); 30675374Sbp smb_rq_wend(rqp); 30775374Sbp smb_rq_bstart(rqp); 30875374Sbp smb_rq_bend(rqp); 30975374Sbp error = smb_rq_simple(rqp); 31075374Sbp if (error) { 31175374Sbp smb_rq_done(rqp); 31275374Sbp return error; 31375374Sbp } 31475374Sbp smb_rq_getreply(rqp, &mdp); 31575374Sbp md_get_uint16le(mdp, &units); 31675374Sbp md_get_uint16le(mdp, &bpu); 31775374Sbp md_get_uint16le(mdp, &bsize); 31875374Sbp md_get_uint16le(mdp, &funits); 31996755Strhodes sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 32096755Strhodes sbp->f_blocks= units; /* total data blocks in filesystem */ 32175374Sbp sbp->f_bfree = funits; /* free blocks in fs */ 32275374Sbp sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 32396755Strhodes sbp->f_files = 0xffff; /* total file nodes in filesystem */ 32475374Sbp sbp->f_ffree = 0xffff; /* free file nodes in fs */ 32575374Sbp smb_rq_done(rqp); 32675374Sbp return 0; 32775374Sbp} 32875374Sbp 329103533Sbpstatic int 330103533Sbpsmbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 331103533Sbp{ 332103533Sbp struct smb_t2rq *t2p; 333103533Sbp struct smb_share *ssp = np->n_mount->sm_share; 334103533Sbp struct mbchain *mbp; 335103533Sbp int error; 336103533Sbp 337103533Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 338103533Sbp scred, &t2p); 339103533Sbp if (error) 340103533Sbp return error; 341103533Sbp mbp = &t2p->t2_tparam; 342103533Sbp mb_init(mbp); 343103533Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 344103533Sbp mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); 345103533Sbp mb_put_uint32le(mbp, 0); 346103533Sbp mbp = &t2p->t2_tdata; 347103533Sbp mb_init(mbp); 348103533Sbp mb_put_int64le(mbp, newsize); 349103533Sbp mb_put_uint32le(mbp, 0); /* padding */ 350103533Sbp mb_put_uint16le(mbp, 0); 351103533Sbp t2p->t2_maxpcount = 2; 352103533Sbp t2p->t2_maxdcount = 0; 353103533Sbp error = smb_t2_request(t2p); 354103533Sbp smb_t2_done(t2p); 355103533Sbp return error; 356103533Sbp} 357103533Sbp 358103533Sbpstatic int 359103533Sbpsmb_smb_flush(struct smbnode *np, struct smb_cred *scred) 360103533Sbp{ 361103533Sbp struct smb_share *ssp = np->n_mount->sm_share; 362103533Sbp struct smb_rq rq, *rqp = &rq; 363103533Sbp struct mbchain *mbp; 364103533Sbp int error; 365103533Sbp 366124434Stjr if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) || 367116486Stjr SMBTOV(np)->v_type != VREG) 368108470Sschweikh return 0; /* not a regular open file */ 369103533Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred); 370103533Sbp if (error) 371103533Sbp return (error); 372103533Sbp smb_rq_getrequest(rqp, &mbp); 373103533Sbp smb_rq_wstart(rqp); 374103533Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 375103533Sbp smb_rq_wend(rqp); 376103533Sbp smb_rq_bstart(rqp); 377103533Sbp smb_rq_bend(rqp); 378103533Sbp error = smb_rq_simple(rqp); 379103533Sbp smb_rq_done(rqp); 380103533Sbp if (!error) 381103533Sbp np->n_flag &= ~NFLUSHWIRE; 382103533Sbp return (error); 383103533Sbp} 384103533Sbp 38575374Sbpint 386103533Sbpsmbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) 387103533Sbp{ 388103533Sbp if (np->n_flag & NFLUSHWIRE) 389103533Sbp return (smb_smb_flush(np, scred)); 390103533Sbp return (0); 391103533Sbp} 392103533Sbp 393103533Sbpint 39475374Sbpsmbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 39575374Sbp{ 39675374Sbp struct smb_share *ssp = np->n_mount->sm_share; 39775374Sbp struct smb_rq rq, *rqp = &rq; 39875374Sbp struct mbchain *mbp; 39975374Sbp int error; 40075374Sbp 401103533Sbp if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { 402103533Sbp np->n_flag |= NFLUSHWIRE; 403103533Sbp return (0); 404103533Sbp } 405103533Sbp 40675374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); 40775374Sbp if (error) 40875374Sbp return error; 40975374Sbp smb_rq_getrequest(rqp, &mbp); 41075374Sbp smb_rq_wstart(rqp); 41175374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 41275374Sbp mb_put_uint16le(mbp, 0); 41375374Sbp mb_put_uint32le(mbp, newsize); 41475374Sbp mb_put_uint16le(mbp, 0); 41575374Sbp smb_rq_wend(rqp); 41675374Sbp smb_rq_bstart(rqp); 41775374Sbp mb_put_uint8(mbp, SMB_DT_DATA); 41875374Sbp mb_put_uint16le(mbp, 0); 41975374Sbp smb_rq_bend(rqp); 42075374Sbp error = smb_rq_simple(rqp); 42175374Sbp smb_rq_done(rqp); 42275374Sbp return error; 42375374Sbp} 42475374Sbp 425103533Sbpint 426103533Sbpsmbfs_smb_query_info(struct smbnode *np, const char *name, int len, 427103533Sbp struct smbfattr *fap, struct smb_cred *scred) 428103533Sbp{ 429103533Sbp struct smb_rq rq, *rqp = &rq; 430103533Sbp struct smb_share *ssp = np->n_mount->sm_share; 431103533Sbp struct mbchain *mbp; 432103533Sbp struct mdchain *mdp; 433103533Sbp u_int8_t wc; 434103533Sbp int error; 435103533Sbp u_int16_t wattr; 436103533Sbp u_int32_t lint; 43775374Sbp 438103533Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); 439103533Sbp if (error) 440103533Sbp return error; 441103533Sbp smb_rq_getrequest(rqp, &mbp); 442103533Sbp smb_rq_wstart(rqp); 443103533Sbp smb_rq_wend(rqp); 444103533Sbp smb_rq_bstart(rqp); 445103533Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 446103533Sbp do { 447103533Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); 448103533Sbp if (error) 449103533Sbp break; 450103533Sbp smb_rq_bend(rqp); 451103533Sbp error = smb_rq_simple(rqp); 452103533Sbp if (error) 453103533Sbp break; 454103533Sbp smb_rq_getreply(rqp, &mdp); 455103533Sbp if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 456103533Sbp error = EBADRPC; 457103533Sbp break; 458103533Sbp } 459103533Sbp md_get_uint16le(mdp, &wattr); 460103533Sbp fap->fa_attr = wattr; 461103533Sbp /* 462103533Sbp * Be careful using the time returned here, as 463103533Sbp * with FAT on NT4SP6, at least, the time returned is low 464103533Sbp * 32 bits of 100s of nanoseconds (since 1601) so it rolls 465103533Sbp * over about every seven minutes! 466103533Sbp */ 467103533Sbp md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ 468103533Sbp if (lint) /* avoid bogus zero returns */ 469103533Sbp smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, 470103533Sbp &fap->fa_mtime); 471103533Sbp md_get_uint32le(mdp, &lint); 472103533Sbp fap->fa_size = lint; 473103533Sbp } while(0); 474103533Sbp smb_rq_done(rqp); 475103533Sbp return error; 476103533Sbp} 477103533Sbp 47875374Sbp/* 47975374Sbp * Set DOS file attributes. mtime should be NULL for dialects above lm10 48075374Sbp */ 48175374Sbpint 48275374Sbpsmbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 48375374Sbp struct smb_cred *scred) 48475374Sbp{ 48575374Sbp struct smb_rq rq, *rqp = &rq; 48675374Sbp struct smb_share *ssp = np->n_mount->sm_share; 48775374Sbp struct mbchain *mbp; 48875374Sbp u_long time; 48975374Sbp int error, svtz; 49075374Sbp 49175374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); 49275374Sbp if (error) 49375374Sbp return error; 49475374Sbp svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 49575374Sbp smb_rq_getrequest(rqp, &mbp); 49675374Sbp smb_rq_wstart(rqp); 49775374Sbp mb_put_uint16le(mbp, attr); 49875374Sbp if (mtime) { 49975374Sbp smb_time_local2server(mtime, svtz, &time); 50075374Sbp } else 50175374Sbp time = 0; 50275374Sbp mb_put_uint32le(mbp, time); /* mtime */ 50375374Sbp mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 50475374Sbp smb_rq_wend(rqp); 50575374Sbp smb_rq_bstart(rqp); 50675374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 50775374Sbp do { 50875374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 50975374Sbp if (error) 51075374Sbp break; 51175374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 51275374Sbp mb_put_uint8(mbp, 0); 51375374Sbp smb_rq_bend(rqp); 51475374Sbp error = smb_rq_simple(rqp); 515163993Sbp if (error) { 516163993Sbp SMBERROR("smb_rq_simple(rqp) => error %d\n", error); 51775374Sbp break; 518163993Sbp } 51975374Sbp } while(0); 52075374Sbp smb_rq_done(rqp); 52175374Sbp return error; 52275374Sbp} 52375374Sbp 52475374Sbp/* 52575374Sbp * Note, win95 doesn't support this call. 52675374Sbp */ 52775374Sbpint 52875374Sbpsmbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 52975374Sbp struct timespec *atime, int attr, struct smb_cred *scred) 53075374Sbp{ 53175374Sbp struct smb_t2rq *t2p; 53275374Sbp struct smb_share *ssp = np->n_mount->sm_share; 53375374Sbp struct smb_vc *vcp = SSTOVC(ssp); 53475374Sbp struct mbchain *mbp; 53575374Sbp u_int16_t date, time; 53675374Sbp int error, tzoff; 53775374Sbp 53875374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 53975374Sbp scred, &t2p); 54075374Sbp if (error) 54175374Sbp return error; 54275374Sbp mbp = &t2p->t2_tparam; 54375374Sbp mb_init(mbp); 54475374Sbp mb_put_uint16le(mbp, SMB_INFO_STANDARD); 54575374Sbp mb_put_uint32le(mbp, 0); /* MBZ */ 546103533Sbp /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 54775374Sbp error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 54875374Sbp if (error) { 54975374Sbp smb_t2_done(t2p); 55075374Sbp return error; 55175374Sbp } 55275374Sbp tzoff = vcp->vc_sopt.sv_tz; 55375374Sbp mbp = &t2p->t2_tdata; 55475374Sbp mb_init(mbp); 55575374Sbp mb_put_uint32le(mbp, 0); /* creation time */ 55675374Sbp if (atime) 55775374Sbp smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 55875374Sbp else 55975374Sbp time = date = 0; 56075374Sbp mb_put_uint16le(mbp, date); 56175374Sbp mb_put_uint16le(mbp, time); 56275374Sbp if (mtime) 56375374Sbp smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 56475374Sbp else 56575374Sbp time = date = 0; 56675374Sbp mb_put_uint16le(mbp, date); 56775374Sbp mb_put_uint16le(mbp, time); 56875374Sbp mb_put_uint32le(mbp, 0); /* file size */ 56975374Sbp mb_put_uint32le(mbp, 0); /* allocation unit size */ 57075374Sbp mb_put_uint16le(mbp, attr); /* DOS attr */ 57175374Sbp mb_put_uint32le(mbp, 0); /* EA size */ 57275374Sbp t2p->t2_maxpcount = 5 * 2; 57375374Sbp t2p->t2_maxdcount = vcp->vc_txmax; 57475374Sbp error = smb_t2_request(t2p); 57575374Sbp smb_t2_done(t2p); 57675374Sbp return error; 57775374Sbp} 57875374Sbp 57975374Sbp/* 58075374Sbp * NT level. Specially for win9x 58175374Sbp */ 58275374Sbpint 58375374Sbpsmbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 58475374Sbp struct timespec *atime, struct smb_cred *scred) 58575374Sbp{ 58675374Sbp struct smb_t2rq *t2p; 58775374Sbp struct smb_share *ssp = np->n_mount->sm_share; 58875374Sbp struct smb_vc *vcp = SSTOVC(ssp); 58975374Sbp struct mbchain *mbp; 59075374Sbp int64_t tm; 59175374Sbp int error, tzoff; 59275374Sbp 59375374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 59475374Sbp scred, &t2p); 59575374Sbp if (error) 59675374Sbp return error; 59775374Sbp mbp = &t2p->t2_tparam; 59875374Sbp mb_init(mbp); 59975374Sbp mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 60075374Sbp mb_put_uint32le(mbp, 0); /* MBZ */ 601103533Sbp /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 60275374Sbp error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 60375374Sbp if (error) { 60475374Sbp smb_t2_done(t2p); 60575374Sbp return error; 60675374Sbp } 60775374Sbp tzoff = vcp->vc_sopt.sv_tz; 60875374Sbp mbp = &t2p->t2_tdata; 60975374Sbp mb_init(mbp); 61075374Sbp mb_put_int64le(mbp, 0); /* creation time */ 61175374Sbp if (atime) { 61275374Sbp smb_time_local2NT(atime, tzoff, &tm); 61375374Sbp } else 61475374Sbp tm = 0; 61575374Sbp mb_put_int64le(mbp, tm); 61675374Sbp if (mtime) { 61775374Sbp smb_time_local2NT(mtime, tzoff, &tm); 61875374Sbp } else 61975374Sbp tm = 0; 62075374Sbp mb_put_int64le(mbp, tm); 62175374Sbp mb_put_int64le(mbp, tm); /* change time */ 62275374Sbp mb_put_uint32le(mbp, attr); /* attr */ 62375374Sbp t2p->t2_maxpcount = 24; 62475374Sbp t2p->t2_maxdcount = 56; 62575374Sbp error = smb_t2_request(t2p); 62675374Sbp smb_t2_done(t2p); 62775374Sbp return error; 62875374Sbp} 62975374Sbp 63075374Sbp/* 63175374Sbp * Set file atime and mtime. Doesn't supported by core dialect. 63275374Sbp */ 63375374Sbpint 63475374Sbpsmbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 63575374Sbp struct timespec *atime, struct smb_cred *scred) 63675374Sbp{ 63775374Sbp struct smb_rq rq, *rqp = &rq; 63875374Sbp struct smb_share *ssp = np->n_mount->sm_share; 63975374Sbp struct mbchain *mbp; 64075374Sbp u_int16_t date, time; 64175374Sbp int error, tzoff; 64275374Sbp 64375374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 64475374Sbp if (error) 64575374Sbp return error; 64675374Sbp tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 64775374Sbp smb_rq_getrequest(rqp, &mbp); 64875374Sbp smb_rq_wstart(rqp); 64975374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 65075374Sbp mb_put_uint32le(mbp, 0); /* creation time */ 65175374Sbp 65275374Sbp if (atime) 65375374Sbp smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 65475374Sbp else 65575374Sbp time = date = 0; 65675374Sbp mb_put_uint16le(mbp, date); 65775374Sbp mb_put_uint16le(mbp, time); 65875374Sbp if (mtime) 65975374Sbp smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 66075374Sbp else 66175374Sbp time = date = 0; 66275374Sbp mb_put_uint16le(mbp, date); 66375374Sbp mb_put_uint16le(mbp, time); 66475374Sbp smb_rq_wend(rqp); 66575374Sbp smb_rq_bstart(rqp); 66675374Sbp smb_rq_bend(rqp); 66775374Sbp error = smb_rq_simple(rqp); 66875374Sbp SMBSDEBUG("%d\n", error); 66975374Sbp smb_rq_done(rqp); 67075374Sbp return error; 67175374Sbp} 67275374Sbp 67375374Sbp/* 67475374Sbp * Set DOS file attributes. 67575374Sbp * Looks like this call can be used only if CAP_NT_SMBS bit is on. 67675374Sbp */ 67775374Sbpint 67875374Sbpsmbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 67975374Sbp struct timespec *atime, struct smb_cred *scred) 68075374Sbp{ 68175374Sbp struct smb_t2rq *t2p; 68275374Sbp struct smb_share *ssp = np->n_mount->sm_share; 68375374Sbp struct mbchain *mbp; 68475374Sbp int64_t tm; 68575374Sbp int error, svtz; 68675374Sbp 68775374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 68875374Sbp scred, &t2p); 68975374Sbp if (error) 69075374Sbp return error; 69175374Sbp svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 69275374Sbp mbp = &t2p->t2_tparam; 69375374Sbp mb_init(mbp); 69475374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 69575374Sbp mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 69675374Sbp mb_put_uint32le(mbp, 0); 69775374Sbp mbp = &t2p->t2_tdata; 69875374Sbp mb_init(mbp); 69975374Sbp mb_put_int64le(mbp, 0); /* creation time */ 70075374Sbp if (atime) { 70175374Sbp smb_time_local2NT(atime, svtz, &tm); 70275374Sbp } else 70375374Sbp tm = 0; 70475374Sbp mb_put_int64le(mbp, tm); 70575374Sbp if (mtime) { 70675374Sbp smb_time_local2NT(mtime, svtz, &tm); 70775374Sbp } else 70875374Sbp tm = 0; 70975374Sbp mb_put_int64le(mbp, tm); 71075374Sbp mb_put_int64le(mbp, tm); /* change time */ 71175374Sbp mb_put_uint16le(mbp, attr); 71275374Sbp mb_put_uint32le(mbp, 0); /* padding */ 71375374Sbp mb_put_uint16le(mbp, 0); 71475374Sbp t2p->t2_maxpcount = 2; 71575374Sbp t2p->t2_maxdcount = 0; 71675374Sbp error = smb_t2_request(t2p); 71775374Sbp smb_t2_done(t2p); 71875374Sbp return error; 71975374Sbp} 72075374Sbp 72175374Sbp 72275374Sbpint 72375374Sbpsmbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 72475374Sbp{ 72575374Sbp struct smb_rq rq, *rqp = &rq; 72675374Sbp struct smb_share *ssp = np->n_mount->sm_share; 72775374Sbp struct mbchain *mbp; 72875374Sbp struct mdchain *mdp; 72975374Sbp u_int8_t wc; 73075374Sbp u_int16_t fid, wattr, grantedmode; 73175374Sbp int error; 73275374Sbp 73375374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 73475374Sbp if (error) 73575374Sbp return error; 73675374Sbp smb_rq_getrequest(rqp, &mbp); 73775374Sbp smb_rq_wstart(rqp); 73875374Sbp mb_put_uint16le(mbp, accmode); 73975374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 74075374Sbp smb_rq_wend(rqp); 74175374Sbp smb_rq_bstart(rqp); 74275374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 74375374Sbp do { 74475374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 74575374Sbp if (error) 74675374Sbp break; 74775374Sbp smb_rq_bend(rqp); 74875374Sbp error = smb_rq_simple(rqp); 74975374Sbp if (error) 75075374Sbp break; 75175374Sbp smb_rq_getreply(rqp, &mdp); 75275374Sbp if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 75375374Sbp error = EBADRPC; 75475374Sbp break; 75575374Sbp } 75675374Sbp md_get_uint16(mdp, &fid); 75775374Sbp md_get_uint16le(mdp, &wattr); 75875374Sbp md_get_uint32(mdp, NULL); /* mtime */ 75975374Sbp md_get_uint32(mdp, NULL); /* fsize */ 76075374Sbp md_get_uint16le(mdp, &grantedmode); 76175374Sbp /* 76275374Sbp * TODO: refresh attributes from this reply 76375374Sbp */ 76475374Sbp } while(0); 76575374Sbp smb_rq_done(rqp); 76675374Sbp if (error) 76775374Sbp return error; 76875374Sbp np->n_fid = fid; 76975374Sbp np->n_rwstate = grantedmode; 77075374Sbp return 0; 77175374Sbp} 77275374Sbp 77375374Sbp 77475374Sbpint 77575374Sbpsmbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 77675374Sbp struct smb_cred *scred) 77775374Sbp{ 77875374Sbp struct smb_rq rq, *rqp = &rq; 77975374Sbp struct mbchain *mbp; 78075374Sbp u_long time; 78175374Sbp int error; 78275374Sbp 78375374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 78475374Sbp if (error) 78575374Sbp return error; 78675374Sbp smb_rq_getrequest(rqp, &mbp); 78775374Sbp smb_rq_wstart(rqp); 78875374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 78975374Sbp if (mtime) { 79075374Sbp smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 79175374Sbp } else 79275374Sbp time = 0; 79375374Sbp mb_put_uint32le(mbp, time); 79475374Sbp smb_rq_wend(rqp); 79575374Sbp smb_rq_bstart(rqp); 79675374Sbp smb_rq_bend(rqp); 79775374Sbp error = smb_rq_simple(rqp); 79875374Sbp smb_rq_done(rqp); 79975374Sbp return error; 80075374Sbp} 80175374Sbp 80275374Sbpint 80375374Sbpsmbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 80475374Sbp struct smb_cred *scred) 80575374Sbp{ 80675374Sbp struct smb_rq rq, *rqp = &rq; 80775374Sbp struct smb_share *ssp = dnp->n_mount->sm_share; 80875374Sbp struct mbchain *mbp; 80975374Sbp struct mdchain *mdp; 81075374Sbp struct timespec ctime; 81175374Sbp u_int8_t wc; 81275374Sbp u_int16_t fid; 81375374Sbp u_long tm; 81475374Sbp int error; 81575374Sbp 81675374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 81775374Sbp if (error) 81875374Sbp return error; 81975374Sbp smb_rq_getrequest(rqp, &mbp); 82075374Sbp smb_rq_wstart(rqp); 82175374Sbp mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 82275374Sbp nanotime(&ctime); 82375374Sbp smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 82475374Sbp mb_put_uint32le(mbp, tm); 82575374Sbp smb_rq_wend(rqp); 82675374Sbp smb_rq_bstart(rqp); 82775374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 82875374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 82975374Sbp if (!error) { 83075374Sbp smb_rq_bend(rqp); 83175374Sbp error = smb_rq_simple(rqp); 83275374Sbp if (!error) { 83375374Sbp smb_rq_getreply(rqp, &mdp); 83475374Sbp md_get_uint8(mdp, &wc); 83575374Sbp if (wc == 1) 83675374Sbp md_get_uint16(mdp, &fid); 83775374Sbp else 83875374Sbp error = EBADRPC; 83975374Sbp } 84075374Sbp } 84175374Sbp smb_rq_done(rqp); 84275374Sbp if (error) 84375374Sbp return error; 84475374Sbp smbfs_smb_close(ssp, fid, &ctime, scred); 84575374Sbp return error; 84675374Sbp} 84775374Sbp 84875374Sbpint 84975374Sbpsmbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 85075374Sbp{ 85175374Sbp struct smb_rq rq, *rqp = &rq; 85275374Sbp struct smb_share *ssp = np->n_mount->sm_share; 85375374Sbp struct mbchain *mbp; 85475374Sbp int error; 85575374Sbp 85675374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 85775374Sbp if (error) 85875374Sbp return error; 85975374Sbp smb_rq_getrequest(rqp, &mbp); 86075374Sbp smb_rq_wstart(rqp); 86175374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 86275374Sbp smb_rq_wend(rqp); 86375374Sbp smb_rq_bstart(rqp); 86475374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 86575374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 86675374Sbp if (!error) { 86775374Sbp smb_rq_bend(rqp); 86875374Sbp error = smb_rq_simple(rqp); 86975374Sbp } 87075374Sbp smb_rq_done(rqp); 87175374Sbp return error; 87275374Sbp} 87375374Sbp 87475374Sbpint 87575374Sbpsmbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 87675374Sbp const char *tname, int tnmlen, struct smb_cred *scred) 87775374Sbp{ 87875374Sbp struct smb_rq rq, *rqp = &rq; 87975374Sbp struct smb_share *ssp = src->n_mount->sm_share; 88075374Sbp struct mbchain *mbp; 88175374Sbp int error; 88275374Sbp 88375374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 88475374Sbp if (error) 88575374Sbp return error; 88675374Sbp smb_rq_getrequest(rqp, &mbp); 88775374Sbp smb_rq_wstart(rqp); 88875374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 88975374Sbp smb_rq_wend(rqp); 89075374Sbp smb_rq_bstart(rqp); 89175374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 89275374Sbp do { 89375374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 89475374Sbp if (error) 89575374Sbp break; 89675374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 89775374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 89875374Sbp if (error) 89975374Sbp break; 90075374Sbp smb_rq_bend(rqp); 90175374Sbp error = smb_rq_simple(rqp); 90275374Sbp } while(0); 90375374Sbp smb_rq_done(rqp); 90475374Sbp return error; 90575374Sbp} 90675374Sbp 90775374Sbpint 90875374Sbpsmbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 90975374Sbp const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 91075374Sbp{ 91175374Sbp struct smb_rq rq, *rqp = &rq; 91275374Sbp struct smb_share *ssp = src->n_mount->sm_share; 91375374Sbp struct mbchain *mbp; 91475374Sbp int error; 91575374Sbp 91675374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 91775374Sbp if (error) 91875374Sbp return error; 91975374Sbp smb_rq_getrequest(rqp, &mbp); 92075374Sbp smb_rq_wstart(rqp); 92175374Sbp mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 92275374Sbp mb_put_uint16le(mbp, 0x20); /* delete target file */ 92375374Sbp mb_put_uint16le(mbp, flags); 92475374Sbp smb_rq_wend(rqp); 92575374Sbp smb_rq_bstart(rqp); 92675374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 92775374Sbp do { 92875374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 92975374Sbp if (error) 93075374Sbp break; 93175374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 93275374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 93375374Sbp if (error) 93475374Sbp break; 93575374Sbp smb_rq_bend(rqp); 93675374Sbp error = smb_rq_simple(rqp); 93775374Sbp } while(0); 93875374Sbp smb_rq_done(rqp); 93975374Sbp return error; 94075374Sbp} 94175374Sbp 94275374Sbpint 94375374Sbpsmbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 94475374Sbp struct smb_cred *scred) 94575374Sbp{ 94675374Sbp struct smb_rq rq, *rqp = &rq; 94775374Sbp struct smb_share *ssp = dnp->n_mount->sm_share; 94875374Sbp struct mbchain *mbp; 94975374Sbp int error; 95075374Sbp 95175374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 95275374Sbp if (error) 95375374Sbp return error; 95475374Sbp smb_rq_getrequest(rqp, &mbp); 95575374Sbp smb_rq_wstart(rqp); 95675374Sbp smb_rq_wend(rqp); 95775374Sbp smb_rq_bstart(rqp); 95875374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 95975374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 96075374Sbp if (!error) { 96175374Sbp smb_rq_bend(rqp); 96275374Sbp error = smb_rq_simple(rqp); 96375374Sbp } 96475374Sbp smb_rq_done(rqp); 96575374Sbp return error; 96675374Sbp} 96775374Sbp 96875374Sbpint 96975374Sbpsmbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 97075374Sbp{ 97175374Sbp struct smb_rq rq, *rqp = &rq; 97275374Sbp struct smb_share *ssp = np->n_mount->sm_share; 97375374Sbp struct mbchain *mbp; 97475374Sbp int error; 97575374Sbp 97675374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 97775374Sbp if (error) 97875374Sbp return error; 97975374Sbp smb_rq_getrequest(rqp, &mbp); 98075374Sbp smb_rq_wstart(rqp); 98175374Sbp smb_rq_wend(rqp); 98275374Sbp smb_rq_bstart(rqp); 98375374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 98475374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 98575374Sbp if (!error) { 98675374Sbp smb_rq_bend(rqp); 98775374Sbp error = smb_rq_simple(rqp); 98875374Sbp } 98975374Sbp smb_rq_done(rqp); 99075374Sbp return error; 99175374Sbp} 99275374Sbp 99375374Sbpstatic int 99475374Sbpsmbfs_smb_search(struct smbfs_fctx *ctx) 99575374Sbp{ 99675374Sbp struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 99775374Sbp struct smb_rq *rqp; 99875374Sbp struct mbchain *mbp; 99975374Sbp struct mdchain *mdp; 100075374Sbp u_int8_t wc, bt; 100175374Sbp u_int16_t ec, dlen, bc; 100275374Sbp int maxent, error, iseof = 0; 100375374Sbp 100475374Sbp maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 100575374Sbp if (ctx->f_rq) { 100675374Sbp smb_rq_done(ctx->f_rq); 100775374Sbp ctx->f_rq = NULL; 100875374Sbp } 100975374Sbp error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 101075374Sbp if (error) 101175374Sbp return error; 101275374Sbp ctx->f_rq = rqp; 101375374Sbp smb_rq_getrequest(rqp, &mbp); 101475374Sbp smb_rq_wstart(rqp); 101575374Sbp mb_put_uint16le(mbp, maxent); /* max entries to return */ 101675374Sbp mb_put_uint16le(mbp, ctx->f_attrmask); 101775374Sbp smb_rq_wend(rqp); 101875374Sbp smb_rq_bstart(rqp); 101975374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 102075374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 102175374Sbp error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 102275374Sbp if (error) 102375374Sbp return error; 102475374Sbp mb_put_uint8(mbp, SMB_DT_VARIABLE); 102575374Sbp mb_put_uint16le(mbp, 0); /* context length */ 102675374Sbp ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 102775374Sbp } else { 102875374Sbp mb_put_uint8(mbp, 0); /* file name length */ 102975374Sbp mb_put_uint8(mbp, SMB_DT_VARIABLE); 103075374Sbp mb_put_uint16le(mbp, SMB_SKEYLEN); 103175374Sbp mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 103275374Sbp } 103375374Sbp smb_rq_bend(rqp); 103475374Sbp error = smb_rq_simple(rqp); 103575374Sbp if (error) { 103675374Sbp if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 103775374Sbp error = 0; 103875374Sbp iseof = 1; 103975374Sbp ctx->f_flags |= SMBFS_RDD_EOF; 104075374Sbp } else 104175374Sbp return error; 104275374Sbp } 104375374Sbp smb_rq_getreply(rqp, &mdp); 104475374Sbp md_get_uint8(mdp, &wc); 104575374Sbp if (wc != 1) 104675374Sbp return iseof ? ENOENT : EBADRPC; 104775374Sbp md_get_uint16le(mdp, &ec); 104875374Sbp if (ec == 0) 104975374Sbp return ENOENT; 105075374Sbp ctx->f_ecnt = ec; 105175374Sbp md_get_uint16le(mdp, &bc); 105275374Sbp if (bc < 3) 105375374Sbp return EBADRPC; 105475374Sbp bc -= 3; 105575374Sbp md_get_uint8(mdp, &bt); 105675374Sbp if (bt != SMB_DT_VARIABLE) 105775374Sbp return EBADRPC; 105875374Sbp md_get_uint16le(mdp, &dlen); 105975374Sbp if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 106075374Sbp return EBADRPC; 106175374Sbp return 0; 106275374Sbp} 106375374Sbp 106475374Sbpstatic int 106575374Sbpsmbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 106675374Sbp const char *wildcard, int wclen, int attr, struct smb_cred *scred) 106775374Sbp{ 106875374Sbp ctx->f_attrmask = attr; 106975374Sbp if (wildcard) { 107075374Sbp if (wclen == 1 && wildcard[0] == '*') { 107175374Sbp ctx->f_wildcard = "*.*"; 107275374Sbp ctx->f_wclen = 3; 107375374Sbp } else { 107475374Sbp ctx->f_wildcard = wildcard; 107575374Sbp ctx->f_wclen = wclen; 107675374Sbp } 107775374Sbp } else { 107875374Sbp ctx->f_wildcard = NULL; 107975374Sbp ctx->f_wclen = 0; 108075374Sbp } 108175374Sbp ctx->f_name = ctx->f_fname; 108275374Sbp return 0; 108375374Sbp} 108475374Sbp 108575374Sbpstatic int 108675374Sbpsmbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 108775374Sbp{ 108875374Sbp struct mdchain *mbp; 108975374Sbp struct smb_rq *rqp; 109075374Sbp char *cp; 109175374Sbp u_int8_t battr; 109275374Sbp u_int16_t date, time; 109375374Sbp u_int32_t size; 109475374Sbp int error; 109575374Sbp 109675374Sbp if (ctx->f_ecnt == 0) { 109775374Sbp if (ctx->f_flags & SMBFS_RDD_EOF) 109875374Sbp return ENOENT; 109975374Sbp ctx->f_left = ctx->f_limit = limit; 110075374Sbp error = smbfs_smb_search(ctx); 110175374Sbp if (error) 110275374Sbp return error; 110375374Sbp } 110475374Sbp rqp = ctx->f_rq; 110575374Sbp smb_rq_getreply(rqp, &mbp); 110675374Sbp md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 110775374Sbp md_get_uint8(mbp, &battr); 110875374Sbp md_get_uint16le(mbp, &time); 110975374Sbp md_get_uint16le(mbp, &date); 111075374Sbp md_get_uint32le(mbp, &size); 111175374Sbp cp = ctx->f_name; 111275374Sbp md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 111375374Sbp cp[sizeof(ctx->f_fname) - 1] = 0; 111475374Sbp cp += strlen(cp) - 1; 111575374Sbp while (*cp == ' ' && cp >= ctx->f_name) 111675374Sbp *cp-- = 0; 111775374Sbp ctx->f_attr.fa_attr = battr; 111875374Sbp smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 111975374Sbp &ctx->f_attr.fa_mtime); 112075374Sbp ctx->f_attr.fa_size = size; 112175374Sbp ctx->f_nmlen = strlen(ctx->f_name); 112275374Sbp ctx->f_ecnt--; 112375374Sbp ctx->f_left--; 112475374Sbp return 0; 112575374Sbp} 112675374Sbp 112775374Sbpstatic int 112875374Sbpsmbfs_findcloseLM1(struct smbfs_fctx *ctx) 112975374Sbp{ 113075374Sbp if (ctx->f_rq) 113175374Sbp smb_rq_done(ctx->f_rq); 113275374Sbp return 0; 113375374Sbp} 113475374Sbp 113575374Sbp/* 113675374Sbp * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 113775374Sbp */ 113875374Sbpstatic int 113975374Sbpsmbfs_smb_trans2find2(struct smbfs_fctx *ctx) 114075374Sbp{ 114175374Sbp struct smb_t2rq *t2p; 114275374Sbp struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 114375374Sbp struct mbchain *mbp; 114475374Sbp struct mdchain *mdp; 114575374Sbp u_int16_t tw, flags; 114675374Sbp int error; 114775374Sbp 114875374Sbp if (ctx->f_t2) { 114975374Sbp smb_t2_done(ctx->f_t2); 115075374Sbp ctx->f_t2 = NULL; 115175374Sbp } 115275374Sbp ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 115375374Sbp flags = 8 | 2; /* <resume> | <close if EOS> */ 115475374Sbp if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 115575374Sbp flags |= 1; /* close search after this request */ 115675374Sbp ctx->f_flags |= SMBFS_RDD_NOCLOSE; 115775374Sbp } 115875374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 115975374Sbp error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 116075374Sbp ctx->f_scred, &t2p); 116175374Sbp if (error) 116275374Sbp return error; 116375374Sbp ctx->f_t2 = t2p; 116475374Sbp mbp = &t2p->t2_tparam; 116575374Sbp mb_init(mbp); 116675374Sbp mb_put_uint16le(mbp, ctx->f_attrmask); 116775374Sbp mb_put_uint16le(mbp, ctx->f_limit); 116875374Sbp mb_put_uint16le(mbp, flags); 116975374Sbp mb_put_uint16le(mbp, ctx->f_infolevel); 117075374Sbp mb_put_uint32le(mbp, 0); 117175374Sbp error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 117275374Sbp if (error) 117375374Sbp return error; 117475374Sbp } else { 117575374Sbp error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 117675374Sbp ctx->f_scred, &t2p); 117775374Sbp if (error) 117875374Sbp return error; 117975374Sbp ctx->f_t2 = t2p; 118075374Sbp mbp = &t2p->t2_tparam; 118175374Sbp mb_init(mbp); 118275374Sbp mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 118375374Sbp mb_put_uint16le(mbp, ctx->f_limit); 118475374Sbp mb_put_uint16le(mbp, ctx->f_infolevel); 118575374Sbp mb_put_uint32le(mbp, 0); /* resume key */ 118675374Sbp mb_put_uint16le(mbp, flags); 118775374Sbp if (ctx->f_rname) 118875374Sbp mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 118975374Sbp else 119075374Sbp mb_put_uint8(mbp, 0); /* resume file name */ 119175374Sbp#if 0 119275374Sbp struct timeval tv; 119375374Sbp tv.tv_sec = 0; 119475374Sbp tv.tv_usec = 200 * 1000; /* 200ms */ 119575374Sbp if (vcp->vc_flags & SMBC_WIN95) { 119675374Sbp /* 119775374Sbp * some implementations suggests to sleep here 119875374Sbp * for 200ms, due to the bug in the Win95. 119975374Sbp * I've didn't notice any problem, but put code 120075374Sbp * for it. 120175374Sbp */ 120275374Sbp tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); 120375374Sbp } 120475374Sbp#endif 120575374Sbp } 120675374Sbp t2p->t2_maxpcount = 5 * 2; 120775374Sbp t2p->t2_maxdcount = vcp->vc_txmax; 120875374Sbp error = smb_t2_request(t2p); 120975374Sbp if (error) 121075374Sbp return error; 121175374Sbp mdp = &t2p->t2_rparam; 121275374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 121375374Sbp if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 121475374Sbp return error; 121575374Sbp ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 121675374Sbp } 121775374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 121875374Sbp return error; 121975374Sbp ctx->f_ecnt = tw; 122075374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122175374Sbp return error; 122275374Sbp if (tw) 122375374Sbp ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 122475374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122575374Sbp return error; 122675374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122775374Sbp return error; 1228152678Sbp if (ctx->f_ecnt == 0) { 1229152678Sbp ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 123075374Sbp return ENOENT; 1231152678Sbp } 123275374Sbp ctx->f_rnameofs = tw; 123375374Sbp mdp = &t2p->t2_rdata; 123475374Sbp if (mdp->md_top == NULL) { 123575374Sbp printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 123675374Sbp return ENOENT; 123775374Sbp } 123875374Sbp if (mdp->md_top->m_len == 0) { 123975374Sbp printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 124075374Sbp return ENOENT; 124175374Sbp } 124275374Sbp ctx->f_eofs = 0; 124375374Sbp return 0; 124475374Sbp} 124575374Sbp 124675374Sbpstatic int 124775374Sbpsmbfs_smb_findclose2(struct smbfs_fctx *ctx) 124875374Sbp{ 124975374Sbp struct smb_rq rq, *rqp = &rq; 125075374Sbp struct mbchain *mbp; 125175374Sbp int error; 125275374Sbp 125375374Sbp error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 125475374Sbp if (error) 125575374Sbp return error; 125675374Sbp smb_rq_getrequest(rqp, &mbp); 125775374Sbp smb_rq_wstart(rqp); 125875374Sbp mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 125975374Sbp smb_rq_wend(rqp); 126075374Sbp smb_rq_bstart(rqp); 126175374Sbp smb_rq_bend(rqp); 126275374Sbp error = smb_rq_simple(rqp); 126375374Sbp smb_rq_done(rqp); 126475374Sbp return error; 126575374Sbp} 126675374Sbp 126775374Sbpstatic int 126875374Sbpsmbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 126975374Sbp const char *wildcard, int wclen, int attr, struct smb_cred *scred) 127075374Sbp{ 1271111119Simp ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 127275374Sbp if (ctx->f_name == NULL) 127375374Sbp return ENOMEM; 127475374Sbp ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 127575374Sbp SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 127675374Sbp ctx->f_attrmask = attr; 127775374Sbp ctx->f_wildcard = wildcard; 127875374Sbp ctx->f_wclen = wclen; 127975374Sbp return 0; 128075374Sbp} 128175374Sbp 128275374Sbpstatic int 128375374Sbpsmbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 128475374Sbp{ 128575374Sbp struct mdchain *mbp; 128675374Sbp struct smb_t2rq *t2p; 128775374Sbp char *cp; 128875374Sbp u_int8_t tb; 128975374Sbp u_int16_t date, time, wattr; 129075374Sbp u_int32_t size, next, dattr; 129175374Sbp int64_t lint; 129275374Sbp int error, svtz, cnt, fxsz, nmlen, recsz; 129375374Sbp 129475374Sbp if (ctx->f_ecnt == 0) { 129575374Sbp if (ctx->f_flags & SMBFS_RDD_EOF) 129675374Sbp return ENOENT; 129775374Sbp ctx->f_left = ctx->f_limit = limit; 129875374Sbp error = smbfs_smb_trans2find2(ctx); 129975374Sbp if (error) 130075374Sbp return error; 130175374Sbp } 130275374Sbp t2p = ctx->f_t2; 130375374Sbp mbp = &t2p->t2_rdata; 130475374Sbp svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 130575374Sbp switch (ctx->f_infolevel) { 130675374Sbp case SMB_INFO_STANDARD: 130775374Sbp next = 0; 130875374Sbp fxsz = 0; 130975374Sbp md_get_uint16le(mbp, &date); 131075374Sbp md_get_uint16le(mbp, &time); /* creation time */ 131175374Sbp md_get_uint16le(mbp, &date); 131275374Sbp md_get_uint16le(mbp, &time); /* access time */ 131375374Sbp smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 131475374Sbp md_get_uint16le(mbp, &date); 131575374Sbp md_get_uint16le(mbp, &time); /* access time */ 131675374Sbp smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 131775374Sbp md_get_uint32le(mbp, &size); 131875374Sbp ctx->f_attr.fa_size = size; 131975374Sbp md_get_uint32(mbp, NULL); /* allocation size */ 132075374Sbp md_get_uint16le(mbp, &wattr); 132175374Sbp ctx->f_attr.fa_attr = wattr; 132275374Sbp md_get_uint8(mbp, &tb); 132375374Sbp size = nmlen = tb; 132475374Sbp fxsz = 23; 132575374Sbp recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 132675374Sbp break; 132775374Sbp case SMB_FIND_FILE_DIRECTORY_INFO: 132875374Sbp md_get_uint32le(mbp, &next); 132975374Sbp md_get_uint32(mbp, NULL); /* file index */ 133075374Sbp md_get_int64(mbp, NULL); /* creation time */ 133175374Sbp md_get_int64le(mbp, &lint); 133275374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 133375374Sbp md_get_int64le(mbp, &lint); 133475374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 133575374Sbp md_get_int64le(mbp, &lint); 133675374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 133775374Sbp md_get_int64le(mbp, &lint); /* file size */ 133875374Sbp ctx->f_attr.fa_size = lint; 133975374Sbp md_get_int64(mbp, NULL); /* real size (should use) */ 134082039Sbp md_get_uint32le(mbp, &dattr); /* EA */ 134175374Sbp ctx->f_attr.fa_attr = dattr; 134275374Sbp md_get_uint32le(mbp, &size); /* name len */ 134375374Sbp fxsz = 64; 134475374Sbp recsz = next ? next : fxsz + size; 134575374Sbp break; 134675374Sbp default: 134775374Sbp SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 134875374Sbp return EINVAL; 134975374Sbp } 135075374Sbp nmlen = min(size, SMB_MAXFNAMELEN); 135175374Sbp cp = ctx->f_name; 135275374Sbp error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 135375374Sbp if (error) 135475374Sbp return error; 135575374Sbp if (next) { 135675374Sbp cnt = next - nmlen - fxsz; 135775374Sbp if (cnt > 0) 135875374Sbp md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 135975374Sbp else if (cnt < 0) { 136075374Sbp SMBERROR("out of sync\n"); 136175374Sbp return EBADRPC; 136275374Sbp } 136375374Sbp } 136475374Sbp if (nmlen && cp[nmlen - 1] == 0) 136575374Sbp nmlen--; 136675374Sbp if (nmlen == 0) 136775374Sbp return EBADRPC; 136875374Sbp 136975374Sbp next = ctx->f_eofs + recsz; 137075374Sbp if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 137175374Sbp (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 137275374Sbp /* 137375374Sbp * Server needs a resume filename. 137475374Sbp */ 137575374Sbp if (ctx->f_rnamelen <= nmlen) { 137675374Sbp if (ctx->f_rname) 137775374Sbp free(ctx->f_rname, M_SMBFSDATA); 1378111119Simp ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 137975374Sbp ctx->f_rnamelen = nmlen; 138075374Sbp } 138175374Sbp bcopy(ctx->f_name, ctx->f_rname, nmlen); 138275374Sbp ctx->f_rname[nmlen] = 0; 138375374Sbp ctx->f_flags |= SMBFS_RDD_GOTRNAME; 138475374Sbp } 138575374Sbp ctx->f_nmlen = nmlen; 138675374Sbp ctx->f_eofs = next; 138775374Sbp ctx->f_ecnt--; 138875374Sbp ctx->f_left--; 138975374Sbp return 0; 139075374Sbp} 139175374Sbp 139275374Sbpstatic int 139375374Sbpsmbfs_findcloseLM2(struct smbfs_fctx *ctx) 139475374Sbp{ 139575374Sbp if (ctx->f_name) 139675374Sbp free(ctx->f_name, M_SMBFSDATA); 139775374Sbp if (ctx->f_t2) 139875374Sbp smb_t2_done(ctx->f_t2); 139975374Sbp if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 140075374Sbp smbfs_smb_findclose2(ctx); 140175374Sbp return 0; 140275374Sbp} 140375374Sbp 140475374Sbpint 140575374Sbpsmbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 140675374Sbp struct smb_cred *scred, struct smbfs_fctx **ctxpp) 140775374Sbp{ 140875374Sbp struct smbfs_fctx *ctx; 140975374Sbp int error; 141075374Sbp 1411111119Simp ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 141275374Sbp if (ctx == NULL) 141375374Sbp return ENOMEM; 141475374Sbp bzero(ctx, sizeof(*ctx)); 141575374Sbp ctx->f_ssp = dnp->n_mount->sm_share; 141675374Sbp ctx->f_dnp = dnp; 141775374Sbp ctx->f_flags = SMBFS_RDD_FINDFIRST; 141875374Sbp ctx->f_scred = scred; 141975374Sbp if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1420138490Sphk (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 142175374Sbp ctx->f_flags |= SMBFS_RDD_USESEARCH; 142275374Sbp error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 142375374Sbp } else 142475374Sbp error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 142575374Sbp if (error) 142675374Sbp smbfs_findclose(ctx, scred); 142775374Sbp else 142875374Sbp *ctxpp = ctx; 142975374Sbp return error; 143075374Sbp} 143175374Sbp 143275374Sbpint 143375374Sbpsmbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 143475374Sbp{ 143575374Sbp int error; 143675374Sbp 143775374Sbp if (limit == 0) 143875374Sbp limit = 1000000; 143975374Sbp else if (limit > 1) 144075374Sbp limit *= 4; /* imperical */ 144175374Sbp ctx->f_scred = scred; 144275374Sbp for (;;) { 144375374Sbp if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 144475374Sbp error = smbfs_findnextLM1(ctx, limit); 144575374Sbp } else 144675374Sbp error = smbfs_findnextLM2(ctx, limit); 144775374Sbp if (error) 144875374Sbp return error; 144975374Sbp if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 145075374Sbp (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 145175374Sbp ctx->f_name[1] == '.')) 145275374Sbp continue; 145375374Sbp break; 145475374Sbp } 1455145872Stakawata smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, 1456145872Stakawata ctx->f_dnp->n_mount->sm_caseopt); 145775374Sbp ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 145875374Sbp return 0; 145975374Sbp} 146075374Sbp 146175374Sbpint 146275374Sbpsmbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 146375374Sbp{ 146475374Sbp ctx->f_scred = scred; 146575374Sbp if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 146675374Sbp smbfs_findcloseLM1(ctx); 146775374Sbp } else 146875374Sbp smbfs_findcloseLM2(ctx); 146975374Sbp if (ctx->f_rname) 147075374Sbp free(ctx->f_rname, M_SMBFSDATA); 147175374Sbp free(ctx, M_SMBFSDATA); 147275374Sbp return 0; 147375374Sbp} 147475374Sbp 147575374Sbpint 147675374Sbpsmbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 147775374Sbp struct smbfattr *fap, struct smb_cred *scred) 147875374Sbp{ 147975374Sbp struct smbfs_fctx *ctx; 148075374Sbp int error; 148175374Sbp 148275374Sbp if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 148375374Sbp bzero(fap, sizeof(*fap)); 148475374Sbp fap->fa_attr = SMB_FA_DIR; 148575374Sbp fap->fa_ino = 2; 148675374Sbp return 0; 148775374Sbp } 148875374Sbp if (nmlen == 1 && name[0] == '.') { 148975374Sbp error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 149075374Sbp return error; 149175374Sbp } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1492107821Stjr error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1493107821Stjr scred); 149487599Sobrien printf("%s: knows NOTHING about '..'\n", __func__); 149575374Sbp return error; 149675374Sbp } 149775374Sbp error = smbfs_findopen(dnp, name, nmlen, 149875374Sbp SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 149975374Sbp if (error) 150075374Sbp return error; 150175374Sbp ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 150275374Sbp error = smbfs_findnext(ctx, 1, scred); 150375374Sbp if (error == 0) { 150475374Sbp *fap = ctx->f_attr; 150575374Sbp if (name == NULL) 150675374Sbp fap->fa_ino = dnp->n_ino; 150775374Sbp } 150875374Sbp smbfs_findclose(ctx, scred); 150975374Sbp return error; 151075374Sbp} 1511