X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e2fac8b15b12a7979f72090454d850e612fc5b13..b0d623f7f2ae71ed96e60569f61f9a9a27016e80:/bsd/miscfs/synthfs/synthfs_vnops.c diff --git a/bsd/miscfs/synthfs/synthfs_vnops.c b/bsd/miscfs/synthfs/synthfs_vnops.c deleted file mode 100644 index d409494e8..000000000 --- a/bsd/miscfs/synthfs/synthfs_vnops.c +++ /dev/null @@ -1,1327 +0,0 @@ -/* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved. - * - * Modification History: - * - * 02-Feb-2000 Clark Warner Added copyfile to table - * 17-Aug-1999 Pat Dirks New today. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "synthfs.h" - -#define RWSUPPORT 0 - -#if RWSUPPORT -#error NOT PORTED FOR UBC -#include -#endif - -static int synthfs_remove_internal(struct vnode *dvp, struct vnode *vp, - struct componentname *cnp, vfs_context_t context); - - -#define VOPFUNC int (*)(void *) - -/* Global vfs data structures for synthfs. */ -int (**synthfs_vnodeop_p) (void *); -struct vnodeopv_entry_desc synthfs_vnodeop_entries[] = { - {&vnop_default_desc, (VOPFUNC)vn_default_error}, - {&vnop_strategy_desc, (VOPFUNC)err_strategy}, /* strategy - not supported */ - {&vnop_bwrite_desc, (VOPFUNC)err_bwrite}, /* bwrite - not supported */ - {&vnop_lookup_desc, (VOPFUNC)synthfs_cached_lookup}, /* cached lookup */ - {&vnop_create_desc, (VOPFUNC)synthfs_create}, /* create - DEBUGGER */ - {&vnop_whiteout_desc, (VOPFUNC)err_whiteout}, /* whiteout - not supported */ - {&vnop_mknod_desc, (VOPFUNC)err_mknod}, /* mknod - not supported */ - {&vnop_open_desc, (VOPFUNC)synthfs_open}, /* open - DEBUGGER */ - {&vnop_close_desc, (VOPFUNC)nop_close}, /* close - NOP */ - {&vnop_getattr_desc, (VOPFUNC)synthfs_getattr}, /* getattr */ - {&vnop_setattr_desc, (VOPFUNC)synthfs_setattr}, /* setattr */ - {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist - not supported */ - {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist - not supported */ - {&vnop_read_desc, (VOPFUNC)err_read}, /* read - not supported */ - {&vnop_write_desc, (VOPFUNC)err_write}, /* write - not supported */ - {&vnop_ioctl_desc, (VOPFUNC)err_ioctl}, /* ioctl - not supported */ - {&vnop_select_desc, (VOPFUNC)synthfs_select}, /* select */ - {&vnop_exchange_desc, (VOPFUNC)err_exchange}, /* exchange - not supported */ - {&vnop_revoke_desc, (VOPFUNC)nop_revoke}, /* revoke - NOP */ - {&vnop_mmap_desc, (VOPFUNC)synthfs_mmap}, /* mmap - DEBUGGER */ - {&vnop_fsync_desc, (VOPFUNC)nop_fsync}, /* fsync - NOP */ - {&vnop_remove_desc, (VOPFUNC)synthfs_remove}, /* remove */ - {&vnop_link_desc, (VOPFUNC)err_link}, /* link - not supported */ - {&vnop_rename_desc, (VOPFUNC)synthfs_rename}, /* rename */ - {&vnop_mkdir_desc, (VOPFUNC)synthfs_mkdir}, /* mkdir */ - {&vnop_rmdir_desc, (VOPFUNC)synthfs_rmdir}, /* rmdir */ - {&vnop_symlink_desc, (VOPFUNC)synthfs_symlink}, /* symlink */ - {&vnop_readdir_desc, (VOPFUNC)synthfs_readdir}, /* readdir */ - {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr - not supported */ - {&vnop_readlink_desc, (VOPFUNC)synthfs_readlink}, /* readlink */ - {&vnop_inactive_desc, (VOPFUNC)synthfs_inactive}, /* inactive */ - {&vnop_reclaim_desc, (VOPFUNC)synthfs_reclaim}, /* reclaim */ - {&vnop_pathconf_desc, (VOPFUNC)synthfs_pathconf}, /* pathconf */ - {&vnop_advlock_desc, (VOPFUNC)err_advlock}, /* advlock - not supported */ - {&vnop_allocate_desc, (VOPFUNC)err_allocate}, /* allocate - not supported */ - {&vnop_pagein_desc, (VOPFUNC)err_pagein}, /* pagein - not supported */ - {&vnop_pageout_desc, (VOPFUNC)err_pageout}, /* pageout - not supported */ - {&vnop_searchfs_desc, (VOPFUNC)err_searchfs}, /* searchfs - not supported */ - {&vnop_copyfile_desc, (VOPFUNC)err_copyfile}, /* copyfile - not supported */ - { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff not supported */ - { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk not supported */ - { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap not supported */ - {(struct vnodeop_desc *) NULL, (int (*) ()) NULL} -}; - -/* - * Oh what a tangled web we weave. This structure will be used by - * bsd/vfs/vfs_conf.c to actually do the initialization of synthfs_vnodeop_p - */ -struct vnodeopv_desc synthfs_vnodeop_opv_desc = -{&synthfs_vnodeop_p, synthfs_vnodeop_entries}; - - - -/* - * Create a regular file -#% create dvp L U U -#% create vpp - L - -# - vnop_create { - IN WILLRELE struct vnode *dvp; - OUT struct vnode **vpp; - IN struct componentname *cnp; - IN struct vnode_attr *vap; - - We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is - a previous error. - -*/ - -int -synthfs_create(ap) -struct vnop_create_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vnode_attr *a_vap; - vfs_context_t a_context; -} */ *ap; -{ -#if DEBUG - struct vnode *dvp = ap->a_dvp; - char debugmsg[255]; - - sprintf(debugmsg, "synthfs_create: attempt to create '%s' in '%s' ?!", ap->a_cnp->cn_nameptr, VTOS(dvp)->s_name); - Debugger(debugmsg); -#endif - - return err_create(ap); -} - - - -/* - * Open called. -#% open vp L L L -# - vnop_open { - IN struct vnode *vp; - IN int mode; - IN vfs_context_t a_context; - */ - -int -synthfs_open(ap) -struct vnop_open_args /* { - struct vnode *a_vp; - int a_mode; - vfs_context_t a_context; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - - if (vp->v_type == VDIR) { - return 0; - } else { -#if DEBUG - struct synthfsnode *sp = VTOS(vp); - char debugmsg[255]; - - sprintf(debugmsg, "synthfs_open: attempt to open '/%s' ?!", sp->s_name); - Debugger(debugmsg); -#endif - }; - - return 0; -} - - - -/* - * Mmap a file - * - * NB Currently unsupported. -# XXX - not used -# - vnop_mmap { - IN struct vnode *vp; - IN int fflags; - IN kauth_cred_t cred; - IN struct proc *p; - - */ - -/* ARGSUSED */ - -int -synthfs_mmap(__unused struct vnop_mmap_args *ap) -{ - return EINVAL; -} - - - -/* -#% getattr vp = = = -# - vnop_getattr { - IN struct vnode *vp; - IN struct vnode_attr *vap; - IN vfs_context_t context; - -*/ -int -synthfs_getattr(ap) -struct vnop_getattr_args /* { - struct vnode *a_vp; - struct vnode_attr *a_vap; - vfs_context_t a_context; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct vnode_attr *vap = ap->a_vap; - struct synthfsnode *sp = VTOS(vp); - - VATTR_RETURN(vap, va_type, vp->v_type); - VATTR_RETURN(vap, va_mode, sp->s_mode); - VATTR_RETURN(vap, va_nlink, sp->s_linkcount); - VATTR_RETURN(vap, va_uid, sp->s_uid); - VATTR_RETURN(vap, va_gid, sp->s_gid); - VATTR_RETURN(vap, va_fsid, VTOVFS(vp)->mnt_vfsstat.f_fsid.val[0]); - VATTR_RETURN(vap, va_fileid, sp->s_nodeid); - switch (vp->v_type) { - case VDIR: - VATTR_RETURN(vap, va_data_size, (sp->s_u.d.d_entrycount + 2) * sizeof(struct dirent)); - break; - - case VREG: - VATTR_RETURN(vap, va_data_size, sp->s_u.f.f_size); - break; - - case VLNK: - VATTR_RETURN(vap, va_data_size, sp->s_u.s.s_length); - break; - - default: - VATTR_RETURN(vap, va_data_size, 0); - }; - VATTR_RETURN(vap, va_iosize, 512); - vap->va_access_time.tv_sec = sp->s_accesstime.tv_sec; - vap->va_access_time.tv_nsec = sp->s_accesstime.tv_usec * 1000; - VATTR_SET_SUPPORTED(vap, va_access_time); - vap->va_modify_time.tv_sec = sp->s_modificationtime.tv_sec; - vap->va_modify_time.tv_nsec = sp->s_modificationtime.tv_usec * 1000; - VATTR_SET_SUPPORTED(vap, va_modify_time); - vap->va_change_time.tv_sec = sp->s_changetime.tv_sec; - vap->va_change_time.tv_nsec = sp->s_changetime.tv_usec * 1000; - VATTR_SET_SUPPORTED(vap, va_change_time); - VATTR_RETURN(vap, va_gen, sp->s_generation); - VATTR_RETURN(vap, va_flags, sp->s_flags); - VATTR_RETURN(vap, va_rdev, sp->s_rdev); - VATTR_RETURN(vap, va_filerev, 0); - VATTR_RETURN(vap, va_acl, NULL); - - return (0); -} - - - -/* - * Change the mode on a file or directory. - * vnode vp must be locked on entry. - */ -int synthfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct proc *p) -{ - struct synthfsnode *sp = VTOS(vp); - int result; - - sp->s_mode &= ~ALLPERMS; - sp->s_mode |= (mode & ALLPERMS); - sp->s_nodeflags |= IN_CHANGE; -#if RWSUPPORT - if ((vp->v_flag & VTEXT) && (sp->s_mode & S_ISTXT) == 0) (void) vnode_uncache(vp); -#endif - - return 0; -} - - - -/* - * Change the flags on a file or directory. - * vnode vp must be locked on entry. - */ -int synthfs_chflags(struct vnode *vp, u_long flags, kauth_cred_t cred, struct proc *p) -{ - struct synthfsnode *sp = VTOS(vp); - - sp->s_flags = flags; - sp->s_nodeflags |= IN_CHANGE; - - return 0; -} - - - -/* - * Perform chown operation on vnode vp; - * vnode vp must be locked on entry. - */ -int synthfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, struct proc *p) -{ - struct synthfsnode *sp = VTOS(vp); - uid_t ouid; - gid_t ogid; - int result = 0; - int is_member; - - if (uid == (uid_t)VNOVAL) uid = sp->s_uid; - if (gid == (gid_t)VNOVAL) gid = sp->s_gid; - - ogid = sp->s_gid; - ouid = sp->s_uid; - - sp->s_gid = gid; - sp->s_uid = uid; - - if (ouid != uid || ogid != gid) sp->s_nodeflags |= IN_CHANGE; - if (ouid != uid && suser(cred, NULL)) sp->s_mode &= ~S_ISUID; - if (ogid != gid && suser(cred, NULL)) sp->s_mode &= ~S_ISGID; - - return 0; -} - - - -/* - * Set attribute vnode op. called from several syscalls -#% setattr vp L L L -# - vnop_setattr { - IN struct vnode *vp; - IN struct vnode_attr *vap; - IN vfs_context_t context; - */ - -int -synthfs_setattr(ap) -struct vnop_setattr_args /* { -struct vnode *a_vp; -struct vnode_attr *a_vap; -vfs_context_t a_context; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct synthfsnode *sp = VTOS(vp); - struct vnode_attr *vap = ap->a_vap; - kauth_cred_t cred = vfs_context_ucred(ap->a_context); - struct proc *p = vfs_context_proc(ap->a_context); - struct timeval atimeval, mtimeval; - uid_t nuid; - gid_t ngid; - int result; - - result = 0; - - if (VATTR_IS_ACTIVE(vap, va_flags)) { - if ((result = synthfs_chflags(vp, vap->va_flags, cred, p))) { - goto Err_Exit; - } - } - VATTR_SET_SUPPORTED(vap, va_flags); - - nuid = (uid_t)ngid = (gid_t)VNOVAL; - if (VATTR_IS_ACTIVE(vap, va_uid)) - nuid = vap->va_uid; - if (VATTR_IS_ACTIVE(vap, va_gid)) - ngid = vap->va_gid; - if (nuid != (uid_t)VNOVAL || ngid != (gid_t)VNOVAL) { - if ((result = synthfs_chown(vp, nuid, ngid, cred, p))) { - goto Err_Exit; - } - } - VATTR_SET_SUPPORTED(vap, va_uid); - VATTR_SET_SUPPORTED(vap, va_gid); - - if (VATTR_IS_ACTIVE(vap, va_data_size)) { -#if RWSUPPORT - if ((result = vnode_setsize(vp, vap->va_data_size, 0, ap->a_context))) { - goto Err_Exit; - }; - VATTR_SET_SUPPORTED(vap, va_data_size); -#else - result = EINVAL; - goto Err_Exit; -#endif - } - - sp = VTOS(vp); - if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) { - if (VATTR_IS_ACTIVE(vap, va_access_time)) { - sp->s_nodeflags |= IN_ACCESS; - atimeval.tv_sec = vap->va_access_time.tv_sec; - atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000; - } - if (VATTR_IS_ACTIVE(vap, va_modify_time)) { - sp->s_nodeflags |= IN_CHANGE | IN_UPDATE; - mtimeval.tv_sec = vap->va_modify_time.tv_sec; - mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000; - } - if ((result = synthfs_update(vp, &atimeval, &mtimeval, 1))) { - goto Err_Exit; - } - } - VATTR_SET_SUPPORTED(vap, va_access_time); - VATTR_SET_SUPPORTED(vap, va_modify_time); - - if (VATTR_IS_ACTIVE(vap, va_mode)) - result = synthfs_chmod(vp, (int)vap->va_mode, cred, p); - VATTR_SET_SUPPORTED(vap, va_mode); - - Err_Exit: - - DBG_VOP(("synthfs_setattr: returning %d...\n", result)); - - return (result); -} - - - -/* - -#% rename sourcePar_vp U U U -#% rename source_vp U U U -#% rename targetPar_vp L U U -#% rename target_vp X U U -# - vnop_rename { - IN WILLRELE struct vnode *sourcePar_vp; - IN WILLRELE struct vnode *source_vp; - IN struct componentname *source_cnp; - IN WILLRELE struct vnode *targetPar_vp; - IN WILLRELE struct vnode *target_vp; - IN struct componentname *target_cnp; - - - */ - -/* - * On entry: - * source's parent directory is unlocked - * source file or directory is unlocked - * destination's parent directory is locked - * destination file or directory is locked if it exists - * - * On exit: - * all denodes should be released - * - */ - -int -synthfs_rename(ap) -struct vnop_rename_args /* { - struct vnode *a_fdvp; - struct vnode *a_fvp; - struct componentname *a_fcnp; - struct vnode *a_tdvp; - struct vnode *a_tvp; - struct componentname *a_tcnp; - vfs_context_t a_context; -} */ *ap; -{ - struct vnode *target_vp = ap->a_tvp; - struct vnode *targetPar_vp = ap->a_tdvp; - struct vnode *source_vp = ap->a_fvp; - struct vnode *sourcePar_vp = ap->a_fdvp; - struct componentname *target_cnp = ap->a_tcnp; - struct componentname *source_cnp = ap->a_fcnp; - struct synthfsnode *target_sp, *targetPar_sp, *source_sp, *sourcePar_sp; - u_short doingdirectory = 0, oldparent = 0, newparent = 0; - int retval = 0; - struct timeval tv; - -#if SYNTHFS_DIAGNOSTIC - if ((target_cnp->cn_flags & HASBUF) == 0 || - (source_cnp->cn_flags & HASBUF) == 0) - panic("synthfs_rename: no name"); -#endif - - DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR)); - target_sp = targetPar_sp = source_sp = sourcePar_sp = NULL; - - - sourcePar_sp = VTOS(sourcePar_vp); - source_sp = VTOS(source_vp); - oldparent = sourcePar_sp->s_nodeid; - - /* - * Be sure we are not renaming ".", "..", or an alias of ".". This - * leads to a crippled directory tree. It's pretty tough to do a - * "ls" or "pwd" with the "." directory entry missing, and "cd .." - * doesn't work if the ".." entry is missing. - */ - if (source_sp->s_type == SYNTHFS_DIRECTORY) { - if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.') - || sourcePar_sp == source_sp - || (source_cnp->cn_flags & ISDOTDOT) - || (source_sp->s_nodeflags & IN_RENAME)) { - retval = EINVAL; - goto abortit; - } - source_sp->s_nodeflags |= IN_RENAME; - doingdirectory = TRUE; - } - - /* Transit between abort and bad */ - - targetPar_sp = VTOS(targetPar_vp); - target_sp = target_vp ? VTOS(target_vp) : NULL; - newparent = targetPar_sp->s_nodeid; - - - /* - * If the destination exists, then be sure its type (file or dir) - * matches that of the source. And, if it is a directory make sure - * it is empty. Then delete the destination. - */ - if (target_vp) { - -#if RWSUPPORT - if (target_vp->v_type == VREG) { - (void) vnode_uncache(target_vp); - }; -#endif - cache_purge(target_vp); - - retval = synthfs_remove_internal(targetPar_vp, target_vp, target_cnp, ap->a_context); - - target_vp = NULL; - target_sp = NULL; - - if (retval) goto bad; - }; - - - /* remove the existing entry from the namei cache: */ - if (source_vp->v_type == VREG) cache_purge(source_vp); - - retval = synthfs_move_rename_entry( source_vp, targetPar_vp, target_cnp->cn_nameptr); - - if (retval) goto bad; - - source_sp->s_nodeflags &= ~IN_RENAME; - - /* - * Timestamp both parent directories. - * Note that if this is a rename within the same directory, - * (where targetPar_hp == sourcePar_hp) - * the code below is still safe and correct. - */ - targetPar_sp->s_nodeflags |= IN_UPDATE; - sourcePar_sp->s_nodeflags |= IN_UPDATE; - - microtime(&tv); - SYNTHFSTIMES(targetPar_sp, &tv, &tv); - SYNTHFSTIMES(sourcePar_sp, &tv, &tv); - - return (retval); - -bad:; - if (retval && doingdirectory) - source_sp->s_nodeflags &= ~IN_RENAME; - - return (retval); - -abortit:; - return (retval); -} - - - -/* - * Mkdir system call - -#% mkdir dvp L U U -#% mkdir vpp - L - -# - vnop_mkdir { - IN WILLRELE struct vnode *dvp; - OUT struct vnode **vpp; - IN struct componentname *cnp; - IN struct vnode_attr *vap; - IN vfs_context_t context; - - We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is - a previous error. - -*/ - -int -synthfs_mkdir(ap) -struct vnop_mkdir_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vnode_attr *a_vap; - vfs_context_t a_context; -} */ *ap; -{ - int retval; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct vnode *vp = NULL; - - *ap->a_vpp = NULL; - - retval = synthfs_new_directory(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, mode, vfs_context_proc(cnp->cn_context), &vp); - if (retval) goto Error_Exit; - - *ap->a_vpp = vp; - - retval = vnode_setattr(vp, ap->a_vap, ap->a_context); - if (retval != 0) goto Error_Exit; - - Error_Exit:; - if (retval != 0) { - if (vp) synthfs_remove_directory(vp); - } - - return retval; -} - - - -/* - -#% remove dvp L U U -#% remove vp L U U -# - vnop_remove { - IN WILLRELE struct vnode *dvp; - IN WILLRELE struct vnode *vp; - IN struct componentname *cnp; - IN vfs_context_t context; - - */ - -int -synthfs_remove(ap) -struct vnop_remove_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; - vfs_context_t a_context; -} */ *ap; -{ - return synthfs_remove_internal(ap->a_dvp, ap->a_vp, ap->a_cnp, ap->a_context); -} - -static int -synthfs_remove_internal(struct vnode *dvp, struct vnode *vp, - __unused struct componentname *cnp, - __unused vfs_context_t context) -{ - struct synthfsnode *sp = VTOS(vp); - struct timeval tv; - int retval = 0; - - /* This is sort of silly right now but someday it may make sense... */ - if (sp->s_nodeflags & IN_MODIFIED) { - microtime(&tv); - synthfs_update(vp, &tv, &tv, 0); - }; - - /* remove the entry from the namei cache: */ - cache_purge(vp); - - /* remove entry from tree and reclaim any resources consumed: */ - switch (sp->s_type) { - case SYNTHFS_DIRECTORY: - synthfs_remove_directory(vp); - break; - - - case SYNTHFS_SYMLINK: - synthfs_remove_symlink(vp); - break; - - case SYNTHFS_FILE: - /* Fall through to default case */ - - default: - synthfs_remove_entry(vp); - }; - -out: - - if (! retval) - VTOS(dvp)->s_nodeflags |= IN_CHANGE | IN_UPDATE; - - return (retval); -} - - - -/* -#% rmdir dvp L U U -#% rmdir vp L U U -# - vnop_rmdir { - IN WILLRELE struct vnode *dvp; - IN WILLRELE struct vnode *vp; - IN struct componentname *cnp; - IN vfs_context_t context; - - */ - -int -synthfs_rmdir(ap) - struct vnop_rmdir_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; - vfs_context_t a_context; -} */ *ap; -{ - return synthfs_remove((struct vnop_remove_args *)ap); -} - - - -/* - * synthfs_select - just say OK. Only possible op is readdir - * - * Locking policy: ignore - */ -int -synthfs_select(__unused -struct vnop_select_args /* { - struct vnode *a_vp; - int a_which; - int a_fflags; - kauth_cred_t a_cred; - void *a_wql; - struct proc *a_p; -} */ *ap) -{ - DBG_VOP(("synthfs_select called\n")); - - return (1); -} - -/* -# -#% symlink dvp L U U -#% symlink vpp - U - -# -# XXX - note that the return vnode has already been vnode_put'ed -# by the filesystem layer. To use it you must use vnode_get, -# possibly with a further namei. -# - vnop_symlink { - IN WILLRELE struct vnode *dvp; - OUT WILLRELE struct vnode **vpp; - IN struct componentname *cnp; - IN struct vnode_attr *vap; - IN char *target; - - We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is - a previous error. - - -*/ - -int -synthfs_symlink(ap) - struct vnop_symlink_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vnode_attr *a_vap; - char *a_target; - vfs_context_t a_context; - } */ *ap; -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - int retval; - - *vpp = NULL; - - retval = synthfs_new_symlink(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, ap->a_target, vfs_context_proc(cnp->cn_context), vpp); - - return (retval); -} - - - -/* -# -#% readlink vp L L L -# - vnop_readlink { - IN struct vnode *vp; - INOUT struct uio *uio; - IN kauth_cred_t cred; - */ - -int -synthfs_readlink(ap) -struct vnop_readlink_args /* { - struct vnode *a_vp; - struct uio *a_uio; - vfs_context_t a_context; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct synthfsnode *sp = VTOS(vp); - struct uio *uio = ap->a_uio; - int retval; - unsigned long count; - - if (ap->a_uio->uio_offset > sp->s_u.s.s_length) { - return 0; - }; - - // LP64todo - fix this! - if (uio->uio_offset + uio_resid(uio) <= sp->s_u.s.s_length) { - count = uio_resid(uio); - } else { - count = sp->s_u.s.s_length - uio->uio_offset; - }; - retval = uiomove((void *)((unsigned char *)sp->s_u.s.s_symlinktarget + uio->uio_offset), count, uio); - return (retval); - -} - - - - - - -/* - * Read directory entries. - */ -int -synthfs_readdir(ap) -struct vnop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_flags; - int *a_eofflag; - int *a_numdirent; - vfs_context_t a_context; -} */ *ap; -{ - struct synthfsnode *sp = VTOS(ap->a_vp); - register struct uio *uio = ap->a_uio; - off_t diroffset; /* Offset into simulated directory file */ - struct synthfsnode *entry; - - DBG_VOP(("\tuio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); - - if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) - return (EINVAL); - - /* We assume it's all one big buffer... */ - if (uio->uio_iovcnt > 1) { - DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt)); - return EINVAL; - }; - - diroffset = 0; - - /* - * We must synthesize . and .. - */ - DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); - if (uio->uio_offset == diroffset) - { - DBG_VOP(("\tAdding .\n")); - diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, ".", uio); - DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); - } - if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { - /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ - return EINVAL; - }; - - if (uio->uio_offset == diroffset) - { - DBG_VOP(("\tAdding ..\n")); - if (sp->s_parent != NULL) { - diroffset += synthfs_adddirentry(sp->s_parent->s_nodeid, DT_DIR, "..", uio); - } else { - diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, "..", uio); - } - DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio))); - } - if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { - /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ - return EINVAL; - }; - - /* OK, so much for the fakes. Now for the "real thing": */ - TAILQ_FOREACH(entry, &sp->s_u.d.d_subnodes, s_sibling) { - if (diroffset == uio->uio_offset) { - /* Return this entry */ - diroffset += synthfs_adddirentry(entry->s_nodeid, VTTOIF(STOV(entry)->v_type), entry->s_name, uio); - }; - if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) { - /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */ - return EINVAL; - }; - }; - - if (ap->a_eofflag) - *ap->a_eofflag = (entry == NULL); /* If we ran all the way through the list, there is no more */ - - return 0; -} - - - -/* - -#% lookup dvp L ? ? -#% lookup vpp - L - - - */ - -int -synthfs_cached_lookup(ap) - struct vnop_lookup_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - } */ *ap; -{ - struct vnode *dp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - u_long nameiop = cnp->cn_nameiop; - u_long flags = cnp->cn_flags; - struct vnode **vpp = ap->a_vpp; - int result = 0; - - DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); -#if DEBUG - if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n")); -#endif - - *vpp = NULL; - - /* - * Look up an entry in the namei cache - */ - - result = cache_lookup(dp, vpp, cnp); - if (result == 0) { - /* There was no entry in the cache for this parent vnode/name pair: - do the full-blown pathname lookup - */ - return synthfs_lookup(ap); - }; - if (result == ENOENT) return result; - - /* An entry matching the parent vnode/name was found in the cache: */ - - return (0); - -Err_Exit:; - return result; -} - - - -int -synthfs_lookup(ap) - struct vnop_lookup_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - vfs_context_t a_context; - } */ *ap; -{ - struct vnode *dp = ap->a_dvp; - struct synthfsnode *dsp = VTOS(dp); - struct componentname *cnp = ap->a_cnp; - u_long nameiop = cnp->cn_nameiop; -// char *nameptr = cnp->cn_nameptr; - u_long flags = cnp->cn_flags; - long namelen = cnp->cn_namelen; -// struct proc *p = cnp->cn_proc; - vfs_context_t ctx = cnp->cn_context; - kauth_cred_t cred = vfs_context_ucred(ctx); - struct synthfsnode *entry; - struct vnode *target_vp = NULL; - int result = 0; - boolean_t found = FALSE; - boolean_t isDot = FALSE; - boolean_t isDotDot = FALSE; - struct vnode *starting_parent = dp; - - DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); -#if DEBUG - if (flags & LOCKPARENT) DBG_VOP(("\tLOCKPARENT is set\n")); - if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n")); -#endif - - *ap->a_vpp = NULL; - - /* first check for "." and ".." */ - if (cnp->cn_nameptr[0] == '.') { - if (namelen == 1) { - /* - "." requested - */ - isDot = TRUE; - found = TRUE; - - target_vp = dp; - vnode_get(target_vp); - - result = 0; - - goto Std_Exit; - } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) { - /* - ".." requested - */ - isDotDot = TRUE; - found = TRUE; - - if ((dsp->s_parent != NULL) && (dsp->s_parent != VTOS(dp))) { - target_vp = STOV(dsp->s_parent); - /* - * Special case for ".." to prevent deadlock: - * always release the parent vnode BEFORE trying to acquire - * ITS parent. This avoids deadlocking with another lookup - * starting from the target_vp trying to vnode_get() this directory. - */ - result = vnode_get(target_vp); - - } else { - target_vp = dp; - /* dp is alread locked and ref'ed */ - result = 0; - } - - goto Std_Exit; - } - } - - /* finally, just look for entries by name (making sure the entry's length - matches the cnp's namelen... */ - TAILQ_FOREACH(entry, &dsp->s_u.d.d_subnodes, s_sibling) { - if ((bcmp(cnp->cn_nameptr, entry->s_name, (unsigned)namelen) == 0) && - (*(entry->s_name + namelen) == (char)0)) { - found = TRUE; - target_vp = STOV(entry); - result = vnode_getwithref(target_vp); /* refcount is always > 0 for any vnode in this list... */ - if (result != 0) { - goto Err_Exit; - }; - - /* The specified entry was found and successfully acquired: */ - goto Std_Exit; - }; - }; - - found = FALSE; - -Std_Exit:; - if (found) { - if ((nameiop == DELETE) && (flags & ISLASTCN)) { - - /* - * If the parent directory is "sticky" then the user must own - * the directory, or the file in it, in order to be allowed to - * delete it (unless the user is root). This implements - * append-only directories - */ - if ((dsp->s_mode & S_ISVTX) && - suser(cred, NULL) && - (kauth_cred_getuid(cred) != dsp->s_uid) && - (target_vp != NULL) && - (target_vp->v_type != VLNK) && - (VTOS(target_vp)->s_uid != kauth_cred_getuid(cred))) { - vnode_put(target_vp); - result = EPERM; - goto Err_Exit; - }; - }; - - if ((nameiop == RENAME) && (flags & WANTPARENT) && (flags * ISLASTCN)) { - - if (isDot) { - vnode_put(target_vp); - result = EISDIR; - goto Err_Exit; - }; - }; - } else { - /* The specified entry wasn't found: */ - result = ENOENT; - - if ((flags & ISLASTCN) && - ((nameiop == CREATE) || - (nameiop == RENAME) || - ((nameiop == DELETE) && (flags & DOWHITEOUT) && (flags & ISWHITEOUT)))) { - /* create a new entry */ - result = EJUSTRETURN; - } - }; - - *ap->a_vpp = target_vp; - -Err_Exit:; - DBG_VOP(("synthfs_lookup: result = %d.\n", result)); - if (found) { - if (target_vp) { - DBG_VOP(("synthfs_lookup: target_vp = 0x%08X \n", (u_long)target_vp)); - } else { - DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n")); - }; - } else { - DBG_VOP(("synthf_lookup: target not found.\n")); - }; - DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X .\n", (u_long)dp, (u_long)starting_parent)); - - return result; -} - - - -/* - -#% pathconf vp L L L -# - vnop_pathconf { - IN struct vnode *vp; - IN int name; - OUT register_t *retval; -*/ -int -synthfs_pathconf(ap) -struct vnop_pathconf_args /* { - struct vnode *a_vp; - int a_name; - int *a_retval; - vfs_context_t a_context; -} */ *ap; -{ - DBG_VOP(("synthfs_pathconf called\n")); - - switch (ap->a_name) - { - case _PC_LINK_MAX: - *ap->a_retval = LINK_MAX; - return (0); - case _PC_NAME_MAX: - *ap->a_retval = NAME_MAX; - return (0); - case _PC_PATH_MAX: - *ap->a_retval = PATH_MAX; - return (0); - case _PC_PIPE_BUF: - *ap->a_retval = PIPE_BUF; - return (0); - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ - return (0); - case _PC_NO_TRUNC: - *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */ - return (0); - default: - return (EINVAL); - } - /* NOTREACHED */ -} - - -/* - * Update the access, modified, and node change times as specified by the - * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is - * used to specify that the node needs to be updated but that the times have - * already been set. The access and modified times are taken from the second - * and third parameters; the node change time is always taken from the current - * time. If waitfor is set, then wait for the disk write of the node to - * complete. - */ - -int -synthfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify, __unused int waitfor) -{ - struct synthfsnode *sp = VTOS(vp); - struct timeval tv; - - DBG_ASSERT(sp != NULL); - - if (((sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) != 0) && - !(VTOVFS(vp)->mnt_flag & MNT_RDONLY)) { - if (sp->s_nodeflags & IN_ACCESS) sp->s_accesstime = *access; - if (sp->s_nodeflags & IN_UPDATE) sp->s_modificationtime = *modify; - if (sp->s_nodeflags & IN_CHANGE) { - - microtime(&tv); - sp->s_changetime = tv; - } - }; - - /* After the updates are finished, clear the flags */ - sp->s_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - - return 0; -} - - - -/******************************************************************************************* - - Utility/housekeeping vnode operations: - - ******************************************************************************************/ - - -/* -# -#% inactive vp L U U -# - vnop_inactive { - IN struct vnode *vp; - IN struct proc *p; - -*/ - -int -synthfs_inactive(ap) -struct vnop_inactive_args /* { - struct vnode *a_vp; - vfs_context_t a_context; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct synthfsnode *sp = VTOS(vp); - struct timeval tv; - -#if DEBUG - if (vp->v_usecount != 0) - DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp->v_usecount )); -#endif - - /* - * Ignore nodes related to stale file handles. - */ - if (vp->v_type == VNON) - goto out; - - /* This is sort of silly but might make sense in the future: */ - if (sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { - microtime(&tv); - synthfs_update(vp, &tv, &tv, 0); - } - -out: - /* - * If we are done with the inode, reclaim it - * so that it can be reused immediately. - */ - if (vp->v_type == VNON) { - vnode_recycle(vp); - }; - - return 0; -} - - - -/* - * synthfs_reclaim - Reclaim a vnode so that it can be used for other purposes. - * - * Locking policy: ignored - */ -int -synthfs_reclaim(ap) - struct vnop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct synthfsnode *sp = VTOS(vp); - void *name = sp->s_name; - - sp->s_name = NULL; - FREE(name, M_TEMP); - - vp->v_data = NULL; - FREE((void *)sp, M_SYNTHFS); - - return (0); -}