2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/mach_types.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/resourcevar.h>
34 #include <sys/kernel.h>
36 #include <sys/filedesc.h>
38 #include <sys/proc_internal.h> /* for p_fd */
39 #include <sys/kauth.h>
41 #include <sys/mount_internal.h>
42 #include <sys/vnode_internal.h>
43 #include <sys/malloc.h>
44 #include <sys/dirent.h>
45 #include <sys/namei.h>
47 #include <sys/kdebug.h>
48 #include <sys/queue.h>
49 #include <sys/uio_internal.h>
52 #include <sys/errno.h>
53 #include <vfs/vfs_support.h>
55 #include <kern/locks.h>
60 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
61 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
62 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
63 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
66 * The root of the volfs filesystem consists of directories named the volume ID's of all the
67 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
68 * supports the lookup by file ID of all files and directories within the filesystem. When a
69 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
70 * allowing immediate access to the target file or directory.
72 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
73 * on a filesystem node, however, returns only . and .. since it is not practical to list all
74 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
75 * enumerating all of the file id's.
77 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
78 * string with no leading zeros (volume ID 1 is represented as "1").
80 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
81 * string with no leading zeros.
83 * Volfs does create a security hole since it is possible to bypass directory permissions higher
84 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
85 * a similar mechanism.
88 static int volfs_reclaim (struct vnop_reclaim_args
*);
89 static int volfs_getattr (struct vnop_getattr_args
*);
90 static int volfs_select (struct vnop_select_args
*);
91 static int volfs_rmdir (struct vnop_rmdir_args
*);
92 static int volfs_readdir (struct vnop_readdir_args
*);
93 static int volfs_pathconf (struct vnop_pathconf_args
*);
94 static int volfs_lookup (struct vnop_lookup_args
*);
96 static int volfs_readdir_callback(mount_t
, void *);
97 static int get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
);
98 static int get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
);
100 /* for the call back function in volfs_readdir */
101 struct volfs_rdstruct
{
108 #define VOPFUNC int (*)(void *)
110 /* Global vfs data structures for volfs. */
111 int (**volfs_vnodeop_p
) (void *);
112 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
113 {&vnop_default_desc
, (VOPFUNC
)vn_default_error
},
114 {&vnop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
115 {&vnop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
116 {&vnop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
117 {&vnop_create_desc
, (VOPFUNC
)err_create
}, /* create */
118 {&vnop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
119 {&vnop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
120 {&vnop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
121 {&vnop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
122 {&vnop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
123 {&vnop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
124 {&vnop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
125 {&vnop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
126 {&vnop_read_desc
, (VOPFUNC
)err_read
}, /* read */
127 {&vnop_write_desc
, (VOPFUNC
)err_write
}, /* write */
128 {&vnop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
129 {&vnop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
130 {&vnop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
131 {&vnop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
132 {&vnop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
133 {&vnop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
134 {&vnop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
135 {&vnop_link_desc
, (VOPFUNC
)err_link
}, /* link */
136 {&vnop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
137 {&vnop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
138 {&vnop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
139 {&vnop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
140 {&vnop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
141 {&vnop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
142 {&vnop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
143 {&vnop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
144 {&vnop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
145 {&vnop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
146 {&vnop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
147 {&vnop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
148 {&vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
149 {&vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
150 {&vnop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
151 {&vnop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
152 {&vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
153 {&vnop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
154 {&vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
155 {&vnop_blockmap_desc
, (VOPFUNC
)err_blockmap
}, /* blockmap */
156 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
160 * Oh what a tangled web we weave. This structure will be used by
161 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
163 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
164 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
166 static char gDotDot
[] = "..";
172 struct finfoattrbuf
{
173 unsigned long length
;
178 static int volfs_getattr_callback(mount_t
, void *);
182 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
186 struct vnop_reclaim_args
/* { struct vnode *a_vp; vfs_context_t a_context; } */ *ap
;
188 struct vnode
*vp
= ap
->a_vp
;
189 void *data
= vp
->v_data
;
192 FREE(data
, M_VOLFSNODE
);
197 struct volfsgetattr_struct
{
203 volfs_getattr_callback(mount_t mp
, void * arg
)
205 struct volfsgetattr_struct
*vstrp
= (struct volfsgetattr_struct
*)arg
;
207 if (mp
!= vnode_mount(vstrp
->a_vp
) && validfsnode(mp
))
209 return(VFS_RETURNED
);
213 * volfs_getattr - fill in the attributes for this vnode
217 struct vnop_getattr_args
/* { struct vnode *a_vp; struct vnode_attr *a_vap;
218 vfs_context_t a_context; } */ *ap
;
220 struct volfs_vndata
*priv_data
;
222 struct vnode_attr
*a_vap
;
224 struct volfsgetattr_struct vstr
;
230 priv_data
= a_vp
->v_data
;
232 VATTR_RETURN(a_vap
, va_type
, VDIR
);
233 VATTR_RETURN(a_vap
, va_mode
, 0555);
234 VATTR_RETURN(a_vap
, va_nlink
, 2);
235 VATTR_RETURN(a_vap
, va_uid
, 0);
236 VATTR_RETURN(a_vap
, va_gid
, 0);
237 VATTR_RETURN(a_vap
, va_fsid
, (int) a_vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
238 VATTR_RETURN(a_vap
, va_fileid
, (uint64_t)((u_long
)priv_data
->nodeID
));
239 VATTR_RETURN(a_vap
, va_acl
, NULL
);
242 * If it's the root vnode calculate its size based on the number of eligible
245 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
249 vfs_iterate(LK_NOWAIT
, volfs_getattr_callback
, (void *)&vstr
);
251 numMounts
= vstr
.numMounts
;
253 VATTR_RETURN(a_vap
, va_data_size
, (numMounts
+ 2) * VLFSDIRENTLEN
);
255 VATTR_RETURN(a_vap
, va_data_size
, 2 * VLFSDIRENTLEN
);
258 VATTR_RETURN(a_vap
, va_iosize
, 512);
259 ts
.tv_sec
= boottime_sec();
261 VATTR_RETURN(a_vap
, va_access_time
, ts
);
262 VATTR_RETURN(a_vap
, va_modify_time
, ts
);
263 VATTR_RETURN(a_vap
, va_change_time
, ts
);
265 VATTR_RETURN(a_vap
, va_gen
, 0);
266 VATTR_RETURN(a_vap
, va_flags
, 0);
267 VATTR_RETURN(a_vap
, va_rdev
, 0);
268 VATTR_RETURN(a_vap
, va_filerev
, 0);
274 * volfs_select - just say OK. Only possible op is readdir
277 volfs_select(__unused
struct vnop_select_args
*ap
)
283 * vofls_rmdir - not possible to remove directories in volfs
287 struct vnop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
288 struct componentname *a_cnp; vfs_context_t a_context; } */ *ap
;
290 if (ap
->a_dvp
== ap
->a_vp
) {
291 (void) nop_rmdir(ap
);
294 return (err_rmdir(ap
));
300 volfs_readdir_callback(mount_t mp
, void * v
)
302 struct volfs_rdstruct
* vcsp
= (struct volfs_rdstruct
*)v
;
303 struct dirent local_dir
;
306 if ((mp
!= vnode_mount(vcsp
->vp
)) && validfsnode(mp
))
309 if (vcsp
->rec_offset
== vcsp
->validindex
)
311 local_dir
.d_fileno
= mp
->mnt_vfsstat
.f_fsid
.val
[0];
312 local_dir
.d_type
= DT_DIR
;
313 local_dir
.d_reclen
= VLFSDIRENTLEN
;
314 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_vfsstat
.f_fsid
.val
[0]);
315 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, vcsp
->uio
);
319 return(VFS_RETURNED
);
323 * volfs_readdir - Get directory entries
325 * Directory listings are only produced for the root volfs node. Filesystems
327 * Filesystems contained within the volfs root are named by the decimal
328 * equivalent of the f_fsid.val[0] from their mount structure (typically
329 * the device id of the volume). The maximum length for a name, then is
334 struct vnop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
335 * int *a_eofflag; int
336 *ncookies; u_long **a_cookies; vfs_context_t a_context; } */ *ap
;
338 struct volfs_vndata
*priv_data
;
339 register struct uio
*uio
= ap
->a_uio
;
343 struct dirent local_dir
;
347 struct volfs_rdstruct vcs
;
349 off
= uio
->uio_offset
;
350 priv_data
= ap
->a_vp
->v_data
;
351 // LP64todo - fix this!
352 starting_resid
= count
= uio_resid(uio
);
354 /* Make sure we don't return partial entries. */
355 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
360 * Make sure we're starting on a directory boundary
362 if (off
& (VLFSDIRENTLEN
- 1)) {
365 rec_offset
= off
/ VLFSDIRENTLEN
;
366 // LP64todo - fix this!
367 lost
= uio_resid(uio
) - count
;
368 uio_setresid(uio
, count
);
369 uio_iov_len_set(uio
, count
);
371 if (IS_VALID_UIO_SEGFLG(uio
->uio_segflg
) == 0) {
372 panic("%s :%d - invalid uio_segflg\n", __FILE__
, __LINE__
);
374 #endif /* LP64_DEBUG */
376 local_dir
.d_reclen
= VLFSDIRENTLEN
;
378 * We must synthesize . and ..
386 local_dir
.d_fileno
= priv_data
->nodeID
;
387 local_dir
.d_type
= DT_DIR
;
388 local_dir
.d_namlen
= 1;
389 local_dir
.d_name
[0] = '.';
390 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
391 local_dir
.d_name
[i
] = 0;
392 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
399 * We only have two levels in the volfs hierarchy. Root's
400 * .. points to itself and the second level points to root,
401 * hence we've hardcoded d_fileno for .. here
403 local_dir
.d_fileno
= ROOT_DIRID
;
404 local_dir
.d_type
= DT_DIR
;
405 local_dir
.d_namlen
= 2;
406 local_dir
.d_name
[0] = '.';
407 local_dir
.d_name
[1] = '.';
408 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
409 local_dir
.d_name
[i
] = 0;
410 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
415 * OK, we've given them the . & .. entries. If this is a
416 * filesystem node then we've gone as far as we're going
419 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
421 *ap
->a_eofflag
= 1; /* we got all the way to the end */
425 if (rec_offset
> 1) {
426 vcs
.validindex
= 1; /* we always have "." and ".." */
427 vcs
.rec_offset
= rec_offset
;
432 vfs_iterate(0, volfs_readdir_callback
, &vcs
);
434 //if (mp == (void *) &mountlist)
435 *ap
->a_eofflag
= 1; /* we got all the way to the end */
437 uio_setresid(uio
, (uio_resid(uio
) + lost
));
439 if (starting_resid
== uio_resid(uio
))
447 * validfsnode - test to see if a file system supports VGET
449 * This can cause context switching, so caller should be lock safe
452 validfsnode(struct mount
*fsnode
)
456 * Just check to see if the the mount flag is set, if it is we assume the
457 * file system supports all of volfs symantecs
460 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
467 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
471 struct vnop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
472 *a_retval; vfs_context_t a_context; } */ *ap
;
477 *ap
->a_retval
= LINK_MAX
;
480 *ap
->a_retval
= NAME_MAX
;
483 *ap
->a_retval
= PATH_MAX
;
486 *ap
->a_retval
= PIPE_BUF
;
488 case _PC_CHOWN_RESTRICTED
:
501 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
502 * On success, *vpp is the parent vp and is returned with a reference.
505 get_parentvp(struct vnode
**vpp
, struct mount
*mp
, vfs_context_t context
)
508 struct vnode_attr va
;
509 struct vnode
*child_vp
= *vpp
;
512 VATTR_WANTED(&va
, va_parentid
);
513 result
= vnode_getattr(child_vp
, &va
, context
);
518 /* Shift attention to the parent directory vnode: */
519 result
= VFS_VGET(mp
, (ino64_t
)va
.va_parentid
, vpp
, context
);
521 if (result
== 0 && child_vp
->v_parent
!= *vpp
) {
522 vnode_update_identity(child_vp
, *vpp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
530 * Look up the parent directory of a given vnode.
533 lookup_parent(vnode_t child_vp
, vnode_t
*parent_vpp
, int is_authorized
, vfs_context_t context
)
535 struct componentname cn
;
539 *parent_vpp
= NULLVP
;
541 if (is_authorized
== 0) {
542 error
= vnode_authorize(child_vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
547 new_vp
= child_vp
->v_parent
;
549 if (new_vp
!= NULLVP
) {
550 if ( (error
= vnode_getwithref(new_vp
)) == 0 )
551 *parent_vpp
= new_vp
;
554 bzero(&cn
, sizeof(cn
));
555 cn
.cn_nameiop
= LOOKUP
;
556 cn
.cn_context
= context
;
557 cn
.cn_pnbuf
= CAST_DOWN(caddr_t
, &gDotDot
);
558 cn
.cn_pnlen
= strlen(cn
.cn_pnbuf
);
559 cn
.cn_nameptr
= cn
.cn_pnbuf
;
560 cn
.cn_namelen
= cn
.cn_pnlen
;
561 cn
.cn_flags
= (FOLLOW
| LOCKLEAF
| ISLASTCN
| ISDOTDOT
);
563 error
= VNOP_LOOKUP(child_vp
, &new_vp
, &cn
, context
);
567 if (new_vp
== child_vp
) {
571 if (child_vp
->v_parent
== NULLVP
) {
572 vnode_update_identity(child_vp
, new_vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
574 *parent_vpp
= new_vp
;
580 * verify_fullpathaccess(ret_vnode);
584 verify_fullpathaccess(struct vnode
*targetvp
, vfs_context_t context
)
586 struct vnode
*vp
, *parent_vp
;
587 struct mount
*mp
= targetvp
->v_mount
;
588 struct proc
*p
= vfs_context_proc(context
);
591 struct filedesc
*fdp
= p
->p_fd
; /* pointer to file descriptor state */
596 /* get the parent directory. */
597 if ((vp
->v_flag
& VROOT
) == 0 && vp
!= fdp
->fd_cdir
&& vp
!= fdp
->fd_rdir
) {
598 if (vp
->v_parent
== NULLVP
|| (vp
->v_flag
& VISHARDLINK
) || (vnode_getwithref(vp
->v_parent
) != 0)) {
599 if (vp
->v_type
== VDIR
) {
600 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
603 * If the lookup fails with EACCES and the vp is a directory,
604 * we should try again but bypass authorization check. Without this
605 * workaround directories that you can navigate to but not traverse will
606 * disappear when clicked in the Finder.
608 if (result
== EACCES
&& (vp
->v_flag
& VROOT
) == 0) {
609 dp_authorized
= 1; /* bypass auth check */
610 if (lookup_parent(vp
, &parent_vp
, dp_authorized
, context
) == 0) {
613 dp_authorized
= 0; /* force us to authorize */
619 * this is not a directory so we must get parent object ID
621 result
= get_parentvp(&vp
, mp
, context
);
629 * we where able to get a reference on v_parent
631 parent_vp
= vp
= vp
->v_parent
;
636 * Keep going up until either the process's root or the process's working
637 * directory is hit, either one of which are potential valid starting points
638 * for a full pathname
640 while (vp
!= NULLVP
) {
642 result
= reverse_lookup(vp
, &parent_vp
, fdp
, context
, &dp_authorized
);
645 * we're done and we have access
649 if (vp
!= parent_vp
) {
651 * we where able to walk up the parent chain so now we don't need
658 * we have a referenced vp at this point... if dp_authorized == 1, than
659 * it's been authorized for search, but v_parent was NULL...
660 * if dp_authorized == 0, than we need to do the authorization check
661 * before looking up the parent
663 if ((vp
->v_flag
& VROOT
) != 0 ||
664 vp
== fdp
->fd_cdir
|| vp
== fdp
->fd_rdir
) {
666 * we're already at the termination point, which implies that
667 * the authorization check in the cache failed (otherwise we
668 * would have returned 'done' from "reverse_lookup"... so,
669 * do the authorization and bail
671 result
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, context
);
674 result
= lookup_parent(vp
, &parent_vp
, dp_authorized
, context
);
678 if (vp
!= parent_vp
) {
680 * got the parent so now we don't need vp any longer
688 * Success: the caller has complete access to the initial vnode
693 if (vp
!= NULLVP
&& vp
!= targetvp
) {
703 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
704 * id of filesystem to lookup and pointer to vnode pointer to fill in
707 get_fsvnode(struct mount
*our_mount
, int id
, vnode_t
*ret_vnode
)
709 struct mount
*cur_mount
;
711 struct vnode
*cur_vnode
;
712 struct volfs_vndata
*cur_privdata
;
714 struct vnode_fsparam vfsp
;
718 * OK, first look up the matching mount on the list of mounted file systems
720 /* the following will return the mount point with vfs_busy held */
721 cur_mount
= mount_lookupby_volfsid(id
, 1);
723 if (cur_mount
== NULL
) {
725 * No mounted file system by the specified ID currently exists in the system.
727 * XXX We could deal with a vnode that is still hanging about for an FS that
728 * does not exists or has been unmounted now, or count on the update below
735 cur_fsid
= cur_mount
->mnt_vfsstat
.f_fsid
;
738 * Now search the list attached to the mount structure to
739 * see if this vnode is already floating around
742 mount_lock(our_mount
);
743 TAILQ_FOREACH(cur_vnode
, &our_mount
->mnt_vnodelist
, v_mntvnodes
) {
744 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
745 if (cur_privdata
->nodeID
== (unsigned int)id
)
747 if (cur_privdata
->fs_mount
!= cur_mount
) {
748 cur_privdata
->fs_mount
= cur_mount
;
749 cur_privdata
->fs_fsid
= cur_fsid
;
754 mount_unlock(our_mount
);
757 vid
= vnode_vid(cur_vnode
);
760 * use vnode_getwithvid since it will wait for a vnode currently being
761 * terminated... if it returns an error, cur_vnode will not be what we
762 * think it is, try again
764 if (vnode_getwithvid(cur_vnode
, vid
) != 0) {
765 goto search_vnodelist
;
770 MALLOC(cur_privdata
, struct volfs_vndata
*,
771 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
773 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
774 cur_privdata
->nodeID
= id
;
776 cur_privdata
->fs_mount
= cur_mount
;
777 cur_privdata
->fs_fsid
= cur_fsid
;
779 vfsp
.vnfs_mp
= our_mount
;
780 vfsp
.vnfs_vtype
= VDIR
;
781 vfsp
.vnfs_str
= "volfs";
783 vfsp
.vnfs_fsnode
= cur_privdata
;
785 vfsp
.vnfs_vops
= volfs_vnodeop_p
;
787 vfsp
.vnfs_filesize
= 0;
788 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
789 vfsp
.vnfs_marksystem
= 0;
790 vfsp
.vnfs_markroot
= 0;
792 retval
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &cur_vnode
);
794 FREE(cur_privdata
, M_VOLFSNODE
);
797 cur_vnode
->v_tag
= VT_VOLFS
;
801 *ret_vnode
= cur_vnode
;
804 vfs_unbusy(cur_mount
);
811 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
812 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
816 get_filevnode(struct mount
*parent_fs
, u_int id
, vnode_t
*ret_vnode
, vfs_context_t context
)
822 * Special case 2 to mean the root of a file system
825 retval
= VFS_ROOT(parent_fs
, ret_vnode
, context
);
827 retval
= VFS_VGET(parent_fs
, (ino64_t
)id
, ret_vnode
, context
);
828 if (retval
) goto error
;
830 retval
= verify_fullpathaccess(*ret_vnode
, context
);
832 /* An error was encountered verifying that the caller has,
833 in fact, got access all the way from "/" or their working
834 directory to the specified item...
836 vnode_put(*ret_vnode
);
838 /* vnode was recycled during access verification. */
839 if (retval
== EAGAIN
) {
850 volfs_lookup(struct vnop_lookup_args
*ap
)
852 struct volfs_vndata
*priv_data
;
855 struct mount
*parent_fs
;
857 int isdot_or_dotdot
= 0;
858 int ret_err
= ENOENT
;
863 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
864 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, 0, 0);
866 priv_data
= ap
->a_dvp
->v_data
;
867 nameptr
= ap
->a_cnp
->cn_nameptr
;
868 namelen
= ap
->a_cnp
->cn_namelen
;
869 firstchar
= nameptr
[0];
871 /* First check for "." and ".." */
872 if (firstchar
== '.') {
876 *ap
->a_vpp
= ap
->a_dvp
;
877 vnode_get(*ap
->a_vpp
);
879 } else if (nameptr
[1] == '.' && namelen
== 2) {
882 ret_err
= VFS_ROOT(ap
->a_dvp
->v_mount
, ap
->a_vpp
, ap
->a_context
);
884 } else if (firstchar
== '@') { /* '@' is alias for system root */
885 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
886 /* the following returns with iteration count on mount point */
887 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
889 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
890 mount_iterdrop(parent_fs
);
895 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
, ap
->a_context
);
896 vfs_unbusy(parent_fs
);
906 } else if (namelen
<= 10 && firstchar
> '0' && firstchar
<= '9') {
910 id
= strtoul(nameptr
, &check_ptr
, 10);
913 * strtol will leave us at the first non-numeric character.
914 * we've checked to make sure the component name does
915 * begin with a numeric so check_ptr must wind up on
916 * the terminating null or there was other junk following the
919 if ((check_ptr
- nameptr
) == namelen
) {
920 if (priv_data
->vnode_type
== VOLFS_ROOT
) {
924 * Obtain the mountpoint and call VFS_VGET in
925 * one step (ie without creating a vnode for
928 if (check_ptr
[0] == '/' &&
929 check_ptr
[1] > '0' && check_ptr
[1] <= '9') {
935 /* this call will return mount point with vfs_busy held */
936 mp
= mount_lookupby_volfsid(id
, 1);
941 id2
= strtoul(&check_ptr
[1], &endptr
, 10);
942 if ((endptr
[0] == '/' || endptr
[0] == '\0') &&
943 get_filevnode(mp
, id2
, &vp
, ap
->a_context
) == 0) {
944 ap
->a_cnp
->cn_consume
= endptr
- check_ptr
;
951 /* Fall through to default behavior... */
953 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
956 parent_fs
= mount_list_lookupby_fsid(&priv_data
->fs_fsid
, 0, 1);
958 ret_val
= vfs_busy(parent_fs
, LK_NOWAIT
);
959 mount_iterdrop(parent_fs
);
964 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
, ap
->a_context
);
965 vfs_unbusy(parent_fs
);
976 if ( ret_err
== 0 && !isdot_or_dotdot
&& (vp
!= NULLVP
) && (vp
->v_parent
== NULLVP
))
977 vnode_update_identity(vp
, ap
->a_dvp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
980 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
981 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, ret_err
, 0);