smbfs_vnops.c revision 9c9af2590af49bb395bc8d2eace0f2d4ea16d165
/*
* Copyright (c) 2000-2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/vfs_opreg.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
/*
* These characters are illegal in NTFS file names.
*
* Careful! The check in the XATTR case skips the
* first character to allow colon in XATTR names.
*/
static const char illegal_chars[] = {
':', /* colon - keep this first! */
'\\', /* back slash */
'/', /* slash */
'*', /* asterisk */
'?', /* question mark */
'"', /* double quote */
'<', /* less than sign */
'>', /* greater than sign */
'|', /* vertical bar */
0
};
/*
* Turning this on causes nodes to be created in the cache
* during directory listings. The "fast" claim is debatable,
* and the effects on the cache can be undesirable.
*/
/* local static function defines */
#ifdef USE_DNLC
#endif
int dnlc, caller_context_t *);
static int smbfs_accessx(void *, int, cred_t *);
caller_context_t *);
/*
* These are the vnode ops routines which implement the vnode interface to
* the networked file system. These routines just take their parameters,
* make them look networkish by putting the right info into interface structs,
* and then calling the appropriate remote routine(s) to do the work.
*
* Note on directory name lookup cacheing: If we detect a stale fhandle,
* we purge the directory cache relative to that vnode. This way, the
* more details on smbnode locking.
*/
caller_context_t *);
caller_context_t *);
caller_context_t *);
caller_context_t *);
caller_context_t *);
caller_context_t *);
int *, pathname_t *);
vsecattr_t *);
int);
caller_context_t *, int);
caller_context_t *, int);
caller_context_t *, int);
cred_t *, caller_context_t *);
caller_context_t *);
caller_context_t *);
caller_context_t *);
caller_context_t *);
/* Dummy function to use until correct function is ported in */
int noop_vnodeop() {
return (0);
}
/*
* Most unimplemented ops will return ENOSYS because of fs_nosys().
* The only ops where that won't work are ACCESS (due to open(2)
* failures) and ... (anything else left?)
*/
const fs_operation_def_t smbfs_vnodeops_template[] = {
};
/*
* XXX
* When new and relevant functionality is enabled, we should be
* calling vfs_set_feature() to inform callers that pieces of
* functionality are available, per PSARC 2007/227.
*/
/* ARGSUSED */
static int
{
int attrcacheupdated = 0;
int tmperror;
int error = 0;
return (EIO);
return (EIO);
return (EACCES);
}
/*
* Get exclusive access to n_fid and related stuff.
* No returns after this until out.
*/
return (EINTR);
/*
* Keep track of the vnode type at first open.
* It may change later, and we need close to do
* cleanup for the type we opened. Also deny
* open of new types until old type is closed.
* XXX: Per-open instance nodes whould help.
*/
SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
goto out;
}
/*
* Directory open is easy.
*/
goto have_fid;
}
/*
* FWRITE (to drive successful setattr(size=0) after open)
*/
/*
* If we already have it open, check to see if current rights
* are sufficient for this open.
*/
int upgrade = 0;
/* BEGIN CSTYLED */
upgrade = 1;
upgrade = 1;
/* END CSTYLED */
if (!upgrade) {
/*
* the existing open is good enough
*/
goto have_fid;
}
}
/*
* we always ask for READ_CONTROL so we can always get the
* XXX: verify that works with "drop boxes"
*/
/* XXX: open gets the current size, but we don't use it. */
if (error)
goto out;
/*
* We have a new FID and access rights.
*/
/*
* We already had it open (presumably because
* it was open with insufficient rights.)
* Close old wire-open.
*/
if (tmperror)
SMBVDEBUG("error %d closing %s\n",
}
/*
* This thread did the open.
* Save our credentials too.
*/
if (oldcr)
/*
* Keep track of the vnode type at first open.
* (see comments above)
*/
/* Get attributes (maybe). */
/* Darwin (derived) code. */
/*
* Try to get attributes, but don't bail on error.
* We already hold r_lkserlock/reader so note:
* this call will recursively take r_lkserlock.
*/
if (tmperror)
else
out:
return (error);
}
/*ARGSUSED*/
static int
{
int error = 0;
/*
* Don't "bail out" for VFS_UNMOUNTED here,
* as we want to do cleanup, etc.
*/
/*
* zone_enter(2) prevents processes from changing zones with SMBFS files
* open; if we happen to get here from the wrong zone we can't do
* anything over the wire.
*/
/*
* We could attempt to clean up locks, except we're sure
* that the current process didn't acquire any locks on
* the file: any attempt to lock a file belong to another zone
* will fail, and one can't lock an SMBFS file and then change
* zones, as that fails too.
*
* Returning an error here is the sane thing to do. A
* subsequent call to VN_RELE() which translates to a
* smbfs_inactive() will clean up state: if the zone of the
* vnode's origin is still alive and kicking, an async worker
* thread will handle the request (from the correct zone), and
* everything (minus the final smbfs_getattr_otw() call) should
* be OK. If the zone is going away smbfs_async_inactive() will
* throw away cached pages inline.
*/
return (EIO);
}
/*
* If we are using local locking for this filesystem, then
* release all of the SYSV style record locks. Otherwise,
* we are doing network locking and we need to release all
* of the network locks. All of the locks held by this
* process on this file are released no matter what the
* incoming reference count is.
*/
}
if (count > 1)
return (0);
/*
* OK, do "last close" stuff.
*/
/*
* Do the CIFS close.
* Darwin code
*/
/*
* Exclusive lock for modifying n_fid stuff.
* Don't want this one ever interruptible.
*/
error = 0;
/*
* Note that vp->v_type may change if a remote node
* is deleted and recreated as a different type, and
* our getattr may change v_type accordingly.
* Now use n_ovtype to keep track of the v_type
* we had during open (see comments above).
*/
struct smbfs_fctx *fctx;
goto out;
}
} else {
goto out;
}
}
if (error) {
SMBERROR("error %d closing %s\n",
}
/* Allow next open to use any v_type. */
out:
/* don't return any errors */
return (0);
}
/* ARGSUSED */
static int
{
/* u_offset_t off; */
/* offset_t diff; */
int error;
return (EIO);
return (EIO);
return (EISDIR);
return (0);
/*
* Like NFS3, just check for 63-bit overflow.
* Our SMB layer takes care to return EFBIG
* when it has to fallback to a 32-bit call.
*/
if (uiop->uio_loffset < 0 ||
return (EINVAL);
/* get vnode attributes from server */
return (error);
/* Update mtime with mtime from server here? */
/* if offset is beyond EOF, read nothing */
return (0);
/*
* Limit the read to the remaining file size.
* Do this by temporarily reducing uio_resid
* by the amount the lies beyoned the EOF.
*/
} else
past_eof = 0;
/* Shared lock for n_fid use in smb_rwuio */
return (EINTR);
&scred, smb_timo_read);
/* undo adjustment of resid */
return (error);
}
/* ARGSUSED */
static int
{
return (EIO);
return (EIO);
return (EISDIR);
return (0);
/*
* Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
*/
/* XXX: smbfs_vinvalbuf? */
}
}
/*
* File size can be changed by another client
*/
return (error);
}
/*
* Like NFS3, just check for 63-bit overflow.
*/
return (EINVAL);
/*
* Check to make sure that the process will not exceed
* its limit on file size. It is okay to write up to
* the limit, but not beyond. Thus, the write which
* reaches the limit will be short and the next write
* will return an error.
*
* So if we're starting at or beyond the limit, EFBIG.
* Otherwise, temporarily reduce resid to the amount
* the falls after the limit.
*/
limit = MAXOFFSET_T;
return (EFBIG);
} else
past_limit = 0;
/* Timeout: longer for append. */
/* Shared lock for n_fid use in smb_rwuio */
return (EINTR);
if (error == 0) {
/* Don't error the I/O if this fails. */
}
}
/* undo adjustment of resid */
return (error);
}
/* ARGSUSED */
static int
{
int error;
return (EIO);
return (EIO);
switch (cmd) {
/* First three from ZFS. XXX - need these? */
case _FIOFFS:
break;
/*
* The following two ioctls are used by bfu.
* Silently ignore to avoid bfu errors.
*/
case _FIOGDIO:
case _FIOSDIO:
error = 0;
break;
#ifdef NOT_YET /* XXX - from the NFS code. */
case _FIODIRECTIO:
#endif
/*
* Useful for testing, diagnosing idmap problems, etc.
*/
case SMBFSIO_GETSD:
break;
case SMBFSIO_SETSD:
break;
default:
break;
}
return (error);
}
/*
* Return either cached or remote attributes. If get remote attr
* use them to check and invalidate caches, then cache the new attributes.
*
* XXX
* This op should eventually support PSARC 2007/315, Extensible Attribute
* Interfaces, for richer metadata.
*/
/* ARGSUSED */
static int
{
return (EIO);
return (EIO);
/*
* If it has been specified that the return value will
* just be used as a hint, and we are only being asked
* for size, fsid or rdevid, then return the client's
* notion of these values without checking to make sure
* that the attribute cache is up to date.
* The whole point is to avoid an over the wire GETATTR
* call.
*/
return (0);
}
}
}
/*
* Mostly from Darwin smbfs_getattr()
*/
int
{
int error;
/*
* If we've got cached attributes, we're done, otherwise go
* to the server to get attributes, which will update the cache
* in the process.
*
* This section from Darwin smbfs_getattr,
* but then modified a lot.
*/
return (error);
/* Shared lock for (possible) n_fid use. */
return (EINTR);
if (!error) {
}
return (error);
}
/*
* XXX
* This op should eventually support PSARC 2007/315, Extensible Attribute
* Interfaces, for richer metadata.
*/
/*ARGSUSED4*/
static int
{
int error;
return (EIO);
return (EIO);
return (EINVAL);
if (error)
return (error);
smbfs_accessx, vp);
if (error)
return (error);
}
/*
* Mostly from Darwin smbfs_setattr()
* but then modified a lot.
*/
/* ARGSUSED */
static int
{
int error = 0;
unsigned short fid;
int have_fid = 0;
/*
* There are no settable attributes on the XATTR dir,
* so just silently ignore these. On XATTR files,
* you can set the size but nothing else.
*/
return (0);
SMBVDEBUG("ignore set time on xattr\n");
}
/*
* If our caller is trying to set multiple attributes, they
* can make no assumption about what order they are done in.
* Here we try to do them in order of decreasing likelihood
* of failure, just to minimize the chance we'll wind up
* with a partially complete request.
*/
/* Shared lock for (possible) n_fid use. */
return (EINTR);
/*
* Will we need an open handle for this setattr?
* If so, what rights will we need?
*/
rights |=
}
rights |=
/*
* Only SIZE requires a handle.
* XXX May be more reliable to just
* always get the file handle here.
*/
if (error) {
SMBVDEBUG("error %d opening %s\n",
goto out;
}
have_fid = 1;
}
/*
* If the server supports the UNIX extensions, right here is where
* we'd support changes to uid, gid, mode, and possibly va_flags.
* For now we claim to have made any such changes.
*/
/*
* If the new file size is less than what the client sees as
* the file size, then just change the size and invalidate
* the pages.
* I am commenting this code at present because the function
* smbfs_putapage() is not yet implemented.
*/
/*
* Set the file size to vap->va_size.
*/
if (error) {
SMBVDEBUG("setsize error %d file %s\n",
} else {
/*
* Darwin had code here to zero-extend.
* Tests indicate the server will zero-fill,
* so looks like we don't need to do this.
* Good thing, as this could take forever.
*/
modified = 1;
}
}
/*
* XXX: When Solaris has create_time, set that too.
* Note: create_time is different from ctime.
*/
/*
* If file is opened with write-attributes capability,
* we use handle-based calls. If not, we use path-based ones.
*/
if (have_fid) {
} else {
}
if (error) {
SMBVDEBUG("set times error %d file %s\n",
} else {
/* XXX: set np->n_mtime, etc? */
modified = 1;
}
}
out:
if (modified) {
/*
* Invalidate attribute cache in case if server doesn't set
* required attributes.
*/
/*
* XXX Darwin called _getattr here to
* update the mtime. Should we?
*/
}
if (have_fid) {
if (cerror)
SMBERROR("error %d closing %s\n",
}
return (error);
}
/*
* smbfs_access_rwx()
* Common function for smbfs_access, etc.
*
* The security model implemented by the FS is unusual
* due to our "single user mounts" restriction.
*
* All access under a given mount point uses the CIFS
* credentials established by the owner of the mount.
* provided by CIFS, and is instead fabricated using
* settings held in the mount structure.
*
* Most access checking is handled by the CIFS server,
* but we need sufficient Unix access checks here to
* prevent other local Unix users from having access
* settings in the mount would not allow.
*
* With this model, there is a case where we need the
* ability to do an access check before we have the
* vnode for an object. This function takes advantage
* avoids the need for a vnode.
*
* We still (sort of) need a vnode when we call
* secpolicy_vnode_access, but that only uses
* the vtype field, so we can use a pair of fake
* vnodes that have only v_type filled in.
*
* XXX: Later, add a new secpolicy_vtype_access()
* that takes the vtype instead of a vnode, and
* get rid of the tmpl_vxxx fake vnodes below.
*/
static int
{
/* See the secpolicy call below. */
int shift = 0;
/*
* Build our (fabricated) vnode attributes.
* XXX: Could make these templates in the
* per-mount struct and use them here.
*/
/*
* Disallow write attempts on read-only file systems,
* unless the file is a device or fifo node. Note:
* Inline vn_is_readonly and IS_DEVVP here because
* we may not have a vnode ptr. Original expr. was:
* (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
*/
return (EROFS);
/*
* Disallow attempts to access mandatory lock files.
* Similarly, expand MANDLOCK here.
* XXX: not sure we need this.
*/
return (EACCES);
/*
* Access check is based on only
* one of owner, group, public.
* If not owner, then check group.
* If not a member of the group,
* then check public access.
*/
shift += 3;
shift += 3;
}
if (mode == 0)
return (0);
/*
* We need a vnode for secpolicy_vnode_access,
* but the only thing it looks at is v_type,
* so pass one of the templates above.
*/
}
/*
* See smbfs_setattr
*/
static int
{
/*
* Note: The caller has checked the current zone,
* the SMI_DEAD and VFS_UNMOUNTED flags, etc.
*/
}
/*
* XXX
* This op should support PSARC 2007/403, Modified Access Checks for CIFS
*/
/* ARGSUSED */
static int
{
return (EIO);
return (EIO);
}
/*
* Flush local dirty pages to stable storage on the server.
*
* If FNODSYNC is specified, then there is nothing to do because
* metadata changes are not cached on the client before being
* sent to the server.
*
* Currently, this is a no-op since we don't cache data, either.
*/
/* ARGSUSED */
static int
{
int error = 0;
return (EIO);
return (EIO);
return (0);
return (error);
}
/*
* Last reference to vnode went away.
*/
/* ARGSUSED */
static void
{
/*
* Don't "bail out" for VFS_UNMOUNTED here,
* as we want to do cleanup, etc.
* See also pcfs_inactive
*/
/*
* If this is coming from the wrong zone, we let someone in the right
* zone take care of it asynchronously. We can get here due to
* VN_RELE() being called from pageout() or fsflush(). This call may
* potentially turn into an expensive no-op if, for instance, v_count
* gets incremented in the meantime, but it's still correct.
*/
/*
* Some paranoia from the Darwin code:
* Make sure the FID was closed.
* If we see this, it's a bug!
*
* No rw_enter here, as this should be the
* last ref, and we're just looking...
*/
SMBVDEBUG("opencount %d fid %d file %s\n",
}
SMBVDEBUG("opencount %d fid %d dir %s\n",
}
}
/*
* Remote file system operations having to do with directory manipulation.
*/
/* ARGSUSED */
static int
{
int error;
return (EPERM);
return (EIO);
/*
* Are we looking up extended attributes? If so, "dvp" is
* the file or directory for which we want attributes, and
* we need a lookup of the (faked up) attribute directory
* before we lookup the rest of the path.
*/
if (flags & LOOKUP_XATTR) {
/*
* Require the xattr mount option.
*/
return (EINVAL);
/*
* We don't allow recursive attributes.
*/
return (EINVAL);
return (error);
}
goto out;
}
out:
return (error);
}
/* ARGSUSED */
static int
{
int error;
int supplen; /* supported length */
/* struct smb_vc *vcp; */
const char *ill;
int rplen;
#ifdef NOT_YET
/* XXX: Should compute this once and store it in smbmntinfo_t */
#else
supplen = 255;
#endif
/*
* RWlock must be held, either reader or writer.
* XXX: Can we check without looking directly
* inside the struct smbfs_rwlock_t?
*/
/*
* If lookup is for "", just return dvp. Don't need
* to send it over the wire, look it up in the dnlc,
* or perform any access checks.
*/
if (nmlen == 0) {
return (0);
}
/*
* Can't do lookups in non-directories.
*/
return (ENOTDIR);
/*
* Need search permission in the directory.
*/
if (error)
return (error);
/*
* If lookup is for ".", just return dvp. Don't need
* to send it over the wire or look it up in the dnlc,
* just need to check access (done above).
*/
return (0);
}
/*
* Now some sanity checks on the name.
* First check the length.
*/
return (ENAMETOOLONG);
/*
* Avoid surprises with characters that are
* illegal in Windows file names.
* Todo: CATIA mappings XXX
*/
ill = illegal_chars;
ill++; /* allow colon */
return (EINVAL);
#ifdef USE_DNLC
if (dnlc) {
/*
* Lookup this name in the DNLC. If there was a valid entry,
* then return the results of the lookup.
*/
return (error);
}
#endif /* USE_DNLC */
/*
* Handle lookup of ".." which is quite tricky,
* because the protocol gives us little help.
*
* We keep full pathnames (as seen on the server)
* so we can just trim off the last component to
* get the full pathname of the parent. Note:
* We don't actually copy and modify, but just
* compute the trimmed length and pass that with
* the current dir path (not null terminated).
*
* We don't go over-the-wire to get attributes
* for ".." because we know it's a directory,
* and we can just leave the rest "stale"
* until someone does a getattr.
*/
/*
* Already at the root. This can happen
* with directory listings at the root,
* which lookup "." and ".." to get the
* inode numbers. Let ".." be the same
* as "." in the FS root.
*/
return (0);
}
/*
* Special case for XATTR directory
*/
/* Intentionally no dnlc_update */
return (error);
}
/*
* Find the parent path length.
*/
while (--rplen >= 0) {
break;
}
if (rplen == 0) {
/* Found our way to the root. */
return (0);
}
#ifdef USE_DNLC
#endif
/* Success! */
return (0);
}
/*
* Normal lookup of a child node.
* Note we handled "." and ".." above.
*
* First, go over-the-wire to get the
* node type (and attributes).
*/
/* Note: this can allocate a new "name" */
#ifdef USE_DNLC
#endif
if (error)
goto out;
/*
* Find or create the node.
*/
if (error)
goto out;
#ifdef USE_DNLC
#endif
/* Success! */
out:
/* smbfs_smb_lookup may have allocated name. */
return (error);
}
#ifdef USE_DNLC
#ifdef DEBUG
static int smbfs_lookup_dnlc_hits = 0;
static int smbfs_lookup_dnlc_misses = 0;
static int smbfs_lookup_dnlc_neg_hits = 0;
static int smbfs_lookup_dnlc_disappears = 0;
static int smbfs_lookup_dnlc_lookups = 0;
#endif
/* ARGSUSED */
static int
{
int error;
/*
* Lookup this name in the DNLC. If successful, then validate
* the caches and then recheck the DNLC. The DNLC is rechecked
* just in case this entry got invalidated during the call
* to smbfsgetattr().
* An assumption is being made that it is safe to say that a
* file exists which may not on the server. Any operations to
* the server will fail with ESTALE.
*/
#ifdef DEBUG
#endif
if (error)
return (error);
/*
* NFS checks VEXEC access here,
* but we've already done that
* in the caller.
*/
if (vp == DNLC_NO_VNODE) {
#ifdef DEBUG
#endif
return (ENOENT);
}
#ifdef DEBUG
#endif
return (0);
}
#ifdef DEBUG
#endif
}
#ifdef DEBUG
else
#endif
return (0);
}
#endif /* USE_DNLC */
/*
* XXX
* vsecattr_t is new to build 77, and we need to eventually support
* it in order to create an ACL when an object is created.
*
* This op should support the new FIGNORECASE flag for case-insensitive
* lookups, per PSARC 2007/244.
*/
/* ARGSUSED */
static int
{
int error;
int cerror;
#ifdef NOT_YET
#endif
int xattr;
return (EPERM);
return (EIO);
/*
* Note: this may break mknod(2) calls to create a directory,
* but that's obscure use. Some other filesystems do this.
* XXX: Later, redirect VDIR type here to _mkdir.
*/
return (EINVAL);
/*
* If the pathname is "", just use dvp, no checks.
* Do this outside of the rwlock (like zfs).
*/
if (nmlen == 0) {
return (0);
}
/* Don't allow "." or ".." through here. */
return (EISDIR);
/*
* We make a copy of the attributes because the caller does not
* expect us to change what va points to.
*/
return (EINTR);
/*
* XXX: Do we need r_lkserlock too?
* No use of any shared fid or fctx...
*/
/*
* NFS needs to go over the wire, just to be sure whether the
* file exists or not. Using the DNLC can be dangerous in
* this case when making a decision regarding existence.
*
* The SMB protocol does NOT really need to go OTW here
* thanks to the expressive NTCREATE disposition values.
* Unfortunately, to do Unix access checks correctly,
* we need to know if the object already exists.
* When the object does not exist, we need VWRITE on
* the directory. Note: smbfslookup() checks VEXEC.
*/
if (error == 0) {
/*
* The file already exists. Error?
* NB: have a hold from smbfslookup
*/
goto out;
}
/*
* Verify requested access.
*/
if (error) {
goto out;
}
/*
* Truncate (if requested).
*/
if (error) {
goto out;
}
}
/* Success! */
#ifdef NOT_YET
#endif
goto out;
}
/*
* The file did not exist. Need VWRITE in the directory.
*/
if (error)
goto out;
/*
* Now things get tricky. We also need to check the
* requested open mode against the file we may create.
* See comments at smbfs_access_rwx
*/
if (error)
goto out;
/* remove possible negative entry from the dnlc */
/*
* Now the code derived from Darwin,
* but with greater use of NT_CREATE
* disposition options. Much changed.
*
* Create (or open) a new child node.
* Note we handled "." and ".." above.
*/
else {
/* Truncate regular files if requested. */
else
}
if (error)
goto out;
/*
* XXX: Missing some code here to deal with
* the case where we opened an existing file,
* it's size is larger than 32-bits, and we're
* setting the size from a process that's not
* aware of large file offsets. i.e.
* from the NFS3 code:
*/
#if NOT_YET /* XXX */
/*
* Check here for large file handled
* by LF-unaware process (as
* ufs_create() does)
*/
}
if (!error) {
}
}
#endif /* XXX */
/*
* while we have it opened here. See above.
*/
if (cerror)
SMBERROR("error %d closing %s\\%s\n",
/*
* In the open case, the name may differ a little
* from what we passed to create (case, etc.)
* so call lookup to get the (opened) name.
*
* XXX: Could avoid this extra lookup if the
* "createact" result from NT_CREATE says we
* created the object.
*/
if (error)
goto out;
/* update attr and directory cache */
if (error)
goto out;
#ifdef USE_DNLC
#endif
/* XXX invalidate pages if we truncated? */
/* Success! */
error = 0;
out:
return (error);
}
/*
* XXX
* This op should support the new FIGNORECASE flag for case-insensitive
* lookups, per PSARC 2007/244.
*/
/* ARGSUSED */
static int
int flags)
{
int error;
/* enum smbfsstat status; */
return (EPERM);
return (EIO);
return (EINTR);
/*
* Verify access to the dirctory.
*/
if (error)
goto out;
/*
* NOTE: the darwin code gets the "vp" passed in so it looks
* like the "vp" has probably been "lookup"ed by the VFS layer.
* It looks like we will need to lookup the vp to check the
* caches and check if the object being deleted is a directory.
*/
if (error)
goto out;
goto out;
}
/*
* First just remove the entry from the name cache, as it
* is most likely the only entry for this vp.
*/
/*
* If the file has a v_count > 1 then there may be more than one
* entry in the name cache due multiple links or an open file,
* but we don't have the real reference count so flush all
* possible entries.
*/
/*
* Now we have the real reference count on the vnode
*/
/*
* NFS does a rename on remove here.
* Probably not applicable for SMB.
* Like Darwin, just return EBUSY.
*
* XXX: Todo - Ask the server to set the
* set the delete-on-close flag.
*/
} else {
}
out:
return (error);
}
/*
* XXX
* This op should support the new FIGNORECASE flag for case-insensitive
* lookups, per PSARC 2007/244.
*/
/* ARGSUSED */
static int
{
/* vnode_t *realvp; */
return (EPERM);
return (EIO);
}
/*
* smbfsrename does the real work of renaming in SMBFS
*/
/* ARGSUSED */
static int
{
int error;
int nvp_locked = 0;
/* enum smbfsstat status; */
return (EINVAL);
/*
* Check that everything is on the same filesystem.
* vn_rename checks the fsid's, but in case we don't
* fill those in correctly, check here too.
*/
return (EXDEV);
/*
* Avoid deadlock here on old vs new directory nodes
* by always taking the locks in order of address.
* The order is arbitrary, but must be consistent.
*/
return (EINTR);
return (EINTR);
}
} else {
return (EINTR);
return (EINTR);
}
}
/*
* No returns after this point (goto out)
*/
/*
* Need write access on source and target.
* Server takes care of most checks.
*/
if (error)
goto out;
if (error)
goto out;
}
/*
* Lookup the source name. Must already exist.
*/
if (error)
goto out;
/*
* Lookup the target file. If it exists, it needs to be
* checked to see whether it is a mount point and whether
* it is active (open).
*/
if (!error) {
/*
* Target (nvp) already exists. Check that it
* has the same type as the source. The server
* will check this also, (and more reliably) but
* this lets us return the correct error codes.
*/
goto out;
}
} else {
goto out;
}
}
/*
* POSIX dictates that when the source and target
* entries refer to the same file object, rename
* must do nothing and exit without error.
*/
error = 0;
goto out;
}
/*
* Also must ensure the target is not a mount point,
*/
if (vn_vfsrlock(nvp)) {
goto out;
}
nvp_locked = 1;
goto out;
}
/*
* Purge the name cache of all references to this vnode
* so that we can check the reference count to infer
* whether it is active or not.
*/
/*
* First just remove the entry from the name cache, as it
* is most likely the only entry for this vp.
*/
/*
* If the file has a v_count > 1 then there may be more
* than one entry in the name cache due multiple links
* or an open file, but we don't have the real reference
* count so flush all possible entries.
*/
/*
* when renaming directories to be a subdirectory of a
* different parent, the dnlc entry for ".." will no
* longer be valid, so it must be removed
*/
}
}
/*
* CIFS gives a SHARING_VIOLATION error when
* trying to rename onto an exising object,
* so try to remove the target first.
* (Only for files, not directories.)
*/
goto out;
}
/*
* Nodes that are "not active" here have v_count=2
* because vn_renameat (our caller) did a lookup on
* both the source and target before this call.
* Otherwise this similar to smbfs_remove.
*/
/*
* The target file exists, is not the same as
* the source file, and is active. Other FS
* implementations unlink the target here.
* For SMB, we don't assume we can remove an
* open file. Return an error instead.
*/
goto out;
}
/*
* Target file is not active. Try to remove it.
*/
if (error)
goto out;
/*
* OK, removed the target file. Continue as if
* lookup target had failed (nvp == NULL).
*/
nvp_locked = 0;
} /* nvp */
out:
if (nvp) {
if (nvp_locked)
}
if (ovp)
return (error);
}
/*
* XXX
* vsecattr_t is new to build 77, and we need to eventually support
* it in order to create an ACL when an object is created.
*
* This op should support the new FIGNORECASE flag for case-insensitive
* lookups, per PSARC 2007/244.
*/
/* ARGSUSED */
static int
{
return (EPERM);
return (EIO);
return (EEXIST);
/* Only plain files are allowed in V_XATTRDIR. */
return (EINVAL);
return (EINTR);
/*
* XXX: Do we need r_lkserlock too?
* No use of any shared fid or fctx...
*/
/*
* Require write access in the containing directory.
*/
if (error)
goto out;
/* remove possible negative entry from the dnlc */
if (error)
goto out;
if (error)
goto out;
if (error)
goto out;
#ifdef USE_DNLC
#endif
if (name[0] == '.')
/* Success! */
error = 0;
out:
return (error);
}
/*
* XXX
* This op should support the new FIGNORECASE flag for case-insensitive
* lookups, per PSARC 2007/244.
*/
/* ARGSUSED */
static int
{
int vp_locked = 0;
int error;
return (EPERM);
return (EIO);
return (EINTR);
/*
* Require w/x access in the containing directory.
* Server handles all other access checks.
*/
if (error)
goto out;
/*
* First lookup the entry to be removed.
*/
if (error)
goto out;
/*
* Disallow rmdir of "." or current dir, or the FS root.
* Also make sure it's a directory, not a mount point,
*/
goto out;
}
goto out;
}
if (vn_vfsrlock(vp)) {
goto out;
}
vp_locked = 1;
goto out;
}
/*
* First just remove the entry from the name cache, as it
* is most likely an entry for this vp.
*/
/*
* If there vnode reference count is greater than one, then
* there may be additional references in the DNLC which will
* need to be purged. First, trying removing the entry for
* the parent directory and see if that removes the additional
* reference(s). If that doesn't do it, then use dnlc_purge_vp
* to completely remove any references to the directory which
* might still exist in the DNLC.
*/
}
if (error)
goto out;
smb_rmhash(np);
out:
if (vp) {
if (vp_locked)
}
return (error);
}
/* ARGSUSED */
static int
{
int error = 0;
return (EIO);
return (EIO);
/*
* Require read access in the directory.
*/
if (error)
return (error);
/*
* XXX: Todo readdir cache here
* Note: NFS code is just below this.
*
* I am serializing the entire readdir opreation
* now since we have not yet implemented readdir
* cache. This fix needs to be revisited once
* we implement readdir cache.
*/
return (EINTR);
return (error);
}
/* ARGSUSED */
static int
{
struct smbfs_fctx *ctx;
/* Make sure we serialize for n_dirseq use. */
/* Min size is DIRENT64_RECLEN(256) rounded up. */
return (EINVAL);
/*
* This dnlc_purge_vp ensures that name cache for this dir will be
* current - it'll only have the items for which the smbfs_nget
* MAKEENTRY happened.
*/
#ifdef NOT_YET
if (smbfs_fastlookup)
#endif
if (offset == 0) {
/* Don't know EOF until findclose */
/* Arrived at end of directory. */
goto out;
}
/*
* Generate the "." and ".." entries here so we can
* (1) make sure they appear (but only once), and
* (2) deal with getting their I numbers which the
* findnext below does only for normal names.
*/
limit--;
/*LINTED*/
/* Tricky: offset 0 is ".", offset 1 is ".." */
/*
* Want the real I-numbers for the "." and ".."
* entries. For these two names, we know that
* smbfslookup can do this all locally.
*/
if (error) {
} else {
}
if (error)
goto out;
}
if (limit == 0)
goto out;
}
if (error) {
goto out;
}
} else
&scred) != 0) {
*eofp = 1;
error = 0;
goto out;
}
}
error = 0;
if (error) {
*eofp = 1;
error = 0;
break;
}
/* Sanity check the name length. */
}
break;
/*LINTED*/
/*
* Note: d_off is the offset that a user-level program
* should seek to for reading the _next_ directory entry.
* See libc: readdir, telldir, seekdir
*/
#ifdef NOT_YET
if (smbfs_fastlookup) {
}
#endif /* NOT_YET */
if (error)
break;
}
error = 0;
out:
return (error);
}
/*
* The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
* are optional functions that are called by:
* (other places)
*
* Careful here: None of the above check for any
* error returns from VOP_RWLOCK / VOP_RWUNLOCK!
* In fact, the return value from _rwlock is NOT
* an error code, but V_WRITELOCK_TRUE / _FALSE.
*
* Therefore, it's up to _this_ code to make sure
* the lock state remains balanced, which means
* we can't "bail out" on interrupts, etc.
*/
/* ARGSUSED2 */
static int
{
if (!write_lock) {
return (V_WRITELOCK_FALSE);
}
return (V_WRITELOCK_TRUE);
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static int
{
return (EPERM);
return (EIO);
/*
* Because we stuff the readdir cookie into the offset field
* someone may attempt to do an lseek with the cookie which
* we want to succeed.
*/
return (0);
/* Like NFS3, just check for 63-bit overflow. */
if (*noffp < 0)
return (EINVAL);
return (0);
}
/*
* XXX
* This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
*/
static int
{
return (EIO);
else
return (ENOSYS);
}
/*
* Free storage space associated with the specified vnode. The portion
* to be freed is specified by bfp->l_start and bfp->l_len (already
* normalized to a "whence" of 0).
*
* Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
*/
/* ARGSUSED */
static int
{
int error;
return (EIO);
return (EIO);
/* Caller (fcntl) has checked v_type */
return (EINVAL);
/*
* Like NFS3, no 32-bit offset checks here.
* Our SMB layer takes care to return EFBIG
* when it has to fallback to a 32-bit call.
*/
if (!error) {
/*
* ftruncate should not change the ctime and
* mtime if we truncate the file to its
* previous size.
*/
return (error);
} else
}
return (error);
}
/* ARGSUSED */
static int
{
return (EIO);
return (EIO);
switch (cmd) {
case _PC_FILESIZEBITS:
*valp = 64;
else
*valp = 32;
break;
case _PC_LINK_MAX:
/* We only ever report one link to an object */
*valp = 1;
break;
case _PC_ACL_ENABLED:
/*
* Always say "yes" here. Our _getsecattr
* will build a trivial ACL when needed,
* i.e. when server does not have ACLs.
*/
*valp = _ACL_ACE_ENABLED;
break;
case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */
*valp = 0;
break;
case _PC_XATTR_EXISTS:
break;
}
return (EINVAL);
default:
}
return (0);
}
/* ARGSUSED */
static int
{
return (EIO);
return (EIO);
/*
* Our _pathconf indicates _ACL_ACE_ENABLED,
* so we should only see VSA_ACE, etc here.
* Note: vn_create asks for VSA_DFACLCNT,
* and it expects ENOSYS and empty data.
*/
if (mask == 0)
return (ENOSYS);
/* XXX - access check ACE_READ_ACL? */
} else
return (error);
}
/* ARGSUSED */
static int
{
int error;
return (EIO);
return (EIO);
/*
* Our _pathconf indicates _ACL_ACE_ENABLED,
* so we should only see VSA_ACE, etc here.
*/
if (mask == 0)
return (ENOSYS);
/*
* If and when smbfs_access is extended, we can
* check ACE_WRITE_ACL here instead. (XXX todo)
* For now, in-line parts of smbfs_access,
* i.e. only allow _setacl by the owner,
* and check for read-only FS.
*/
return (EROFS);
return (EACCES);
} else
return (error);
}
/*
* XXX
* This op should eventually support PSARC 2007/268.
*/
static int
{
return (EIO);
else
return (ENOSYS);
}