/*
 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include "DAStage.h"

#include "DACallback.h"
#include "DADialog.h"
#include "DADisk.h"
#include "DAFileSystem.h"
#include "DALog.h"
#include "DAMain.h"
#include "DAMount.h"
#include "DAPrivate.h"
#include "DAQueue.h"
#include "DASupport.h"

#include <fsproperties.h>
#include <unistd.h>
#include <sys/mount.h>
#include <IOKit/storage/IOMedia.h>

static CFRunLoopSourceRef __gDAStageRunLoopSource = NULL;

static void               __DAStageAppeared( DADiskRef disk );
static void               __DAStageMount( DADiskRef disk );
static void               __DAStageMountCallback( int status, CFURLRef mountpoint, void * context );
static void               __DAStageMountApproval( DADiskRef disk );
static void               __DAStageMountApprovalCallback( CFTypeRef response, void * context );
static void               __DAStageMountAuthorization( DADiskRef disk );
static void               __DAStageMountAuthorizationCallback( DAReturn status, void * context );
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, CFBooleanRef clean, CFStringRef name, CFUUIDRef uuid, void * context );
static void               __DAStageRepair( DADiskRef disk );
static void               __DAStageRepairCallback( int status, void * context );

static void __DAStageAppeared( DADiskRef disk )
{
    /*
     * We commence the "appeared" stage if the conditions are right.
     */

    DADiskLog( disk );

    DADiskSetState( disk, kDADiskStateStagedAppear, TRUE );
    
    DADiskAppearedCallback( disk );

    DAStageSignal( );
}

static void __DAStageDispatch( void * info )
{
    static Boolean fresh = FALSE;

    CFIndex count;
    CFIndex index;
    Boolean quiet = TRUE;

    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, kDADiskStateStagedRepair ) == FALSE )
            {
                __DAStageRepair( disk );
            }
            else if ( DADiskGetState( disk, kDADiskStateStagedApprove ) == FALSE )
            {
                __DAStageMountApproval( disk );
            }
            else if ( DADiskGetState( disk, kDADiskStateStagedAuthorize ) == FALSE )
            {
                __DAStageMountAuthorization( disk );
            }
            else if ( DADiskGetState( disk, kDADiskStateStagedMount ) == FALSE )
            {
                __DAStageMount( disk );
            }
            else if ( DADiskGetState( disk, kDADiskStateStagedAppear ) == FALSE )
            {
                __DAStageAppeared( disk );
            }
            else
            {
                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 );

                    /*
                     * Determine whether the request has undispatched dependencies.
                     */

                    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 )
                    {
                        /*
                         * Prepare to dispatch the request.
                         */

                        if ( DARequestGetKind( request ) == _kDADiskMount )
                        {
                            if ( fresh )
                            {
                                DAFileSystemListRefresh( );

                                DAMountMapListRefresh1( );

                                DAMountMapListRefresh2( );

                                fresh = FALSE;
                            }
                        }

                        /*
                         * Dispatch the request.
                         */

                        dispatch = DARequestDispatch( request );
                    }

                    if ( dispatch )
                    {
                        CFArrayRemoveValueAtIndex( gDARequestList, index );

                        count--;
                        index--;
                    }
                    else
                    {
                        /*
                         * Add the request to the undispatched dependencies.
                         */

                        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( );

        DAMainRendezvous( );

        if ( gDAConsoleUser )
        {
///w:start
            if ( CFEqual( gDAConsoleUser, CFSTR( "loginwindow" ) ) )
            {
                return;
            }
///w:stop
            /*
             * Determine whether a unit is unreadable.
             */

            count = CFArrayGetCount( gDADiskList );

            for ( index = 0; index < count; index++ )
            {
                DADiskRef disk;

                disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );

                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue )
                {
                    if ( DADiskGetOption( disk, kDADiskOptionMountAutomatic ) )
                    {
                        if ( DAUnitGetState( disk, kDAUnitStateStagedUnreadable ) == FALSE )
                        {
///w:start
                            io_service_t media;

                            media = DADiskGetIOMedia( disk );

                            if ( media )
                            {
                                CFTypeRef object;

                                object = IORegistryEntrySearchCFProperty( media,
                                                                          kIOServicePlane,
                                                                          CFSTR( "image-path" ),
                                                                          kCFAllocatorDefault,
                                                                          kIORegistryIterateParents | kIORegistryIterateRecursively );

                                if ( object )
                                {
                                    CFRelease( object );

                                    continue;
                                }
                            }
///w:stop
                            if ( _DAUnitIsUnreadable( disk ) )
                            {
                                DADialogShowDeviceUnreadable( disk );
                            }

                            DAUnitSetState( disk, kDAUnitStateStagedUnreadable, TRUE );
                        }
                    }
                }
            }
        }
    }
}

