DAMount.c   [plain text]


/*
 * Copyright (c) 1998-2013 Apple 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 "DAMount.h"

#include "DABase.h"
#include "DAInternal.h"
#include "DALog.h"
#include "DAMain.h"
#include "DASupport.h"

#include <fstab.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>

struct __DAMountCallbackContext
{
///w:start
    Boolean         automatic;
///w:stop
    DAMountCallback callback;
    void *          callbackContext;
    DADiskRef       disk;
    Boolean         force;
    CFURLRef        mountpoint;
    CFStringRef     options;
};

typedef struct __DAMountCallbackContext __DAMountCallbackContext;

static void __DAMountWithArgumentsCallbackStage1( int status, void * context );
static void __DAMountWithArgumentsCallbackStage2( int status, void * context );
static void __DAMountWithArgumentsCallbackStage3( int status, void * context );

static void __DAMountWithArgumentsCallback( int status, void * parameter )
{
    /*
     * Process the mount request completion.
     */

    __DAMountCallbackContext * context = parameter;

///w:start
    if ( context->automatic )
    {
        if ( status == ___EDIRTY )
        {
            DAMountWithArguments( context->disk, NULL, context->callback, context->callbackContext, kDAFileSystemMountArgumentForce, kDAFileSystemMountArgumentNoWrite, NULL );

            context->callback = NULL;
        }
    }
///w:stop
    if ( context->callback )
    {
        ( context->callback )( status, context->mountpoint, context->callbackContext );
    }

    CFRelease( context->disk    );
    CFRelease( context->options );

    if ( context->mountpoint )  CFRelease( context->mountpoint );

    free( context );
}

static void __DAMountWithArgumentsCallbackStage1( int status, void * parameter )
{
    /*
     * Process the repair command's completion.
     */

    __DAMountCallbackContext * context = parameter;

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

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

        if ( status == ECANCELED )
        {
            status = 0;
        }
        else
        {
            DALogDebug( "  repaired disk, id = %@, failure.", context->disk );

            DALogError( "unable to repair %@ (status code 0x%08X).", context->disk, status );

            if ( context->force )
            {
                status = 0;
            }
            else
            {
                __DAMountWithArgumentsCallback( ___EDIRTY, context );
            }
        }
    }
    else
    {
        /*
         * We were able to repair the volume.
         */

        DADiskSetState( context->disk, kDADiskStateRequireRepair, FALSE );

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

    /*
     * Mount the volume.
     */

    if ( status == 0 )
    {
        /*
         * Create the mount point, in case one needs to be created.
         */

        if ( context->mountpoint == NULL )
        {
            context->mountpoint = DAMountCreateMountPointWithAction( context->disk, kDAMountPointActionMake );
        }

        /*
         * Execute the mount command.
         */

        if ( context->mountpoint )
        {
            DALogDebug( "  mounted disk, id = %@, ongoing.", context->disk );

            DAFileSystemMountWithArguments( DADiskGetFileSystem( context->disk ),
                                            DADiskGetDevice( context->disk ),
                                            context->mountpoint,
                                            DADiskGetUserUID( context->disk ),
                                            DADiskGetUserGID( context->disk ),
                                            __DAMountWithArgumentsCallbackStage2,
                                            context,
                                            context->options,
                                            NULL );
        }
        else
        {
            __DAMountWithArgumentsCallback( ENOSPC, context );
        }
    }
}

static void __DAMountWithArgumentsCallbackStage2( int status, void * parameter )
{
    /*
     * Process the mount command's completion.
     */

    __DAMountCallbackContext * context = parameter;

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

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

        DALogDebug( "  mounted disk, id = %@, failure.", context->disk );

        DALogError( "unable to mount %@ (status code 0x%08X).", context->disk, status );

        DAMountRemoveMountPoint( context->mountpoint );

        __DAMountWithArgumentsCallback( status, context );
    }
    else
    {
        /*
         * We were able to mount the volume.
         */

        DALogDebug( "  mounted disk, id = %@, success.", context->disk );

        _DAMountCreateTrashFolder( context->disk, context->mountpoint );

        /*
         * Execute the "repair quotas" command.
         */

        if ( DADiskGetState( context->disk, kDADiskStateRequireRepairQuotas ) )
        {
            DAFileSystemRepairQuotas( DADiskGetFileSystem( context->disk ),
                                      context->mountpoint,
                                      __DAMountWithArgumentsCallbackStage3,
                                      context );
        }
        else
        {
            __DAMountWithArgumentsCallbackStage3( 0, context );
        }
    }
}

