Пример #1
0
int
smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
    int flags, cred_t *cr, vsecattr_t *vsap)
{
	int error;
	int option_flags = 0;
	xvattr_t xvattr;
	vattr_t *vap;
	char *np = name;
	char namebuf[MAXNAMELEN];

	if (flags & SMB_IGNORE_CASE)
		option_flags = FIGNORECASE;

	attr->sa_vattr.va_mask = 0;

	if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
		smb_vop_setup_xvattr(attr, &xvattr);
		vap = &xvattr.xva_vattr;
	} else {
		smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
		vap = &attr->sa_vattr;
	}

	if (flags & SMB_CATIA) {
		np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
		if (strchr(np, '/') != NULL)
			return (EILSEQ);
	}

	error = VOP_MKDIR(dvp, np, vap, vpp, cr, &smb_ct, option_flags, vsap);

	return (error);
}
Пример #2
0
/*
 * smb_vop_setattr()
 *
 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of
 * VOP_SETATTR() when calling from the CIFS service, due to special processing
 * for streams files.
 *
 * Streams have a size but otherwise do not have separate attributes from
 * the (unnamed stream) file, i.e., the security and ownership of the file
 * applies to the stream.  In contrast, extended attribute files, which are
 * used to implement streams, are independent objects with their own
 * attributes.
 *
 * For compatibility with streams, we set the size on the extended attribute
 * file and apply other attributes to the (unnamed stream) file.  The one
 * exception is that the UID and GID can be set on the stream by passing a
 * NULL unnamed_vp, which allows callers to synchronize stream ownership
 * with the (unnamed stream) file.
 */
int
smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *attr,
    int flags, cred_t *cr)
{
	int error = 0;
	int at_size = 0;
	vnode_t *use_vp;
	xvattr_t xvattr;
	vattr_t *vap;

	if (attr->sa_mask & SMB_AT_DOSATTR) {
		attr->sa_dosattr &=
		    (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY |
		    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
	}

	if (unnamed_vp) {
		use_vp = unnamed_vp;
		if (attr->sa_mask & SMB_AT_SIZE) {
			at_size = 1;
			attr->sa_mask &= ~SMB_AT_SIZE;
		}
	} else {
		use_vp = vp;
	}

	/*
	 * The caller should not be setting sa_vattr.va_mask,
	 * but rather sa_mask.
	 */

	attr->sa_vattr.va_mask = 0;

	if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
		smb_vop_setup_xvattr(attr, &xvattr);
		vap = &xvattr.xva_vattr;
	} else {
		smb_sa_to_va_mask(attr->sa_mask,
		    &attr->sa_vattr.va_mask);
		vap = &attr->sa_vattr;
	}

	if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
		return (error);

	if (at_size) {
		attr->sa_vattr.va_mask = AT_SIZE;
		error = VOP_SETATTR(vp, &attr->sa_vattr, flags, kcred, &smb_ct);
	}

	return (error);
}
Пример #3
0
/*
 * smb_vop_readdir()
 *
 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries.
 * The directory entries are returned in an fs-independent format by the
 * underlying file system.  That is, the "page" of information returned is
 * not literally stored on-disk in the format returned.
 * If the file system supports extended directory entries (has features
 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
 * filled with edirent_t structures, instead of dirent64_t structures.
 * If the file system supports access based enumeration (abe), set
 * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
 */