static void __DAStageMount( DADiskRef disk )
{
    /*
     * We commence the "mount" stage if the conditions are right.
     */

    DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );

    if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE )
    {
        /*
         * Commence the mount.
         */

        CFRetain( disk );

        DADiskSetState( disk, kDADiskStateStagedMount, TRUE );

        DADiskSetState( disk, kDADiskStateCommandActive, TRUE );

        DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE );

	DAUnitSetState( disk, kDAUnitStateEjected, FALSE );

        DALogDebug( "  mounted disk, id = %@, ongoing.", disk );

        DAMountWithArguments( disk, NULL, __DAStageMountCallback, disk, CFSTR( "automatic" ), NULL );
    }
}

static void __DAStageMountCallback( int status, CFURLRef mountpoint, void * context )
{
    DADiskRef disk = context;

    DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );

    if ( status )
    {
        /*
         * We were unable to mount the volume.
         */

        if ( status == ECANCELED )
        {
            DALogDebug( "  mounted disk, id = %@, deferred.", disk );
        }
        else
        {
            DALogDebug( "  mounted disk, id = %@, failure.", disk );

            DALogError( "unable to mount %@ (status code 0x%08X).", disk, status );
        }
    }
    else
    {
        /*
         * We were able to mount the volume.
         */

        DADiskSetBypath( disk, mountpoint );

        DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, mountpoint );

        DALogDebug( "  mounted disk, id = %@, success.", disk );
    }

    DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE );

    DADiskSetState( disk, kDADiskStateCommandActive, FALSE );

    DAStageSignal( );

    CFRelease( disk );
}

static void __DAStageMountApproval( DADiskRef disk )
{
    /*
     * We commence the "mount approval" stage if the conditions are right.
     */

    Boolean mount = TRUE;

    /*
     * Determine whether the disk is mountable.
     */

    if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse )
    {
        mount = FALSE;
    }

    /*
     * Determine whether the disk is mounted.
     */

    if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) )
    {
        mount = FALSE;
    }

    /*
     * Determine whether the disk is clean.
     */

    if ( DADiskGetState( disk, kDADiskStateRequireRepair ) )
    {
        mount = FALSE;
    }

    /*
     * Commence the mount approval.
     */

    DADiskSetState( disk, kDADiskStateStagedApprove, TRUE );

    if ( mount )
    {
        CFRetain( disk );

        DADiskSetState( disk, kDADiskStateCommandActive, TRUE );

        DADiskMountApprovalCallback( disk, __DAStageMountApprovalCallback, disk );
    }
    else
    {
        DADiskSetState( disk, kDADiskStateStagedMount, TRUE );

        DAStageSignal( );
    }
}

static void __DAStageMountApprovalCallback( CFTypeRef response, void * context )
{
    DADiskRef      disk      = context;
    DADissenterRef dissenter = response;

    if ( dissenter )
    {
        /*
         * The mount was disapproved.
         */

///w:start
        if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF01 )
        {
            DADiskSetState( disk, _kDADiskStateRequireAuthorize, TRUE );
        }
        else if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF02 )
        {
            DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, TRUE );
        }
        else if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF03 )
        {
            DADiskSetState( disk, _kDADiskStateRequireAuthorize, TRUE );

            DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, TRUE );
        }
        else
///w:stop
        DADiskSetState( disk, kDADiskStateStagedMount, TRUE );
    }

    DADiskSetState( disk, kDADiskStateCommandActive, FALSE );

    DAStageSignal( );

    CFRelease( disk );
}

static void __DAStageMountAuthorization( DADiskRef disk )
{
    /*
     * We commence the "mount authorization" stage if the conditions are right.
     */

    /*
     * Commence the mount authorization.
     */

    DADiskSetState( disk, kDADiskStateStagedAuthorize, TRUE );

///w:start
    if ( DADiskGetState( disk, _kDADiskStateRequireAuthorize ) )
///w:stop
    {
        CFRetain( disk );

        DADiskSetState( disk, kDADiskStateCommandActive, TRUE );

        DAAuthorizeWithCallback( NULL,
                                 kDAAuthorizeOptionForce | kDAAuthorizeOptionInteract,
                                 disk,
                                 ___UID_ROOT,
                                 ___GID_ADMIN,
                                 __DAStageMountAuthorizationCallback,
                                 disk,
                                 _kDAAuthorizeRightMount );
    }
    else
    {
        DAStageSignal( );
    }
}