static void __DAMountWithArgumentsCallbackStage3( int status, void * parameter )
{
    /*
     * Process the "repair quotas" command's completion.
     */

    __DAMountCallbackContext * context = parameter;

    if ( status )
    {
        DALogError( "unable to repair quotas on disk %@ (status code 0x%08X).", context->disk, status );
    }
    else
    {
        DADiskSetState( context->disk, kDADiskStateRequireRepairQuotas, FALSE );
    }

    __DAMountWithArgumentsCallback( 0, context );
}

void _DAMountCreateTrashFolder( DADiskRef disk, CFURLRef mountpoint )
{
    /*
     * Create the trash folder in which the user trashes will be stored.
     */

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

    if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanTrue )
    {
        char path[MAXPATHLEN];

        /*
         * Obtain the mount point path.
         */

        if ( CFURLGetFileSystemRepresentation( mountpoint, TRUE, ( void * ) path, sizeof( path ) ) )
        {
            struct stat status;

            /*
             * Determine whether the trash folder exists.
             */

            strlcat( path, "/.Trashes", sizeof( path ) );

            if ( stat( path, &status ) )
            {
                /*
                 * Create the trash folder.
                 */

                if ( ___mkdir( path, 01333 ) == 0 )
                {
                    /*
                     * Correct the trash folder's attributes.
                     */

                    ___chattr( path, ___ATTR_INVISIBLE, 0 );
                }
            }
        }
    }
}

void DAMount( DADiskRef disk, CFURLRef mountpoint, DAMountCallback callback, void * callbackContext )
{
    /*
     * Mount the specified volume.  A status of 0 indicates success.
     */

    return DAMountWithArguments( disk, mountpoint, callback, callbackContext, NULL );

}

Boolean DAMountContainsArgument( CFStringRef arguments, CFStringRef argument )
{
    CFBooleanRef argumentValue;
    CFBooleanRef argumentsValue;

    argumentsValue = NULL;

    if ( CFStringHasPrefix( argument, CFSTR( "no" ) ) )
    {
        argument      = CFStringCreateWithSubstring( kCFAllocatorDefault, argument, CFRangeMake( 2, CFStringGetLength( argument ) - 2 ) );
        argumentValue = kCFBooleanFalse;
    }
    else
    {
        argument      = CFRetain( argument );
        argumentValue = kCFBooleanTrue;
    }

    if ( argument )
    {
        CFArrayRef argumentList;
        CFIndex    argumentListCount;
        CFIndex    argumentListIndex;

        argumentList = CFStringCreateArrayBySeparatingStrings( kCFAllocatorDefault, arguments, CFSTR( "," ) );

        if ( argumentList )
        {
            argumentListCount = CFArrayGetCount( argumentList );

            for ( argumentListIndex = 0; argumentListIndex < argumentListCount; argumentListIndex++ )
            {
                CFStringRef compare;

                compare = CFArrayGetValueAtIndex( argumentList, argumentListIndex );

                if ( compare )
                {
                    CFBooleanRef compareValue;

                    if ( CFStringHasPrefix( compare, CFSTR( "no" ) ) )
                    {
                        compare      = CFStringCreateWithSubstring( kCFAllocatorDefault, compare, CFRangeMake( 2, CFStringGetLength( compare ) - 2 ) );
                        compareValue = kCFBooleanFalse;
                    }
                    else
                    {
                        compare      = CFRetain( compare );
                        compareValue = kCFBooleanTrue;
                    }

                    if ( compare )
                    {
                        if ( CFEqual( compare, CFSTR( FSTAB_RO ) ) )
                        {
                            CFRelease( compare );

                            compare      = CFRetain( kDAFileSystemMountArgumentNoWrite );
                            compareValue = compareValue;
                        }

                        if ( CFEqual( compare, CFSTR( FSTAB_RW ) ) )
                        {
                            CFRelease( compare );

                            compare      = CFRetain( kDAFileSystemMountArgumentNoWrite );
                            compareValue = ( compareValue == kCFBooleanTrue ) ? kCFBooleanFalse : kCFBooleanTrue;
                        }
                    }

                    if ( compare )
                    {
                        if ( CFEqual( argument, compare ) )
                        {
                            argumentsValue = compareValue;
                        }

                        CFRelease( compare );
                    }
                }
            }

            CFRelease( argumentList );
        }

        CFRelease( argument );
    }

    return ( argumentValue == argumentsValue ) ? TRUE : FALSE;
}

