コード例 #1
0
ファイル: devfs_vnops.c プロジェクト: 0xffea/xnu
static int
devfs_symlink(struct vnop_symlink_args *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;
        } */
{
	int error;
	devdirent_t *newent;

	DEVFS_LOCK();
	error = devfs_make_symlink(VTODN(ap->a_dvp), ap->a_cnp->cn_nameptr, ap->a_vap->va_mode, ap->a_target, &newent);
	
	if (error == 0) {
		error = devfs_dntovn(newent->de_dnp, ap->a_vpp, vfs_context_proc(ap->a_context));
	}

	DEVFS_UNLOCK();

	return error;

}
コード例 #2
0
/*
 * Mknod vnode call
 */
static int
devfs_mknod(struct vnop_mknod_args *ap)
        /* struct vnop_mknod_args {
		struct vnode *a_dvp;
		struct vnode **a_vpp;
		struct componentname *a_cnp;
		struct vnode_attr *a_vap;
		vfs_context_t a_context;
	} */
{
    	struct componentname * cnp = ap->a_cnp;
	vfs_context_t ctx = cnp->cn_context;
	struct proc *p = vfs_context_proc(ctx);
	devnode_t *	dev_p;
	devdirent_t *	devent;
	devnode_t *	dir_p;	/* devnode for parent directory */
    	struct vnode * 	dvp = ap->a_dvp;
	int 		error = 0;
	devnode_type_t	typeinfo;
	struct vnode_attr *	vap = ap->a_vap;
	struct vnode ** vpp = ap->a_vpp;

	*vpp = NULL;
	if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) {
	        return (EINVAL); /* only support mknod of special files */
	}
	typeinfo.dev = vap->va_rdev;

	DEVFS_LOCK();

	dir_p = VTODN(dvp);

	error = dev_add_entry(cnp->cn_nameptr, dir_p, 
			      (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV,
			      &typeinfo, NULL, NULL, &devent);
	if (error) {
	        goto failure;
	}
	dev_p = devent->de_dnp;
	error = devfs_dntovn(dev_p, vpp, p);
	if (error)
	        goto failure;
	dev_p->dn_uid = vap->va_uid;
	dev_p->dn_gid = vap->va_gid;
	dev_p->dn_mode = vap->va_mode;
	VATTR_SET_SUPPORTED(vap, va_uid);
	VATTR_SET_SUPPORTED(vap, va_gid);
	VATTR_SET_SUPPORTED(vap, va_mode);
failure:
	DEVFS_UNLOCK();

	return (error);
}
コード例 #3
0
ファイル: devfs_vfsops.c プロジェクト: 0xffea/xnu
/* return the address of the root vnode  in *vpp */
static int
devfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t ctx)
{
	struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data);
	int error;

	DEVFS_LOCK();
	/* last parameter to devfs_dntovn() is ignored */
	error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp, vpp, NULL);
	DEVFS_UNLOCK();

	return error;
}
コード例 #4
0
static int
devfs_symlink(struct vnop_symlink_args *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;
        } */
{
	struct componentname * cnp = ap->a_cnp;
	vfs_context_t ctx = cnp->cn_context;
	struct proc *p = vfs_context_proc(ctx);
	int error = 0;
	devnode_t * dir_p;
	devnode_type_t typeinfo;
	devdirent_t * nm_p;
	devnode_t * dev_p;
	struct vnode_attr *	vap = ap->a_vap;
	struct vnode * * vpp = ap->a_vpp;

	typeinfo.Slnk.name = ap->a_target;
	typeinfo.Slnk.namelen = strlen(ap->a_target);

	DEVFS_LOCK();

	dir_p = VTODN(ap->a_dvp);

	error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, 
			      &typeinfo, NULL, NULL, &nm_p);
	if (error) {
	    goto failure;
	}
	dev_p = nm_p->de_dnp;
	dev_p->dn_uid = dir_p->dn_uid;
	dev_p->dn_gid = dir_p->dn_gid;
	dev_p->dn_mode = vap->va_mode;
	dn_copy_times(dev_p, dir_p);

	error = devfs_dntovn(dev_p, vpp, p);
