2 * Copyright (c) 2000-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 * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
31 * Modification History:
33 * 02-Feb-2000 Clark Warner Added copyfile to table
34 * 17-Aug-1999 Pat Dirks New today.
37 #include <mach/mach_types.h>
38 #include <mach/machine/boolean.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
45 #include <sys/kauth.h>
47 #include <sys/mount_internal.h>
48 #include <sys/vnode_internal.h>
49 #include <sys/malloc.h>
50 #include <sys/dirent.h>
51 #include <sys/namei.h>
53 #include <sys/uio_internal.h>
56 #include <sys/errno.h>
57 #include <vfs/vfs_support.h>
64 #error NOT PORTED FOR UBC
68 static int synthfs_remove_internal(struct vnode
*dvp
, struct vnode
*vp
,
69 struct componentname
*cnp
, vfs_context_t context
);
72 #define VOPFUNC int (*)(void *)
74 /* Global vfs data structures for synthfs. */
75 int (**synthfs_vnodeop_p
) (void *);
76 struct vnodeopv_entry_desc synthfs_vnodeop_entries
[] = {
77 {&vnop_default_desc
, (VOPFUNC
)vn_default_error
},
78 {&vnop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy - not supported */
79 {&vnop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite - not supported */
80 {&vnop_lookup_desc
, (VOPFUNC
)synthfs_cached_lookup
}, /* cached lookup */
81 {&vnop_create_desc
, (VOPFUNC
)synthfs_create
}, /* create - DEBUGGER */
82 {&vnop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout - not supported */
83 {&vnop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod - not supported */
84 {&vnop_open_desc
, (VOPFUNC
)synthfs_open
}, /* open - DEBUGGER */
85 {&vnop_close_desc
, (VOPFUNC
)nop_close
}, /* close - NOP */
86 {&vnop_getattr_desc
, (VOPFUNC
)synthfs_getattr
}, /* getattr */
87 {&vnop_setattr_desc
, (VOPFUNC
)synthfs_setattr
}, /* setattr */
88 {&vnop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist - not supported */
89 {&vnop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist - not supported */
90 {&vnop_read_desc
, (VOPFUNC
)err_read
}, /* read - not supported */
91 {&vnop_write_desc
, (VOPFUNC
)err_write
}, /* write - not supported */
92 {&vnop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl - not supported */
93 {&vnop_select_desc
, (VOPFUNC
)synthfs_select
}, /* select */
94 {&vnop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange - not supported */
95 {&vnop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke - NOP */
96 {&vnop_mmap_desc
, (VOPFUNC
)synthfs_mmap
}, /* mmap - DEBUGGER */
97 {&vnop_fsync_desc
, (VOPFUNC
)nop_fsync
}, /* fsync - NOP */
98 {&vnop_remove_desc
, (VOPFUNC
)synthfs_remove
}, /* remove */
99 {&vnop_link_desc
, (VOPFUNC
)err_link
}, /* link - not supported */
100 {&vnop_rename_desc
, (VOPFUNC
)synthfs_rename
}, /* rename */
101 {&vnop_mkdir_desc
, (VOPFUNC
)synthfs_mkdir
}, /* mkdir */
102 {&vnop_rmdir_desc
, (VOPFUNC
)synthfs_rmdir
}, /* rmdir */
103 {&vnop_symlink_desc
, (VOPFUNC
)synthfs_symlink
}, /* symlink */
104 {&vnop_readdir_desc
, (VOPFUNC
)synthfs_readdir
}, /* readdir */
105 {&vnop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr - not supported */
106 {&vnop_readlink_desc
, (VOPFUNC
)synthfs_readlink
}, /* readlink */
107 {&vnop_inactive_desc
, (VOPFUNC
)synthfs_inactive
}, /* inactive */
108 {&vnop_reclaim_desc
, (VOPFUNC
)synthfs_reclaim
}, /* reclaim */
109 {&vnop_pathconf_desc
, (VOPFUNC
)synthfs_pathconf
}, /* pathconf */
110 {&vnop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock - not supported */
111 {&vnop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate - not supported */
112 {&vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein - not supported */
113 {&vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout - not supported */
114 {&vnop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize - not supported */
115 {&vnop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs - not supported */
116 {&vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* copyfile - not supported */
117 { &vnop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff not supported */
118 { &vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk not supported */
119 { &vnop_blockmap_desc
, (VOPFUNC
)err_blockmap
}, /* blockmap not supported */
120 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
124 * Oh what a tangled web we weave. This structure will be used by
125 * bsd/vfs/vfs_conf.c to actually do the initialization of synthfs_vnodeop_p
127 struct vnodeopv_desc synthfs_vnodeop_opv_desc
=
128 {&synthfs_vnodeop_p
, synthfs_vnodeop_entries
};
133 * Create a regular file
138 IN WILLRELE struct vnode *dvp;
139 OUT struct vnode **vpp;
140 IN struct componentname *cnp;
141 IN struct vnode_attr *vap;
143 We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
150 struct vnop_create_args
/* {
152 struct vnode **a_vpp;
153 struct componentname *a_cnp;
154 struct vnode_attr *a_vap;
155 vfs_context_t a_context;
159 struct vnode
*dvp
= ap
->a_dvp
;
162 sprintf(debugmsg
, "synthfs_create: attempt to create '%s' in '%s' ?!", ap
->a_cnp
->cn_nameptr
, VTOS(dvp
)->s_name
);
166 return err_create(ap
);
178 IN vfs_context_t a_context;
183 struct vnop_open_args
/* {
186 vfs_context_t a_context;
189 struct vnode
*vp
= ap
->a_vp
;
191 if (vp
->v_type
== VDIR
) {
195 struct synthfsnode
*sp
= VTOS(vp
);
198 sprintf(debugmsg
, "synthfs_open: attempt to open '/%s' ?!", sp
->s_name
);
211 * NB Currently unsupported.
217 IN kauth_cred_t cred;
225 synthfs_mmap(__unused
struct vnop_mmap_args
*ap
)
237 IN struct vnode_attr *vap;
238 IN vfs_context_t context;
243 struct vnop_getattr_args
/* {
245 struct vnode_attr *a_vap;
246 vfs_context_t a_context;
249 struct vnode
*vp
= ap
->a_vp
;
250 struct vnode_attr
*vap
= ap
->a_vap
;
251 struct synthfsnode
*sp
= VTOS(vp
);
253 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
254 VATTR_RETURN(vap
, va_mode
, sp
->s_mode
);
255 VATTR_RETURN(vap
, va_nlink
, sp
->s_linkcount
);
256 VATTR_RETURN(vap
, va_uid
, sp
->s_uid
);
257 VATTR_RETURN(vap
, va_gid
, sp
->s_gid
);
258 VATTR_RETURN(vap
, va_fsid
, VTOVFS(vp
)->mnt_vfsstat
.f_fsid
.val
[0]);
259 VATTR_RETURN(vap
, va_fileid
, sp
->s_nodeid
);
260 switch (vp
->v_type
) {
262 VATTR_RETURN(vap
, va_data_size
, (sp
->s_u
.d
.d_entrycount
+ 2) * sizeof(struct dirent
));
266 VATTR_RETURN(vap
, va_data_size
, sp
->s_u
.f
.f_size
);
270 VATTR_RETURN(vap
, va_data_size
, sp
->s_u
.s
.s_length
);
274 VATTR_RETURN(vap
, va_data_size
, 0);
276 VATTR_RETURN(vap
, va_iosize
, 512);
277 vap
->va_access_time
.tv_sec
= sp
->s_accesstime
.tv_sec
;
278 vap
->va_access_time
.tv_nsec
= sp
->s_accesstime
.tv_usec
* 1000;
279 VATTR_SET_SUPPORTED(vap
, va_access_time
);
280 vap
->va_modify_time
.tv_sec
= sp
->s_modificationtime
.tv_sec
;
281 vap
->va_modify_time
.tv_nsec
= sp
->s_modificationtime
.tv_usec
* 1000;
282 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
283 vap
->va_change_time
.tv_sec
= sp
->s_changetime
.tv_sec
;
284 vap
->va_change_time
.tv_nsec
= sp
->s_changetime
.tv_usec
* 1000;
285 VATTR_SET_SUPPORTED(vap
, va_change_time
);
286 VATTR_RETURN(vap
, va_gen
, sp
->s_generation
);
287 VATTR_RETURN(vap
, va_flags
, sp
->s_flags
);
288 VATTR_RETURN(vap
, va_rdev
, sp
->s_rdev
);
289 VATTR_RETURN(vap
, va_filerev
, 0);
290 VATTR_RETURN(vap
, va_acl
, NULL
);
298 * Change the mode on a file or directory.
299 * vnode vp must be locked on entry.
301 int synthfs_chmod(struct vnode
*vp
, int mode
, kauth_cred_t cred
, struct proc
*p
)
303 struct synthfsnode
*sp
= VTOS(vp
);
306 sp
->s_mode
&= ~ALLPERMS
;
307 sp
->s_mode
|= (mode
& ALLPERMS
);
308 sp
->s_nodeflags
|= IN_CHANGE
;
310 if ((vp
->v_flag
& VTEXT
) && (sp
->s_mode
& S_ISTXT
) == 0) (void) vnode_uncache(vp
);
319 * Change the flags on a file or directory.
320 * vnode vp must be locked on entry.
322 int synthfs_chflags(struct vnode
*vp
, u_long flags
, kauth_cred_t cred
, struct proc
*p
)
324 struct synthfsnode
*sp
= VTOS(vp
);
327 sp
->s_nodeflags
|= IN_CHANGE
;
335 * Perform chown operation on vnode vp;
336 * vnode vp must be locked on entry.
338 int synthfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
, struct proc
*p
)
340 struct synthfsnode
*sp
= VTOS(vp
);
346 if (uid
== (uid_t
)VNOVAL
) uid
= sp
->s_uid
;
347 if (gid
== (gid_t
)VNOVAL
) gid
= sp
->s_gid
;
355 if (ouid
!= uid
|| ogid
!= gid
) sp
->s_nodeflags
|= IN_CHANGE
;
356 if (ouid
!= uid
&& suser(cred
, NULL
)) sp
->s_mode
&= ~S_ISUID
;
357 if (ogid
!= gid
&& suser(cred
, NULL
)) sp
->s_mode
&= ~S_ISGID
;
365 * Set attribute vnode op. called from several syscalls
370 IN struct vnode_attr *vap;
371 IN vfs_context_t context;
376 struct vnop_setattr_args
/* {
378 struct vnode_attr *a_vap;
379 vfs_context_t a_context;
382 struct vnode
*vp
= ap
->a_vp
;
383 struct synthfsnode
*sp
= VTOS(vp
);
384 struct vnode_attr
*vap
= ap
->a_vap
;
385 kauth_cred_t cred
= vfs_context_ucred(ap
->a_context
);
386 struct proc
*p
= vfs_context_proc(ap
->a_context
);
387 struct timeval atimeval
, mtimeval
;
394 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
395 if ((result
= synthfs_chflags(vp
, vap
->va_flags
, cred
, p
))) {
399 VATTR_SET_SUPPORTED(vap
, va_flags
);
401 nuid
= (uid_t
)ngid
= (gid_t
)VNOVAL
;
402 if (VATTR_IS_ACTIVE(vap
, va_uid
))
404 if (VATTR_IS_ACTIVE(vap
, va_gid
))
406 if (nuid
!= (uid_t
)VNOVAL
|| ngid
!= (gid_t
)VNOVAL
) {
407 if ((result
= synthfs_chown(vp
, nuid
, ngid
, cred
, p
))) {
411 VATTR_SET_SUPPORTED(vap
, va_uid
);
412 VATTR_SET_SUPPORTED(vap
, va_gid
);
414 if (VATTR_IS_ACTIVE(vap
, va_data_size
)) {
416 if ((result
= vnode_setsize(vp
, vap
->va_data_size
, 0, ap
->a_context
))) {
419 VATTR_SET_SUPPORTED(vap
, va_data_size
);
427 if (VATTR_IS_ACTIVE(vap
, va_access_time
) || VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
428 if (VATTR_IS_ACTIVE(vap
, va_access_time
)) {
429 sp
->s_nodeflags
|= IN_ACCESS
;
430 atimeval
.tv_sec
= vap
->va_access_time
.tv_sec
;
431 atimeval
.tv_usec
= vap
->va_access_time
.tv_nsec
/ 1000;
433 if (VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
434 sp
->s_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
435 mtimeval
.tv_sec
= vap
->va_modify_time
.tv_sec
;
436 mtimeval
.tv_usec
= vap
->va_modify_time
.tv_nsec
/ 1000;
438 if ((result
= synthfs_update(vp
, &atimeval
, &mtimeval
, 1))) {
442 VATTR_SET_SUPPORTED(vap
, va_access_time
);
443 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
445 if (VATTR_IS_ACTIVE(vap
, va_mode
))
446 result
= synthfs_chmod(vp
, (int)vap
->va_mode
, cred
, p
);
447 VATTR_SET_SUPPORTED(vap
, va_mode
);
451 DBG_VOP(("synthfs_setattr: returning %d...\n", result
));
460 #% rename sourcePar_vp U U U
461 #% rename source_vp U U U
462 #% rename targetPar_vp L U U
463 #% rename target_vp X U U
466 IN WILLRELE struct vnode *sourcePar_vp;
467 IN WILLRELE struct vnode *source_vp;
468 IN struct componentname *source_cnp;
469 IN WILLRELE struct vnode *targetPar_vp;
470 IN WILLRELE struct vnode *target_vp;
471 IN struct componentname *target_cnp;
478 * source's parent directory is unlocked
479 * source file or directory is unlocked
480 * destination's parent directory is locked
481 * destination file or directory is locked if it exists
484 * all denodes should be released
490 struct vnop_rename_args
/* {
491 struct vnode *a_fdvp;
493 struct componentname *a_fcnp;
494 struct vnode *a_tdvp;
496 struct componentname *a_tcnp;
497 vfs_context_t a_context;
500 struct vnode
*target_vp
= ap
->a_tvp
;
501 struct vnode
*targetPar_vp
= ap
->a_tdvp
;
502 struct vnode
*source_vp
= ap
->a_fvp
;
503 struct vnode
*sourcePar_vp
= ap
->a_fdvp
;
504 struct componentname
*target_cnp
= ap
->a_tcnp
;
505 struct componentname
*source_cnp
= ap
->a_fcnp
;
506 struct synthfsnode
*target_sp
, *targetPar_sp
, *source_sp
, *sourcePar_sp
;
507 u_short doingdirectory
= 0, oldparent
= 0, newparent
= 0;
511 #if SYNTHFS_DIAGNOSTIC
512 if ((target_cnp
->cn_flags
& HASBUF
) == 0 ||
513 (source_cnp
->cn_flags
& HASBUF
) == 0)
514 panic("synthfs_rename: no name");
517 DBG_ASSERT((ap
->a_fdvp
->v_type
== VDIR
) && (ap
->a_tdvp
->v_type
== VDIR
));
518 target_sp
= targetPar_sp
= source_sp
= sourcePar_sp
= NULL
;
521 sourcePar_sp
= VTOS(sourcePar_vp
);
522 source_sp
= VTOS(source_vp
);
523 oldparent
= sourcePar_sp
->s_nodeid
;
526 * Be sure we are not renaming ".", "..", or an alias of ".". This
527 * leads to a crippled directory tree. It's pretty tough to do a
528 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
529 * doesn't work if the ".." entry is missing.
531 if (source_sp
->s_type
== SYNTHFS_DIRECTORY
) {
532 if ((source_cnp
->cn_namelen
== 1 && source_cnp
->cn_nameptr
[0] == '.')
533 || sourcePar_sp
== source_sp
534 || (source_cnp
->cn_flags
& ISDOTDOT
)
535 || (source_sp
->s_nodeflags
& IN_RENAME
)) {
539 source_sp
->s_nodeflags
|= IN_RENAME
;
540 doingdirectory
= TRUE
;
543 /* Transit between abort and bad */
545 targetPar_sp
= VTOS(targetPar_vp
);
546 target_sp
= target_vp
? VTOS(target_vp
) : NULL
;
547 newparent
= targetPar_sp
->s_nodeid
;
551 * If the destination exists, then be sure its type (file or dir)
552 * matches that of the source. And, if it is a directory make sure
553 * it is empty. Then delete the destination.
558 if (target_vp
->v_type
== VREG
) {
559 (void) vnode_uncache(target_vp
);
562 cache_purge(target_vp
);
564 retval
= synthfs_remove_internal(targetPar_vp
, target_vp
, target_cnp
, ap
->a_context
);
569 if (retval
) goto bad
;
573 /* remove the existing entry from the namei cache: */
574 if (source_vp
->v_type
== VREG
) cache_purge(source_vp
);
576 retval
= synthfs_move_rename_entry( source_vp
, targetPar_vp
, target_cnp
->cn_nameptr
);
578 if (retval
) goto bad
;
580 source_sp
->s_nodeflags
&= ~IN_RENAME
;
583 * Timestamp both parent directories.
584 * Note that if this is a rename within the same directory,
585 * (where targetPar_hp == sourcePar_hp)
586 * the code below is still safe and correct.
588 targetPar_sp
->s_nodeflags
|= IN_UPDATE
;
589 sourcePar_sp
->s_nodeflags
|= IN_UPDATE
;
592 SYNTHFSTIMES(targetPar_sp
, &tv
, &tv
);
593 SYNTHFSTIMES(sourcePar_sp
, &tv
, &tv
);
598 if (retval
&& doingdirectory
)
599 source_sp
->s_nodeflags
&= ~IN_RENAME
;
616 IN WILLRELE struct vnode *dvp;
617 OUT struct vnode **vpp;
618 IN struct componentname *cnp;
619 IN struct vnode_attr *vap;
620 IN vfs_context_t context;
622 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
629 struct vnop_mkdir_args
/* {
631 struct vnode **a_vpp;
632 struct componentname *a_cnp;
633 struct vnode_attr *a_vap;
634 vfs_context_t a_context;
638 struct vnode
*dvp
= ap
->a_dvp
;
639 struct componentname
*cnp
= ap
->a_cnp
;
640 int mode
= MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
);
641 struct vnode
*vp
= NULL
;
645 retval
= synthfs_new_directory(VTOVFS(dvp
), dvp
, cnp
->cn_nameptr
, VTOSFS(dvp
)->synthfs_nextid
++, mode
, vfs_context_proc(cnp
->cn_context
), &vp
);
646 if (retval
) goto Error_Exit
;
650 retval
= vnode_setattr(vp
, ap
->a_vap
, ap
->a_context
);
651 if (retval
!= 0) goto Error_Exit
;
655 if (vp
) synthfs_remove_directory(vp
);
669 IN WILLRELE struct vnode *dvp;
670 IN WILLRELE struct vnode *vp;
671 IN struct componentname *cnp;
672 IN vfs_context_t context;
678 struct vnop_remove_args
/* {
681 struct componentname *a_cnp;
682 vfs_context_t a_context;
685 return synthfs_remove_internal(ap
->a_dvp
, ap
->a_vp
, ap
->a_cnp
, ap
->a_context
);
689 synthfs_remove_internal(struct vnode
*dvp
, struct vnode
*vp
,
690 __unused
struct componentname
*cnp
,
691 __unused vfs_context_t context
)
693 struct synthfsnode
*sp
= VTOS(vp
);
697 /* This is sort of silly right now but someday it may make sense... */
698 if (sp
->s_nodeflags
& IN_MODIFIED
) {
700 synthfs_update(vp
, &tv
, &tv
, 0);
703 /* remove the entry from the namei cache: */
706 /* remove entry from tree and reclaim any resources consumed: */
707 switch (sp
->s_type
) {
708 case SYNTHFS_DIRECTORY
:
709 synthfs_remove_directory(vp
);
713 case SYNTHFS_SYMLINK
:
714 synthfs_remove_symlink(vp
);
718 /* Fall through to default case */
721 synthfs_remove_entry(vp
);
727 VTOS(dvp
)->s_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
739 IN WILLRELE struct vnode *dvp;
740 IN WILLRELE struct vnode *vp;
741 IN struct componentname *cnp;
742 IN vfs_context_t context;
748 struct vnop_rmdir_args
/* {
751 struct componentname *a_cnp;
752 vfs_context_t a_context;
755 return synthfs_remove((struct vnop_remove_args
*)ap
);
761 * synthfs_select - just say OK. Only possible op is readdir
763 * Locking policy: ignore
766 synthfs_select(__unused
767 struct vnop_select_args
/* {
776 DBG_VOP(("synthfs_select called\n"));
786 # XXX - note that the return vnode has already been vnode_put'ed
787 # by the filesystem layer. To use it you must use vnode_get,
788 # possibly with a further namei.
791 IN WILLRELE struct vnode *dvp;
792 OUT WILLRELE struct vnode **vpp;
793 IN struct componentname *cnp;
794 IN struct vnode_attr *vap;
797 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
805 struct vnop_symlink_args
/* {
807 struct vnode **a_vpp;
808 struct componentname *a_cnp;
809 struct vnode_attr *a_vap;
811 vfs_context_t a_context;
814 struct vnode
*dvp
= ap
->a_dvp
;
815 struct vnode
**vpp
= ap
->a_vpp
;
816 struct componentname
*cnp
= ap
->a_cnp
;
821 retval
= synthfs_new_symlink(VTOVFS(dvp
), dvp
, cnp
->cn_nameptr
, VTOSFS(dvp
)->synthfs_nextid
++, ap
->a_target
, vfs_context_proc(cnp
->cn_context
), vpp
);
834 INOUT struct uio *uio;
835 IN kauth_cred_t cred;
840 struct vnop_readlink_args
/* {
843 vfs_context_t a_context;
846 struct vnode
*vp
= ap
->a_vp
;
847 struct synthfsnode
*sp
= VTOS(vp
);
848 struct uio
*uio
= ap
->a_uio
;
852 if (ap
->a_uio
->uio_offset
> sp
->s_u
.s
.s_length
) {
856 // LP64todo - fix this!
857 if (uio
->uio_offset
+ uio_resid(uio
) <= sp
->s_u
.s
.s_length
) {
858 count
= uio_resid(uio
);
860 count
= sp
->s_u
.s
.s_length
- uio
->uio_offset
;
862 retval
= uiomove((void *)((unsigned char *)sp
->s_u
.s
.s_symlinktarget
+ uio
->uio_offset
), count
, uio
);
873 * Read directory entries.
877 struct vnop_readdir_args
/* {
883 vfs_context_t a_context;
886 struct synthfsnode
*sp
= VTOS(ap
->a_vp
);
887 register struct uio
*uio
= ap
->a_uio
;
888 off_t diroffset
; /* Offset into simulated directory file */
889 struct synthfsnode
*entry
;
891 DBG_VOP(("\tuio_offset = %d, uio_resid = %lld\n", (int) uio
->uio_offset
, uio_resid(uio
)));
893 if (ap
->a_flags
& (VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
))
896 /* We assume it's all one big buffer... */
897 if (uio
->uio_iovcnt
> 1) {
898 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
905 * We must synthesize . and ..
907 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %lld\n", (int) uio
->uio_offset
, uio_resid(uio
)));
908 if (uio
->uio_offset
== diroffset
)
910 DBG_VOP(("\tAdding .\n"));
911 diroffset
+= synthfs_adddirentry(sp
->s_nodeid
, DT_DIR
, ".", uio
);
912 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %lld\n", (int) uio
->uio_offset
, uio_resid(uio
)));
914 if ((uio_resid(uio
) > 0) && (diroffset
> uio
->uio_offset
)) {
915 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
919 if (uio
->uio_offset
== diroffset
)
921 DBG_VOP(("\tAdding ..\n"));
922 if (sp
->s_parent
!= NULL
) {
923 diroffset
+= synthfs_adddirentry(sp
->s_parent
->s_nodeid
, DT_DIR
, "..", uio
);
925 diroffset
+= synthfs_adddirentry(sp
->s_nodeid
, DT_DIR
, "..", uio
);
927 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %lld\n", (int) uio
->uio_offset
, uio_resid(uio
)));
929 if ((uio_resid(uio
) > 0) && (diroffset
> uio
->uio_offset
)) {
930 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
934 /* OK, so much for the fakes. Now for the "real thing": */
935 TAILQ_FOREACH(entry
, &sp
->s_u
.d
.d_subnodes
, s_sibling
) {
936 if (diroffset
== uio
->uio_offset
) {
937 /* Return this entry */
938 diroffset
+= synthfs_adddirentry(entry
->s_nodeid
, VTTOIF(STOV(entry
)->v_type
), entry
->s_name
, uio
);
940 if ((uio_resid(uio
) > 0) && (diroffset
> uio
->uio_offset
)) {
941 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
947 *ap
->a_eofflag
= (entry
== NULL
); /* If we ran all the way through the list, there is no more */
962 synthfs_cached_lookup(ap
)
963 struct vnop_lookup_args
/* {
965 struct vnode **a_vpp;
966 struct componentname *a_cnp;
969 struct vnode
*dp
= ap
->a_dvp
;
970 struct componentname
*cnp
= ap
->a_cnp
;
971 u_long nameiop
= cnp
->cn_nameiop
;
972 u_long flags
= cnp
->cn_flags
;
973 struct vnode
**vpp
= ap
->a_vpp
;
976 DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
978 if (flags
& ISLASTCN
) DBG_VOP(("\tISLASTCN is set\n"));
984 * Look up an entry in the namei cache
987 result
= cache_lookup(dp
, vpp
, cnp
);
989 /* There was no entry in the cache for this parent vnode/name pair:
990 do the full-blown pathname lookup
992 return synthfs_lookup(ap
);
994 if (result
== ENOENT
) return result
;
996 /* An entry matching the parent vnode/name was found in the cache: */
1008 struct vnop_lookup_args
/* {
1009 struct vnode *a_dvp;
1010 struct vnode **a_vpp;
1011 struct componentname *a_cnp;
1012 vfs_context_t a_context;
1015 struct vnode
*dp
= ap
->a_dvp
;
1016 struct synthfsnode
*dsp
= VTOS(dp
);
1017 struct componentname
*cnp
= ap
->a_cnp
;
1018 u_long nameiop
= cnp
->cn_nameiop
;
1019 // char *nameptr = cnp->cn_nameptr;
1020 u_long flags
= cnp
->cn_flags
;
1021 long namelen
= cnp
->cn_namelen
;
1022 // struct proc *p = cnp->cn_proc;
1023 vfs_context_t ctx
= cnp
->cn_context
;
1024 kauth_cred_t cred
= vfs_context_ucred(ctx
);
1025 struct synthfsnode
*entry
;
1026 struct vnode
*target_vp
= NULL
;
1028 boolean_t found
= FALSE
;
1029 boolean_t isDot
= FALSE
;
1030 boolean_t isDotDot
= FALSE
;
1031 struct vnode
*starting_parent
= dp
;
1033 DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
1035 if (flags
& LOCKPARENT
) DBG_VOP(("\tLOCKPARENT is set\n"));
1036 if (flags
& ISLASTCN
) DBG_VOP(("\tISLASTCN is set\n"));
1041 /* first check for "." and ".." */
1042 if (cnp
->cn_nameptr
[0] == '.') {
1051 vnode_get(target_vp
);
1056 } else if ((namelen
== 2) && (cnp
->cn_nameptr
[1] == '.')) {
1063 if ((dsp
->s_parent
!= NULL
) && (dsp
->s_parent
!= VTOS(dp
))) {
1064 target_vp
= STOV(dsp
->s_parent
);
1066 * Special case for ".." to prevent deadlock:
1067 * always release the parent vnode BEFORE trying to acquire
1068 * ITS parent. This avoids deadlocking with another lookup
1069 * starting from the target_vp trying to vnode_get() this directory.
1071 result
= vnode_get(target_vp
);
1075 /* dp is alread locked and ref'ed */
1083 /* finally, just look for entries by name (making sure the entry's length
1084 matches the cnp's namelen... */
1085 TAILQ_FOREACH(entry
, &dsp
->s_u
.d
.d_subnodes
, s_sibling
) {
1086 if ((bcmp(cnp
->cn_nameptr
, entry
->s_name
, (unsigned)namelen
) == 0) &&
1087 (*(entry
->s_name
+ namelen
) == (char)0)) {
1089 target_vp
= STOV(entry
);
1090 result
= vnode_getwithref(target_vp
); /* refcount is always > 0 for any vnode in this list... */
1095 /* The specified entry was found and successfully acquired: */
1104 if ((nameiop
== DELETE
) && (flags
& ISLASTCN
)) {
1107 * If the parent directory is "sticky" then the user must own
1108 * the directory, or the file in it, in order to be allowed to
1109 * delete it (unless the user is root). This implements
1110 * append-only directories
1112 if ((dsp
->s_mode
& S_ISVTX
) &&
1113 suser(cred
, NULL
) &&
1114 (kauth_cred_getuid(cred
) != dsp
->s_uid
) &&
1115 (target_vp
!= NULL
) &&
1116 (target_vp
->v_type
!= VLNK
) &&
1117 (VTOS(target_vp
)->s_uid
!= kauth_cred_getuid(cred
))) {
1118 vnode_put(target_vp
);
1124 if ((nameiop
== RENAME
) && (flags
& WANTPARENT
) && (flags
* ISLASTCN
)) {
1127 vnode_put(target_vp
);
1133 /* The specified entry wasn't found: */
1136 if ((flags
& ISLASTCN
) &&
1137 ((nameiop
== CREATE
) ||
1138 (nameiop
== RENAME
) ||
1139 ((nameiop
== DELETE
) && (flags
& DOWHITEOUT
) && (flags
& ISWHITEOUT
)))) {
1140 /* create a new entry */
1141 result
= EJUSTRETURN
;
1145 *ap
->a_vpp
= target_vp
;
1148 DBG_VOP(("synthfs_lookup: result = %d.\n", result
));
1151 DBG_VOP(("synthfs_lookup: target_vp = 0x%08X \n", (u_long
)target_vp
));
1153 DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n"));
1156 DBG_VOP(("synthf_lookup: target not found.\n"));
1158 DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X .\n", (u_long
)dp
, (u_long
)starting_parent
));
1167 #% pathconf vp L L L
1170 IN struct vnode *vp;
1172 OUT register_t *retval;
1175 synthfs_pathconf(ap
)
1176 struct vnop_pathconf_args
/* {
1180 vfs_context_t a_context;
1183 DBG_VOP(("synthfs_pathconf called\n"));
1188 *ap
->a_retval
= LINK_MAX
;
1191 *ap
->a_retval
= NAME_MAX
;
1194 *ap
->a_retval
= PATH_MAX
;
1197 *ap
->a_retval
= PIPE_BUF
;
1199 case _PC_CHOWN_RESTRICTED
:
1213 * Update the access, modified, and node change times as specified by the
1214 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
1215 * used to specify that the node needs to be updated but that the times have
1216 * already been set. The access and modified times are taken from the second
1217 * and third parameters; the node change time is always taken from the current
1218 * time. If waitfor is set, then wait for the disk write of the node to
1223 synthfs_update(struct vnode
*vp
, struct timeval
*access
, struct timeval
*modify
, __unused
int waitfor
)
1225 struct synthfsnode
*sp
= VTOS(vp
);
1228 DBG_ASSERT(sp
!= NULL
);
1230 if (((sp
->s_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) != 0) &&
1231 !(VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
)) {
1232 if (sp
->s_nodeflags
& IN_ACCESS
) sp
->s_accesstime
= *access
;
1233 if (sp
->s_nodeflags
& IN_UPDATE
) sp
->s_modificationtime
= *modify
;
1234 if (sp
->s_nodeflags
& IN_CHANGE
) {
1237 sp
->s_changetime
= tv
;
1241 /* After the updates are finished, clear the flags */
1242 sp
->s_nodeflags
&= ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
1249 /*******************************************************************************************
1251 Utility/housekeeping vnode operations:
1253 ******************************************************************************************/
1258 #% inactive vp L U U
1261 IN struct vnode *vp;
1267 synthfs_inactive(ap
)
1268 struct vnop_inactive_args
/* {
1270 vfs_context_t a_context;
1273 struct vnode
*vp
= ap
->a_vp
;
1274 struct synthfsnode
*sp
= VTOS(vp
);
1278 if (vp
->v_usecount
!= 0)
1279 DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp
->v_usecount
));
1283 * Ignore nodes related to stale file handles.
1285 if (vp
->v_type
== VNON
)
1288 /* This is sort of silly but might make sense in the future: */
1289 if (sp
->s_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) {
1291 synthfs_update(vp
, &tv
, &tv
, 0);
1296 * If we are done with the inode, reclaim it
1297 * so that it can be reused immediately.
1299 if (vp
->v_type
== VNON
) {
1309 * synthfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
1311 * Locking policy: ignored
1315 struct vnop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
1317 struct vnode
*vp
= ap
->a_vp
;
1318 struct synthfsnode
*sp
= VTOS(vp
);
1319 void *name
= sp
->s_name
;
1325 FREE((void *)sp
, M_SYNTHFS
);