1/*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25// AppleCDDAFileSystemVFSOps.c created by CJS on Mon 10-Apr-2000
26
27
28// System Includes
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/proc.h>
32#include <sys/vnode.h>
33#include <sys/mount.h>
34#include <sys/buf.h>
35#include <sys/malloc.h>
36#include <sys/ubc.h>
37#include <mach/kmod.h>
38#include <libkern/OSKextLib.h>
39
40// Project Includes
41#ifndef __APPLE_CDDA_FS_VFS_OPS_H__
42#include "AppleCDDAFileSystemVFSOps.h"
43#endif
44
45#ifndef __APPLE_CDDA_FS_VNODE_OPS_H__
46#include "AppleCDDAFileSystemVNodeOps.h"
47#endif
48
49#ifndef __APPLE_CDDA_FS_DEBUG_H__
50#include "AppleCDDAFileSystemDebug.h"
51#endif
52
53#ifndef __APPLE_CDDA_FS_DEFINES_H__
54#include "AppleCDDAFileSystemDefines.h"
55#endif
56
57#ifndef __APPLE_CDDA_FS_UTILS_H__
58#include "AppleCDDAFileSystemUtils.h"
59#endif
60
61#ifndef __AIFF_SUPPORT_H__
62#include "AIFFSupport.h"
63#endif
64
65
66//-----------------------------------------------------------------------------
67//	Globals
68//-----------------------------------------------------------------------------
69
70
71// Global variables defined in other modules
72extern struct vnodeopv_desc		gCDDA_VNodeOperationsDesc;
73
74// CDDA File System globals
75static char gAppleCDDAName[MFSNAMELEN] = "cddafs";
76
77static vfstable_t gCDDA_VFSTableEntry;
78static struct vnodeopv_desc * gCDDA_VNodeOperationsDescList[1] =
79{
80	&gCDDA_VNodeOperationsDesc
81};
82
83// vfsops
84struct vfsops gCDDA_VFSOps =
85{
86	CDDA_Mount,
87	0,			// start
88	CDDA_Unmount,
89	CDDA_Root,
90	0,			// quotactl
91	CDDA_VFSGetAttributes,
92	0,			// synchronize
93	CDDA_VGet,
94	0,			// fhtovp
95	0,			// vptofh
96	0,			// init
97	0,			// sysctl
98	0,			// setattr
99	{ 0 }		// reserved
100};
101
102static void
103FindVolumeName ( const char * mn, const char ** np, ssize_t * nl );
104
105
106//-----------------------------------------------------------------------------
107//	CDDA_Mount -	This routine is responsible for mounting the filesystem
108//					in the desired path
109//-----------------------------------------------------------------------------
110
111int
112CDDA_Mount ( mount_t					mountPtr,
113			 vnode_t					blockDeviceVNodePtr,
114			 user_addr_t				data,
115			 vfs_context_t              context )
116{
117
118#pragma unused ( context )
119
120	AppleCDDAMountPtr		cddaMountPtr	= NULL;
121	AppleCDDANodePtr		cddaNodePtr		= NULL;
122	void *					xmlData			= NULL;
123	int						error			= 0;
124	AppleCDDAArguments		cddaArgs;
125	struct timeval			now;
126	struct timespec			timespec;
127
128	OSKextRetainKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) );
129
130	bzero ( &cddaArgs, sizeof ( cddaArgs ) );
131	bzero ( &now, sizeof ( now ) );
132	bzero ( &timespec, sizeof ( timespec ) );
133
134	DebugLog ( ( "CDDA_Mount: Entering.\n" ) );
135
136	DebugAssert ( ( mountPtr != NULL ) );
137	DebugAssert ( ( context != NULL ) );
138
139	error = copyin ( data, ( caddr_t ) &cddaArgs, sizeof ( cddaArgs ) );
140	if ( error != 0 )
141	{
142
143		DebugLog ( ( "CDDA_Mount: copyin error = %d\n", error ) );
144		goto ERROR;
145
146	}
147
148	if ( ( vfs_isrdwr ( mountPtr ) ) != 0 )
149	{
150
151		DebugLog ( ( "Returning EROFS...\n" ) );
152		error = EROFS;
153		goto ERROR;
154
155	}
156
157	// Update is a no-op
158	if ( vfs_isupdate ( mountPtr ) )
159	{
160
161		DebugLog ( ( "Returning ENOTSUP...\n" ) );
162		error = ENOTSUP;
163		goto ERROR;
164
165	}
166
167	if ( ( cddaArgs.nameData == USER_ADDR_NULL ) || ( cddaArgs.xmlData == USER_ADDR_NULL ) )
168	{
169
170		DebugLog ( ( "cddaArgs.nameData = 0x%qX, cddaArgs.xmlData = 0x%qX, Returning EINVAL...\n", cddaArgs.nameData, cddaArgs.xmlData ) );
171		error = EINVAL;
172		goto ERROR;
173
174	}
175
176	if ( ( cddaArgs.nameDataSize == 0 ) || ( cddaArgs.nameDataSize > kMaxNameDataSize ) )
177	{
178
179		DebugLog ( ( "cddaArgs.nameDataSize = %u, invalid, Returning EINVAL...\n", cddaArgs.nameDataSize ) );
180		error = EINVAL;
181		goto ERROR;
182
183	}
184
185	if ( ( cddaArgs.xmlFileSize == 0 ) || ( cddaArgs.xmlFileSize > kMaxXMLDataSize ) )
186	{
187
188		DebugLog ( ( "cddaArgs.xmlFileSize = %u, invalid, Returning EINVAL...\n", cddaArgs.xmlFileSize ) );
189		error = EINVAL;
190		goto ERROR;
191
192	}
193
194	// Allocate memory for private mount data
195	MALLOC ( cddaMountPtr, AppleCDDAMountPtr, sizeof ( AppleCDDAMount ), M_TEMP, M_WAITOK );
196
197	// Zero the structure
198	bzero ( cddaMountPtr, sizeof ( AppleCDDAMount ) );
199
200	// Initialize the lock
201	cddaMountPtr->cddaMountLockGroupAttr = lck_grp_attr_alloc_init ( );
202	cddaMountPtr->cddaMountLockGroup	 = lck_grp_alloc_init ( "cddafs mount structure", cddaMountPtr->cddaMountLockGroupAttr );
203	cddaMountPtr->cddaMountLockAttr		 = lck_attr_alloc_init ( );
204	cddaMountPtr->cddaMountLock			 = lck_mtx_alloc_init ( cddaMountPtr->cddaMountLockGroup, cddaMountPtr->cddaMountLockAttr );
205
206	// Save the number of audio tracks
207	cddaMountPtr->numTracks = cddaArgs.numTracks;
208
209	// Save file TYPE/CREATOR
210	cddaMountPtr->fileType		= cddaArgs.fileType;
211	cddaMountPtr->fileCreator	= cddaArgs.fileCreator;
212
213	// Allocate memory for NodeInfo array
214	MALLOC ( cddaMountPtr->nodeInfoArrayPtr, AppleCDDANodeInfoPtr,
215			 sizeof ( AppleCDDANodeInfo ) * cddaMountPtr->numTracks, M_TEMP, M_WAITOK );
216
217	// Zero the array
218	bzero ( cddaMountPtr->nodeInfoArrayPtr, sizeof ( AppleCDDANodeInfo ) * cddaMountPtr->numTracks );
219
220	// Fill in the mount time
221	microtime ( &now );
222	TIMEVAL_TO_TIMESPEC ( &now, &timespec );
223	cddaMountPtr->mountTime = timespec;
224
225	// Allocate memory for CD Track Names data
226	MALLOC ( cddaMountPtr->nameData, UInt8 *, cddaArgs.nameDataSize, M_TEMP, M_WAITOK );
227	cddaMountPtr->nameDataSize = cddaArgs.nameDataSize;
228
229	DebugLog ( ( "cddaMountPtr->nameData = %p, cddaMountPtr->nameDataSize = %d\n", cddaMountPtr->nameData, cddaMountPtr->nameDataSize ) );
230
231	error = copyin ( cddaArgs.nameData, ( caddr_t ) cddaMountPtr->nameData, cddaMountPtr->nameDataSize );
232	if ( error != 0 )
233	{
234
235		DebugLog ( ( "CDDA_Mount: copyin failed with error = %d.\n", error ) );
236		goto FREE_NODE_INFO_ERROR;
237
238	}
239
240	error = CreateNewCDDADirectory ( mountPtr,
241									 kAppleCDDARootFileID,
242									 &cddaMountPtr->root );
243
244	if ( error != 0 )
245	{
246
247		// XXX fix error to return a valid error number here
248		DebugLog ( ( "Returning error = %d after CreateNewCDDADirectory.\n", error ) );
249		goto FREE_TRACK_NAMES;
250
251	}
252
253	// Cache the vid for the root vnode.
254	cddaMountPtr->rootVID = vnode_vid ( cddaMountPtr->root );
255
256	// Set the root vnode's blockDeviceVNodePtr
257	cddaNodePtr = VTOCDDA ( cddaMountPtr->root );
258	cddaNodePtr->blockDeviceVNodePtr = blockDeviceVNodePtr;
259
260	vfs_setflags ( mountPtr, ( MNT_LOCAL | MNT_RDONLY | MNT_DOVOLFS ) );	// Local Read-Only FileSystem
261	vfs_setfsprivate ( mountPtr, ( void * ) cddaMountPtr );					// Hang our data off the MountPoint
262
263	// Get a filesystem ID for us
264	vfs_getnewfsid ( mountPtr );
265
266	// Allocate memory for xml data
267	MALLOC ( xmlData, void *, cddaArgs.xmlFileSize, M_TEMP, M_WAITOK );
268
269	error = copyin ( cddaArgs.xmlData, ( caddr_t ) xmlData, cddaArgs.xmlFileSize );
270	if ( error != 0 )
271	{
272
273		DebugLog ( ( "CDDA_Mount: copyin 2 failed with error = %d.\n", error ) );
274		goto FREE_ROOT_DIRECTORY;
275
276	}
277
278	cddaMountPtr->xmlData		= xmlData;
279	cddaMountPtr->xmlDataSize	= cddaArgs.xmlFileSize;
280
281	// Parse the TOC of the CD and build the tracks
282	error = ParseTOC ( mountPtr, cddaMountPtr->numTracks );
283	if ( error != 0 )
284	{
285
286		DebugLog ( ( "CDDA_Mount: Error = %d returned from ParseTOC.\n", error ) );
287		goto FREE_ROOT_DIRECTORY;
288
289	}
290
291	// Keep a reference on the root directory, and unlock it
292	vnode_ref ( cddaMountPtr->root );
293	vnode_put ( cddaMountPtr->root );
294
295	DebugLog ( ( "CDDA_Mount: Exiting CDDA_Mount.\n" ) );
296
297	return ( 0 );
298
299
300FREE_ROOT_DIRECTORY:
301
302
303	if ( cddaMountPtr->root != NULL )
304	{
305
306		// Release the root directory vnode we got above
307		vnode_put ( cddaMountPtr->root );
308
309	}
310
311
312FREE_TRACK_NAMES:
313
314
315	if ( cddaMountPtr->nameData != NULL )
316	{
317
318		FREE ( ( caddr_t ) cddaMountPtr->nameData, M_TEMP );
319		cddaMountPtr->nameData		= NULL;
320		cddaMountPtr->nameDataSize	= 0;
321
322	}
323
324
325FREE_NODE_INFO_ERROR:
326
327
328	if ( cddaMountPtr->nodeInfoArrayPtr != NULL )
329	{
330
331		// Free memory allocated for NodeInfo array
332		FREE ( ( caddr_t ) cddaMountPtr->nodeInfoArrayPtr, M_TEMP );
333		cddaMountPtr->nodeInfoArrayPtr = NULL;
334
335	}
336
337
338	if ( cddaMountPtr != NULL )
339	{
340
341		// Free memory allocated for mount structure
342		FREE ( ( caddr_t ) cddaMountPtr, M_TEMP );
343		cddaMountPtr = NULL;
344
345	}
346
347
348ERROR:
349
350
351	OSKextReleaseKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) );
352
353	return error;
354
355}
356
357
358//-----------------------------------------------------------------------------
359//	CDDA_Unmount -	This routine is called to unmount the disc at the
360//					specified mount point
361//-----------------------------------------------------------------------------
362
363int
364CDDA_Unmount ( mount_t					mountPtr,
365			   int						theFlags,
366			   unused vfs_context_t		context )
367{
368
369	vnode_t					rootVNodePtr		= NULLVP;
370	AppleCDDAMountPtr		cddaMountPtr		= NULL;
371	AppleCDDANodePtr		cddaNodePtr			= NULL;
372	AppleCDDANodeInfoPtr	nodeInfoArrayPtr	= NULL;
373	UInt8 *					nameData			= NULL;
374	UInt8 *					xmlData				= NULL;
375	int						error				= 0;
376	int						flags				= 0;
377
378	DebugLog ( ( "CDDA_Unmount: Entering.\n" ) );
379
380	DebugAssert ( ( mountPtr != NULL ) );
381	DebugAssert ( ( context != NULL ) );
382
383	cddaMountPtr = VFSTOCDDA ( mountPtr );
384	DebugAssert ( ( cddaMountPtr != NULL ) );
385
386	rootVNodePtr = cddaMountPtr->root;
387	DebugAssert ( ( rootVNodePtr != NULL ) );
388
389	cddaNodePtr = VTOCDDA ( rootVNodePtr );
390	DebugAssert ( ( cddaNodePtr != NULL ) );
391
392	if ( theFlags & MNT_FORCE )
393	{
394
395		DebugLog ( ( "CDDA_Unmount: Setting forceclose.\n" ) );
396		flags |= FORCECLOSE;
397
398	}
399
400	DebugAssert ( ( rootVNodePtr != NULL ) );
401
402	// Check for open files
403	error = vflush ( mountPtr, rootVNodePtr, flags );
404	if ( error != 0 )
405	{
406
407		DebugLog ( ( "CDDA_Unmount: Returning error = %d after vflush.\n", error ) );
408		return ( error );
409
410	}
411
412	// Release the underlying root vnode
413	vnode_rele ( rootVNodePtr );
414
415	error = vflush ( mountPtr, NULLVP, FORCECLOSE );
416	if ( error != 0 )
417	{
418
419		DebugLog ( ( "CDDA_Unmount: Returning error = %d after vflush.\n", error ) );
420		return ( error );
421
422	}
423
424	DebugLog ( ( "CDDA_Unmount: released the root vnode.\n" ) );
425	DebugLog ( ( "CDDA_Unmount: All vnodes killed!\n" ) );
426
427	// Get a pointer to the name data
428	nameData = VFSTONAMEINFO ( mountPtr );
429
430	// Get a pointer to the XML data
431	xmlData	 = VFSTOXMLDATA ( mountPtr );
432
433	DebugLog ( ( "CDDA_Unmount: Free the name data.\n" ) );
434
435	// Free the name data
436	FREE ( ( caddr_t ) nameData, M_TEMP );
437
438	DebugLog ( ( "CDDA_Unmount: Free the XML data.\n" ) );
439
440	// Free the XML data
441	FREE ( ( caddr_t ) xmlData, M_TEMP );
442
443	// Get a pointer to the NodeInfo Array
444	nodeInfoArrayPtr = VFSTONODEINFO ( mountPtr );
445
446	DebugLog ( ( "CDDA_Unmount: Free the nodeinfo array.\n" ) );
447
448	// Free the NodeInfo Array we allocated at mount time
449	FREE ( nodeInfoArrayPtr, M_TEMP );
450
451	DebugLog ( ( "CDDA_Unmount: Free the nodeinfo lock.\n" ) );
452
453	lck_mtx_free ( cddaMountPtr->cddaMountLock, cddaMountPtr->cddaMountLockGroup );
454	lck_attr_free ( cddaMountPtr->cddaMountLockAttr );
455	lck_grp_free ( cddaMountPtr->cddaMountLockGroup );
456	lck_grp_attr_free ( cddaMountPtr->cddaMountLockGroupAttr );
457
458	DebugLog ( ( "CDDA_Unmount: Free the mount point data.\n" ) );
459
460	// Finally, free the mount-specific data we allocated at mount time
461	FREE ( vfs_fsprivate ( mountPtr ), M_TEMP );
462
463	// Point the pointer to nothing
464	vfs_setfsprivate ( mountPtr, NULL );
465
466	DebugLog ( ( "CDDA_Unmount: Exiting, returning error = %d.\n", error ) );
467
468	OSKextReleaseKextWithLoadTag ( OSKextGetCurrentLoadTag ( ) );
469
470	return 0;
471
472}
473
474
475//-----------------------------------------------------------------------------
476//	CDDA_Root - This routine is called to get a vnode pointer to the root
477//				vnode of the filesystem
478//-----------------------------------------------------------------------------
479
480int
481CDDA_Root ( mount_t			mountPtr,
482			vnode_t *		vNodeHandle,
483			vfs_context_t	context )
484{
485
486	int			error	= 0;
487	ino64_t		inode	= kAppleCDDARootFileID;
488
489	DebugLog ( ( "CDDA_Root: Entering.\n" ) );
490
491	DebugAssert ( ( mountPtr != NULL ) );
492	DebugAssert ( ( vNodeHandle != NULL ) );
493	DebugAssert ( ( context != NULL ) );
494
495	error = CDDA_VGet ( mountPtr, inode, vNodeHandle, context );
496
497	DebugLog ( ( "CDDA_Root: exiting...\n" ) );
498
499	return ( error );
500
501}
502
503
504//-----------------------------------------------------------------------------
505//	CDDA_VFSGetAttributes -	This routine is called to get filesystem attributes.
506//-----------------------------------------------------------------------------
507
508int
509CDDA_VFSGetAttributes ( mount_t					mountPtr,
510						struct vfs_attr *		attrPtr,
511						unused vfs_context_t	context )
512{
513
514	AppleCDDAMountPtr			cddaMountPtr	= NULL;
515	AppleCDDANodePtr			rootCDDANodePtr = NULL;
516	vol_capabilities_attr_t *	capabilities	= NULL;
517	vol_attributes_attr_t *		attributes		= NULL;
518
519	DebugLog ( ( "CDDA_VFSGetAttributes: Entering.\n" ) );
520
521	DebugAssert ( ( mountPtr != NULL ) );
522	DebugAssert ( ( attrPtr != NULL ) );
523
524	capabilities	= &attrPtr->f_capabilities;
525	attributes		= &attrPtr->f_attributes;
526
527	cddaMountPtr = VFSTOCDDA ( mountPtr );
528	DebugAssert ( ( cddaMountPtr != NULL ) );
529
530	rootCDDANodePtr = VTOCDDA ( cddaMountPtr->root );
531	DebugAssert ( ( rootCDDANodePtr != NULL ) );
532
533	DebugAssert ( ( rootCDDANodePtr->nodeType == kAppleCDDADirectoryType ) );
534
535	//
536	// The +1's below are to account for the ".TOC.plist" file
537	//
538	VFSATTR_RETURN ( attrPtr, f_objcount, cddaMountPtr->numTracks + 1 );
539	VFSATTR_RETURN ( attrPtr, f_filecount, cddaMountPtr->numTracks + 1 );
540	VFSATTR_RETURN ( attrPtr, f_dircount, 0 );
541	VFSATTR_RETURN ( attrPtr, f_maxobjcount, cddaMountPtr->numTracks + 1 );
542	VFSATTR_RETURN ( attrPtr, f_iosize, kMaxBytesPerRead * 2 );
543	VFSATTR_RETURN ( attrPtr, f_blocks, rootCDDANodePtr->u.directory.directorySize / kPhysicalMediaBlockSize );
544	VFSATTR_RETURN ( attrPtr, f_bfree, 0 );
545	VFSATTR_RETURN ( attrPtr, f_bavail, 0 );
546	VFSATTR_RETURN ( attrPtr, f_bused, attrPtr->f_blocks );
547	VFSATTR_RETURN ( attrPtr, f_files, rootCDDANodePtr->u.directory.entryCount );
548	VFSATTR_RETURN ( attrPtr, f_ffree, 0 );
549	VFSATTR_RETURN ( attrPtr, f_bsize, kPhysicalMediaBlockSize );
550
551	VFSATTR_RETURN ( attrPtr, f_create_time, cddaMountPtr->mountTime );
552	VFSATTR_RETURN ( attrPtr, f_modify_time, cddaMountPtr->mountTime );
553
554	if ( VFSATTR_IS_ACTIVE ( attrPtr, f_backup_time ) )
555	{
556
557		attrPtr->f_backup_time.tv_sec = 0;
558		attrPtr->f_backup_time.tv_nsec = 0;
559		VFSATTR_SET_SUPPORTED ( attrPtr, f_backup_time );
560
561	}
562
563	if ( VFSATTR_IS_ACTIVE ( attrPtr, f_vol_name ) )
564	{
565
566		const char *	vname 	= NULL;
567		ssize_t			length 	= 0;
568
569		FindVolumeName ( vfs_statfs ( mountPtr )->f_mntonname, &vname, &length );
570
571		if ( vname != NULL )
572 		{
573
574 			strlcpy ( attrPtr->f_vol_name, vname, MAXPATHLEN );
575 			VFSATTR_SET_SUPPORTED ( attrPtr, f_vol_name );
576
577		}
578
579	}
580
581	// XXX these will go away soon
582	VFSATTR_RETURN ( attrPtr, f_fsid, vfs_statfs ( mountPtr )->f_fsid );
583
584	// Set the signature to 'BD'.
585	VFSATTR_RETURN ( attrPtr, f_signature, kAppleCDDAFileSystemVolumeSignature );
586
587	// Set the carbon FSID to 'JH'.
588	VFSATTR_RETURN ( attrPtr, f_carbon_fsid, kAppleCDDAFileSystemVCBFSID );
589
590	// We understand the following.
591	capabilities->valid[VOL_CAPABILITIES_FORMAT] =
592			VOL_CAP_FMT_PERSISTENTOBJECTIDS |
593			VOL_CAP_FMT_SYMBOLICLINKS |
594			VOL_CAP_FMT_HARDLINKS |
595			VOL_CAP_FMT_JOURNAL |
596			VOL_CAP_FMT_JOURNAL_ACTIVE |
597			VOL_CAP_FMT_NO_ROOT_TIMES |
598			VOL_CAP_FMT_SPARSE_FILES |
599			VOL_CAP_FMT_ZERO_RUNS |
600			VOL_CAP_FMT_CASE_SENSITIVE |
601			VOL_CAP_FMT_CASE_PRESERVING |
602			VOL_CAP_FMT_FAST_STATFS |
603			VOL_CAP_FMT_PATH_FROM_ID;
604
605	// We understand the following interfaces.
606	capabilities->valid[VOL_CAPABILITIES_INTERFACES] =
607			VOL_CAP_INT_SEARCHFS |
608			VOL_CAP_INT_ATTRLIST |
609			VOL_CAP_INT_NFSEXPORT |
610			VOL_CAP_INT_READDIRATTR |
611			VOL_CAP_INT_EXCHANGEDATA |
612			VOL_CAP_INT_COPYFILE |
613			VOL_CAP_INT_ALLOCATE |
614			VOL_CAP_INT_VOL_RENAME |
615			VOL_CAP_INT_ADVLOCK |
616			VOL_CAP_INT_FLOCK |
617			VOL_CAP_INT_EXTENDED_ATTR;
618
619	// We only support these bits of the above recognized things.
620	capabilities->capabilities[VOL_CAPABILITIES_FORMAT] =
621			VOL_CAP_FMT_PATH_FROM_ID |
622			VOL_CAP_FMT_PERSISTENTOBJECTIDS |
623			VOL_CAP_FMT_FAST_STATFS |
624			VOL_CAP_FMT_NO_ROOT_TIMES;
625
626	// We only support these things of the above recognized ones.
627	capabilities->capabilities[VOL_CAPABILITIES_INTERFACES] =
628			VOL_CAP_INT_ATTRLIST |
629			VOL_CAP_INT_EXTENDED_ATTR;
630
631	// Reserved. Zero them.
632	capabilities->capabilities[VOL_CAPABILITIES_RESERVED1]	= 0;
633	capabilities->capabilities[VOL_CAPABILITIES_RESERVED2]	= 0;
634	capabilities->valid[VOL_CAPABILITIES_RESERVED1]			= 0;
635	capabilities->valid[VOL_CAPABILITIES_RESERVED2]			= 0;
636
637	// Set the attributes.
638	VFSATTR_SET_SUPPORTED ( attrPtr, f_capabilities );
639
640	attributes->validattr.commonattr	= kAppleCDDACommonAttributesValidMask;
641	attributes->validattr.volattr		= kAppleCDDAVolumeAttributesValidMask;
642	attributes->validattr.dirattr		= kAppleCDDADirectoryAttributesValidMask;
643	attributes->validattr.fileattr		= kAppleCDDAFileAttributesValidMask;
644	attributes->validattr.forkattr		= kAppleCDDAForkAttributesValidMask;
645
646	attributes->nativeattr.commonattr	= kAppleCDDACommonAttributesValidMask;
647	attributes->nativeattr.volattr		= kAppleCDDAVolumeAttributesValidMask;
648	attributes->nativeattr.dirattr		= kAppleCDDADirectoryAttributesValidMask;
649	attributes->nativeattr.fileattr		= kAppleCDDAFileAttributesValidMask;
650	attributes->nativeattr.forkattr		= kAppleCDDAForkAttributesValidMask;
651
652	// Set the attributes.
653	VFSATTR_SET_SUPPORTED ( attrPtr, f_attributes );
654
655	return ( 0 );
656
657}
658
659
660//-----------------------------------------------------------------------------
661//	CDDA_VGet - This routine is responsible for getting the desired vnode.
662//-----------------------------------------------------------------------------
663
664int
665CDDA_VGet ( mount_t					mountPtr,
666			ino64_t					ino,
667			vnode_t *				vNodeHandle,
668			unused vfs_context_t	context )
669{
670
671	DebugLog ( ( "CDDA_VGet: Entering.\n" ) );
672
673	DebugAssert ( ( mountPtr != NULL ) );
674	DebugAssert ( ( vNodeHandle != NULL ) );
675	DebugAssert ( ( context != NULL ) );
676
677	return CDDA_VGetInternal ( mountPtr, ino, NULL, NULL, vNodeHandle );
678
679}
680
681
682//-----------------------------------------------------------------------------
683//	CDDA_VGetInternal - This routine is responsible for getting the
684//						desired vnode.
685//-----------------------------------------------------------------------------
686
687int
688CDDA_VGetInternal ( mount_t					mountPtr,
689					ino64_t					ino,
690					vnode_t					parentVNodePtr,
691					struct componentname *	compNamePtr,
692					vnode_t *				vNodeHandle )
693{
694
695	AppleCDDAMountPtr		cddaMountPtr		= NULL;
696	AppleCDDANodePtr		parentCDDANodePtr	= NULL;
697	AppleCDDANodeInfoPtr	nodeInfoArrayPtr	= NULL;
698	vnode_t					vNodePtr			= NULLVP;
699	int						error				= 0;
700	uint32_t				index				= 0;
701	uint32_t				vid					= 0;
702
703	cddaMountPtr = VFSTOCDDA ( mountPtr );
704
705	DebugAssert ( ( cddaMountPtr != NULL ) );
706
707	if ( ino == kAppleCDDARootFileID )
708	{
709
710		DebugLog ( ( "Root vnode asked for!\n" ) );
711
712		// Get the root vnode.
713		error = vnode_getwithvid ( cddaMountPtr->root, cddaMountPtr->rootVID );
714		if ( error == 0 )
715		{
716
717			// Return the root vnode to the caller since we have an iocount
718			// on it now.
719			*vNodeHandle = cddaMountPtr->root;
720
721		}
722
723		goto Exit;
724
725	}
726
727	else if ( ino == kAppleCDDAXMLFileID )
728	{
729
730		DebugLog ( ( "XML vnode asked for!\n" ) );
731
732		lck_mtx_lock ( cddaMountPtr->cddaMountLock );
733
734		while ( cddaMountPtr->xmlFileFlags & kAppleCDDANodeBusyMask )
735		{
736
737			cddaMountPtr->xmlFileFlags |= kAppleCDDANodeWantedMask;
738			( void ) msleep ( &cddaMountPtr->xmlFileFlags,
739						cddaMountPtr->cddaMountLock,
740						PINOD,
741						"CDDA_VGetInternal(XML)",
742						0 );
743
744		}
745
746		cddaMountPtr->xmlFileFlags |= kAppleCDDANodeBusyMask;
747		vNodePtr = cddaMountPtr->xmlFileVNodePtr;
748
749		if ( vNodePtr != NULL )
750		{
751
752			// Get an io_count on the vnode
753			vid = vnode_vid ( vNodePtr );
754
755			// Release the lock on our nodeInfo structure first
756			lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
757
758			error = vnode_getwithvid ( vNodePtr, vid );
759
760			lck_mtx_lock ( cddaMountPtr->cddaMountLock );
761
762			if ( error == 0 )
763			{
764
765				// Return the vnode to the caller since we have an iocount
766				// on it now.
767				*vNodeHandle = vNodePtr;
768
769			}
770
771		}
772
773		else
774		{
775
776			lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
777
778			error = CreateNewXMLFile ( mountPtr,
779									   cddaMountPtr->xmlDataSize,
780									   cddaMountPtr->xmlData,
781									   parentVNodePtr,
782									   compNamePtr,
783									   &vNodePtr );
784
785			lck_mtx_lock ( cddaMountPtr->cddaMountLock );
786
787			if ( error == 0 )
788			{
789
790				cddaMountPtr->xmlFileVNodePtr = vNodePtr;
791				*vNodeHandle = vNodePtr;
792
793			}
794
795		}
796
797		cddaMountPtr->xmlFileFlags &= ~kAppleCDDANodeBusyMask;
798		lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
799
800		if ( cddaMountPtr->xmlFileFlags & kAppleCDDANodeWantedMask )
801		{
802
803			cddaMountPtr->xmlFileFlags &= ~kAppleCDDANodeWantedMask;
804			wakeup ( &cddaMountPtr->xmlFileFlags );
805
806		}
807
808		goto Exit;
809
810	}
811
812	else if ( ( ino > 100 ) && ( ino < 200 ) )
813	{
814
815		parentCDDANodePtr = VTOCDDA ( cddaMountPtr->root );
816
817		// subtract our file offset to get to the real nodeID
818		ino -= kOffsetForFiles;
819
820		// Look in our NodeInfo array to see if a vnode has been created for this
821		// track yet.
822
823		nodeInfoArrayPtr = VFSTONODEINFO ( mountPtr );
824		DebugAssert ( ( nodeInfoArrayPtr != NULL ) );
825
826		DebugLog ( ( "Locking cddaMountLock.\n" ) );
827		DebugLog ( ( "Looking for nodeID = %lld.\n", ino ) );
828
829		lck_mtx_lock ( cddaMountPtr->cddaMountLock );
830
831		index = 0;
832
833		while ( index < ( parentCDDANodePtr->u.directory.entryCount - kNumberOfFakeDirEntries ) )
834		{
835
836			if ( nodeInfoArrayPtr->trackDescriptor.point == ( UInt8 ) ino )
837			{
838
839				while ( nodeInfoArrayPtr->flags & kAppleCDDANodeBusyMask )
840				{
841
842					nodeInfoArrayPtr->flags |= kAppleCDDANodeWantedMask;
843					( void ) msleep ( &nodeInfoArrayPtr->flags,
844								cddaMountPtr->cddaMountLock,
845								PINOD,
846								"CDDA_VGetInternal(Track)",
847								0 );
848
849				}
850
851				nodeInfoArrayPtr->flags |= kAppleCDDANodeBusyMask;
852				vNodePtr = nodeInfoArrayPtr->vNodePtr;
853
854				// See if the vNodePtr was attached (vNodePtr is only non-NULL if the node has been created)
855				if ( vNodePtr != NULL )
856				{
857
858					// Get the vid, so we can get an io_count on the vnode.
859					vid = vnode_vid ( vNodePtr );
860
861					DebugLog ( ( "Releasing cddaMountLock.\n" ) );
862
863					// Release the lock on our nodeInfo structure first.
864					lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
865
866					// Get the iocount.
867					error = vnode_getwithvid ( vNodePtr, vid );
868
869					// Grab our lock again.
870					lck_mtx_lock ( cddaMountPtr->cddaMountLock );
871
872					if ( error == 0 )
873					{
874
875						// The specified vNode was found and we got
876						// an iocount on it. Return this vnode.
877						*vNodeHandle = vNodePtr;
878
879					}
880
881				}
882
883				else
884				{
885
886					DebugLog ( ( "Couldn't find the vnode...Calling CreateNewCDDAFile\n" ) );
887
888					// Release the lock. Creating a vnode could cause another one to be reclaimed.
889					// We don't want to deadlock in reclaim because we forgot to drop the lock here!
890					lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
891
892					// If we get here, it doesn't exist yet, so create it
893					error = CreateNewCDDAFile ( mountPtr,
894												nodeInfoArrayPtr->trackDescriptor.point + kOffsetForFiles,
895												nodeInfoArrayPtr,
896												parentVNodePtr,
897												compNamePtr,
898												&vNodePtr );
899
900					lck_mtx_lock ( cddaMountPtr->cddaMountLock );
901
902					if ( error == 0 )
903					{
904
905						// Make sure we mark this vnode as being in the array now.
906						*vNodeHandle = vNodePtr;
907						nodeInfoArrayPtr->vNodePtr = vNodePtr;
908
909					}
910
911				}
912
913				nodeInfoArrayPtr->flags &= ~kAppleCDDANodeBusyMask;
914				lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
915
916				if ( nodeInfoArrayPtr->flags & kAppleCDDANodeWantedMask )
917				{
918
919					nodeInfoArrayPtr->flags &= ~kAppleCDDANodeWantedMask;
920					wakeup ( &nodeInfoArrayPtr->flags );
921
922				}
923
924				goto Exit;
925
926			}
927
928			index++;
929			nodeInfoArrayPtr++;
930
931		}
932
933		DebugLog ( ( "Releasing cddaMountLock...About to return ENOENT.\n" ) );
934
935		// Now we can release our lock because we're getting out
936		lck_mtx_unlock ( cddaMountPtr->cddaMountLock );
937
938		// If we get here, we couldn't find anything with that name. Return ENOENT.
939		error = ENOENT;
940
941	}
942
943	else
944	{
945
946		error = ENOENT;
947
948	}
949
950
951Exit:
952
953	DebugLog ( ( "CDDA_VGetInternal: exiting...\n" ) );
954
955	return ( error );
956
957}
958
959
960//-----------------------------------------------------------------------------
961//	FindVolumeName - Cribbed from vfs_attrlist.c. Gets volume name.
962//-----------------------------------------------------------------------------
963
964static void
965FindVolumeName ( const char * mn, const char ** np, ssize_t * nl )
966{
967
968	int				counting = 0;
969	const char *	cp		 = NULL;
970
971	// We're looking for the last sequence of non-'/' characters, but
972	// not including any trailing '/' characters.
973	*np 		= NULL;
974	*nl 		= 0;
975
976	for ( cp = mn; *cp != 0; cp++ )
977	{
978
979		if ( !counting )
980		{
981
982			// start of run of chars
983			if ( *cp != '/' )
984			{
985
986				*np = cp;
987				counting = 1;
988
989			}
990
991		}
992
993		else
994		{
995
996			// end of run of chars
997			if ( *cp == '/' )
998			{
999
1000				*nl = cp - *np;
1001				counting = 0;
1002
1003			}
1004
1005		}
1006
1007	}
1008
1009	// Need to close run?
1010	if ( counting )
1011		*nl = cp - *np;
1012
1013}
1014
1015
1016//-----------------------------------------------------------------------------
1017//	Apple_CDDA_FS_Module_Start -	This routine is responsible for
1018//									all the initialization that would
1019//									ordinarily be done as part of the
1020//									system startup
1021//-----------------------------------------------------------------------------
1022
1023int
1024Apple_CDDA_FS_Module_Start ( unused kmod_info_t * moduleInfo,
1025							 unused void * loadArgument )
1026{
1027
1028	errno_t				error		= KERN_FAILURE;
1029	struct vfs_fsentry	vfsEntry;
1030
1031	bzero ( &vfsEntry, sizeof ( vfsEntry ) );
1032
1033	vfsEntry.vfe_vfsops		= &gCDDA_VFSOps;
1034	vfsEntry.vfe_vopcnt		= 1;	// Just one vnode operation table
1035	vfsEntry.vfe_opvdescs	= gCDDA_VNodeOperationsDescList;
1036	vfsEntry.vfe_flags		= VFS_TBLNOTYPENUM | VFS_TBLLOCALVOL | VFS_TBL64BITREADY | VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK;
1037
1038	strlcpy ( vfsEntry.vfe_fsname, gAppleCDDAName, sizeof ( gAppleCDDAName ) );
1039
1040	error = vfs_fsadd ( &vfsEntry, &gCDDA_VFSTableEntry );
1041
1042	return error ? KERN_FAILURE : KERN_SUCCESS;
1043
1044}
1045
1046
1047//-----------------------------------------------------------------------------
1048//	Apple_CDDA_FS_Module_Stop - This routine is responsible for stopping
1049//								filesystem services
1050//-----------------------------------------------------------------------------
1051
1052int
1053Apple_CDDA_FS_Module_Stop ( unused kmod_info_t * moduleInfo,
1054							unused void * unloadArgument )
1055{
1056
1057	errno_t 	error = KERN_SUCCESS;
1058
1059	error = vfs_fsremove ( gCDDA_VFSTableEntry );
1060
1061	return error ? KERN_FAILURE : KERN_SUCCESS;
1062
1063}
1064
1065
1066//-----------------------------------------------------------------------------
1067//				End				Of			File
1068//-----------------------------------------------------------------------------
1069