]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/synthfs/synthfs_util.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_util.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* Copyright (c) 1998, Apple Computer, Inc. All rights reserved. */
26 /*
27 * Change History:
28 *
29 * 17-Aug-1999 Pat Dirks New today.
30 *
31 */
32
33 #include <mach/mach_types.h>
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/file.h>
39 #include <sys/stat.h>
40 #include <sys/buf.h>
41 #include <sys/proc.h>
42 #include <sys/conf.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>
48 #include <sys/attr.h>
49 #include <sys/time.h>
50
51 #include <sys/vm.h>
52 #include <sys/errno.h>
53 #include <vfs/vfs_support.h>
54
55 #include "synthfs.h"
56
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 */
62 };
63
64
65 #define PATHSEPARATOR '/'
66 #define ROOTDIRID 2
67
68 void synthfs_setupuio(struct iovec *iov,
69 struct uio *uio,
70 void *buffer,
71 size_t bufsize,
72 enum uio_seg space,
73 enum uio_rw direction,
74 struct proc *p) {
75 iov->iov_base = (char *)buffer;
76 iov->iov_len = bufsize;
77
78 uio->uio_iov = iov;
79 uio->uio_iovcnt = 1;
80 uio->uio_offset = 0;
81 uio->uio_resid = bufsize;
82 uio->uio_segflg = space;
83 uio->uio_rw = direction;
84 uio->uio_procp = p;
85 }
86
87
88 static int synthfs_insertnode(struct synthfsnode *newnode_sp, struct synthfsnode *parent_sp) {
89 struct timeval now;
90
91 DBG_ASSERT(parent_sp->s_type == SYNTHFS_DIRECTORY);
92
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;
96
97 parent_sp->s_nodeflags |= IN_CHANGE | IN_MODIFIED;
98 now = time;
99 VOP_UPDATE(STOV(parent_sp), &now, &now, 0);
100
101 return 0;
102 }
103
104
105
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) {
107 int result;
108 struct synthfsnode *sp;
109 struct vnode *vp;
110 struct timeval now;
111 char *nodename;
112
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);
116
117 if (name == NULL) {
118 MALLOC(nodename, char *, 1, M_TEMP, M_WAITOK);
119 nodename[0] = 0;
120 } else {
121 MALLOC(nodename, char *, strlen(name) + 1, M_TEMP, M_WAITOK);
122 strcpy(nodename, name);
123 };
124
125 /*
126 Note that getnewvnode() returns the vnode with a refcount of +1;
127 this routine returns the newly created vnode with this positive refcount.
128 */
129 result = getnewvnode(VT_SYNTHFS, mp, synthfs_vnodeop_p, &vp);
130 if (result != 0) {
131 DBG_VOP(("getnewvnode failed with error code %d\n", result));
132 FREE(nodename, M_TEMP);
133 FREE(sp, M_TEMP);
134 return result;
135 }
136 if (vp == NULL) {
137 DBG_VOP(("getnewvnod returned NULL without an error!\n"));
138 FREE(nodename, M_TEMP);
139 FREE(sp, M_TEMP);
140 return EINVAL;
141 }
142
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;
147
148 /* Initialize all times from a consistent snapshot of the clock: */
149 now = time;
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;
155 sp->s_mode = mode;
156
157 sp->s_vp = vp;
158 vp->v_data = sp;
159
160 vget(vp, LK_EXCLUSIVE, p);
161
162 /* If there's a parent directory, update its subnode structures to insert this new node: */
163 if (dp) {
164 result = synthfs_insertnode(sp, VTOS(dp));
165 };
166
167 *vpp = vp;
168
169 return result;
170 }
171
172
173
174 int synthfs_remove_entry(struct vnode *vp) {
175 struct synthfsnode *sp = VTOS(vp);
176 struct synthfsnode *psp = sp->s_parent;
177 struct timeval now;
178
179 if (psp) {
180 TAILQ_REMOVE(&psp->s_u.d.d_subnodes, sp, s_sibling);
181 --psp->s_u.d.d_entrycount;
182
183 psp->s_nodeflags |= IN_CHANGE | IN_MODIFIED;
184 now = time;
185 VOP_UPDATE(STOV(psp), &now, &now, 0);
186 };
187
188 return 0;
189 }
190
191
192
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);
196 char *new_name_ptr;
197 int result = 0;
198
199 /* Unlink the entry from its current place: */
200 result = synthfs_remove_entry(source_vp);
201 if (result) goto err_exit;
202
203 /* Change the name as necessary: */
204 if (new_name) {
205 FREE(source_sp->s_name, M_TEMP);
206 MALLOC(new_name_ptr, char *, strlen(new_name) + 1, M_TEMP, M_WAITOK);
207 strcpy(new_name_ptr, new_name);
208 source_sp->s_name = new_name_ptr;
209 };
210
211 /* Insert the entry in its new home: */
212 result = synthfs_insertnode(source_sp, parent_sp);
213
214 err_exit:
215 return result;
216 }
217
218
219
220 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) {
221 int result;
222 struct vnode *vp;
223 struct synthfsnode *sp;
224
225 result = synthfs_newnode(mp, dp, name, nodeid, mode, p, &vp);
226 if (result) {
227 return result;
228 };
229 sp = VTOS(vp);
230 sp->s_linkcount = 2;
231
232 /* Initialize the relevant vnode fields: */
233 vp->v_type = VDIR;
234 if (dp) {
235 ++VTOS(dp)->s_linkcount; /* Account for the [fictitious] ".." link */
236 };
237
238 /* Set up the directory-specific fields: */
239 sp->s_type = SYNTHFS_DIRECTORY;
240 sp->s_u.d.d_entrycount = 0; /* No entries in this directory yet */
241 TAILQ_INIT(&sp->s_u.d.d_subnodes); /* No subnodes of this directory yet */
242
243 *vpp = vp;
244
245 return 0;
246 }
247
248
249
250 int synthfs_remove_directory(struct vnode *vp) {
251 struct synthfsnode *sp = VTOS(vp);
252 struct synthfsnode *psp = sp->s_parent;
253
254 if (psp && (sp->s_type == SYNTHFS_DIRECTORY) && (psp != sp)) {
255 --psp->s_linkcount; /* account for the [fictitious] ".." link now removed */
256 };
257
258 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
259 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
260 }
261
262
263
264 int synthfs_new_symlink(
265 struct mount *mp,
266 struct vnode *dp,
267 const char *name,
268 unsigned long nodeid,
269 char *targetstring,
270 struct proc *p,
271 struct vnode **vpp) {
272
273 int result;
274 struct vnode *vp;
275 struct synthfsnode *sp;
276
277 result = synthfs_newnode(mp, dp, name, nodeid, 0, p, &vp);
278 if (result) {
279 return result;
280 };
281 sp = VTOS(vp);
282 sp->s_linkcount = 1;
283
284 /* Initialize the relevant vnode fields: */
285 vp->v_type = VLNK;
286
287 /* Set up the symlink-specific fields: */
288 sp->s_type = SYNTHFS_SYMLINK;
289 sp->s_u.s.s_length = strlen(targetstring);
290 MALLOC(sp->s_u.s.s_symlinktarget, char *, sp->s_u.s.s_length + 1, M_TEMP, M_WAITOK);
291 strcpy(sp->s_u.s.s_symlinktarget, targetstring);
292
293 *vpp = vp;
294
295 return 0;
296 }
297
298
299
300 int synthfs_remove_symlink(struct vnode *vp) {
301 struct synthfsnode *sp = VTOS(vp);
302
303 FREE(sp->s_u.s.s_symlinktarget, M_TEMP);
304
305 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
306 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
307 }
308
309
310
311
312
313
314 long synthfs_adddirentry(u_int32_t fileno, u_int8_t type, const char *name, struct uio *uio) {
315 struct synthfs_direntry_head direntry;
316 long namelength;
317 int padding;
318 long padtext = 0;
319 unsigned short direntrylength;
320
321 namelength = ((name == NULL) ? 0 : strlen(name) + 1);
322 padding = (4 - (namelength & 3)) & 3;
323 direntrylength = sizeof(struct synthfs_direntry_head) + namelength + padding;
324
325 direntry.d_fileno = fileno;
326 direntry.d_reclen = direntrylength;
327 direntry.d_type = type;
328 direntry.d_namlen = namelength;
329
330 if (uio->uio_resid < direntry.d_reclen) {
331 direntrylength = 0;
332 } else {
333 uiomove((caddr_t)(&direntry), sizeof(direntry), uio);
334 if (name != NULL) {
335 uiomove((caddr_t)name, namelength, uio);
336 };
337 if (padding > 0) {
338 uiomove((caddr_t)&padtext, padding, uio);
339 };
340 };
341
342 return direntrylength;
343 }
344
345