#include "DAStage.h"
#include "DABase.h"
#include "DACallback.h"
#include "DADialog.h"
#include "DADisk.h"
#include "DAFileSystem.h"
#include "DAMain.h"
#include "DAMount.h"
#include "DAPrivate.h"
#include "DAProbe.h"
#include "DAQueue.h"
#include "DASupport.h"
#include <unistd.h>
#include <sys/mount.h>
const CFTimeInterval __kDABusyTimerGrace = 1;
const CFTimeInterval __kDABusyTimerLimit = 1;
static CFRunLoopSourceRef __gDAStageRunLoopSource = NULL;
static void __DAStageAppeared( DADiskRef disk );
static void __DAStageMount( DADiskRef disk );
static void __DAStagePeek( DADiskRef disk );
static void __DAStagePeekCallback( CFTypeRef response, void * context );
static CFComparisonResult __DAStagePeekCompare( const void * value1, const void * value2, void * context );
static void __DAStageProbe( DADiskRef disk );
static void __DAStageProbeCallback( int status,
DAFileSystemRef filesystem,
CFBooleanRef clean,
CFStringRef name,
CFStringRef type,
CFUUIDRef uuid,
void * context );
static void __DABusyTimerCallback( CFRunLoopTimerRef timer, void * info )
{
DAStageSignal( );
}
static void __DABusyTimerRefresh( CFAbsoluteTime clock )
{
static CFRunLoopTimerRef timer = NULL;
if ( timer )
{
CFRunLoopTimerSetNextFireDate( timer, clock );
}
else
{
timer = CFRunLoopTimerCreate( kCFAllocatorDefault, clock, kCFAbsoluteTimeIntervalSince1904, 0, 0, __DABusyTimerCallback, NULL );
if ( timer )
{
CFRunLoopAddTimer( CFRunLoopGetCurrent( ), timer, kCFRunLoopDefaultMode );
}
}
}
static void __DAStageAppeared( DADiskRef disk )
{
DADiskSetState( disk, kDADiskStateStagedAppear, TRUE );
DADiskAppearedCallback( disk );
DAStageSignal( );
}
static void __DAStageDispatch( void * info )
{
static Boolean fresh = FALSE;
CFAbsoluteTime clock;
CFIndex count;
CFIndex index;
Boolean quiet = TRUE;
clock = kCFAbsoluteTimeIntervalSince1904;
count = CFArrayGetCount( gDADiskList );
for ( index = 0; index < count; index++ )
{
DADiskRef disk;
disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
if ( disk )
{
CFAbsoluteTime timeout;
timeout = DADiskGetBusy( disk ) + __kDABusyTimerLimit;
if ( timeout < CFAbsoluteTimeGetCurrent( ) )
{
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue )
{
DAUnitSetState( disk, kDAUnitStateHasQuiesced, TRUE );
}
}
else
{
timeout += __kDABusyTimerGrace;
if ( timeout < clock )
{
clock = timeout;
}
quiet = FALSE;
}
}
}
__DABusyTimerRefresh( clock );
count = CFArrayGetCount( gDADiskList );
for ( index = 0; index < count; index++ )
{
DADiskRef disk;
disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
if ( DADiskGetState( disk, kDADiskStateCommandActive ) == FALSE )
{
if ( DADiskGetState( disk, kDADiskStateStagedProbe ) == FALSE )
{
if ( fresh )
{
DAFileSystemListRefresh( );
DAMountMapListRefresh1( );
DAMountMapListRefresh2( );
fresh = FALSE;
}
__DAStageProbe( disk );
}
else if ( DADiskGetState( disk, kDADiskStateStagedPeek ) == FALSE )
{
__DAStagePeek( disk );
}
else if ( DADiskGetState( disk, kDADiskStateStagedMount ) == FALSE )
{
if ( gDAExit )
{
continue;
}
if ( DADiskGetState( disk, kDADiskStateRequireRepair ) )
{
CFIndex subcount;
CFIndex subindex;
subcount = CFArrayGetCount( gDADiskList );
for ( subindex = 0; subindex < subcount; subindex++ )
{
DADiskRef subdisk;
subdisk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, subindex );
if ( DADiskGetBSDUnit( disk ) == DADiskGetBSDUnit( subdisk ) )
{
if ( DADiskGetState( subdisk, kDADiskStateStagedProbe ) == FALSE )
{
break;
}
if ( DADiskGetState( subdisk, kDADiskStateStagedMount ) == FALSE )
{
if ( DADiskGetState( subdisk, kDADiskStateRequireRepair ) == FALSE )
{
break;
}
}
}
}
if ( subindex == subcount )
{
__DAStageMount( disk );
}
}
else
{
__DAStageMount( disk );
}
}
else if ( DADiskGetState( disk, kDADiskStateStagedAppear ) == FALSE )
{
__DAStageAppeared( disk );
}
else
{
if ( gDAConsoleUserList == NULL )
{
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaTypeKey ) )
{
CFNumberRef size;
size = DADiskGetDescription( disk, kDADiskDescriptionMediaSizeKey );
if ( size )
{
if ( ___CFNumberGetIntegerValue( size ) == 0 )
{
if ( DAUnitGetState( disk, kDAUnitStateStagedUnreadable ) == FALSE )
{
if ( _DAUnitIsUnreadable( disk ) )
{
DADiskEject( disk, kDADiskEjectOptionDefault, NULL );
}
DAUnitSetState( disk, kDAUnitStateStagedUnreadable, TRUE );
}
}
}
}
}
continue;
}
}
quiet = FALSE;
}
count = CFArrayGetCount( gDARequestList );
if ( count )
{
CFMutableSetRef dependencies;
dependencies = CFSetCreateMutable( kCFAllocatorDefault, 0, &kCFTypeSetCallBacks );
if ( dependencies )
{
for ( index = 0; index < count; index++ )
{
DARequestRef request;
request = ( void * ) CFArrayGetValueAtIndex( gDARequestList, index );
if ( request )
{
DADiskRef disk;
Boolean dispatch = TRUE;
disk = DARequestGetDisk( request );
if ( disk )
{
CFArrayRef link;
link = DARequestGetLink( request );
if ( link )
{
CFIndex subcount;
CFIndex subindex;
subcount = CFArrayGetCount( link );
for ( subindex = 0; subindex < subcount; subindex++ )
{
DARequestRef subrequest;
subrequest = ( void * ) CFArrayGetValueAtIndex( link, subindex );
if ( CFSetContainsValue( dependencies, DARequestGetDisk( subrequest ) ) )
{
break;
}
}
if ( subindex < subcount )
{
dispatch = FALSE;
}
}
if ( CFSetContainsValue( dependencies, disk ) )
{
dispatch = FALSE;
}
}
else
{
if ( index )
{
break;
}
}
if ( dispatch )
{
if ( DARequestGetKind( request ) == _kDADiskMount )
{
if ( fresh )
{
DAFileSystemListRefresh( );
DAMountMapListRefresh1( );
DAMountMapListRefresh2( );
fresh = FALSE;
}
}
dispatch = DARequestDispatch( request );
}
if ( dispatch )
{
CFArrayRemoveValueAtIndex( gDARequestList, index );
count--;
index--;
}
else
{
if ( disk )
{
CFArrayRef link;
link = DARequestGetLink( request );
if ( link )
{
CFIndex subcount;
CFIndex subindex;
subcount = CFArrayGetCount( link );
for ( subindex = 0; subindex < subcount; subindex++ )
{
DARequestRef subrequest;
subrequest = ( void * ) CFArrayGetValueAtIndex( link, subindex );
CFSetSetValue( dependencies, DARequestGetDisk( subrequest ) );
}
}
CFSetSetValue( dependencies, disk );
}
}
}
}
CFRelease( dependencies );
}
quiet = FALSE;
}
if ( quiet )
{
fresh = TRUE;
gDAIdle = TRUE;
DAIdleCallback( );
___vproc_transaction_end( );
if ( gDAConsoleUser )
{
count = CFArrayGetCount( gDADiskList );
for ( index = 0; index < count; index++ )
{
DADiskRef disk;
disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue )
{
if ( DAUnitGetState( disk, kDAUnitStateStagedUnreadable ) == FALSE )
{
if ( _DAUnitIsUnreadable( disk ) )
{
DADialogShowDeviceUnreadable( disk );
}
DAUnitSetState( disk, kDAUnitStateStagedUnreadable, TRUE );
}
}
if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) )
{
if ( DADiskGetState( disk, kDADiskStateStagedUnrepairable ) == FALSE )
{
if ( DADiskGetState( disk, kDADiskStateRequireRepair ) )
{
if ( DADiskGetState( disk, _kDADiskStateMountAutomatic ) )
{
if ( DADiskGetClaim( disk ) == NULL )
{
DADialogShowDeviceUnrepairable( disk );
}
}
}
DADiskSetState( disk, kDADiskStateStagedUnrepairable, TRUE );
}
}
}
}
}
}
static void __DAStageMount( DADiskRef disk )
{
DADiskSetState( disk, kDADiskStateStagedMount, TRUE );
DADiskMountWithArguments( disk, NULL, kDADiskMountOptionDefault, NULL, CFSTR( "automatic" ) );
DAStageSignal( );
}
static void __DAStagePeek( DADiskRef disk )
{
CFMutableArrayRef candidates;
candidates = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( candidates )
{
DASessionRef session;
CFArrayRef sessionList;
CFIndex sessionListCount;
CFIndex sessionListIndex;
sessionList = gDASessionList;
sessionListCount = CFArrayGetCount( sessionList );
for ( sessionListIndex = 0; sessionListIndex < sessionListCount; sessionListIndex++ )
{
DACallbackRef callback;
CFArrayRef callbackList;
CFIndex callbackListCount;
CFIndex callbackListIndex;
session = ( void * ) CFArrayGetValueAtIndex( sessionList, sessionListIndex );
callbackList = DASessionGetCallbackRegister( session );
callbackListCount = CFArrayGetCount( callbackList );
for ( callbackListIndex = 0; callbackListIndex < callbackListCount; callbackListIndex++ )
{
callback = ( void * ) CFArrayGetValueAtIndex( callbackList, callbackListIndex );
if ( DACallbackGetKind( callback ) == _kDADiskPeekCallback )
{
CFArrayAppendValue( candidates, callback );
}
}
}
CFArraySortValues( candidates, CFRangeMake( 0, CFArrayGetCount( candidates ) ), __DAStagePeekCompare, NULL );
CFRetain( disk );
DADiskSetContext( disk, candidates );
DADiskSetState( disk, kDADiskStateStagedPeek, TRUE );
DADiskSetState( disk, kDADiskStateCommandActive, TRUE );
__DAStagePeekCallback( NULL, disk );
CFRelease( candidates );
}
}
static void __DAStagePeekCallback( CFTypeRef response, void * context )
{
CFMutableArrayRef candidates;
DADiskRef disk = context;
candidates = ( void * ) DADiskGetContext( disk );
if ( CFArrayGetCount( candidates ) )
{
DACallbackRef candidate;
candidate = ( void * ) CFArrayGetValueAtIndex( candidates, 0 );
CFRetain( candidate );
CFArrayRemoveValueAtIndex( candidates, 0 );
DADiskPeekCallback( disk, candidate, __DAStagePeekCallback, context );
CFRelease( candidate );
return;
}
DADiskSetState( disk, kDADiskStateCommandActive, FALSE );
DADiskSetContext( disk, NULL );
DAStageSignal( );
CFRelease( disk );
}
static CFComparisonResult __DAStagePeekCompare( const void * value1, const void * value2, void * context )
{
SInt32 order1 = DACallbackGetOrder( ( void * ) value1 );
SInt32 order2 = DACallbackGetOrder( ( void * ) value2 );
if ( order1 > order2 ) return kCFCompareGreaterThan;
if ( order1 < order2 ) return kCFCompareLessThan;
return kCFCompareEqualTo;
}
static void __DAStageProbe( DADiskRef disk )
{
if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE )
{
CFRetain( disk );
DADiskSetState( disk, kDADiskStateStagedProbe, TRUE );
DADiskSetState( disk, kDADiskStateCommandActive, TRUE );
DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE );
DAProbe( disk, __DAStageProbeCallback, disk );
}
}
static void __DAStageProbeCallback( int status,
DAFileSystemRef filesystem,
CFBooleanRef clean,
CFStringRef name,
CFStringRef type,
CFUUIDRef uuid,
void * context )
{
DADiskRef disk = context;
CFMutableArrayRef keys;
CFStringRef kind;
DADiskSetFileSystem( disk, filesystem );
DADiskSetState( disk, kDADiskStateRequireRepair, FALSE );
DADiskSetState( disk, kDADiskStateRequireRepairQuotas, FALSE );
if ( status )
{
kind = NULL;
}
else
{
kind = DAFileSystemGetKind( filesystem );
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse )
{
clean = kCFBooleanTrue;
}
if ( clean == kCFBooleanFalse )
{
DADiskSetState( disk, kDADiskStateRequireRepair, TRUE );
DADiskSetState( disk, kDADiskStateRequireRepairQuotas, TRUE );
}
}
keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( keys )
{
CFTypeRef object;
object = kind ? kCFBooleanTrue : kCFBooleanFalse;
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeMountableKey, object ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeMountableKey, object );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeMountableKey );
}
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeKindKey, kind ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeKindKey, kind );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeKindKey );
}
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeNameKey, name ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeNameKey, name );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeNameKey );
}
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeTypeKey, type ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeTypeKey, type );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeTypeKey );
}
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeUUIDKey, uuid ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeUUIDKey, uuid );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeUUIDKey );
}
if ( CFArrayGetCount( keys ) )
{
if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
{
DADiskDescriptionChangedCallback( disk, keys );
}
}
CFRelease( keys );
}
if ( DADiskGetState( disk, kDADiskStateStagedMount ) == FALSE )
{
struct statfs * mountList;
int mountListCount;
int mountListIndex;
mountListCount = getmntinfo( &mountList, MNT_NOWAIT );
for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
{
if ( mountList[mountListIndex].f_fsid.val[0] == DADiskGetBSDNode( disk ) )
{
CFURLRef path;
path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault,
( void * ) mountList[mountListIndex].f_mntonname,
strlen( mountList[mountListIndex].f_mntonname ),
TRUE );
if ( path )
{
DADiskSetBypath( disk, path );
DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, path );
CFRelease( path );
}
if ( strcmp( mountList[mountListIndex].f_mntonname, "/" ) == 0 )
{
path = DAMountCreateMountPointWithAction( disk, kDAMountPointActionLink );
if ( path )
{
DADiskSetBypath( disk, path );
CFRelease( path );
}
DADiskSetState( disk, _kDADiskStateMountAutomatic, TRUE );
DADiskSetState( disk, _kDADiskStateMountAutomaticNoDefer, TRUE );
}
DADiskSetState( disk, kDADiskStateRequireRepair, FALSE );
DADiskSetState( disk, kDADiskStateRequireRepairQuotas, FALSE );
break;
}
}
}
DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE );
DADiskSetState( disk, kDADiskStateCommandActive, FALSE );
DAStageSignal( );
CFRelease( disk );
}
CFRunLoopSourceRef DAStageCreateRunLoopSource( CFAllocatorRef allocator, CFIndex order )
{
if ( __gDAStageRunLoopSource == NULL )
{
CFRunLoopSourceContext context = { 0 };
context.perform = __DAStageDispatch;
__gDAStageRunLoopSource = CFRunLoopSourceCreate( allocator, order, &context );
}
if ( __gDAStageRunLoopSource )
{
CFRetain( __gDAStageRunLoopSource );
}
return __gDAStageRunLoopSource;
}
void DAStageSignal( void )
{
if ( gDAIdle )
{
___vproc_transaction_begin( );
}
gDAIdle = FALSE;
CFRunLoopSourceSignal( __gDAStageRunLoopSource );
}