2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <mach/mach_types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/resourcevar.h>
36 #include <sys/kernel.h>
38 #include <sys/filedesc.h>
40 #include <sys/proc_internal.h> /* for p_fd */
41 #include <sys/kauth.h>
43 #include <sys/mount_internal.h>
44 #include <sys/vnode_internal.h>
45 #include <sys/malloc.h>
46 #include <sys/dirent.h>
47 #include <sys/namei.h>
49 #include <sys/kdebug.h>
50 #include <sys/queue.h>
51 #include <sys/uio_internal.h>
54 #include <sys/errno.h>
55 #include <vfs/vfs_support.h>
57 #include <kern/locks.h>
62 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
63 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
64 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
65 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
68 * The root of the volfs filesystem consists of directories named the volume ID's of all the
69 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
70 * supports the lookup by file ID of all files and directories within the filesystem. When a
71 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
72 * allowing immediate access to the target file or directory.
74 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
75 * on a filesystem node, however, returns only . and .. since it is not practical to list all
76 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
77 * enumerating all of the file id's.
79 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
80 * string with no leading zeros (volume ID 1 is represented as "1").
82 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
83 * string with no leading zeros.
85 * Volfs does create a security hole since it is possible to bypass directory permissions higher
86 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
87 * a similar mechanism.
90 static int volfs_reclaim (struct vnop_reclaim_args
*);
91 static int volfs_getattr (struct vnop_getattr_args
*);
92 static int volfs_select (struct vnop_select_args
*);
93 static int volfs_rmdir (struct vnop_rmdir_args
*);
94 static int volfs_readdir (struct vnop_readdir_args
*);
95 static int volfs_pathconf (struct vnop_pathconf_args
*);
96 static int volfs_lookup (struct vnop_lookup_args
*);
98 static int volfs_readdir_callback(mount_t
, void *);
99 static int get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
);
100 static int get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
);
102 /* for the call back function in volfs_readdir */
103 struct volfs_rdstruct
{
110 #define VOPFUNC int (*)(void *)
112 /* Global vfs data structures for volfs. */
113 int (**volfs_vnodeop_p
) (void *);
114 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
115 {&vnop_default_desc
, (VOPFUNC
)vn_default_error
},
116 {&vnop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
117 {&vnop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
118 {&vnop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
119 {&vnop_create_desc
, (VOPFUNC
)err_create
}, /* create */
120 {&vnop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
121 {&vnop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
122 {&vnop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
123 {&vnop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
124 {&vnop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
125 {&vnop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
126 {&vnop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
127 {&vnop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
128 {&vnop_read_desc
, (VOPFUNC
)err_read
}, /* read */
129 {&vnop_write_desc
, (VOPFUNC
)err_write
}, /* write */
130 {&vnop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
131 {&vnop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
132 {&vnop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
133 {&vnop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
134 {&vnop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
135 {&vnop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
136 {&vnop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
137 {&vnop_link_desc
, (VOPFUNC
)err_link
}, /* link */
138 {&vnop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
139 {&vnop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
140 {&vnop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
141 {&vnop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
142 {&vnop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
143 {&vnop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
144 {&vnop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
145 {&vnop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
146 {&vnop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
147 {&vnop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
148 {&vnop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
149 {&vnop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
150 {&vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
151 {&vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
152 {&vnop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
153 {&vnop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
154 {&vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
155 {&vnop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
156 {&vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
157 {&vnop_blockmap_desc
, (VOPFUNC
)err_blockmap
}, /* blockmap */
158 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
162 * Oh what a tangled web we weave. This structure will be used by
163 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
165 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
166 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
168 static char gDotDot
[] = "..";
174 struct finfoattrbuf
{
175 unsigned long length
;
180 static int volfs_getattr_callback(mount_t
, void *);
184 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
188 struct vnop_reclaim_args
/* { struct vnode *a_vp; vfs_context_t a_context; } */ *ap
;
190 struct vnode
*vp
= ap
->a_vp
;
191 void *data
= vp
->v_data
;
194 FREE(data
, M_VOLFSNODE
);
199 struct volfsgetattr_struct
{
205 volfs_getattr_callback(mount_t mp
, void * arg
)
207 struct volfsgetattr_struct
*vstrp
= (struct volfsgetattr_struct
*)arg
;
209 if (mp
!= vnode_mount(vstrp
->a_vp
) && validfsnode(mp
))
211 return(VFS_RETURNED
);
215 * volfs_getattr - fill in the attributes for this vnode
219 struct vnop_getattr_args
/* { struct vnode *a_vp; struct vnode_attr *a_vap;
220 vfs_context_t a_context; } */ *ap
;
222 struct volfs_vndata
*priv_data
;
224 struct vnode_attr
*a_vap
;
226 struct volfsgetattr_struct vstr
;
232 priv_data
= a_vp
->v_data
;
234 VATTR_RETURN(a_vap
, va_type
, VDIR
);
235 VATTR_RETURN(a_vap
, va_mode
, 0555);
236 VATTR_RETURN(a_vap
, va_nlink
, 2);
237 VATTR_RETURN(a_vap
, va_uid
, 0);
238 VATTR_RETURN(a_vap
, va_gid
, 0);
239 VATTR_RETURN(a_vap
, va_fsid
, (int) a_vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
240 VATTR_RETURN(a_vap
, va_fileid
, (uint64_t)((u_long
)priv_data
->nodeID
));
241 VATTR_RETURN(a_vap
, va_acl
, NULL
);
244 * If it's the root vnode calculate its size based on the number of eligible
247 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
251 vfs_iterate(LK_NOWAIT
, volfs_getattr_callback
, (void *)&vstr
);
253 numMounts
= vstr
.numMounts
;
255 VATTR_RETURN(a_vap
, va_data_size
, (numMounts
+ 2) * VLFSDIRENTLEN
);
257 VATTR_RETURN(a_vap
, va_data_size
, 2 * VLFSDIRENTLEN
);
260 VATTR_RETURN(a_vap
, va_iosize
, 512);
261 ts
.tv_sec
= boottime_sec();
263 VATTR_RETURN(a_vap
, va_access_time
, ts
);
264 VATTR_RETURN(a_vap
, va_modify_time
, ts
);
265 VATTR_RETURN(a_vap
, va_change_time
, ts
);
267 VATTR_RETURN(a_vap
, va_gen
, 0);
268 VATTR_RETURN(a_vap
, va_flags
, 0);
269 VATTR_RETURN(a_vap
, va_rdev
, 0);
270 VATTR_RETURN(a_vap
, va_filerev
, 0);
276 * volfs_select - just say OK. Only possible op is readdir
279 volfs_select(__unused
struct vnop_select_args
*ap
)
285 * vofls_rmdir - not possible to remove directories in volfs
289 struct vnop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
290 struct componentname *a_cnp; vfs_context_t a_context; } */ *ap
;
292 if (ap
->a_dvp
== ap
->a_vp
) {
293 (void) nop_rmdir(ap
);
296 return (err_rmdir(ap
));
302 volfs_readdir_callback(mount_t mp
, void * v
)
304 struct volfs_rdstruct
* vcsp
= (struct volfs_rdstruct
*)v
;
305 struct dirent local_dir
;
308 if ((mp
!= vnode_mount(vcsp
->vp
)) && validfsnode(mp
))
311 if (vcsp
->rec_offset
== vcsp
->validindex
)
313 local_dir
.d_fileno
= mp
->mnt_vfsstat
.f_fsid
.val
[0];
314 local_dir
.d_type
= DT_DIR
;
315 local_dir
.d_reclen
= VLFSDIRENTLEN
;
316 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_vfsstat
.f_fsid
.val
[0]);
317 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, vcsp
->uio
);
321 return(VFS_RETURNED
);
325 * volfs_readdir - Get directory entries
327 * Directory listings are only produced for the root volfs node. Filesystems
329 * Filesystems contained within the volfs root are named by the decimal
330 * equivalent of the f_fsid.val[0] from their mount structure (typically
331 * the device id of the volume). The maximum length for a name, then is
336 struct vnop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
337 * int *a_eofflag; int
338 *ncookies; u_long **a_cookies; vfs_context_t a_context; } */ *ap
;
340 struct volfs_vndata
*priv_data
;
341 register struct uio
*uio
= ap
->a_uio
;
345 struct dirent local_dir
;
349 struct volfs_rdstruct vcs
;
351 off
= uio
->uio_offset
;
352 priv_data
= ap
->a_vp
->v_data
;
353 // LP64todo - fix this!
354 starting_resid
= count
= uio_resid(uio
);
356 /* Make sure we don't return partial entries. */
357 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
362 * Make sure we're starting on a directory boundary
364 if (off
& (VLFSDIRENTLEN
- 1)) {
367 rec_offset
= off
/ VLFSDIRENTLEN
;
368 // LP64todo - fix this!
369 lost
= uio_resid(uio
) - count
;
370 uio_setresid(uio
, count
);
371 uio_iov_len_set(uio
, count
);
373 if (IS_VALID_UIO_SEGFLG(uio
->uio_segflg
) == 0) {
374 panic("%s :%d - invalid uio_segflg\n", __FILE__
, __LINE__
);
376 #endif /* LP64_DEBUG */
378 local_dir
.d_reclen
= VLFSDIRENTLEN
;
380 * We must synthesize . and ..
388 local_dir
.d_fileno
= priv_data
->nodeID
;
389 local_dir
.d_type
= DT_DIR
;
390 local_dir
.d_namlen
= 1;
391 local_dir
.d_name
[0] = '.';
392 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
393 local_dir
.d_name
[i
] = 0;
394 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
401 * We only have two levels in the volfs hierarchy. Root's
402 * .. points to itself and the second level points to root,
403 * hence we've hardcoded d_fileno for .. here
405 local_dir
.d_fileno
= ROOT_DIRID
;
406 local_dir
.d_type
= DT_DIR
;
407 local_dir
.d_namlen
= 2;
408 local_dir
.d_name
[0] = '.';
409 local_dir
.d_name
[1] = '.';
410 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
411 local_dir
.d_name
[i
] = 0;
412 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
417 * OK, we've given them the . & .. entries. If this is a
418 * filesystem node then we've gone as far as we're going
421 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
423 *ap
->a_eofflag
= 1; /* we got all the way to the end */
427 if (rec_offset
> 1) {
428 vcs
.validindex
= 1; /* we always have "." and ".." */
429 vcs
.rec_offset
= rec_offset
;
434 vfs_iterate(0, volfs_readdir_callback
, &vcs
);
436 //if (mp == (void *) &mountlist)
437 *ap
->a_eofflag
= 1; /* we got all the way to the end */
439 uio_setresid(uio
, (uio_resid(uio
) + lost
));
441 if (starting_resid
== uio_resid(uio
))
449 * validfsnode - test to see if a file system supports VGET
451 * This can cause context switching, so caller should be lock safe
454 validfsnode(struct mount
*fsnode
)
458 * Just check to see if the the mount flag is set, if it is we assume the
459 * file system supports all of volfs symantecs
462 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
469 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
473 struct vnop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
474 *a_retval; vfs_context_t a_context; } */ *ap
;
479 *ap
->a_retval
= LINK_MAX
;
482 *ap
->a_retval
= NAME_MAX
;
485 *ap
->a_retval
= PATH_MAX
;
488 *ap
->a_retval
= PIPE_BUF
;
490 case _PC_CHOWN_RESTRICTED
:
503 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
504 * On success, *vpp is the parent vp and is returned with a reference.
507 get_parentvp(struct vnode
**vpp
, struct mount
*mp
, vfs_context_t context
)
510 struct vnode_attr va
;
511 struct vnode
*child_vp
= *vpp
;
514 VATTR_WANTED(&va
, va_parentid
);
515 result
= vnode_getattr(child_vp
, &va
, context
);
520 /* Shift attention to the parent directory vnode: */
521 result
= VFS_VGET(mp
, (ino64_t
)va
.va_parentid
, vpp
, context
);
523 if (result
== 0 && child_vp
->v_parent
!= *vpp
) {
524 vnode_update_identity(child_vp
, *vpp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
532 * Look up the parent directory of a given vnode.
535 lookup_parent(vnode_t child_vp
, vnode_t
*parent_vpp
, int is_authorized
, vfs_context_t context
)
537 struct componentname cn
;
541 *parent_vpp
= NULLVP
;
543 if (is_authorized
== 0) {
544 error
= vnode_authorize(child_vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
549 new_vp
= child_vp
->v_parent
;
551 if (new_vp
!= NULLVP
) {
552 if ( (error
= vnode_getwithref(new_vp
)) == 0 )
553 *parent_vpp
= new_vp
;
556 bzero(&cn
, sizeof(cn
));
557 cn
.cn_nameiop
= LOOKUP
;
558 cn
.cn_context
= context
;
559 cn
.cn_pnbuf
= CAST_DOWN(caddr_t
, &gDotDot
);
560 cn
.cn_pnlen
= strlen(cn
.cn_pnbuf
);
561 cn
.cn_nameptr
= cn
.cn_pnbuf
;
562 cn
.cn_namelen
= cn
.cn_pnlen
;
563 cn
.cn_flags
= (FOLLOW
| LOCKLEAF
| ISLASTCN
| ISDOTDOT
);
565 error
= VNOP_LOOKUP(child_vp
, &new_vp
, &cn
, context
);
569 if (new_vp
== child_vp
) {
573 if (child_vp
->v_parent
== NULLVP
) {
574 vnode_update_identity(child_vp
, new_vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
576 *parent_vpp
= new_vp
;
582 * verify_fullpathaccess(ret_vnode);
586 verify_fullpathaccess(struct vnode
*targetvp
, vfs_context_t context
)
588 struct vnode
*vp
, *parent_vp
;
589 struct mount
*mp
= targetvp
->v_mount
;
590 struct proc
*p
= vfs_context_proc(context
);
593 struct filedesc
*fdp
= p
->p_fd
; /* pointer to file descriptor state */
598 /* get the parent directory. */
599 if ((vp
->v_flag
& VROOT
) == 0 && vp
!= fdp
->fd_cdir
&& vp
!= fdp
->fd_rdir
) {
600 if (vp
->v_parent
== NULLVP
|| (vp
->v_flag
& VISHARDLINK
) || (vnode_getwithref(vp
->v_parent
) != 0)) {
601 if (vp
->v_type
== VDIR
) {
602 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
605 * If the lookup fails with EACCES and the vp is a directory,
606 * we should try again but bypass authorization check. Without this
607 * workaround directories that you can navigate to but not traverse will
608 * disappear when clicked in the Finder.
610 if (result
== EACCES
&& (vp
->v_flag
& VROOT
) == 0) {
611 dp_authorized
= 1; /* bypass auth check */
612 if (lookup_parent(vp
, &parent_vp
, dp_authorized
, context
) == 0) {
615 dp_authorized
= 0; /* force us to authorize */
621 * this is not a directory so we must get parent object ID
623 result
= get_parentvp(&vp
, mp
, context
);
631 * we where able to get a reference on v_parent
633 parent_vp
= vp
= vp
->v_parent
;
638 * Keep going up until either the process's root or the process's working
639 * directory is hit, either one of which are potential valid starting points
640 * for a full pathname
642 while (vp
!= NULLVP
) {
644 result
= reverse_lookup(vp
, &parent_vp
, fdp
, context
, &dp_authorized
);
647 * we're done and we have access
651 if (vp
!= parent_vp
) {
653 * we where able to walk up the parent chain so now we don't need
660 * we have a referenced vp at this point... if dp_authorized == 1, than
661 * it's been authorized for search, but v_parent was NULL...
662 * if dp_authorized == 0, than we need to do the authorization check
663 * before looking up the parent
665 if ((vp
->v_flag
& VROOT
) != 0 ||
666 vp
== fdp
->fd_cdir
|| vp
== fdp
->fd_rdir
) {
668 * we're already at the termination point, which implies that
669 * the authorization check in the cache failed (otherwise we
670 * would have returned 'done' from "reverse_lookup"... so,
671 * do the authorization and bail
673 result
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
676 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
680 if (vp
!= parent_vp
) {
682 * got the parent so now we don't need vp any longer
690 * Success: the caller has complete access to the initial vnode
695 if (vp
!= NULLVP
&& vp
!= targetvp
) {
705 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
706 * id of filesystem to lookup and pointer to vnode pointer to fill in
709 get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
)
711 struct mount
*cur_mount
;
713 struct vnode
*cur_vnode
;
714 struct volfs_vndata
*cur_privdata
;
716 struct vnode_fsparam vfsp
;
720 * OK, first look up the matching mount on the list of mounted file systems
722 /* the following will return the mount point with vfs_busy held */
723 cur_mount
= mount_lookupby_volfsid(id
, 1);
725 if (cur_mount
== NULL
) {
727 * No mounted file system by the specified ID currently exists in the system.
729 * XXX We could deal with a vnode that is still hanging about for an FS that
730 * does not exists or has been unmounted now, or count on the update below
737 cur_fsid
= cur_mount
->mnt_vfsstat
.f_fsid
;
740 * Now search the list attached to the mount structure to
741 * see if this vnode is already floating around
744 mount_lock(our_mount
);
745 TAILQ_FOREACH(cur_vnode
, &our_mount
->mnt_vnodelist
, v_mntvnodes
) {
746 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
747 if (cur_privdata
->nodeID
== (unsigned int)id
)
749 if (cur_privdata
->fs_mount
!= cur_mount
) {
750 cur_privdata
->fs_mount
= cur_mount
;
751 cur_privdata
->fs_fsid
= cur_fsid
;
756 mount_unlock(our_mount
);
759 vid
= vnode_vid(cur_vnode
);
762 * use vnode_getwithvid since it will wait for a vnode currently being
763 * terminated... if it returns an error, cur_vnode will not be what we
764 * think it is, try again
766 if (vnode_getwithvid(cur_vnode
, vid
) != 0) {
767 goto search_vnodelist
;
772 MALLOC(cur_privdata
, struct volfs_vndata
*,
773 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
775 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
776 cur_privdata
->nodeID
= id
;
778 cur_privdata
->fs_mount
= cur_mount
;
779 cur_privdata
->fs_fsid
= cur_fsid
;
781 vfsp
.vnfs_mp
= our_mount
;
782 vfsp
.vnfs_vtype
= VDIR
;
783 vfsp
.vnfs_str
= "volfs";
785 vfsp
.vnfs_fsnode
= cur_privdata
;
787 vfsp
.vnfs_vops
= volfs_vnodeop_p
;
789 vfsp
.vnfs_filesize
= 0;
790 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
791 vfsp
.vnfs_marksystem
= 0;
792 vfsp
.vnfs_markroot
= 0;
794 retval
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &cur_vnode
);
796 FREE(cur_privdata
, M_VOLFSNODE
);
799 cur_vnode
->v_tag
= VT_VOLFS
;
803 *ret_vnode
= cur_vnode
;
806 vfs_unbusy(cur_mount
);
813 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
814 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
818 get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
)
824 * Special case 2 to mean the root of a file system
827 retval
= VFS_ROOT(parent_fs
, ret_vnode
, context
);
829 retval
= VFS_VGET(parent_fs
, (ino64_t
)id
, ret_vnode
, context
);
830 if (retval
) goto error
;
832 retval
= verify_fullpathaccess(*ret_vnode
, context
);
834 /* An error was encountered verifying that the caller has,
835 in fact, got access all the way from "/" or their working
836 directory to the specified item...
838 vnode_put(*ret_vnode
);
840 /* vnode was recycled during access verification. */
841 if (retval
== EAGAIN
) {
852 volfs_lookup(struct vnop_lookup_args
*ap
)
854 struct volfs_vndata
*priv_data
;
857 struct mount
*parent_fs
;
859 int isdot_or_dotdot
= 0;
860 int ret_err
= ENOENT
;
865 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
866 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, 0, 0);
868 priv_data
= ap
->a_dvp
->v_data
;
869 nameptr
= ap
->a_cnp
->cn_nameptr
;
870 namelen
= ap
->a_cnp
->cn_namelen
;
871 firstchar
= nameptr
[0];
873 /* First check for "." and ".." */
874 if (firstchar
== '.') {
878 *ap
->a_vpp
= ap
->a_dvp
;
879 vnode_get(*ap
->a_vpp
);
881 } else if (nameptr
[1] == '.' && namelen
== 2) {
884 ret_err
= VFS_ROOT(ap
->a_dvp
->v_mount
, ap
->a_vpp
, ap
->a_context
);
886 } else if (firstchar
== '@') { /* '@' is alias for system root */
887 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
888 /* the following returns with iteration count on mount point */
889 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
891 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
892 mount_iterdrop(parent_fs
);
897 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
, ap
->a_context
);
898 vfs_unbusy(parent_fs
);
908 } else if (namelen
<= 10 && firstchar
> '0' && firstchar
<= '9') {
912 id
= strtoul(nameptr
, &check_ptr
, 10);
915 * strtol will leave us at the first non-numeric character.
916 * we've checked to make sure the component name does
917 * begin with a numeric so check_ptr must wind up on
918 * the terminating null or there was other junk following the
921 if ((check_ptr
- nameptr
) == namelen
) {
922 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
926 * Obtain the mountpoint and call VFS_VGET in
927 * one step (ie without creating a vnode for
930 if (check_ptr
[0] == '/' &&
931 check_ptr
[1] > '0' && check_ptr
[1] <= '9') {
937 /* this call will return mount point with vfs_busy held */
938 mp
= mount_lookupby_volfsid(id
, 1);
943 id2
= strtoul(&check_ptr
[1], &endptr
, 10);
944 if ((endptr
[0] == '/' || endptr
[0] == '\0') &&
945 get_filevnode(mp
, id2
, &vp
, ap
->a_context
) == 0) {
946 ap
->a_cnp
->cn_consume
= endptr
- check_ptr
;
953 /* Fall through to default behavior... */
955 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
958 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
960 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
961 mount_iterdrop(parent_fs
);
966 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
, ap
->a_context
);
967 vfs_unbusy(parent_fs
);
978 if ( ret_err
== 0 && !isdot_or_dotdot
&& (vp
!= NULLVP
) && (vp
->v_parent
== NULLVP
))
979 vnode_update_identity(vp
, ap
->a_dvp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
982 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
983 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, ret_err
, 0);