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 "DAQueue.h"
25
26#include "DABase.h"
27#include "DACallback.h"
28#include "DAInternal.h"
29#include "DALog.h"
30#include "DAMain.h"
31#include "DARequest.h"
32#include "DASession.h"
33#include "DAStage.h"
34
35struct __DAResponseContext
36{
37    DAResponseCallback callback;
38    void *             callbackContext;
39    CFTypeRef          response;
40};
41
42typedef struct __DAResponseContext __DAResponseContext;
43
44const CFGregorianUnits __kDAResponseTimerGrace = { 0, 0, 0, 0, 0,  1 };
45const CFGregorianUnits __kDAResponseTimerLimit = { 0, 0, 0, 0, 0, 10 };
46
47static void __DAResponseTimerRefresh( void );
48
49static void __DAQueueCallbacks( _DACallbackKind kind, DADiskRef argument0, CFTypeRef argument1 )
50{
51    CFIndex count;
52    CFIndex index;
53
54    count = CFArrayGetCount( gDASessionList );
55
56    for ( index = 0; index < count; index++ )
57    {
58        DASessionRef session;
59
60        session = ( void * ) CFArrayGetValueAtIndex( gDASessionList, index );
61
62        if ( kind == _kDAIdleCallback )
63        {
64            if ( DASessionGetState( session, kDASessionStateIdle ) )
65            {
66                continue;
67            }
68        }
69
70        DAQueueCallbacks( session, kind, argument0, argument1 );
71
72        if ( kind == _kDAIdleCallback )
73        {
74            DASessionSetState( session, kDASessionStateIdle, TRUE );
75        }
76    }
77}
78
79static void __DAQueueRequest( _DARequestKind kind, DADiskRef argument0, CFIndex argument1, CFTypeRef argument2, CFTypeRef argument3, DACallbackRef callback )
80{
81    DARequestRef request;
82
83///w:start
84    if ( kind == _kDADiskMount )
85    {
86        request = DARequestCreate( kCFAllocatorDefault, kind, argument0, argument1, argument2, argument3, ___UID_UNKNOWN, ___GID_UNKNOWN, callback );
87    }
88    else
89///w:stop
90    request = DARequestCreate( kCFAllocatorDefault, kind, argument0, argument1, argument2, argument3, ___UID_ROOT, ___GID_WHEEL, callback );
91
92    if ( request )
93    {
94        DAQueueRequest( request );
95
96        CFRelease( request );
97    }
98}
99
100static void __DAResponseComplete( DADiskRef disk )
101{
102    CFIndex count;
103    CFIndex index;
104
105    count = CFArrayGetCount( gDAResponseList );
106
107    for ( index = 0; index < count; index++ )
108    {
109        DACallbackRef callback;
110
111        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
112
113        if ( DACallbackGetDisk( callback ) == disk )
114        {
115            break;
116        }
117    }
118
119    if ( index == count )
120    {
121        __DAResponseContext context;
122
123        context = *( ( __DAResponseContext * ) CFDataGetBytePtr( DADiskGetContextRe( disk ) ) );
124
125        DADiskSetContextRe( disk, NULL );
126
127        ( context.callback )( context.response, context.callbackContext );
128
129        if ( context.response )  CFRelease( context.response );
130    }
131
132    __DAResponseTimerRefresh( );
133}
134
135static void __DAResponsePrepare( DADiskRef disk, DAResponseCallback callback, void * callbackContext )
136{
137    CFDataRef data;
138
139    data = CFDataCreateMutable( kCFAllocatorDefault, sizeof( __DAResponseContext ) );
140
141    if ( data )
142    {
143        __DAResponseContext * context;
144
145        context = ( void * ) CFDataGetBytePtr( data );
146
147        bzero( context, sizeof( __DAResponseContext ) );
148
149        context->callback        = callback;
150        context->callbackContext = callbackContext;
151
152        DADiskSetContextRe( disk, data );
153
154        CFRelease( data );
155    }
156}
157
158static void __DAResponseTimerCallback( CFRunLoopTimerRef timer, void * info )
159{
160    CFAbsoluteTime clock;
161    CFIndex        count;
162    CFIndex        index;
163
164    clock = CFAbsoluteTimeGetCurrent( );
165
166    count = CFArrayGetCount( gDAResponseList );
167
168    for ( index = count - 1; index > -1; index-- )
169    {
170        DACallbackRef callback;
171
172        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
173
174        if ( callback )
175        {
176            DASessionRef session;
177
178            session = DACallbackGetSession( callback );
179
180            if ( DASessionGetOption( session, kDASessionOptionNoTimeout ) == FALSE )
181            {
182                CFAbsoluteTime timeout;
183
184                timeout = DACallbackGetTime( callback );
185
186                timeout = CFAbsoluteTimeAddGregorianUnits( timeout, NULL, __kDAResponseTimerLimit );
187
188                if ( timeout < clock )
189                {
190                    DADiskRef disk;
191
192                    disk = DACallbackGetDisk( callback );
193
194                    if ( DASessionGetState( session, kDASessionStateTimeout ) == FALSE )
195                    {
196                        DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID );
197
198                        DALogDebug( "  timed out session, id = %@.", session );
199
200                        DALogError( "%@ not responding.", session );
201
202                        DASessionSetState( session, kDASessionStateTimeout, TRUE );
203                    }
204
205                    CFRetain( disk );
206
207                    CFArrayRemoveValueAtIndex( gDAResponseList, index );
208
209                    __DAResponseComplete( disk );
210
211                    CFRelease( disk );
212                }
213            }
214        }
215    }
216}
217
218static void __DAResponseTimerRefresh( void )
219{
220    static CFRunLoopTimerRef timer = NULL;
221
222    CFAbsoluteTime clock;
223    CFIndex        count;
224    CFIndex        index;
225
226    clock = kCFAbsoluteTimeIntervalSince1904;
227
228    count = CFArrayGetCount( gDAResponseList );
229
230    for ( index = 0; index < count; index++ )
231    {
232        DACallbackRef callback;
233
234        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
235
236        if ( callback )
237        {
238            DASessionRef session;
239
240            session = DACallbackGetSession( callback );
241
242            if ( DASessionGetOption( session, kDASessionOptionNoTimeout ) == FALSE )
243            {
244                CFAbsoluteTime timeout;
245
246                timeout = DACallbackGetTime( callback );
247
248                timeout = CFAbsoluteTimeAddGregorianUnits( timeout, NULL, __kDAResponseTimerLimit );
249
250                if ( timeout < clock )
251                {
252                    clock = timeout;
253                }
254            }
255        }
256    }
257
258    clock = CFAbsoluteTimeAddGregorianUnits( clock, NULL, __kDAResponseTimerGrace );
259
260    if ( timer )
261    {
262        CFRunLoopTimerSetNextFireDate( timer, clock );
263    }
264    else
265    {
266        timer = CFRunLoopTimerCreate( kCFAllocatorDefault, clock, kCFAbsoluteTimeIntervalSince1904, 0, 0, __DAResponseTimerCallback, NULL );
267
268        if ( timer )
269        {
270            CFRunLoopAddTimer( CFRunLoopGetCurrent( ), timer, kCFRunLoopDefaultMode );
271        }
272    }
273}
274
275Boolean _DAResponseDispatch( CFTypeRef response, SInt32 responseID )
276{
277    CFIndex count;
278    CFIndex index;
279
280    count = CFArrayGetCount( gDAResponseList );
281
282    for ( index = 0; index < count; index++ )
283    {
284        DACallbackRef callback;
285
286        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
287
288        if ( ___CFNumberGetIntegerValue( DACallbackGetArgument1( callback ) ) == responseID )
289        {
290            DADiskRef disk;
291
292            disk = DACallbackGetDisk( callback );
293
294            switch ( DACallbackGetKind( callback ) )
295            {
296                case _kDADiskClaimReleaseCallback:
297                case _kDADiskEjectApprovalCallback:
298                case _kDADiskMountApprovalCallback:
299                case _kDADiskUnmountApprovalCallback:
300                {
301                    DADissenterRef dissenter;
302
303                    dissenter = ( void * ) response;
304
305                    if ( dissenter )
306                    {
307                        CFDataRef data;
308
309                        data = DADiskGetContextRe( disk );
310
311                        if ( data )
312                        {
313                            __DAResponseContext * context;
314
315                            context = ( void * ) CFDataGetBytePtr( data );
316
317                            if ( context->response == NULL )
318                            {
319                                context->response = CFRetain( dissenter );
320                            }
321                        }
322
323                        DALogDebug( "  dispatched response, id = %016llX:%016llX, kind = %s, disk = %@, dissented, status = 0x%08X.",
324                                    DACallbackGetAddress( callback ),
325                                    DACallbackGetContext( callback ),
326                                    _DACallbackKindGetName( DACallbackGetKind( callback ) ),
327                                    disk,
328                                    DADissenterGetStatus( dissenter ) );
329                    }
330                    else
331                    {
332                        DALogDebug( "  dispatched response, id = %016llX:%016llX, kind = %s, disk = %@, approved.",
333                                    DACallbackGetAddress( callback ),
334                                    DACallbackGetContext( callback ),
335                                    _DACallbackKindGetName( DACallbackGetKind( callback ) ),
336                                    disk );
337                    }
338
339                    break;
340                }
341                case _kDADiskPeekCallback:
342                {
343                    DALogDebug( "  dispatched response, id = %016llX:%016llX, kind = %s, disk = %@.",
344                                DACallbackGetAddress( callback ),
345                                DACallbackGetContext( callback ),
346                                _DACallbackKindGetName( DACallbackGetKind( callback ) ),
347                                disk );
348
349                    break;
350                }
351            }
352
353            CFArrayRemoveValueAtIndex( gDAResponseList, index );
354
355            __DAResponseComplete( disk );
356
357            break;
358        }
359    }
360
361    return ( index < count ) ? TRUE : FALSE;
362}
363
364void DADiskAppearedCallback( DADiskRef disk )
365{
366    __DAQueueCallbacks( _kDADiskAppearedCallback, disk, NULL );
367}
368
369void DADiskClaimReleaseCallback( DADiskRef disk, DACallbackRef callback, DAResponseCallback response, void * responseContext )
370{
371    __DAResponsePrepare( disk, response, responseContext );
372
373    DAQueueCallback( callback, disk, NULL );
374
375    __DAResponseComplete( disk );
376}
377
378void DADiskDescriptionChangedCallback( DADiskRef disk, CFTypeRef key )
379{
380    if ( CFGetTypeID( key ) == CFArrayGetTypeID( ) )
381    {
382        __DAQueueCallbacks( _kDADiskDescriptionChangedCallback, disk, key );
383    }
384    else
385    {
386        CFMutableArrayRef keys;
387
388        keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
389
390        CFArrayAppendValue( keys, key );
391
392        __DAQueueCallbacks( _kDADiskDescriptionChangedCallback, disk, keys );
393
394        CFRelease( keys );
395    }
396}
397
398void DADiskDisappearedCallback( DADiskRef disk )
399{
400    __DAQueueCallbacks( _kDADiskDisappearedCallback, disk, NULL );
401}
402
403void DADiskEject( DADiskRef disk, DADiskEjectOptions options, DACallbackRef callback )
404{
405    __DAQueueRequest( _kDADiskEject, disk, options, NULL, NULL, callback );
406}
407
408void DADiskEjectApprovalCallback( DADiskRef disk, DAResponseCallback response, void * responseContext )
409{
410    __DAResponsePrepare( disk, response, responseContext );
411
412    __DAQueueCallbacks( _kDADiskEjectApprovalCallback, disk, NULL );
413
414    __DAResponseComplete( disk );
415}
416
417void DADiskMount( DADiskRef disk, CFURLRef mountpoint, DADiskMountOptions options, DACallbackRef callback )
418{
419    DADiskMountWithArguments( disk, mountpoint, options, callback, NULL );
420}
421
422void DADiskMountApprovalCallback( DADiskRef disk, DAResponseCallback response, void * responseContext )
423{
424    __DAResponsePrepare( disk, response, responseContext );
425
426    __DAQueueCallbacks( _kDADiskMountApprovalCallback, disk, NULL );
427
428    __DAResponseComplete( disk );
429}
430
431void DADiskMountWithArguments( DADiskRef disk, CFURLRef mountpoint, DADiskMountOptions options, DACallbackRef callback, CFStringRef arguments )
432{
433    __DAQueueRequest( _kDADiskMount, disk, options, mountpoint, arguments, callback );
434}
435
436void DADiskPeekCallback( DADiskRef disk, DACallbackRef callback, DAResponseCallback response, void * responseContext )
437{
438    __DAResponsePrepare( disk, response, responseContext );
439
440    DAQueueCallback( callback, disk, NULL );
441
442    __DAResponseComplete( disk );
443}
444
445void DADiskProbe( DADiskRef disk, DACallbackRef callback )
446{
447    __DAQueueRequest( _kDADiskProbe, disk, 0, NULL, NULL, callback );
448}
449
450void DADiskRefresh( DADiskRef disk, DACallbackRef callback )
451{
452    __DAQueueRequest( _kDADiskRefresh, disk, 0, NULL, NULL, callback );
453}
454
455void DADiskUnmount( DADiskRef disk, DADiskUnmountOptions options, DACallbackRef callback )
456{
457    __DAQueueRequest( _kDADiskUnmount, disk, options, NULL, NULL, callback );
458}
459
460void DADiskUnmountApprovalCallback( DADiskRef disk, DAResponseCallback response, void * responseContext )
461{
462    __DAResponsePrepare( disk, response, responseContext );
463
464    __DAQueueCallbacks( _kDADiskUnmountApprovalCallback, disk, NULL );
465
466    __DAResponseComplete( disk );
467}
468
469void DAIdleCallback( void )
470{
471    __DAQueueCallbacks( _kDAIdleCallback, NULL, NULL );
472}
473
474void DAQueueCallback( DACallbackRef callback, DADiskRef argument0, CFTypeRef argument1 )
475{
476    static SInt32 responseID = 0;
477
478    DASessionRef session;
479
480    session = DACallbackGetSession( callback );
481
482    DALogDebugHeader( "%s -> %@", gDAProcessNameID, session );
483
484    if ( DASessionGetState( session, kDASessionStateZombie ) == FALSE )
485    {
486        if ( DACallbackGetAddress( callback ) )
487        {
488            CFDictionaryRef match;
489
490            match = DACallbackGetMatch( callback );
491
492            if ( match )
493            {
494                if ( DADiskMatch( argument0, match ) == FALSE )
495                {
496                    return;
497                }
498            }
499
500            switch ( DACallbackGetKind( callback ) )
501            {
502                case _kDADiskAppearedCallback:
503                case _kDADiskDisappearedCallback:
504                {
505                    if ( DADiskGetOption( argument0, kDADiskOptionPrivate ) == FALSE )
506                    {
507                        callback = DACallbackCreateCopy( kCFAllocatorDefault, callback );
508
509                        if ( callback )
510                        {
511                            DACallbackSetDisk( callback, argument0 );
512
513                            DACallbackSetArgument0( callback, DADiskGetSerialization( argument0 ) );
514
515                            DASessionQueueCallback( session, callback );
516
517                            DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@.",
518                                        DACallbackGetAddress( callback ),
519                                        DACallbackGetContext( callback ),
520                                        _DACallbackKindGetName( DACallbackGetKind( callback ) ),
521                                        argument0 );
522
523                            CFRelease( callback );
524                        }
525                    }
526
527                    break;
528                }
529                case _kDADiskClaimCallback:
530                case _kDADiskEjectCallback:
531                case _kDADiskMountCallback:
532                case _kDADiskRenameCallback:
533                case _kDADiskUnmountCallback:
534                {
535                    DACallbackSetDisk( callback, argument0 );
536
537                    DACallbackSetArgument0( callback, DADiskGetSerialization( argument0 ) );
538
539                    DACallbackSetArgument1( callback, argument1 );
540
541                    DASessionQueueCallback( session, callback );
542
543                    if ( argument1 )
544                    {
545                        DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@, status = 0x%08X.",
546                                    DACallbackGetAddress( callback ),
547                                    DACallbackGetContext( callback ),
548                                    _DACallbackKindGetName( DACallbackGetKind( callback ) ),
549                                    argument0,
550                                    DADissenterGetStatus( argument1 ) );
551                    }
552                    else
553                    {
554                        DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@, success.",
555                                    DACallbackGetAddress( callback ),
556                                    DACallbackGetContext( callback ),
557                                    _DACallbackKindGetName( DACallbackGetKind( callback ) ),
558                                    argument0 );
559                    }
560
561                    break;
562                }
563                case _kDADiskClaimReleaseCallback:
564                {
565                    if ( DASessionGetState( session, kDASessionStateTimeout ) == FALSE )
566                    {
567                        assert( argument1 == NULL );
568
569                        argument1 = ___CFNumberCreateWithIntegerValue( kCFAllocatorDefault, responseID );
570
571                        if ( argument1 )
572                        {
573                            DACallbackRef response;
574
575                            response = DACallbackCreateCopy( kCFAllocatorDefault, callback );
576
577                            if ( response )
578                            {
579                                DACallbackSetDisk( response, argument0 );
580
581                                DACallbackSetArgument1( response, argument1 );
582
583                                DACallbackSetTime( response, CFAbsoluteTimeGetCurrent( ) );
584
585                                CFArrayAppendValue( gDAResponseList, response );
586
587                                CFRelease( response );
588                            }
589
590                            callback = DACallbackCreateCopy( kCFAllocatorDefault, callback );
591
592                            if ( callback )
593                            {
594                                DACallbackSetDisk( callback, argument0 );
595
596                                DACallbackSetArgument0( callback, DADiskGetSerialization( argument0 ) );
597
598                                DACallbackSetArgument1( callback, argument1 );
599
600                                DASessionQueueCallback( session, callback );
601
602                                DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@.",
603                                            DACallbackGetAddress( callback ),
604                                            DACallbackGetContext( callback ),
605                                            _DACallbackKindGetName( DACallbackGetKind( callback ) ),
606                                            argument0 );
607
608                                CFRelease( callback );
609                            }
610
611                            CFRelease( argument1 );
612                        }
613
614                        responseID++;
615                    }
616
617                    break;
618                }
619                case _kDADiskEjectApprovalCallback:
620                case _kDADiskMountApprovalCallback:
621                case _kDADiskPeekCallback:
622                case _kDADiskUnmountApprovalCallback:
623                {
624                    if ( DASessionGetState( session, kDASessionStateTimeout ) == FALSE )
625                    {
626                        if ( DADiskGetOption( argument0, kDADiskOptionPrivate ) == FALSE )
627                        {
628                            assert( argument1 == NULL );
629
630                            argument1 = ___CFNumberCreateWithIntegerValue( kCFAllocatorDefault, responseID );
631
632                            if ( argument1 )
633                            {
634                                DACallbackRef response;
635
636                                response = DACallbackCreateCopy( kCFAllocatorDefault, callback );
637
638                                if ( response )
639                                {
640                                    DACallbackSetDisk( response, argument0 );
641
642                                    DACallbackSetArgument1( response, argument1 );
643
644                                    DACallbackSetTime( response, CFAbsoluteTimeGetCurrent( ) );
645
646                                    CFArrayAppendValue( gDAResponseList, response );
647
648                                    CFRelease( response );
649                                }
650
651                                callback = DACallbackCreateCopy( kCFAllocatorDefault, callback );
652
653                                if ( callback )
654                                {
655                                    DACallbackSetDisk( callback, argument0 );
656
657                                    DACallbackSetArgument0( callback, DADiskGetSerialization( argument0 ) );
658
659                                    DACallbackSetArgument1( callback, argument1 );
660
661                                    DASessionQueueCallback( session, callback );
662
663                                    DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@.",
664                                                DACallbackGetAddress( callback ),
665                                                DACallbackGetContext( callback ),
666                                                _DACallbackKindGetName( DACallbackGetKind( callback ) ),
667                                                argument0 );
668
669                                    CFRelease( callback );
670                                }
671
672                                CFRelease( argument1 );
673                            }
674
675                            responseID++;
676                        }
677                    }
678
679                    break;
680                }
681                case _kDADiskDescriptionChangedCallback:
682                {
683                    if ( DADiskGetState( argument0, kDADiskStateZombie ) == FALSE )
684                    {
685                        CFMutableArrayRef intersection;
686
687                        if ( DADiskGetOption( argument0, kDADiskOptionPrivate ) == FALSE )
688                        {
689                            CFArrayRef watch;
690
691                            watch = DACallbackGetWatch( callback );
692
693                            if ( watch )
694                            {
695                                intersection = CFArrayCreateMutableCopy( kCFAllocatorDefault, 0, argument1 );
696
697                                if ( intersection )
698                                {
699                                    ___CFArrayIntersect( intersection, watch );
700                                }
701                            }
702                            else
703                            {
704                                intersection = ( void * ) CFRetain( argument1 );
705                            }
706
707                            if ( intersection )
708                            {
709                                if ( CFArrayGetCount( intersection ) )
710                                {
711                                    callback = DACallbackCreateCopy( kCFAllocatorDefault, callback );
712
713                                    if ( callback )
714                                    {
715                                        CFIndex count;
716                                        CFIndex index;
717
718                                        count = CFArrayGetCount( intersection );
719
720                                        for ( index = 0; index < count; index++ )
721                                        {
722                                            DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s, disk = %@, key = %@.",
723                                                        DACallbackGetAddress( callback ),
724                                                        DACallbackGetContext( callback ),
725                                                        _DACallbackKindGetName( DACallbackGetKind( callback ) ),
726                                                        argument0,
727                                                        CFArrayGetValueAtIndex( intersection, index ) );
728                                        }
729
730                                        DACallbackSetDisk( callback, argument0 );
731
732                                        DACallbackSetArgument0( callback, DADiskGetSerialization( argument0 ) );
733
734                                        DACallbackSetArgument1( callback, intersection );
735
736                                        DASessionQueueCallback( session, callback );
737
738                                        CFRelease( callback );
739                                    }
740                                }
741
742                                CFRelease( intersection );
743                            }
744                        }
745                    }
746
747                    break;
748                }
749                case _kDAIdleCallback:
750                {
751                    callback = DACallbackCreateCopy( kCFAllocatorDefault, callback );
752
753                    if ( callback )
754                    {
755                        DASessionQueueCallback( session, callback );
756
757                        DALogDebug( "  dispatched callback, id = %016llX:%016llX, kind = %s.",
758                                    DACallbackGetAddress( callback ),
759                                    DACallbackGetContext( callback ),
760                                    _DACallbackKindGetName( DACallbackGetKind( callback ) ) );
761
762                        CFRelease( callback );
763                    }
764
765                    break;
766                }
767            }
768        }
769    }
770}
771
772void DAQueueCallbacks( DASessionRef session, _DACallbackKind kind, DADiskRef argument0, CFTypeRef argument1 )
773{
774    CFArrayRef callbacks;
775
776    callbacks = DASessionGetCallbackRegister( session );
777
778    if ( callbacks )
779    {
780        CFIndex count;
781        CFIndex index;
782
783        count = CFArrayGetCount( callbacks );
784
785        for ( index = 0; index < count; index++ )
786        {
787            DACallbackRef callback;
788
789            callback = ( void * ) CFArrayGetValueAtIndex( callbacks, index );
790
791            if ( DACallbackGetKind( callback ) == kind )
792            {
793                DAQueueCallback( callback, argument0, argument1 );
794            }
795        }
796    }
797}
798
799void DAQueueReleaseDisk( DADiskRef disk )
800{
801    CFIndex count;
802    CFIndex index;
803
804    count = CFArrayGetCount( gDAResponseList );
805
806    for ( index = count - 1; index > -1; index-- )
807    {
808        DACallbackRef callback;
809
810        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
811
812        if ( DACallbackGetDisk( callback ) == disk )
813        {
814            CFArrayRemoveValueAtIndex( gDAResponseList, index );
815
816            __DAResponseComplete( disk );
817        }
818    }
819
820    count = CFArrayGetCount( gDARequestList );
821
822    for ( index = count - 1; index > -1; index-- )
823    {
824        DARequestRef request;
825
826        request = ( void * ) CFArrayGetValueAtIndex( gDARequestList, index );
827
828        if ( DARequestGetDisk( request ) == disk )
829        {
830            DARequestDispatchCallback( request, kDAReturnNotFound );
831
832            CFArrayRemoveValueAtIndex( gDARequestList, index );
833        }
834    }
835}
836
837void DAQueueReleaseSession( DASessionRef session )
838{
839    CFIndex count;
840    CFIndex index;
841
842    count = CFArrayGetCount( gDAResponseList );
843
844    for ( index = count - 1; index > -1; index-- )
845    {
846        DACallbackRef callback;
847
848        callback = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
849
850        if ( DACallbackGetSession( callback ) == session )
851        {
852            DADiskRef disk;
853
854            disk = DACallbackGetDisk( callback );
855
856            CFArrayRemoveValueAtIndex( gDAResponseList, index );
857
858            __DAResponseComplete( disk );
859        }
860    }
861
862    count = CFArrayGetCount( gDARequestList );
863
864    for ( index = count - 1; index > -1; index-- )
865    {
866        DARequestRef request;
867
868        request = ( void * ) CFArrayGetValueAtIndex( gDARequestList, index );
869
870        if ( request )
871        {
872            DACallbackRef callback;
873
874            callback = DARequestGetCallback( request );
875
876            if ( callback )
877            {
878                if ( DACallbackGetSession( callback ) == session )
879                {
880                    DARequestSetCallback( request, NULL );
881                }
882            }
883        }
884    }
885
886    count = CFArrayGetCount( gDADiskList );
887
888    for ( index = count - 1; index > -1; index-- )
889    {
890        DADiskRef disk;
891
892        disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
893
894        if ( disk )
895        {
896            DACallbackRef callback;
897
898            callback = DADiskGetClaim( disk );
899
900            if ( callback )
901            {
902                if ( DACallbackGetSession( callback ) == session )
903                {
904                    DADiskSetClaim( disk, NULL );
905                }
906            }
907        }
908    }
909}
910
911void DAQueueRequest( DARequestRef request )
912{
913    DAReturn status;
914
915    status = kDAReturnSuccess;
916
917    switch ( DARequestGetKind( request ) )
918    {
919        case _kDADiskEject:
920        case _kDADiskMount:
921        case _kDADiskUnmount:
922        {
923            DADiskMountOptions options;
924
925            options = DARequestGetArgument1( request );
926
927            assert( kDADiskMountOptionWhole == kDADiskUnmountOptionWhole );
928
929            if ( DARequestGetKind( request ) == _kDADiskEject )
930            {
931                options |= kDADiskMountOptionWhole;
932            }
933
934            if ( ( options & kDADiskMountOptionWhole ) )
935            {
936                DADiskRef disk;
937
938                disk = DARequestGetDisk( request );
939
940                if ( DARequestGetArgument2( request ) )
941                {
942                    status = kDAReturnBadArgument;
943                }
944
945                if ( DARequestGetArgument3( request ) )
946                {
947                    status = kDAReturnBadArgument;
948                }
949
950                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == NULL )
951                {
952                    status = kDAReturnUnsupported;
953                }
954
955                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanFalse )
956                {
957                    status = kDAReturnUnsupported;
958                }
959
960                if ( status )
961                {
962                    break;
963                }
964                else
965                {
966                    CFMutableArrayRef link;
967
968                    link = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
969
970                    if ( link )
971                    {
972                        CFIndex count;
973                        CFIndex index;
974
975                        count = CFArrayGetCount( gDADiskList );
976
977                        for ( index = 0; index < count; index++ )
978                        {
979                            DADiskRef subdisk;
980
981                            subdisk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
982
983                            if ( disk != subdisk )
984                            {
985                                if ( DADiskGetBSDUnit( disk ) == DADiskGetBSDUnit( subdisk ) )
986                                {
987                                    DARequestRef subrequest;
988
989                                    subrequest = DARequestCreate( kCFAllocatorDefault,
990                                                                  DARequestGetKind( request ),
991                                                                  subdisk,
992                                                                  options,
993                                                                  NULL,
994                                                                  NULL,
995                                                                  DARequestGetUserUID( request ),
996                                                                  DARequestGetUserGID( request ),
997                                                                  NULL );
998
999                                    if ( subrequest )
1000                                    {
1001                                        CFArrayAppendValue( link, subrequest );
1002
1003                                        CFArrayAppendValue( gDARequestList, subrequest );
1004
1005                                        CFRelease( subrequest );
1006                                    }
1007                                }
1008                            }
1009                        }
1010
1011                        DARequestSetLink( request, link );
1012
1013                        CFRelease( link );
1014                    }
1015                }
1016            }
1017
1018            break;
1019        }
1020    }
1021
1022    if ( status )
1023    {
1024        DARequestDispatchCallback( request, status );
1025    }
1026    else
1027    {
1028        CFArrayAppendValue( gDARequestList, request );
1029
1030        DAStageSignal( );
1031    }
1032}
1033
1034void DAQueueUnregisterCallback( DACallbackRef callback )
1035{
1036    CFIndex count;
1037    CFIndex index;
1038
1039    count = CFArrayGetCount( gDAResponseList );
1040
1041    for ( index = count - 1; index > -1; index-- )
1042    {
1043        DACallbackRef item;
1044
1045        item = ( void * ) CFArrayGetValueAtIndex( gDAResponseList, index );
1046
1047        if ( DACallbackGetSession( item ) == DACallbackGetSession( callback ) )
1048        {
1049            if ( DACallbackGetAddress( item ) == DACallbackGetAddress( callback ) )
1050            {
1051                if ( DACallbackGetContext( item ) == DACallbackGetContext( callback ) )
1052                {
1053                    DADiskRef disk;
1054
1055                    disk = DACallbackGetDisk( item );
1056
1057                    CFArrayRemoveValueAtIndex( gDAResponseList, index );
1058
1059                    __DAResponseComplete( disk );
1060                }
1061            }
1062        }
1063    }
1064}
1065