191d632c8Sgwr /*
291d632c8Sgwr * CDDL HEADER START
391d632c8Sgwr *
491d632c8Sgwr * The contents of this file are subject to the terms of the
591d632c8Sgwr * Common Development and Distribution License (the "License").
691d632c8Sgwr * You may not use this file except in compliance with the License.
791d632c8Sgwr *
891d632c8Sgwr * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
991d632c8Sgwr * or http://www.opensolaris.org/os/licensing.
1091d632c8Sgwr * See the License for the specific language governing permissions
1191d632c8Sgwr * and limitations under the License.
1291d632c8Sgwr *
1391d632c8Sgwr * When distributing Covered Code, include this CDDL HEADER in each
1491d632c8Sgwr * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1591d632c8Sgwr * If applicable, add the following below this CDDL HEADER, with the
1691d632c8Sgwr * fields enclosed by brackets "[]" replaced with your own identifying
1791d632c8Sgwr * information: Portions Copyright [yyyy] [name of copyright owner]
1891d632c8Sgwr *
1991d632c8Sgwr * CDDL HEADER END
2091d632c8Sgwr */
2191d632c8Sgwr
2291d632c8Sgwr /*
23148c5f43SAlan Wright * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*adee6784SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
2591d632c8Sgwr */
2691d632c8Sgwr
2791d632c8Sgwr /*
2891d632c8Sgwr * Functions supporting Solaris Extended Attributes,
2991d632c8Sgwr * used to provide access to CIFS "named streams".
3091d632c8Sgwr */
3191d632c8Sgwr
3291d632c8Sgwr #include <sys/systm.h>
338329232eSGordon Ross #include <sys/inttypes.h>
3491d632c8Sgwr #include <sys/cred.h>
3591d632c8Sgwr #include <sys/vnode.h>
3691d632c8Sgwr #include <sys/vfs.h>
3791d632c8Sgwr #include <sys/filio.h>
3891d632c8Sgwr #include <sys/uio.h>
3991d632c8Sgwr #include <sys/dirent.h>
4091d632c8Sgwr #include <sys/errno.h>
4191d632c8Sgwr #include <sys/sysmacros.h>
4291d632c8Sgwr #include <sys/kmem.h>
4391d632c8Sgwr #include <sys/stat.h>
4491d632c8Sgwr #include <sys/cmn_err.h>
4591d632c8Sgwr #include <sys/u8_textprep.h>
4691d632c8Sgwr
4791d632c8Sgwr #include <netsmb/smb_osdep.h>
48*adee6784SGordon Ross
4991d632c8Sgwr #include <netsmb/smb.h>
50*adee6784SGordon Ross #include <netsmb/smb2.h>
5191d632c8Sgwr #include <netsmb/smb_conn.h>
5291d632c8Sgwr #include <netsmb/smb_subr.h>
5391d632c8Sgwr #include <netsmb/smb_rq.h>
5491d632c8Sgwr
5591d632c8Sgwr #include <smbfs/smbfs.h>
5691d632c8Sgwr #include <smbfs/smbfs_node.h>
5791d632c8Sgwr #include <smbfs/smbfs_subr.h>
5891d632c8Sgwr
5991d632c8Sgwr #include <fs/fs_subr.h>
6091d632c8Sgwr
6191d632c8Sgwr /*
6291d632c8Sgwr * Solaris wants there to be a directory node to contain
6391d632c8Sgwr * all the extended attributes. The SMB protocol does not
6491d632c8Sgwr * really support a directory here, and uses very different
6591d632c8Sgwr * operations to list attributes, etc. so we "fake up" an
6691d632c8Sgwr * smbnode here to represent the attributes directory.
6791d632c8Sgwr *
6891d632c8Sgwr * We need to give this (fake) directory a unique identity,
6991d632c8Sgwr * and since we're using the full remote pathname as the
7091d632c8Sgwr * unique identity of all nodes, the easiest thing to do
7191d632c8Sgwr * here is append a colon (:) to the given pathname.
7291d632c8Sgwr *
7391d632c8Sgwr * There are several places where smbfs_fullpath and its
7491d632c8Sgwr * callers must decide what separator to use when building
7591d632c8Sgwr * a remote path name, and the rule is now as follows:
7691d632c8Sgwr * 1: When no XATTR involved, use "\\" as the separator.
7791d632c8Sgwr * 2: Traversal into the (fake) XATTR dir adds one ":"
7891d632c8Sgwr * 3: Children of the XATTR dir add nothing (sep=0)
7991d632c8Sgwr * The result should be _one_ colon before the attr name.
8091d632c8Sgwr */
8191d632c8Sgwr
8291d632c8Sgwr /* ARGSUSED */
8391d632c8Sgwr int
smbfs_get_xattrdir(vnode_t * pvp,vnode_t ** vpp,cred_t * cr,int flags)8491d632c8Sgwr smbfs_get_xattrdir(vnode_t *pvp, vnode_t **vpp, cred_t *cr, int flags)
8591d632c8Sgwr {
8691d632c8Sgwr vnode_t *xvp;
8791d632c8Sgwr smbnode_t *pnp, *xnp;
8891d632c8Sgwr
8991d632c8Sgwr pnp = VTOSMB(pvp);
9091d632c8Sgwr
9102d09e03SGordon Ross /*
9202d09e03SGordon Ross * We don't allow recursive extended attributes
9302d09e03SGordon Ross * (xattr under xattr dir.) so the "parent" node
9402d09e03SGordon Ross * (pnp) must NOT be an XATTR directory or file.
9502d09e03SGordon Ross */
9602d09e03SGordon Ross if (pnp->n_flag & N_XATTR)
9702d09e03SGordon Ross return (EINVAL);
9802d09e03SGordon Ross
9902d09e03SGordon Ross xnp = smbfs_node_findcreate(pnp->n_mount,
10002d09e03SGordon Ross pnp->n_rpath, pnp->n_rplen, NULL, 0, ':',
10102d09e03SGordon Ross &smbfs_fattr0); /* force create */
10202d09e03SGordon Ross ASSERT(xnp != NULL);
10302d09e03SGordon Ross xvp = SMBTOV(xnp);
10491d632c8Sgwr /* Note: xvp has a VN_HOLD, which our caller expects. */
10591d632c8Sgwr
10691d632c8Sgwr /* If it's a new node, initialize. */
10791d632c8Sgwr if (xvp->v_type == VNON) {
10891d632c8Sgwr
10991d632c8Sgwr mutex_enter(&xvp->v_lock);
11091d632c8Sgwr xvp->v_type = VDIR;
11191d632c8Sgwr xvp->v_flag |= V_XATTRDIR;
11291d632c8Sgwr mutex_exit(&xvp->v_lock);
11391d632c8Sgwr
11491d632c8Sgwr mutex_enter(&xnp->r_statelock);
11591d632c8Sgwr xnp->n_flag |= N_XATTR;
11691d632c8Sgwr mutex_exit(&xnp->r_statelock);
11791d632c8Sgwr }
11891d632c8Sgwr
11991d632c8Sgwr /* Success! */
12091d632c8Sgwr *vpp = xvp;
12191d632c8Sgwr return (0);
12291d632c8Sgwr }
12391d632c8Sgwr
12491d632c8Sgwr /*
12591d632c8Sgwr * Find the parent of an XATTR directory or file,
12691d632c8Sgwr * by trimming off the ":attrname" part of rpath.
12791d632c8Sgwr * Called on XATTR files to get the XATTR dir, and
12891d632c8Sgwr * called on the XATTR dir to get the real object
12991d632c8Sgwr * under which the (faked up) XATTR dir lives.
13091d632c8Sgwr */
13191d632c8Sgwr int
smbfs_xa_parent(vnode_t * vp,vnode_t ** vpp)13291d632c8Sgwr smbfs_xa_parent(vnode_t *vp, vnode_t **vpp)
13391d632c8Sgwr {
13491d632c8Sgwr smbnode_t *np = VTOSMB(vp);
13502d09e03SGordon Ross smbnode_t *pnp;
13691d632c8Sgwr int rplen;
13791d632c8Sgwr
13802d09e03SGordon Ross *vpp = NULL;
13902d09e03SGordon Ross
14091d632c8Sgwr if ((np->n_flag & N_XATTR) == 0)
14191d632c8Sgwr return (EINVAL);
14291d632c8Sgwr
14391d632c8Sgwr if (vp->v_flag & V_XATTRDIR) {
14491d632c8Sgwr /*
14591d632c8Sgwr * Want the parent of the XATTR directory.
14691d632c8Sgwr * That's easy: just remove trailing ":"
14791d632c8Sgwr */
14891d632c8Sgwr rplen = np->n_rplen - 1;
14991d632c8Sgwr if (rplen < 1) {
15091d632c8Sgwr SMBVDEBUG("rplen < 1?");
15191d632c8Sgwr return (ENOENT);
15291d632c8Sgwr }
15391d632c8Sgwr if (np->n_rpath[rplen] != ':') {
15491d632c8Sgwr SMBVDEBUG("last is not colon");
15591d632c8Sgwr return (ENOENT);
15691d632c8Sgwr }
15791d632c8Sgwr } else {
15891d632c8Sgwr /*
15991d632c8Sgwr * Want the XATTR directory given
16091d632c8Sgwr * one of its XATTR files (children).
16191d632c8Sgwr * Find the ":" and trim after it.
16291d632c8Sgwr */
16391d632c8Sgwr for (rplen = 1; rplen < np->n_rplen; rplen++)
16491d632c8Sgwr if (np->n_rpath[rplen] == ':')
16591d632c8Sgwr break;
16691d632c8Sgwr /* Should have found ":stream_name" */
16791d632c8Sgwr if (rplen >= np->n_rplen) {
16891d632c8Sgwr SMBVDEBUG("colon not found");
16991d632c8Sgwr return (ENOENT);
17091d632c8Sgwr }
17191d632c8Sgwr rplen++; /* keep the ":" */
17291d632c8Sgwr if (rplen >= np->n_rplen) {
17391d632c8Sgwr SMBVDEBUG("no stream name");
17491d632c8Sgwr return (ENOENT);
17591d632c8Sgwr }
17691d632c8Sgwr }
17791d632c8Sgwr
17802d09e03SGordon Ross pnp = smbfs_node_findcreate(np->n_mount,
17902d09e03SGordon Ross np->n_rpath, rplen, NULL, 0, 0,
18002d09e03SGordon Ross &smbfs_fattr0); /* force create */
18102d09e03SGordon Ross ASSERT(pnp != NULL);
18202d09e03SGordon Ross /* Note: have VN_HOLD from smbfs_node_findcreate */
18302d09e03SGordon Ross *vpp = SMBTOV(pnp);
18491d632c8Sgwr return (0);
18591d632c8Sgwr }
18691d632c8Sgwr
18791d632c8Sgwr /*
18891d632c8Sgwr * This is called by smbfs_pathconf to find out
18991d632c8Sgwr * if some file has any extended attributes.
19091d632c8Sgwr * There's no short-cut way to find out, so we
19191d632c8Sgwr * just list the attributes the usual way and
19291d632c8Sgwr * check for an empty result.
19391d632c8Sgwr *
19491d632c8Sgwr * Returns 1: (exists) or 0: (none found)
19591d632c8Sgwr */
19691d632c8Sgwr int
smbfs_xa_exists(vnode_t * vp,cred_t * cr)19791d632c8Sgwr smbfs_xa_exists(vnode_t *vp, cred_t *cr)
19891d632c8Sgwr {
19991d632c8Sgwr smbnode_t *xnp;
20091d632c8Sgwr vnode_t *xvp;
20191d632c8Sgwr struct smb_cred scred;
20291d632c8Sgwr struct smbfs_fctx ctx;
20391d632c8Sgwr int error, rc = 0;
20491d632c8Sgwr
20591d632c8Sgwr /* Get the xattr dir */
20691d632c8Sgwr error = smbfs_get_xattrdir(vp, &xvp, cr, LOOKUP_XATTR);
20791d632c8Sgwr if (error)
20891d632c8Sgwr return (0);
20991d632c8Sgwr /* NB: have VN_HOLD on xpv */
21091d632c8Sgwr xnp = VTOSMB(xvp);
21191d632c8Sgwr
212613a2f6bSGordon Ross smb_credinit(&scred, cr);
21391d632c8Sgwr
21491d632c8Sgwr bzero(&ctx, sizeof (ctx));
21591d632c8Sgwr ctx.f_flags = SMBFS_RDD_FINDFIRST;
21691d632c8Sgwr ctx.f_dnp = xnp;
21791d632c8Sgwr ctx.f_scred = &scred;
21891d632c8Sgwr ctx.f_ssp = xnp->n_mount->smi_share;
21991d632c8Sgwr
22091d632c8Sgwr error = smbfs_xa_findopen(&ctx, xnp, "*", 1);
22191d632c8Sgwr if (error)
22291d632c8Sgwr goto out;
22391d632c8Sgwr
22491d632c8Sgwr error = smbfs_xa_findnext(&ctx, 1);
22591d632c8Sgwr if (error)
22691d632c8Sgwr goto out;
22791d632c8Sgwr
22891d632c8Sgwr /* Have at least one named stream. */
22991d632c8Sgwr SMBVDEBUG("ctx.f_name: %s\n", ctx.f_name);
23091d632c8Sgwr rc = 1;
23191d632c8Sgwr
23291d632c8Sgwr out:
23391d632c8Sgwr /* NB: Always call findclose, error or not. */
23491d632c8Sgwr (void) smbfs_xa_findclose(&ctx);
23591d632c8Sgwr smb_credrele(&scred);
23691d632c8Sgwr VN_RELE(xvp);
23791d632c8Sgwr return (rc);
23891d632c8Sgwr }
23991d632c8Sgwr
24091d632c8Sgwr
24191d632c8Sgwr /*
24291d632c8Sgwr * This is called to get attributes (size, etc.) of either
24391d632c8Sgwr * the "faked up" XATTR directory or a named stream.
24491d632c8Sgwr */
24591d632c8Sgwr int
smbfs_xa_getfattr(struct smbnode * xnp,struct smbfattr * fap,struct smb_cred * scrp)24691d632c8Sgwr smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap,
24791d632c8Sgwr struct smb_cred *scrp)
24891d632c8Sgwr {
24991d632c8Sgwr vnode_t *xvp; /* xattr */
25091d632c8Sgwr vnode_t *pvp; /* parent */
25191d632c8Sgwr smbnode_t *pnp; /* parent */
25291d632c8Sgwr int error, nlen;
25391d632c8Sgwr const char *name, *sname;
25491d632c8Sgwr
25591d632c8Sgwr xvp = SMBTOV(xnp);
25691d632c8Sgwr
25791d632c8Sgwr /*
25891d632c8Sgwr * Simulate smbfs_smb_getfattr() for a named stream.
25991d632c8Sgwr * OK to leave a,c,m times zero (expected w/ XATTR).
26091d632c8Sgwr * The XATTR directory is easy (all fake).
26191d632c8Sgwr */
26291d632c8Sgwr if (xvp->v_flag & V_XATTRDIR) {
26391d632c8Sgwr fap->fa_attr = SMB_FA_DIR;
26491d632c8Sgwr fap->fa_size = DEV_BSIZE;
26591d632c8Sgwr return (0);
26691d632c8Sgwr }
26791d632c8Sgwr
26891d632c8Sgwr /*
26991d632c8Sgwr * Do a lookup in the XATTR directory,
27091d632c8Sgwr * using the stream name (last part)
27191d632c8Sgwr * from the xattr node.
27291d632c8Sgwr */
27391d632c8Sgwr error = smbfs_xa_parent(xvp, &pvp);
27491d632c8Sgwr if (error)
27591d632c8Sgwr return (error);
27691d632c8Sgwr /* Note: pvp has a VN_HOLD */
27791d632c8Sgwr pnp = VTOSMB(pvp);
27891d632c8Sgwr
27991d632c8Sgwr /* Get stream name (ptr and length) */
28091d632c8Sgwr ASSERT(xnp->n_rplen > pnp->n_rplen);
28191d632c8Sgwr nlen = xnp->n_rplen - pnp->n_rplen;
28291d632c8Sgwr name = xnp->n_rpath + pnp->n_rplen;
28391d632c8Sgwr sname = name;
28491d632c8Sgwr
28591d632c8Sgwr /* Note: this can allocate a new "name" */
28691d632c8Sgwr error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp);
28791d632c8Sgwr if (error == 0 && name != sname)
28891d632c8Sgwr smbfs_name_free(name, nlen);
28991d632c8Sgwr
29091d632c8Sgwr VN_RELE(pvp);
29191d632c8Sgwr
29291d632c8Sgwr return (error);
29391d632c8Sgwr }
29491d632c8Sgwr
29591d632c8Sgwr /*
296*adee6784SGordon Ross * Actually go OtW to get the list of "streams".
29791d632c8Sgwr *
29891d632c8Sgwr * This is called on the XATTR directory, so we
29991d632c8Sgwr * have to get the (real) parent object first.
30091d632c8Sgwr */
301*adee6784SGordon Ross static int
smbfs_xa_get_streaminfo(struct smbfs_fctx * ctx)302*adee6784SGordon Ross smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)
30391d632c8Sgwr {
30491d632c8Sgwr vnode_t *pvp; /* parent */
30591d632c8Sgwr smbnode_t *pnp;
306*adee6784SGordon Ross smbnode_t *dnp = ctx->f_dnp;
307*adee6784SGordon Ross struct mdchain *mdp;
30891d632c8Sgwr int error;
30991d632c8Sgwr
31091d632c8Sgwr error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
31191d632c8Sgwr if (error)
31291d632c8Sgwr return (error);
31391d632c8Sgwr ASSERT(pvp);
31491d632c8Sgwr /* Note: pvp has a VN_HOLD */
31591d632c8Sgwr pnp = VTOSMB(pvp);
31691d632c8Sgwr
317*adee6784SGordon Ross /*
318*adee6784SGordon Ross * Get stream info into f_mdchain
319*adee6784SGordon Ross */
320*adee6784SGordon Ross mdp = &ctx->f_mdchain;
321*adee6784SGordon Ross md_done(mdp);
32291d632c8Sgwr
323*adee6784SGordon Ross if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
324*adee6784SGordon Ross error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
325*adee6784SGordon Ross } else {
326*adee6784SGordon Ross error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
327*adee6784SGordon Ross }
32891d632c8Sgwr if (error)
32991d632c8Sgwr goto out;
33091d632c8Sgwr
33191d632c8Sgwr /*
332*adee6784SGordon Ross * Have stream info in ctx->f_mdchain
333*adee6784SGordon Ross * Initialize buffer length, position.
33491d632c8Sgwr */
335*adee6784SGordon Ross ctx->f_left = m_fixhdr(mdp->md_top);
336*adee6784SGordon Ross ctx->f_eofs = 0;
337*adee6784SGordon Ross
338*adee6784SGordon Ross /*
339*adee6784SGordon Ross * After one successful call, we're at EOF.
340*adee6784SGordon Ross */
341*adee6784SGordon Ross ctx->f_flags |= SMBFS_RDD_EOF;
34291d632c8Sgwr
34391d632c8Sgwr out:
34491d632c8Sgwr VN_RELE(pvp);
34591d632c8Sgwr return (error);
34691d632c8Sgwr }
34791d632c8Sgwr
34891d632c8Sgwr /*
349*adee6784SGordon Ross * Get a buffer of directory entries (if we don't already have
350*adee6784SGordon Ross * some remaining in the current buffer) then decode one.
35191d632c8Sgwr */
35291d632c8Sgwr int
smbfs_xa_findopen(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen)353*adee6784SGordon Ross smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
354*adee6784SGordon Ross const char *wildcard, int wclen)
35591d632c8Sgwr {
35691d632c8Sgwr
357*adee6784SGordon Ross ASSERT(dnp->n_flag & N_XATTR);
35891d632c8Sgwr
359*adee6784SGordon Ross ctx->f_type = ft_XA;
360*adee6784SGordon Ross ctx->f_namesz = SMB_MAXFNAMELEN + 1;
361*adee6784SGordon Ross ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
362*adee6784SGordon Ross ctx->f_infolevel = FileStreamInformation;
363*adee6784SGordon Ross ctx->f_wildcard = wildcard;
364*adee6784SGordon Ross ctx->f_wclen = wclen;
36591d632c8Sgwr
366*adee6784SGordon Ross return (0);
367*adee6784SGordon Ross }
36891d632c8Sgwr
36991d632c8Sgwr
370*adee6784SGordon Ross /*
371*adee6784SGordon Ross * Get the next name in an XATTR directory
372*adee6784SGordon Ross */
373*adee6784SGordon Ross /* ARGSUSED */
374*adee6784SGordon Ross int
smbfs_xa_findnext(struct smbfs_fctx * ctx,uint16_t limit)375*adee6784SGordon Ross smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
376*adee6784SGordon Ross {
377*adee6784SGordon Ross int error;
37891d632c8Sgwr
37991d632c8Sgwr /*
380*adee6784SGordon Ross * If we've scanned to the end of the current buffer
381*adee6784SGordon Ross * try to read anohther buffer of dir entries.
382*adee6784SGordon Ross * Treat anything less than 8 bytes as an "empty"
383*adee6784SGordon Ross * buffer to ensure we can read something.
384*adee6784SGordon Ross * (There may be up to 8 bytes of padding.)
38591d632c8Sgwr */
386*adee6784SGordon Ross again:
387*adee6784SGordon Ross if ((ctx->f_eofs + 8) > ctx->f_left) {
388*adee6784SGordon Ross /* Scanned the whole buffer. */
389*adee6784SGordon Ross if (ctx->f_flags & SMBFS_RDD_EOF)
390*adee6784SGordon Ross return (ENOENT);
391*adee6784SGordon Ross ctx->f_limit = limit;
392*adee6784SGordon Ross error = smbfs_xa_get_streaminfo(ctx);
393*adee6784SGordon Ross if (error)
394*adee6784SGordon Ross return (error);
395*adee6784SGordon Ross ctx->f_otws++;
396*adee6784SGordon Ross }
39791d632c8Sgwr
39891d632c8Sgwr /*
399*adee6784SGordon Ross * Decode one entry, advance f_eofs
40091d632c8Sgwr */
401*adee6784SGordon Ross error = smbfs_decode_dirent(ctx);
402*adee6784SGordon Ross if (error)
403*adee6784SGordon Ross return (error);
404*adee6784SGordon Ross SMBVDEBUG("name: %s\n", ctx->f_name);
40591d632c8Sgwr
40691d632c8Sgwr /*
40791d632c8Sgwr * Chop off the trailing ":$DATA"
40891d632c8Sgwr * The 6 here is strlen(":$DATA")
40991d632c8Sgwr */
41091d632c8Sgwr if (ctx->f_nmlen >= 6) {
41191d632c8Sgwr char *p = ctx->f_name + ctx->f_nmlen - 6;
41291d632c8Sgwr if (strncmp(p, ":$DATA", 6) == 0) {
41391d632c8Sgwr *p = '\0'; /* Chop! */
41491d632c8Sgwr ctx->f_nmlen -= 6;
41591d632c8Sgwr }
41691d632c8Sgwr }
41791d632c8Sgwr
41891d632c8Sgwr /*
41991d632c8Sgwr * The Chop above will typically leave
42091d632c8Sgwr * an empty name in the first slot,
42191d632c8Sgwr * which we will skip here.
42291d632c8Sgwr */
42391d632c8Sgwr if (ctx->f_nmlen == 0)
42491d632c8Sgwr goto again;
42591d632c8Sgwr
42691d632c8Sgwr /*
427*adee6784SGordon Ross * When called by lookup, we'll have the "single" flag,
428*adee6784SGordon Ross * and a name with no wildcards. We need to filter here
429*adee6784SGordon Ross * because smbfs_xa_get_streaminfo() gets ALL the names
430*adee6784SGordon Ross * (not just those matching our pattern).
43191d632c8Sgwr */
43291d632c8Sgwr if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
43391d632c8Sgwr if (ctx->f_wclen != ctx->f_nmlen)
43491d632c8Sgwr goto again;
43591d632c8Sgwr if (u8_strcmp(ctx->f_wildcard, ctx->f_name,
43691d632c8Sgwr ctx->f_nmlen, U8_STRCMP_CI_LOWER,
43791d632c8Sgwr U8_UNICODE_LATEST, &error) || error)
43891d632c8Sgwr goto again;
43991d632c8Sgwr }
44091d632c8Sgwr
44191d632c8Sgwr return (0);
44291d632c8Sgwr }
44391d632c8Sgwr
44491d632c8Sgwr /*
44591d632c8Sgwr * Find first/next/close for XATTR directories.
44691d632c8Sgwr * NB: also used by smbfs_smb_lookup
44791d632c8Sgwr */
44891d632c8Sgwr
44991d632c8Sgwr int
smbfs_xa_findclose(struct smbfs_fctx * ctx)45091d632c8Sgwr smbfs_xa_findclose(struct smbfs_fctx *ctx)
45191d632c8Sgwr {
45291d632c8Sgwr
45391d632c8Sgwr if (ctx->f_name)
45491d632c8Sgwr kmem_free(ctx->f_name, ctx->f_namesz);
45591d632c8Sgwr
45691d632c8Sgwr return (0);
45791d632c8Sgwr }
458