static void __DAStageMountAuthorizationCallback( DAReturn status, void * context )
{
    DADiskRef disk = context;

    if ( status )
    {
        /*
         * The mount was unauthorized.
         */

        DADiskSetState( disk, kDADiskStateStagedMount, TRUE );
    }

    DADiskSetState( disk, kDADiskStateCommandActive, FALSE );

    DAStageSignal( );

    CFRelease( disk );
}

static void __DAStagePeek( DADiskRef disk )
{
    /*
     * We commence the "peek" stage if the conditions are right.
     */

    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 );

        /*
         * Commence the peek.
         */

        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 )
{
    /*
     * We commence the "probe" stage if the conditions are right.
     */

    if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE )
    {
        CFMutableArrayRef candidates;

        candidates = CFArrayCreateMutableCopy( kCFAllocatorDefault, 0, gDAFileSystemProbeList );

        if ( candidates )
        {
            CFNumberRef size;

            /*
             * Determine whether the disk is formatted.
             */

            size = DADiskGetDescription( disk, kDADiskDescriptionMediaSizeKey );

            if ( size )
            {
                if ( ___CFNumberGetIntegerValue( size ) == 0 )
                {
                    CFArrayRemoveAllValues( candidates );
                }
            }

            /*
             * Commence the probe.
             */

            CFRetain( disk );

            DADiskSetFileSystem( disk, NULL );

            DADiskSetContext( disk, candidates );

            DADiskSetState( disk, kDADiskStateStagedProbe, TRUE );

            DADiskSetState( disk, kDADiskStateCommandActive, TRUE );

            DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE );

            __DAStageProbeCallback( -1, NULL, NULL, NULL, disk );

            CFRelease( candidates );
        }
    }
}

static void __DAStageProbeCallback( int status, CFBooleanRef clean, CFStringRef name, CFUUIDRef uuid, void * context )
{
    DADiskRef         disk = context;
    CFMutableArrayRef keys = NULL;
    CFStringRef       kind = NULL;

    DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );

    if ( status )
    {
        CFMutableArrayRef candidates;

        candidates = ( void * ) DADiskGetContext( disk );

        if ( DADiskGetFileSystem( disk ) )
        {
            kind = DAFileSystemGetKind( DADiskGetFileSystem( disk ) );

            DALogDebug( "  probed disk, id = %@, with %@, failure.", disk, kind );
        }

        /*
         * Find a probe candidate for this media object.
         */

        while ( CFArrayGetCount( candidates ) )
        {
            CFDictionaryRef candidate;

            candidate = CFArrayGetValueAtIndex( candidates, 0 );

            if ( candidate )
            {
                DAFileSystemRef filesystem;

                filesystem = ( void * ) CFDictionaryGetValue( candidate, kDAFileSystemKey );

                if ( filesystem )
                {
                    CFDictionaryRef properties;

                    properties = CFDictionaryGetValue( candidate, CFSTR( kFSMediaPropertiesKey ) );

                    if ( properties )
                    {
                        boolean_t match = FALSE;

                        IOServiceMatchPropertyTable( DADiskGetIOMedia( disk ), properties, &match );

                        if ( match )
                        {
                            /*
                             * We have found a probe candidate for this media object.
                             */

                            kind = DAFileSystemGetKind( filesystem );

                            DADiskSetFileSystem( disk, filesystem );

                            CFArrayRemoveValueAtIndex( candidates, 0 );

                            DALogDebug( "  probed disk, id = %@, with %@, ongoing.", disk, kind );

                            DAFileSystemProbe( filesystem, DADiskGetDevice( disk ), __DAStageProbeCallback, context );

                            return;
                        }
                    }
                }
            }

            CFArrayRemoveValueAtIndex( candidates, 0 );
        }
    }

///w:start
    DADiskSetState( disk, _kDADiskStateRequireAuthorize,   FALSE );
///w:stop
    DADiskSetState( disk, kDADiskStateRequireRepair,       FALSE );
    DADiskSetState( disk, kDADiskStateRequireRepairQuotas, FALSE );

    if ( status )
    {
        /*
         * We have found no probe match for this media object.
         */

        kind = NULL;

        if ( DADiskGetFileSystem( disk ) )
        {
            DADiskSetFileSystem( disk, NULL );

            DALogDebug( "  probed disk, id = %@, no match.", disk );
        }
    }
    else
    {
        /*
         * We have found a probe match for this media object.
         */

        kind = DAFileSystemGetKind( DADiskGetFileSystem( disk ) );

        if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanTrue )
        {
            DADiskSetState( disk, kDADiskStateRequireRepair,       ( clean == kCFBooleanFalse ) );
            DADiskSetState( disk, kDADiskStateRequireRepairQuotas, ( clean == kCFBooleanFalse ) );
        }

        DALogDebug( "  probed disk, id = %@, with %@, success.", disk, kind );
    }

    keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );

    if ( keys )
    {
        CFTypeRef object;
///w:start
        object = IORegistryEntryCreateCFProperty( DADiskGetIOMedia( disk ), CFSTR( kIOMediaWritableKey ), kCFAllocatorDefault, 0 ); 

        if ( object )
        {
            if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaWritableKey, object ) )
            {
                DADiskSetDescription( disk, kDADiskDescriptionMediaWritableKey, object );

                CFArrayAppendValue( keys, kDADiskDescriptionMediaWritableKey );
            }

            CFRelease( object );
        }
