smb_vops.c revision c8ec8eea9849cac239663c46be8a7f5d2ba7ca00
6a67d144095c31bbafed93cec1619590157335eajvergara * CDDL HEADER START
6a67d144095c31bbafed93cec1619590157335eajvergara * The contents of this file are subject to the terms of the
6a67d144095c31bbafed93cec1619590157335eajvergara * Common Development and Distribution License (the "License").
6a67d144095c31bbafed93cec1619590157335eajvergara * You may not use this file except in compliance with the License.
6a67d144095c31bbafed93cec1619590157335eajvergara * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * See the License for the specific language governing permissions
6a67d144095c31bbafed93cec1619590157335eajvergara * and limitations under the License.
6a67d144095c31bbafed93cec1619590157335eajvergara * When distributing Covered Code, include this CDDL HEADER in each
6a67d144095c31bbafed93cec1619590157335eajvergara * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * If applicable, add the following below this CDDL HEADER, with the
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * fields enclosed by brackets "[]" replaced with your own identifying
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * information: Portions Copyright [yyyy] [name of copyright owner]
6a67d144095c31bbafed93cec1619590157335eajvergara * CDDL HEADER END
6a67d144095c31bbafed93cec1619590157335eajvergara * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
6a67d144095c31bbafed93cec1619590157335eajvergara * Use is subject to license terms.
6a67d144095c31bbafed93cec1619590157335eajvergara#pragma ident "@(#)smb_vops.c 1.13 08/07/30 SMI"
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr);
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *);
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *,
6a67d144095c31bbafed93cec1619590157335eajvergara ino64_t *, vnode_t **, char *, int, cred_t *, char *, int);
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_sutersmb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t,
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_suter smb_request_t *, cred_t *, char *, int *, int, char *);
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_gather_dents_info(char *args, ino_t fileid, int namelen,
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
6a67d144095c31bbafed93cec1619590157335eajvergaracallb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *);
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter * smb_vop_init
0142bbb7ccb5d0efb942c20f5d27e5ddfb4344fdkenneth_suter * This function is not multi-thread safe. The caller must make sure only one
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter * thread makes the call.
6a67d144095c31bbafed93cec1619590157335eajvergara return (0);
c6c8254710feb80354037c2afb8d1cdae930a27akenneth_suter * The caller_context will be used primarily for range locking.
6a67d144095c31bbafed93cec1619590157335eajvergara * Since the CIFS server is mapping its locks to POSIX locks,
6a67d144095c31bbafed93cec1619590157335eajvergara * only one pid is used for operations originating from the
6a67d144095c31bbafed93cec1619590157335eajvergara * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
6a67d144095c31bbafed93cec1619590157335eajvergara return (0);
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_vop_fini
2401d3c2af505789c7c3b860a43e973f27731243jvergara * This function is not multi-thread safe. The caller must make sure only one
2401d3c2af505789c7c3b860a43e973f27731243jvergara * thread makes the call.
2401d3c2af505789c7c3b860a43e973f27731243jvergara * The smb_ct will be used primarily for range locking.
6a67d144095c31bbafed93cec1619590157335eajvergara * Since the CIFS server is mapping its locks to POSIX locks,
6a67d144095c31bbafed93cec1619590157335eajvergara * only one pid is used for operations originating from the
0877596da3b90efc5fd39171cef80a2fb8ec395ekenneth_suter * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
6a67d144095c31bbafed93cec1619590157335eajvergara (void) VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct);
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
6a67d144095c31bbafed93cec1619590157335eajvergara (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
6a67d144095c31bbafed93cec1619590157335eajvergara ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
6a67d144095c31bbafed93cec1619590157335eajvergara (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
6a67d144095c31bbafed93cec1619590157335eajvergara * The smb_vop_* functions have minimal knowledge of CIFS semantics and
6a67d144095c31bbafed93cec1619590157335eajvergara * serve as an interface to the VFS layer.
c9d984b0d2c0fda320e79eb3868dd6fbeb1ffa34jvergara * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
c9d984b0d2c0fda320e79eb3868dd6fbeb1ffa34jvergara * (Higher-level CIFS service code should never skip the smb_fsop_* layer
0877596da3b90efc5fd39171cef80a2fb8ec395ekenneth_suter * to call smb_vop_* layer functions directly.)
c9d984b0d2c0fda320e79eb3868dd6fbeb1ffa34jvergara * XXX - Extended attributes support in the file system assumed.
c9d984b0d2c0fda320e79eb3868dd6fbeb1ffa34jvergara * This is needed for full NT Streams functionality.
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_vop_getattr()
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
6a67d144095c31bbafed93cec1619590157335eajvergara * service (instead of calling VOP_GETATTR directly) to retrieve attributes
6a67d144095c31bbafed93cec1619590157335eajvergara * due to special processing needed for streams files.
6a67d144095c31bbafed93cec1619590157335eajvergara * All attributes are retrieved.
6a67d144095c31bbafed93cec1619590157335eajvergara * A named stream's attributes (as far as CIFS is concerned) are those of the
6a67d144095c31bbafed93cec1619590157335eajvergara * unnamed (i.e. data) stream (minus the size attribute), and the size of the
6a67d144095c31bbafed93cec1619590157335eajvergara * named stream. Though the file system may store attributes other than size
6a67d144095c31bbafed93cec1619590157335eajvergara * with the named stream, these should not be used by CIFS for any purpose.
6a67d144095c31bbafed93cec1619590157335eajvergara * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
6a67d144095c31bbafed93cec1619590157335eajvergara * the corresponding unnamed stream).
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
6a67d144095c31bbafed93cec1619590157335eajvergara if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
6a67d144095c31bbafed93cec1619590157335eajvergara if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
6a67d144095c31bbafed93cec1619590157335eajvergara * Copy special attributes to ret_attr parameter
6a67d144095c31bbafed93cec1619590157335eajvergara if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
6a67d144095c31bbafed93cec1619590157335eajvergara * Retrieve stream size attribute into temporary
6a67d144095c31bbafed93cec1619590157335eajvergara * structure, in case the underlying file system
6a67d144095c31bbafed93cec1619590157335eajvergara * returns attributes other than the size (we do not
6a67d144095c31bbafed93cec1619590157335eajvergara * want to have ret_attr's other fields get
6a67d144095c31bbafed93cec1619590157335eajvergara * overwritten).
6a67d144095c31bbafed93cec1619590157335eajvergara * Note that vp is used here, and not use_vp.
6a67d144095c31bbafed93cec1619590157335eajvergara * Also, only AT_SIZE is needed.
6a67d144095c31bbafed93cec1619590157335eajvergara if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr,
6a67d144095c31bbafed93cec1619590157335eajvergara * Support for file systems without VFSFT_XVATTR
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct);
6a67d144095c31bbafed93cec1619590157335eajvergara * "Fake" DOS attributes and create time, filesystem doesn't support
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime;
6a67d144095c31bbafed93cec1619590157335eajvergara if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
6a67d144095c31bbafed93cec1619590157335eajvergara * Retrieve stream size attribute into temporary structure,
6a67d144095c31bbafed93cec1619590157335eajvergara * in case the underlying file system returns attributes
6a67d144095c31bbafed93cec1619590157335eajvergara * other than the size (we do not want to have ret_attr's
6a67d144095c31bbafed93cec1619590157335eajvergara * other fields get overwritten).
6a67d144095c31bbafed93cec1619590157335eajvergara * Note that vp is used here, and not use_vp.
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter * Also, only AT_SIZE is needed.
0142bbb7ccb5d0efb942c20f5d27e5ddfb4344fdkenneth_suter error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct);
6a67d144095c31bbafed93cec1619590157335eajvergara ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_vop_setattr()
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of
6a67d144095c31bbafed93cec1619590157335eajvergara * VOP_SETATTR() when calling from the CIFS service, due to special processing
6a67d144095c31bbafed93cec1619590157335eajvergara * for streams files.
6a67d144095c31bbafed93cec1619590157335eajvergara * Streams have a size but otherwise do not have separate attributes from
6a67d144095c31bbafed93cec1619590157335eajvergara * the (unnamed stream) file, i.e., the security and ownership of the file
6a67d144095c31bbafed93cec1619590157335eajvergara * applies to the stream. In contrast, extended attribute files, which are
6a67d144095c31bbafed93cec1619590157335eajvergara * used to implement streams, are independent objects with their own
6a67d144095c31bbafed93cec1619590157335eajvergara * attributes.
6a67d144095c31bbafed93cec1619590157335eajvergara * For compatibility with streams, we set the size on the extended attribute
6a67d144095c31bbafed93cec1619590157335eajvergara * file and apply other attributes to the (unnamed stream) file. The one
6a67d144095c31bbafed93cec1619590157335eajvergara * exception is that the UID and GID can be set on the stream by passing a
6a67d144095c31bbafed93cec1619590157335eajvergara * NULL unnamed_vp, which allows callers to synchronize stream ownership
2401d3c2af505789c7c3b860a43e973f27731243jvergara * with the (unnamed stream) file.
6a67d144095c31bbafed93cec1619590157335eajvergarasmb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_suter * The caller should not be setting sa_vattr.va_mask,
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_suter * but rather sa_mask.
6a67d144095c31bbafed93cec1619590157335eajvergara if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
6a67d144095c31bbafed93cec1619590157335eajvergara * If the size of the stream needs to be set, set it on
6a67d144095c31bbafed93cec1619590157335eajvergara * the stream file directly. (All other indicated attributes
6a67d144095c31bbafed93cec1619590157335eajvergara * are set on the stream's unnamed stream, except under the
6a67d144095c31bbafed93cec1619590157335eajvergara * exception described in the function header.)
6a67d144095c31bbafed93cec1619590157335eajvergara * set_attr->sa_vattr.va_size already contains the
6a67d144095c31bbafed93cec1619590157335eajvergara * size as set by the caller
6a67d144095c31bbafed93cec1619590157335eajvergara * Note that vp is used here, and not use_vp.
6a67d144095c31bbafed93cec1619590157335eajvergara * Also, only AT_SIZE is needed.
6a67d144095c31bbafed93cec1619590157335eajvergara error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr,
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_vop_access
6a67d144095c31bbafed93cec1619590157335eajvergara * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
6a67d144095c31bbafed93cec1619590157335eajvergara * against file's ACL or Unix permissions. CIFS on the other hand needs to
6a67d144095c31bbafed93cec1619590157335eajvergara * know if the requested operation can succeed for the given object, this
6a67d144095c31bbafed93cec1619590157335eajvergara * requires more checks in case of DELETE bit since permissions on the parent
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter * directory are important as well. Based on Windows rules if parent's ACL
6a67d144095c31bbafed93cec1619590157335eajvergara * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
6a67d144095c31bbafed93cec1619590157335eajvergara * permissions.
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_sutersmb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
6a67d144095c31bbafed93cec1619590157335eajvergara return (0);
6a67d144095c31bbafed93cec1619590157335eajvergara if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
6a67d144095c31bbafed93cec1619590157335eajvergara error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
6a67d144095c31bbafed93cec1619590157335eajvergara * smb_vop_lookup
char *name,
char *od_name,
int flags,
int error = 0;
int option_flags = 0;
return (EINVAL);
return (EIO);
return (error);
int error;
int option_flags = 0;
return (error);
int error;
int option_flags = 0;
return (error);
int error;
int option_flags = 0;
return (error);
int error;
int option_flags = 0;
return (error);
int error;
int option_flags = 0;
return (error);
int num_bytes;
int error = 0;
*namelen = 0;
return (ENOTDIR);
if (vpp)
if (num_bytes <= 0)
if (error)
if (*name)
if (error) {
*namelen = 0;
return (error);
*namelen = 0;
* MAXGETDENTS_SIZE is defined in getdents.c
int error = 0;
int rdirent_flags = 0;
int sink;
return (ENOTDIR);
return (EINVAL);
return (EINVAL);
if (error) {
*count = 0;
return (error);
*count = 0;
char *name,
int *namelen,
char *od_name,
int flags,
char *dirbuf,
int num_bytes)
int ebufsize;
int error = 0;
int len;
int rc;
while (edp) {
if (dp)
if (dp) {
*namelen = 0;
if (ebuf)
return (EOVERFLOW);
if (error) {
if (dp) {
*namelen = 0;
if (ebuf)
return (error);
if (inop)
if (ebuf)
return (error);
char *arg,
char *pattern,
int error = 0;
int maxentries;
int num_bytes;
int resid;
while (maxentries) {
pattern);
if (error)
goto out;
if (num_bytes < 0) {
} else if (num_bytes == 0) {
error = 0;
error = 0;
out:
if (dirbuf)
return (error);
char *arg,
char *dirbuf,
int *maxentries,
int num_bytes,
char *pattern)
int ebufsize;
char *tmp_name;
int error;
int rc;
while (edp) {
if (dp)
if (*maxentries == 0)
if (dp) {
if (error) {
if (dp) {
if (ebuf)
return (error);
if (ebuf)
return (ENOMEM);
if (error > 0) {
if (ebuf)
return (error);
if (error < 0) {
if (ebuf)
*maxentries = 0;
(*maxentries)--;
if (dp) {
if (ebuf)
char *stream_name,
char *od_name,
int flags,
char *solaris_stream_name;
char *name;
int error;
return (error);
return (error);
char *solaris_stream_name;
int error;
return (error);
return (error);
char *solaris_stream_name;
int error;
if (error != 0)
return (error);
return (error);
* Note: stream_info.size is not filled in in this routine.
int nsize;
int error = 0;
char *tmp_name;
cr)) != 0)
return (error);
if (vpp)
if (xattrdirvpp)
return (error);
int error;
return (error);
int error;
return (error);
int error;
return (error);
int error;
switch (acl_type) {
case ACLENT_T:
case ACE_T:
return (EINVAL);
return (error);
int error;
int aclbsize;
if (error == 0) {
return (error);
int error;
if (error != 0) {
return (ACLENT_T);
return (ACE_T);
static int zfs_perms[] = {
int error, i;
int pnum;
*mode = 0;
for (i = 0; i < pnum; i++) {
if (error == 0)
for (i = 0; i < pnum; i++) {
if (error == 0)
short new_access = 0;
short deny = 0;
int flag = 0;
int cmd;
ACE_ADD_FILE)) {
static callb_cpr_t *