int
smb_vop_readdir(vnode_t *vp, uint32_t offset,
    void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
{
	int error = 0;
	int flags = 0;
	int rdirent_size;
	struct uio auio;
	struct iovec aiov;

	if (vp->v_type != VDIR)
		return (ENOTDIR);

	if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
		flags |= V_RDDIR_ENTFLAGS;
		rdirent_size = sizeof (edirent_t);
	} else {
		rdirent_size = sizeof (dirent64_t);
	}

	if (*count < rdirent_size)
		return (EINVAL);

	if (rddir_flag & SMB_ABE)
		flags |= V_RDDIR_ACCFILTER;

	aiov.iov_base = buf;
	aiov.iov_len = *count;
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	auio.uio_loffset = (uint64_t)offset;
	auio.uio_segflg = UIO_SYSSPACE;
	auio.uio_resid = *count;
	auio.uio_fmode = 0;

	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
	error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, flags);
	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);

	if (error == 0)
		*count = *count - auio.uio_resid;

	return (error);
}
Пример #4
0
/* ARGSUSED */
static int
xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    caller_context_t *ct)
{
	int error = 0;
	char *buf;
	char *domain;
	uint32_t rid;
	ssize_t size = uiop->uio_resid;
	nvlist_t *nvp;
	nvpair_t *pair = NULL;
	vnode_t *ppvp;
	xvattr_t xvattr;
	xoptattr_t *xoap = NULL;	/* Pointer to optional attributes */

	if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0)
		return (EINVAL);

	/*
	 * Validate file offset and size.
	 */
	if (uiop->uio_loffset < (offset_t)0)
		return (EINVAL);

	if (size == 0)
		return (EINVAL);

	xva_init(&xvattr);

	if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
		return (EINVAL);
	}

	/*
	 * Copy and unpack the nvlist
	 */
	buf = kmem_alloc(size, KM_SLEEP);
	if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
		return (EFAULT);
	}

	if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
		kmem_free(buf, size);
		uiop->uio_resid = size;
		return (EINVAL);
	}
	kmem_free(buf, size);

	/*
	 * Fasttrack empty writes (nvlist with no nvpairs)
	 */
	if (nvlist_next_nvpair(nvp, NULL) == 0)
		return (0);

	ppvp = gfs_file_parent(gfs_file_parent(vp));

	while (pair = nvlist_next_nvpair(nvp, pair)) {
		data_type_t type;
		f_attr_t attr;
		boolean_t value;
		uint64_t *time, *times;
		uint_t elem, nelems;
		nvlist_t *nvp_sid;
		uint8_t *scanstamp;

		/*
		 * Validate the name and type of each attribute.
		 * Log any unknown names and continue.  This will
		 * help if additional attributes are added later.
		 */
		type = nvpair_type(pair);
		if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
			cmn_err(CE_WARN, "Unknown attribute %s",
			    nvpair_name(pair));
			continue;
		}

		/*
		 * Verify nvlist type matches required type and view is OK
		 */

		if (type != attr_to_data_type(attr) ||
		    (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
			nvlist_free(nvp);
			return (EINVAL);
		}

		/*
		 * For OWNERSID/GROUPSID make sure the target
		 * file system support ephemeral ID's
		 */
		if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
		    (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
			nvlist_free(nvp);
			return (EINVAL);
		}

		/*
		 * Retrieve data from nvpair
		 */
		switch (type) {
		case DATA_TYPE_BOOLEAN_VALUE:
			if (nvpair_value_boolean_value(pair, &value)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_UINT64_ARRAY:
			if (nvpair_value_uint64_array(pair, &times, &nelems)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_NVLIST:
			if (nvpair_value_nvlist(pair, &nvp_sid)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case DATA_TYPE_UINT8_ARRAY:
			if (nvpair_value_uint8_array(pair,
			    &scanstamp, &nelems)) {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		default:
			nvlist_free(nvp);
			return (EINVAL);
		}

		switch (attr) {
		/*
		 * If we have several similar optional attributes to
		 * process then we should do it all together here so that
		 * xoap and the requested bitmap can be set in one place.
		 */
		case F_READONLY:
			XVA_SET_REQ(&xvattr, XAT_READONLY);
			xoap->xoa_readonly = value;
			break;
		case F_HIDDEN:
			XVA_SET_REQ(&xvattr, XAT_HIDDEN);
			xoap->xoa_hidden = value;
			break;
		case F_SYSTEM:
			XVA_SET_REQ(&xvattr, XAT_SYSTEM);
			xoap->xoa_system = value;
			break;
		case F_ARCHIVE:
			XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
			xoap->xoa_archive = value;
			break;
		case F_IMMUTABLE:
			XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
			xoap->xoa_immutable = value;
			break;
		case F_NOUNLINK:
			XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
			xoap->xoa_nounlink = value;
			break;
		case F_APPENDONLY:
			XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
			xoap->xoa_appendonly = value;
			break;
		case F_NODUMP:
			XVA_SET_REQ(&xvattr, XAT_NODUMP);
			xoap->xoa_nodump = value;
			break;
		case F_AV_QUARANTINED:
			XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
			xoap->xoa_av_quarantined = value;
			break;
		case F_AV_MODIFIED:
			XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
			xoap->xoa_av_modified = value;
			break;
		case F_CRTIME:
			XVA_SET_REQ(&xvattr, XAT_CREATETIME);
			time = (uint64_t *)&(xoap->xoa_createtime);
			for (elem = 0; elem < nelems; elem++)
				*time++ = times[elem];
			break;
		case F_OWNERSID:
		case F_GROUPSID:
			if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
			    &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
			    &rid)) {
				nvlist_free(nvp);
				return (EINVAL);
			}

			/*
			 * Now map domain+rid to ephemeral id's
			 *
			 * If mapping fails, then the uid/gid will
			 * be set to UID_NOBODY by Winchester.
			 */

			if (attr == F_OWNERSID) {
				(void) kidmap_getuidbysid(crgetzone(cr), domain,
				    rid, &xvattr.xva_vattr.va_uid);
				xvattr.xva_vattr.va_mask |= AT_UID;
			} else {
				(void) kidmap_getgidbysid(crgetzone(cr), domain,
				    rid, &xvattr.xva_vattr.va_gid);
				xvattr.xva_vattr.va_mask |= AT_GID;
			}
			break;
		case F_AV_SCANSTAMP:
			if (ppvp->v_type == VREG) {
				XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
				(void) memcpy(xoap->xoa_av_scanstamp,
				    scanstamp, nelems);
			} else {
				nvlist_free(nvp);
				return (EINVAL);
			}
			break;
		case F_REPARSE:
			XVA_SET_REQ(&xvattr, XAT_REPARSE);
			xoap->xoa_reparse = value;
			break;
		case F_OFFLINE:
			XVA_SET_REQ(&xvattr, XAT_OFFLINE);
			xoap->xoa_offline = value;
			break;
		case F_SPARSE:
			XVA_SET_REQ(&xvattr, XAT_SPARSE);
			xoap->xoa_sparse = value;
			break;
		default:
			break;
		}
	}

	ppvp = gfs_file_parent(gfs_file_parent(vp));
	error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
	if (error)
		uiop->uio_resid = size;

	nvlist_free(nvp);
	return (error);
}
Пример #5
0
/* ARGSUSED */
int
fs_pathconf(
	vnode_t *vp,
	int cmd,
	ulong_t *valp,
	cred_t *cr,
	caller_context_t *ct)
{
	register ulong_t val;
	register int error = 0;
	struct statvfs64 vfsbuf;

	switch (cmd) {

	case _PC_LINK_MAX:
		val = MAXLINK;
		break;

	case _PC_MAX_CANON:
		val = MAX_CANON;
		break;

	case _PC_MAX_INPUT:
		val = MAX_INPUT;
		break;

	case _PC_NAME_MAX:
		bzero(&vfsbuf, sizeof (vfsbuf));
		if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
			break;
		val = vfsbuf.f_namemax;
		break;

	case _PC_PATH_MAX:
	case _PC_SYMLINK_MAX:
		val = MAXPATHLEN;
		break;

	case _PC_PIPE_BUF:
		val = PIPE_BUF;
		break;

	case _PC_NO_TRUNC:
		if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
			val = 1;	/* NOTRUNC is enabled for vp */
		else
			val = (ulong_t)-1;
		break;

	case _PC_VDISABLE:
		val = _POSIX_VDISABLE;
		break;

	case _PC_CHOWN_RESTRICTED:
		if (rstchown)
			val = rstchown; /* chown restricted enabled */
		else
			val = (ulong_t)-1;
		break;

	case _PC_FILESIZEBITS:

		/*
		 * If ever we come here it means that underlying file system
		 * does not recognise the command and therefore this
		 * configurable limit cannot be determined. We return -1
		 * and don't change errno.
		 */

		val = (ulong_t)-1;    /* large file support */
		break;

	case _PC_ACL_ENABLED:
		val = 0;
		break;

	case _PC_CASE_BEHAVIOR:
		val = _CASE_SENSITIVE;
		if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
			val |= _CASE_INSENSITIVE;
		if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
			val &= ~_CASE_SENSITIVE;
		break;

	case _PC_SATTR_ENABLED:
	case _PC_SATTR_EXISTS:
		val = 0;
		break;

	case _PC_ACCESS_FILTERING:
		val = 0;
		break;

	default:
		error = EINVAL;
		break;
	}

	if (error == 0)
		*valp = val;
	return (error);
}
Пример #6
0
/*
 * gfs_dir_lookup()
 *
 * Looks up the given name in the directory and returns the corresponding
 * vnode, if found.
 *
 * First, we search statically defined entries, if any, with a call to
 * gfs_dir_lookup_static().  If no static entry is found, and we have
 * a callback function we try a dynamic lookup via gfs_dir_lookup_dynamic().
 *
 * This function returns 0 on success, non-zero on error.
 */
int
gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr,
    int flags, int *direntflags, pathname_t *realpnp)
{
	gfs_dir_t *dp = dvp->v_data;
	boolean_t casecheck;
	vnode_t *dynvp = NULL;
	vnode_t *vp = NULL;
	int (*compare)(const char *, const char *);
	int error, idx;

	ASSERT(dvp->v_type == VDIR);

	if (gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm) == 0)
		return (0);

	casecheck = (flags & FIGNORECASE) != 0 && direntflags != NULL;
	if (vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) ||
	    (flags & FIGNORECASE))
		compare = strcasecmp;
	else
		compare = strcmp;

	gfs_dir_lock(dp);

	error = gfs_dir_lookup_static(compare, dp, nm, dvp, &idx, &vp, realpnp);

	if (vp && casecheck) {
		gfs_dirent_t *ge;
		int i;

		for (i = idx + 1; i < dp->gfsd_nstatic; i++) {
			ge = &dp->gfsd_static[i];

			if (strcasecmp(ge->gfse_name, nm) == 0) {
				*direntflags |= ED_CASE_CONFLICT;
				goto out;
			}
		}
	}

	if ((error || casecheck) && dp->gfsd_lookup)
		error = gfs_dir_lookup_dynamic(dp->gfsd_lookup, dp, nm, dvp,
		    &dynvp, cr, flags, direntflags, vp ? NULL : realpnp);

	if (vp && dynvp) {
		/* static and dynamic entries are case-insensitive conflict */
		ASSERT(casecheck);
		*direntflags |= ED_CASE_CONFLICT;
		VN_RELE(dynvp);
	} else if (vp == NULL) {
		vp = dynvp;
	} else if (error == ENOENT) {
		error = 0;
	} else if (error) {
		VN_RELE(vp);
		vp = NULL;
	}