///w:stop

        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, kDADiskDescriptionVolumeUUIDKey, uuid ) )
        {
            DADiskSetDescription( disk, kDADiskDescriptionVolumeUUIDKey, uuid );

            CFArrayAppendValue( keys, kDADiskDescriptionVolumeUUIDKey );
        }

        if ( CFArrayGetCount( keys ) )
        {
            if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
            {
                DADiskDescriptionChangedCallback( disk, keys );
            }
        }

        CFRelease( keys );
    }

    DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE );

    DADiskSetState( disk, kDADiskStateCommandActive, FALSE );

    DADiskSetContext( disk, NULL );

    DAStageSignal( );

    CFRelease( disk );
}

static void __DAStageRepair( DADiskRef disk )
{
    /*
     * We commence the "repair" stage if the conditions are right.
     */

    DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );

    if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE )
    {
        struct statfs * mountList;
        int             mountListCount;
        int             mountListIndex;

        /*
         * Determine whether the disk is mounted.
         */

        mountListCount = getmntinfo( &mountList, MNT_NOWAIT );

        for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
        {
            if ( mountList[mountListIndex].f_fsid.val[0] == DADiskGetBSDNode( disk ) )
            {
                /*
                 * We have determined that the disk is mounted.
                 */

                CFURLRef path;

                path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault,
                                                                mountList[mountListIndex].f_mntonname,
                                                                strlen( mountList[mountListIndex].f_mntonname ),
                                                                TRUE );

                if ( path )
                {
                    _DAMountCreateTrashFolder( disk, 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, kDADiskStateRequireRepair,       FALSE );
                DADiskSetState( disk, kDADiskStateRequireRepairQuotas, FALSE );

                break;
            }
        }

        /*
         * Commence the repair.
         */

        DADiskSetState( disk, kDADiskStateStagedRepair, TRUE );

        if ( DADiskGetState( disk, kDADiskStateRequireRepair ) )
        {
            CFRetain( disk );

            DADiskSetState( disk, kDADiskStateCommandActive, TRUE );

            DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE );

            DALogDebug( "  repaired disk, id = %@, ongoing.", disk );

            DAFileSystemRepair( DADiskGetFileSystem( disk ), DADiskGetDevice( disk ), __DAStageRepairCallback, disk );
        }
        else
        {
            DAStageSignal( );
        }
    }
}

static void __DAStageRepairCallback( int status, void * context )
{
    DADiskRef disk = context;

    DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );

    if ( status )
    {
        /*
         * We were unable to repair the volume.
         */

        DALogDebug( "  repaired disk, id = %@, failure.", disk );

        DALogError( "unable to repair %@ (status code 0x%08X).", disk, status );
    }
    else
    {
        /*
         * We were able to repair the volume.
         */

        DADiskSetState( disk, kDADiskStateRequireRepair, FALSE );

        DALogDebug( "  repaired disk, id = %@, success.", disk );
    }

    DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE );

    DADiskSetState( disk, kDADiskStateCommandActive, FALSE );

    DAStageSignal( );

    /*
     * Release our resources.
     */

    CFRelease( disk );
}

CFRunLoopSourceRef DAStageCreateRunLoopSource( CFAllocatorRef allocator, CFIndex order )
{
    /*
     * Create a CFRunLoopSource for DAStage signals.
     */

    if ( __gDAStageRunLoopSource == NULL )
    {
        CFRunLoopSourceContext context = { 0 };

        context.perform = __DAStageDispatch;

        __gDAStageRunLoopSource = CFRunLoopSourceCreate( allocator, order, &context );
    }

    if ( __gDAStageRunLoopSource )
    {
        CFRetain( __gDAStageRunLoopSource );
    }

    return __gDAStageRunLoopSource;
}

void DAStageSignal( void )
{
    /*
     * Signal DAStage.
     */

    gDAIdle = FALSE;

    CFRunLoopSourceSignal( __gDAStageRunLoopSource );
}
