2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <mach/mach_types.h>
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/resourcevar.h>
28 #include <sys/kernel.h>
30 #include <sys/filedesc.h>
32 #include <sys/proc_internal.h> /* for p_fd */
33 #include <sys/kauth.h>
35 #include <sys/mount_internal.h>
36 #include <sys/vnode_internal.h>
37 #include <sys/malloc.h>
38 #include <sys/dirent.h>
39 #include <sys/namei.h>
41 #include <sys/kdebug.h>
42 #include <sys/queue.h>
43 #include <sys/uio_internal.h>
46 #include <sys/errno.h>
47 #include <vfs/vfs_support.h>
49 #include <kern/locks.h>
54 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
55 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
56 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
57 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
60 * The root of the volfs filesystem consists of directories named the volume ID's of all the
61 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
62 * supports the lookup by file ID of all files and directories within the filesystem. When a
63 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
64 * allowing immediate access to the target file or directory.
66 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
67 * on a filesystem node, however, returns only . and .. since it is not practical to list all
68 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
69 * enumerating all of the file id's.
71 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
72 * string with no leading zeros (volume ID 1 is represented as "1").
74 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
75 * string with no leading zeros.
77 * Volfs does create a security hole since it is possible to bypass directory permissions higher
78 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
79 * a similar mechanism.
82 static int volfs_reclaim (struct vnop_reclaim_args
*);
83 static int volfs_getattr (struct vnop_getattr_args
*);
84 static int volfs_select (struct vnop_select_args
*);
85 static int volfs_rmdir (struct vnop_rmdir_args
*);
86 static int volfs_readdir (struct vnop_readdir_args
*);
87 static int volfs_pathconf (struct vnop_pathconf_args
*);
88 static int volfs_lookup (struct vnop_lookup_args
*);
90 static int volfs_readdir_callback(mount_t
, void *);
91 static int get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
);
92 static int get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
);
94 /* for the call back function in volfs_readdir */
95 struct volfs_rdstruct
{
102 #define VOPFUNC int (*)(void *)
104 /* Global vfs data structures for volfs. */
105 int (**volfs_vnodeop_p
) (void *);
106 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
107 {&vnop_default_desc
, (VOPFUNC
)vn_default_error
},
108 {&vnop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
109 {&vnop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
110 {&vnop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
111 {&vnop_create_desc
, (VOPFUNC
)err_create
}, /* create */
112 {&vnop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
113 {&vnop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
114 {&vnop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
115 {&vnop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
116 {&vnop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
117 {&vnop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
118 {&vnop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
119 {&vnop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
120 {&vnop_read_desc
, (VOPFUNC
)err_read
}, /* read */
121 {&vnop_write_desc
, (VOPFUNC
)err_write
}, /* write */
122 {&vnop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
123 {&vnop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
124 {&vnop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
125 {&vnop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
126 {&vnop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
127 {&vnop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
128 {&vnop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
129 {&vnop_link_desc
, (VOPFUNC
)err_link
}, /* link */
130 {&vnop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
131 {&vnop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
132 {&vnop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
133 {&vnop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
134 {&vnop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
135 {&vnop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
136 {&vnop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
137 {&vnop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
138 {&vnop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
139 {&vnop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
140 {&vnop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
141 {&vnop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
142 {&vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
143 {&vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
144 {&vnop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
145 {&vnop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
146 {&vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
147 {&vnop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
148 {&vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
149 {&vnop_blockmap_desc
, (VOPFUNC
)err_blockmap
}, /* blockmap */
150 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
154 * Oh what a tangled web we weave. This structure will be used by
155 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
157 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
158 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
160 static char gDotDot
[] = "..";
166 struct finfoattrbuf
{
167 unsigned long length
;
172 static int volfs_getattr_callback(mount_t
, void *);
176 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
180 struct vnop_reclaim_args
/* { struct vnode *a_vp; vfs_context_t a_context; } */ *ap
;
182 struct vnode
*vp
= ap
->a_vp
;
183 void *data
= vp
->v_data
;
186 FREE(data
, M_VOLFSNODE
);
191 struct volfsgetattr_struct
{
197 volfs_getattr_callback(mount_t mp
, void * arg
)
199 struct volfsgetattr_struct
*vstrp
= (struct volfsgetattr_struct
*)arg
;
201 if (mp
!= vnode_mount(vstrp
->a_vp
) && validfsnode(mp
))
203 return(VFS_RETURNED
);
207 * volfs_getattr - fill in the attributes for this vnode
211 struct vnop_getattr_args
/* { struct vnode *a_vp; struct vnode_attr *a_vap;
212 vfs_context_t a_context; } */ *ap
;
214 struct volfs_vndata
*priv_data
;
216 struct vnode_attr
*a_vap
;
218 struct volfsgetattr_struct vstr
;
224 priv_data
= a_vp
->v_data
;
226 VATTR_RETURN(a_vap
, va_type
, VDIR
);
227 VATTR_RETURN(a_vap
, va_mode
, 0555);
228 VATTR_RETURN(a_vap
, va_nlink
, 2);
229 VATTR_RETURN(a_vap
, va_uid
, 0);
230 VATTR_RETURN(a_vap
, va_gid
, 0);
231 VATTR_RETURN(a_vap
, va_fsid
, (int) a_vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
232 VATTR_RETURN(a_vap
, va_fileid
, (uint64_t)((u_long
)priv_data
->nodeID
));
233 VATTR_RETURN(a_vap
, va_acl
, NULL
);
236 * If it's the root vnode calculate its size based on the number of eligible
239 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
243 vfs_iterate(LK_NOWAIT
, volfs_getattr_callback
, (void *)&vstr
);
245 numMounts
= vstr
.numMounts
;
247 VATTR_RETURN(a_vap
, va_data_size
, (numMounts
+ 2) * VLFSDIRENTLEN
);
249 VATTR_RETURN(a_vap
, va_data_size
, 2 * VLFSDIRENTLEN
);
252 VATTR_RETURN(a_vap
, va_iosize
, 512);
253 ts
.tv_sec
= boottime_sec();
255 VATTR_RETURN(a_vap
, va_access_time
, ts
);
256 VATTR_RETURN(a_vap
, va_modify_time
, ts
);
257 VATTR_RETURN(a_vap
, va_change_time
, ts
);
259 VATTR_RETURN(a_vap
, va_gen
, 0);
260 VATTR_RETURN(a_vap
, va_flags
, 0);
261 VATTR_RETURN(a_vap
, va_rdev
, 0);
262 VATTR_RETURN(a_vap
, va_filerev
, 0);
268 * volfs_select - just say OK. Only possible op is readdir
271 volfs_select(__unused
struct vnop_select_args
*ap
)
277 * vofls_rmdir - not possible to remove directories in volfs
281 struct vnop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
282 struct componentname *a_cnp; vfs_context_t a_context; } */ *ap
;
284 if (ap
->a_dvp
== ap
->a_vp
) {
285 (void) nop_rmdir(ap
);
288 return (err_rmdir(ap
));
294 volfs_readdir_callback(mount_t mp
, void * v
)
296 struct volfs_rdstruct
* vcsp
= (struct volfs_rdstruct
*)v
;
297 struct dirent local_dir
;
300 if ((mp
!= vnode_mount(vcsp
->vp
)) && validfsnode(mp
))
303 if (vcsp
->rec_offset
== vcsp
->validindex
)
305 local_dir
.d_fileno
= mp
->mnt_vfsstat
.f_fsid
.val
[0];
306 local_dir
.d_type
= DT_DIR
;
307 local_dir
.d_reclen
= VLFSDIRENTLEN
;
308 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_vfsstat
.f_fsid
.val
[0]);
309 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, vcsp
->uio
);
313 return(VFS_RETURNED
);
317 * volfs_readdir - Get directory entries
319 * Directory listings are only produced for the root volfs node. Filesystems
321 * Filesystems contained within the volfs root are named by the decimal
322 * equivalent of the f_fsid.val[0] from their mount structure (typically
323 * the device id of the volume). The maximum length for a name, then is
328 struct vnop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
329 * int *a_eofflag; int
330 *ncookies; u_long **a_cookies; vfs_context_t a_context; } */ *ap
;
332 struct volfs_vndata
*priv_data
;
333 register struct uio
*uio
= ap
->a_uio
;
337 struct dirent local_dir
;
341 struct volfs_rdstruct vcs
;
343 off
= uio
->uio_offset
;
344 priv_data
= ap
->a_vp
->v_data
;
345 // LP64todo - fix this!
346 starting_resid
= count
= uio_resid(uio
);
348 /* Make sure we don't return partial entries. */
349 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
354 * Make sure we're starting on a directory boundary
356 if (off
& (VLFSDIRENTLEN
- 1)) {
359 rec_offset
= off
/ VLFSDIRENTLEN
;
360 // LP64todo - fix this!
361 lost
= uio_resid(uio
) - count
;
362 uio_setresid(uio
, count
);
363 uio_iov_len_set(uio
, count
);
365 if (IS_VALID_UIO_SEGFLG(uio
->uio_segflg
) == 0) {
366 panic("%s :%d - invalid uio_segflg\n", __FILE__
, __LINE__
);
368 #endif /* LP64_DEBUG */
370 local_dir
.d_reclen
= VLFSDIRENTLEN
;
372 * We must synthesize . and ..
380 local_dir
.d_fileno
= priv_data
->nodeID
;
381 local_dir
.d_type
= DT_DIR
;
382 local_dir
.d_namlen
= 1;
383 local_dir
.d_name
[0] = '.';
384 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
385 local_dir
.d_name
[i
] = 0;
386 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
393 * We only have two levels in the volfs hierarchy. Root's
394 * .. points to itself and the second level points to root,
395 * hence we've hardcoded d_fileno for .. here
397 local_dir
.d_fileno
= ROOT_DIRID
;
398 local_dir
.d_type
= DT_DIR
;
399 local_dir
.d_namlen
= 2;
400 local_dir
.d_name
[0] = '.';
401 local_dir
.d_name
[1] = '.';
402 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
403 local_dir
.d_name
[i
] = 0;
404 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
409 * OK, we've given them the . & .. entries. If this is a
410 * filesystem node then we've gone as far as we're going
413 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
415 *ap
->a_eofflag
= 1; /* we got all the way to the end */
419 if (rec_offset
> 1) {
420 vcs
.validindex
= 1; /* we always have "." and ".." */
421 vcs
.rec_offset
= rec_offset
;
426 vfs_iterate(0, volfs_readdir_callback
, &vcs
);
428 //if (mp == (void *) &mountlist)
429 *ap
->a_eofflag
= 1; /* we got all the way to the end */
431 uio_setresid(uio
, (uio_resid(uio
) + lost
));
433 if (starting_resid
== uio_resid(uio
))
441 * validfsnode - test to see if a file system supports VGET
443 * This can cause context switching, so caller should be lock safe
446 validfsnode(struct mount
*fsnode
)
450 * Just check to see if the the mount flag is set, if it is we assume the
451 * file system supports all of volfs symantecs
454 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
461 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
465 struct vnop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
466 *a_retval; vfs_context_t a_context; } */ *ap
;
471 *ap
->a_retval
= LINK_MAX
;
474 *ap
->a_retval
= NAME_MAX
;
477 *ap
->a_retval
= PATH_MAX
;
480 *ap
->a_retval
= PIPE_BUF
;
482 case _PC_CHOWN_RESTRICTED
:
495 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
496 * On success, *vpp is the parent vp and is returned with a reference.
499 get_parentvp(struct vnode
**vpp
, struct mount
*mp
, vfs_context_t context
)
502 struct vnode_attr va
;
503 struct vnode
*child_vp
= *vpp
;
506 VATTR_WANTED(&va
, va_parentid
);
507 result
= vnode_getattr(child_vp
, &va
, context
);
512 /* Shift attention to the parent directory vnode: */
513 result
= VFS_VGET(mp
, (ino64_t
)va
.va_parentid
, vpp
, context
);
515 if (result
== 0 && child_vp
->v_parent
!= *vpp
) {
516 vnode_update_identity(child_vp
, *vpp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
524 * Look up the parent directory of a given vnode.
527 lookup_parent(vnode_t child_vp
, vnode_t
*parent_vpp
, int is_authorized
, vfs_context_t context
)
529 struct componentname cn
;
533 *parent_vpp
= NULLVP
;
535 if (is_authorized
== 0) {
536 error
= vnode_authorize(child_vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
541 new_vp
= child_vp
->v_parent
;
543 if (new_vp
!= NULLVP
) {
544 if ( (error
= vnode_getwithref(new_vp
)) == 0 )
545 *parent_vpp
= new_vp
;
548 bzero(&cn
, sizeof(cn
));
549 cn
.cn_nameiop
= LOOKUP
;
550 cn
.cn_context
= context
;
551 cn
.cn_pnbuf
= CAST_DOWN(caddr_t
, &gDotDot
);
552 cn
.cn_pnlen
= strlen(cn
.cn_pnbuf
);
553 cn
.cn_nameptr
= cn
.cn_pnbuf
;
554 cn
.cn_namelen
= cn
.cn_pnlen
;
555 cn
.cn_flags
= (FOLLOW
| LOCKLEAF
| ISLASTCN
| ISDOTDOT
);
557 error
= VNOP_LOOKUP(child_vp
, &new_vp
, &cn
, context
);
561 if (new_vp
== child_vp
) {
565 if (child_vp
->v_parent
== NULLVP
) {
566 vnode_update_identity(child_vp
, new_vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
568 *parent_vpp
= new_vp
;
574 * verify_fullpathaccess(ret_vnode);
578 verify_fullpathaccess(struct vnode
*targetvp
, vfs_context_t context
)
580 struct vnode
*vp
, *parent_vp
;
581 struct mount
*mp
= targetvp
->v_mount
;
582 struct proc
*p
= vfs_context_proc(context
);
585 struct filedesc
*fdp
= p
->p_fd
; /* pointer to file descriptor state */
590 /* get the parent directory. */
591 if ((vp
->v_flag
& VROOT
) == 0 && vp
!= fdp
->fd_cdir
&& vp
!= fdp
->fd_rdir
) {
592 if (vp
->v_parent
== NULLVP
|| (vp
->v_flag
& VISHARDLINK
) || (vnode_getwithref(vp
->v_parent
) != 0)) {
593 if (vp
->v_type
== VDIR
) {
594 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
597 * If the lookup fails with EACCES and the vp is a directory,
598 * we should try again but bypass authorization check. Without this
599 * workaround directories that you can navigate to but not traverse will
600 * disappear when clicked in the Finder.
602 if (result
== EACCES
&& (vp
->v_flag
& VROOT
) == 0) {
603 dp_authorized
= 1; /* bypass auth check */
604 if (lookup_parent(vp
, &parent_vp
, dp_authorized
, context
) == 0) {
607 dp_authorized
= 0; /* force us to authorize */
613 * this is not a directory so we must get parent object ID
615 result
= get_parentvp(&vp
, mp
, context
);
623 * we where able to get a reference on v_parent
625 parent_vp
= vp
= vp
->v_parent
;
630 * Keep going up until either the process's root or the process's working
631 * directory is hit, either one of which are potential valid starting points
632 * for a full pathname
634 while (vp
!= NULLVP
) {
636 result
= reverse_lookup(vp
, &parent_vp
, fdp
, context
, &dp_authorized
);
639 * we're done and we have access
643 if (vp
!= parent_vp
) {
645 * we where able to walk up the parent chain so now we don't need
652 * we have a referenced vp at this point... if dp_authorized == 1, than
653 * it's been authorized for search, but v_parent was NULL...
654 * if dp_authorized == 0, than we need to do the authorization check
655 * before looking up the parent
657 if ((vp
->v_flag
& VROOT
) != 0 ||
658 vp
== fdp
->fd_cdir
|| vp
== fdp
->fd_rdir
) {
660 * we're already at the termination point, which implies that
661 * the authorization check in the cache failed (otherwise we
662 * would have returned 'done' from "reverse_lookup"... so,
663 * do the authorization and bail
665 result
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
668 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
672 if (vp
!= parent_vp
) {
674 * got the parent so now we don't need vp any longer
682 * Success: the caller has complete access to the initial vnode
687 if (vp
!= NULLVP
&& vp
!= targetvp
) {
697 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
698 * id of filesystem to lookup and pointer to vnode pointer to fill in
701 get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
)
703 struct mount
*cur_mount
;
705 struct vnode
*cur_vnode
;
706 struct volfs_vndata
*cur_privdata
;
708 struct vnode_fsparam vfsp
;
712 * OK, first look up the matching mount on the list of mounted file systems
714 /* the following will return the mount point with vfs_busy held */
715 cur_mount
= mount_lookupby_volfsid(id
, 1);
717 if (cur_mount
== NULL
) {
719 * No mounted file system by the specified ID currently exists in the system.
721 * XXX We could deal with a vnode that is still hanging about for an FS that
722 * does not exists or has been unmounted now, or count on the update below
729 cur_fsid
= cur_mount
->mnt_vfsstat
.f_fsid
;
732 * Now search the list attached to the mount structure to
733 * see if this vnode is already floating around
736 mount_lock(our_mount
);
737 TAILQ_FOREACH(cur_vnode
, &our_mount
->mnt_vnodelist
, v_mntvnodes
) {
738 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
739 if (cur_privdata
->nodeID
== (unsigned int)id
)
741 if (cur_privdata
->fs_mount
!= cur_mount
) {
742 cur_privdata
->fs_mount
= cur_mount
;
743 cur_privdata
->fs_fsid
= cur_fsid
;
748 mount_unlock(our_mount
);
751 vid
= vnode_vid(cur_vnode
);
754 * use vnode_getwithvid since it will wait for a vnode currently being
755 * terminated... if it returns an error, cur_vnode will not be what we
756 * think it is, try again
758 if (vnode_getwithvid(cur_vnode
, vid
) != 0) {
759 goto search_vnodelist
;
764 MALLOC(cur_privdata
, struct volfs_vndata
*,
765 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
767 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
768 cur_privdata
->nodeID
= id
;
770 cur_privdata
->fs_mount
= cur_mount
;
771 cur_privdata
->fs_fsid
= cur_fsid
;
773 vfsp
.vnfs_mp
= our_mount
;
774 vfsp
.vnfs_vtype
= VDIR
;
775 vfsp
.vnfs_str
= "volfs";
777 vfsp
.vnfs_fsnode
= cur_privdata
;
779 vfsp
.vnfs_vops
= volfs_vnodeop_p
;
781 vfsp
.vnfs_filesize
= 0;
782 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
783 vfsp
.vnfs_marksystem
= 0;
784 vfsp
.vnfs_markroot
= 0;
786 retval
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &cur_vnode
);
788 FREE(cur_privdata
, M_VOLFSNODE
);
791 cur_vnode
->v_tag
= VT_VOLFS
;
795 *ret_vnode
= cur_vnode
;
798 vfs_unbusy(cur_mount
);
805 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
806 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
810 get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
)
816 * Special case 2 to mean the root of a file system
819 retval
= VFS_ROOT(parent_fs
, ret_vnode
, context
);
821 retval
= VFS_VGET(parent_fs
, (ino64_t
)id
, ret_vnode
, context
);
822 if (retval
) goto error
;
824 retval
= verify_fullpathaccess(*ret_vnode
, context
);
826 /* An error was encountered verifying that the caller has,
827 in fact, got access all the way from "/" or their working
828 directory to the specified item...
830 vnode_put(*ret_vnode
);
832 /* vnode was recycled during access verification. */
833 if (retval
== EAGAIN
) {
844 volfs_lookup(struct vnop_lookup_args
*ap
)
846 struct volfs_vndata
*priv_data
;
849 struct mount
*parent_fs
;
851 int isdot_or_dotdot
= 0;
852 int ret_err
= ENOENT
;
857 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
858 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, 0, 0);
860 priv_data
= ap
->a_dvp
->v_data
;
861 nameptr
= ap
->a_cnp
->cn_nameptr
;
862 namelen
= ap
->a_cnp
->cn_namelen
;
863 firstchar
= nameptr
[0];
865 /* First check for "." and ".." */
866 if (firstchar
== '.') {
870 *ap
->a_vpp
= ap
->a_dvp
;
871 vnode_get(*ap
->a_vpp
);
873 } else if (nameptr
[1] == '.' && namelen
== 2) {
876 ret_err
= VFS_ROOT(ap
->a_dvp
->v_mount
, ap
->a_vpp
, ap
->a_context
);
878 } else if (firstchar
== '@') { /* '@' is alias for system root */
879 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
880 /* the following returns with iteration count on mount point */
881 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
883 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
884 mount_iterdrop(parent_fs
);
889 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
, ap
->a_context
);
890 vfs_unbusy(parent_fs
);
900 } else if (namelen
<= 10 && firstchar
> '0' && firstchar
<= '9') {
904 id
= strtoul(nameptr
, &check_ptr
, 10);
907 * strtol will leave us at the first non-numeric character.
908 * we've checked to make sure the component name does
909 * begin with a numeric so check_ptr must wind up on
910 * the terminating null or there was other junk following the
913 if ((check_ptr
- nameptr
) == namelen
) {
914 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
918 * Obtain the mountpoint and call VFS_VGET in
919 * one step (ie without creating a vnode for
922 if (check_ptr
[0] == '/' &&
923 check_ptr
[1] > '0' && check_ptr
[1] <= '9') {
929 /* this call will return mount point with vfs_busy held */
930 mp
= mount_lookupby_volfsid(id
, 1);
935 id2
= strtoul(&check_ptr
[1], &endptr
, 10);
936 if ((endptr
[0] == '/' || endptr
[0] == '\0') &&
937 get_filevnode(mp
, id2
, &vp
, ap
->a_context
) == 0) {
938 ap
->a_cnp
->cn_consume
= endptr
- check_ptr
;
945 /* Fall through to default behavior... */
947 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
950 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
952 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
953 mount_iterdrop(parent_fs
);
958 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
, ap
->a_context
);
959 vfs_unbusy(parent_fs
);
970 if ( ret_err
== 0 && !isdot_or_dotdot
&& (vp
!= NULLVP
) && (vp
->v_parent
== NULLVP
))
971 vnode_update_identity(vp
, ap
->a_dvp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
974 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
975 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, ret_err
, 0);