19749STim.Haley@Sun.COM /*
29749STim.Haley@Sun.COM * CDDL HEADER START
39749STim.Haley@Sun.COM *
49749STim.Haley@Sun.COM * The contents of this file are subject to the terms of the
59749STim.Haley@Sun.COM * Common Development and Distribution License (the "License").
69749STim.Haley@Sun.COM * You may not use this file except in compliance with the License.
79749STim.Haley@Sun.COM *
89749STim.Haley@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99749STim.Haley@Sun.COM * or http://www.opensolaris.org/os/licensing.
109749STim.Haley@Sun.COM * See the License for the specific language governing permissions
119749STim.Haley@Sun.COM * and limitations under the License.
129749STim.Haley@Sun.COM *
139749STim.Haley@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149749STim.Haley@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159749STim.Haley@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169749STim.Haley@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179749STim.Haley@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189749STim.Haley@Sun.COM *
199749STim.Haley@Sun.COM * CDDL HEADER END
209749STim.Haley@Sun.COM */
219749STim.Haley@Sun.COM /*
22*13082SJoyce.McIntosh@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
239749STim.Haley@Sun.COM */
249749STim.Haley@Sun.COM
259749STim.Haley@Sun.COM #include <sys/conf.h>
269749STim.Haley@Sun.COM #include <sys/stat.h>
279749STim.Haley@Sun.COM #include <sys/file.h>
289749STim.Haley@Sun.COM #include <sys/types.h>
299749STim.Haley@Sun.COM #include <sys/pathname.h>
309749STim.Haley@Sun.COM #include <sys/proc.h>
319749STim.Haley@Sun.COM #include <sys/mode.h>
329749STim.Haley@Sun.COM #include <sys/vnode.h>
339749STim.Haley@Sun.COM #include <sys/ddi.h>
349749STim.Haley@Sun.COM #include <sys/sunddi.h>
359749STim.Haley@Sun.COM #include <sys/sunldi.h>
369749STim.Haley@Sun.COM #include <sys/uio.h>
379749STim.Haley@Sun.COM #include <sys/attr.h>
389749STim.Haley@Sun.COM #include <sys/acl.h>
399749STim.Haley@Sun.COM #include <sys/fs/zut.h>
409749STim.Haley@Sun.COM
419749STim.Haley@Sun.COM ldi_ident_t zut_li = NULL;
429749STim.Haley@Sun.COM dev_info_t *zut_dip;
439749STim.Haley@Sun.COM
449749STim.Haley@Sun.COM static int
zut_open_dir(char * path,vnode_t * startvp,cred_t * cr,int flags,pathname_t * realpn,vnode_t ** dvn)459749STim.Haley@Sun.COM zut_open_dir(char *path, vnode_t *startvp, cred_t *cr, int flags,
469749STim.Haley@Sun.COM pathname_t *realpn, vnode_t **dvn)
479749STim.Haley@Sun.COM {
489749STim.Haley@Sun.COM pathname_t pn;
499749STim.Haley@Sun.COM vnode_t *vp;
509749STim.Haley@Sun.COM vnode_t *rootvp;
519749STim.Haley@Sun.COM proc_t *p = curproc;
529749STim.Haley@Sun.COM int error;
539749STim.Haley@Sun.COM
549749STim.Haley@Sun.COM pn_alloc(&pn);
559749STim.Haley@Sun.COM (void) strlcpy(pn.pn_buf, path, MAXPATHLEN);
569749STim.Haley@Sun.COM pn.pn_pathlen = strlen(path);
579749STim.Haley@Sun.COM
589749STim.Haley@Sun.COM mutex_enter(&p->p_lock); /* for u_rdir and u_cdir */
599749STim.Haley@Sun.COM if ((rootvp = PTOU(p)->u_rdir) == NULL)
609749STim.Haley@Sun.COM rootvp = rootdir;
619749STim.Haley@Sun.COM else if (rootvp != rootdir) /* no need to VN_HOLD rootdir */
629749STim.Haley@Sun.COM VN_HOLD(rootvp);
639749STim.Haley@Sun.COM
649749STim.Haley@Sun.COM if (pn.pn_path[0] == '/') {
659749STim.Haley@Sun.COM vp = rootvp;
669749STim.Haley@Sun.COM } else {
679749STim.Haley@Sun.COM vp = (startvp == NULL) ? PTOU(p)->u_cdir : startvp;
689749STim.Haley@Sun.COM }
699749STim.Haley@Sun.COM VN_HOLD(vp);
709749STim.Haley@Sun.COM mutex_exit(&p->p_lock);
719749STim.Haley@Sun.COM
729749STim.Haley@Sun.COM /*
739749STim.Haley@Sun.COM * Skip over leading slashes
749749STim.Haley@Sun.COM */
759749STim.Haley@Sun.COM while (pn.pn_path[0] == '/') {
769749STim.Haley@Sun.COM pn.pn_path++;
779749STim.Haley@Sun.COM pn.pn_pathlen--;
789749STim.Haley@Sun.COM }
799749STim.Haley@Sun.COM
809749STim.Haley@Sun.COM error = lookuppnvp(&pn, realpn, flags | FOLLOW, NULL,
819749STim.Haley@Sun.COM dvn, rootvp, vp, cr);
829749STim.Haley@Sun.COM
839749STim.Haley@Sun.COM /*
849749STim.Haley@Sun.COM * If we lack read access to the directory, we should error out.
859749STim.Haley@Sun.COM */
869749STim.Haley@Sun.COM if (!error) {
879749STim.Haley@Sun.COM if (vfs_has_feature((*dvn)->v_vfsp, VFSFT_ACEMASKONACCESS)) {
889749STim.Haley@Sun.COM error = VOP_ACCESS(*dvn, ACE_LIST_DIRECTORY,
899749STim.Haley@Sun.COM V_ACE_MASK, cr, NULL);
909749STim.Haley@Sun.COM } else {
919749STim.Haley@Sun.COM error = VOP_ACCESS(*dvn, VREAD, 0, cr, NULL);
929749STim.Haley@Sun.COM }
939749STim.Haley@Sun.COM }
949749STim.Haley@Sun.COM
959749STim.Haley@Sun.COM pn_free(&pn);
969749STim.Haley@Sun.COM
979749STim.Haley@Sun.COM return (error);
989749STim.Haley@Sun.COM }
999749STim.Haley@Sun.COM
1009749STim.Haley@Sun.COM static int
zut_readdir(intptr_t arg,cred_t * cr,int iflag,int * rvalp)1019749STim.Haley@Sun.COM zut_readdir(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
1029749STim.Haley@Sun.COM {
1039749STim.Haley@Sun.COM zut_readdir_t *zr;
1049749STim.Haley@Sun.COM struct iovec aiov;
1059749STim.Haley@Sun.COM struct uio auio;
1069749STim.Haley@Sun.COM vnode_t *dvn = NULL;
1079749STim.Haley@Sun.COM vnode_t *fvn = NULL;
1089749STim.Haley@Sun.COM char *kbuf;
1099749STim.Haley@Sun.COM int flags = 0;
1109749STim.Haley@Sun.COM int error, rc;
1119749STim.Haley@Sun.COM
1129749STim.Haley@Sun.COM zr = kmem_zalloc(sizeof (zut_readdir_t), KM_SLEEP);
1139749STim.Haley@Sun.COM error = ddi_copyin((void *)arg, zr, sizeof (zut_readdir_t), iflag);
1149749STim.Haley@Sun.COM if (error)
1159749STim.Haley@Sun.COM goto zutr_bail;
1169749STim.Haley@Sun.COM
1179749STim.Haley@Sun.COM kbuf = kmem_zalloc(zr->zr_buflen, KM_SLEEP);
1189749STim.Haley@Sun.COM
1199749STim.Haley@Sun.COM zr->zr_retcode = zut_open_dir(zr->zr_dir, NULL, cr, flags, NULL, &dvn);
1209749STim.Haley@Sun.COM if (zr->zr_retcode)
1219749STim.Haley@Sun.COM goto zutr_done;
1229749STim.Haley@Sun.COM
1239749STim.Haley@Sun.COM if (zr->zr_reqflags & ZUT_XATTR) {
1249749STim.Haley@Sun.COM vattr_t vattr;
1259749STim.Haley@Sun.COM
1269749STim.Haley@Sun.COM zr->zr_retcode = VOP_LOOKUP(dvn, zr->zr_file, &fvn,
1279749STim.Haley@Sun.COM NULL, flags, NULL, cr, NULL, NULL, NULL);
1289749STim.Haley@Sun.COM VN_RELE(dvn);
1299749STim.Haley@Sun.COM dvn = NULL;
1309749STim.Haley@Sun.COM if (zr->zr_retcode)
1319749STim.Haley@Sun.COM goto zutr_done;
1329749STim.Haley@Sun.COM
1339749STim.Haley@Sun.COM /*
1349749STim.Haley@Sun.COM * In order to access hidden attribute directory the
1359749STim.Haley@Sun.COM * user must have appropriate read access and be able
1369749STim.Haley@Sun.COM * to stat() the file
1379749STim.Haley@Sun.COM */
1389749STim.Haley@Sun.COM if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
1399749STim.Haley@Sun.COM zr->zr_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
1409749STim.Haley@Sun.COM V_ACE_MASK, cr, NULL);
1419749STim.Haley@Sun.COM } else {
1429749STim.Haley@Sun.COM zr->zr_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
1439749STim.Haley@Sun.COM }
1449749STim.Haley@Sun.COM if (zr->zr_retcode)
1459749STim.Haley@Sun.COM goto zutr_done;
1469749STim.Haley@Sun.COM
1479749STim.Haley@Sun.COM vattr.va_mask = AT_ALL;
1489749STim.Haley@Sun.COM zr->zr_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
1499749STim.Haley@Sun.COM if (zr->zr_retcode)
1509749STim.Haley@Sun.COM goto zutr_done;
1519749STim.Haley@Sun.COM
1529749STim.Haley@Sun.COM zr->zr_retcode = VOP_LOOKUP(fvn, "", &dvn, NULL,
1539749STim.Haley@Sun.COM flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
1549749STim.Haley@Sun.COM VN_RELE(fvn);
1559749STim.Haley@Sun.COM if (zr->zr_retcode)
1569749STim.Haley@Sun.COM goto zutr_done;
1579749STim.Haley@Sun.COM }
1589749STim.Haley@Sun.COM
1599749STim.Haley@Sun.COM aiov.iov_base = kbuf;
1609749STim.Haley@Sun.COM aiov.iov_len = zr->zr_buflen;
1619749STim.Haley@Sun.COM auio.uio_iov = &aiov;
1629749STim.Haley@Sun.COM auio.uio_iovcnt = 1;
1639749STim.Haley@Sun.COM auio.uio_loffset = zr->zr_loffset;
1649749STim.Haley@Sun.COM auio.uio_segflg = UIO_SYSSPACE;
1659749STim.Haley@Sun.COM auio.uio_resid = zr->zr_buflen;
1669749STim.Haley@Sun.COM auio.uio_fmode = 0;
1679749STim.Haley@Sun.COM auio.uio_extflg = UIO_COPY_CACHED;
1689749STim.Haley@Sun.COM
1699749STim.Haley@Sun.COM if (zr->zr_reqflags & ZUT_EXTRDDIR)
1709749STim.Haley@Sun.COM flags |= V_RDDIR_ENTFLAGS;
1719749STim.Haley@Sun.COM if (zr->zr_reqflags & ZUT_ACCFILTER)
1729749STim.Haley@Sun.COM flags |= V_RDDIR_ACCFILTER;
1739749STim.Haley@Sun.COM
1749749STim.Haley@Sun.COM (void) VOP_RWLOCK(dvn, V_WRITELOCK_FALSE, NULL);
1759749STim.Haley@Sun.COM zr->zr_retcode = VOP_READDIR(dvn, &auio, cr, &zr->zr_eof,
1769749STim.Haley@Sun.COM NULL, flags);
1779749STim.Haley@Sun.COM VOP_RWUNLOCK(dvn, V_WRITELOCK_FALSE, NULL);
1789749STim.Haley@Sun.COM VN_RELE(dvn);
1799749STim.Haley@Sun.COM
1809749STim.Haley@Sun.COM zr->zr_bytes = aiov.iov_base - kbuf;
1819749STim.Haley@Sun.COM zr->zr_loffset = auio.uio_loffset;
1829749STim.Haley@Sun.COM
1839749STim.Haley@Sun.COM error = ddi_copyout(kbuf, (void *)(uintptr_t)zr->zr_buf,
1849749STim.Haley@Sun.COM zr->zr_buflen, iflag);
1859749STim.Haley@Sun.COM
1869749STim.Haley@Sun.COM zutr_done:
1879749STim.Haley@Sun.COM kmem_free(kbuf, zr->zr_buflen);
1889749STim.Haley@Sun.COM rc = ddi_copyout(zr, (void *)arg, sizeof (zut_readdir_t), iflag);
1899749STim.Haley@Sun.COM if (error == 0)
1909749STim.Haley@Sun.COM error = rc;
1919749STim.Haley@Sun.COM
1929749STim.Haley@Sun.COM zutr_bail:
1939749STim.Haley@Sun.COM kmem_free(zr, sizeof (zut_readdir_t));
1949749STim.Haley@Sun.COM if (rvalp)
1959749STim.Haley@Sun.COM *rvalp = error;
1969749STim.Haley@Sun.COM return (error);
1979749STim.Haley@Sun.COM }
1989749STim.Haley@Sun.COM
1999749STim.Haley@Sun.COM static int
zut_stat64(vnode_t * vp,struct stat64 * sb,uint64_t * xvs,int flag,cred_t * cr)2009749STim.Haley@Sun.COM zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
2019749STim.Haley@Sun.COM {
2029749STim.Haley@Sun.COM xoptattr_t *xoap = NULL;
2039749STim.Haley@Sun.COM xvattr_t xv = { 0 };
2049749STim.Haley@Sun.COM int error;
2059749STim.Haley@Sun.COM
2069749STim.Haley@Sun.COM xva_init(&xv);
2079749STim.Haley@Sun.COM
2089749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_ARCHIVE);
2099749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_SYSTEM);
2109749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_READONLY);
2119749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_HIDDEN);
2129749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_NOUNLINK);
2139749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_IMMUTABLE);
2149749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_APPENDONLY);
2159749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_NODUMP);
2169749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_OPAQUE);
2179749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
2189749STim.Haley@Sun.COM XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
21910793Sdai.ngo@sun.com XVA_SET_REQ(&xv, XAT_REPARSE);
220*13082SJoyce.McIntosh@Sun.COM XVA_SET_REQ(&xv, XAT_OFFLINE);
221*13082SJoyce.McIntosh@Sun.COM XVA_SET_REQ(&xv, XAT_SPARSE);
2229749STim.Haley@Sun.COM
2239749STim.Haley@Sun.COM xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
2249749STim.Haley@Sun.COM if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
2259749STim.Haley@Sun.COM return (error);
2269749STim.Haley@Sun.COM
2279749STim.Haley@Sun.COM bzero(sb, sizeof (sb));
2289749STim.Haley@Sun.COM sb->st_dev = xv.xva_vattr.va_fsid;
2299749STim.Haley@Sun.COM sb->st_ino = xv.xva_vattr.va_nodeid;
2309749STim.Haley@Sun.COM sb->st_mode = VTTOIF(xv.xva_vattr.va_type) | xv.xva_vattr.va_mode;
2319749STim.Haley@Sun.COM sb->st_nlink = xv.xva_vattr.va_nlink;
2329749STim.Haley@Sun.COM sb->st_uid = xv.xva_vattr.va_uid;
2339749STim.Haley@Sun.COM sb->st_gid = xv.xva_vattr.va_gid;
2349749STim.Haley@Sun.COM sb->st_rdev = xv.xva_vattr.va_rdev;
2359749STim.Haley@Sun.COM sb->st_size = xv.xva_vattr.va_size;
2369749STim.Haley@Sun.COM sb->st_atim = xv.xva_vattr.va_atime;
2379749STim.Haley@Sun.COM sb->st_mtim = xv.xva_vattr.va_mtime;
2389749STim.Haley@Sun.COM sb->st_ctim = xv.xva_vattr.va_ctime;
2399749STim.Haley@Sun.COM sb->st_blksize = xv.xva_vattr.va_blksize;
2409749STim.Haley@Sun.COM sb->st_blocks = xv.xva_vattr.va_nblocks;
2419749STim.Haley@Sun.COM sb->st_fstype[0] = 0;
2429749STim.Haley@Sun.COM
2439749STim.Haley@Sun.COM if ((xoap = xva_getxoptattr(&xv)) == NULL)
2449749STim.Haley@Sun.COM return (0);
2459749STim.Haley@Sun.COM
2469749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_ARCHIVE) && xoap->xoa_archive)
2479749STim.Haley@Sun.COM *xvs |= (1 << F_ARCHIVE);
2489749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_SYSTEM) && xoap->xoa_system)
2499749STim.Haley@Sun.COM *xvs |= (1 << F_SYSTEM);
2509749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_READONLY) && xoap->xoa_readonly)
2519749STim.Haley@Sun.COM *xvs |= (1 << F_READONLY);
2529749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_HIDDEN) && xoap->xoa_hidden)
2539749STim.Haley@Sun.COM *xvs |= (1 << F_HIDDEN);
2549749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_NOUNLINK) && xoap->xoa_nounlink)
2559749STim.Haley@Sun.COM *xvs |= (1 << F_NOUNLINK);
2569749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_IMMUTABLE) && xoap->xoa_immutable)
2579749STim.Haley@Sun.COM *xvs |= (1 << F_IMMUTABLE);
2589749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_APPENDONLY) && xoap->xoa_appendonly)
2599749STim.Haley@Sun.COM *xvs |= (1 << F_APPENDONLY);
2609749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_NODUMP) && xoap->xoa_nodump)
2619749STim.Haley@Sun.COM *xvs |= (1 << F_NODUMP);
2629749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_OPAQUE) && xoap->xoa_opaque)
2639749STim.Haley@Sun.COM *xvs |= (1 << F_OPAQUE);
2649749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_AV_QUARANTINED) && xoap->xoa_av_quarantined)
2659749STim.Haley@Sun.COM *xvs |= (1 << F_AV_QUARANTINED);
2669749STim.Haley@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_AV_MODIFIED) && xoap->xoa_av_modified)
2679749STim.Haley@Sun.COM *xvs |= (1 << F_AV_MODIFIED);
26810793Sdai.ngo@sun.com if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
26910793Sdai.ngo@sun.com *xvs |= (1 << F_REPARSE);
270*13082SJoyce.McIntosh@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_OFFLINE) && xoap->xoa_offline)
271*13082SJoyce.McIntosh@Sun.COM *xvs |= (1 << F_OFFLINE);
272*13082SJoyce.McIntosh@Sun.COM if (XVA_ISSET_RTN(&xv, XAT_SPARSE) && xoap->xoa_sparse)
273*13082SJoyce.McIntosh@Sun.COM *xvs |= (1 << F_SPARSE);
2749749STim.Haley@Sun.COM
2759749STim.Haley@Sun.COM return (0);
2769749STim.Haley@Sun.COM }
2779749STim.Haley@Sun.COM
2789749STim.Haley@Sun.COM /*ARGSUSED*/
2799749STim.Haley@Sun.COM static int
zut_lookup(intptr_t arg,cred_t * cr,int iflag,int * rvalp)2809749STim.Haley@Sun.COM zut_lookup(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
2819749STim.Haley@Sun.COM {
2829749STim.Haley@Sun.COM zut_lookup_t *zl;
2839749STim.Haley@Sun.COM pathname_t rpn;
2849749STim.Haley@Sun.COM vnode_t *dvn = NULL;
2859749STim.Haley@Sun.COM vnode_t *fvn = NULL;
2869749STim.Haley@Sun.COM vnode_t *xdvn = NULL;
2879749STim.Haley@Sun.COM vnode_t *xfvn = NULL;
2889749STim.Haley@Sun.COM vnode_t *release = NULL;
2899749STim.Haley@Sun.COM int flags = 0;
2909749STim.Haley@Sun.COM int error, rc;
2919749STim.Haley@Sun.COM
2929749STim.Haley@Sun.COM zl = kmem_zalloc(sizeof (zut_lookup_t), KM_SLEEP);
2939749STim.Haley@Sun.COM
2949749STim.Haley@Sun.COM error = ddi_copyin((void *)arg, zl, sizeof (zut_lookup_t), iflag);
2959749STim.Haley@Sun.COM if (error)
2969749STim.Haley@Sun.COM goto zutl_bail;
2979749STim.Haley@Sun.COM
2989749STim.Haley@Sun.COM pn_alloc(&rpn);
2999749STim.Haley@Sun.COM bzero(rpn.pn_buf, MAXPATHLEN);
3009749STim.Haley@Sun.COM
3019749STim.Haley@Sun.COM zl->zl_retcode = zut_open_dir(zl->zl_dir, NULL, cr, flags, &rpn, &dvn);
3029749STim.Haley@Sun.COM if (zl->zl_retcode)
3039749STim.Haley@Sun.COM goto zutl_done;
3049749STim.Haley@Sun.COM
3059749STim.Haley@Sun.COM if (zl->zl_reqflags & ZUT_IGNORECASE)
3069749STim.Haley@Sun.COM flags |= FIGNORECASE;
3079749STim.Haley@Sun.COM
3089749STim.Haley@Sun.COM zl->zl_retcode = VOP_LOOKUP(dvn, zl->zl_file, &fvn, NULL, flags, NULL,
3099749STim.Haley@Sun.COM cr, NULL, &zl->zl_deflags, &rpn);
3109749STim.Haley@Sun.COM if (zl->zl_retcode)
3119749STim.Haley@Sun.COM goto zutl_done;
3129749STim.Haley@Sun.COM
3139749STim.Haley@Sun.COM release = fvn;
3149749STim.Haley@Sun.COM
3159749STim.Haley@Sun.COM if (zl->zl_reqflags & ZUT_XATTR) {
3169749STim.Haley@Sun.COM vattr_t vattr;
3179749STim.Haley@Sun.COM
3189749STim.Haley@Sun.COM /*
3199749STim.Haley@Sun.COM * In order to access hidden attribute directory the
3209749STim.Haley@Sun.COM * user must have appropriate read access and be able
3219749STim.Haley@Sun.COM * to stat() the file
3229749STim.Haley@Sun.COM */
3239749STim.Haley@Sun.COM if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
3249749STim.Haley@Sun.COM zl->zl_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
3259749STim.Haley@Sun.COM V_ACE_MASK, cr, NULL);
3269749STim.Haley@Sun.COM } else {
3279749STim.Haley@Sun.COM zl->zl_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
3289749STim.Haley@Sun.COM }
3299749STim.Haley@Sun.COM if (zl->zl_retcode)
3309749STim.Haley@Sun.COM goto zutl_done;
3319749STim.Haley@Sun.COM
3329749STim.Haley@Sun.COM vattr.va_mask = AT_ALL;
3339749STim.Haley@Sun.COM zl->zl_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
3349749STim.Haley@Sun.COM if (zl->zl_retcode)
3359749STim.Haley@Sun.COM goto zutl_done;
3369749STim.Haley@Sun.COM
3379749STim.Haley@Sun.COM zl->zl_retcode = VOP_LOOKUP(fvn, "", &xdvn, NULL,
3389749STim.Haley@Sun.COM flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
3399749STim.Haley@Sun.COM if (zl->zl_retcode)
3409749STim.Haley@Sun.COM goto zutl_done;
3419749STim.Haley@Sun.COM VN_RELE(fvn);
3429749STim.Haley@Sun.COM release = xdvn;
3439749STim.Haley@Sun.COM
3449749STim.Haley@Sun.COM zl->zl_retcode = VOP_LOOKUP(xdvn, zl->zl_xfile, &xfvn,
3459749STim.Haley@Sun.COM NULL, flags, NULL, cr, NULL, &zl->zl_deflags, &rpn);
3469749STim.Haley@Sun.COM if (zl->zl_retcode)
3479749STim.Haley@Sun.COM goto zutl_done;
3489749STim.Haley@Sun.COM VN_RELE(xdvn);
3499749STim.Haley@Sun.COM release = xfvn;
3509749STim.Haley@Sun.COM }
3519749STim.Haley@Sun.COM
3529749STim.Haley@Sun.COM if (zl->zl_reqflags & ZUT_GETSTAT) {
3539749STim.Haley@Sun.COM zl->zl_retcode = zut_stat64(release,
3549749STim.Haley@Sun.COM &zl->zl_statbuf, &zl->zl_xvattrs, 0, cr);
3559749STim.Haley@Sun.COM }
3569749STim.Haley@Sun.COM
3579749STim.Haley@Sun.COM zutl_done:
3589749STim.Haley@Sun.COM (void) strlcpy(zl->zl_real, rpn.pn_path, MAXPATHLEN);
3599749STim.Haley@Sun.COM
3609749STim.Haley@Sun.COM rc = ddi_copyout(zl, (void *)arg, sizeof (zut_lookup_t), iflag);
3619749STim.Haley@Sun.COM if (error == 0)
3629749STim.Haley@Sun.COM error = rc;
3639749STim.Haley@Sun.COM
3649749STim.Haley@Sun.COM if (release)
3659749STim.Haley@Sun.COM VN_RELE(release);
3669749STim.Haley@Sun.COM if (dvn)
3679749STim.Haley@Sun.COM VN_RELE(dvn);
3689749STim.Haley@Sun.COM pn_free(&rpn);
3699749STim.Haley@Sun.COM
3709749STim.Haley@Sun.COM zutl_bail:
3719749STim.Haley@Sun.COM kmem_free(zl, sizeof (zut_lookup_t));
3729749STim.Haley@Sun.COM if (rvalp)
3739749STim.Haley@Sun.COM *rvalp = error;
3749749STim.Haley@Sun.COM return (error);
3759749STim.Haley@Sun.COM }
3769749STim.Haley@Sun.COM
3779749STim.Haley@Sun.COM /*ARGSUSED*/
3789749STim.Haley@Sun.COM static int
zut_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cr,int * rvalp)3799749STim.Haley@Sun.COM zut_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
3809749STim.Haley@Sun.COM {
3819749STim.Haley@Sun.COM int error;
3829749STim.Haley@Sun.COM
3839749STim.Haley@Sun.COM if (getminor(dev) != 0)
3849749STim.Haley@Sun.COM return (ENXIO);
3859749STim.Haley@Sun.COM
3869749STim.Haley@Sun.COM if (cmd <= ZUT_IOC_MIN_CMD || cmd >= ZUT_IOC_MAX_CMD)
3879749STim.Haley@Sun.COM return (EINVAL);
3889749STim.Haley@Sun.COM
3899749STim.Haley@Sun.COM switch (cmd) {
3909749STim.Haley@Sun.COM case ZUT_IOC_LOOKUP:
3919749STim.Haley@Sun.COM error = zut_lookup(arg, cr, flag, rvalp);
3929749STim.Haley@Sun.COM break;
3939749STim.Haley@Sun.COM case ZUT_IOC_READDIR:
3949749STim.Haley@Sun.COM error = zut_readdir(arg, cr, flag, rvalp);
3959749STim.Haley@Sun.COM default:
3969749STim.Haley@Sun.COM break;
3979749STim.Haley@Sun.COM }
3989749STim.Haley@Sun.COM
3999749STim.Haley@Sun.COM return (error);
4009749STim.Haley@Sun.COM }
4019749STim.Haley@Sun.COM
4029749STim.Haley@Sun.COM static int
zut_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4039749STim.Haley@Sun.COM zut_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4049749STim.Haley@Sun.COM {
4059749STim.Haley@Sun.COM if (cmd != DDI_ATTACH)
4069749STim.Haley@Sun.COM return (DDI_FAILURE);
4079749STim.Haley@Sun.COM
4089749STim.Haley@Sun.COM if (ddi_create_minor_node(dip, "zut", S_IFCHR, 0,
4099749STim.Haley@Sun.COM DDI_PSEUDO, 0) == DDI_FAILURE)
4109749STim.Haley@Sun.COM return (DDI_FAILURE);
4119749STim.Haley@Sun.COM
4129749STim.Haley@Sun.COM zut_dip = dip;
4139749STim.Haley@Sun.COM
4149749STim.Haley@Sun.COM ddi_report_dev(dip);
4159749STim.Haley@Sun.COM
4169749STim.Haley@Sun.COM return (DDI_SUCCESS);
4179749STim.Haley@Sun.COM }
4189749STim.Haley@Sun.COM
4199749STim.Haley@Sun.COM static int
zut_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4209749STim.Haley@Sun.COM zut_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4219749STim.Haley@Sun.COM {
4229749STim.Haley@Sun.COM if (cmd != DDI_DETACH)
4239749STim.Haley@Sun.COM return (DDI_FAILURE);
4249749STim.Haley@Sun.COM
4259749STim.Haley@Sun.COM zut_dip = NULL;
4269749STim.Haley@Sun.COM
4279749STim.Haley@Sun.COM ddi_prop_remove_all(dip);
4289749STim.Haley@Sun.COM ddi_remove_minor_node(dip, NULL);
4299749STim.Haley@Sun.COM
4309749STim.Haley@Sun.COM return (DDI_SUCCESS);
4319749STim.Haley@Sun.COM }
4329749STim.Haley@Sun.COM
4339749STim.Haley@Sun.COM /*ARGSUSED*/
4349749STim.Haley@Sun.COM static int
zut_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4359749STim.Haley@Sun.COM zut_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4369749STim.Haley@Sun.COM {
4379749STim.Haley@Sun.COM switch (infocmd) {
4389749STim.Haley@Sun.COM case DDI_INFO_DEVT2DEVINFO:
4399749STim.Haley@Sun.COM *result = zut_dip;
4409749STim.Haley@Sun.COM return (DDI_SUCCESS);
4419749STim.Haley@Sun.COM
4429749STim.Haley@Sun.COM case DDI_INFO_DEVT2INSTANCE:
4439749STim.Haley@Sun.COM *result = (void *)0;
4449749STim.Haley@Sun.COM return (DDI_SUCCESS);
4459749STim.Haley@Sun.COM }
4469749STim.Haley@Sun.COM
4479749STim.Haley@Sun.COM return (DDI_FAILURE);
4489749STim.Haley@Sun.COM }
4499749STim.Haley@Sun.COM
4509749STim.Haley@Sun.COM /*ARGSUSED*/
4519749STim.Haley@Sun.COM int
zut_open(dev_t * devp,int flag,int otyp,cred_t * cr)4529749STim.Haley@Sun.COM zut_open(dev_t *devp, int flag, int otyp, cred_t *cr)
4539749STim.Haley@Sun.COM {
4549749STim.Haley@Sun.COM minor_t minor = getminor(*devp);
4559749STim.Haley@Sun.COM
4569749STim.Haley@Sun.COM if (minor == 0) /* This is the control device */
4579749STim.Haley@Sun.COM return (0);
4589749STim.Haley@Sun.COM
4599749STim.Haley@Sun.COM return (ENXIO);
4609749STim.Haley@Sun.COM }
4619749STim.Haley@Sun.COM
4629749STim.Haley@Sun.COM /*ARGSUSED*/
4639749STim.Haley@Sun.COM int
zut_close(dev_t dev,int flag,int otyp,cred_t * cr)4649749STim.Haley@Sun.COM zut_close(dev_t dev, int flag, int otyp, cred_t *cr)
4659749STim.Haley@Sun.COM {
4669749STim.Haley@Sun.COM minor_t minor = getminor(dev);
4679749STim.Haley@Sun.COM
4689749STim.Haley@Sun.COM if (minor == 0) /* This is the control device */
4699749STim.Haley@Sun.COM return (0);
4709749STim.Haley@Sun.COM
4719749STim.Haley@Sun.COM return (ENXIO);
4729749STim.Haley@Sun.COM }
4739749STim.Haley@Sun.COM
4749749STim.Haley@Sun.COM /*
4759749STim.Haley@Sun.COM * /dev/zut is the control node, i.e. minor 0.
4769749STim.Haley@Sun.COM *
4779749STim.Haley@Sun.COM * There are no other minor nodes, and /dev/zut basically does nothing
4789749STim.Haley@Sun.COM * other than serve up ioctls.
4799749STim.Haley@Sun.COM */
4809749STim.Haley@Sun.COM static struct cb_ops zut_cb_ops = {
4819749STim.Haley@Sun.COM zut_open, /* open */
4829749STim.Haley@Sun.COM zut_close, /* close */
4839749STim.Haley@Sun.COM nodev, /* strategy */
4849749STim.Haley@Sun.COM nodev, /* print */
4859749STim.Haley@Sun.COM nodev, /* dump */
4869749STim.Haley@Sun.COM nodev, /* read */
4879749STim.Haley@Sun.COM nodev, /* write */
4889749STim.Haley@Sun.COM zut_ioctl, /* ioctl */
4899749STim.Haley@Sun.COM nodev, /* devmap */
4909749STim.Haley@Sun.COM nodev, /* mmap */
4919749STim.Haley@Sun.COM nodev, /* segmap */
4929749STim.Haley@Sun.COM nochpoll, /* poll */
4939749STim.Haley@Sun.COM ddi_prop_op, /* prop_op */
4949749STim.Haley@Sun.COM NULL, /* streamtab */
4959749STim.Haley@Sun.COM D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */
4969749STim.Haley@Sun.COM CB_REV, /* version */
4979749STim.Haley@Sun.COM nodev, /* async read */
4989749STim.Haley@Sun.COM nodev, /* async write */
4999749STim.Haley@Sun.COM };
5009749STim.Haley@Sun.COM
5019749STim.Haley@Sun.COM static struct dev_ops zut_dev_ops = {
5029749STim.Haley@Sun.COM DEVO_REV, /* version */
5039749STim.Haley@Sun.COM 0, /* refcnt */
5049749STim.Haley@Sun.COM zut_info, /* info */
5059749STim.Haley@Sun.COM nulldev, /* identify */
5069749STim.Haley@Sun.COM nulldev, /* probe */
5079749STim.Haley@Sun.COM zut_attach, /* attach */
5089749STim.Haley@Sun.COM zut_detach, /* detach */
5099749STim.Haley@Sun.COM nodev, /* reset */
5109749STim.Haley@Sun.COM &zut_cb_ops, /* driver operations */
5119749STim.Haley@Sun.COM NULL /* no bus operations */
5129749STim.Haley@Sun.COM };
5139749STim.Haley@Sun.COM
5149749STim.Haley@Sun.COM static struct modldrv zut_modldrv = {
5159749STim.Haley@Sun.COM &mod_driverops, "ZFS unit test " ZUT_VERSION_STRING,
5169749STim.Haley@Sun.COM &zut_dev_ops
5179749STim.Haley@Sun.COM };
5189749STim.Haley@Sun.COM
5199749STim.Haley@Sun.COM static struct modlinkage modlinkage = {
5209749STim.Haley@Sun.COM MODREV_1,
5219749STim.Haley@Sun.COM (void *)&zut_modldrv,
5229749STim.Haley@Sun.COM NULL
5239749STim.Haley@Sun.COM };
5249749STim.Haley@Sun.COM
5259749STim.Haley@Sun.COM int
_init(void)5269749STim.Haley@Sun.COM _init(void)
5279749STim.Haley@Sun.COM {
5289749STim.Haley@Sun.COM int error;
5299749STim.Haley@Sun.COM
5309749STim.Haley@Sun.COM if ((error = mod_install(&modlinkage)) != 0) {
5319749STim.Haley@Sun.COM return (error);
5329749STim.Haley@Sun.COM }
5339749STim.Haley@Sun.COM
5349749STim.Haley@Sun.COM error = ldi_ident_from_mod(&modlinkage, &zut_li);
5359749STim.Haley@Sun.COM ASSERT(error == 0);
5369749STim.Haley@Sun.COM
5379749STim.Haley@Sun.COM return (0);
5389749STim.Haley@Sun.COM }
5399749STim.Haley@Sun.COM
5409749STim.Haley@Sun.COM int
_fini(void)5419749STim.Haley@Sun.COM _fini(void)
5429749STim.Haley@Sun.COM {
5439749STim.Haley@Sun.COM int error;
5449749STim.Haley@Sun.COM
5459749STim.Haley@Sun.COM if ((error = mod_remove(&modlinkage)) != 0)
5469749STim.Haley@Sun.COM return (error);
5479749STim.Haley@Sun.COM
5489749STim.Haley@Sun.COM ldi_ident_release(zut_li);
5499749STim.Haley@Sun.COM zut_li = NULL;
5509749STim.Haley@Sun.COM
5519749STim.Haley@Sun.COM return (error);
5529749STim.Haley@Sun.COM }
5539749STim.Haley@Sun.COM
5549749STim.Haley@Sun.COM int
_info(struct modinfo * modinfop)5559749STim.Haley@Sun.COM _info(struct modinfo *modinfop)
5569749STim.Haley@Sun.COM {
5579749STim.Haley@Sun.COM return (mod_info(&modlinkage, modinfop));
5589749STim.Haley@Sun.COM }
559