CFURLRef DAMountCreateMountPoint( DADiskRef disk )
{
    return DAMountCreateMountPointWithAction( disk, kDAMountPointActionMake );
}

CFURLRef DAMountCreateMountPointWithAction( DADiskRef disk, DAMountPointAction action )
{
    FILE *      file;
    CFIndex     index;
    CFURLRef    mountpoint;
    char        name[MAXPATHLEN];
    char        path[MAXPATHLEN];
    CFStringRef string;

    mountpoint = NULL;

    /*
     * Obtain the volume name.
     */

    string = DADiskGetDescription( disk, kDADiskDescriptionVolumeNameKey );

    if ( string )
    {
        if ( CFStringGetLength( string ) )
        {
            CFRetain( string );
        }
        else
        {
            string = NULL;
        }
    }

    if ( string == NULL )
    {
        string = ___CFBundleCopyLocalizedStringInDirectory( gDABundlePath, CFSTR( "Untitled" ), CFSTR( "Untitled" ), NULL );
    }

    if ( ___CFStringGetCString( string, name, MNAMELEN - 20 ) )
    {
        /*
         * Adjust the volume name.
         */

        while ( strchr( name, '/' ) )
        {
            *strchr( name, '/' ) = ':';
        }

        /*
         * Create the mount point path.
         */

        for ( index = 0; index < 100; index++ )
        {
            if ( index == 0 )
            {
                snprintf( path, sizeof( path ), "%s/%s", kDAMainMountPointFolder, name );
            }
            else
            {
                snprintf( path, sizeof( path ), "%s/%s %lu", kDAMainMountPointFolder, name, index );
            }

            switch ( action )
            {
                case kDAMountPointActionLink:
                {
                    /*
                     * Link the mount point.
                     */

                    CFURLRef url;

                    url = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey );

                    if ( url )
                    {
                        char source[MAXPATHLEN];

                        if ( CFURLGetFileSystemRepresentation( url, TRUE, ( void * ) source, sizeof( source ) ) )
                        {
                            if ( symlink( source, path ) == 0 )
                            {
                                mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE );
                            }
                        }
                    }

                    break;
                }
                case kDAMountPointActionMake:
                {
                    /*
                     * Create the mount point.
                     */

                    if ( mkdir( path, 0111 ) == 0 )
                    {
                        if ( DADiskGetUserUID( disk ) )
                        {
                            chown( path, DADiskGetUserUID( disk ), -1 );
                        }

                        mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE );

                        /*
                         * Create the mount point cookie file.
                         */

                        strlcat( path, "/",                               sizeof( path ) );
                        strlcat( path, kDAMainMountPointFolderCookieFile, sizeof( path ) );

                        file = fopen( path, "w" );

                        if ( file )
                        {
                            fclose( file );
                        }
                    }

                    break;
                }
                case kDAMountPointActionMove:
                {
                    /*
                     * Move the mount point.
                     */

                    CFURLRef url;

                    url = DADiskGetBypath( disk );

                    if ( url )
                    {
                        char source[MAXPATHLEN];

                        if ( CFURLGetFileSystemRepresentation( url, TRUE, ( void * ) source, sizeof( source ) ) )
                        {
                            if ( rename( source, path ) == 0 )
                            {
                                mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE );
                            }
                        }
                    }

                    break;
                }
                case kDAMountPointActionNone:
                {
                    mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE );

                    break;
                }
            }

            if ( mountpoint )
            {
                break;
            }
        }
    }

    CFRelease( string );

    return mountpoint;
}

