1/*
2 * Copyright (c) 1998-2013 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#include "DiskArbitration.h"
25
26#include "DiskArbitrationPrivate.h"
27#include "DAInternal.h"
28#include "DAServer.h"
29
30#include <pthread.h>
31#include <unistd.h>
32#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
33#include <Security/Authorization.h>
34
35CFDictionaryRef kDADiskDescriptionMatchMediaUnformatted   = NULL;
36CFDictionaryRef kDADiskDescriptionMatchMediaWhole         = NULL;
37CFDictionaryRef kDADiskDescriptionMatchVolumeMountable    = NULL;
38CFDictionaryRef kDADiskDescriptionMatchVolumeUnrecognized = NULL;
39
40CFArrayRef kDADiskDescriptionWatchVolumeName = NULL;
41CFArrayRef kDADiskDescriptionWatchVolumePath = NULL;
42
43__private_extern__ char *      _DADiskGetID( DADiskRef disk );
44__private_extern__ mach_port_t _DADiskGetSessionID( DADiskRef disk );
45__private_extern__ void        _DADiskInitialize( void );
46__private_extern__ void        _DADiskSetDescription( DADiskRef disk, CFDictionaryRef description );
47
48__private_extern__ AuthorizationRef _DASessionGetAuthorization( DASessionRef session );
49__private_extern__ mach_port_t      _DASessionGetID( DASessionRef session );
50__private_extern__ void             _DASessionInitialize( void );
51
52static void __DAInitialize( void )
53{
54    CFMutableDictionaryRef match;
55    CFMutableArrayRef      watch;
56
57    /*
58     * Initialize classes.
59     */
60
61    _DADiskInitialize( );
62
63    _DASessionInitialize( );
64
65    /*
66     * Create the disk match description for unformatted media.
67     */
68
69    match = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
70
71    assert( match );
72
73    ___CFDictionarySetIntegerValue( match, kDADiskDescriptionMediaSizeKey, 0 );
74
75    kDADiskDescriptionMatchMediaUnformatted = match;
76
77    /*
78     * Create the disk match description for whole media.
79     */
80
81    match = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
82
83    assert( match );
84
85    CFDictionarySetValue( match, kDADiskDescriptionMediaWholeKey, kCFBooleanTrue );
86
87    kDADiskDescriptionMatchMediaWhole = match;
88
89    /*
90     * Create the disk match description for mountable volumes.
91     */
92
93    match = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
94
95    assert( match );
96
97    CFDictionarySetValue( match, kDADiskDescriptionVolumeMountableKey, kCFBooleanTrue );
98
99    kDADiskDescriptionMatchVolumeMountable = match;
100
101    /*
102     * Create the disk match description for unrecognized volumes.
103     */
104
105    match = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
106
107    assert( match );
108
109    CFDictionarySetValue( match, kDADiskDescriptionVolumeMountableKey, kCFBooleanFalse );
110
111    kDADiskDescriptionMatchVolumeUnrecognized = match;
112
113    /*
114     * Create the disk watch description for volume name changes.
115     */
116
117    watch = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
118
119    assert( watch );
120
121    CFArrayAppendValue( watch, kDADiskDescriptionVolumeNameKey );
122
123    kDADiskDescriptionWatchVolumeName = watch;
124
125    /*
126     * Create the disk watch description for volume path changes.
127     */
128
129    watch = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
130
131    assert( watch );
132
133    CFArrayAppendValue( watch, kDADiskDescriptionVolumePathKey );
134
135    kDADiskDescriptionWatchVolumePath = watch;
136}
137
138static DAReturn __DAQueueRequest( DASessionRef   session,
139                                  _DARequestKind kind,
140                                  DADiskRef      argument0,
141                                  CFIndex        argument1,
142                                  CFTypeRef      argument2,
143                                  CFTypeRef      argument3,
144                                  void *         address,
145                                  void *         context )
146{
147    DAReturn status;
148
149    status = kDAReturnBadArgument;
150
151    if ( session )
152    {
153        CFDataRef _argument2 = NULL;
154        CFDataRef _argument3 = NULL;
155
156        if ( argument2 )  _argument2 = _DASerialize( kCFAllocatorDefault, argument2 );
157        if ( argument3 )  _argument3 = _DASerialize( kCFAllocatorDefault, argument3 );
158
159        status = _DAServerSessionQueueRequest( _DASessionGetID( session ),
160                                               ( int32_t                ) kind,
161                                               ( caddr_t                ) _DADiskGetID( argument0 ),
162                                               ( int32_t                ) argument1,
163                                               ( vm_address_t           ) ( _argument2 ? CFDataGetBytePtr( _argument2 ) : 0 ),
164                                               ( mach_msg_type_number_t ) ( _argument2 ? CFDataGetLength(  _argument2 ) : 0 ),
165                                               ( vm_address_t           ) ( _argument3 ? CFDataGetBytePtr( _argument3 ) : 0 ),
166                                               ( mach_msg_type_number_t ) ( _argument3 ? CFDataGetLength(  _argument3 ) : 0 ),
167                                               ( uintptr_t              ) address,
168                                               ( uintptr_t              ) context );
169
170        if ( _argument2 )  CFRelease( _argument2 );
171        if ( _argument3 )  CFRelease( _argument3 );
172    }
173
174    return status;
175}
176
177static void __DAQueueResponse( DASessionRef    session,
178                               void *          address,
179                               void *          context,
180                               _DACallbackKind kind,
181                               DADiskRef       disk,
182                               CFTypeRef       response,
183                               SInt32          responseID )
184{
185    CFDataRef _response = NULL;
186
187    if ( response )  _response = _DASerialize( kCFAllocatorDefault, response );
188
189    _DAServerSessionQueueResponse( _DASessionGetID( session ),
190                                   ( uintptr_t              ) address,
191                                   ( uintptr_t              ) context,
192                                   ( int32_t                ) kind,
193                                   ( caddr_t                ) _DADiskGetID( disk ),
194                                   ( vm_address_t           ) ( _response ? CFDataGetBytePtr( _response ) : 0 ),
195                                   ( mach_msg_type_number_t ) ( _response ? CFDataGetLength(  _response ) : 0 ),
196                                   ( int32_t                ) responseID );
197
198    if ( _response )  CFRelease( _response );
199}
200
201__private_extern__ DAReturn _DAAuthorize( DASessionRef session, _DAAuthorizeOptions options, DADiskRef disk, const char * right )
202{
203    DAReturn status;
204
205    status = kDAReturnNotPrivileged;
206
207    if ( status )
208    {
209        if ( ( options & _kDAAuthorizeOptionIsOwner ) )
210        {
211            uid_t diskUID;
212
213            status = _DAServerDiskGetUserUID( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), &diskUID );
214
215            if ( status )
216            {
217                return status;
218            }
219
220            status = kDAReturnNotPrivileged;
221
222            if ( diskUID == geteuid( ) )
223            {
224                status = kDAReturnSuccess;
225            }
226        }
227    }
228
229    if ( status )
230    {
231        AuthorizationRef authorization;
232
233        authorization = _DASessionGetAuthorization( session );
234
235        if ( authorization )
236        {
237            CFDictionaryRef description;
238
239            description = DADiskCopyDescription( disk );
240
241            if ( description )
242            {
243                AuthorizationFlags  flags;
244                AuthorizationItem   item;
245                char *              name;
246                AuthorizationRights rights;
247
248                flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize;
249
250                if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumeNetworkKey ) == kCFBooleanTrue )
251                {
252                    asprintf( &name, "system.volume.network.%s", right );
253                }
254                else
255                {
256                    CFTypeRef object;
257
258                    object = CFDictionaryGetValue( description, kDADiskDescriptionDeviceProtocolKey );
259
260                    if ( object && CFEqual( object, CFSTR( kIOPropertyPhysicalInterconnectTypeVirtual ) ) )
261                    {
262                        asprintf( &name, "system.volume.virtual.%s", right );
263                    }
264                    else
265                    {
266                        if ( CFDictionaryGetValue( description, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue )
267                        {
268                            if ( CFDictionaryGetValue( description, kDADiskDescriptionMediaTypeKey ) )
269                            {
270                                asprintf( &name, "system.volume.optical.%s", right );
271                            }
272                            else
273                            {
274                                asprintf( &name, "system.volume.removable.%s", right );
275                            }
276                        }
277                        else
278                        {
279                            if ( CFDictionaryGetValue( description, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
280                            {
281                                asprintf( &name, "system.volume.internal.%s", right );
282                            }
283                            else
284                            {
285                                asprintf( &name, "system.volume.external.%s", right );
286                            }
287                        }
288                    }
289                }
290
291                if ( name )
292                {
293                    item.flags       = 0;
294                    item.name        = name;
295                    item.value       = NULL;
296                    item.valueLength = 0;
297
298                    rights.count = 1;
299                    rights.items = &item;
300
301                    status = AuthorizationCopyRights( authorization, &rights, NULL, flags, NULL );
302
303                    if ( status )
304                    {
305                        status = kDAReturnNotPrivileged;
306                    }
307
308                    free( name );
309                }
310
311                CFRelease( description );
312            }
313        }
314    }
315
316    return status;
317}
318
319__private_extern__ void _DADispatchCallback( DASessionRef    session,
320                                             void *          address,
321                                             void *          context,
322                                             _DACallbackKind kind,
323                                             CFTypeRef       argument0,
324                                             CFTypeRef       argument1 )
325{
326    DADiskRef disk     = NULL;
327    CFTypeRef response = NULL;
328
329    if ( argument0 )
330    {
331        disk = _DADiskCreateFromSerialization( CFGetAllocator( session ), session, argument0 );
332    }
333
334    switch ( kind )
335    {
336        case _kDADiskAppearedCallback:
337        {
338            ( ( DADiskAppearedCallback ) address )( disk, context );
339
340            break;
341        }
342        case _kDADiskClaimCallback:
343        {
344            ( ( DADiskClaimCallback ) address )( disk, argument1, context );
345
346            break;
347        }
348        case _kDADiskClaimReleaseCallback:
349        {
350            response = ( ( DADiskClaimReleaseCallback ) address )( disk, context );
351
352            response = response ? response : kCFNull;
353
354            break;
355        }
356        case _kDADiskDescriptionChangedCallback:
357        {
358            ( ( DADiskDescriptionChangedCallback ) address )( disk, argument1, context );
359
360            break;
361        }
362        case _kDADiskDisappearedCallback:
363        {
364            ( ( DADiskDisappearedCallback ) address )( disk, context );
365
366            break;
367        }
368        case _kDADiskEjectCallback:
369        {
370            ( ( DADiskEjectCallback ) address )( disk, argument1, context );
371
372            break;
373        }
374        case _kDADiskEjectApprovalCallback:
375        {
376            response = ( ( DADiskEjectApprovalCallback ) address )( disk, context );
377
378            response = response ? response : kCFNull;
379
380            break;
381        }
382        case _kDADiskMountCallback:
383        {
384            ( ( DADiskMountCallback ) address )( disk, argument1, context );
385
386            break;
387        }
388        case _kDADiskMountApprovalCallback:
389        {
390            response = ( ( DADiskMountApprovalCallback ) address )( disk, context );
391
392            response = response ? response : kCFNull;
393
394            break;
395        }
396        case _kDADiskPeekCallback:
397        {
398            ( ( DADiskPeekCallback ) address )( disk, context );
399
400            response = kCFNull;
401
402            break;
403        }
404        case _kDADiskRenameCallback:
405        {
406            ( ( DADiskRenameCallback ) address )( disk, argument1, context );
407
408            break;
409        }
410        case _kDADiskUnmountCallback:
411        {
412            ( ( DADiskUnmountCallback ) address )( disk, argument1, context );
413
414            break;
415        }
416        case _kDADiskUnmountApprovalCallback:
417        {
418            response = ( ( DADiskUnmountApprovalCallback ) address )( disk, context );
419
420            response = response ? response : kCFNull;
421
422            break;
423        }
424        case _kDAIdleCallback:
425        {
426            ( ( DAIdleCallback ) address )( context );
427
428            break;
429        }
430    }
431
432    if ( response )
433    {
434        SInt32 responseID;
435
436        responseID = ___CFNumberGetIntegerValue( argument1 );
437
438        if ( response == kCFNull )
439        {
440            response = NULL;
441        }
442
443        __DAQueueResponse( session, address, context, kind, disk, response, responseID );
444
445        if ( response )
446        {
447            CFRelease( response );
448        }
449    }
450
451    if ( disk )
452    {
453        _DADiskSetDescription( disk, NULL );
454
455        CFRelease( disk );
456    }
457}
458
459__private_extern__ void _DAInitialize( void )
460{
461    static pthread_once_t initialize = PTHREAD_ONCE_INIT;
462
463    pthread_once( &initialize, __DAInitialize );
464}
465
466__private_extern__ void _DARegisterCallback( DASessionRef    session,
467                                             void *          address,
468                                             void *          context,
469                                             _DACallbackKind kind,
470                                             CFIndex         order,
471                                             CFDictionaryRef match,
472                                             CFArrayRef      watch )
473{
474    if ( session )
475    {
476        CFDataRef _match = NULL;
477        CFDataRef _watch = NULL;
478
479        if ( match )  _match = _DASerializeDiskDescription( kCFAllocatorDefault, match );
480        if ( watch )  _watch = _DASerialize( kCFAllocatorDefault, watch );
481
482        _DAServerSessionRegisterCallback( _DASessionGetID( session ),
483                                          ( uintptr_t              ) address,
484                                          ( uintptr_t              ) context,
485                                          ( int32_t                ) kind,
486                                          ( int32_t                ) order,
487                                          ( vm_address_t           ) ( _match ? CFDataGetBytePtr( _match ) : 0 ),
488                                          ( mach_msg_type_number_t ) ( _match ? CFDataGetLength(  _match ) : 0 ),
489                                          ( vm_address_t           ) ( _watch ? CFDataGetBytePtr( _watch ) : 0 ),
490                                          ( mach_msg_type_number_t ) ( _watch ? CFDataGetLength(  _watch ) : 0 ) );
491
492        if ( _match )  CFRelease( _match );
493        if ( _watch )  CFRelease( _watch );
494    }
495}
496
497__private_extern__ void _DAUnregisterCallback( DASessionRef session, void * address, void * context )
498{
499    if ( session )
500    {
501        _DAServerSessionUnregisterCallback( _DASessionGetID( session ), ( uintptr_t ) address, ( uintptr_t ) context );
502    }
503}
504
505void DADiskClaim( DADiskRef                  disk,
506                  DADiskClaimOptions         options,
507                  DADiskClaimReleaseCallback release,
508                  void *                     releaseContext,
509                  DADiskClaimCallback        callback,
510                  void *                     callbackContext )
511{
512    CFNumberRef _release;
513    CFNumberRef _releaseContext;
514    DAReturn    status;
515
516    status = kDAReturnBadArgument;
517
518    if ( disk )
519    {
520        _release        = ___CFNumberCreateWithIntegerValue( kCFAllocatorDefault, ( uintptr_t ) release        );
521        _releaseContext = ___CFNumberCreateWithIntegerValue( kCFAllocatorDefault, ( uintptr_t ) releaseContext );
522
523        status = __DAQueueRequest( _DADiskGetSession( disk ), _kDADiskClaim, disk, options, _release, _releaseContext, callback, callbackContext );
524
525        if ( _release        )  CFRelease( _release        );
526        if ( _releaseContext )  CFRelease( _releaseContext );
527    }
528
529    if ( status )
530    {
531        if ( callback )
532        {
533            DADissenterRef dissenter;
534
535            dissenter = DADissenterCreate( kCFAllocatorDefault, status, NULL );
536
537            ( callback )( disk, dissenter, callbackContext );
538
539            CFRelease( dissenter );
540        }
541    }
542}
543
544void DADiskEject( DADiskRef disk, DADiskEjectOptions options, DADiskEjectCallback callback, void * context )
545{
546    DAReturn status;
547
548    status = kDAReturnBadArgument;
549
550    if ( disk )
551    {
552        status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionIsOwner, disk, _kDAAuthorizeRightUnmount );
553
554        if ( status == kDAReturnSuccess )
555        {
556            status = __DAQueueRequest( _DADiskGetSession( disk ), _kDADiskEject, disk, options, NULL, NULL, callback, context );
557        }
558    }
559
560    if ( status )
561    {
562        if ( callback )
563        {
564            DADissenterRef dissenter;
565
566            dissenter = DADissenterCreate( kCFAllocatorDefault, status, NULL );
567
568            ( callback )( disk, dissenter, context );
569
570            CFRelease( dissenter );
571        }
572    }
573}
574
575DADiskOptions DADiskGetOptions( DADiskRef disk )
576{
577    int32_t options;
578
579    options = kDADiskOptionDefault;
580
581    if ( disk )
582    {
583        _DAServerDiskGetOptions( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), &options );
584    }
585
586    return options;
587}
588
589Boolean DADiskIsClaimed( DADiskRef disk )
590{
591    boolean_t claimed;
592
593    claimed = FALSE;
594
595    if ( disk )
596    {
597        _DAServerDiskIsClaimed( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), &claimed );
598    }
599
600    return claimed;
601}
602
603void DADiskMount( DADiskRef disk, CFURLRef path, DADiskMountOptions options, DADiskMountCallback callback, void * context )
604{
605    DADiskMountWithArguments( disk, path, options, callback, context, NULL );
606}
607
608void DADiskMountWithArguments( DADiskRef           disk,
609                               CFURLRef            path,
610                               DADiskMountOptions  options,
611                               DADiskMountCallback callback,
612                               void *              context,
613                               CFStringRef         arguments[] )
614{
615    CFMutableStringRef argument;
616    DAReturn           status;
617
618    argument = NULL;
619
620    if ( arguments )
621    {
622        if ( arguments[0] )
623        {
624            if ( arguments[1] )
625            {
626                argument = CFStringCreateMutableCopy( kCFAllocatorDefault, 0, arguments[0] );
627
628                if ( argument )
629                {
630                    CFIndex index;
631
632                    for ( index = 1; arguments[index]; index++ )
633                    {
634                        CFStringAppend( argument, CFSTR( "," ) );
635                        CFStringAppend( argument, arguments[index] );
636                    }
637                }
638            }
639            else
640            {
641                argument = ( void * ) CFRetain( arguments[0] );
642            }
643        }
644    }
645
646    if ( path )
647    {
648        char * _path;
649
650        _path = ___CFURLCopyFileSystemRepresentation( path );
651
652        if ( _path )
653        {
654            char name[MAXPATHLEN];
655
656            if ( realpath( _path, name ) )
657            {
658                path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) name, strlen( name ), TRUE );
659            }
660            else
661            {
662                CFRetain( path );
663            }
664
665            free( _path );
666        }
667        else
668        {
669            CFRetain( path );
670        }
671    }
672
673    status = kDAReturnBadArgument;
674
675    if ( disk )
676    {
677        status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionIsOwner, disk, _kDAAuthorizeRightMount );
678
679        if ( status == kDAReturnSuccess )
680        {
681            status = __DAQueueRequest( _DADiskGetSession( disk ), _kDADiskMount, disk, options, path ? CFURLGetString( path ) : NULL, argument, callback, context );
682        }
683    }
684
685    if ( argument )
686    {
687        CFRelease( argument );
688    }
689
690    if ( path )
691    {
692        CFRelease( path );
693    }
694
695    if ( status )
696    {
697        if ( callback )
698        {
699            DADissenterRef dissenter;
700
701            dissenter = DADissenterCreate( kCFAllocatorDefault, status, NULL );
702
703            ( callback )( disk, dissenter, context );
704
705            CFRelease( dissenter );
706        }
707    }
708}
709
710void DADiskRename( DADiskRef disk, CFStringRef name, DADiskRenameOptions options, DADiskRenameCallback callback, void * context )
711{
712    DAReturn status;
713
714    status = kDAReturnBadArgument;
715
716    if ( disk )
717    {
718        if ( name )
719        {
720            if ( CFGetTypeID( name ) == CFStringGetTypeID( ) )
721            {
722                status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionIsOwner, disk, _kDAAuthorizeRightRename );
723
724                if ( status == kDAReturnSuccess )
725                {
726                    status = __DAQueueRequest( _DADiskGetSession( disk ), _kDADiskRename, disk, options, name, NULL, callback, context );
727                }
728            }
729        }
730    }
731
732    if ( status )
733    {
734        if ( callback )
735        {
736            DADissenterRef dissenter;
737
738            dissenter = DADissenterCreate( kCFAllocatorDefault, status, NULL );
739
740            ( callback )( disk, dissenter, context );
741
742            CFRelease( dissenter );
743        }
744    }
745}
746
747DAReturn DADiskSetOptions( DADiskRef disk, DADiskOptions options, Boolean value )
748{
749    DAReturn status;
750
751    status = kDAReturnBadArgument;
752
753    if ( disk )
754    {
755        status = _DAServerDiskSetOptions( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), options, value );
756    }
757
758    return status;
759}
760
761void DADiskUnmount( DADiskRef disk, DADiskUnmountOptions options, DADiskUnmountCallback callback, void * context )
762{
763    DAReturn status;
764
765    status = kDAReturnBadArgument;
766
767    if ( disk )
768    {
769        status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionIsOwner, disk, _kDAAuthorizeRightUnmount );
770
771        if ( status == kDAReturnSuccess )
772        {
773            status = __DAQueueRequest( _DADiskGetSession( disk ), _kDADiskUnmount, disk, options, NULL, NULL, callback, context );
774        }
775    }
776
777    if ( status )
778    {
779        if ( callback )
780        {
781            DADissenterRef dissenter;
782
783            dissenter = DADissenterCreate( kCFAllocatorDefault, status, NULL );
784
785            ( callback )( disk, dissenter, context );
786
787            CFRelease( dissenter );
788        }
789    }
790}
791
792void DARegisterDiskAppearedCallback( DASessionRef           session,
793                                     CFDictionaryRef        match,
794                                     DADiskAppearedCallback callback,
795                                     void *                 context )
796{
797    _DARegisterCallback( session, callback, context, _kDADiskAppearedCallback, 0, match, NULL );
798}
799
800void DARegisterDiskDescriptionChangedCallback( DASessionRef                     session,
801                                               CFDictionaryRef                  match,
802                                               CFArrayRef                       watch,
803                                               DADiskDescriptionChangedCallback callback,
804                                               void *                           context )
805{
806    _DARegisterCallback( session, callback, context, _kDADiskDescriptionChangedCallback, 0, match, watch );
807}
808
809void DARegisterDiskDisappearedCallback( DASessionRef              session,
810                                        CFDictionaryRef           match,
811                                        DADiskDisappearedCallback callback,
812                                        void *                    context )
813{
814    _DARegisterCallback( session, callback, context, _kDADiskDisappearedCallback, 0, match, NULL );
815}
816
817void DARegisterDiskEjectApprovalCallback( DASessionRef                session,
818                                          CFDictionaryRef             match,
819                                          DADiskEjectApprovalCallback callback,
820                                          void *                      context )
821{
822    _DARegisterCallback( session, callback, context, _kDADiskEjectApprovalCallback, 0, match, NULL );
823}
824
825void DARegisterDiskPeekCallback( DASessionRef        session,
826                                 CFDictionaryRef     match,
827                                 CFIndex             order,
828                                 DADiskPeekCallback  callback,
829                                 void *              context )
830{
831    _DARegisterCallback( session, callback, context, _kDADiskPeekCallback, order, match, NULL );
832}
833
834void DARegisterDiskMountApprovalCallback( DASessionRef                session,
835                                          CFDictionaryRef             match,
836                                          DADiskMountApprovalCallback callback,
837                                          void *                      context )
838{
839    _DARegisterCallback( session, callback, context, _kDADiskMountApprovalCallback, 0, match, NULL );
840}
841
842void DARegisterDiskUnmountApprovalCallback( DASessionRef                  session,
843                                            CFDictionaryRef               match,
844                                            DADiskUnmountApprovalCallback callback,
845                                            void *                        context )
846{
847    _DARegisterCallback( session, callback, context, _kDADiskUnmountApprovalCallback, 0, match, NULL );
848}
849
850void DADiskUnclaim( DADiskRef disk )
851{
852    if ( disk )
853    {
854        _DAServerDiskUnclaim( _DADiskGetSessionID( disk ), _DADiskGetID( disk ) );
855    }
856}
857
858void DAUnregisterCallback( DASessionRef session, void * callback, void * context )
859{
860    _DAUnregisterCallback( session, callback, context );
861}
862
863void DAUnregisterApprovalCallback( DASessionRef session, void * callback, void * context )
864{
865    _DAUnregisterCallback( session, callback, context );
866}
867