1*91d632c8Sgwr /* 2*91d632c8Sgwr * CDDL HEADER START 3*91d632c8Sgwr * 4*91d632c8Sgwr * The contents of this file are subject to the terms of the 5*91d632c8Sgwr * Common Development and Distribution License (the "License"). 6*91d632c8Sgwr * You may not use this file except in compliance with the License. 7*91d632c8Sgwr * 8*91d632c8Sgwr * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*91d632c8Sgwr * or http://www.opensolaris.org/os/licensing. 10*91d632c8Sgwr * See the License for the specific language governing permissions 11*91d632c8Sgwr * and limitations under the License. 12*91d632c8Sgwr * 13*91d632c8Sgwr * When distributing Covered Code, include this CDDL HEADER in each 14*91d632c8Sgwr * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*91d632c8Sgwr * If applicable, add the following below this CDDL HEADER, with the 16*91d632c8Sgwr * fields enclosed by brackets "[]" replaced with your own identifying 17*91d632c8Sgwr * information: Portions Copyright [yyyy] [name of copyright owner] 18*91d632c8Sgwr * 19*91d632c8Sgwr * CDDL HEADER END 20*91d632c8Sgwr */ 21*91d632c8Sgwr 22*91d632c8Sgwr /* 23*91d632c8Sgwr * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*91d632c8Sgwr * Use is subject to license terms. 25*91d632c8Sgwr */ 26*91d632c8Sgwr 27*91d632c8Sgwr #pragma ident "%Z%%M% %I% %E% SMI" 28*91d632c8Sgwr 29*91d632c8Sgwr /* 30*91d632c8Sgwr * Functions supporting Solaris Extended Attributes, 31*91d632c8Sgwr * used to provide access to CIFS "named streams". 32*91d632c8Sgwr */ 33*91d632c8Sgwr 34*91d632c8Sgwr #include <sys/systm.h> 35*91d632c8Sgwr #include <sys/cred.h> 36*91d632c8Sgwr #include <sys/vnode.h> 37*91d632c8Sgwr #include <sys/vfs.h> 38*91d632c8Sgwr #include <sys/filio.h> 39*91d632c8Sgwr #include <sys/uio.h> 40*91d632c8Sgwr #include <sys/dirent.h> 41*91d632c8Sgwr #include <sys/errno.h> 42*91d632c8Sgwr #include <sys/sysmacros.h> 43*91d632c8Sgwr #include <sys/kmem.h> 44*91d632c8Sgwr #include <sys/stat.h> 45*91d632c8Sgwr #include <sys/cmn_err.h> 46*91d632c8Sgwr #include <sys/dnlc.h> 47*91d632c8Sgwr #include <sys/vfs_opreg.h> 48*91d632c8Sgwr #include <sys/u8_textprep.h> 49*91d632c8Sgwr 50*91d632c8Sgwr #include <netsmb/smb_osdep.h> 51*91d632c8Sgwr #include <netsmb/smb.h> 52*91d632c8Sgwr #include <netsmb/smb_conn.h> 53*91d632c8Sgwr #include <netsmb/smb_subr.h> 54*91d632c8Sgwr #include <netsmb/smb_rq.h> 55*91d632c8Sgwr 56*91d632c8Sgwr #include <smbfs/smbfs.h> 57*91d632c8Sgwr #include <smbfs/smbfs_node.h> 58*91d632c8Sgwr #include <smbfs/smbfs_subr.h> 59*91d632c8Sgwr 60*91d632c8Sgwr #include <fs/fs_subr.h> 61*91d632c8Sgwr 62*91d632c8Sgwr /* 63*91d632c8Sgwr * Solaris wants there to be a directory node to contain 64*91d632c8Sgwr * all the extended attributes. The SMB protocol does not 65*91d632c8Sgwr * really support a directory here, and uses very different 66*91d632c8Sgwr * operations to list attributes, etc. so we "fake up" an 67*91d632c8Sgwr * smbnode here to represent the attributes directory. 68*91d632c8Sgwr * 69*91d632c8Sgwr * We need to give this (fake) directory a unique identity, 70*91d632c8Sgwr * and since we're using the full remote pathname as the 71*91d632c8Sgwr * unique identity of all nodes, the easiest thing to do 72*91d632c8Sgwr * here is append a colon (:) to the given pathname. 73*91d632c8Sgwr * 74*91d632c8Sgwr * There are several places where smbfs_fullpath and its 75*91d632c8Sgwr * callers must decide what separator to use when building 76*91d632c8Sgwr * a remote path name, and the rule is now as follows: 77*91d632c8Sgwr * 1: When no XATTR involved, use "\\" as the separator. 78*91d632c8Sgwr * 2: Traversal into the (fake) XATTR dir adds one ":" 79*91d632c8Sgwr * 3: Children of the XATTR dir add nothing (sep=0) 80*91d632c8Sgwr * The result should be _one_ colon before the attr name. 81*91d632c8Sgwr */ 82*91d632c8Sgwr 83*91d632c8Sgwr /* ARGSUSED */ 84*91d632c8Sgwr int 85*91d632c8Sgwr smbfs_get_xattrdir(vnode_t *pvp, vnode_t **vpp, cred_t *cr, int flags) 86*91d632c8Sgwr { 87*91d632c8Sgwr vnode_t *xvp; 88*91d632c8Sgwr smbnode_t *pnp, *xnp; 89*91d632c8Sgwr 90*91d632c8Sgwr pnp = VTOSMB(pvp); 91*91d632c8Sgwr 92*91d632c8Sgwr xvp = smbfs_make_node(pvp->v_vfsp, 93*91d632c8Sgwr pnp->n_rpath, pnp->n_rplen, 94*91d632c8Sgwr NULL, 0, ':', NULL); 95*91d632c8Sgwr ASSERT(xvp); 96*91d632c8Sgwr /* Note: xvp has a VN_HOLD, which our caller expects. */ 97*91d632c8Sgwr xnp = VTOSMB(xvp); 98*91d632c8Sgwr 99*91d632c8Sgwr /* If it's a new node, initialize. */ 100*91d632c8Sgwr if (xvp->v_type == VNON) { 101*91d632c8Sgwr 102*91d632c8Sgwr mutex_enter(&xvp->v_lock); 103*91d632c8Sgwr xvp->v_type = VDIR; 104*91d632c8Sgwr xvp->v_flag |= V_XATTRDIR; 105*91d632c8Sgwr mutex_exit(&xvp->v_lock); 106*91d632c8Sgwr 107*91d632c8Sgwr mutex_enter(&xnp->r_statelock); 108*91d632c8Sgwr xnp->n_flag |= N_XATTR; 109*91d632c8Sgwr mutex_exit(&xnp->r_statelock); 110*91d632c8Sgwr } 111*91d632c8Sgwr 112*91d632c8Sgwr /* Success! */ 113*91d632c8Sgwr *vpp = xvp; 114*91d632c8Sgwr return (0); 115*91d632c8Sgwr } 116*91d632c8Sgwr 117*91d632c8Sgwr /* 118*91d632c8Sgwr * Find the parent of an XATTR directory or file, 119*91d632c8Sgwr * by trimming off the ":attrname" part of rpath. 120*91d632c8Sgwr * Called on XATTR files to get the XATTR dir, and 121*91d632c8Sgwr * called on the XATTR dir to get the real object 122*91d632c8Sgwr * under which the (faked up) XATTR dir lives. 123*91d632c8Sgwr */ 124*91d632c8Sgwr int 125*91d632c8Sgwr smbfs_xa_parent(vnode_t *vp, vnode_t **vpp) 126*91d632c8Sgwr { 127*91d632c8Sgwr smbnode_t *np = VTOSMB(vp); 128*91d632c8Sgwr vnode_t *pvp; 129*91d632c8Sgwr int rplen; 130*91d632c8Sgwr 131*91d632c8Sgwr if ((np->n_flag & N_XATTR) == 0) 132*91d632c8Sgwr return (EINVAL); 133*91d632c8Sgwr 134*91d632c8Sgwr if (vp->v_flag & V_XATTRDIR) { 135*91d632c8Sgwr /* 136*91d632c8Sgwr * Want the parent of the XATTR directory. 137*91d632c8Sgwr * That's easy: just remove trailing ":" 138*91d632c8Sgwr */ 139*91d632c8Sgwr rplen = np->n_rplen - 1; 140*91d632c8Sgwr if (rplen < 1) { 141*91d632c8Sgwr SMBVDEBUG("rplen < 1?"); 142*91d632c8Sgwr return (ENOENT); 143*91d632c8Sgwr } 144*91d632c8Sgwr if (np->n_rpath[rplen] != ':') { 145*91d632c8Sgwr SMBVDEBUG("last is not colon"); 146*91d632c8Sgwr return (ENOENT); 147*91d632c8Sgwr } 148*91d632c8Sgwr } else { 149*91d632c8Sgwr /* 150*91d632c8Sgwr * Want the XATTR directory given 151*91d632c8Sgwr * one of its XATTR files (children). 152*91d632c8Sgwr * Find the ":" and trim after it. 153*91d632c8Sgwr */ 154*91d632c8Sgwr for (rplen = 1; rplen < np->n_rplen; rplen++) 155*91d632c8Sgwr if (np->n_rpath[rplen] == ':') 156*91d632c8Sgwr break; 157*91d632c8Sgwr /* Should have found ":stream_name" */ 158*91d632c8Sgwr if (rplen >= np->n_rplen) { 159*91d632c8Sgwr SMBVDEBUG("colon not found"); 160*91d632c8Sgwr return (ENOENT); 161*91d632c8Sgwr } 162*91d632c8Sgwr rplen++; /* keep the ":" */ 163*91d632c8Sgwr if (rplen >= np->n_rplen) { 164*91d632c8Sgwr SMBVDEBUG("no stream name"); 165*91d632c8Sgwr return (ENOENT); 166*91d632c8Sgwr } 167*91d632c8Sgwr } 168*91d632c8Sgwr 169*91d632c8Sgwr pvp = smbfs_make_node(vp->v_vfsp, 170*91d632c8Sgwr np->n_rpath, rplen, 171*91d632c8Sgwr NULL, 0, 0, NULL); 172*91d632c8Sgwr ASSERT(pvp); 173*91d632c8Sgwr 174*91d632c8Sgwr /* Note: pvp has a VN_HOLD from _make_node */ 175*91d632c8Sgwr *vpp = pvp; 176*91d632c8Sgwr return (0); 177*91d632c8Sgwr } 178*91d632c8Sgwr 179*91d632c8Sgwr /* 180*91d632c8Sgwr * This is called by smbfs_pathconf to find out 181*91d632c8Sgwr * if some file has any extended attributes. 182*91d632c8Sgwr * There's no short-cut way to find out, so we 183*91d632c8Sgwr * just list the attributes the usual way and 184*91d632c8Sgwr * check for an empty result. 185*91d632c8Sgwr * 186*91d632c8Sgwr * Returns 1: (exists) or 0: (none found) 187*91d632c8Sgwr */ 188*91d632c8Sgwr int 189*91d632c8Sgwr smbfs_xa_exists(vnode_t *vp, cred_t *cr) 190*91d632c8Sgwr { 191*91d632c8Sgwr smbnode_t *xnp; 192*91d632c8Sgwr vnode_t *xvp; 193*91d632c8Sgwr struct smb_cred scred; 194*91d632c8Sgwr struct smbfs_fctx ctx; 195*91d632c8Sgwr int error, rc = 0; 196*91d632c8Sgwr 197*91d632c8Sgwr /* Get the xattr dir */ 198*91d632c8Sgwr error = smbfs_get_xattrdir(vp, &xvp, cr, LOOKUP_XATTR); 199*91d632c8Sgwr if (error) 200*91d632c8Sgwr return (0); 201*91d632c8Sgwr /* NB: have VN_HOLD on xpv */ 202*91d632c8Sgwr xnp = VTOSMB(xvp); 203*91d632c8Sgwr 204*91d632c8Sgwr smb_credinit(&scred, curproc, cr); 205*91d632c8Sgwr 206*91d632c8Sgwr bzero(&ctx, sizeof (ctx)); 207*91d632c8Sgwr ctx.f_flags = SMBFS_RDD_FINDFIRST; 208*91d632c8Sgwr ctx.f_dnp = xnp; 209*91d632c8Sgwr ctx.f_scred = &scred; 210*91d632c8Sgwr ctx.f_ssp = xnp->n_mount->smi_share; 211*91d632c8Sgwr 212*91d632c8Sgwr error = smbfs_xa_findopen(&ctx, xnp, "*", 1); 213*91d632c8Sgwr if (error) 214*91d632c8Sgwr goto out; 215*91d632c8Sgwr 216*91d632c8Sgwr error = smbfs_xa_findnext(&ctx, 1); 217*91d632c8Sgwr if (error) 218*91d632c8Sgwr goto out; 219*91d632c8Sgwr 220*91d632c8Sgwr /* Have at least one named stream. */ 221*91d632c8Sgwr SMBVDEBUG("ctx.f_name: %s\n", ctx.f_name); 222*91d632c8Sgwr rc = 1; 223*91d632c8Sgwr 224*91d632c8Sgwr out: 225*91d632c8Sgwr /* NB: Always call findclose, error or not. */ 226*91d632c8Sgwr (void) smbfs_xa_findclose(&ctx); 227*91d632c8Sgwr smb_credrele(&scred); 228*91d632c8Sgwr VN_RELE(xvp); 229*91d632c8Sgwr return (rc); 230*91d632c8Sgwr } 231*91d632c8Sgwr 232*91d632c8Sgwr 233*91d632c8Sgwr /* 234*91d632c8Sgwr * This is called to get attributes (size, etc.) of either 235*91d632c8Sgwr * the "faked up" XATTR directory or a named stream. 236*91d632c8Sgwr */ 237*91d632c8Sgwr int 238*91d632c8Sgwr smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap, 239*91d632c8Sgwr struct smb_cred *scrp) 240*91d632c8Sgwr { 241*91d632c8Sgwr vnode_t *xvp; /* xattr */ 242*91d632c8Sgwr vnode_t *pvp; /* parent */ 243*91d632c8Sgwr smbnode_t *pnp; /* parent */ 244*91d632c8Sgwr int error, nlen; 245*91d632c8Sgwr const char *name, *sname; 246*91d632c8Sgwr 247*91d632c8Sgwr xvp = SMBTOV(xnp); 248*91d632c8Sgwr 249*91d632c8Sgwr /* 250*91d632c8Sgwr * Simulate smbfs_smb_getfattr() for a named stream. 251*91d632c8Sgwr * OK to leave a,c,m times zero (expected w/ XATTR). 252*91d632c8Sgwr * The XATTR directory is easy (all fake). 253*91d632c8Sgwr */ 254*91d632c8Sgwr if (xvp->v_flag & V_XATTRDIR) { 255*91d632c8Sgwr fap->fa_attr = SMB_FA_DIR; 256*91d632c8Sgwr fap->fa_size = DEV_BSIZE; 257*91d632c8Sgwr return (0); 258*91d632c8Sgwr } 259*91d632c8Sgwr 260*91d632c8Sgwr /* 261*91d632c8Sgwr * Do a lookup in the XATTR directory, 262*91d632c8Sgwr * using the stream name (last part) 263*91d632c8Sgwr * from the xattr node. 264*91d632c8Sgwr */ 265*91d632c8Sgwr error = smbfs_xa_parent(xvp, &pvp); 266*91d632c8Sgwr if (error) 267*91d632c8Sgwr return (error); 268*91d632c8Sgwr /* Note: pvp has a VN_HOLD */ 269*91d632c8Sgwr pnp = VTOSMB(pvp); 270*91d632c8Sgwr 271*91d632c8Sgwr /* Get stream name (ptr and length) */ 272*91d632c8Sgwr ASSERT(xnp->n_rplen > pnp->n_rplen); 273*91d632c8Sgwr nlen = xnp->n_rplen - pnp->n_rplen; 274*91d632c8Sgwr name = xnp->n_rpath + pnp->n_rplen; 275*91d632c8Sgwr sname = name; 276*91d632c8Sgwr 277*91d632c8Sgwr /* Note: this can allocate a new "name" */ 278*91d632c8Sgwr error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp); 279*91d632c8Sgwr if (error == 0 && name != sname) 280*91d632c8Sgwr smbfs_name_free(name, nlen); 281*91d632c8Sgwr 282*91d632c8Sgwr VN_RELE(pvp); 283*91d632c8Sgwr 284*91d632c8Sgwr return (error); 285*91d632c8Sgwr } 286*91d632c8Sgwr 287*91d632c8Sgwr /* 288*91d632c8Sgwr * Fetch the entire attribute list here in findopen. 289*91d632c8Sgwr * Will parse the results in findnext. 290*91d632c8Sgwr * 291*91d632c8Sgwr * This is called on the XATTR directory, so we 292*91d632c8Sgwr * have to get the (real) parent object first. 293*91d632c8Sgwr */ 294*91d632c8Sgwr /* ARGSUSED */ 295*91d632c8Sgwr int 296*91d632c8Sgwr smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, 297*91d632c8Sgwr const char *wildcard, int wclen) 298*91d632c8Sgwr { 299*91d632c8Sgwr vnode_t *pvp; /* parent */ 300*91d632c8Sgwr smbnode_t *pnp; 301*91d632c8Sgwr struct smb_t2rq *t2p; 302*91d632c8Sgwr struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 303*91d632c8Sgwr struct mbchain *mbp; 304*91d632c8Sgwr int error; 305*91d632c8Sgwr 306*91d632c8Sgwr ASSERT(dnp->n_flag & N_XATTR); 307*91d632c8Sgwr 308*91d632c8Sgwr ctx->f_type = ft_XA; 309*91d632c8Sgwr 310*91d632c8Sgwr error = smbfs_xa_parent(SMBTOV(dnp), &pvp); 311*91d632c8Sgwr if (error) 312*91d632c8Sgwr return (error); 313*91d632c8Sgwr ASSERT(pvp); 314*91d632c8Sgwr /* Note: pvp has a VN_HOLD */ 315*91d632c8Sgwr pnp = VTOSMB(pvp); 316*91d632c8Sgwr 317*91d632c8Sgwr if (ctx->f_t2) { 318*91d632c8Sgwr smb_t2_done(ctx->f_t2); 319*91d632c8Sgwr ctx->f_t2 = NULL; 320*91d632c8Sgwr } 321*91d632c8Sgwr 322*91d632c8Sgwr error = smb_t2_alloc(SSTOCP(ctx->f_ssp), 323*91d632c8Sgwr SMB_TRANS2_QUERY_PATH_INFORMATION, 324*91d632c8Sgwr ctx->f_scred, &t2p); 325*91d632c8Sgwr if (error) 326*91d632c8Sgwr goto out; 327*91d632c8Sgwr ctx->f_t2 = t2p; 328*91d632c8Sgwr 329*91d632c8Sgwr mbp = &t2p->t2_tparam; 330*91d632c8Sgwr mb_init(mbp); 331*91d632c8Sgwr mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO); 332*91d632c8Sgwr mb_put_uint32le(mbp, 0); 333*91d632c8Sgwr error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0); 334*91d632c8Sgwr if (error) 335*91d632c8Sgwr goto out; 336*91d632c8Sgwr t2p->t2_maxpcount = 2; 337*91d632c8Sgwr t2p->t2_maxdcount = INT16_MAX; 338*91d632c8Sgwr error = smb_t2_request(t2p); 339*91d632c8Sgwr if (error) { 340*91d632c8Sgwr if (smb_t2_err(t2p) == NT_STATUS_INVALID_PARAMETER) 341*91d632c8Sgwr error = ENOTSUP; 342*91d632c8Sgwr } 343*91d632c8Sgwr /* 344*91d632c8Sgwr * No returned parameters to parse. 345*91d632c8Sgwr * Returned data are in t2_rdata, 346*91d632c8Sgwr * which we'll parse in _findnext. 347*91d632c8Sgwr * However, save the wildcard. 348*91d632c8Sgwr */ 349*91d632c8Sgwr ctx->f_wildcard = wildcard; 350*91d632c8Sgwr ctx->f_wclen = wclen; 351*91d632c8Sgwr 352*91d632c8Sgwr out: 353*91d632c8Sgwr VN_RELE(pvp); 354*91d632c8Sgwr return (error); 355*91d632c8Sgwr } 356*91d632c8Sgwr 357*91d632c8Sgwr /* 358*91d632c8Sgwr * Get the next name in an XATTR directory into f_name 359*91d632c8Sgwr */ 360*91d632c8Sgwr /* ARGSUSED */ 361*91d632c8Sgwr int 362*91d632c8Sgwr smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit) 363*91d632c8Sgwr { 364*91d632c8Sgwr struct mdchain *mdp; 365*91d632c8Sgwr struct smb_t2rq *t2p; 366*91d632c8Sgwr uint32_t size, next; 367*91d632c8Sgwr uint64_t llongint; 368*91d632c8Sgwr int error, skip, used, nmlen; 369*91d632c8Sgwr 370*91d632c8Sgwr t2p = ctx->f_t2; 371*91d632c8Sgwr mdp = &t2p->t2_rdata; 372*91d632c8Sgwr 373*91d632c8Sgwr if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 374*91d632c8Sgwr ASSERT(ctx->f_wildcard); 375*91d632c8Sgwr SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard); 376*91d632c8Sgwr } 377*91d632c8Sgwr 378*91d632c8Sgwr again: 379*91d632c8Sgwr if (ctx->f_flags & SMBFS_RDD_EOF) 380*91d632c8Sgwr return (ENOENT); 381*91d632c8Sgwr 382*91d632c8Sgwr /* Parse FILE_STREAM_INFORMATION */ 383*91d632c8Sgwr if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */ 384*91d632c8Sgwr return (ENOENT); 385*91d632c8Sgwr if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */ 386*91d632c8Sgwr return (ENOENT); 387*91d632c8Sgwr md_get_uint64le(mdp, &llongint); /* file size */ 388*91d632c8Sgwr ctx->f_attr.fa_size = llongint; 389*91d632c8Sgwr md_get_uint64le(mdp, NULL); /* alloc. size */ 390*91d632c8Sgwr used = 4 + 4 + 8 + 8; /* how much we consumed */ 391*91d632c8Sgwr 392*91d632c8Sgwr /* 393*91d632c8Sgwr * Copy the string, but skip the first char (":") 394*91d632c8Sgwr * Watch out for zero-length strings here. 395*91d632c8Sgwr */ 396*91d632c8Sgwr if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 397*91d632c8Sgwr if (size >= 2) { 398*91d632c8Sgwr size -= 2; used += 2; 399*91d632c8Sgwr md_get_uint16le(mdp, NULL); 400*91d632c8Sgwr } 401*91d632c8Sgwr nmlen = min(size, SMB_MAXFNAMELEN * 2); 402*91d632c8Sgwr } else { 403*91d632c8Sgwr if (size >= 1) { 404*91d632c8Sgwr size -= 1; used += 1; 405*91d632c8Sgwr md_get_uint8(mdp, NULL); 406*91d632c8Sgwr } 407*91d632c8Sgwr nmlen = min(size, SMB_MAXFNAMELEN); 408*91d632c8Sgwr } 409*91d632c8Sgwr 410*91d632c8Sgwr if (ctx->f_name) 411*91d632c8Sgwr kmem_free(ctx->f_name, ctx->f_namesz); 412*91d632c8Sgwr ctx->f_nmlen = nmlen; 413*91d632c8Sgwr /* Add one to prevent allocating size zero. */ 414*91d632c8Sgwr ctx->f_namesz = nmlen + 1; 415*91d632c8Sgwr ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); 416*91d632c8Sgwr error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM); 417*91d632c8Sgwr if (error) 418*91d632c8Sgwr return (error); 419*91d632c8Sgwr used += nmlen; 420*91d632c8Sgwr 421*91d632c8Sgwr /* 422*91d632c8Sgwr * Convert UCS-2 to UTF-8 423*91d632c8Sgwr */ 424*91d632c8Sgwr smbfs_fname_tolocal(ctx); 425*91d632c8Sgwr if (nmlen) 426*91d632c8Sgwr SMBVDEBUG("name: %s\n", ctx->f_name); 427*91d632c8Sgwr else 428*91d632c8Sgwr SMBVDEBUG("null name!\n"); 429*91d632c8Sgwr 430*91d632c8Sgwr /* 431*91d632c8Sgwr * Skip padding until next offset 432*91d632c8Sgwr */ 433*91d632c8Sgwr if (next > used) { 434*91d632c8Sgwr skip = next - used; 435*91d632c8Sgwr md_get_mem(mdp, NULL, skip, MB_MSYSTEM); 436*91d632c8Sgwr } 437*91d632c8Sgwr if (next == 0) 438*91d632c8Sgwr ctx->f_flags |= SMBFS_RDD_EOF; 439*91d632c8Sgwr 440*91d632c8Sgwr /* 441*91d632c8Sgwr * Chop off the trailing ":$DATA" 442*91d632c8Sgwr * The 6 here is strlen(":$DATA") 443*91d632c8Sgwr */ 444*91d632c8Sgwr if (ctx->f_nmlen >= 6) { 445*91d632c8Sgwr char *p = ctx->f_name + ctx->f_nmlen - 6; 446*91d632c8Sgwr if (strncmp(p, ":$DATA", 6) == 0) { 447*91d632c8Sgwr *p = '\0'; /* Chop! */ 448*91d632c8Sgwr ctx->f_nmlen -= 6; 449*91d632c8Sgwr } 450*91d632c8Sgwr } 451*91d632c8Sgwr 452*91d632c8Sgwr /* 453*91d632c8Sgwr * The Chop above will typically leave 454*91d632c8Sgwr * an empty name in the first slot, 455*91d632c8Sgwr * which we will skip here. 456*91d632c8Sgwr */ 457*91d632c8Sgwr if (ctx->f_nmlen == 0) 458*91d632c8Sgwr goto again; 459*91d632c8Sgwr 460*91d632c8Sgwr /* 461*91d632c8Sgwr * If this is a lookup of a specific name, 462*91d632c8Sgwr * skip past any non-matching names. 463*91d632c8Sgwr */ 464*91d632c8Sgwr if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 465*91d632c8Sgwr if (ctx->f_wclen != ctx->f_nmlen) 466*91d632c8Sgwr goto again; 467*91d632c8Sgwr if (u8_strcmp(ctx->f_wildcard, ctx->f_name, 468*91d632c8Sgwr ctx->f_nmlen, U8_STRCMP_CI_LOWER, 469*91d632c8Sgwr U8_UNICODE_LATEST, &error) || error) 470*91d632c8Sgwr goto again; 471*91d632c8Sgwr } 472*91d632c8Sgwr 473*91d632c8Sgwr return (0); 474*91d632c8Sgwr } 475*91d632c8Sgwr 476*91d632c8Sgwr /* 477*91d632c8Sgwr * Find first/next/close for XATTR directories. 478*91d632c8Sgwr * NB: also used by smbfs_smb_lookup 479*91d632c8Sgwr */ 480*91d632c8Sgwr 481*91d632c8Sgwr int 482*91d632c8Sgwr smbfs_xa_findclose(struct smbfs_fctx *ctx) 483*91d632c8Sgwr { 484*91d632c8Sgwr 485*91d632c8Sgwr if (ctx->f_name) 486*91d632c8Sgwr kmem_free(ctx->f_name, ctx->f_namesz); 487*91d632c8Sgwr if (ctx->f_t2) 488*91d632c8Sgwr smb_t2_done(ctx->f_t2); 489*91d632c8Sgwr 490*91d632c8Sgwr return (0); 491*91d632c8Sgwr } 492