2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1998, Apple Computer, Inc. All rights reserved. */
29 * 17-Aug-1999 Pat Dirks New today.
33 #include <mach/mach_types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
43 #include <sys/mount.h>
44 #include <sys/vnode.h>
45 #include <sys/malloc.h>
46 #include <sys/dirent.h>
47 #include <sys/namei.h>
52 #include <sys/errno.h>
53 #include <vfs/vfs_support.h>
57 struct synthfs_direntry_head
{
58 u_int32_t d_fileno
; /* file number of entry */
59 u_int16_t d_reclen
; /* length of this record */
60 u_int8_t d_type
; /* file type, see below */
61 u_int8_t d_namlen
; /* length of string in d_name */
65 #define PATHSEPARATOR '/'
68 void synthfs_setupuio(struct iovec
*iov
,
73 enum uio_rw direction
,
75 iov
->iov_base
= (char *)buffer
;
76 iov
->iov_len
= bufsize
;
81 uio
->uio_resid
= bufsize
;
82 uio
->uio_segflg
= space
;
83 uio
->uio_rw
= direction
;
88 static int synthfs_insertnode(struct synthfsnode
*newnode_sp
, struct synthfsnode
*parent_sp
) {
91 DBG_ASSERT(parent_sp
->s_type
== SYNTHFS_DIRECTORY
);
93 TAILQ_INSERT_TAIL(&parent_sp
->s_u
.d
.d_subnodes
, newnode_sp
, s_sibling
);
94 ++parent_sp
->s_u
.d
.d_entrycount
;
95 newnode_sp
->s_parent
= parent_sp
;
97 parent_sp
->s_nodeflags
|= IN_CHANGE
| IN_MODIFIED
;
99 VOP_UPDATE(STOV(parent_sp
), &now
, &now
, 0);
106 static int synthfs_newnode(struct mount
*mp
, struct vnode
*dp
, const char *name
, unsigned long nodeid
, mode_t mode
, struct proc
*p
, struct vnode
**vpp
) {
108 struct synthfsnode
*sp
;
113 /* Allocate the synthfsnode now to avoid blocking between the call
114 to getnewvnode(), below, and the initialization of v_data: */
115 MALLOC(sp
, struct synthfsnode
*, sizeof(struct synthfsnode
), M_SYNTHFS
, M_WAITOK
);
118 MALLOC(nodename
, char *, 1, M_TEMP
, M_WAITOK
);
121 MALLOC(nodename
, char *, strlen(name
) + 1, M_TEMP
, M_WAITOK
);
122 strcpy(nodename
, name
);
126 Note that getnewvnode() returns the vnode with a refcount of +1;
127 this routine returns the newly created vnode with this positive refcount.
129 result
= getnewvnode(VT_SYNTHFS
, mp
, synthfs_vnodeop_p
, &vp
);
131 DBG_VOP(("getnewvnode failed with error code %d\n", result
));
132 FREE(nodename
, M_TEMP
);
137 DBG_VOP(("getnewvnod returned NULL without an error!\n"));
138 FREE(nodename
, M_TEMP
);
143 /* Initialize the relevant synthfsnode fields: */
144 bzero(sp
, sizeof(*sp
));
145 lockinit(&sp
->s_lock
, PINOD
, "synthfsnode", 0, 0);
146 sp
->s_nodeid
= nodeid
;
148 /* Initialize all times from a consistent snapshot of the clock: */
150 sp
->s_createtime
= now
;
151 sp
->s_accesstime
= now
;
152 sp
->s_modificationtime
= now
;
153 sp
->s_changetime
= now
;
154 sp
->s_name
= nodename
;
160 vget(vp
, LK_EXCLUSIVE
, p
);
162 /* If there's a parent directory, update its subnode structures to insert this new node: */
164 result
= synthfs_insertnode(sp
, VTOS(dp
));
174 int synthfs_remove_entry(struct vnode
*vp
) {
175 struct synthfsnode
*sp
= VTOS(vp
);
176 struct synthfsnode
*psp
= sp
->s_parent
;
180 TAILQ_REMOVE(&psp
->s_u
.d
.d_subnodes
, sp
, s_sibling
);
181 --psp
->s_u
.d
.d_entrycount
;
183 psp
->s_nodeflags
|= IN_CHANGE
| IN_MODIFIED
;
185 VOP_UPDATE(STOV(psp
), &now
, &now
, 0);
193 int synthfs_move_rename_entry(struct vnode
*source_vp
, struct vnode
*newparent_vp
, char *new_name
) {
194 struct synthfsnode
*source_sp
= VTOS(source_vp
);
195 struct synthfsnode
*parent_sp
= VTOS(newparent_vp
);
199 if (parent_sp
== source_sp
->s_parent
) return 0;
201 /* Unlink the entry from its current place: */
202 result
= synthfs_remove_entry(source_vp
);
203 if (result
) return result
;
205 /* Change the name as necessary: */
206 FREE(source_sp
->s_name
, M_TEMP
);
207 if (new_name
== NULL
) {
208 MALLOC(new_name_ptr
, char *, 1, M_TEMP
, M_WAITOK
);
211 MALLOC(new_name_ptr
, char *, strlen(new_name
) + 1, M_TEMP
, M_WAITOK
);
212 strcpy(new_name_ptr
, new_name
);
214 source_sp
->s_name
= new_name_ptr
;
216 /* Insert the entry in its new home: */
217 return synthfs_insertnode(source_sp
, parent_sp
);
222 int synthfs_new_directory(struct mount
*mp
, struct vnode
*dp
, const char *name
, unsigned long nodeid
, mode_t mode
, struct proc
*p
, struct vnode
**vpp
) {
225 struct synthfsnode
*sp
;
227 result
= synthfs_newnode(mp
, dp
, name
, nodeid
, mode
, p
, &vp
);
234 /* Initialize the relevant vnode fields: */
237 ++VTOS(dp
)->s_linkcount
; /* Account for the [fictitious] ".." link */
240 /* Set up the directory-specific fields: */
241 sp
->s_type
= SYNTHFS_DIRECTORY
;
242 sp
->s_u
.d
.d_entrycount
= 0; /* No entries in this directory yet */
243 TAILQ_INIT(&sp
->s_u
.d
.d_subnodes
); /* No subnodes of this directory yet */
252 int synthfs_remove_directory(struct vnode
*vp
) {
253 struct synthfsnode
*sp
= VTOS(vp
);
254 struct synthfsnode
*psp
= sp
->s_parent
;
256 if (psp
&& (sp
->s_type
== SYNTHFS_DIRECTORY
) && (psp
!= sp
)) {
257 --psp
->s_linkcount
; /* account for the [fictitious] ".." link now removed */
260 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
261 return synthfs_remove_entry(vp
); /* Do whatever standard cleanup is required */
266 int synthfs_new_symlink(
270 unsigned long nodeid
,
273 struct vnode
**vpp
) {
277 struct synthfsnode
*sp
;
279 result
= synthfs_newnode(mp
, dp
, name
, nodeid
, 0, p
, &vp
);
286 /* Initialize the relevant vnode fields: */
289 /* Set up the symlink-specific fields: */
290 sp
->s_type
= SYNTHFS_SYMLINK
;
291 sp
->s_u
.s
.s_length
= strlen(targetstring
);
292 MALLOC(sp
->s_u
.s
.s_symlinktarget
, char *, sp
->s_u
.s
.s_length
+ 1, M_TEMP
, M_WAITOK
);
293 strcpy(sp
->s_u
.s
.s_symlinktarget
, targetstring
);
302 int synthfs_remove_symlink(struct vnode
*vp
) {
303 struct synthfsnode
*sp
= VTOS(vp
);
305 FREE(sp
->s_u
.s
.s_symlinktarget
, M_TEMP
);
307 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
308 return synthfs_remove_entry(vp
); /* Do whatever standard cleanup is required */
316 long synthfs_adddirentry(u_int32_t fileno
, u_int8_t type
, const char *name
, struct uio
*uio
) {
317 struct synthfs_direntry_head direntry
;
321 unsigned short direntrylength
;
323 namelength
= ((name
== NULL
) ? 0 : strlen(name
));
324 padding
= (4 - (namelength
& 3)) & 3;
325 direntrylength
= sizeof(struct synthfs_direntry_head
) + namelength
+ padding
;
327 direntry
.d_fileno
= fileno
;
328 direntry
.d_reclen
= direntrylength
;
329 direntry
.d_type
= type
;
330 direntry
.d_namlen
= namelength
;
332 if (uio
->uio_resid
< direntry
.d_reclen
) {
335 uiomove((caddr_t
)(&direntry
), sizeof(direntry
), uio
);
337 uiomove((caddr_t
)name
, namelength
, uio
);
340 uiomove((caddr_t
)&padtext
, padding
, uio
);
344 return direntrylength
;