1/*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
40#include <sys/proc_internal.h>
41#include <sys/kernel.h>
42#include <mach/machine/vm_types.h>
43#include <sys/vnode_internal.h>
44#include <sys/socket.h>
45#include <sys/mount_internal.h>
46#include <sys/mbuf.h>
47#include <sys/file.h>
48#include <sys/disk.h>
49#include <sys/ioctl.h>
50#include <sys/errno.h>
51#include <sys/malloc.h>
52#include <sys/attr.h>
53#include <sys/uio_internal.h>
54
55#include <miscfs/specfs/specdev.h>
56
57#include "synthfs.h"
58
59#define LOADABLE_FS 0
60
61typedef int (*PFI)();
62
63struct vfsops synthfs_vfsops = {
64	synthfs_mount,
65	synthfs_start,
66	synthfs_unmount,
67	synthfs_root,
68	NULL,				/* quotactl */
69	synthfs_vfs_getattr,
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
80static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs";
81static char synthfs_fake_mntfromname[] = "<synthfs>";
82
83
84extern struct vnodeopv_desc synthfs_vnodeop_opv_desc;
85
86/* The following refer to kernel global variables used in the loading/initialization: */
87extern int maxvfsslots;				/* Total number of slots in the system's vfsconf table */
88extern int maxvfsconf;				/* The highest fs type number [old-style ID] in use [dispite its name] */
89extern int vfs_opv_numops;			/* The total number of defined vnode operations */
90
91int vn_mkdir(struct proc *p, char *path, int mode);
92int vn_symlink(struct proc *p, char *path, char *link);
93
94
95
96
97#if LOADABLE_FS
98void
99synthfs_load(int loadArgument) {
100	/* Should use vfs_fsadd kpi */
101}
102
103
104
105int synthfs_unload(void) {
106
107	/* should use fs_fsremove kpi */
108    return 0;
109}
110#endif
111
112
113
114/*
115 * VFS Operations.
116 *
117 * mount system call
118 */
119int
120synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data,  struct proc *p)
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
130	strlcpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename));
131	strlcpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname));
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: */
155    vnode_put(priv_mnt_data->synthfs_rootvp);
156
157    return (0);
158}
159
160
161
162int
163synthfs_mount(mp, devvp, data, context)
164	register struct mount *mp;
165	vnode_t devvp;
166	user_addr_t data;
167	vfs_context_t context;
168{
169	size_t size;
170
171	return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context)));
172}
173
174
175
176
177
178
179/*
180 * Initialize the filesystem
181 */
182int
183synthfs_init(vfsp)
184	struct vfsconf *vfsp;
185{
186	DBG_VOP(("synthfs_init called.\n"));
187	return 0;
188}
189
190int
191synthfs_start(mp, flags, context)
192struct mount * mp;
193int	flags;
194vfs_context_t context;
195{
196    DBG_VOP(("synthfs_start called.\n"));
197    return 0;
198}
199
200/*
201 * Return the root of a filesystem.
202 */
203int
204synthfs_root(mp, vpp, context)
205        struct mount *mp;
206        struct vnode **vpp;
207        vfs_context_t context;
208{
209    unsigned long root_nodeid = ROOT_DIRID;
210
211    DBG_VOP(("synthfs_root called.\n"));
212
213	*vpp = VFSTOSFS(mp)->synthfs_rootvp;
214	return vnode_get(VFSTOSFS(mp)->synthfs_rootvp);
215}
216
217/*
218 * unmount system call
219 */
220int
221synthfs_unmount(mp, mntflags, context)
222	struct mount *mp;
223	int mntflags;
224	vfs_context_t context;
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.
238       the ref. count has been maintained at +1 ever since mount time. */
239    if (root_vp) {
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));
245	            retval = EBUSY;
246	            goto Err_Exit;
247	        };
248        };
249
250        synth->synthfs_rootvp = NULL;
251
252        if (retval == 0) {
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 */
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
265Err_Exit:
266
267	if (mntflags & MNT_FORCE) retval = 0;
268
269    return(retval);
270}
271
272/*
273 * Get file system statistics.
274 */
275int
276synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
277{
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;
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 */
298int
299synthfs_sync(mp, waitfor, context)
300	struct mount *mp;
301	int waitfor;
302	vfs_context_t context;
303{
304//	DBG_VOP(("synthfs_sync called\n"));
305	return 0;
306}
307/*
308 * Look up a synthfs node by node number.
309 */
310int
311synthfs_vget(mp, ino, vpp, context)
312	struct mount *mp;
313	ino64_t ino;
314	struct vnode **vpp;
315	vfs_context_t context;
316{
317	struct vnode *vp;
318	int	vid = 0;
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
328loop:
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			};
344			*vpp = vp;
345			return 0;
346		};
347	};
348	*vpp = NULL;
349	return -1;
350}
351
352/*
353 * fast filesystem related variables.
354 */
355int
356synthfs_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)
358{
359	DBG_VOP(("synthfs_sysctl called.\n"));
360	return (ENOTSUP);
361}
362
363/*
364 * File handle to vnode
365 *
366 */
367int
368synthfs_fhtovp(mp, fhlen, fhp, vpp, context)
369	register struct mount *mp;
370	int fhlen;
371	unsigned char *fhp;
372	struct vnode **vpp;
373	vfs_context_t context;
374{
375	DBG_VOP(("synthfs_fhtovp called.\n"));
376    return ENOTSUP;
377}
378
379/*
380 * Vnode pointer to File handle
381 */
382/* ARGSUSED */
383int
384synthfs_vptofh(vp, fhlenp, fhp, context)
385	struct vnode *vp;
386	int *fhlenp;
387	unsigned char *fhp;
388	vfs_context_t context;
389{
390	DBG_VOP(("synthfs_vptofh called.\n"));
391    return ENOTSUP;
392}
393
394
395
396
397
398
399int
400vn_mkdir(struct proc *p, char *path, int mode)
401{
402	struct nameidata nd;
403	struct vnode *vp;
404	struct vnode_attr va;
405	vfs_context_t ctx = vfs_context_kernel();
406	int error;
407
408
409	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), ctx);
410	error = namei(&nd);
411	if (error) {
412		DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
413		return (error);
414	};
415	vp = nd.ni_vp;
416
417	if (vp == NULL) {
418		VATTR_INIT(&va);
419		VATTR_SET(&va, va_type, VDIR);
420		VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask);
421
422		error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, ctx);
423		if (error)
424		        DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error));
425	} else {
426		DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
427	        error = EEXIST;
428	}
429	vnode_put(nd.ni_dvp);
430	if (nd.ni_vp)
431	        vnode_put(nd.ni_vp);
432	nameidone(&nd);
433
434	return (error);
435}
436
437
438
439int
440vn_symlink(struct proc *p, char *path, char *link) {
441	struct nameidata nd;
442	struct vnode_attr va;
443	vfs_context_t ctx = vfs_context_kernel();
444	int error;
445
446	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), ctx);
447	if ((error = namei(&nd))) {
448		return error;
449	}
450
451	if (nd.ni_vp == NULL) {
452		VATTR_INIT(&va);
453		VATTR_SET(&va, va_type, VLNK);
454		VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask);
455
456		error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, ctx);
457	} else
458	        error = EEXIST;
459
460	vnode_put(nd.ni_dvp);
461	if (nd.ni_vp)
462		vnode_put(nd.ni_vp);
463	nameidone(&nd);
464
465	return (error);
466}
467
468
469