1681a5bbeSBoris Popov /* 2681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 3. All advertising materials mentioning features or use of this software 14681a5bbeSBoris Popov * must display the following acknowledgement: 15681a5bbeSBoris Popov * This product includes software developed by Boris Popov. 16681a5bbeSBoris Popov * 4. Neither the name of the author nor the names of any co-contributors 17681a5bbeSBoris Popov * may be used to endorse or promote products derived from this software 18681a5bbeSBoris Popov * without specific prior written permission. 19681a5bbeSBoris Popov * 20681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30681a5bbeSBoris Popov * SUCH DAMAGE. 31681a5bbeSBoris Popov * 32681a5bbeSBoris Popov * $FreeBSD$ 33681a5bbeSBoris Popov */ 34681a5bbeSBoris Popov #include <sys/param.h> 35681a5bbeSBoris Popov #include <sys/systm.h> 36681a5bbeSBoris Popov #include <sys/kernel.h> 37681a5bbeSBoris Popov #include <sys/malloc.h> 38681a5bbeSBoris Popov #include <sys/proc.h> 39681a5bbeSBoris Popov #include <sys/lock.h> 40681a5bbeSBoris Popov #include <sys/vnode.h> 41681a5bbeSBoris Popov #include <sys/mbuf.h> 42681a5bbeSBoris Popov #include <sys/mount.h> 43681a5bbeSBoris Popov 44681a5bbeSBoris Popov #ifdef USE_MD5_HASH 45681a5bbeSBoris Popov #include <sys/md5.h> 46681a5bbeSBoris Popov #endif 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov #include <netsmb/smb.h> 49681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 50681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 51681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 52681a5bbeSBoris Popov 53681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 54681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 55681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 56681a5bbeSBoris Popov 57681a5bbeSBoris Popov /* 58681a5bbeSBoris Popov * Lack of inode numbers leads us to the problem of generating them. 59681a5bbeSBoris Popov * Partially this problem can be solved by having a dir/file cache 60681a5bbeSBoris Popov * with inode numbers generated from the incremented by one counter. 61681a5bbeSBoris Popov * However this way will require too much kernel memory, gives all 62681a5bbeSBoris Popov * sorts of locking and consistency problems, not to mentinon counter overflows. 63681a5bbeSBoris Popov * So, I'm decided to use a hash function to generate pseudo random (and unique) 64681a5bbeSBoris Popov * inode numbers. 65681a5bbeSBoris Popov */ 66681a5bbeSBoris Popov static long 67681a5bbeSBoris Popov smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 68681a5bbeSBoris Popov { 69681a5bbeSBoris Popov #ifdef USE_MD5_HASH 70681a5bbeSBoris Popov MD5_CTX md5; 71681a5bbeSBoris Popov u_int32_t state[4]; 72681a5bbeSBoris Popov long ino; 73681a5bbeSBoris Popov int i; 74681a5bbeSBoris Popov 75681a5bbeSBoris Popov MD5Init(&md5); 76681a5bbeSBoris Popov MD5Update(&md5, name, nmlen); 77681a5bbeSBoris Popov MD5Final((u_char *)state, &md5); 78681a5bbeSBoris Popov for (i = 0, ino = 0; i < 4; i++) 79681a5bbeSBoris Popov ino += state[i]; 80681a5bbeSBoris Popov return dnp->n_ino + ino; 81681a5bbeSBoris Popov #endif 82681a5bbeSBoris Popov u_int32_t ino; 83681a5bbeSBoris Popov 84681a5bbeSBoris Popov ino = dnp->n_ino + smbfs_hash(name, nmlen); 85681a5bbeSBoris Popov if (ino <= 2) 86681a5bbeSBoris Popov ino += 3; 87681a5bbeSBoris Popov return ino; 88681a5bbeSBoris Popov } 89681a5bbeSBoris Popov 90681a5bbeSBoris Popov static int 91681a5bbeSBoris Popov smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, 92681a5bbeSBoris Popov struct smb_cred *scred) 93681a5bbeSBoris Popov { 94681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 95681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 96681a5bbeSBoris Popov struct mbchain *mbp; 97681a5bbeSBoris Popov u_char ltype = 0; 98681a5bbeSBoris Popov int error; 99681a5bbeSBoris Popov 100681a5bbeSBoris Popov if (op == SMB_LOCK_SHARED) 101681a5bbeSBoris Popov ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 102681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred); 103681a5bbeSBoris Popov if (error) 104681a5bbeSBoris Popov return error; 105681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 106681a5bbeSBoris Popov smb_rq_wstart(rqp); 107681a5bbeSBoris Popov mb_put_uint8(mbp, 0xff); /* secondary command */ 108681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* MBZ */ 109681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 110681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 111681a5bbeSBoris Popov mb_put_uint8(mbp, ltype); /* locktype */ 112681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 113681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 114681a5bbeSBoris Popov mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 115681a5bbeSBoris Popov mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 116681a5bbeSBoris Popov smb_rq_wend(rqp); 117681a5bbeSBoris Popov smb_rq_bstart(rqp); 118681a5bbeSBoris Popov mb_put_uint16le(mbp, pid); 119681a5bbeSBoris Popov mb_put_uint32le(mbp, start); 120681a5bbeSBoris Popov mb_put_uint32le(mbp, end - start); 121681a5bbeSBoris Popov smb_rq_bend(rqp); 122681a5bbeSBoris Popov error = smb_rq_simple(rqp); 123681a5bbeSBoris Popov smb_rq_done(rqp); 124681a5bbeSBoris Popov return error; 125681a5bbeSBoris Popov } 126681a5bbeSBoris Popov 127681a5bbeSBoris Popov int 128681a5bbeSBoris Popov smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 129681a5bbeSBoris Popov off_t start, off_t end, struct smb_cred *scred) 130681a5bbeSBoris Popov { 131681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 132681a5bbeSBoris Popov 133681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 134681a5bbeSBoris Popov /* 135681a5bbeSBoris Popov * TODO: use LOCK_BYTE_RANGE here. 136681a5bbeSBoris Popov */ 137681a5bbeSBoris Popov return EINVAL; 138681a5bbeSBoris Popov else 139681a5bbeSBoris Popov return smbfs_smb_lockandx(np, op, (u_int32_t)id, start, end, scred); 140681a5bbeSBoris Popov } 141681a5bbeSBoris Popov 142681a5bbeSBoris Popov int 143681a5bbeSBoris Popov smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp, 144681a5bbeSBoris Popov struct smb_cred *scred) 145681a5bbeSBoris Popov { 146681a5bbeSBoris Popov struct smb_t2rq *t2p; 147681a5bbeSBoris Popov struct mbchain *mbp; 148681a5bbeSBoris Popov struct mdchain *mdp; 149681a5bbeSBoris Popov u_int16_t bsize; 150681a5bbeSBoris Popov u_int32_t units, bpu, funits; 151681a5bbeSBoris Popov int error; 152681a5bbeSBoris Popov 153681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 154681a5bbeSBoris Popov scred, &t2p); 155681a5bbeSBoris Popov if (error) 156681a5bbeSBoris Popov return error; 157681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 158681a5bbeSBoris Popov mb_init(mbp); 159681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 160681a5bbeSBoris Popov t2p->t2_maxpcount = 4; 161681a5bbeSBoris Popov t2p->t2_maxdcount = 4 * 4 + 2; 162681a5bbeSBoris Popov error = smb_t2_request(t2p); 163681a5bbeSBoris Popov if (error) { 164681a5bbeSBoris Popov smb_t2_done(t2p); 165681a5bbeSBoris Popov return error; 166681a5bbeSBoris Popov } 167681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 168681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* fs id */ 169681a5bbeSBoris Popov md_get_uint32le(mdp, &bpu); 170681a5bbeSBoris Popov md_get_uint32le(mdp, &units); 171681a5bbeSBoris Popov md_get_uint32le(mdp, &funits); 172681a5bbeSBoris Popov md_get_uint16le(mdp, &bsize); 173681a5bbeSBoris Popov sbp->f_bsize = bpu * bsize; /* fundamental file system block size */ 174681a5bbeSBoris Popov sbp->f_blocks= units; /* total data blocks in file system */ 175681a5bbeSBoris Popov sbp->f_bfree = funits; /* free blocks in fs */ 176681a5bbeSBoris Popov sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 177681a5bbeSBoris Popov sbp->f_files = 0xffff; /* total file nodes in file system */ 178681a5bbeSBoris Popov sbp->f_ffree = 0xffff; /* free file nodes in fs */ 179681a5bbeSBoris Popov smb_t2_done(t2p); 180681a5bbeSBoris Popov return 0; 181681a5bbeSBoris Popov } 182681a5bbeSBoris Popov 183681a5bbeSBoris Popov int 184681a5bbeSBoris Popov smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, 185681a5bbeSBoris Popov struct smb_cred *scred) 186681a5bbeSBoris Popov { 187681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 188681a5bbeSBoris Popov struct mdchain *mdp; 189681a5bbeSBoris Popov u_int16_t units, bpu, bsize, funits; 190681a5bbeSBoris Popov int error; 191681a5bbeSBoris Popov 192681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); 193681a5bbeSBoris Popov if (error) 194681a5bbeSBoris Popov return error; 195681a5bbeSBoris Popov smb_rq_wstart(rqp); 196681a5bbeSBoris Popov smb_rq_wend(rqp); 197681a5bbeSBoris Popov smb_rq_bstart(rqp); 198681a5bbeSBoris Popov smb_rq_bend(rqp); 199681a5bbeSBoris Popov error = smb_rq_simple(rqp); 200681a5bbeSBoris Popov if (error) { 201681a5bbeSBoris Popov smb_rq_done(rqp); 202681a5bbeSBoris Popov return error; 203681a5bbeSBoris Popov } 204681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 205681a5bbeSBoris Popov md_get_uint16le(mdp, &units); 206681a5bbeSBoris Popov md_get_uint16le(mdp, &bpu); 207681a5bbeSBoris Popov md_get_uint16le(mdp, &bsize); 208681a5bbeSBoris Popov md_get_uint16le(mdp, &funits); 209681a5bbeSBoris Popov sbp->f_bsize = bpu * bsize; /* fundamental file system block size */ 210681a5bbeSBoris Popov sbp->f_blocks= units; /* total data blocks in file system */ 211681a5bbeSBoris Popov sbp->f_bfree = funits; /* free blocks in fs */ 212681a5bbeSBoris Popov sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 213681a5bbeSBoris Popov sbp->f_files = 0xffff; /* total file nodes in file system */ 214681a5bbeSBoris Popov sbp->f_ffree = 0xffff; /* free file nodes in fs */ 215681a5bbeSBoris Popov smb_rq_done(rqp); 216681a5bbeSBoris Popov return 0; 217681a5bbeSBoris Popov } 218681a5bbeSBoris Popov 219681a5bbeSBoris Popov int 220681a5bbeSBoris Popov smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 221681a5bbeSBoris Popov { 222681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 223681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 224681a5bbeSBoris Popov struct mbchain *mbp; 225681a5bbeSBoris Popov int error; 226681a5bbeSBoris Popov 227681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); 228681a5bbeSBoris Popov if (error) 229681a5bbeSBoris Popov return error; 230681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 231681a5bbeSBoris Popov smb_rq_wstart(rqp); 232681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 233681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 234681a5bbeSBoris Popov mb_put_uint32le(mbp, newsize); 235681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 236681a5bbeSBoris Popov smb_rq_wend(rqp); 237681a5bbeSBoris Popov smb_rq_bstart(rqp); 238681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_DATA); 239681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 240681a5bbeSBoris Popov smb_rq_bend(rqp); 241681a5bbeSBoris Popov error = smb_rq_simple(rqp); 242681a5bbeSBoris Popov smb_rq_done(rqp); 243681a5bbeSBoris Popov return error; 244681a5bbeSBoris Popov } 245681a5bbeSBoris Popov 246681a5bbeSBoris Popov 247681a5bbeSBoris Popov /* 248681a5bbeSBoris Popov * Set DOS file attributes. mtime should be NULL for dialects above lm10 249681a5bbeSBoris Popov */ 250681a5bbeSBoris Popov int 251681a5bbeSBoris Popov smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 252681a5bbeSBoris Popov struct smb_cred *scred) 253681a5bbeSBoris Popov { 254681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 255681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 256681a5bbeSBoris Popov struct mbchain *mbp; 257681a5bbeSBoris Popov u_long time; 258681a5bbeSBoris Popov int error, svtz; 259681a5bbeSBoris Popov 260681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); 261681a5bbeSBoris Popov if (error) 262681a5bbeSBoris Popov return error; 263681a5bbeSBoris Popov svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 264681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 265681a5bbeSBoris Popov smb_rq_wstart(rqp); 266681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); 267681a5bbeSBoris Popov if (mtime) { 268681a5bbeSBoris Popov smb_time_local2server(mtime, svtz, &time); 269681a5bbeSBoris Popov } else 270681a5bbeSBoris Popov time = 0; 271681a5bbeSBoris Popov mb_put_uint32le(mbp, time); /* mtime */ 272681a5bbeSBoris Popov mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 273681a5bbeSBoris Popov smb_rq_wend(rqp); 274681a5bbeSBoris Popov smb_rq_bstart(rqp); 275681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 276681a5bbeSBoris Popov do { 277681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 278681a5bbeSBoris Popov if (error) 279681a5bbeSBoris Popov break; 280681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 281681a5bbeSBoris Popov mb_put_uint8(mbp, 0); 282681a5bbeSBoris Popov smb_rq_bend(rqp); 283681a5bbeSBoris Popov error = smb_rq_simple(rqp); 284681a5bbeSBoris Popov SMBERROR("%d\n", error); 285681a5bbeSBoris Popov if (error) 286681a5bbeSBoris Popov break; 287681a5bbeSBoris Popov } while(0); 288681a5bbeSBoris Popov smb_rq_done(rqp); 289681a5bbeSBoris Popov return error; 290681a5bbeSBoris Popov } 291681a5bbeSBoris Popov 292681a5bbeSBoris Popov /* 293681a5bbeSBoris Popov * Note, win95 doesn't support this call. 294681a5bbeSBoris Popov */ 295681a5bbeSBoris Popov int 296681a5bbeSBoris Popov smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 297681a5bbeSBoris Popov struct timespec *atime, int attr, struct smb_cred *scred) 298681a5bbeSBoris Popov { 299681a5bbeSBoris Popov struct smb_t2rq *t2p; 300681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 301681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 302681a5bbeSBoris Popov struct mbchain *mbp; 303681a5bbeSBoris Popov u_int16_t date, time; 304681a5bbeSBoris Popov int error, tzoff; 305681a5bbeSBoris Popov 306681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 307681a5bbeSBoris Popov scred, &t2p); 308681a5bbeSBoris Popov if (error) 309681a5bbeSBoris Popov return error; 310681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 311681a5bbeSBoris Popov mb_init(mbp); 312681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_INFO_STANDARD); 313681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* MBZ */ 314681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 315681a5bbeSBoris Popov if (error) { 316681a5bbeSBoris Popov smb_t2_done(t2p); 317681a5bbeSBoris Popov return error; 318681a5bbeSBoris Popov } 319681a5bbeSBoris Popov tzoff = vcp->vc_sopt.sv_tz; 320681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 321681a5bbeSBoris Popov mb_init(mbp); 322681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* creation time */ 323681a5bbeSBoris Popov if (atime) 324681a5bbeSBoris Popov smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 325681a5bbeSBoris Popov else 326681a5bbeSBoris Popov time = date = 0; 327681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 328681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 329681a5bbeSBoris Popov if (mtime) 330681a5bbeSBoris Popov smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 331681a5bbeSBoris Popov else 332681a5bbeSBoris Popov time = date = 0; 333681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 334681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 335681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* file size */ 336681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* allocation unit size */ 337681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); /* DOS attr */ 338681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* EA size */ 339681a5bbeSBoris Popov t2p->t2_maxpcount = 5 * 2; 340681a5bbeSBoris Popov t2p->t2_maxdcount = vcp->vc_txmax; 341681a5bbeSBoris Popov error = smb_t2_request(t2p); 342681a5bbeSBoris Popov smb_t2_done(t2p); 343681a5bbeSBoris Popov return error; 344681a5bbeSBoris Popov } 345681a5bbeSBoris Popov 346681a5bbeSBoris Popov /* 347681a5bbeSBoris Popov * NT level. Specially for win9x 348681a5bbeSBoris Popov */ 349681a5bbeSBoris Popov int 350681a5bbeSBoris Popov smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 351681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 352681a5bbeSBoris Popov { 353681a5bbeSBoris Popov struct smb_t2rq *t2p; 354681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 355681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 356681a5bbeSBoris Popov struct mbchain *mbp; 357681a5bbeSBoris Popov int64_t tm; 358681a5bbeSBoris Popov int error, tzoff; 359681a5bbeSBoris Popov 360681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 361681a5bbeSBoris Popov scred, &t2p); 362681a5bbeSBoris Popov if (error) 363681a5bbeSBoris Popov return error; 364681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 365681a5bbeSBoris Popov mb_init(mbp); 366681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 367681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* MBZ */ 368681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 369681a5bbeSBoris Popov if (error) { 370681a5bbeSBoris Popov smb_t2_done(t2p); 371681a5bbeSBoris Popov return error; 372681a5bbeSBoris Popov } 373681a5bbeSBoris Popov tzoff = vcp->vc_sopt.sv_tz; 374681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 375681a5bbeSBoris Popov mb_init(mbp); 376681a5bbeSBoris Popov mb_put_int64le(mbp, 0); /* creation time */ 377681a5bbeSBoris Popov if (atime) { 378681a5bbeSBoris Popov smb_time_local2NT(atime, tzoff, &tm); 379681a5bbeSBoris Popov } else 380681a5bbeSBoris Popov tm = 0; 381681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 382681a5bbeSBoris Popov if (mtime) { 383681a5bbeSBoris Popov smb_time_local2NT(mtime, tzoff, &tm); 384681a5bbeSBoris Popov } else 385681a5bbeSBoris Popov tm = 0; 386681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 387681a5bbeSBoris Popov mb_put_int64le(mbp, tm); /* change time */ 388681a5bbeSBoris Popov mb_put_uint32le(mbp, attr); /* attr */ 389681a5bbeSBoris Popov t2p->t2_maxpcount = 24; 390681a5bbeSBoris Popov t2p->t2_maxdcount = 56; 391681a5bbeSBoris Popov error = smb_t2_request(t2p); 392681a5bbeSBoris Popov smb_t2_done(t2p); 393681a5bbeSBoris Popov return error; 394681a5bbeSBoris Popov } 395681a5bbeSBoris Popov 396681a5bbeSBoris Popov /* 397681a5bbeSBoris Popov * Set file atime and mtime. Doesn't supported by core dialect. 398681a5bbeSBoris Popov */ 399681a5bbeSBoris Popov int 400681a5bbeSBoris Popov smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 401681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 402681a5bbeSBoris Popov { 403681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 404681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 405681a5bbeSBoris Popov struct mbchain *mbp; 406681a5bbeSBoris Popov u_int16_t date, time; 407681a5bbeSBoris Popov int error, tzoff; 408681a5bbeSBoris Popov 409681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 410681a5bbeSBoris Popov if (error) 411681a5bbeSBoris Popov return error; 412681a5bbeSBoris Popov tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 413681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 414681a5bbeSBoris Popov smb_rq_wstart(rqp); 415681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 416681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* creation time */ 417681a5bbeSBoris Popov 418681a5bbeSBoris Popov if (atime) 419681a5bbeSBoris Popov smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 420681a5bbeSBoris Popov else 421681a5bbeSBoris Popov time = date = 0; 422681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 423681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 424681a5bbeSBoris Popov if (mtime) 425681a5bbeSBoris Popov smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 426681a5bbeSBoris Popov else 427681a5bbeSBoris Popov time = date = 0; 428681a5bbeSBoris Popov mb_put_uint16le(mbp, date); 429681a5bbeSBoris Popov mb_put_uint16le(mbp, time); 430681a5bbeSBoris Popov smb_rq_wend(rqp); 431681a5bbeSBoris Popov smb_rq_bstart(rqp); 432681a5bbeSBoris Popov smb_rq_bend(rqp); 433681a5bbeSBoris Popov error = smb_rq_simple(rqp); 434681a5bbeSBoris Popov SMBSDEBUG("%d\n", error); 435681a5bbeSBoris Popov smb_rq_done(rqp); 436681a5bbeSBoris Popov return error; 437681a5bbeSBoris Popov } 438681a5bbeSBoris Popov 439681a5bbeSBoris Popov /* 440681a5bbeSBoris Popov * Set DOS file attributes. 441681a5bbeSBoris Popov * Looks like this call can be used only if CAP_NT_SMBS bit is on. 442681a5bbeSBoris Popov */ 443681a5bbeSBoris Popov int 444681a5bbeSBoris Popov smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 445681a5bbeSBoris Popov struct timespec *atime, struct smb_cred *scred) 446681a5bbeSBoris Popov { 447681a5bbeSBoris Popov struct smb_t2rq *t2p; 448681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 449681a5bbeSBoris Popov struct mbchain *mbp; 450681a5bbeSBoris Popov int64_t tm; 451681a5bbeSBoris Popov int error, svtz; 452681a5bbeSBoris Popov 453681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 454681a5bbeSBoris Popov scred, &t2p); 455681a5bbeSBoris Popov if (error) 456681a5bbeSBoris Popov return error; 457681a5bbeSBoris Popov svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 458681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 459681a5bbeSBoris Popov mb_init(mbp); 460681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 461681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 462681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); 463681a5bbeSBoris Popov mbp = &t2p->t2_tdata; 464681a5bbeSBoris Popov mb_init(mbp); 465681a5bbeSBoris Popov mb_put_int64le(mbp, 0); /* creation time */ 466681a5bbeSBoris Popov if (atime) { 467681a5bbeSBoris Popov smb_time_local2NT(atime, svtz, &tm); 468681a5bbeSBoris Popov } else 469681a5bbeSBoris Popov tm = 0; 470681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 471681a5bbeSBoris Popov if (mtime) { 472681a5bbeSBoris Popov smb_time_local2NT(mtime, svtz, &tm); 473681a5bbeSBoris Popov } else 474681a5bbeSBoris Popov tm = 0; 475681a5bbeSBoris Popov mb_put_int64le(mbp, tm); 476681a5bbeSBoris Popov mb_put_int64le(mbp, tm); /* change time */ 477681a5bbeSBoris Popov mb_put_uint16le(mbp, attr); 478681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* padding */ 479681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); 480681a5bbeSBoris Popov t2p->t2_maxpcount = 2; 481681a5bbeSBoris Popov t2p->t2_maxdcount = 0; 482681a5bbeSBoris Popov error = smb_t2_request(t2p); 483681a5bbeSBoris Popov smb_t2_done(t2p); 484681a5bbeSBoris Popov return error; 485681a5bbeSBoris Popov } 486681a5bbeSBoris Popov 487681a5bbeSBoris Popov 488681a5bbeSBoris Popov int 489681a5bbeSBoris Popov smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 490681a5bbeSBoris Popov { 491681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 492681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 493681a5bbeSBoris Popov struct mbchain *mbp; 494681a5bbeSBoris Popov struct mdchain *mdp; 495681a5bbeSBoris Popov u_int8_t wc; 496681a5bbeSBoris Popov u_int16_t fid, wattr, grantedmode; 497681a5bbeSBoris Popov int error; 498681a5bbeSBoris Popov 499681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 500681a5bbeSBoris Popov if (error) 501681a5bbeSBoris Popov return error; 502681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 503681a5bbeSBoris Popov smb_rq_wstart(rqp); 504681a5bbeSBoris Popov mb_put_uint16le(mbp, accmode); 505681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 506681a5bbeSBoris Popov smb_rq_wend(rqp); 507681a5bbeSBoris Popov smb_rq_bstart(rqp); 508681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 509681a5bbeSBoris Popov do { 510681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 511681a5bbeSBoris Popov if (error) 512681a5bbeSBoris Popov break; 513681a5bbeSBoris Popov smb_rq_bend(rqp); 514681a5bbeSBoris Popov error = smb_rq_simple(rqp); 515681a5bbeSBoris Popov if (error) 516681a5bbeSBoris Popov break; 517681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 518681a5bbeSBoris Popov if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 519681a5bbeSBoris Popov error = EBADRPC; 520681a5bbeSBoris Popov break; 521681a5bbeSBoris Popov } 522681a5bbeSBoris Popov md_get_uint16(mdp, &fid); 523681a5bbeSBoris Popov md_get_uint16le(mdp, &wattr); 524681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* mtime */ 525681a5bbeSBoris Popov md_get_uint32(mdp, NULL); /* fsize */ 526681a5bbeSBoris Popov md_get_uint16le(mdp, &grantedmode); 527681a5bbeSBoris Popov /* 528681a5bbeSBoris Popov * TODO: refresh attributes from this reply 529681a5bbeSBoris Popov */ 530681a5bbeSBoris Popov } while(0); 531681a5bbeSBoris Popov smb_rq_done(rqp); 532681a5bbeSBoris Popov if (error) 533681a5bbeSBoris Popov return error; 534681a5bbeSBoris Popov np->n_fid = fid; 535681a5bbeSBoris Popov np->n_rwstate = grantedmode; 536681a5bbeSBoris Popov return 0; 537681a5bbeSBoris Popov } 538681a5bbeSBoris Popov 539681a5bbeSBoris Popov 540681a5bbeSBoris Popov int 541681a5bbeSBoris Popov smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 542681a5bbeSBoris Popov struct smb_cred *scred) 543681a5bbeSBoris Popov { 544681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 545681a5bbeSBoris Popov struct mbchain *mbp; 546681a5bbeSBoris Popov u_long time; 547681a5bbeSBoris Popov int error; 548681a5bbeSBoris Popov 549681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 550681a5bbeSBoris Popov if (error) 551681a5bbeSBoris Popov return error; 552681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 553681a5bbeSBoris Popov smb_rq_wstart(rqp); 554681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 555681a5bbeSBoris Popov if (mtime) { 556681a5bbeSBoris Popov smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 557681a5bbeSBoris Popov } else 558681a5bbeSBoris Popov time = 0; 559681a5bbeSBoris Popov mb_put_uint32le(mbp, time); 560681a5bbeSBoris Popov smb_rq_wend(rqp); 561681a5bbeSBoris Popov smb_rq_bstart(rqp); 562681a5bbeSBoris Popov smb_rq_bend(rqp); 563681a5bbeSBoris Popov error = smb_rq_simple(rqp); 564681a5bbeSBoris Popov smb_rq_done(rqp); 565681a5bbeSBoris Popov return error; 566681a5bbeSBoris Popov } 567681a5bbeSBoris Popov 568681a5bbeSBoris Popov int 569681a5bbeSBoris Popov smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 570681a5bbeSBoris Popov struct smb_cred *scred) 571681a5bbeSBoris Popov { 572681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 573681a5bbeSBoris Popov struct smb_share *ssp = dnp->n_mount->sm_share; 574681a5bbeSBoris Popov struct mbchain *mbp; 575681a5bbeSBoris Popov struct mdchain *mdp; 576681a5bbeSBoris Popov struct timespec ctime; 577681a5bbeSBoris Popov u_int8_t wc; 578681a5bbeSBoris Popov u_int16_t fid; 579681a5bbeSBoris Popov u_long tm; 580681a5bbeSBoris Popov int error; 581681a5bbeSBoris Popov 582681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 583681a5bbeSBoris Popov if (error) 584681a5bbeSBoris Popov return error; 585681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 586681a5bbeSBoris Popov smb_rq_wstart(rqp); 587681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 588681a5bbeSBoris Popov nanotime(&ctime); 589681a5bbeSBoris Popov smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 590681a5bbeSBoris Popov mb_put_uint32le(mbp, tm); 591681a5bbeSBoris Popov smb_rq_wend(rqp); 592681a5bbeSBoris Popov smb_rq_bstart(rqp); 593681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 594681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 595681a5bbeSBoris Popov if (!error) { 596681a5bbeSBoris Popov smb_rq_bend(rqp); 597681a5bbeSBoris Popov error = smb_rq_simple(rqp); 598681a5bbeSBoris Popov if (!error) { 599681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 600681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 601681a5bbeSBoris Popov if (wc == 1) 602681a5bbeSBoris Popov md_get_uint16(mdp, &fid); 603681a5bbeSBoris Popov else 604681a5bbeSBoris Popov error = EBADRPC; 605681a5bbeSBoris Popov } 606681a5bbeSBoris Popov } 607681a5bbeSBoris Popov smb_rq_done(rqp); 608681a5bbeSBoris Popov if (error) 609681a5bbeSBoris Popov return error; 610681a5bbeSBoris Popov smbfs_smb_close(ssp, fid, &ctime, scred); 611681a5bbeSBoris Popov return error; 612681a5bbeSBoris Popov } 613681a5bbeSBoris Popov 614681a5bbeSBoris Popov int 615681a5bbeSBoris Popov smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 616681a5bbeSBoris Popov { 617681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 618681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 619681a5bbeSBoris Popov struct mbchain *mbp; 620681a5bbeSBoris Popov int error; 621681a5bbeSBoris Popov 622681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 623681a5bbeSBoris Popov if (error) 624681a5bbeSBoris Popov return error; 625681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 626681a5bbeSBoris Popov smb_rq_wstart(rqp); 627681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 628681a5bbeSBoris Popov smb_rq_wend(rqp); 629681a5bbeSBoris Popov smb_rq_bstart(rqp); 630681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 631681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 632681a5bbeSBoris Popov if (!error) { 633681a5bbeSBoris Popov smb_rq_bend(rqp); 634681a5bbeSBoris Popov error = smb_rq_simple(rqp); 635681a5bbeSBoris Popov } 636681a5bbeSBoris Popov smb_rq_done(rqp); 637681a5bbeSBoris Popov return error; 638681a5bbeSBoris Popov } 639681a5bbeSBoris Popov 640681a5bbeSBoris Popov int 641681a5bbeSBoris Popov smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 642681a5bbeSBoris Popov const char *tname, int tnmlen, struct smb_cred *scred) 643681a5bbeSBoris Popov { 644681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 645681a5bbeSBoris Popov struct smb_share *ssp = src->n_mount->sm_share; 646681a5bbeSBoris Popov struct mbchain *mbp; 647681a5bbeSBoris Popov int error; 648681a5bbeSBoris Popov 649681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 650681a5bbeSBoris Popov if (error) 651681a5bbeSBoris Popov return error; 652681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 653681a5bbeSBoris Popov smb_rq_wstart(rqp); 654681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 655681a5bbeSBoris Popov smb_rq_wend(rqp); 656681a5bbeSBoris Popov smb_rq_bstart(rqp); 657681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 658681a5bbeSBoris Popov do { 659681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 660681a5bbeSBoris Popov if (error) 661681a5bbeSBoris Popov break; 662681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 663681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 664681a5bbeSBoris Popov if (error) 665681a5bbeSBoris Popov break; 666681a5bbeSBoris Popov smb_rq_bend(rqp); 667681a5bbeSBoris Popov error = smb_rq_simple(rqp); 668681a5bbeSBoris Popov } while(0); 669681a5bbeSBoris Popov smb_rq_done(rqp); 670681a5bbeSBoris Popov return error; 671681a5bbeSBoris Popov } 672681a5bbeSBoris Popov 673681a5bbeSBoris Popov int 674681a5bbeSBoris Popov smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 675681a5bbeSBoris Popov const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 676681a5bbeSBoris Popov { 677681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 678681a5bbeSBoris Popov struct smb_share *ssp = src->n_mount->sm_share; 679681a5bbeSBoris Popov struct mbchain *mbp; 680681a5bbeSBoris Popov int error; 681681a5bbeSBoris Popov 682681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 683681a5bbeSBoris Popov if (error) 684681a5bbeSBoris Popov return error; 685681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 686681a5bbeSBoris Popov smb_rq_wstart(rqp); 687681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 688681a5bbeSBoris Popov mb_put_uint16le(mbp, 0x20); /* delete target file */ 689681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 690681a5bbeSBoris Popov smb_rq_wend(rqp); 691681a5bbeSBoris Popov smb_rq_bstart(rqp); 692681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 693681a5bbeSBoris Popov do { 694681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 695681a5bbeSBoris Popov if (error) 696681a5bbeSBoris Popov break; 697681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 698681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 699681a5bbeSBoris Popov if (error) 700681a5bbeSBoris Popov break; 701681a5bbeSBoris Popov smb_rq_bend(rqp); 702681a5bbeSBoris Popov error = smb_rq_simple(rqp); 703681a5bbeSBoris Popov } while(0); 704681a5bbeSBoris Popov smb_rq_done(rqp); 705681a5bbeSBoris Popov return error; 706681a5bbeSBoris Popov } 707681a5bbeSBoris Popov 708681a5bbeSBoris Popov int 709681a5bbeSBoris Popov smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 710681a5bbeSBoris Popov struct smb_cred *scred) 711681a5bbeSBoris Popov { 712681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 713681a5bbeSBoris Popov struct smb_share *ssp = dnp->n_mount->sm_share; 714681a5bbeSBoris Popov struct mbchain *mbp; 715681a5bbeSBoris Popov int error; 716681a5bbeSBoris Popov 717681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 718681a5bbeSBoris Popov if (error) 719681a5bbeSBoris Popov return error; 720681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 721681a5bbeSBoris Popov smb_rq_wstart(rqp); 722681a5bbeSBoris Popov smb_rq_wend(rqp); 723681a5bbeSBoris Popov smb_rq_bstart(rqp); 724681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 725681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 726681a5bbeSBoris Popov if (!error) { 727681a5bbeSBoris Popov smb_rq_bend(rqp); 728681a5bbeSBoris Popov error = smb_rq_simple(rqp); 729681a5bbeSBoris Popov } 730681a5bbeSBoris Popov smb_rq_done(rqp); 731681a5bbeSBoris Popov return error; 732681a5bbeSBoris Popov } 733681a5bbeSBoris Popov 734681a5bbeSBoris Popov int 735681a5bbeSBoris Popov smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 736681a5bbeSBoris Popov { 737681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 738681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 739681a5bbeSBoris Popov struct mbchain *mbp; 740681a5bbeSBoris Popov int error; 741681a5bbeSBoris Popov 742681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 743681a5bbeSBoris Popov if (error) 744681a5bbeSBoris Popov return error; 745681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 746681a5bbeSBoris Popov smb_rq_wstart(rqp); 747681a5bbeSBoris Popov smb_rq_wend(rqp); 748681a5bbeSBoris Popov smb_rq_bstart(rqp); 749681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); 750681a5bbeSBoris Popov error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 751681a5bbeSBoris Popov if (!error) { 752681a5bbeSBoris Popov smb_rq_bend(rqp); 753681a5bbeSBoris Popov error = smb_rq_simple(rqp); 754681a5bbeSBoris Popov } 755681a5bbeSBoris Popov smb_rq_done(rqp); 756681a5bbeSBoris Popov return error; 757681a5bbeSBoris Popov } 758681a5bbeSBoris Popov 759681a5bbeSBoris Popov static int 760681a5bbeSBoris Popov smbfs_smb_search(struct smbfs_fctx *ctx) 761681a5bbeSBoris Popov { 762681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 763681a5bbeSBoris Popov struct smb_rq *rqp; 764681a5bbeSBoris Popov struct mbchain *mbp; 765681a5bbeSBoris Popov struct mdchain *mdp; 766681a5bbeSBoris Popov u_int8_t wc, bt; 767681a5bbeSBoris Popov u_int16_t ec, dlen, bc; 768681a5bbeSBoris Popov int maxent, error, iseof = 0; 769681a5bbeSBoris Popov 770681a5bbeSBoris Popov maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 771681a5bbeSBoris Popov if (ctx->f_rq) { 772681a5bbeSBoris Popov smb_rq_done(ctx->f_rq); 773681a5bbeSBoris Popov ctx->f_rq = NULL; 774681a5bbeSBoris Popov } 775681a5bbeSBoris Popov error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 776681a5bbeSBoris Popov if (error) 777681a5bbeSBoris Popov return error; 778681a5bbeSBoris Popov ctx->f_rq = rqp; 779681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 780681a5bbeSBoris Popov smb_rq_wstart(rqp); 781681a5bbeSBoris Popov mb_put_uint16le(mbp, maxent); /* max entries to return */ 782681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_attrmask); 783681a5bbeSBoris Popov smb_rq_wend(rqp); 784681a5bbeSBoris Popov smb_rq_bstart(rqp); 785681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 786681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 787681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 788681a5bbeSBoris Popov if (error) 789681a5bbeSBoris Popov return error; 790681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_VARIABLE); 791681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); /* context length */ 792681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 793681a5bbeSBoris Popov } else { 794681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* file name length */ 795681a5bbeSBoris Popov mb_put_uint8(mbp, SMB_DT_VARIABLE); 796681a5bbeSBoris Popov mb_put_uint16le(mbp, SMB_SKEYLEN); 797681a5bbeSBoris Popov mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 798681a5bbeSBoris Popov } 799681a5bbeSBoris Popov smb_rq_bend(rqp); 800681a5bbeSBoris Popov error = smb_rq_simple(rqp); 801681a5bbeSBoris Popov if (error) { 802681a5bbeSBoris Popov if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 803681a5bbeSBoris Popov error = 0; 804681a5bbeSBoris Popov iseof = 1; 805681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_EOF; 806681a5bbeSBoris Popov } else 807681a5bbeSBoris Popov return error; 808681a5bbeSBoris Popov } 809681a5bbeSBoris Popov smb_rq_getreply(rqp, &mdp); 810681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 811681a5bbeSBoris Popov if (wc != 1) 812681a5bbeSBoris Popov return iseof ? ENOENT : EBADRPC; 813681a5bbeSBoris Popov md_get_uint16le(mdp, &ec); 814681a5bbeSBoris Popov if (ec == 0) 815681a5bbeSBoris Popov return ENOENT; 816681a5bbeSBoris Popov ctx->f_ecnt = ec; 817681a5bbeSBoris Popov md_get_uint16le(mdp, &bc); 818681a5bbeSBoris Popov if (bc < 3) 819681a5bbeSBoris Popov return EBADRPC; 820681a5bbeSBoris Popov bc -= 3; 821681a5bbeSBoris Popov md_get_uint8(mdp, &bt); 822681a5bbeSBoris Popov if (bt != SMB_DT_VARIABLE) 823681a5bbeSBoris Popov return EBADRPC; 824681a5bbeSBoris Popov md_get_uint16le(mdp, &dlen); 825681a5bbeSBoris Popov if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 826681a5bbeSBoris Popov return EBADRPC; 827681a5bbeSBoris Popov return 0; 828681a5bbeSBoris Popov } 829681a5bbeSBoris Popov 830681a5bbeSBoris Popov static int 831681a5bbeSBoris Popov smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 832681a5bbeSBoris Popov const char *wildcard, int wclen, int attr, struct smb_cred *scred) 833681a5bbeSBoris Popov { 834681a5bbeSBoris Popov ctx->f_attrmask = attr; 835681a5bbeSBoris Popov if (wildcard) { 836681a5bbeSBoris Popov if (wclen == 1 && wildcard[0] == '*') { 837681a5bbeSBoris Popov ctx->f_wildcard = "*.*"; 838681a5bbeSBoris Popov ctx->f_wclen = 3; 839681a5bbeSBoris Popov } else { 840681a5bbeSBoris Popov ctx->f_wildcard = wildcard; 841681a5bbeSBoris Popov ctx->f_wclen = wclen; 842681a5bbeSBoris Popov } 843681a5bbeSBoris Popov } else { 844681a5bbeSBoris Popov ctx->f_wildcard = NULL; 845681a5bbeSBoris Popov ctx->f_wclen = 0; 846681a5bbeSBoris Popov } 847681a5bbeSBoris Popov ctx->f_name = ctx->f_fname; 848681a5bbeSBoris Popov return 0; 849681a5bbeSBoris Popov } 850681a5bbeSBoris Popov 851681a5bbeSBoris Popov static int 852681a5bbeSBoris Popov smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 853681a5bbeSBoris Popov { 854681a5bbeSBoris Popov struct mdchain *mbp; 855681a5bbeSBoris Popov struct smb_rq *rqp; 856681a5bbeSBoris Popov char *cp; 857681a5bbeSBoris Popov u_int8_t battr; 858681a5bbeSBoris Popov u_int16_t date, time; 859681a5bbeSBoris Popov u_int32_t size; 860681a5bbeSBoris Popov int error; 861681a5bbeSBoris Popov 862681a5bbeSBoris Popov if (ctx->f_ecnt == 0) { 863681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_EOF) 864681a5bbeSBoris Popov return ENOENT; 865681a5bbeSBoris Popov ctx->f_left = ctx->f_limit = limit; 866681a5bbeSBoris Popov error = smbfs_smb_search(ctx); 867681a5bbeSBoris Popov if (error) 868681a5bbeSBoris Popov return error; 869681a5bbeSBoris Popov } 870681a5bbeSBoris Popov rqp = ctx->f_rq; 871681a5bbeSBoris Popov smb_rq_getreply(rqp, &mbp); 872681a5bbeSBoris Popov md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 873681a5bbeSBoris Popov md_get_uint8(mbp, &battr); 874681a5bbeSBoris Popov md_get_uint16le(mbp, &time); 875681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 876681a5bbeSBoris Popov md_get_uint32le(mbp, &size); 877681a5bbeSBoris Popov cp = ctx->f_name; 878681a5bbeSBoris Popov md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 879681a5bbeSBoris Popov cp[sizeof(ctx->f_fname) - 1] = 0; 880681a5bbeSBoris Popov cp += strlen(cp) - 1; 881681a5bbeSBoris Popov while (*cp == ' ' && cp >= ctx->f_name) 882681a5bbeSBoris Popov *cp-- = 0; 883681a5bbeSBoris Popov ctx->f_attr.fa_attr = battr; 884681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 885681a5bbeSBoris Popov &ctx->f_attr.fa_mtime); 886681a5bbeSBoris Popov ctx->f_attr.fa_size = size; 887681a5bbeSBoris Popov ctx->f_nmlen = strlen(ctx->f_name); 888681a5bbeSBoris Popov ctx->f_ecnt--; 889681a5bbeSBoris Popov ctx->f_left--; 890681a5bbeSBoris Popov return 0; 891681a5bbeSBoris Popov } 892681a5bbeSBoris Popov 893681a5bbeSBoris Popov static int 894681a5bbeSBoris Popov smbfs_findcloseLM1(struct smbfs_fctx *ctx) 895681a5bbeSBoris Popov { 896681a5bbeSBoris Popov if (ctx->f_rq) 897681a5bbeSBoris Popov smb_rq_done(ctx->f_rq); 898681a5bbeSBoris Popov return 0; 899681a5bbeSBoris Popov } 900681a5bbeSBoris Popov 901681a5bbeSBoris Popov /* 902681a5bbeSBoris Popov * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 903681a5bbeSBoris Popov */ 904681a5bbeSBoris Popov static int 905681a5bbeSBoris Popov smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 906681a5bbeSBoris Popov { 907681a5bbeSBoris Popov struct smb_t2rq *t2p; 908681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 909681a5bbeSBoris Popov struct mbchain *mbp; 910681a5bbeSBoris Popov struct mdchain *mdp; 911681a5bbeSBoris Popov u_int16_t tw, flags; 912681a5bbeSBoris Popov int error; 913681a5bbeSBoris Popov 914681a5bbeSBoris Popov if (ctx->f_t2) { 915681a5bbeSBoris Popov smb_t2_done(ctx->f_t2); 916681a5bbeSBoris Popov ctx->f_t2 = NULL; 917681a5bbeSBoris Popov } 918681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 919681a5bbeSBoris Popov flags = 8 | 2; /* <resume> | <close if EOS> */ 920681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 921681a5bbeSBoris Popov flags |= 1; /* close search after this request */ 922681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_NOCLOSE; 923681a5bbeSBoris Popov } 924681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 925681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 926681a5bbeSBoris Popov ctx->f_scred, &t2p); 927681a5bbeSBoris Popov if (error) 928681a5bbeSBoris Popov return error; 929681a5bbeSBoris Popov ctx->f_t2 = t2p; 930681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 931681a5bbeSBoris Popov mb_init(mbp); 932681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_attrmask); 933681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_limit); 934681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 935681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_infolevel); 936681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); 937681a5bbeSBoris Popov error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 938681a5bbeSBoris Popov if (error) 939681a5bbeSBoris Popov return error; 940681a5bbeSBoris Popov } else { 941681a5bbeSBoris Popov error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 942681a5bbeSBoris Popov ctx->f_scred, &t2p); 943681a5bbeSBoris Popov if (error) 944681a5bbeSBoris Popov return error; 945681a5bbeSBoris Popov ctx->f_t2 = t2p; 946681a5bbeSBoris Popov mbp = &t2p->t2_tparam; 947681a5bbeSBoris Popov mb_init(mbp); 948681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 949681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_limit); 950681a5bbeSBoris Popov mb_put_uint16le(mbp, ctx->f_infolevel); 951681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* resume key */ 952681a5bbeSBoris Popov mb_put_uint16le(mbp, flags); 953681a5bbeSBoris Popov if (ctx->f_rname) 954681a5bbeSBoris Popov mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 955681a5bbeSBoris Popov else 956681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* resume file name */ 957681a5bbeSBoris Popov #if 0 958681a5bbeSBoris Popov struct timeval tv; 959681a5bbeSBoris Popov tv.tv_sec = 0; 960681a5bbeSBoris Popov tv.tv_usec = 200 * 1000; /* 200ms */ 961681a5bbeSBoris Popov if (vcp->vc_flags & SMBC_WIN95) { 962681a5bbeSBoris Popov /* 963681a5bbeSBoris Popov * some implementations suggests to sleep here 964681a5bbeSBoris Popov * for 200ms, due to the bug in the Win95. 965681a5bbeSBoris Popov * I've didn't notice any problem, but put code 966681a5bbeSBoris Popov * for it. 967681a5bbeSBoris Popov */ 968681a5bbeSBoris Popov tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); 969681a5bbeSBoris Popov } 970681a5bbeSBoris Popov #endif 971681a5bbeSBoris Popov } 972681a5bbeSBoris Popov t2p->t2_maxpcount = 5 * 2; 973681a5bbeSBoris Popov t2p->t2_maxdcount = vcp->vc_txmax; 974681a5bbeSBoris Popov error = smb_t2_request(t2p); 975681a5bbeSBoris Popov if (error) 976681a5bbeSBoris Popov return error; 977681a5bbeSBoris Popov mdp = &t2p->t2_rparam; 978681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 979681a5bbeSBoris Popov if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 980681a5bbeSBoris Popov return error; 981681a5bbeSBoris Popov ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 982681a5bbeSBoris Popov } 983681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 984681a5bbeSBoris Popov return error; 985681a5bbeSBoris Popov ctx->f_ecnt = tw; 986681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 987681a5bbeSBoris Popov return error; 988681a5bbeSBoris Popov if (tw) 989681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 990681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 991681a5bbeSBoris Popov return error; 992681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tw)) != 0) 993681a5bbeSBoris Popov return error; 994681a5bbeSBoris Popov if (ctx->f_ecnt == 0) 995681a5bbeSBoris Popov return ENOENT; 996681a5bbeSBoris Popov ctx->f_rnameofs = tw; 997681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 998681a5bbeSBoris Popov if (mdp->md_top == NULL) { 999681a5bbeSBoris Popov printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 1000681a5bbeSBoris Popov return ENOENT; 1001681a5bbeSBoris Popov } 1002681a5bbeSBoris Popov if (mdp->md_top->m_len == 0) { 1003681a5bbeSBoris Popov printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 1004681a5bbeSBoris Popov return ENOENT; 1005681a5bbeSBoris Popov } 1006681a5bbeSBoris Popov ctx->f_eofs = 0; 1007681a5bbeSBoris Popov return 0; 1008681a5bbeSBoris Popov } 1009681a5bbeSBoris Popov 1010681a5bbeSBoris Popov static int 1011681a5bbeSBoris Popov smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1012681a5bbeSBoris Popov { 1013681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 1014681a5bbeSBoris Popov struct mbchain *mbp; 1015681a5bbeSBoris Popov int error; 1016681a5bbeSBoris Popov 1017681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 1018681a5bbeSBoris Popov if (error) 1019681a5bbeSBoris Popov return error; 1020681a5bbeSBoris Popov smb_rq_getrequest(rqp, &mbp); 1021681a5bbeSBoris Popov smb_rq_wstart(rqp); 1022681a5bbeSBoris Popov mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1023681a5bbeSBoris Popov smb_rq_wend(rqp); 1024681a5bbeSBoris Popov smb_rq_bstart(rqp); 1025681a5bbeSBoris Popov smb_rq_bend(rqp); 1026681a5bbeSBoris Popov error = smb_rq_simple(rqp); 1027681a5bbeSBoris Popov smb_rq_done(rqp); 1028681a5bbeSBoris Popov return error; 1029681a5bbeSBoris Popov } 1030681a5bbeSBoris Popov 1031681a5bbeSBoris Popov static int 1032681a5bbeSBoris Popov smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1033681a5bbeSBoris Popov const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1034681a5bbeSBoris Popov { 1035681a5bbeSBoris Popov ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 1036681a5bbeSBoris Popov if (ctx->f_name == NULL) 1037681a5bbeSBoris Popov return ENOMEM; 1038681a5bbeSBoris Popov ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1039681a5bbeSBoris Popov SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1040681a5bbeSBoris Popov ctx->f_attrmask = attr; 1041681a5bbeSBoris Popov ctx->f_wildcard = wildcard; 1042681a5bbeSBoris Popov ctx->f_wclen = wclen; 1043681a5bbeSBoris Popov return 0; 1044681a5bbeSBoris Popov } 1045681a5bbeSBoris Popov 1046681a5bbeSBoris Popov static int 1047681a5bbeSBoris Popov smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1048681a5bbeSBoris Popov { 1049681a5bbeSBoris Popov struct mdchain *mbp; 1050681a5bbeSBoris Popov struct smb_t2rq *t2p; 1051681a5bbeSBoris Popov char *cp; 1052681a5bbeSBoris Popov u_int8_t tb; 1053681a5bbeSBoris Popov u_int16_t date, time, wattr; 1054681a5bbeSBoris Popov u_int32_t size, next, dattr; 1055681a5bbeSBoris Popov int64_t lint; 1056681a5bbeSBoris Popov int error, svtz, cnt, fxsz, nmlen, recsz; 1057681a5bbeSBoris Popov 1058681a5bbeSBoris Popov if (ctx->f_ecnt == 0) { 1059681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_EOF) 1060681a5bbeSBoris Popov return ENOENT; 1061681a5bbeSBoris Popov ctx->f_left = ctx->f_limit = limit; 1062681a5bbeSBoris Popov error = smbfs_smb_trans2find2(ctx); 1063681a5bbeSBoris Popov if (error) 1064681a5bbeSBoris Popov return error; 1065681a5bbeSBoris Popov } 1066681a5bbeSBoris Popov t2p = ctx->f_t2; 1067681a5bbeSBoris Popov mbp = &t2p->t2_rdata; 1068681a5bbeSBoris Popov svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1069681a5bbeSBoris Popov switch (ctx->f_infolevel) { 1070681a5bbeSBoris Popov case SMB_INFO_STANDARD: 1071681a5bbeSBoris Popov next = 0; 1072681a5bbeSBoris Popov fxsz = 0; 1073681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1074681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* creation time */ 1075681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1076681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* access time */ 1077681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 1078681a5bbeSBoris Popov md_get_uint16le(mbp, &date); 1079681a5bbeSBoris Popov md_get_uint16le(mbp, &time); /* access time */ 1080681a5bbeSBoris Popov smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 1081681a5bbeSBoris Popov md_get_uint32le(mbp, &size); 1082681a5bbeSBoris Popov ctx->f_attr.fa_size = size; 1083681a5bbeSBoris Popov md_get_uint32(mbp, NULL); /* allocation size */ 1084681a5bbeSBoris Popov md_get_uint16le(mbp, &wattr); 1085681a5bbeSBoris Popov ctx->f_attr.fa_attr = wattr; 1086681a5bbeSBoris Popov md_get_uint8(mbp, &tb); 1087681a5bbeSBoris Popov size = nmlen = tb; 1088681a5bbeSBoris Popov fxsz = 23; 1089681a5bbeSBoris Popov recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1090681a5bbeSBoris Popov break; 1091681a5bbeSBoris Popov case SMB_FIND_FILE_DIRECTORY_INFO: 1092681a5bbeSBoris Popov md_get_uint32le(mbp, &next); 1093681a5bbeSBoris Popov md_get_uint32(mbp, NULL); /* file index */ 1094681a5bbeSBoris Popov md_get_int64(mbp, NULL); /* creation time */ 1095681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1096681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 1097681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1098681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 1099681a5bbeSBoris Popov md_get_int64le(mbp, &lint); 1100681a5bbeSBoris Popov smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 1101681a5bbeSBoris Popov md_get_int64le(mbp, &lint); /* file size */ 1102681a5bbeSBoris Popov ctx->f_attr.fa_size = lint; 1103681a5bbeSBoris Popov md_get_int64(mbp, NULL); /* real size (should use) */ 1104798bb23eSBoris Popov md_get_uint32le(mbp, &dattr); /* EA */ 1105681a5bbeSBoris Popov ctx->f_attr.fa_attr = dattr; 1106681a5bbeSBoris Popov md_get_uint32le(mbp, &size); /* name len */ 1107681a5bbeSBoris Popov fxsz = 64; 1108681a5bbeSBoris Popov recsz = next ? next : fxsz + size; 1109681a5bbeSBoris Popov break; 1110681a5bbeSBoris Popov default: 1111681a5bbeSBoris Popov SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 1112681a5bbeSBoris Popov return EINVAL; 1113681a5bbeSBoris Popov } 1114681a5bbeSBoris Popov nmlen = min(size, SMB_MAXFNAMELEN); 1115681a5bbeSBoris Popov cp = ctx->f_name; 1116681a5bbeSBoris Popov error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1117681a5bbeSBoris Popov if (error) 1118681a5bbeSBoris Popov return error; 1119681a5bbeSBoris Popov if (next) { 1120681a5bbeSBoris Popov cnt = next - nmlen - fxsz; 1121681a5bbeSBoris Popov if (cnt > 0) 1122681a5bbeSBoris Popov md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1123681a5bbeSBoris Popov else if (cnt < 0) { 1124681a5bbeSBoris Popov SMBERROR("out of sync\n"); 1125681a5bbeSBoris Popov return EBADRPC; 1126681a5bbeSBoris Popov } 1127681a5bbeSBoris Popov } 1128681a5bbeSBoris Popov if (nmlen && cp[nmlen - 1] == 0) 1129681a5bbeSBoris Popov nmlen--; 1130681a5bbeSBoris Popov if (nmlen == 0) 1131681a5bbeSBoris Popov return EBADRPC; 1132681a5bbeSBoris Popov 1133681a5bbeSBoris Popov next = ctx->f_eofs + recsz; 1134681a5bbeSBoris Popov if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1135681a5bbeSBoris Popov (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1136681a5bbeSBoris Popov /* 1137681a5bbeSBoris Popov * Server needs a resume filename. 1138681a5bbeSBoris Popov */ 1139681a5bbeSBoris Popov if (ctx->f_rnamelen <= nmlen) { 1140681a5bbeSBoris Popov if (ctx->f_rname) 1141681a5bbeSBoris Popov free(ctx->f_rname, M_SMBFSDATA); 1142681a5bbeSBoris Popov ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1143681a5bbeSBoris Popov ctx->f_rnamelen = nmlen; 1144681a5bbeSBoris Popov } 1145681a5bbeSBoris Popov bcopy(ctx->f_name, ctx->f_rname, nmlen); 1146681a5bbeSBoris Popov ctx->f_rname[nmlen] = 0; 1147681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1148681a5bbeSBoris Popov } 1149681a5bbeSBoris Popov ctx->f_nmlen = nmlen; 1150681a5bbeSBoris Popov ctx->f_eofs = next; 1151681a5bbeSBoris Popov ctx->f_ecnt--; 1152681a5bbeSBoris Popov ctx->f_left--; 1153681a5bbeSBoris Popov return 0; 1154681a5bbeSBoris Popov } 1155681a5bbeSBoris Popov 1156681a5bbeSBoris Popov static int 1157681a5bbeSBoris Popov smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1158681a5bbeSBoris Popov { 1159681a5bbeSBoris Popov if (ctx->f_name) 1160681a5bbeSBoris Popov free(ctx->f_name, M_SMBFSDATA); 1161681a5bbeSBoris Popov if (ctx->f_t2) 1162681a5bbeSBoris Popov smb_t2_done(ctx->f_t2); 1163681a5bbeSBoris Popov if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1164681a5bbeSBoris Popov smbfs_smb_findclose2(ctx); 1165681a5bbeSBoris Popov return 0; 1166681a5bbeSBoris Popov } 1167681a5bbeSBoris Popov 1168681a5bbeSBoris Popov int 1169681a5bbeSBoris Popov smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1170681a5bbeSBoris Popov struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1171681a5bbeSBoris Popov { 1172681a5bbeSBoris Popov struct smbfs_fctx *ctx; 1173681a5bbeSBoris Popov int error; 1174681a5bbeSBoris Popov 1175681a5bbeSBoris Popov ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 1176681a5bbeSBoris Popov if (ctx == NULL) 1177681a5bbeSBoris Popov return ENOMEM; 1178681a5bbeSBoris Popov bzero(ctx, sizeof(*ctx)); 1179681a5bbeSBoris Popov ctx->f_ssp = dnp->n_mount->sm_share; 1180681a5bbeSBoris Popov ctx->f_dnp = dnp; 1181681a5bbeSBoris Popov ctx->f_flags = SMBFS_RDD_FINDFIRST; 1182681a5bbeSBoris Popov ctx->f_scred = scred; 1183681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1184681a5bbeSBoris Popov (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) { 1185681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_USESEARCH; 1186681a5bbeSBoris Popov error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1187681a5bbeSBoris Popov } else 1188681a5bbeSBoris Popov error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1189681a5bbeSBoris Popov if (error) 1190681a5bbeSBoris Popov smbfs_findclose(ctx, scred); 1191681a5bbeSBoris Popov else 1192681a5bbeSBoris Popov *ctxpp = ctx; 1193681a5bbeSBoris Popov return error; 1194681a5bbeSBoris Popov } 1195681a5bbeSBoris Popov 1196681a5bbeSBoris Popov int 1197681a5bbeSBoris Popov smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1198681a5bbeSBoris Popov { 1199681a5bbeSBoris Popov int error; 1200681a5bbeSBoris Popov 1201681a5bbeSBoris Popov if (limit == 0) 1202681a5bbeSBoris Popov limit = 1000000; 1203681a5bbeSBoris Popov else if (limit > 1) 1204681a5bbeSBoris Popov limit *= 4; /* imperical */ 1205681a5bbeSBoris Popov ctx->f_scred = scred; 1206681a5bbeSBoris Popov for (;;) { 1207681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1208681a5bbeSBoris Popov error = smbfs_findnextLM1(ctx, limit); 1209681a5bbeSBoris Popov } else 1210681a5bbeSBoris Popov error = smbfs_findnextLM2(ctx, limit); 1211681a5bbeSBoris Popov if (error) 1212681a5bbeSBoris Popov return error; 1213681a5bbeSBoris Popov if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1214681a5bbeSBoris Popov (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1215681a5bbeSBoris Popov ctx->f_name[1] == '.')) 1216681a5bbeSBoris Popov continue; 1217681a5bbeSBoris Popov break; 1218681a5bbeSBoris Popov } 1219681a5bbeSBoris Popov smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen, 1220681a5bbeSBoris Popov ctx->f_dnp->n_mount->sm_caseopt); 1221681a5bbeSBoris Popov ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1222681a5bbeSBoris Popov return 0; 1223681a5bbeSBoris Popov } 1224681a5bbeSBoris Popov 1225681a5bbeSBoris Popov int 1226681a5bbeSBoris Popov smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1227681a5bbeSBoris Popov { 1228681a5bbeSBoris Popov ctx->f_scred = scred; 1229681a5bbeSBoris Popov if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1230681a5bbeSBoris Popov smbfs_findcloseLM1(ctx); 1231681a5bbeSBoris Popov } else 1232681a5bbeSBoris Popov smbfs_findcloseLM2(ctx); 1233681a5bbeSBoris Popov if (ctx->f_rname) 1234681a5bbeSBoris Popov free(ctx->f_rname, M_SMBFSDATA); 1235681a5bbeSBoris Popov free(ctx, M_SMBFSDATA); 1236681a5bbeSBoris Popov return 0; 1237681a5bbeSBoris Popov } 1238681a5bbeSBoris Popov 1239681a5bbeSBoris Popov int 1240681a5bbeSBoris Popov smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1241681a5bbeSBoris Popov struct smbfattr *fap, struct smb_cred *scred) 1242681a5bbeSBoris Popov { 1243681a5bbeSBoris Popov struct smbfs_fctx *ctx; 1244681a5bbeSBoris Popov int error; 1245681a5bbeSBoris Popov 1246681a5bbeSBoris Popov if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1247681a5bbeSBoris Popov bzero(fap, sizeof(*fap)); 1248681a5bbeSBoris Popov fap->fa_attr = SMB_FA_DIR; 1249681a5bbeSBoris Popov fap->fa_ino = 2; 1250681a5bbeSBoris Popov return 0; 1251681a5bbeSBoris Popov } 1252681a5bbeSBoris Popov if (nmlen == 1 && name[0] == '.') { 1253681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1254681a5bbeSBoris Popov return error; 1255681a5bbeSBoris Popov } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1256681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, fap, scred); 1257681a5bbeSBoris Popov printf("%s: knows NOTHING about '..'\n", __FUNCTION__); 1258681a5bbeSBoris Popov return error; 1259681a5bbeSBoris Popov } 1260681a5bbeSBoris Popov error = smbfs_findopen(dnp, name, nmlen, 1261681a5bbeSBoris Popov SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1262681a5bbeSBoris Popov if (error) 1263681a5bbeSBoris Popov return error; 1264681a5bbeSBoris Popov ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1265681a5bbeSBoris Popov error = smbfs_findnext(ctx, 1, scred); 1266681a5bbeSBoris Popov if (error == 0) { 1267681a5bbeSBoris Popov *fap = ctx->f_attr; 1268681a5bbeSBoris Popov if (name == NULL) 1269681a5bbeSBoris Popov fap->fa_ino = dnp->n_ino; 1270681a5bbeSBoris Popov } 1271681a5bbeSBoris Popov smbfs_findclose(ctx, scred); 1272681a5bbeSBoris Popov return error; 1273681a5bbeSBoris Popov } 1274