smbfs_smb.c revision 138490
175374Sbp/* 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 138490 2004-12-06 20:31:08Z phk $ 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); 51575374Sbp SMBERROR("%d\n", error); 51675374Sbp if (error) 51775374Sbp break; 51875374Sbp } while(0); 51975374Sbp smb_rq_done(rqp); 52075374Sbp return error; 52175374Sbp} 52275374Sbp 52375374Sbp/* 52475374Sbp * Note, win95 doesn't support this call. 52575374Sbp */ 52675374Sbpint 52775374Sbpsmbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 52875374Sbp struct timespec *atime, int attr, struct smb_cred *scred) 52975374Sbp{ 53075374Sbp struct smb_t2rq *t2p; 53175374Sbp struct smb_share *ssp = np->n_mount->sm_share; 53275374Sbp struct smb_vc *vcp = SSTOVC(ssp); 53375374Sbp struct mbchain *mbp; 53475374Sbp u_int16_t date, time; 53575374Sbp int error, tzoff; 53675374Sbp 53775374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 53875374Sbp scred, &t2p); 53975374Sbp if (error) 54075374Sbp return error; 54175374Sbp mbp = &t2p->t2_tparam; 54275374Sbp mb_init(mbp); 54375374Sbp mb_put_uint16le(mbp, SMB_INFO_STANDARD); 54475374Sbp mb_put_uint32le(mbp, 0); /* MBZ */ 545103533Sbp /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 54675374Sbp error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 54775374Sbp if (error) { 54875374Sbp smb_t2_done(t2p); 54975374Sbp return error; 55075374Sbp } 55175374Sbp tzoff = vcp->vc_sopt.sv_tz; 55275374Sbp mbp = &t2p->t2_tdata; 55375374Sbp mb_init(mbp); 55475374Sbp mb_put_uint32le(mbp, 0); /* creation time */ 55575374Sbp if (atime) 55675374Sbp smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 55775374Sbp else 55875374Sbp time = date = 0; 55975374Sbp mb_put_uint16le(mbp, date); 56075374Sbp mb_put_uint16le(mbp, time); 56175374Sbp if (mtime) 56275374Sbp smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 56375374Sbp else 56475374Sbp time = date = 0; 56575374Sbp mb_put_uint16le(mbp, date); 56675374Sbp mb_put_uint16le(mbp, time); 56775374Sbp mb_put_uint32le(mbp, 0); /* file size */ 56875374Sbp mb_put_uint32le(mbp, 0); /* allocation unit size */ 56975374Sbp mb_put_uint16le(mbp, attr); /* DOS attr */ 57075374Sbp mb_put_uint32le(mbp, 0); /* EA size */ 57175374Sbp t2p->t2_maxpcount = 5 * 2; 57275374Sbp t2p->t2_maxdcount = vcp->vc_txmax; 57375374Sbp error = smb_t2_request(t2p); 57475374Sbp smb_t2_done(t2p); 57575374Sbp return error; 57675374Sbp} 57775374Sbp 57875374Sbp/* 57975374Sbp * NT level. Specially for win9x 58075374Sbp */ 58175374Sbpint 58275374Sbpsmbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 58375374Sbp struct timespec *atime, struct smb_cred *scred) 58475374Sbp{ 58575374Sbp struct smb_t2rq *t2p; 58675374Sbp struct smb_share *ssp = np->n_mount->sm_share; 58775374Sbp struct smb_vc *vcp = SSTOVC(ssp); 58875374Sbp struct mbchain *mbp; 58975374Sbp int64_t tm; 59075374Sbp int error, tzoff; 59175374Sbp 59275374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 59375374Sbp scred, &t2p); 59475374Sbp if (error) 59575374Sbp return error; 59675374Sbp mbp = &t2p->t2_tparam; 59775374Sbp mb_init(mbp); 59875374Sbp mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 59975374Sbp mb_put_uint32le(mbp, 0); /* MBZ */ 600103533Sbp /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 60175374Sbp error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 60275374Sbp if (error) { 60375374Sbp smb_t2_done(t2p); 60475374Sbp return error; 60575374Sbp } 60675374Sbp tzoff = vcp->vc_sopt.sv_tz; 60775374Sbp mbp = &t2p->t2_tdata; 60875374Sbp mb_init(mbp); 60975374Sbp mb_put_int64le(mbp, 0); /* creation time */ 61075374Sbp if (atime) { 61175374Sbp smb_time_local2NT(atime, tzoff, &tm); 61275374Sbp } else 61375374Sbp tm = 0; 61475374Sbp mb_put_int64le(mbp, tm); 61575374Sbp if (mtime) { 61675374Sbp smb_time_local2NT(mtime, tzoff, &tm); 61775374Sbp } else 61875374Sbp tm = 0; 61975374Sbp mb_put_int64le(mbp, tm); 62075374Sbp mb_put_int64le(mbp, tm); /* change time */ 62175374Sbp mb_put_uint32le(mbp, attr); /* attr */ 62275374Sbp t2p->t2_maxpcount = 24; 62375374Sbp t2p->t2_maxdcount = 56; 62475374Sbp error = smb_t2_request(t2p); 62575374Sbp smb_t2_done(t2p); 62675374Sbp return error; 62775374Sbp} 62875374Sbp 62975374Sbp/* 63075374Sbp * Set file atime and mtime. Doesn't supported by core dialect. 63175374Sbp */ 63275374Sbpint 63375374Sbpsmbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 63475374Sbp struct timespec *atime, struct smb_cred *scred) 63575374Sbp{ 63675374Sbp struct smb_rq rq, *rqp = &rq; 63775374Sbp struct smb_share *ssp = np->n_mount->sm_share; 63875374Sbp struct mbchain *mbp; 63975374Sbp u_int16_t date, time; 64075374Sbp int error, tzoff; 64175374Sbp 64275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 64375374Sbp if (error) 64475374Sbp return error; 64575374Sbp tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 64675374Sbp smb_rq_getrequest(rqp, &mbp); 64775374Sbp smb_rq_wstart(rqp); 64875374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 64975374Sbp mb_put_uint32le(mbp, 0); /* creation time */ 65075374Sbp 65175374Sbp if (atime) 65275374Sbp smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 65375374Sbp else 65475374Sbp time = date = 0; 65575374Sbp mb_put_uint16le(mbp, date); 65675374Sbp mb_put_uint16le(mbp, time); 65775374Sbp if (mtime) 65875374Sbp smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 65975374Sbp else 66075374Sbp time = date = 0; 66175374Sbp mb_put_uint16le(mbp, date); 66275374Sbp mb_put_uint16le(mbp, time); 66375374Sbp smb_rq_wend(rqp); 66475374Sbp smb_rq_bstart(rqp); 66575374Sbp smb_rq_bend(rqp); 66675374Sbp error = smb_rq_simple(rqp); 66775374Sbp SMBSDEBUG("%d\n", error); 66875374Sbp smb_rq_done(rqp); 66975374Sbp return error; 67075374Sbp} 67175374Sbp 67275374Sbp/* 67375374Sbp * Set DOS file attributes. 67475374Sbp * Looks like this call can be used only if CAP_NT_SMBS bit is on. 67575374Sbp */ 67675374Sbpint 67775374Sbpsmbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 67875374Sbp struct timespec *atime, struct smb_cred *scred) 67975374Sbp{ 68075374Sbp struct smb_t2rq *t2p; 68175374Sbp struct smb_share *ssp = np->n_mount->sm_share; 68275374Sbp struct mbchain *mbp; 68375374Sbp int64_t tm; 68475374Sbp int error, svtz; 68575374Sbp 68675374Sbp error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 68775374Sbp scred, &t2p); 68875374Sbp if (error) 68975374Sbp return error; 69075374Sbp svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 69175374Sbp mbp = &t2p->t2_tparam; 69275374Sbp mb_init(mbp); 69375374Sbp mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 69475374Sbp mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 69575374Sbp mb_put_uint32le(mbp, 0); 69675374Sbp mbp = &t2p->t2_tdata; 69775374Sbp mb_init(mbp); 69875374Sbp mb_put_int64le(mbp, 0); /* creation time */ 69975374Sbp if (atime) { 70075374Sbp smb_time_local2NT(atime, svtz, &tm); 70175374Sbp } else 70275374Sbp tm = 0; 70375374Sbp mb_put_int64le(mbp, tm); 70475374Sbp if (mtime) { 70575374Sbp smb_time_local2NT(mtime, svtz, &tm); 70675374Sbp } else 70775374Sbp tm = 0; 70875374Sbp mb_put_int64le(mbp, tm); 70975374Sbp mb_put_int64le(mbp, tm); /* change time */ 71075374Sbp mb_put_uint16le(mbp, attr); 71175374Sbp mb_put_uint32le(mbp, 0); /* padding */ 71275374Sbp mb_put_uint16le(mbp, 0); 71375374Sbp t2p->t2_maxpcount = 2; 71475374Sbp t2p->t2_maxdcount = 0; 71575374Sbp error = smb_t2_request(t2p); 71675374Sbp smb_t2_done(t2p); 71775374Sbp return error; 71875374Sbp} 71975374Sbp 72075374Sbp 72175374Sbpint 72275374Sbpsmbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 72375374Sbp{ 72475374Sbp struct smb_rq rq, *rqp = &rq; 72575374Sbp struct smb_share *ssp = np->n_mount->sm_share; 72675374Sbp struct mbchain *mbp; 72775374Sbp struct mdchain *mdp; 72875374Sbp u_int8_t wc; 72975374Sbp u_int16_t fid, wattr, grantedmode; 73075374Sbp int error; 73175374Sbp 73275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 73375374Sbp if (error) 73475374Sbp return error; 73575374Sbp smb_rq_getrequest(rqp, &mbp); 73675374Sbp smb_rq_wstart(rqp); 73775374Sbp mb_put_uint16le(mbp, accmode); 73875374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 73975374Sbp smb_rq_wend(rqp); 74075374Sbp smb_rq_bstart(rqp); 74175374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 74275374Sbp do { 74375374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 74475374Sbp if (error) 74575374Sbp break; 74675374Sbp smb_rq_bend(rqp); 74775374Sbp error = smb_rq_simple(rqp); 74875374Sbp if (error) 74975374Sbp break; 75075374Sbp smb_rq_getreply(rqp, &mdp); 75175374Sbp if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 75275374Sbp error = EBADRPC; 75375374Sbp break; 75475374Sbp } 75575374Sbp md_get_uint16(mdp, &fid); 75675374Sbp md_get_uint16le(mdp, &wattr); 75775374Sbp md_get_uint32(mdp, NULL); /* mtime */ 75875374Sbp md_get_uint32(mdp, NULL); /* fsize */ 75975374Sbp md_get_uint16le(mdp, &grantedmode); 76075374Sbp /* 76175374Sbp * TODO: refresh attributes from this reply 76275374Sbp */ 76375374Sbp } while(0); 76475374Sbp smb_rq_done(rqp); 76575374Sbp if (error) 76675374Sbp return error; 76775374Sbp np->n_fid = fid; 76875374Sbp np->n_rwstate = grantedmode; 76975374Sbp return 0; 77075374Sbp} 77175374Sbp 77275374Sbp 77375374Sbpint 77475374Sbpsmbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 77575374Sbp struct smb_cred *scred) 77675374Sbp{ 77775374Sbp struct smb_rq rq, *rqp = &rq; 77875374Sbp struct mbchain *mbp; 77975374Sbp u_long time; 78075374Sbp int error; 78175374Sbp 78275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 78375374Sbp if (error) 78475374Sbp return error; 78575374Sbp smb_rq_getrequest(rqp, &mbp); 78675374Sbp smb_rq_wstart(rqp); 78775374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 78875374Sbp if (mtime) { 78975374Sbp smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 79075374Sbp } else 79175374Sbp time = 0; 79275374Sbp mb_put_uint32le(mbp, time); 79375374Sbp smb_rq_wend(rqp); 79475374Sbp smb_rq_bstart(rqp); 79575374Sbp smb_rq_bend(rqp); 79675374Sbp error = smb_rq_simple(rqp); 79775374Sbp smb_rq_done(rqp); 79875374Sbp return error; 79975374Sbp} 80075374Sbp 80175374Sbpint 80275374Sbpsmbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 80375374Sbp struct smb_cred *scred) 80475374Sbp{ 80575374Sbp struct smb_rq rq, *rqp = &rq; 80675374Sbp struct smb_share *ssp = dnp->n_mount->sm_share; 80775374Sbp struct mbchain *mbp; 80875374Sbp struct mdchain *mdp; 80975374Sbp struct timespec ctime; 81075374Sbp u_int8_t wc; 81175374Sbp u_int16_t fid; 81275374Sbp u_long tm; 81375374Sbp int error; 81475374Sbp 81575374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 81675374Sbp if (error) 81775374Sbp return error; 81875374Sbp smb_rq_getrequest(rqp, &mbp); 81975374Sbp smb_rq_wstart(rqp); 82075374Sbp mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 82175374Sbp nanotime(&ctime); 82275374Sbp smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 82375374Sbp mb_put_uint32le(mbp, tm); 82475374Sbp smb_rq_wend(rqp); 82575374Sbp smb_rq_bstart(rqp); 82675374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 82775374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 82875374Sbp if (!error) { 82975374Sbp smb_rq_bend(rqp); 83075374Sbp error = smb_rq_simple(rqp); 83175374Sbp if (!error) { 83275374Sbp smb_rq_getreply(rqp, &mdp); 83375374Sbp md_get_uint8(mdp, &wc); 83475374Sbp if (wc == 1) 83575374Sbp md_get_uint16(mdp, &fid); 83675374Sbp else 83775374Sbp error = EBADRPC; 83875374Sbp } 83975374Sbp } 84075374Sbp smb_rq_done(rqp); 84175374Sbp if (error) 84275374Sbp return error; 84375374Sbp smbfs_smb_close(ssp, fid, &ctime, scred); 84475374Sbp return error; 84575374Sbp} 84675374Sbp 84775374Sbpint 84875374Sbpsmbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 84975374Sbp{ 85075374Sbp struct smb_rq rq, *rqp = &rq; 85175374Sbp struct smb_share *ssp = np->n_mount->sm_share; 85275374Sbp struct mbchain *mbp; 85375374Sbp int error; 85475374Sbp 85575374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 85675374Sbp if (error) 85775374Sbp return error; 85875374Sbp smb_rq_getrequest(rqp, &mbp); 85975374Sbp smb_rq_wstart(rqp); 86075374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 86175374Sbp smb_rq_wend(rqp); 86275374Sbp smb_rq_bstart(rqp); 86375374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 86475374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 86575374Sbp if (!error) { 86675374Sbp smb_rq_bend(rqp); 86775374Sbp error = smb_rq_simple(rqp); 86875374Sbp } 86975374Sbp smb_rq_done(rqp); 87075374Sbp return error; 87175374Sbp} 87275374Sbp 87375374Sbpint 87475374Sbpsmbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 87575374Sbp const char *tname, int tnmlen, struct smb_cred *scred) 87675374Sbp{ 87775374Sbp struct smb_rq rq, *rqp = &rq; 87875374Sbp struct smb_share *ssp = src->n_mount->sm_share; 87975374Sbp struct mbchain *mbp; 88075374Sbp int error; 88175374Sbp 88275374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 88375374Sbp if (error) 88475374Sbp return error; 88575374Sbp smb_rq_getrequest(rqp, &mbp); 88675374Sbp smb_rq_wstart(rqp); 88775374Sbp mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 88875374Sbp smb_rq_wend(rqp); 88975374Sbp smb_rq_bstart(rqp); 89075374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 89175374Sbp do { 89275374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 89375374Sbp if (error) 89475374Sbp break; 89575374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 89675374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 89775374Sbp if (error) 89875374Sbp break; 89975374Sbp smb_rq_bend(rqp); 90075374Sbp error = smb_rq_simple(rqp); 90175374Sbp } while(0); 90275374Sbp smb_rq_done(rqp); 90375374Sbp return error; 90475374Sbp} 90575374Sbp 90675374Sbpint 90775374Sbpsmbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 90875374Sbp const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 90975374Sbp{ 91075374Sbp struct smb_rq rq, *rqp = &rq; 91175374Sbp struct smb_share *ssp = src->n_mount->sm_share; 91275374Sbp struct mbchain *mbp; 91375374Sbp int error; 91475374Sbp 91575374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 91675374Sbp if (error) 91775374Sbp return error; 91875374Sbp smb_rq_getrequest(rqp, &mbp); 91975374Sbp smb_rq_wstart(rqp); 92075374Sbp mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 92175374Sbp mb_put_uint16le(mbp, 0x20); /* delete target file */ 92275374Sbp mb_put_uint16le(mbp, flags); 92375374Sbp smb_rq_wend(rqp); 92475374Sbp smb_rq_bstart(rqp); 92575374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 92675374Sbp do { 92775374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 92875374Sbp if (error) 92975374Sbp break; 93075374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 93175374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 93275374Sbp if (error) 93375374Sbp break; 93475374Sbp smb_rq_bend(rqp); 93575374Sbp error = smb_rq_simple(rqp); 93675374Sbp } while(0); 93775374Sbp smb_rq_done(rqp); 93875374Sbp return error; 93975374Sbp} 94075374Sbp 94175374Sbpint 94275374Sbpsmbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 94375374Sbp struct smb_cred *scred) 94475374Sbp{ 94575374Sbp struct smb_rq rq, *rqp = &rq; 94675374Sbp struct smb_share *ssp = dnp->n_mount->sm_share; 94775374Sbp struct mbchain *mbp; 94875374Sbp int error; 94975374Sbp 95075374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 95175374Sbp if (error) 95275374Sbp return error; 95375374Sbp smb_rq_getrequest(rqp, &mbp); 95475374Sbp smb_rq_wstart(rqp); 95575374Sbp smb_rq_wend(rqp); 95675374Sbp smb_rq_bstart(rqp); 95775374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 95875374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 95975374Sbp if (!error) { 96075374Sbp smb_rq_bend(rqp); 96175374Sbp error = smb_rq_simple(rqp); 96275374Sbp } 96375374Sbp smb_rq_done(rqp); 96475374Sbp return error; 96575374Sbp} 96675374Sbp 96775374Sbpint 96875374Sbpsmbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 96975374Sbp{ 97075374Sbp struct smb_rq rq, *rqp = &rq; 97175374Sbp struct smb_share *ssp = np->n_mount->sm_share; 97275374Sbp struct mbchain *mbp; 97375374Sbp int error; 97475374Sbp 97575374Sbp error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 97675374Sbp if (error) 97775374Sbp return error; 97875374Sbp smb_rq_getrequest(rqp, &mbp); 97975374Sbp smb_rq_wstart(rqp); 98075374Sbp smb_rq_wend(rqp); 98175374Sbp smb_rq_bstart(rqp); 98275374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); 98375374Sbp error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 98475374Sbp if (!error) { 98575374Sbp smb_rq_bend(rqp); 98675374Sbp error = smb_rq_simple(rqp); 98775374Sbp } 98875374Sbp smb_rq_done(rqp); 98975374Sbp return error; 99075374Sbp} 99175374Sbp 99275374Sbpstatic int 99375374Sbpsmbfs_smb_search(struct smbfs_fctx *ctx) 99475374Sbp{ 99575374Sbp struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 99675374Sbp struct smb_rq *rqp; 99775374Sbp struct mbchain *mbp; 99875374Sbp struct mdchain *mdp; 99975374Sbp u_int8_t wc, bt; 100075374Sbp u_int16_t ec, dlen, bc; 100175374Sbp int maxent, error, iseof = 0; 100275374Sbp 100375374Sbp maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 100475374Sbp if (ctx->f_rq) { 100575374Sbp smb_rq_done(ctx->f_rq); 100675374Sbp ctx->f_rq = NULL; 100775374Sbp } 100875374Sbp error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 100975374Sbp if (error) 101075374Sbp return error; 101175374Sbp ctx->f_rq = rqp; 101275374Sbp smb_rq_getrequest(rqp, &mbp); 101375374Sbp smb_rq_wstart(rqp); 101475374Sbp mb_put_uint16le(mbp, maxent); /* max entries to return */ 101575374Sbp mb_put_uint16le(mbp, ctx->f_attrmask); 101675374Sbp smb_rq_wend(rqp); 101775374Sbp smb_rq_bstart(rqp); 101875374Sbp mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 101975374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 102075374Sbp error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 102175374Sbp if (error) 102275374Sbp return error; 102375374Sbp mb_put_uint8(mbp, SMB_DT_VARIABLE); 102475374Sbp mb_put_uint16le(mbp, 0); /* context length */ 102575374Sbp ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 102675374Sbp } else { 102775374Sbp mb_put_uint8(mbp, 0); /* file name length */ 102875374Sbp mb_put_uint8(mbp, SMB_DT_VARIABLE); 102975374Sbp mb_put_uint16le(mbp, SMB_SKEYLEN); 103075374Sbp mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 103175374Sbp } 103275374Sbp smb_rq_bend(rqp); 103375374Sbp error = smb_rq_simple(rqp); 103475374Sbp if (error) { 103575374Sbp if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 103675374Sbp error = 0; 103775374Sbp iseof = 1; 103875374Sbp ctx->f_flags |= SMBFS_RDD_EOF; 103975374Sbp } else 104075374Sbp return error; 104175374Sbp } 104275374Sbp smb_rq_getreply(rqp, &mdp); 104375374Sbp md_get_uint8(mdp, &wc); 104475374Sbp if (wc != 1) 104575374Sbp return iseof ? ENOENT : EBADRPC; 104675374Sbp md_get_uint16le(mdp, &ec); 104775374Sbp if (ec == 0) 104875374Sbp return ENOENT; 104975374Sbp ctx->f_ecnt = ec; 105075374Sbp md_get_uint16le(mdp, &bc); 105175374Sbp if (bc < 3) 105275374Sbp return EBADRPC; 105375374Sbp bc -= 3; 105475374Sbp md_get_uint8(mdp, &bt); 105575374Sbp if (bt != SMB_DT_VARIABLE) 105675374Sbp return EBADRPC; 105775374Sbp md_get_uint16le(mdp, &dlen); 105875374Sbp if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 105975374Sbp return EBADRPC; 106075374Sbp return 0; 106175374Sbp} 106275374Sbp 106375374Sbpstatic int 106475374Sbpsmbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 106575374Sbp const char *wildcard, int wclen, int attr, struct smb_cred *scred) 106675374Sbp{ 106775374Sbp ctx->f_attrmask = attr; 106875374Sbp if (wildcard) { 106975374Sbp if (wclen == 1 && wildcard[0] == '*') { 107075374Sbp ctx->f_wildcard = "*.*"; 107175374Sbp ctx->f_wclen = 3; 107275374Sbp } else { 107375374Sbp ctx->f_wildcard = wildcard; 107475374Sbp ctx->f_wclen = wclen; 107575374Sbp } 107675374Sbp } else { 107775374Sbp ctx->f_wildcard = NULL; 107875374Sbp ctx->f_wclen = 0; 107975374Sbp } 108075374Sbp ctx->f_name = ctx->f_fname; 108175374Sbp return 0; 108275374Sbp} 108375374Sbp 108475374Sbpstatic int 108575374Sbpsmbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 108675374Sbp{ 108775374Sbp struct mdchain *mbp; 108875374Sbp struct smb_rq *rqp; 108975374Sbp char *cp; 109075374Sbp u_int8_t battr; 109175374Sbp u_int16_t date, time; 109275374Sbp u_int32_t size; 109375374Sbp int error; 109475374Sbp 109575374Sbp if (ctx->f_ecnt == 0) { 109675374Sbp if (ctx->f_flags & SMBFS_RDD_EOF) 109775374Sbp return ENOENT; 109875374Sbp ctx->f_left = ctx->f_limit = limit; 109975374Sbp error = smbfs_smb_search(ctx); 110075374Sbp if (error) 110175374Sbp return error; 110275374Sbp } 110375374Sbp rqp = ctx->f_rq; 110475374Sbp smb_rq_getreply(rqp, &mbp); 110575374Sbp md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 110675374Sbp md_get_uint8(mbp, &battr); 110775374Sbp md_get_uint16le(mbp, &time); 110875374Sbp md_get_uint16le(mbp, &date); 110975374Sbp md_get_uint32le(mbp, &size); 111075374Sbp cp = ctx->f_name; 111175374Sbp md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 111275374Sbp cp[sizeof(ctx->f_fname) - 1] = 0; 111375374Sbp cp += strlen(cp) - 1; 111475374Sbp while (*cp == ' ' && cp >= ctx->f_name) 111575374Sbp *cp-- = 0; 111675374Sbp ctx->f_attr.fa_attr = battr; 111775374Sbp smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 111875374Sbp &ctx->f_attr.fa_mtime); 111975374Sbp ctx->f_attr.fa_size = size; 112075374Sbp ctx->f_nmlen = strlen(ctx->f_name); 112175374Sbp ctx->f_ecnt--; 112275374Sbp ctx->f_left--; 112375374Sbp return 0; 112475374Sbp} 112575374Sbp 112675374Sbpstatic int 112775374Sbpsmbfs_findcloseLM1(struct smbfs_fctx *ctx) 112875374Sbp{ 112975374Sbp if (ctx->f_rq) 113075374Sbp smb_rq_done(ctx->f_rq); 113175374Sbp return 0; 113275374Sbp} 113375374Sbp 113475374Sbp/* 113575374Sbp * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 113675374Sbp */ 113775374Sbpstatic int 113875374Sbpsmbfs_smb_trans2find2(struct smbfs_fctx *ctx) 113975374Sbp{ 114075374Sbp struct smb_t2rq *t2p; 114175374Sbp struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 114275374Sbp struct mbchain *mbp; 114375374Sbp struct mdchain *mdp; 114475374Sbp u_int16_t tw, flags; 114575374Sbp int error; 114675374Sbp 114775374Sbp if (ctx->f_t2) { 114875374Sbp smb_t2_done(ctx->f_t2); 114975374Sbp ctx->f_t2 = NULL; 115075374Sbp } 115175374Sbp ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 115275374Sbp flags = 8 | 2; /* <resume> | <close if EOS> */ 115375374Sbp if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 115475374Sbp flags |= 1; /* close search after this request */ 115575374Sbp ctx->f_flags |= SMBFS_RDD_NOCLOSE; 115675374Sbp } 115775374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 115875374Sbp error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 115975374Sbp ctx->f_scred, &t2p); 116075374Sbp if (error) 116175374Sbp return error; 116275374Sbp ctx->f_t2 = t2p; 116375374Sbp mbp = &t2p->t2_tparam; 116475374Sbp mb_init(mbp); 116575374Sbp mb_put_uint16le(mbp, ctx->f_attrmask); 116675374Sbp mb_put_uint16le(mbp, ctx->f_limit); 116775374Sbp mb_put_uint16le(mbp, flags); 116875374Sbp mb_put_uint16le(mbp, ctx->f_infolevel); 116975374Sbp mb_put_uint32le(mbp, 0); 117075374Sbp error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 117175374Sbp if (error) 117275374Sbp return error; 117375374Sbp } else { 117475374Sbp error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 117575374Sbp ctx->f_scred, &t2p); 117675374Sbp if (error) 117775374Sbp return error; 117875374Sbp ctx->f_t2 = t2p; 117975374Sbp mbp = &t2p->t2_tparam; 118075374Sbp mb_init(mbp); 118175374Sbp mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 118275374Sbp mb_put_uint16le(mbp, ctx->f_limit); 118375374Sbp mb_put_uint16le(mbp, ctx->f_infolevel); 118475374Sbp mb_put_uint32le(mbp, 0); /* resume key */ 118575374Sbp mb_put_uint16le(mbp, flags); 118675374Sbp if (ctx->f_rname) 118775374Sbp mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 118875374Sbp else 118975374Sbp mb_put_uint8(mbp, 0); /* resume file name */ 119075374Sbp#if 0 119175374Sbp struct timeval tv; 119275374Sbp tv.tv_sec = 0; 119375374Sbp tv.tv_usec = 200 * 1000; /* 200ms */ 119475374Sbp if (vcp->vc_flags & SMBC_WIN95) { 119575374Sbp /* 119675374Sbp * some implementations suggests to sleep here 119775374Sbp * for 200ms, due to the bug in the Win95. 119875374Sbp * I've didn't notice any problem, but put code 119975374Sbp * for it. 120075374Sbp */ 120175374Sbp tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); 120275374Sbp } 120375374Sbp#endif 120475374Sbp } 120575374Sbp t2p->t2_maxpcount = 5 * 2; 120675374Sbp t2p->t2_maxdcount = vcp->vc_txmax; 120775374Sbp error = smb_t2_request(t2p); 120875374Sbp if (error) 120975374Sbp return error; 121075374Sbp mdp = &t2p->t2_rparam; 121175374Sbp if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 121275374Sbp if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 121375374Sbp return error; 121475374Sbp ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 121575374Sbp } 121675374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 121775374Sbp return error; 121875374Sbp ctx->f_ecnt = tw; 121975374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122075374Sbp return error; 122175374Sbp if (tw) 122275374Sbp ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 122375374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122475374Sbp return error; 122575374Sbp if ((error = md_get_uint16le(mdp, &tw)) != 0) 122675374Sbp return error; 122775374Sbp if (ctx->f_ecnt == 0) 122875374Sbp return ENOENT; 122975374Sbp ctx->f_rnameofs = tw; 123075374Sbp mdp = &t2p->t2_rdata; 123175374Sbp if (mdp->md_top == NULL) { 123275374Sbp printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 123375374Sbp return ENOENT; 123475374Sbp } 123575374Sbp if (mdp->md_top->m_len == 0) { 123675374Sbp printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 123775374Sbp return ENOENT; 123875374Sbp } 123975374Sbp ctx->f_eofs = 0; 124075374Sbp return 0; 124175374Sbp} 124275374Sbp 124375374Sbpstatic int 124475374Sbpsmbfs_smb_findclose2(struct smbfs_fctx *ctx) 124575374Sbp{ 124675374Sbp struct smb_rq rq, *rqp = &rq; 124775374Sbp struct mbchain *mbp; 124875374Sbp int error; 124975374Sbp 125075374Sbp error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 125175374Sbp if (error) 125275374Sbp return error; 125375374Sbp smb_rq_getrequest(rqp, &mbp); 125475374Sbp smb_rq_wstart(rqp); 125575374Sbp mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 125675374Sbp smb_rq_wend(rqp); 125775374Sbp smb_rq_bstart(rqp); 125875374Sbp smb_rq_bend(rqp); 125975374Sbp error = smb_rq_simple(rqp); 126075374Sbp smb_rq_done(rqp); 126175374Sbp return error; 126275374Sbp} 126375374Sbp 126475374Sbpstatic int 126575374Sbpsmbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 126675374Sbp const char *wildcard, int wclen, int attr, struct smb_cred *scred) 126775374Sbp{ 1268111119Simp ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 126975374Sbp if (ctx->f_name == NULL) 127075374Sbp return ENOMEM; 127175374Sbp ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 127275374Sbp SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 127375374Sbp ctx->f_attrmask = attr; 127475374Sbp ctx->f_wildcard = wildcard; 127575374Sbp ctx->f_wclen = wclen; 127675374Sbp return 0; 127775374Sbp} 127875374Sbp 127975374Sbpstatic int 128075374Sbpsmbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 128175374Sbp{ 128275374Sbp struct mdchain *mbp; 128375374Sbp struct smb_t2rq *t2p; 128475374Sbp char *cp; 128575374Sbp u_int8_t tb; 128675374Sbp u_int16_t date, time, wattr; 128775374Sbp u_int32_t size, next, dattr; 128875374Sbp int64_t lint; 128975374Sbp int error, svtz, cnt, fxsz, nmlen, recsz; 129075374Sbp 129175374Sbp if (ctx->f_ecnt == 0) { 129275374Sbp if (ctx->f_flags & SMBFS_RDD_EOF) 129375374Sbp return ENOENT; 129475374Sbp ctx->f_left = ctx->f_limit = limit; 129575374Sbp error = smbfs_smb_trans2find2(ctx); 129675374Sbp if (error) 129775374Sbp return error; 129875374Sbp } 129975374Sbp t2p = ctx->f_t2; 130075374Sbp mbp = &t2p->t2_rdata; 130175374Sbp svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 130275374Sbp switch (ctx->f_infolevel) { 130375374Sbp case SMB_INFO_STANDARD: 130475374Sbp next = 0; 130575374Sbp fxsz = 0; 130675374Sbp md_get_uint16le(mbp, &date); 130775374Sbp md_get_uint16le(mbp, &time); /* creation time */ 130875374Sbp md_get_uint16le(mbp, &date); 130975374Sbp md_get_uint16le(mbp, &time); /* access time */ 131075374Sbp smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 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_mtime); 131475374Sbp md_get_uint32le(mbp, &size); 131575374Sbp ctx->f_attr.fa_size = size; 131675374Sbp md_get_uint32(mbp, NULL); /* allocation size */ 131775374Sbp md_get_uint16le(mbp, &wattr); 131875374Sbp ctx->f_attr.fa_attr = wattr; 131975374Sbp md_get_uint8(mbp, &tb); 132075374Sbp size = nmlen = tb; 132175374Sbp fxsz = 23; 132275374Sbp recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 132375374Sbp break; 132475374Sbp case SMB_FIND_FILE_DIRECTORY_INFO: 132575374Sbp md_get_uint32le(mbp, &next); 132675374Sbp md_get_uint32(mbp, NULL); /* file index */ 132775374Sbp md_get_int64(mbp, NULL); /* creation time */ 132875374Sbp md_get_int64le(mbp, &lint); 132975374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 133075374Sbp md_get_int64le(mbp, &lint); 133175374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 133275374Sbp md_get_int64le(mbp, &lint); 133375374Sbp smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 133475374Sbp md_get_int64le(mbp, &lint); /* file size */ 133575374Sbp ctx->f_attr.fa_size = lint; 133675374Sbp md_get_int64(mbp, NULL); /* real size (should use) */ 133782039Sbp md_get_uint32le(mbp, &dattr); /* EA */ 133875374Sbp ctx->f_attr.fa_attr = dattr; 133975374Sbp md_get_uint32le(mbp, &size); /* name len */ 134075374Sbp fxsz = 64; 134175374Sbp recsz = next ? next : fxsz + size; 134275374Sbp break; 134375374Sbp default: 134475374Sbp SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 134575374Sbp return EINVAL; 134675374Sbp } 134775374Sbp nmlen = min(size, SMB_MAXFNAMELEN); 134875374Sbp cp = ctx->f_name; 134975374Sbp error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 135075374Sbp if (error) 135175374Sbp return error; 135275374Sbp if (next) { 135375374Sbp cnt = next - nmlen - fxsz; 135475374Sbp if (cnt > 0) 135575374Sbp md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 135675374Sbp else if (cnt < 0) { 135775374Sbp SMBERROR("out of sync\n"); 135875374Sbp return EBADRPC; 135975374Sbp } 136075374Sbp } 136175374Sbp if (nmlen && cp[nmlen - 1] == 0) 136275374Sbp nmlen--; 136375374Sbp if (nmlen == 0) 136475374Sbp return EBADRPC; 136575374Sbp 136675374Sbp next = ctx->f_eofs + recsz; 136775374Sbp if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 136875374Sbp (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 136975374Sbp /* 137075374Sbp * Server needs a resume filename. 137175374Sbp */ 137275374Sbp if (ctx->f_rnamelen <= nmlen) { 137375374Sbp if (ctx->f_rname) 137475374Sbp free(ctx->f_rname, M_SMBFSDATA); 1375111119Simp ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 137675374Sbp ctx->f_rnamelen = nmlen; 137775374Sbp } 137875374Sbp bcopy(ctx->f_name, ctx->f_rname, nmlen); 137975374Sbp ctx->f_rname[nmlen] = 0; 138075374Sbp ctx->f_flags |= SMBFS_RDD_GOTRNAME; 138175374Sbp } 138275374Sbp ctx->f_nmlen = nmlen; 138375374Sbp ctx->f_eofs = next; 138475374Sbp ctx->f_ecnt--; 138575374Sbp ctx->f_left--; 138675374Sbp return 0; 138775374Sbp} 138875374Sbp 138975374Sbpstatic int 139075374Sbpsmbfs_findcloseLM2(struct smbfs_fctx *ctx) 139175374Sbp{ 139275374Sbp if (ctx->f_name) 139375374Sbp free(ctx->f_name, M_SMBFSDATA); 139475374Sbp if (ctx->f_t2) 139575374Sbp smb_t2_done(ctx->f_t2); 139675374Sbp if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 139775374Sbp smbfs_smb_findclose2(ctx); 139875374Sbp return 0; 139975374Sbp} 140075374Sbp 140175374Sbpint 140275374Sbpsmbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 140375374Sbp struct smb_cred *scred, struct smbfs_fctx **ctxpp) 140475374Sbp{ 140575374Sbp struct smbfs_fctx *ctx; 140675374Sbp int error; 140775374Sbp 1408111119Simp ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 140975374Sbp if (ctx == NULL) 141075374Sbp return ENOMEM; 141175374Sbp bzero(ctx, sizeof(*ctx)); 141275374Sbp ctx->f_ssp = dnp->n_mount->sm_share; 141375374Sbp ctx->f_dnp = dnp; 141475374Sbp ctx->f_flags = SMBFS_RDD_FINDFIRST; 141575374Sbp ctx->f_scred = scred; 141675374Sbp if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1417138490Sphk (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 141875374Sbp ctx->f_flags |= SMBFS_RDD_USESEARCH; 141975374Sbp error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 142075374Sbp } else 142175374Sbp error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 142275374Sbp if (error) 142375374Sbp smbfs_findclose(ctx, scred); 142475374Sbp else 142575374Sbp *ctxpp = ctx; 142675374Sbp return error; 142775374Sbp} 142875374Sbp 142975374Sbpint 143075374Sbpsmbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 143175374Sbp{ 143275374Sbp int error; 143375374Sbp 143475374Sbp if (limit == 0) 143575374Sbp limit = 1000000; 143675374Sbp else if (limit > 1) 143775374Sbp limit *= 4; /* imperical */ 143875374Sbp ctx->f_scred = scred; 143975374Sbp for (;;) { 144075374Sbp if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 144175374Sbp error = smbfs_findnextLM1(ctx, limit); 144275374Sbp } else 144375374Sbp error = smbfs_findnextLM2(ctx, limit); 144475374Sbp if (error) 144575374Sbp return error; 144675374Sbp if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 144775374Sbp (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 144875374Sbp ctx->f_name[1] == '.')) 144975374Sbp continue; 145075374Sbp break; 145175374Sbp } 145275374Sbp smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen, 145375374Sbp ctx->f_dnp->n_mount->sm_caseopt); 145475374Sbp ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 145575374Sbp return 0; 145675374Sbp} 145775374Sbp 145875374Sbpint 145975374Sbpsmbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 146075374Sbp{ 146175374Sbp ctx->f_scred = scred; 146275374Sbp if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 146375374Sbp smbfs_findcloseLM1(ctx); 146475374Sbp } else 146575374Sbp smbfs_findcloseLM2(ctx); 146675374Sbp if (ctx->f_rname) 146775374Sbp free(ctx->f_rname, M_SMBFSDATA); 146875374Sbp free(ctx, M_SMBFSDATA); 146975374Sbp return 0; 147075374Sbp} 147175374Sbp 147275374Sbpint 147375374Sbpsmbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 147475374Sbp struct smbfattr *fap, struct smb_cred *scred) 147575374Sbp{ 147675374Sbp struct smbfs_fctx *ctx; 147775374Sbp int error; 147875374Sbp 147975374Sbp if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 148075374Sbp bzero(fap, sizeof(*fap)); 148175374Sbp fap->fa_attr = SMB_FA_DIR; 148275374Sbp fap->fa_ino = 2; 148375374Sbp return 0; 148475374Sbp } 148575374Sbp if (nmlen == 1 && name[0] == '.') { 148675374Sbp error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 148775374Sbp return error; 148875374Sbp } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1489107821Stjr error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1490107821Stjr scred); 149187599Sobrien printf("%s: knows NOTHING about '..'\n", __func__); 149275374Sbp return error; 149375374Sbp } 149475374Sbp error = smbfs_findopen(dnp, name, nmlen, 149575374Sbp SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 149675374Sbp if (error) 149775374Sbp return error; 149875374Sbp ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 149975374Sbp error = smbfs_findnext(ctx, 1, scred); 150075374Sbp if (error == 0) { 150175374Sbp *fap = ctx->f_attr; 150275374Sbp if (name == NULL) 150375374Sbp fap->fa_ino = dnp->n_ino; 150475374Sbp } 150575374Sbp smbfs_findclose(ctx, scred); 150675374Sbp return error; 150775374Sbp} 1508