Boolean DAMountGetPreference( DADiskRef disk, DAMountPreference preference )
{
    CFBooleanRef value;

    switch ( preference )
    {
        case kDAMountPreferenceDefer:
        {
            /*
             * Determine whether the media is removable.
             */

            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue )
            {
                value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey );

                value = value ? value : kCFBooleanTrue;
            }
            else
            {
                /*
                 * Determine whether the device is internal.
                 */

                if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
                {
                    value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferInternalKey );

                    value = value ? value : kCFBooleanFalse;
                }
                else
                {
                    value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey );

                    value = value ? value : kCFBooleanTrue;
                }
            }

            break;
        }
        case kDAMountPreferenceTrust:
        {
            /*
             * Determine whether the media is removable.
             */

            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue )
            {
                value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustRemovableKey );

                value = value ? value : kCFBooleanFalse;
            }
            else
            {
                /*
                 * Determine whether the device is internal.
                 */

                if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
                {
                    value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustInternalKey );

                    value = value ? value : kCFBooleanTrue;
                }
                else
                {
                    value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey );

                    value = value ? value : kCFBooleanFalse;
                }
            }

            break;
        }
        case kDAMountPreferenceWrite:
        {
            value = kCFBooleanTrue;
///w:start
            if ( DADiskGetState( disk, _kDADiskStateMountPreferenceNoWrite ) )
            {
                DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, FALSE );

                value = kCFBooleanFalse;
            }
///w:stop

            break;
        }
        default:
        {
            value = kCFBooleanFalse;

            break;
        }
    }

    assert( value );

    return CFBooleanGetValue( value );
}

void DAMountRemoveMountPoint( CFURLRef mountpoint )
{
    char path[MAXPATHLEN];

    /*
     * Obtain the mount point path.
     */

    if ( CFURLGetFileSystemRepresentation( mountpoint, TRUE, ( void * ) path, sizeof( path ) ) )
    {
        if ( ___isautofs( path ) == 0 )
        {
            Boolean remove;

            remove = FALSE;

            if ( strncmp( path, kDAMainMountPointFolder, strlen( kDAMainMountPointFolder ) ) == 0 )
            {
                if ( strrchr( path + strlen( kDAMainMountPointFolder ), '/' ) == path + strlen( kDAMainMountPointFolder ) )
                {
                    remove = TRUE;
                }
            }

///w:start
//          if ( remove == FALSE )
///w:stop
            {
                char file[MAXPATHLEN];

                strlcpy( file, path,                              sizeof( file ) );
                strlcat( file, "/",                               sizeof( file ) );
                strlcat( file, kDAMainMountPointFolderCookieFile, sizeof( file ) );

                /*
                 * Remove the mount point cookie file.
                 */

                if ( unlink( file ) == 0 )
                {
                    remove = TRUE;
                }
            }

            if ( remove )
            {
                /*
                 * Remove the mount point.
                 */

                rmdir( path );
            }
        }
    }
}

