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