]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
ff6e181a A |
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. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
1c79356b | 12 | * |
ff6e181a A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
ff6e181a A |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
1c79356b A |
20 | * |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */ | |
24 | /* | |
25 | * Change History: | |
26 | * | |
27 | * 17-Aug-1999 Pat Dirks New today. | |
28 | * | |
29 | */ | |
30 | ||
31 | #include <sys/param.h> | |
32 | #include <sys/systm.h> | |
33 | #include <sys/namei.h> | |
34 | #include <sys/filedesc.h> | |
91447636 | 35 | #include <sys/proc_internal.h> |
1c79356b A |
36 | #include <sys/kernel.h> |
37 | #include <mach/machine/vm_types.h> | |
91447636 | 38 | #include <sys/vnode_internal.h> |
1c79356b | 39 | #include <sys/socket.h> |
91447636 | 40 | #include <sys/mount_internal.h> |
1c79356b A |
41 | #include <sys/mbuf.h> |
42 | #include <sys/file.h> | |
55e303ae | 43 | #include <sys/disk.h> |
1c79356b A |
44 | #include <sys/ioctl.h> |
45 | #include <sys/errno.h> | |
46 | #include <sys/malloc.h> | |
47 | #include <sys/attr.h> | |
91447636 | 48 | #include <sys/uio_internal.h> |
1c79356b A |
49 | |
50 | #include <miscfs/specfs/specdev.h> | |
51 | ||
52 | #include "synthfs.h" | |
53 | ||
54 | #define LOADABLE_FS 0 | |
55 | ||
56 | typedef int (*PFI)(); | |
57 | ||
58 | struct vfsops synthfs_vfsops = { | |
59 | synthfs_mount, | |
60 | synthfs_start, | |
61 | synthfs_unmount, | |
62 | synthfs_root, | |
91447636 A |
63 | NULL, /* quotactl */ |
64 | synthfs_vfs_getattr, | |
1c79356b A |
65 | synthfs_sync, |
66 | synthfs_vget, | |
67 | synthfs_fhtovp, | |
68 | synthfs_vptofh, | |
69 | synthfs_init, | |
70 | synthfs_sysctl | |
71 | }; | |
72 | ||
73 | #define ROOTMPMODE 0755 | |
74 | #define ROOTPLACEHOLDERMODE 0700 | |
91447636 | 75 | static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs"; |
1c79356b A |
76 | static char synthfs_fake_mntfromname[] = "<synthfs>"; |
77 | ||
78 | ||
79 | extern struct vnodeopv_desc synthfs_vnodeop_opv_desc; | |
80 | ||
81 | /* The following refer to kernel global variables used in the loading/initialization: */ | |
82 | extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */ | |
83 | extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */ | |
84 | extern int vfs_opv_numops; /* The total number of defined vnode operations */ | |
85 | ||
86 | int vn_mkdir(struct proc *p, char *path, int mode); | |
87 | int vn_symlink(struct proc *p, char *path, char *link); | |
88 | ||
89 | ||
90 | ||
91 | ||
92 | #if LOADABLE_FS | |
93 | void | |
94 | synthfs_load(int loadArgument) { | |
91447636 | 95 | /* Should use vfs_fsadd kpi */ |
1c79356b A |
96 | } |
97 | ||
98 | ||
99 | ||
100 | int synthfs_unload(void) { | |
1c79356b | 101 | |
91447636 | 102 | /* should use fs_fsremove kpi */ |
1c79356b A |
103 | return 0; |
104 | } | |
105 | #endif | |
106 | ||
107 | ||
108 | ||
109 | /* | |
110 | * VFS Operations. | |
111 | * | |
112 | * mount system call | |
113 | */ | |
114 | int | |
91447636 | 115 | synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data, struct proc *p) |
1c79356b A |
116 | { |
117 | struct synthfs_mntdata *priv_mnt_data; | |
118 | int error; | |
119 | size_t size; | |
120 | ||
121 | DBG_VOP(("synthfs_mount_fs called.\n")); | |
122 | MALLOC(priv_mnt_data, struct synthfs_mntdata *, sizeof(struct synthfs_mntdata), M_SYNTHFS, M_WAITOK); | |
123 | DBG_VOP(("MALLOC succeeded...\n")); | |
124 | ||
91447636 A |
125 | strncpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename)); |
126 | strncpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname)); | |
1c79356b A |
127 | priv_mnt_data->synthfs_mounteddev = (dev_t)0; |
128 | priv_mnt_data->synthfs_nextid = FIRST_SYNTHFS_ID; | |
129 | priv_mnt_data->synthfs_filecount = 0; | |
130 | priv_mnt_data->synthfs_dircount = 0; | |
131 | priv_mnt_data->synthfs_encodingsused = 0x00000001; | |
132 | ||
133 | /* | |
134 | Set up the root vnode for fast reference in the future. | |
135 | Note that synthfs_new_directory() returns the vnode with a refcount of +2. | |
136 | The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount. | |
137 | */ | |
138 | error = synthfs_new_directory(mp, NULL, "", ROOT_DIRID, (S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH), p, &priv_mnt_data->synthfs_rootvp); | |
139 | if (error) { | |
140 | DBG_VOP(("Attempt to create root directory failed with error %d.\n", error)); | |
141 | return error; | |
142 | }; | |
143 | priv_mnt_data->synthfs_rootvp->v_flag |= VROOT; | |
144 | ||
145 | priv_mnt_data->synthfs_mp = mp; | |
146 | mp->mnt_data = (void *)priv_mnt_data; | |
147 | ||
148 | /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent | |
149 | the vnode from beeing freed: */ | |
91447636 | 150 | vnode_put(priv_mnt_data->synthfs_rootvp); |
1c79356b A |
151 | |
152 | return (0); | |
153 | } | |
154 | ||
155 | ||
156 | ||
157 | int | |
91447636 | 158 | synthfs_mount(mp, devvp, data, context) |
1c79356b | 159 | register struct mount *mp; |
91447636 A |
160 | vnode_t devvp; |
161 | user_addr_t data; | |
162 | vfs_context_t context; | |
1c79356b A |
163 | { |
164 | size_t size; | |
165 | ||
91447636 | 166 | return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context))); |
1c79356b A |
167 | } |
168 | ||
169 | ||
170 | ||
171 | ||
172 | ||
173 | ||
174 | /* | |
175 | * Initialize the filesystem | |
176 | */ | |
177 | int | |
178 | synthfs_init(vfsp) | |
179 | struct vfsconf *vfsp; | |
180 | { | |
181 | DBG_VOP(("synthfs_init called.\n")); | |
182 | return 0; | |
183 | } | |
184 | ||
185 | int | |
91447636 | 186 | synthfs_start(mp, flags, context) |
1c79356b A |
187 | struct mount * mp; |
188 | int flags; | |
91447636 | 189 | vfs_context_t context; |
1c79356b A |
190 | { |
191 | DBG_VOP(("synthfs_start called.\n")); | |
192 | return 0; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Return the root of a filesystem. | |
197 | */ | |
198 | int | |
91447636 | 199 | synthfs_root(mp, vpp, context) |
1c79356b A |
200 | struct mount *mp; |
201 | struct vnode **vpp; | |
91447636 | 202 | vfs_context_t context; |
1c79356b A |
203 | { |
204 | unsigned long root_nodeid = ROOT_DIRID; | |
205 | ||
206 | DBG_VOP(("synthfs_root called.\n")); | |
207 | ||
208 | *vpp = VFSTOSFS(mp)->synthfs_rootvp; | |
91447636 | 209 | return vnode_get(VFSTOSFS(mp)->synthfs_rootvp); |
1c79356b A |
210 | } |
211 | ||
212 | /* | |
213 | * unmount system call | |
214 | */ | |
215 | int | |
91447636 | 216 | synthfs_unmount(mp, mntflags, context) |
1c79356b A |
217 | struct mount *mp; |
218 | int mntflags; | |
91447636 | 219 | vfs_context_t context; |
1c79356b A |
220 | { |
221 | struct synthfs_mntdata *synth; | |
222 | struct vnode *root_vp; | |
223 | int retval; | |
224 | ||
225 | DBG_VOP(("synthfs_unmount called.\n")); | |
226 | synth = (struct synthfs_mntdata *)mp->mnt_data; | |
227 | ||
228 | root_vp = synth->synthfs_rootvp; | |
229 | retval = vflush(mp, root_vp, (mntflags & MNT_FORCE) ? FORCECLOSE : 0); | |
230 | if (retval && ((mntflags & MNT_FORCE) == 0)) goto Err_Exit; | |
231 | ||
232 | /* Free the root vnode. | |
1c79356b A |
233 | the ref. count has been maintained at +1 ever since mount time. */ |
234 | if (root_vp) { | |
1c79356b A |
235 | if ((mntflags & MNT_FORCE) == 0) { |
236 | if (retval) goto Err_Exit; | |
237 | ||
238 | if (root_vp->v_usecount > 1) { | |
239 | DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, synth->synthfs_rootvp->v_usecount)); | |
1c79356b A |
240 | retval = EBUSY; |
241 | goto Err_Exit; | |
242 | }; | |
243 | }; | |
244 | ||
245 | synth->synthfs_rootvp = NULL; | |
246 | ||
247 | if (retval == 0) { | |
91447636 A |
248 | vnode_get(root_vp); |
249 | vnode_rele(root_vp); | |
250 | vnode_recycle(root_vp); | |
251 | vnode_put(root_vp); /* This drops synthfs's own refcount */ | |
1c79356b A |
252 | }; |
253 | }; | |
254 | ||
255 | /* All vnodes should be gone, and no errors, clean up the last */ | |
256 | ||
257 | mp->mnt_data = NULL; | |
258 | FREE(synth, M_SYNTHFS); | |
259 | ||
260 | Err_Exit: | |
261 | ||
262 | if (mntflags & MNT_FORCE) retval = 0; | |
263 | ||
264 | return(retval); | |
265 | } | |
266 | ||
267 | /* | |
268 | * Get file system statistics. | |
269 | */ | |
270 | int | |
91447636 | 271 | synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context) |
1c79356b | 272 | { |
91447636 A |
273 | struct synthfs_mntdata *synthfs_mp = VFSTOSFS(mp); |
274 | DBG_VOP(("synthfs_vfs_getattr called.\n")); | |
275 | ||
276 | VFSATTR_RETURN(fsap, f_bsize, 512); | |
277 | VFSATTR_RETURN(fsap, f_iosize, 512); | |
278 | VFSATTR_RETURN(fsap, f_blocks, 1024); | |
279 | VFSATTR_RETURN(fsap, f_bfree, 0); | |
280 | VFSATTR_RETURN(fsap, f_bavail, 0); | |
281 | VFSATTR_RETURN(fsap, f_bused, 1024); | |
282 | VFSATTR_RETURN(fsap, f_files, synthfs_mp->synthfs_filecount + synthfs_mp->synthfs_dircount); | |
283 | VFSATTR_RETURN(fsap, f_ffree, 0); | |
284 | VFSATTR_RETURN(fsap, f_fssubtype, 0); | |
285 | ||
286 | return 0; | |
1c79356b A |
287 | } |
288 | ||
289 | /* | |
290 | * synthfs doesn't have any data or backing store and you can't write into any of the synthfs | |
291 | * structures, so don't do anything | |
292 | */ | |
293 | int | |
91447636 | 294 | synthfs_sync(mp, waitfor, context) |
1c79356b A |
295 | struct mount *mp; |
296 | int waitfor; | |
91447636 | 297 | vfs_context_t context; |
1c79356b A |
298 | { |
299 | // DBG_VOP(("synthfs_sync called\n")); | |
300 | return 0; | |
301 | } | |
302 | /* | |
303 | * Look up a synthfs node by node number. | |
304 | */ | |
305 | int | |
91447636 | 306 | synthfs_vget(mp, ino, vpp, context) |
1c79356b | 307 | struct mount *mp; |
91447636 | 308 | ino64_t ino; |
1c79356b | 309 | struct vnode **vpp; |
91447636 | 310 | vfs_context_t context; |
1c79356b A |
311 | { |
312 | struct vnode *vp; | |
91447636 | 313 | int vid = 0; |
1c79356b A |
314 | |
315 | // DBG_VOP(("synthfs_vget called\n")); | |
316 | ||
317 | /* Check for unmount in progress */ | |
318 | if (mp->mnt_kern_flag & MNTK_UNMOUNT) { | |
319 | *vpp = NULL; | |
320 | return (EPERM); | |
321 | } | |
322 | ||
323 | loop: | |
91447636 A |
324 | TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { |
325 | if (VTOS(vp)->s_nodeid == (unsigned long)ino) { | |
326 | /* | |
327 | * doing a vnode_getwithvid isn't technically | |
328 | * necessary since synthfs is an unsafe filesystem | |
329 | * and we're running behind a funnel at this point | |
330 | * however, vnode_get always succeeds, which isn't | |
331 | * what we want if this vnode is in the process of | |
332 | * being terminated | |
333 | */ | |
334 | vid = vnode_vid(vp); | |
335 | ||
336 | if (vnode_getwithvid(vp, vid) != 0) { | |
337 | goto loop; | |
338 | }; | |
1c79356b A |
339 | *vpp = vp; |
340 | return 0; | |
341 | }; | |
342 | }; | |
343 | *vpp = NULL; | |
344 | return -1; | |
345 | } | |
346 | ||
347 | /* | |
348 | * fast filesystem related variables. | |
349 | */ | |
350 | int | |
91447636 A |
351 | synthfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, |
352 | user_addr_t newp, size_t newlen, vfs_context_t context) | |
1c79356b A |
353 | { |
354 | DBG_VOP(("synthfs_sysctl called.\n")); | |
91447636 | 355 | return (ENOTSUP); |
1c79356b A |
356 | } |
357 | ||
358 | /* | |
359 | * File handle to vnode | |
360 | * | |
361 | */ | |
362 | int | |
91447636 | 363 | synthfs_fhtovp(mp, fhlen, fhp, vpp, context) |
1c79356b | 364 | register struct mount *mp; |
91447636 A |
365 | int fhlen; |
366 | unsigned char *fhp; | |
1c79356b | 367 | struct vnode **vpp; |
91447636 | 368 | vfs_context_t context; |
1c79356b A |
369 | { |
370 | DBG_VOP(("synthfs_fhtovp called.\n")); | |
91447636 | 371 | return ENOTSUP; |
1c79356b A |
372 | } |
373 | ||
374 | /* | |
375 | * Vnode pointer to File handle | |
376 | */ | |
377 | /* ARGSUSED */ | |
378 | int | |
91447636 | 379 | synthfs_vptofh(vp, fhlenp, fhp, context) |
1c79356b | 380 | struct vnode *vp; |
91447636 A |
381 | int *fhlenp; |
382 | unsigned char *fhp; | |
383 | vfs_context_t context; | |
1c79356b A |
384 | { |
385 | DBG_VOP(("synthfs_vptofh called.\n")); | |
91447636 | 386 | return ENOTSUP; |
1c79356b A |
387 | } |
388 | ||
389 | ||
390 | ||
391 | ||
392 | ||
393 | ||
394 | int | |
91447636 A |
395 | vn_mkdir(struct proc *p, char *path, int mode) |
396 | { | |
1c79356b A |
397 | struct nameidata nd; |
398 | struct vnode *vp; | |
91447636 A |
399 | struct vnode_attr va; |
400 | struct vfs_context context; | |
1c79356b A |
401 | int error; |
402 | ||
91447636 A |
403 | context.vc_proc = p; |
404 | context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */ | |
405 | ||
406 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), &context); | |
407 | error = namei(&nd); | |
408 | if (error) { | |
1c79356b A |
409 | DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error)); |
410 | return (error); | |
411 | }; | |
412 | vp = nd.ni_vp; | |
91447636 A |
413 | |
414 | if (vp == NULL) { | |
415 | VATTR_INIT(&va); | |
416 | VATTR_SET(&va, va_type, VDIR); | |
417 | VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask); | |
418 | ||
419 | error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, &context); | |
420 | if (error) | |
421 | DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error)); | |
422 | } else { | |
1c79356b | 423 | DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n")); |
91447636 | 424 | error = EEXIST; |
1c79356b | 425 | } |
91447636 A |
426 | vnode_put(nd.ni_dvp); |
427 | if (nd.ni_vp) | |
428 | vnode_put(nd.ni_vp); | |
429 | nameidone(&nd); | |
430 | ||
1c79356b A |
431 | return (error); |
432 | } | |
433 | ||
434 | ||
435 | ||
436 | int | |
437 | vn_symlink(struct proc *p, char *path, char *link) { | |
438 | struct nameidata nd; | |
91447636 A |
439 | struct vnode_attr va; |
440 | struct vfs_context context; | |
1c79356b A |
441 | int error; |
442 | ||
91447636 A |
443 | context.vc_proc = p; |
444 | context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */ | |
445 | ||
446 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), &context); | |
447 | if ((error = namei(&nd))) return error; | |
448 | ||
449 | if (nd.ni_vp == NULL) { | |
450 | VATTR_INIT(&va); | |
451 | VATTR_SET(&va, va_type, VLNK); | |
452 | VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask); | |
453 | ||
454 | error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, &context); | |
455 | } else | |
456 | error = EEXIST; | |
457 | ||
458 | vnode_put(nd.ni_dvp); | |
459 | if (nd.ni_vp) | |
460 | vnode_put(nd.ni_vp); | |
461 | nameidone(&nd); | |
462 | ||
463 | return (error); | |
1c79356b A |
464 | } |
465 | ||
466 |