void DAMountWithArguments( DADiskRef disk, CFURLRef mountpoint, DAMountCallback callback, void * callbackContext, ... )
{
    /*
     * Mount the specified volume.  A status of 0 indicates success.  All arguments in
     * the argument list shall be of type CFStringRef.  The argument list must be NULL
     * terminated.
     */

    CFStringRef                argument   = NULL;
    va_list                    arguments;
    CFBooleanRef               automatic  = kCFBooleanTrue;
    CFBooleanRef               check      = NULL;
    __DAMountCallbackContext * context    = NULL;
    CFIndex                    count      = 0;
    DAFileSystemRef            filesystem = DADiskGetFileSystem( disk );
    Boolean                    force      = FALSE;
    CFIndex                    index      = 0;
    CFDictionaryRef            map        = NULL;
    CFMutableStringRef         options    = NULL;
    int                        status     = 0;

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

    /*
     * Initialize our minimal state.
     */

    if ( mountpoint )
    {
        CFRetain( mountpoint );
    }

    /*
     * Prepare the mount context.
     */

    context = malloc( sizeof( __DAMountCallbackContext ) );

    if ( context == NULL )
    {
        status = ENOMEM;

        goto DAMountWithArgumentsErr;
    }

    /*
     * Prepare the mount options.
     */

    options = CFStringCreateMutable( kCFAllocatorDefault, 0 );

    if ( options == NULL )
    {
        status = ENOMEM;

        goto DAMountWithArgumentsErr;
    }

    va_start( arguments, callbackContext );

    while ( ( argument = va_arg( arguments, CFStringRef ) ) )
    {
        if ( CFEqual( argument, kDAFileSystemMountArgumentForce ) )
        {
            force = TRUE;
        }
        else
        {
            CFStringAppend( options, argument );
            CFStringAppend( options, CFSTR( "," ) );
        }
    }

    va_end( arguments );

    CFStringTrim( options, CFSTR( "," ) );

    if ( CFEqual( options, CFSTR( "automatic" ) ) )
    {
        automatic = NULL;

        check = kCFBooleanTrue;

        CFStringReplaceAll( options, CFSTR( "" ) );
    }
///w:start
    context->automatic = ( automatic == NULL ) ? TRUE : FALSE;
///w:stop

    /*
     * Determine whether the volume is to be updated.
     */

    if ( DAMountContainsArgument( options, kDAFileSystemMountArgumentUpdate ) )
    {
        if ( mountpoint )
        {
            status = EINVAL;

            goto DAMountWithArgumentsErr;
        }

        mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey );

        if ( mountpoint == NULL )
        {
            status = EINVAL;

            goto DAMountWithArgumentsErr;
        }

        CFRetain( mountpoint );
    }

    /*
     * Scan the mount map list.
     */

    count = CFArrayGetCount( gDAMountMapList1 );

    for ( index = 0; index < count; index++ )
    {
        map = CFArrayGetValueAtIndex( gDAMountMapList1, index );

        if ( map )
        {
            CFTypeRef   id;
            CFStringRef kind;

            id   = CFDictionaryGetValue( map, kDAMountMapProbeIDKey );
            kind = CFDictionaryGetValue( map, kDAMountMapProbeKindKey );

            if ( kind )
            {
                /*
                 * Determine whether the volume kind matches.
                 */

                if ( CFEqual( kind, DAFileSystemGetKind( filesystem ) ) == FALSE )
                {
                    continue;
                }
            }

            if ( CFGetTypeID( id ) == CFUUIDGetTypeID( ) )
            {
                /*
                 * Determine whether the volume UUID matches.
                 */

                if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeUUIDKey, id ) == kCFCompareEqualTo )
                {
                    break;
                }
            }
            else if ( CFGetTypeID( id ) == CFStringGetTypeID( ) )
            {
                /*
                 * Determine whether the volume name matches.
                 */

                if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeNameKey, id ) == kCFCompareEqualTo )
                {
                    break;
                }
            }
            else if ( CFGetTypeID( id ) == CFDictionaryGetTypeID( ) )
            {
                boolean_t match = FALSE;

                /*
                 * Determine whether the device description matches.
                 */

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

                if ( match )
                {
                    break;
                }
            }
        }
    }

    /*
     * Process the map.
     */

    if ( index < count )
    {
        CFStringRef string;

        /*
         * Determine whether the volume is to be mounted.
         */

        if ( automatic == NULL )
        {
            automatic = CFDictionaryGetValue( map, kDAMountMapMountAutomaticKey );

            if ( automatic == kCFBooleanTrue )
            {
                DADiskSetOption( disk, kDADiskOptionMountAutomatic,        TRUE );
                DADiskSetOption( disk, kDADiskOptionMountAutomaticNoDefer, TRUE );
            }
        }

        /*
         * Prepare the mount options.
         */

        string = CFDictionaryGetValue( map, kDAMountMapMountOptionsKey );

        if ( string )
        {
            CFStringInsert( options, 0, CFSTR( "," ) );
            CFStringInsert( options, 0, string );
        }

        /*
         * Prepare the mount point.
         */

        if ( mountpoint == NULL )
        {
            mountpoint = CFDictionaryGetValue( map, kDAMountMapMountPathKey );

            if ( mountpoint )
            {
                CFRetain( mountpoint );
            }
        }
    }

    /*
     * Scan the mount map list.
     */

    count = CFArrayGetCount( gDAMountMapList2 );

    for ( index = 0; index < count; index++ )
    {
        map = CFArrayGetValueAtIndex( gDAMountMapList2, index );

        if ( map )
        {
            CFTypeRef id;

            id = CFDictionaryGetValue( map, kDAMountMapProbeIDKey );

            /*
             * Determine whether the volume UUID matches.
             */

            if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeUUIDKey, id ) == kCFCompareEqualTo )
            {
                break;
            }
        }
    }

    /*
     * Process the map.
     */

    if ( index < count )
    {
        CFStringRef string;

        /*
         * Prepare the mount options.
         */

        string = CFDictionaryGetValue( map, kDAMountMapMountOptionsKey );

        if ( string )
        {
            CFStringInsert( options, 0, CFSTR( "," ) );
            CFStringInsert( options, 0, string );
        }
    }

    /*
     * Determine whether the volume is to be mounted.
     */

    if ( automatic == NULL )
    {
        if ( DADiskGetOption( disk, kDADiskOptionMountAutomatic ) )
        {
            if ( DADiskGetOption( disk, kDADiskOptionMountAutomaticNoDefer ) )
            {
                automatic = kCFBooleanTrue;
            }
        }
        else
        {
            automatic = kCFBooleanFalse;
        }

        if ( automatic == NULL )
        {
            if ( gDAConsoleUserList == NULL )
            {
                if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) )
                {
                    automatic = kCFBooleanFalse;
                }
            }
        }
    }

    if ( automatic == kCFBooleanFalse )
    {
        status = ECANCELED;

        goto DAMountWithArgumentsErr;
    }

    /*
     * Prepare the mount options.
     */

    if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse )
    {
        CFStringInsert( options, 0, CFSTR( "," ) );
        CFStringInsert( options, 0, kDAFileSystemMountArgumentNoWrite );
    }

    if ( DAMountGetPreference( disk, kDAMountPreferenceWrite ) == FALSE )
    {
        CFStringInsert( options, 0, CFSTR( "," ) );
        CFStringInsert( options, 0, kDAFileSystemMountArgumentNoWrite );
    }

    if ( DAMountGetPreference( disk, kDAMountPreferenceTrust ) == FALSE )
    {
        CFStringInsert( options, 0, CFSTR( "," ) );
        CFStringInsert( options, 0, kDAFileSystemMountArgumentNoSetUserID );

        CFStringInsert( options, 0, CFSTR( "," ) );
        CFStringInsert( options, 0, kDAFileSystemMountArgumentNoOwnership );

        CFStringInsert( options, 0, CFSTR( "," ) );
        CFStringInsert( options, 0, kDAFileSystemMountArgumentNoDevice );
    }
