]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/synthfs/synthfs_util.c
xnu-517.12.7.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 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1998, Apple Computer, Inc. All rights reserved. */
23 /*
24 * Change History:
25 *
26 * 17-Aug-1999 Pat Dirks New today.
27 *
28 */
29
30 #include <mach/mach_types.h>
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/file.h>
36 #include <sys/stat.h>
37 #include <sys/buf.h>
38 #include <sys/proc.h>
39 #include <sys/conf.h>
40 #include <sys/mount.h>
41 #include <sys/vnode.h>
42 #include <sys/malloc.h>
43 #include <sys/dirent.h>
44 #include <sys/namei.h>
45 #include <sys/attr.h>
46 #include <sys/time.h>
47
48 #include <sys/vm.h>
49 #include <sys/errno.h>
50 #include <vfs/vfs_support.h>
51
52 #include "synthfs.h"
53
54 struct synthfs_direntry_head {
55 u_int32_t d_fileno; /* file number of entry */
56 u_int16_t d_reclen; /* length of this record */
57 u_int8_t d_type; /* file type, see below */
58 u_int8_t d_namlen; /* length of string in d_name */
59 };
60
61
62 #define PATHSEPARATOR '/'
63 #define ROOTDIRID 2
64
65 void synthfs_setupuio(struct iovec *iov,
66 struct uio *uio,
67 void *buffer,
68 size_t bufsize,
69 enum uio_seg space,
70 enum uio_rw direction,
71 struct proc *p) {
72 iov->iov_base = (char *)buffer;
73 iov->iov_len = bufsize;
74
75 uio->uio_iov = iov;
76 uio->uio_iovcnt = 1;
77 uio->uio_offset = 0;
78 uio->uio_resid = bufsize;
79 uio->uio_segflg = space;
80 uio->uio_rw = direction;
81 uio->uio_procp = p;
82 }
83
84
85 static int synthfs_insertnode(struct synthfsnode *newnode_sp, struct synthfsnode *parent_sp) {
86 struct timeval now;
87
88 DBG_ASSERT(parent_sp->s_type == SYNTHFS_DIRECTORY);
89
90 TAILQ_INSERT_TAIL(&parent_sp->s_u.d.d_subnodes, newnode_sp, s_sibling);
91 ++parent_sp->s_u.d.d_entrycount;
92 newnode_sp->s_parent = parent_sp;
93
94 parent_sp->s_nodeflags |= IN_CHANGE | IN_MODIFIED;
95 now = time;
96 VOP_UPDATE(STOV(parent_sp), &now, &now, 0);
97
98 return 0;
99 }
100
101
102
103 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) {
104 int result;
105 struct synthfsnode *sp;
106 struct vnode *vp;
107 struct timeval now;
108 char *nodename;
109
110 /* Allocate the synthfsnode now to avoid blocking between the call
111 to getnewvnode(), below, and the initialization of v_data: */
112 MALLOC(sp, struct synthfsnode *, sizeof(struct synthfsnode), M_SYNTHFS, M_WAITOK);
113
114 if (name == NULL) {
115 MALLOC(nodename, char *, 1, M_TEMP, M_WAITOK);
116 nodename[0] = 0;
117 } else {
118 MALLOC(nodename, char *, strlen(name) + 1, M_TEMP, M_WAITOK);
119 strcpy(nodename, name);
120 };
121
122 /*
123 Note that getnewvnode() returns the vnode with a refcount of +1;
124 this routine returns the newly created vnode with this positive refcount.
125 */
126 result = getnewvnode(VT_SYNTHFS, mp, synthfs_vnodeop_p, &vp);
127 if (result != 0) {
128 DBG_VOP(("getnewvnode failed with error code %d\n", result));
129 FREE(nodename, M_TEMP);
130 FREE(sp, M_TEMP);
131 return result;
132 }
133 if (vp == NULL) {
134 DBG_VOP(("getnewvnod returned NULL without an error!\n"));
135 FREE(nodename, M_TEMP);
136 FREE(sp, M_TEMP);
137 return EINVAL;
138 }
139
140 /* Initialize the relevant synthfsnode fields: */
141 bzero(sp, sizeof(*sp));
142 lockinit(&sp->s_lock, PINOD, "synthfsnode", 0, 0);
143 sp->s_nodeid = nodeid;
144
145 /* Initialize all times from a consistent snapshot of the clock: */
146 now = time;
147 sp->s_createtime = now;
148 sp->s_accesstime = now;
149 sp->s_modificationtime = now;
150 sp->s_changetime = now;
151 sp->s_name = nodename;
152 sp->s_mode = mode;
153
154 sp->s_vp = vp;
155 vp->v_data = sp;
156
157 vget(vp, LK_EXCLUSIVE, p);
158
159 /* If there's a parent directory, update its subnode structures to insert this new node: */
160 if (dp) {
161 result = synthfs_insertnode(sp, VTOS(dp));
162 };
163
164 *vpp = vp;
165
166 return result;
167 }
168
169
170
171 int synthfs_remove_entry(struct vnode *vp) {
172 struct synthfsnode *sp = VTOS(vp);
173 struct synthfsnode *psp = sp->s_parent;
174 struct timeval now;
175
176 if (psp) {
177 TAILQ_REMOVE(&psp->s_u.d.d_subnodes, sp, s_sibling);
178 --psp->s_u.d.d_entrycount;
179
180 psp->s_nodeflags |= IN_CHANGE | IN_MODIFIED;
181 now = time;
182 VOP_UPDATE(STOV(psp), &now, &now, 0);
183 };
184
185 return 0;
186 }
187
188
189
190 int synthfs_move_rename_entry(struct vnode *source_vp, struct vnode *newparent_vp, char *new_name) {
191 struct synthfsnode *source_sp = VTOS(source_vp);
192 struct synthfsnode *parent_sp = VTOS(newparent_vp);
193 char *new_name_ptr;
194 int result = 0;
195
196 /* Unlink the entry from its current place: */
197 result = synthfs_remove_entry(source_vp);
198 if (result) goto err_exit;
199
200 /* Change the name as necessary: */
201 if (new_name) {
202 FREE(source_sp->s_name, M_TEMP);
203 MALLOC(new_name_ptr, char *, strlen(new_name) + 1, M_TEMP, M_WAITOK);
204 strcpy(new_name_ptr, new_name);
205 source_sp->s_name = new_name_ptr;
206 };
207
208 /* Insert the entry in its new home: */
209 result = synthfs_insertnode(source_sp, parent_sp);
210
211 err_exit:
212 return result;
213 }
214
215
216
217 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) {
218 int result;
219 struct vnode *vp;
220 struct synthfsnode *sp;
221
222 result = synthfs_newnode(mp, dp, name, nodeid, mode, p, &vp);
223 if (result) {
224 return result;
225 };
226 sp = VTOS(vp);
227 sp->s_linkcount = 2;
228
229 /* Initialize the relevant vnode fields: */
230 vp->v_type = VDIR;
231 if (dp) {
232 ++VTOS(dp)->s_linkcount; /* Account for the [fictitious] ".." link */
233 };
234
235 /* Set up the directory-specific fields: */
236 sp->s_type = SYNTHFS_DIRECTORY;
237 sp->s_u.d.d_entrycount = 0; /* No entries in this directory yet */
238 TAILQ_INIT(&sp->s_u.d.d_subnodes); /* No subnodes of this directory yet */
239
240 *vpp = vp;
241
242 return 0;
243 }
244
245
246
247 int synthfs_remove_directory(struct vnode *vp) {
248 struct synthfsnode *sp = VTOS(vp);
249 struct synthfsnode *psp = sp->s_parent;
250
251 if (psp && (sp->s_type == SYNTHFS_DIRECTORY) && (psp != sp)) {
252 --psp->s_linkcount; /* account for the [fictitious] ".." link now removed */
253 };
254
255 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
256 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
257 }
258
259
260
261 int synthfs_new_symlink(
262 struct mount *mp,
263 struct vnode *dp,
264 const char *name,
265 unsigned long nodeid,
266 char *targetstring,
267 struct proc *p,
268 struct vnode **vpp) {
269
270 int result;
271 struct vnode *vp;
272 struct synthfsnode *sp;
273
274 result = synthfs_newnode(mp, dp, name, nodeid, 0, p, &vp);
275 if (result) {
276 return result;
277 };
278 sp = VTOS(vp);
279 sp->s_linkcount = 1;
280
281 /* Initialize the relevant vnode fields: */
282 vp->v_type = VLNK;
283
284 /* Set up the symlink-specific fields: */
285 sp->s_type = SYNTHFS_SYMLINK;
286 sp->s_u.s.s_length = strlen(targetstring);
287 MALLOC(sp->s_u.s.s_symlinktarget, char *, sp->s_u.s.s_length + 1, M_TEMP, M_WAITOK);
288 strcpy(sp->s_u.s.s_symlinktarget, targetstring);
289
290 *vpp = vp;
291
292 return 0;
293 }
294
295
296
297 int synthfs_remove_symlink(struct vnode *vp) {
298 struct synthfsnode *sp = VTOS(vp);
299
300 FREE(sp->s_u.s.s_symlinktarget, M_TEMP);
301
302 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
303 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
304 }
305
306
307
308
309
310
311 long synthfs_adddirentry(u_int32_t fileno, u_int8_t type, const char *name, struct uio *uio) {
312 struct synthfs_direntry_head direntry;
313 long namelength;
314 int padding;
315 long padtext = 0;
316 unsigned short direntrylength;
317
318 namelength = ((name == NULL) ? 0 : strlen(name) + 1);
319 padding = (4 - (namelength & 3)) & 3;
320 direntrylength = sizeof(struct synthfs_direntry_head) + namelength + padding;
321
322 direntry.d_fileno = fileno;
323 direntry.d_reclen = direntrylength;
324 direntry.d_type = type;
325 direntry.d_namlen = namelength;
326
327 if (uio->uio_resid < direntry.d_reclen) {
328 direntrylength = 0;
329 } else {
330 uiomove((caddr_t)(&direntry), sizeof(direntry), uio);
331 if (name != NULL) {
332 uiomove((caddr_t)name, namelength, uio);
333 };
334 if (padding > 0) {
335 uiomove((caddr_t)&padtext, padding, uio);
336 };
337 };
338
339 return direntrylength;
340 }
341
342