]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/synthfs/synthfs_util.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_util.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
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
54struct 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
65void 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
85static 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
103static 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
171int 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
190int 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;
195
196 if (parent_sp == source_sp->s_parent) return 0;
197
198 /* Unlink the entry from its current place: */
199 result = synthfs_remove_entry(source_vp);
200 if (result) return result;
201
202 /* Change the name as necessary: */
203 FREE(source_sp->s_name, M_TEMP);
204 if (new_name == NULL) {
205 MALLOC(new_name_ptr, char *, 1, M_TEMP, M_WAITOK);
206 new_name_ptr[0] = 0;
207 } else {
208 MALLOC(new_name_ptr, char *, strlen(new_name) + 1, M_TEMP, M_WAITOK);
209 strcpy(new_name_ptr, new_name);
210 };
211 source_sp->s_name = new_name_ptr;
212
213 /* Insert the entry in its new home: */
214 return synthfs_insertnode(source_sp, parent_sp);
215}
216
217
218
219int synthfs_new_directory(struct mount *mp, struct vnode *dp, const char *name, unsigned long nodeid, mode_t mode, struct proc *p, struct vnode **vpp) {
220 int result;
221 struct vnode *vp;
222 struct synthfsnode *sp;
223
224 result = synthfs_newnode(mp, dp, name, nodeid, mode, p, &vp);
225 if (result) {
226 return result;
227 };
228 sp = VTOS(vp);
229 sp->s_linkcount = 2;
230
231 /* Initialize the relevant vnode fields: */
232 vp->v_type = VDIR;
233 if (dp) {
234 ++VTOS(dp)->s_linkcount; /* Account for the [fictitious] ".." link */
235 };
236
237 /* Set up the directory-specific fields: */
238 sp->s_type = SYNTHFS_DIRECTORY;
239 sp->s_u.d.d_entrycount = 0; /* No entries in this directory yet */
240 TAILQ_INIT(&sp->s_u.d.d_subnodes); /* No subnodes of this directory yet */
241
242 *vpp = vp;
243
244 return 0;
245}
246
247
248
249int synthfs_remove_directory(struct vnode *vp) {
250 struct synthfsnode *sp = VTOS(vp);
251 struct synthfsnode *psp = sp->s_parent;
252
253 if (psp && (sp->s_type == SYNTHFS_DIRECTORY) && (psp != sp)) {
254 --psp->s_linkcount; /* account for the [fictitious] ".." link now removed */
255 };
256
257 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
258 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
259}
260
261
262
263int synthfs_new_symlink(
264 struct mount *mp,
265 struct vnode *dp,
266 const char *name,
267 unsigned long nodeid,
268 char *targetstring,
269 struct proc *p,
270 struct vnode **vpp) {
271
272 int result;
273 struct vnode *vp;
274 struct synthfsnode *sp;
275
276 result = synthfs_newnode(mp, dp, name, nodeid, 0, p, &vp);
277 if (result) {
278 return result;
279 };
280 sp = VTOS(vp);
281 sp->s_linkcount = 1;
282
283 /* Initialize the relevant vnode fields: */
284 vp->v_type = VLNK;
285
286 /* Set up the symlink-specific fields: */
287 sp->s_type = SYNTHFS_SYMLINK;
288 sp->s_u.s.s_length = strlen(targetstring);
289 MALLOC(sp->s_u.s.s_symlinktarget, char *, sp->s_u.s.s_length + 1, M_TEMP, M_WAITOK);
290 strcpy(sp->s_u.s.s_symlinktarget, targetstring);
291
292 *vpp = vp;
293
294 return 0;
295}
296
297
298
299int synthfs_remove_symlink(struct vnode *vp) {
300 struct synthfsnode *sp = VTOS(vp);
301
302 FREE(sp->s_u.s.s_symlinktarget, M_TEMP);
303
304 /* Do the standard cleanup involved in pruning an entry from the filesystem: */
305 return synthfs_remove_entry(vp); /* Do whatever standard cleanup is required */
306}
307
308
309
310
311
312
313long synthfs_adddirentry(u_int32_t fileno, u_int8_t type, const char *name, struct uio *uio) {
314 struct synthfs_direntry_head direntry;
315 long namelength;
316 int padding;
317 long padtext = 0;
318 unsigned short direntrylength;
319
320 namelength = ((name == NULL) ? 0 : strlen(name));
321 padding = (4 - (namelength & 3)) & 3;
322 direntrylength = sizeof(struct synthfs_direntry_head) + namelength + padding;
323
324 direntry.d_fileno = fileno;
325 direntry.d_reclen = direntrylength;
326 direntry.d_type = type;
327 direntry.d_namlen = namelength;
328
329 if (uio->uio_resid < direntry.d_reclen) {
330 direntrylength = 0;
331 } else {
332 uiomove((caddr_t)(&direntry), sizeof(direntry), uio);
333 if (name != NULL) {
334 uiomove((caddr_t)name, namelength, uio);
335 };
336 if (padding > 0) {
337 uiomove((caddr_t)&padtext, padding, uio);
338 };
339 };
340
341 return direntrylength;
342}
343
344