failure:
	DEVFS_UNLOCK();

	return error;
}
コード例 #5
0
static int
devfs_mkdir(struct vnop_mkdir_args *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;
        } */
{
	struct componentname * cnp = ap->a_cnp;
	vfs_context_t ctx = cnp->cn_context;
	struct proc *p = vfs_context_proc(ctx);
	int error = 0;
	devnode_t * dir_p;
	devdirent_t * nm_p;
	devnode_t * dev_p;
	struct vnode_attr *	vap = ap->a_vap;
	struct vnode * * vpp = ap->a_vpp;

	DEVFS_LOCK();

	dir_p = VTODN(ap->a_dvp);
	error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_DIR, 
			      NULL, NULL, NULL, &nm_p);
	if (error) {
	    goto failure;
	}
	dev_p = nm_p->de_dnp;
	dev_p->dn_uid = dir_p->dn_uid;
	dev_p->dn_gid = dir_p->dn_gid;
	dev_p->dn_mode = vap->va_mode;
	dn_copy_times(dev_p, dir_p);

	error = devfs_dntovn(dev_p, vpp, p);
failure:
	DEVFS_UNLOCK();

	return error;
}
コード例 #6
0
/*
 * Convert a component of a pathname into a pointer to a locked node.
 * This is a very central and rather complicated routine.
 * If the file system is not maintained in a strict tree hierarchy,
 * this can result in a deadlock situation (see comments in code below).
 *
 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
 * whether the name is to be looked up, created, renamed, or deleted.
 * When CREATE, RENAME, or DELETE is specified, information usable in
 * creating, renaming, or deleting a directory entry may be calculated.
 * If flag has LOCKPARENT or'ed into it and the target of the pathname
 * exists, lookup returns both the target and its parent directory locked.
 * When creating or renaming and LOCKPARENT is specified, the target may
 * not be ".".  When deleting and LOCKPARENT is specified, the target may
 * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
 * instead of two DNUNLOCKs.
 *
 * Overall outline of devfs_lookup:
 *
 *	check accessibility of directory
 *	null terminate the component (lookup leaves the whole string alone)
 *	look for name in cache, if found, then if at end of path
 *	  and deleting or creating, drop it, else return name
 *	search for name in directory, to found or notfound
 * notfound:
 *	if creating, return locked directory,
 *	else return error
 * found:
 *	if at end of path and deleting, return information to allow delete
 *	if at end of path and rewriting (RENAME and LOCKPARENT), lock target
 *	  node and return info to allow rewrite
 *	if not at end, add name to cache; if at end and neither creating
 *	  nor deleting, add name to cache
 * On return to lookup, remove the null termination we put in at the start.
 *
 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
 */