///w:start
    if ( CFEqual( DAFileSystemGetKind( filesystem ), CFSTR( "hfs" ) ) )
    {
        ___CFStringInsertFormat( options, 0, CFSTR( "-m=%o," ), 0755 );

        if ( DADiskGetUserGID( disk ) )
        {
            ___CFStringInsertFormat( options, 0, CFSTR( "-g=%d," ), DADiskGetUserGID( disk ) );
        }
        else
        {
            ___CFStringInsertFormat( options, 0, CFSTR( "-g=%d," ), ___GID_UNKNOWN );
        }

        if ( DADiskGetUserUID( disk ) )
        {
            ___CFStringInsertFormat( options, 0, CFSTR( "-u=%d," ), DADiskGetUserUID( disk ) );
        }
        else
        {
            ___CFStringInsertFormat( options, 0, CFSTR( "-u=%d," ), ___UID_UNKNOWN );
        }
    }
///w:stop

    CFStringTrim( options, CFSTR( "," ) );

    /*
     * Determine whether the volume is to be repaired.
     */

    if ( check == NULL )
    {
        if ( DAMountContainsArgument( options, kDAFileSystemMountArgumentNoWrite ) )
        {
            check = kCFBooleanFalse;
        }
        else
        {
            check = kCFBooleanTrue;
        }
    }

    if ( check == kCFBooleanFalse )
    {
        if ( DADiskGetState( disk, kDADiskStateRequireRepair ) )
        {
            if ( force == FALSE )
            {
                status = ___EDIRTY;

                goto DAMountWithArgumentsErr;
            }
        }
    }

    if ( check == kCFBooleanTrue )
    {
        if ( DADiskGetState( disk, kDADiskStateRequireRepair ) == FALSE )
        {
            check = kCFBooleanFalse;
        }
    }

    /*
     * Repair the volume.
     */

    CFRetain( disk );

    context->callback        = callback;
    context->callbackContext = callbackContext;
    context->disk            = disk;
    context->force           = force;
    context->mountpoint      = mountpoint;
    context->options         = options;

    if ( check == kCFBooleanTrue )
    {
        DALogDebug( "  repaired disk, id = %@, ongoing.", disk );

        DAFileSystemRepair( DADiskGetFileSystem( disk ),
                            DADiskGetDevice( disk ),
                            __DAMountWithArgumentsCallbackStage1,
                            context );
    }
    else
    {
        __DAMountWithArgumentsCallbackStage1( ECANCELED, context );
    }

DAMountWithArgumentsErr:

    if ( status )
    {
        if ( context )
        {
            free( context );
        }

        if ( mountpoint )
        {
            CFRelease( mountpoint );
        }

        if ( options )
        {
            CFRelease( options );
        }

        if ( callback )
        {
            ( callback )( status, NULL, callbackContext );
        }
    }
}