out:
	gfs_dir_unlock(dp);

	*vpp = vp;
	return (error);
}
Пример #7
0
/*
 * Always set ACL support because the VFS will fake ACLs for file systems
 * that don't support them.
 *
 * Some flags are dependent on the typename, which is also set up here.
 * File system types are hardcoded in uts/common/os/vfs_conf.c.
 */
static void
smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
{
	typedef struct smb_mtype {
		char		*mt_name;
		size_t		mt_namelen;
		uint32_t	mt_flags;
	} smb_mtype_t;

	static smb_mtype_t smb_mtype[] = {
		{ "zfs",	3,	SMB_TREE_UNICODE_ON_DISK },
		{ "ufs",	3,	SMB_TREE_UNICODE_ON_DISK },
		{ "nfs",	3,	SMB_TREE_NFS_MOUNTED },
		{ "tmpfs",	5,	SMB_TREE_NO_EXPORT }
	};
	smb_mtype_t	*mtype;
	char		*name;
	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
	int		i;

	if (si->shr_flags & SMB_SHRF_CATIA)
		flags |= SMB_TREE_CATIA;

	if (si->shr_flags & SMB_SHRF_ABE)
		flags |= SMB_TREE_ABE;

	if (vfsp->vfs_flag & VFS_RDONLY)
		flags |= SMB_TREE_READONLY;

	if (vfsp->vfs_flag & VFS_XATTR)
		flags |= SMB_TREE_STREAMS;

	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
		flags |= SMB_TREE_NO_ATIME;

	name = vfssw[vfsp->vfs_fstype].vsw_name;

	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
		mtype = &smb_mtype[i];
		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
			flags |= mtype->mt_flags;
	}

	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
	(void) smb_strupr((char *)tree->t_typename);

	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
		flags |= SMB_TREE_XVATTR;

	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
		flags |= SMB_TREE_CASEINSENSITIVE;

	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
		flags |= SMB_TREE_NO_CASESENSITIVE;

	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
		flags |= SMB_TREE_DIRENTFLAGS;

	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
		flags |= SMB_TREE_ACLONCREATE;

	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
		flags |= SMB_TREE_ACEMASKONACCESS;

	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);


	tree->t_flags = flags;
}
Пример #8
0
/*
 * smb_vop_getattr()
 *
 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
 * service (instead of calling VOP_GETATTR directly) to retrieve attributes
 * due to special processing needed for streams files.
 *
 * All attributes are retrieved.
 *
 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
 * the corresponding unnamed stream).
 * A named stream's attributes (as far as CIFS is concerned) are those of the
 * unnamed stream (minus the size attribute, and the type), plus  the size of
 * the named stream, and a type value of VREG.
 * Although the file system may store other attributes with the named stream,
 * these should not be used by CIFS for any purpose.
 *
 * File systems without VFSFT_XVATTR do not support DOS attributes or create
 * time (crtime). In this case the mtime is used as the crtime.
 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr
 * is 0 and the mtime is used as the crtime.
 */