static int
devfs_lookup(struct vnop_lookup_args *ap)
        /*struct vnop_lookup_args {
                struct vnode * a_dvp; directory vnode ptr
                struct vnode ** a_vpp; where to put the result
                struct componentname * a_cnp; the name we want
		vfs_context_t a_context;
        };*/
{
	struct componentname *cnp = ap->a_cnp;
	vfs_context_t ctx = cnp->cn_context;
	struct proc *p = vfs_context_proc(ctx);
	struct vnode *dir_vnode = ap->a_dvp;
	struct vnode **result_vnode = ap->a_vpp;
	devnode_t *   dir_node;       /* the directory we are searching */
	devnode_t *   node = NULL;       /* the node we are searching for */
	devdirent_t * nodename;
	int flags = cnp->cn_flags;
	int op = cnp->cn_nameiop;       /* LOOKUP, CREATE, RENAME, or DELETE */
	int wantparent = flags & (LOCKPARENT|WANTPARENT);
	int error = 0;
	char	heldchar;	/* the char at the end of the name componet */

retry:

	*result_vnode = NULL; /* safe not sorry */ /*XXX*/

	/*  okay to look at directory vnodes ourside devfs lock as they are not aliased */
	dir_node = VTODN(dir_vnode);

	/*
	 * Make sure that our node is a directory as well.
	 */
	if (dir_node->dn_type != DEV_DIR) {
		return (ENOTDIR);
	}

	DEVFS_LOCK();
	/*
	 * temporarily terminate string component
	 */
	heldchar = cnp->cn_nameptr[cnp->cn_namelen];
	cnp->cn_nameptr[cnp->cn_namelen] = '\0';

	nodename = dev_findname(dir_node, cnp->cn_nameptr);
	/*
	 * restore saved character
	 */
	cnp->cn_nameptr[cnp->cn_namelen] = heldchar;

	if (nodename) {
	        /* entry exists */
	        node = nodename->de_dnp;

		/* Do potential vnode allocation here inside the lock 
		 * to make sure that our device node has a non-NULL dn_vn
		 * associated with it.  The device node might otherwise
		 * get deleted out from under us (see devfs_dn_free()).
		 */
		error = devfs_dntovn(node, result_vnode, p);
	}
	DEVFS_UNLOCK();

	if (error) {
	        if (error == EAGAIN)
		        goto retry;
		return error;
	}
	if (!nodename) {
		/*
		 * we haven't called devfs_dntovn if we get here
		 * we have not taken a reference on the node.. no
		 * vnode_put is necessary on these error returns
		 *
		 * If it doesn't exist and we're not the last component,
		 * or we're at the last component, but we're not creating
		 * or renaming, return ENOENT.
		 */
        	if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
			return ENOENT;
		}
		/*
		 * We return with the directory locked, so that
		 * the parameters we set up above will still be
		 * valid if we actually decide to add a new entry.
		 * We return ni_vp == NULL to indicate that the entry
		 * does not currently exist; we leave a pointer to
		 * the (locked) directory vnode in namei_data->ni_dvp.
		 *
		 * NB - if the directory is unlocked, then this
		 * information cannot be used.
		 */
		return (EJUSTRETURN);
	}
	/*
	 * from this point forward, we need to vnode_put the reference
	 * picked up in devfs_dntovn if we decide to return an error
	 */

	/*
	 * If deleting, and at end of pathname, return
	 * parameters which can be used to remove file.
	 * If the wantparent flag isn't set, we return only
	 * the directory (in namei_data->ni_dvp), otherwise we go
	 * on and lock the node, being careful with ".".
	 */
	if (op == DELETE && (flags & ISLASTCN)) {

		/*
		 * we are trying to delete '.'.  What does this mean? XXX
		 */
		if (dir_node == node) {
		        if (*result_vnode) {
			        vnode_put(*result_vnode);
			        *result_vnode = NULL;
			}				
			if ( ((error = vnode_get(dir_vnode)) == 0) ) {
			        *result_vnode = dir_vnode;
			}
			return (error);
		}
		return (0);
	}

	/*
	 * If rewriting (RENAME), return the vnode and the
	 * information required to rewrite the present directory
	 * Must get node of directory entry to verify it's a
	 * regular file, or empty directory.
	 */
	if (op == RENAME && wantparent && (flags & ISLASTCN)) {

		/*
		 * Careful about locking second node.
		 * This can only occur if the target is ".".
		 */
		if (dir_node == node) {
		        error = EISDIR;
			goto drop_ref;
		}
		return (0);
	}

	/*
	 * Step through the translation in the name.  We do not unlock the
	 * directory because we may need it again if a symbolic link
	 * is relative to the current directory.  Instead we save it
	 * unlocked as "saved_dir_node" XXX.  We must get the target
	 * node before unlocking
	 * the directory to insure that the node will not be removed
	 * before we get it.  We prevent deadlock by always fetching
	 * nodes from the root, moving down the directory tree. Thus
	 * when following backward pointers ".." we must unlock the
	 * parent directory before getting the requested directory.
	 * There is a potential race condition here if both the current
	 * and parent directories are removed before the lock for the
	 * node associated with ".." returns.  We hope that this occurs
	 * infrequently since we cannot avoid this race condition without
	 * implementing a sophisticated deadlock detection algorithm.
	 * Note also that this simple deadlock detection scheme will not
	 * work if the file system has any hard links other than ".."
	 * that point backwards in the directory structure.
	 */
	if ((flags & ISDOTDOT) == 0 && dir_node == node) {
	        if (*result_vnode) {
		        vnode_put(*result_vnode);
		        *result_vnode = NULL;
		}
		if ( (error = vnode_get(dir_vnode)) ) {
			return (error);
		}
		*result_vnode = dir_vnode;
	}
	return (0);

drop_ref:
	if (*result_vnode) {
	        vnode_put(*result_vnode);
		*result_vnode = NULL;
	}
	return (error);
}