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