int
smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
    int flags, cred_t *cr)
{
	int error;
	vnode_t *use_vp;
	smb_attr_t tmp_attr;
	xvattr_t tmp_xvattr;
	xoptattr_t *xoap = NULL;

	if (unnamed_vp)
		use_vp = unnamed_vp;
	else
		use_vp = vp;

	if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
		xva_init(&tmp_xvattr);
		xoap = xva_getxoptattr(&tmp_xvattr);
		ASSERT(xoap);

		smb_sa_to_va_mask(ret_attr->sa_mask,
		    &tmp_xvattr.xva_vattr.va_mask);

		XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
		XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
		XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
		XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
		XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);

		error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags,
		    cr, &smb_ct);
		if (error != 0)
			return (error);

		ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
		ret_attr->sa_dosattr = 0;

		if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) {
			xoap = xva_getxoptattr(&tmp_xvattr);
			ASSERT(xoap);

			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) &&
			    (xoap->xoa_readonly)) {
				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
			}

			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) &&
			    (xoap->xoa_hidden)) {
				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
			}

			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) &&
			    (xoap->xoa_system)) {
				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
			}

			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) &&
			    (xoap->xoa_archive)) {
				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
			}

			ret_attr->sa_crtime = xoap->xoa_createtime;
		} else {
			ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
		}
	} else {
		/*
		 * Support for file systems without VFSFT_XVATTR
		 */
		smb_sa_to_va_mask(ret_attr->sa_mask,
		    &ret_attr->sa_vattr.va_mask);

		error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr,
		    flags, cr, &smb_ct);
		if (error != 0)
			return (error);

		ret_attr->sa_dosattr = 0;
		ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
	}

	if (unnamed_vp) {
		ret_attr->sa_vattr.va_type = VREG;

		if (ret_attr->sa_mask & (SMB_AT_SIZE | SMB_AT_NBLOCKS)) {
			tmp_attr.sa_vattr.va_mask = AT_SIZE | AT_NBLOCKS;

			error = VOP_GETATTR(vp, &tmp_attr.sa_vattr,
			    flags, cr, &smb_ct);
			if (error != 0)
				return (error);

			ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
			ret_attr->sa_vattr.va_nblocks =
			    tmp_attr.sa_vattr.va_nblocks;
		}
	}

	if (ret_attr->sa_vattr.va_type == VDIR)
		ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;

	return (error);
}
Пример #9
0
static int
copen(int startfd, char *fname, int filemode, int createmode)
{
	struct pathname pn;
	vnode_t *vp, *sdvp;
	file_t *fp, *startfp;
	enum vtype type;
	int error;
	int fd, dupfd;
	vnode_t *startvp;
	proc_t *p = curproc;
	uio_seg_t seg = UIO_USERSPACE;
	char *open_filename = fname;
	uint32_t auditing = AU_AUDITING();
	char startchar;

	if (filemode & (FSEARCH|FEXEC)) {
		/*
		 * Must be one or the other and neither FREAD nor FWRITE
		 * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN
		 * XXX: Should these just be silently ignored?
		 */
		if ((filemode & (FREAD|FWRITE)) ||
		    (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) ||
		    (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN)))
			return (set_errno(EINVAL));
	}

	if (startfd == AT_FDCWD) {
		/*
		 * Regular open()
		 */
		startvp = NULL;
	} else {
		/*
		 * We're here via openat()
		 */
		if (copyin(fname, &startchar, sizeof (char)))
			return (set_errno(EFAULT));

		/*
		 * if startchar is / then startfd is ignored
		 */
		if (startchar == '/')
			startvp = NULL;
		else {
			if ((startfp = getf(startfd)) == NULL)
				return (set_errno(EBADF));
			startvp = startfp->f_vnode;
			VN_HOLD(startvp);
			releasef(startfd);
		}
	}

	/*
	 * Handle __openattrdirat() requests
	 */
	if (filemode & FXATTRDIROPEN) {
		if (auditing && startvp != NULL)
			audit_setfsat_path(1);
		if (error = lookupnameat(fname, seg, FOLLOW,
		    NULLVPP, &vp, startvp))
			return (set_errno(error));
		if (startvp != NULL)
			VN_RELE(startvp);

		startvp = vp;
	}

	/*
	 * Do we need to go into extended attribute space?
	 */
	if (filemode & FXATTR) {
		if (startfd == AT_FDCWD) {
			if (copyin(fname, &startchar, sizeof (char)))
				return (set_errno(EFAULT));

			/*
			 * If startchar == '/' then no extended attributes
			 * are looked up.
			 */
			if (startchar == '/') {
				startvp = NULL;
			} else {
				mutex_enter(&p->p_lock);
				startvp = PTOU(p)->u_cdir;
				VN_HOLD(startvp);
				mutex_exit(&p->p_lock);
			}
		}

		/*
		 * Make sure we have a valid extended attribute request.
		 * We must either have a real fd or AT_FDCWD and a relative
		 * pathname.
		 */
		if (startvp == NULL) {
			goto noxattr;
		}
	}

	if (filemode & (FXATTR|FXATTRDIROPEN)) {
		vattr_t vattr;

		if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
			goto out;
		}

		/*
		 * In order to access hidden attribute directory the
		 * user must be able to stat() the file
		 */
		vattr.va_mask = AT_ALL;
		if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
			pn_free(&pn);
			goto out;
		}

		if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
		    vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
			error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
			    (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR :
			    LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
			    NULL, NULL, NULL);
		} else {
			error = EINVAL;
		}

		/*
		 * For __openattrdirat() use "." as filename to open
		 * as part of vn_openat()
		 */
		if (error == 0 && (filemode & FXATTRDIROPEN)) {
			open_filename = ".";
			seg = UIO_SYSSPACE;
		}

		pn_free(&pn);
		if (error != 0)
			goto out;

		VN_RELE(startvp);
		startvp = sdvp;
	}

noxattr:
	if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) {
		if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
			filemode &= ~FNDELAY;
		error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
		if (error == 0) {
			if (auditing && startvp != NULL)
				audit_setfsat_path(1);
			/*
			 * Last arg is a don't-care term if
			 * !(filemode & FCREAT).
			 */
			error = vn_openat(open_filename, seg, filemode,
			    (int)(createmode & MODEMASK),
			    &vp, CRCREAT, PTOU(curproc)->u_cmask,
			    startvp, fd);

			if (startvp != NULL)
				VN_RELE(startvp);
			if (error == 0) {
				if ((vp->v_flag & VDUP) == 0) {
					fp->f_vnode = vp;
					mutex_exit(&fp->f_tlock);
					/*
					 * We must now fill in the slot
					 * falloc reserved.
					 */
					setf(fd, fp);
					return (fd);
				} else {
					/*
					 * Special handling for /dev/fd.
					 * Give up the file pointer
					 * and dup the indicated file descriptor
					 * (in v_rdev). This is ugly, but I've
					 * seen worse.
					 */
					unfalloc(fp);
					dupfd = getminor(vp->v_rdev);
					type = vp->v_type;
					mutex_enter(&vp->v_lock);
					vp->v_flag &= ~VDUP;
					mutex_exit(&vp->v_lock);
					VN_RELE(vp);
					if (type != VCHR)
						return (set_errno(EINVAL));
					if ((fp = getf(dupfd)) == NULL) {
						setf(fd, NULL);
						return (set_errno(EBADF));
					}
					mutex_enter(&fp->f_tlock);
					fp->f_count++;
					mutex_exit(&fp->f_tlock);
					setf(fd, fp);
					releasef(dupfd);
				}
				return (fd);
			} else {
				setf(fd, NULL);
				unfalloc(fp);
				return (set_errno(error));
			}
		}
	} else {
		error = EINVAL;
	}
out:
	if (startvp != NULL)
		VN_RELE(startvp);
	return (set_errno(error));
}
Пример #10
0
/*
 * smb_odir_create
 * Allocate and populate an odir obect and add it to the tree's list.
 */
static uint16_t
smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
    char *pattern, uint16_t sattr, cred_t *cr)
{
	smb_odir_t	*od;
	smb_tree_t	*tree;
	uint16_t	odid;

	ASSERT(sr);
	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
	ASSERT(sr->tid_tree);
	ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
	ASSERT(dnode);
	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);

	tree = sr->tid_tree;

	if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) {
		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
		return (0);
	}

	od = kmem_cache_alloc(smb_cache_odir, KM_SLEEP);
	bzero(od, sizeof (smb_odir_t));

	mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL);
	od->d_refcnt = 0;
	od->d_state = SMB_ODIR_STATE_OPEN;
	od->d_magic = SMB_ODIR_MAGIC;
	od->d_opened_by_pid = sr->smb_pid;
	od->d_session = tree->t_session;
	od->d_cred = cr;
	/*
	 * grab a ref for od->d_user
	 * released in  smb_odir_delete()
	 */
	smb_user_hold_internal(sr->uid_user);
	od->d_user = sr->uid_user;
	od->d_tree = tree;
	od->d_dnode = dnode;
	smb_node_ref(dnode);
	od->d_odid = odid;
	od->d_sattr = sattr;
	(void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
	od->d_flags = 0;
	if (smb_contains_wildcards(od->d_pattern))
		od->d_flags |= SMB_ODIR_FLAG_WILDCARDS;
	if (vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS))
		od->d_flags |= SMB_ODIR_FLAG_EDIRENT;
	if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE))
		od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
	if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES))
		od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES;
	if (SMB_TREE_SUPPORTS_CATIA(sr))
		od->d_flags |= SMB_ODIR_FLAG_CATIA;
	if (SMB_TREE_SUPPORTS_ABE(sr))
		od->d_flags |= SMB_ODIR_FLAG_ABE;
	if (dnode->flags & NODE_XATTR_DIR)
		od->d_flags |= SMB_ODIR_FLAG_XATTR;
	od->d_eof = B_FALSE;

	smb_llist_enter(&tree->t_odir_list, RW_WRITER);
	smb_llist_insert_tail(&tree->t_odir_list, od);
	smb_llist_exit(&tree->t_odir_list);

	atomic_inc_32(&tree->t_session->s_dir_cnt);
	return (odid);
}