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 "DiskArbitrationPrivate.h"
25
26#include "DAInternal.h"
27#include "DAServer.h"
28
29#ifndef __LP64__
30
31#include <paths.h>
32#include <unistd.h>
33#include <servers/bootstrap.h>
34#include <sys/attr.h>
35#include <sys/mount.h>
36#include <IOKit/IOKitLib.h>
37#include <IOKit/storage/IOMedia.h>
38#include <IOKit/storage/IOBDMedia.h>
39#include <IOKit/storage/IOCDMedia.h>
40#include <IOKit/storage/IODVDMedia.h>
41///w:start
42static kern_return_t          __gDiskArbStatus                      = KERN_SUCCESS;
43static Boolean                __gDiskArbStatusLock                  = FALSE;
44///w:stop
45
46static int                    __gDiskArbAck                         = 0;
47static CFMutableDictionaryRef __gDiskArbCallbackList                = NULL;
48static CFMutableSetRef        __gDiskArbEjectList                   = NULL;
49static int                    __gDiskArbHandlesUnrecognized         = 0;
50static int                    __gDiskArbHandlesUnrecognizedPriority = 0;
51static int                    __gDiskArbHandlesUnrecognizedTypes    = 0;
52static int                    __gDiskArbNotificationComplete        = 0;
53static CFMutableArrayRef      __gDiskArbRegisterList                = NULL;
54static CFMutableSetRef        __gDiskArbReservationList             = NULL;
55static DASessionRef           __gDiskArbSession                     = NULL;
56static CFMutableSetRef        __gDiskArbUnmountList                 = NULL;
57
58#endif /* !__LP64__ */
59
60__private_extern__ DAReturn _DAAuthorize( DASessionRef session, _DAAuthorizeOptions options, DADiskRef disk, const char * right );
61
62__private_extern__ char *      _DADiskGetID( DADiskRef disk );
63__private_extern__ mach_port_t _DADiskGetSessionID( DADiskRef disk );
64
65__private_extern__ void _DARegisterCallback( DASessionRef    session,
66                                             void *          callback,
67                                             void *          context,
68                                             _DACallbackKind kind,
69                                             CFIndex         order,
70                                             CFDictionaryRef match,
71                                             CFArrayRef      watch );
72
73#ifndef __LP64__
74
75__private_extern__ void             _DASessionCallback( CFMachPortRef port, void * message, CFIndex messageSize, void * info );
76__private_extern__ AuthorizationRef _DASessionGetAuthorization( DASessionRef session );
77__private_extern__ mach_port_t      _DASessionGetClientPort( DASessionRef session );
78__private_extern__ void             _DASessionScheduleWithRunLoop( DASessionRef session );
79
80static unsigned __DiskArbCopyDiskDescriptionAppearanceTime( DADiskRef disk )
81{
82    double time = 0;
83
84    if ( disk )
85    {
86        CFDictionaryRef description;
87
88        description = DADiskCopyDescription( disk );
89
90        if ( description )
91        {
92            CFNumberRef number;
93
94            number = CFDictionaryGetValue( description, kDADiskDescriptionAppearanceTimeKey );
95
96            if ( number )
97            {
98                CFNumberGetValue( number, kCFNumberDoubleType, &time );
99            }
100
101            CFRelease( description );
102        }
103    }
104
105    return time;
106}
107
108static char * __DiskArbCopyDiskDescriptionDeviceTreePath( DADiskRef disk )
109{
110    char * path = NULL;
111
112    if ( disk )
113    {
114        CFDictionaryRef description;
115
116        description = DADiskCopyDescription( disk );
117
118        if ( description )
119        {
120            CFStringRef string;
121
122            string = CFDictionaryGetValue( description, kDADiskDescriptionMediaPathKey );
123
124            if ( string )
125            {
126                char * buffer;
127
128                buffer = ___CFStringCopyCString( string );
129
130                if ( buffer )
131                {
132                    if ( strncmp( buffer, kIODeviceTreePlane ":", strlen( kIODeviceTreePlane ":" ) ) == 0 )
133                    {
134                        path = strdup( buffer + strlen( kIODeviceTreePlane ":" ) );
135                    }
136
137                    free( buffer );
138                }
139            }
140
141            CFRelease( description );
142        }
143    }
144
145    return path ? path : strdup( "" );
146}
147
148static unsigned __DiskArbCopyDiskDescriptionFlags( DADiskRef disk )
149{
150    unsigned flags = 0;
151
152    if ( disk )
153    {
154        CFDictionaryRef description;
155
156        description = DADiskCopyDescription( disk );
157
158        if ( description )
159        {
160            CFTypeRef object;
161
162            object = CFDictionaryGetValue( description, kDADiskDescriptionDeviceInternalKey );
163
164            if ( object )
165            {
166                if ( object == kCFBooleanTrue )
167                {
168                    flags |= kDiskArbDiskAppearedInternal;
169                }
170            }
171
172            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaEjectableKey );
173
174            if ( object )
175            {
176                if ( object == kCFBooleanTrue )
177                {
178                    flags |= kDiskArbDiskAppearedEjectableMask;
179
180                    object = CFDictionaryGetValue( description, kDADiskDescriptionMediaKindKey );
181
182                    if ( object )
183                    {
184                        DADiskRef whole;
185
186                        whole = DADiskCopyWholeDisk( disk );
187
188                        if ( whole )
189                        {
190                            io_service_t media;
191
192                            media = DADiskCopyIOMedia( whole );
193
194                            if ( media )
195                            {
196                                if ( IOObjectConformsTo( media, kIOBDMediaClass ) )
197                                {
198                                    flags |= kDiskArbDiskAppearedBDROMMask;
199                                }
200
201                                if ( IOObjectConformsTo( media, kIOCDMediaClass ) )
202                                {
203                                    flags |= kDiskArbDiskAppearedCDROMMask;
204                                }
205
206                                if ( IOObjectConformsTo( media, kIODVDMediaClass ) )
207                                {
208                                    flags |= kDiskArbDiskAppearedDVDROMMask;
209                                }
210
211                                IOObjectRelease( media );
212                            }
213
214                            CFRelease( whole );
215                        }
216                    }
217                }
218            }
219
220            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaLeafKey );
221
222            if ( object )
223            {
224                if ( object == kCFBooleanFalse )
225                {
226                    flags |= kDiskArbDiskAppearedNonLeafDiskMask;
227                }
228            }
229
230            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaSizeKey );
231
232            if ( object )
233            {
234                if ( ___CFNumberGetIntegerValue( object ) == 0 )
235                {
236                    flags |= kDiskArbDiskAppearedNoSizeMask;
237                }
238            }
239
240            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaWholeKey );
241
242            if ( object )
243            {
244                if ( object == kCFBooleanTrue )
245                {
246                    flags |= kDiskArbDiskAppearedWholeDiskMask;
247                }
248            }
249
250            object = CFDictionaryGetValue( description, kDADiskDescriptionMediaWritableKey );
251
252            if ( object )
253            {
254                if ( object == kCFBooleanFalse )
255                {
256                    flags |= kDiskArbDiskAppearedLockedMask;
257                }
258            }
259
260            object = CFDictionaryGetValue( description, kDADiskDescriptionVolumeMountableKey );
261
262            if ( object )
263            {
264                if ( object == kCFBooleanFalse )
265                {
266                    flags |= kDiskArbDiskAppearedUnrecognizableFormat;
267                }
268            }
269
270            object = CFDictionaryGetValue( description, kDADiskDescriptionVolumeNetworkKey );
271
272            if ( object )
273            {
274                if ( object == kCFBooleanTrue )
275                {
276                    flags |= kDiskArbDiskAppearedNetworkDiskMask;
277                }
278            }
279
280            CFRelease( description );
281        }
282    }
283
284    return flags;
285}
286
287static char * __DiskArbCopyDiskDescriptionMediaContent( DADiskRef disk )
288{
289    char * content = NULL;
290
291    if ( disk )
292    {
293        CFDictionaryRef description;
294
295        description = DADiskCopyDescription( disk );
296
297        if ( description )
298        {
299            CFStringRef string;
300
301            string = CFDictionaryGetValue( description, kDADiskDescriptionMediaContentKey );
302
303            if ( string )
304            {
305                content = ___CFStringCopyCString( string );
306            }
307
308            CFRelease( description );
309        }
310    }
311
312    return content ? content : strdup( "" );
313}
314
315static unsigned __DiskArbCopyDiskDescriptionSequenceNumber( DADiskRef disk )
316{
317    unsigned sequence = -1;
318
319    if ( disk )
320    {
321        CFDictionaryRef description;
322
323        description = DADiskCopyDescription( disk );
324
325        if ( description )
326        {
327            CFURLRef url;
328
329            url = CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey );
330
331            if ( url )
332            {
333                CFNumberRef number;
334
335                number = CFDictionaryGetValue( description, kDADiskDescriptionMediaBSDMinorKey );
336
337                if ( number )
338                {
339                    CFNumberGetValue( number, kCFNumberIntType, &sequence );
340                }
341            }
342
343            CFRelease( description );
344        }
345    }
346
347    return sequence;
348}
349
350static char * __DiskArbCopyDiskDescriptionVolumeKind( DADiskRef disk )
351{
352    char * kind = NULL;
353
354    if ( disk )
355    {
356        CFDictionaryRef description;
357
358        description = DADiskCopyDescription( disk );
359
360        if ( description )
361        {
362            CFStringRef string;
363
364            string = CFDictionaryGetValue( description, kDADiskDescriptionVolumeKindKey );
365
366            if ( string )
367            {
368                kind = ___CFStringCopyCString( string );
369            }
370
371            CFRelease( description );
372        }
373    }
374
375    return kind ? kind : strdup( "" );
376}
377
378static char * __DiskArbCopyDiskDescriptionVolumeName( DADiskRef disk )
379{
380    char * name = NULL;
381
382    if ( disk )
383    {
384        CFDictionaryRef description;
385
386        description = DADiskCopyDescription( disk );
387
388        if ( description )
389        {
390            CFStringRef string;
391
392            string = CFDictionaryGetValue( description, kDADiskDescriptionVolumeNameKey );
393
394            if ( string )
395            {
396                name = ___CFStringCopyCString( string );
397            }
398
399            CFRelease( description );
400        }
401    }
402
403    return name ? name : strdup( "" );
404}
405
406static char * __DiskArbCopyDiskDescriptionVolumePath( DADiskRef disk )
407{
408    char * path = NULL;
409
410    if ( disk )
411    {
412        CFDictionaryRef description;
413
414        description = DADiskCopyDescription( disk );
415
416        if ( description )
417        {
418            CFURLRef url;
419
420            url = CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey );
421
422            if ( url )
423            {
424                path = ___CFURLCopyFileSystemRepresentation( url );
425            }
426
427            CFRelease( description );
428        }
429    }
430
431    return path ? path : strdup( "" );
432}
433
434static CFArrayRef __DiskArbGetCallbackHandler( int type )
435{
436    CFArrayRef callbacks = NULL;
437
438    if ( __gDiskArbCallbackList )
439    {
440        CFNumberRef key;
441
442        key = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &type );
443
444        if ( key )
445        {
446            callbacks = CFDictionaryGetValue( __gDiskArbCallbackList, key );
447
448            CFRelease( key );
449        }
450    }
451
452    return callbacks;
453}
454
455static char * __DiskArbGetDiskID( DADiskRef _disk )
456{
457    char * disk;
458
459    disk = _DADiskGetID( _disk );
460
461    if ( strncmp( disk, _PATH_DEV, strlen( _PATH_DEV ) ) == 0 )
462    {
463        disk += strlen( _PATH_DEV );
464    }
465
466    return disk;
467}
468
469static struct statfs * __DiskArbGetFileSystemStatus( char * disk )
470{
471    struct statfs * mountList;
472    int             mountListCount;
473    int             mountListIndex;
474
475    mountListCount = getmntinfo( &mountList, MNT_NOWAIT );
476
477    for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
478    {
479        if ( strncmp( disk, "disk", strlen( "disk" ) ) )
480        {
481            if ( strcmp( mountList[mountListIndex].f_mntfromname, disk ) == 0 )
482            {
483                break;
484            }
485
486            if ( strcmp( mountList[mountListIndex].f_mntonname, disk ) == 0 )
487            {
488                break;
489            }
490        }
491        else
492        {
493            if ( strncmp( mountList[mountListIndex].f_mntfromname, _PATH_DEV, strlen( _PATH_DEV ) ) == 0 )
494            {
495                if ( strcmp( mountList[mountListIndex].f_mntfromname + strlen( _PATH_DEV ), disk ) == 0 )
496                {
497                    break;
498                }
499            }
500        }
501    }
502
503    return ( mountListIndex < mountListCount ) ? ( mountList + mountListIndex ) : ( NULL );
504}
505
506static void __DiskArbCallback_CallFailedNotification( char * disk, int type, int status )
507{
508    CFArrayRef callbacks;
509
510    callbacks = __DiskArbGetCallbackHandler( kDA_CALL_FAILED );
511
512    if ( callbacks )
513    {
514        CFIndex count;
515        CFIndex index;
516
517        count = CFArrayGetCount( callbacks );
518
519        for ( index = 0; index < count; index++ )
520        {
521            DiskArbCallback_CallFailedNotification_t callback;
522
523            callback = CFArrayGetValueAtIndex( callbacks, index );
524
525            if ( callback )
526            {
527                ( callback )( disk, type, status );
528            }
529        }
530    }
531}
532
533static void __DiskArbCallback_Device_Reservation_Status( char * disk, int status, int pid )
534{
535    CFArrayRef callbacks;
536
537    callbacks = __DiskArbGetCallbackHandler( kDA_DEVICE_RESERVATION_STATUS );
538
539    if ( callbacks )
540    {
541        CFIndex count;
542        CFIndex index;
543
544        count = CFArrayGetCount( callbacks );
545
546        for ( index = 0; index < count; index++ )
547        {
548            DiskArbCallback_Device_Reservation_Status_t callback;
549
550            callback = CFArrayGetValueAtIndex( callbacks, index );
551
552            if ( callback )
553            {
554                ( callback )( disk, status, pid );
555            }
556        }
557    }
558}
559
560static void __DiskArbCallback_DiskChangedNotification( char * disk, char * mountpoint, char * name, int context, int success )
561{
562    CFArrayRef callbacks;
563
564    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_CHANGED );
565
566    if ( callbacks )
567    {
568        CFIndex count;
569        CFIndex index;
570
571        count = CFArrayGetCount( callbacks );
572
573        for ( index = 0; index < count; index++ )
574        {
575            DiskArbCallback_DiskChangedNotification_t callback;
576
577            callback = CFArrayGetValueAtIndex( callbacks, index );
578
579            if ( callback )
580            {
581                ( callback )( disk, mountpoint, name, context, success );
582            }
583        }
584    }
585}
586
587static void __DiskArbCallback_EjectPostNotification( char * disk, int status, pid_t dissenter )
588{
589    CFArrayRef callbacks;
590
591    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_EJECT_POST_NOTIFY );
592
593    if ( callbacks )
594    {
595        CFIndex count;
596        CFIndex index;
597
598        count = CFArrayGetCount( callbacks );
599
600        for ( index = 0; index < count; index++ )
601        {
602            DiskArbCallback_EjectPostNotification_t callback;
603
604            callback = CFArrayGetValueAtIndex( callbacks, index );
605
606            if ( callback )
607            {
608                ( callback )( disk, status, dissenter );
609            }
610        }
611    }
612
613    __gDiskArbNotificationComplete |= kDiskArbCompletedPostEject;
614}
615
616static void __DiskArbCallback_EjectPostNotificationApplier( const void * value, void * context )
617{
618    DADiskRef disk = ( DADiskRef ) value;
619
620    __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( disk ), context ? EBUSY : 0, context ? -1 : 0 );
621}
622
623static void __DiskArbCallback_UnmountPostNotification( char * disk, int status, pid_t dissenter )
624{
625    CFArrayRef callbacks;
626
627    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_UNMOUNT_POST_NOTIFY );
628
629    if ( callbacks )
630    {
631        CFIndex count;
632        CFIndex index;
633
634        count = CFArrayGetCount( callbacks );
635
636        for ( index = 0; index < count; index++ )
637        {
638            DiskArbCallback_UnmountPostNotification_t callback;
639
640            callback = CFArrayGetValueAtIndex( callbacks, index );
641
642            if ( callback )
643            {
644                ( callback )( disk, status, dissenter );
645            }
646        }
647    }
648
649    __gDiskArbNotificationComplete |= kDiskArbCompletedPostUnmount;
650}
651
652static void __DiskArbCallback_UnmountPostNotificationApplier( const void * value, void * context )
653{
654    DADiskRef disk = ( DADiskRef ) value;
655
656    __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), context ? EBUSY : 0, context ? -1 : 0 );
657}
658
659static void __DiskArbDiskAppearedCallback( DADiskRef disk, void * context )
660{
661    CFArrayRef      callbacks   = NULL;
662    char *          content     = NULL;
663    char *          filesystem  = NULL;
664    unsigned        flags       = 0;
665    char *          mountpoint  = NULL;
666    char *          name        = NULL;
667    char *          path        = NULL;
668    unsigned        sequence    = -1;
669    double          time        = 0;
670
671    content    = __DiskArbCopyDiskDescriptionMediaContent( disk );
672    filesystem = __DiskArbCopyDiskDescriptionVolumeKind( disk );
673    flags      = __DiskArbCopyDiskDescriptionFlags( disk );
674    mountpoint = __DiskArbCopyDiskDescriptionVolumePath( disk );
675    name       = __DiskArbCopyDiskDescriptionVolumeName( disk );
676    path       = __DiskArbCopyDiskDescriptionDeviceTreePath( disk );
677    sequence   = __DiskArbCopyDiskDescriptionSequenceNumber( disk );
678    time       = __DiskArbCopyDiskDescriptionAppearanceTime( disk );
679
680    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_APPEARED );
681
682    if ( callbacks )
683    {
684        CFIndex count;
685        CFIndex index;
686
687        count = CFArrayGetCount( callbacks );
688
689        for ( index = 0; index < count; index++ )
690        {
691            DiskArbCallback_DiskAppeared2_t callback;
692
693            callback = CFArrayGetValueAtIndex( callbacks, index );
694
695            if ( callback )
696            {
697                ( callback )( __DiskArbGetDiskID( disk ), flags, mountpoint, content, path, sequence );
698            }
699        }
700    }
701
702    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_APPEARED1 );
703
704    if ( callbacks )
705    {
706        CFIndex count;
707        CFIndex index;
708
709        count = CFArrayGetCount( callbacks );
710
711        for ( index = 0; index < count; index++ )
712        {
713            DiskArbCallback_DiskAppeared_t callback;
714
715            callback = CFArrayGetValueAtIndex( callbacks, index );
716
717            if ( callback )
718            {
719                ( callback )( __DiskArbGetDiskID( disk ), flags, mountpoint, content );
720            }
721        }
722    }
723
724    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_APPEARED_COMPLETE );
725
726    if ( callbacks )
727    {
728        CFIndex count;
729        CFIndex index;
730
731        count = CFArrayGetCount( callbacks );
732
733        for ( index = 0; index < count; index++ )
734        {
735            DiskArbCallback_DiskAppearedComplete_t callback;
736
737            callback = CFArrayGetValueAtIndex( callbacks, index );
738
739            if ( callback )
740            {
741                ( callback )( __DiskArbGetDiskID( disk ), flags, mountpoint, content, path, sequence, time, filesystem, name );
742            }
743        }
744    }
745
746    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_APPEARED_WITH_MT );
747
748    if ( callbacks )
749    {
750        if ( strcmp( mountpoint, "" ) )
751        {
752            CFIndex count;
753            CFIndex index;
754
755            count = CFArrayGetCount( callbacks );
756
757            for ( index = 0; index < count; index++ )
758            {
759                DiskArbCallback_DiskAppearedWithMountpoint_t callback;
760
761                callback = CFArrayGetValueAtIndex( callbacks, index );
762
763                if ( callback )
764                {
765                    ( callback )( __DiskArbGetDiskID( disk ), flags, mountpoint );
766                }
767            }
768        }
769    }
770
771    __gDiskArbNotificationComplete |= kDiskArbCompletedDiskAppeared;
772
773    if ( content    )  free( content    );
774    if ( filesystem )  free( filesystem );
775    if ( mountpoint )  free( mountpoint );
776    if ( name       )  free( name       );
777    if ( path       )  free( path       );
778}
779
780static void __DiskArbDiskClaimCallback( DADiskRef disk, DADissenterRef dissenter, void * context )
781{
782    if ( dissenter == NULL )
783    {
784        CFSetSetValue( __gDiskArbReservationList, disk );
785    }
786
787    if ( context == 0 )
788    {
789        if ( dissenter )
790        {
791            __DiskArbCallback_Device_Reservation_Status( __DiskArbGetDiskID( disk ), kDiskArbDeviceReservationRefused, -1 );
792        }
793        else
794        {
795            __DiskArbCallback_Device_Reservation_Status( __DiskArbGetDiskID( disk ), kDiskArbDeviceReservationObtained, getpid( ) );
796        }
797    }
798}
799
800static DADissenterRef __DiskArbDiskClaimReleaseCallback( DADiskRef disk, void * context )
801{
802    DADissenterRef dissenter = NULL;
803
804    if ( context == 0 )
805    {
806        CFArrayRef callbacks;
807
808        callbacks = __DiskArbGetCallbackHandler( kDA_WILL_CLIENT_RELEASE_DEVICE );
809
810        if ( callbacks )
811        {
812            CFIndex count;
813            CFIndex index;
814
815            count = CFArrayGetCount( callbacks );
816
817            if ( count )
818            {
819                for ( index = 0; index < count; index++ )
820                {
821                    DiskArbCallback_Will_Client_Release_t callback;
822
823                    callback = CFArrayGetValueAtIndex( callbacks, index );
824
825                    if ( callback )
826                    {
827                        __gDiskArbAck = 0;
828
829                        ( callback )( __DiskArbGetDiskID( disk ), -1 );
830
831                        if ( dissenter == NULL )
832                        {
833                            if ( __gDiskArbAck == 0 )
834                            {
835                                dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
836                            }
837                        }
838                    }
839                }
840            }
841            else
842            {
843                dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
844            }
845        }
846        else
847        {
848            dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
849        }
850    }
851
852    if ( dissenter == NULL )
853    {
854        CFSetRemoveValue( __gDiskArbReservationList, disk );
855    }
856
857    return dissenter;
858}
859
860static void __DiskArbDiskDescriptionChangedCallback( DADiskRef disk, CFArrayRef keys, void * context )
861{
862    CFDictionaryRef description;
863
864    description = DADiskCopyDescription( disk );
865
866    if ( description )
867    {
868        if ( ___CFArrayContainsValue( keys, kDADiskDescriptionVolumeNameKey ) )
869        {
870            if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey ) )
871            {
872                char * name;
873                char * path;
874
875                name = __DiskArbCopyDiskDescriptionVolumeName( disk );
876                path = __DiskArbCopyDiskDescriptionVolumePath( disk );
877
878                __DiskArbCallback_DiskChangedNotification( __DiskArbGetDiskID( disk ), path, name, 0, kDiskArbRenameSuccessful );
879
880                if ( name )  free( name );
881                if ( path )  free( path );
882            }
883        }
884        else if ( ___CFArrayContainsValue( keys, kDADiskDescriptionVolumePathKey ) )
885        {
886            if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey ) )
887            {
888                __DiskArbDiskAppearedCallback( disk, NULL );
889            }
890            else
891            {
892                CFSetRemoveValue( __gDiskArbUnmountList, disk );
893
894                __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
895            }
896        }
897
898        CFRelease( description );
899    }
900}
901
902static void __DiskArbDiskDisappearedCallback( DADiskRef disk, void * context )
903{
904    CFDictionaryRef description;
905
906    CFSetRemoveValue( __gDiskArbUnmountList, disk );
907
908    CFSetRemoveValue( __gDiskArbEjectList, disk );
909
910    description = DADiskCopyDescription( disk );
911
912    if ( description )
913    {
914        if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey ) )
915        {
916            __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
917        }
918
919        CFRelease( description );
920    }
921
922    __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
923}
924
925static void __DiskArbDiskEjectCallback( DADiskRef disk, DADissenterRef dissenter, void * context )
926{
927    if ( dissenter )
928    {
929        io_service_t media;
930        DAReturn     status;
931
932        status = DADissenterGetStatus( dissenter );
933
934        media = DADiskCopyIOMedia( disk );
935
936        if ( media )
937        {
938            io_iterator_t services = IO_OBJECT_NULL;
939
940            IORegistryEntryCreateIterator( media, kIOServicePlane, kIORegistryIterateRecursively, &services );
941
942            if ( services )
943            {
944                io_service_t service;
945
946                while ( ( service = IOIteratorNext( services ) ) )
947                {
948                    if ( IOObjectConformsTo( service, kIOMediaClass ) )
949                    {
950                        DADiskRef child;
951
952                        child = DADiskCreateFromIOMedia( kCFAllocatorDefault, __gDiskArbSession, service );
953
954                        if ( child )
955                        {
956                            CFSetRemoveValue( __gDiskArbEjectList, child );
957
958                            __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( child ), status ? EBUSY : 0, status ? -1 : 0 );
959
960                            CFRelease( child );
961                        }
962                    }
963
964                    IOObjectRelease( service );
965                }
966
967                IOObjectRelease( services );
968            }
969
970            IOObjectRelease( media );
971        }
972
973        CFSetRemoveValue( __gDiskArbEjectList, disk );
974
975        __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( disk ), status ? EBUSY : 0, status ? -1 : 0 );
976
977        if ( ( ( ( int ) context ) & kDiskArbUnmountAndEjectFlag ) )
978        {
979            __DiskArbCallback_CallFailedNotification( __DiskArbGetDiskID( disk ), kDiskArbUnmountAndEjectRequestFailed, status ? EBUSY : 0 );
980        }
981        else
982        {
983            __DiskArbCallback_CallFailedNotification( __DiskArbGetDiskID( disk ), kDiskArbEjectRequestFailed, status ? EBUSY : 0 );
984        }
985    }
986    else
987    {
988        io_service_t media;
989
990        media = DADiskCopyIOMedia( disk );
991
992        if ( media )
993        {
994            io_iterator_t services = IO_OBJECT_NULL;
995
996            IORegistryEntryCreateIterator( media, kIOServicePlane, kIORegistryIterateRecursively, &services );
997
998            if ( services )
999            {
1000                io_service_t service;
1001
1002                while ( ( service = IOIteratorNext( services ) ) )
1003                {
1004                    if ( IOObjectConformsTo( service, kIOMediaClass ) )
1005                    {
1006                        DADiskRef child;
1007
1008                        child = DADiskCreateFromIOMedia( kCFAllocatorDefault, __gDiskArbSession, service );
1009
1010                        if ( child )
1011                        {
1012                            CFSetRemoveValue( __gDiskArbEjectList, child );
1013
1014                            __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( child ), 0, 0 );
1015
1016                            CFRelease( child );
1017                        }
1018                    }
1019
1020                    IOObjectRelease( service );
1021                }
1022
1023                IOObjectRelease( services );
1024            }
1025
1026            IOObjectRelease( media );
1027        }
1028
1029        CFSetRemoveValue( __gDiskArbEjectList, disk );
1030
1031        __DiskArbCallback_EjectPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
1032    }
1033}
1034
1035static DADissenterRef __DiskArbDiskEjectApprovalCallback( DADiskRef disk, void * context )
1036{
1037    CFArrayRef     callbacks;
1038    DADissenterRef dissenter = NULL;
1039
1040    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_EJECT_PRE_NOTIFY );
1041
1042    if ( callbacks )
1043    {
1044        io_service_t media;
1045
1046        media = DADiskCopyIOMedia( disk );
1047
1048        if ( media )
1049        {
1050            io_iterator_t services = IO_OBJECT_NULL;
1051
1052            IORegistryEntryCreateIterator( media, kIOServicePlane, kIORegistryIterateRecursively, &services );
1053
1054            if ( services )
1055            {
1056                io_service_t service;
1057
1058                IOObjectRetain( media );
1059
1060                for ( service = media; service; service = IOIteratorNext( services ) )
1061                {
1062                    if ( IOObjectConformsTo( service, kIOMediaClass ) )
1063                    {
1064                        DADiskRef child;
1065
1066                        child = DADiskCreateFromIOMedia( kCFAllocatorDefault, __gDiskArbSession, service );
1067
1068                        if ( child )
1069                        {
1070                            CFIndex count;
1071                            CFIndex index;
1072
1073                            count = CFArrayGetCount( callbacks );
1074
1075                            for ( index = 0; index < count; index++ )
1076                            {
1077                                DiskArbCallback_EjectPreNotification_t callback;
1078
1079                                callback = CFArrayGetValueAtIndex( callbacks, index );
1080
1081                                if ( callback )
1082                                {
1083                                    __gDiskArbAck = 0;
1084
1085                                    ( callback )( __DiskArbGetDiskID( child ), 0 );
1086
1087                                    if ( dissenter == NULL )
1088                                    {
1089                                        switch ( __gDiskArbAck )
1090                                        {
1091                                            case 0:
1092                                            {
1093                                                break;
1094                                            }
1095                                            default:
1096                                            {
1097                                                dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
1098
1099                                                break;
1100                                            }
1101                                        }
1102                                    }
1103                                }
1104                            }
1105
1106                            CFSetSetValue( __gDiskArbEjectList, child );
1107
1108                            CFRelease( child );
1109                        }
1110                    }
1111
1112                    IOObjectRelease( service );
1113                }
1114
1115                IOObjectRelease( services );
1116            }
1117
1118            IOObjectRelease( media );
1119        }
1120    }
1121
1122    return dissenter;
1123}
1124
1125static void __DiskArbDiskMountCallback( DADiskRef disk, DADissenterRef dissenter, void * context )
1126{
1127    if ( dissenter )
1128    {
1129///w:start
1130        DAReturn status;
1131
1132        status = DADissenterGetStatus( dissenter );
1133
1134        if ( __gDiskArbStatusLock )
1135        {
1136             if ( status )
1137             {
1138                 __gDiskArbStatus = status;
1139
1140                 return;
1141             }
1142        }
1143///w:stop
1144        __DiskArbDiskAppearedCallback( disk, NULL );
1145    }
1146    else
1147    {
1148        if ( context )
1149        {
1150            __DiskArbDiskAppearedCallback( disk, NULL );
1151        }
1152    }
1153}
1154
1155static DADissenterRef __DiskArbDiskMountApprovalCallback( DADiskRef disk, void * context )
1156{
1157    CFArrayRef     callbacks  = NULL;
1158    char *         content    = NULL;
1159    DADissenterRef dissenter  = NULL;
1160    char *         filesystem = NULL;
1161    unsigned       flags      = 0;
1162    char *         name       = NULL;
1163    char *         path       = NULL;
1164    int            removable  = FALSE;
1165    int            whole      = FALSE;
1166    int            writable   = FALSE;
1167
1168    content    = __DiskArbCopyDiskDescriptionMediaContent( disk );
1169    filesystem = __DiskArbCopyDiskDescriptionVolumeKind( disk );
1170    flags      = __DiskArbCopyDiskDescriptionFlags( disk );
1171    name       = __DiskArbCopyDiskDescriptionVolumeName( disk );
1172    path       = __DiskArbCopyDiskDescriptionDeviceTreePath( disk );
1173    removable  = ( flags & kDiskArbDiskAppearedEjectableMask ) ? TRUE : FALSE;
1174    whole      = ( flags & kDiskArbDiskAppearedWholeDiskMask ) ? TRUE : FALSE;
1175    writable   = ( flags & kDiskArbDiskAppearedLockedMask ) ? FALSE : TRUE;
1176
1177    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_APPROVAL_NOTIFY );
1178
1179    if ( callbacks )
1180    {
1181        CFIndex count;
1182        CFIndex index;
1183
1184        count = CFArrayGetCount( callbacks );
1185
1186        for ( index = 0; index < count; index++ )
1187        {
1188            DiskArbCallback_DiskApprovalNotification_t callback;
1189
1190            callback = CFArrayGetValueAtIndex( callbacks, index );
1191
1192            if ( callback )
1193            {
1194                __gDiskArbAck = 0;
1195
1196                ( callback )( __DiskArbGetDiskID( disk ), name, content, path, flags, writable, removable, whole, filesystem );
1197
1198                if ( dissenter == NULL )
1199                {
1200///w:start
1201                    if ( ( __gDiskArbAck & kDiskArbEjectDevice ) )
1202                    {
1203                        if ( removable )
1204                        {
1205                            DiskArbEjectRequest_async_auto( __DiskArbGetDiskID( disk ), 0 );
1206                        }
1207
1208                        __gDiskArbAck &= ~kDiskArbEjectDevice;
1209
1210                        if ( __gDiskArbAck == 0 )
1211                        {
1212                            __gDiskArbAck = kDiskArbDisallowMounting;
1213                        }
1214                    }
1215///w:stop
1216
1217                    switch ( __gDiskArbAck )
1218                    {
1219                        case 0:
1220                        {
1221                            break;
1222                        }
1223///w:start
1224                        case kDiskArbMountReadOnly | kDiskArbRequireAuthentication:
1225                        {
1226                            dissenter = DADissenterCreate( kCFAllocatorDefault, 0xF8DAFF03, NULL );
1227
1228                            break;
1229                        }
1230                        case kDiskArbMountReadOnly:
1231                        {
1232                            dissenter = DADissenterCreate( kCFAllocatorDefault, 0xF8DAFF02, NULL );
1233
1234                            break;
1235                        }
1236                        case kDiskArbRequireAuthentication:
1237                        {
1238                            dissenter = DADissenterCreate( kCFAllocatorDefault, 0xF8DAFF01, NULL );
1239
1240                            break;
1241                        }
1242///w:stop
1243                        default:
1244                        {
1245                            dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
1246
1247                            break;
1248                        }
1249                    }
1250                }
1251            }
1252        }
1253    }
1254
1255    if ( content    )  free( content    );
1256    if ( filesystem )  free( filesystem );
1257    if ( name       )  free( name       );
1258    if ( path       )  free( path       );
1259
1260    return dissenter;
1261}
1262
1263static void __DiskArbDiskPeekCallback( DADiskRef disk, void * context )
1264{
1265    CFDictionaryRef description = NULL;
1266    unsigned        flags       = 0;
1267    CFStringRef     kind        = NULL;
1268    int             removable   = FALSE;
1269    UInt64          size        = 0;
1270    int             type        = 0;
1271    int             whole       = FALSE;
1272    int             writable    = FALSE;
1273
1274    description = DADiskCopyDescription( disk );
1275
1276    if ( description )
1277    {
1278        flags      = __DiskArbCopyDiskDescriptionFlags( disk );
1279        kind       = CFDictionaryGetValue( description, kDADiskDescriptionMediaKindKey );
1280        removable  = ( flags & kDiskArbDiskAppearedEjectableMask ) ? TRUE : FALSE;
1281        size       = ___CFDictionaryGetIntegerValue( description, kDADiskDescriptionMediaSizeKey );
1282        whole      = ( flags & kDiskArbDiskAppearedWholeDiskMask ) ? TRUE : FALSE;
1283        writable   = ( flags & kDiskArbDiskAppearedLockedMask ) ? FALSE : TRUE;
1284
1285        if ( CFEqual( kind, CFSTR( kIOBDMediaClass ) ) )
1286        {
1287            type = size ? kDiskArbHandlesUnrecognizedBDMedia : kDiskArbHandlesUninitializedBDMedia;
1288        }
1289        else if ( CFEqual( kind, CFSTR( kIOCDMediaClass ) ) )
1290        {
1291            type = size ? kDiskArbHandlesUnrecognizedCDMedia : kDiskArbHandlesUninitializedCDMedia;
1292        }
1293        else if ( CFEqual( kind, CFSTR( kIODVDMediaClass ) ) )
1294        {
1295            type = size ? kDiskArbHandlesUnrecognizedDVDMedia : kDiskArbHandlesUninitializedDVDMedia;
1296        }
1297        else if ( CFDictionaryGetValue( description, kDADiskDescriptionMediaEjectableKey ) == kCFBooleanTrue )
1298        {
1299            type = size ? kDiskArbHandlesUnrecognizedOtherRemovableMedia : kDiskArbHandlesUninitializedOtherRemovableMedia;
1300        }
1301        else
1302        {
1303            type = size ? kDiskArbHandlesUnrecognizedFixedMedia : kDiskArbHandlesUninitializedFixedMedia;
1304        }
1305
1306        CFRelease( description );
1307    }
1308
1309    if ( context )
1310    {
1311        if ( __gDiskArbHandlesUnrecognized )
1312        {
1313            DADiskClaim( disk, kDADiskClaimOptionDefault, __DiskArbDiskClaimReleaseCallback, ( void * ) 1, __DiskArbDiskClaimCallback, ( void * ) 1 );
1314        }
1315    }
1316    else
1317    {
1318        if ( __gDiskArbHandlesUnrecognizedPriority > 0 )
1319        {
1320            if ( ( __gDiskArbHandlesUnrecognizedTypes & type ) )
1321            {
1322                CFArrayRef callbacks;
1323
1324                callbacks = __DiskArbGetCallbackHandler( kDA_CLIENT_WILL_HANDLE_UNRECOGNIZED_DISK );
1325
1326                if ( callbacks )
1327                {
1328                    CFIndex count;
1329                    CFIndex index;
1330
1331                    count = CFArrayGetCount( callbacks );
1332
1333                    for ( index = 0; index < count; index++ )
1334                    {
1335                        DiskArbCallback_Will_Client_Handle_Unrecognized_Disk_t callback;
1336
1337                        callback = CFArrayGetValueAtIndex( callbacks, index );
1338
1339                        ( callback )( __DiskArbGetDiskID( disk ), type, "", "", writable, removable, whole );
1340                    }
1341                }
1342            }
1343        }
1344    }
1345}
1346
1347static void __DiskArbDiskRenameCallback( DADiskRef disk, DADissenterRef dissenter, void * context )
1348{
1349    if ( dissenter )
1350    {
1351        DAReturn status;
1352
1353        status = DADissenterGetStatus( dissenter );
1354///w:start
1355        if ( __gDiskArbStatusLock )
1356        {
1357             if ( status )
1358             {
1359                 __gDiskArbStatus = status;
1360
1361                 return;
1362             }
1363        }
1364///w:stop
1365
1366        __DiskArbCallback_DiskChangedNotification( __DiskArbGetDiskID( disk ), "", "", 0, 0 );
1367
1368        __DiskArbCallback_CallFailedNotification( __DiskArbGetDiskID( disk ), kDiskArbDiskChangeRequestFailed, status ? EBUSY : 0 );
1369    }
1370}
1371
1372static void __DiskArbDiskUnmountCallback( DADiskRef disk, DADissenterRef dissenter, void * context )
1373{
1374    if ( dissenter )
1375    {
1376        DAReturn status;
1377
1378        status = DADissenterGetStatus( dissenter );
1379///w:start
1380        if ( __gDiskArbStatusLock )
1381        {
1382             if ( status )
1383             {
1384                 __gDiskArbStatus = status;
1385
1386                 return;
1387             }
1388        }
1389///w:stop
1390
1391        if ( ( ( ( int ) context ) & kDiskArbUnmountOneFlag ) == 0 )
1392        {
1393            io_service_t media;
1394
1395            media = DADiskCopyIOMedia( disk );
1396
1397            if ( media )
1398            {
1399                io_iterator_t services = IO_OBJECT_NULL;
1400
1401                IORegistryEntryCreateIterator( media, kIOServicePlane, kIORegistryIterateRecursively, &services );
1402
1403                if ( services )
1404                {
1405                    io_service_t service;
1406
1407                    while ( ( service = IOIteratorNext( services ) ) )
1408                    {
1409                        if ( IOObjectConformsTo( service, kIOMediaClass ) )
1410                        {
1411                            DADiskRef child;
1412
1413                            child = DADiskCreateFromIOMedia( kCFAllocatorDefault, __gDiskArbSession, service );
1414
1415                            if ( child )
1416                            {
1417                                if ( __DiskArbGetFileSystemStatus( __DiskArbGetDiskID( child ) ) )
1418                                {
1419                                    CFSetRemoveValue( __gDiskArbUnmountList, child );
1420
1421                                    __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( child ), status ? EBUSY : 0, status ? -1 : 0 );
1422                                }
1423
1424                                CFRelease( child );
1425                            }
1426                        }
1427
1428                        IOObjectRelease( service );
1429                    }
1430
1431                    IOObjectRelease( services );
1432                }
1433
1434                IOObjectRelease( media );
1435            }
1436        }
1437
1438        if ( status == kDAReturnNotMounted )
1439        {
1440            CFSetRemoveValue( __gDiskArbUnmountList, disk );
1441
1442            __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
1443        }
1444        else
1445        {
1446            CFSetRemoveValue( __gDiskArbUnmountList, disk );
1447
1448            __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), status ? EBUSY : 0, status ? -1 : 0 );
1449
1450            if ( ( ( ( int ) context ) & kDiskArbUnmountAndEjectFlag ) )
1451            {
1452                __DiskArbCallback_CallFailedNotification( __DiskArbGetDiskID( disk ), kDiskArbUnmountAndEjectRequestFailed, status ? EBUSY : 0 );
1453            }
1454            else
1455            {
1456                __DiskArbCallback_CallFailedNotification( __DiskArbGetDiskID( disk ), kDiskArbUnmountRequestFailed, status ? EBUSY : 0 );
1457            }
1458        }
1459    }
1460    else
1461    {
1462        if ( ( ( ( int ) context ) & kDiskArbUnmountOneFlag ) == 0 )
1463        {
1464            CFSetRemoveValue( __gDiskArbUnmountList, disk );
1465
1466            __DiskArbCallback_UnmountPostNotification( __DiskArbGetDiskID( disk ), 0, 0 );
1467        }
1468
1469        if ( ( ( ( int ) context ) & kDiskArbUnmountAndEjectFlag ) )
1470        {
1471            DADiskEject( disk, kDADiskEjectOptionDefault, __DiskArbDiskEjectCallback, ( void * ) kDiskArbUnmountAndEjectFlag );
1472        }
1473    }
1474}
1475
1476static DADissenterRef __DiskArbDiskUnmountApprovalCallback( DADiskRef disk, void * context )
1477{
1478    CFArrayRef     callbacks;
1479    DADissenterRef dissenter = NULL;
1480
1481    callbacks = __DiskArbGetCallbackHandler( kDA_DISK_UNMOUNT_PRE_NOTIFY );
1482
1483    if ( callbacks )
1484    {
1485        CFIndex count;
1486        CFIndex index;
1487
1488        count = CFArrayGetCount( callbacks );
1489
1490        for ( index = 0; index < count; index++ )
1491        {
1492            DiskArbCallback_UnmountPreNotification_t callback;
1493
1494            callback = CFArrayGetValueAtIndex( callbacks, index );
1495
1496            if ( callback )
1497            {
1498                __gDiskArbAck = 0;
1499
1500                ( callback )( __DiskArbGetDiskID( disk ), 0 );
1501
1502                if ( dissenter == NULL )
1503                {
1504                    switch ( __gDiskArbAck )
1505                    {
1506                        case 0:
1507                        {
1508                            break;
1509                        }
1510                        default:
1511                        {
1512                            dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted, NULL );
1513
1514                            break;
1515                        }
1516                    }
1517                }
1518            }
1519        }
1520
1521        CFSetSetValue( __gDiskArbUnmountList, disk );
1522    }
1523
1524    return dissenter;
1525}
1526
1527static void __DiskArbIdleCallback( void * context )
1528{
1529    CFArrayRef callbacks;
1530
1531    CFSetApplyFunction( __gDiskArbUnmountList, __DiskArbCallback_UnmountPostNotificationApplier, ( void * ) 1 );
1532
1533    CFSetRemoveAllValues( __gDiskArbUnmountList );
1534
1535    CFSetApplyFunction( __gDiskArbEjectList, __DiskArbCallback_EjectPostNotificationApplier, ( void * ) 1 );
1536
1537    CFSetRemoveAllValues( __gDiskArbEjectList );
1538
1539    callbacks = __DiskArbGetCallbackHandler( kDA_NOTIFICATIONS_COMPLETE );
1540
1541    if ( callbacks )
1542    {
1543        CFIndex count;
1544        CFIndex index;
1545
1546        count = CFArrayGetCount( callbacks );
1547
1548        for ( index = 0; index < count; index++ )
1549        {
1550            DiskArbCallback_NotificationComplete_t callback;
1551
1552            callback = CFArrayGetValueAtIndex( callbacks, index );
1553
1554            if ( callback )
1555            {
1556                if ( ( __gDiskArbNotificationComplete & kDiskArbCompletedDiskAppeared ) )
1557                {
1558                    ( callback )( kDiskArbCompletedDiskAppeared );
1559                }
1560
1561                if ( ( __gDiskArbNotificationComplete & kDiskArbCompletedPostUnmount ) )
1562                {
1563                    ( callback )( kDiskArbCompletedPostUnmount );
1564                }
1565
1566                if ( ( __gDiskArbNotificationComplete & kDiskArbCompletedPostEject ) )
1567                {
1568                    ( callback )( kDiskArbCompletedPostEject );
1569                }
1570            }
1571        }
1572    }
1573
1574    __gDiskArbNotificationComplete = 0;
1575}
1576
1577void DiskArbAddCallbackHandler( int type, void * callback, int overwrite )
1578{
1579    if ( __gDiskArbCallbackList == NULL )
1580    {
1581        __gDiskArbCallbackList = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
1582
1583        assert( __gDiskArbCallbackList );
1584
1585        __gDiskArbEjectList = CFSetCreateMutable( kCFAllocatorDefault, 0, &kCFTypeSetCallBacks );
1586
1587        assert( __gDiskArbEjectList );
1588
1589        __gDiskArbRegisterList = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
1590
1591        assert( __gDiskArbRegisterList );
1592
1593        __gDiskArbReservationList = CFSetCreateMutable( kCFAllocatorDefault, 0, &kCFTypeSetCallBacks );
1594
1595        assert( __gDiskArbReservationList );
1596
1597        __gDiskArbUnmountList = CFSetCreateMutable( kCFAllocatorDefault, 0, &kCFTypeSetCallBacks );
1598
1599        assert( __gDiskArbUnmountList );
1600    }
1601
1602    if ( callback )
1603    {
1604        CFNumberRef key;
1605
1606        key = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &type );
1607
1608        if ( key )
1609        {
1610            CFMutableArrayRef callbacks;
1611
1612            callbacks = ( void * ) CFDictionaryGetValue( __gDiskArbCallbackList, key );
1613
1614            if ( callbacks )
1615            {
1616                CFRetain( callbacks );
1617            }
1618            else
1619            {
1620                callbacks = CFArrayCreateMutable( kCFAllocatorDefault, 0, NULL );
1621
1622                CFArrayAppendValue( __gDiskArbRegisterList, key );
1623            }
1624
1625            if ( callbacks )
1626            {
1627                if ( overwrite )
1628                {
1629                    CFArrayRemoveAllValues( callbacks );
1630                }
1631
1632                CFArrayAppendValue( callbacks, callback );
1633
1634                CFDictionarySetValue( __gDiskArbCallbackList, key, callbacks );
1635
1636                CFRelease( callbacks );
1637            }
1638
1639            CFRelease( key );
1640        }
1641    }
1642}
1643
1644kern_return_t DiskArbClientHandlesUninitializedDisks_auto( int yes )
1645{
1646    if ( __gDiskArbSession )
1647    {
1648        static Boolean registered = FALSE;
1649
1650        __gDiskArbHandlesUnrecognized = yes;
1651
1652        if ( yes )
1653        {
1654            if ( registered == FALSE )
1655            {
1656                DARegisterDiskPeekCallback( __gDiskArbSession, kDADiskDescriptionMatchVolumeUnrecognized, -16384, __DiskArbDiskPeekCallback, ( void * ) 1 );
1657
1658                registered = TRUE;
1659            }
1660        }
1661    }
1662
1663    return KERN_SUCCESS;
1664}
1665
1666kern_return_t DiskArbClientHandlesUnrecognizedDisks( int types, int priority )
1667{
1668    if ( __gDiskArbSession )
1669    {
1670        static Boolean registered = FALSE;
1671
1672        __gDiskArbHandlesUnrecognizedPriority = priority;
1673        __gDiskArbHandlesUnrecognizedTypes    = types;
1674
1675        if ( priority > 0 )
1676        {
1677            if ( registered == FALSE )
1678            {
1679                DARegisterDiskPeekCallback( __gDiskArbSession, kDADiskDescriptionMatchVolumeUnrecognized, 16384 - priority, __DiskArbDiskPeekCallback, NULL );
1680
1681                registered = TRUE;
1682            }
1683        }
1684    }
1685
1686    return KERN_SUCCESS;
1687}
1688
1689kern_return_t DiskArbClientRelinquishesReservation( char * disk, int pid, int status )
1690{
1691    __gDiskArbAck = status;
1692
1693    return KERN_SUCCESS;
1694}
1695
1696kern_return_t DiskArbClientWillHandleUnrecognizedDisk( char * disk, int yes )
1697{
1698    if ( yes )
1699    {
1700        DADiskRef _disk;
1701
1702        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
1703
1704        if ( _disk )
1705        {
1706            DADiskClaim( _disk, kDADiskClaimOptionDefault, __DiskArbDiskClaimReleaseCallback, NULL, __DiskArbDiskClaimCallback, ( void * ) 1 );
1707
1708            CFRelease( _disk );
1709        }
1710    }
1711
1712    return KERN_SUCCESS;
1713}
1714
1715kern_return_t DiskArbDiskAppearedWithMountpointPing_auto( char * disk, unsigned reserved, char * mountpoint )
1716{
1717    return KERN_SUCCESS;
1718}
1719
1720kern_return_t DiskArbDiskApprovedAck_auto( char * disk, int status )
1721{
1722    __gDiskArbAck = status;
1723
1724    return KERN_SUCCESS;
1725}
1726
1727kern_return_t DiskArbDiskDisappearedPing_auto( char * disk, unsigned reserved )
1728{
1729    return KERN_SUCCESS;
1730}
1731
1732kern_return_t DiskArbEjectPreNotifyAck_async_auto( char * disk, int status )
1733{
1734    __gDiskArbAck = status;
1735
1736    return KERN_SUCCESS;
1737}
1738
1739kern_return_t DiskArbEjectRequest_async_auto( char * disk, unsigned flags )
1740{
1741    kern_return_t status;
1742
1743    status = KERN_FAILURE;
1744
1745    if ( disk )
1746    {
1747        DADiskRef _disk;
1748
1749        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
1750
1751        if ( _disk )
1752        {
1753            DADiskRef whole;
1754
1755            whole = DADiskCopyWholeDisk( _disk );
1756
1757            if ( whole )
1758            {
1759                DADiskEject( whole, kDADiskEjectOptionDefault, __DiskArbDiskEjectCallback, NULL );
1760
1761                status = KERN_SUCCESS;
1762
1763                CFRelease( whole );
1764            }
1765
1766            CFRelease( _disk );
1767        }
1768    }
1769
1770    return status;
1771}
1772
1773int DiskArbGetVolumeEncoding_auto( char * disk )
1774{
1775    struct attr_text_encoding_t
1776    {
1777        size_t          size;
1778        text_encoding_t text_encoding;
1779    };
1780
1781    struct attr_text_encoding_t attr;
1782    struct attrlist             attrlist;
1783    struct statfs *             fs;
1784
1785    bzero( &attrlist, sizeof( attrlist ) );
1786
1787    attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
1788    attrlist.commonattr  = ATTR_CMN_SCRIPT;
1789
1790    fs = __DiskArbGetFileSystemStatus( disk );
1791
1792    return fs ? ( getattrlist( fs->f_mntonname, &attrlist, &attr, sizeof( attr ), 0 ) ? -1 : ( int ) attr.text_encoding ) : -1;
1793}
1794
1795boolean_t DiskArbHandleMsg( mach_msg_header_t * message, mach_msg_header_t * reply )
1796{
1797    if ( reply )
1798    {
1799        reply->msgh_bits        = MACH_MSGH_BITS_ZERO;
1800        reply->msgh_id          = 0;
1801        reply->msgh_local_port  = MACH_PORT_NULL;
1802        reply->msgh_remote_port = MACH_PORT_NULL;
1803        reply->msgh_reserved    = 0;
1804        reply->msgh_size        = sizeof( mach_msg_header_t );
1805    }
1806
1807    if ( message->msgh_id == 0 )
1808    {
1809        _DASessionCallback( NULL, message, message->msgh_size, __gDiskArbSession );
1810
1811        return TRUE;
1812    }
1813
1814    return FALSE;
1815}
1816
1817kern_return_t DiskArbInit( void )
1818{
1819    if ( __gDiskArbSession == NULL )
1820    {
1821        __gDiskArbSession = DASessionCreate( kCFAllocatorDefault );
1822
1823        if ( __gDiskArbSession )
1824        {
1825            _DASessionScheduleWithRunLoop( __gDiskArbSession );
1826        }
1827    }
1828
1829    return __gDiskArbSession ? BOOTSTRAP_SUCCESS : BOOTSTRAP_UNKNOWN_SERVICE;
1830}
1831
1832int DiskArbIsActive( void )
1833{
1834    return __gDiskArbSession ? 1 : 0;
1835}
1836
1837kern_return_t DiskArbIsDeviceReservedForClient( char * disk )
1838{
1839    kern_return_t status;
1840
1841    status = KERN_FAILURE;
1842
1843    if ( disk )
1844    {
1845        DADiskRef _disk;
1846
1847        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
1848
1849        if ( _disk )
1850        {
1851            status = DADiskIsClaimed( _disk ) ? kDiskArbDeviceIsReserved : kDiskArbDeviceIsNotReserved;
1852
1853            if ( CFSetContainsValue( __gDiskArbReservationList, _disk ) )
1854            {
1855                __DiskArbCallback_Device_Reservation_Status( disk, status, getpid( ) );
1856            }
1857            else
1858            {
1859                __DiskArbCallback_Device_Reservation_Status( disk, status, -1 );
1860            }
1861
1862            status = KERN_SUCCESS;
1863
1864            CFRelease( _disk );
1865        }
1866    }
1867
1868    return status;
1869}
1870
1871kern_return_t DiskArbMsgLoop( void )
1872{
1873    return DiskArbMsgLoopWithTimeout( MACH_MSG_TIMEOUT_NONE );
1874}
1875
1876kern_return_t DiskArbMsgLoopWithTimeout( mach_msg_timeout_t timeout )
1877{
1878    mach_msg_return_t status;
1879
1880    status = KERN_FAILURE;
1881
1882    if ( __gDiskArbSession )
1883    {
1884        mach_msg_empty_rcv_t message;
1885
1886        status = mach_msg( ( void * ) &message,
1887                           MACH_RCV_MSG | ( timeout ? MACH_RCV_TIMEOUT : 0 ),
1888                           0,
1889                           sizeof( message ),
1890                           _DASessionGetClientPort( __gDiskArbSession ),
1891                           timeout,
1892                           MACH_PORT_NULL );
1893
1894        if ( status == MACH_MSG_SUCCESS )
1895        {
1896            DiskArbHandleMsg( ( void * ) &message, NULL );
1897        }
1898    }
1899
1900    return status;
1901}
1902
1903void DiskArbNoOp( void )
1904{
1905    return;
1906}
1907
1908kern_return_t DiskArbRefresh_auto( void )
1909{
1910    return KERN_SUCCESS;
1911}
1912
1913void DiskArbRegisterCallback_CallFailedNotification( DiskArbCallback_CallFailedNotification_t callback )
1914{
1915    DiskArbAddCallbackHandler( kDA_CALL_FAILED, callback, 0 );
1916}
1917
1918void DiskArbRegisterCallback_CallSucceededNotification( DiskArbCallback_CallSucceededNotification_t callback )
1919{
1920    return;
1921}
1922
1923void DiskArbRegisterCallback_ClientDisconnectedNotification( DiskArbCallback_ClientDisconnectedNotification_t callback )
1924{
1925    return;
1926}
1927
1928void DiskArbRegisterCallback_DiskAppeared( DiskArbCallback_DiskAppeared_t callback )
1929{
1930    DiskArbAddCallbackHandler( kDA_DISK_APPEARED1, callback, 0 );
1931}
1932
1933void DiskArbRegisterCallback_DiskAppeared2( DiskArbCallback_DiskAppeared2_t callback )
1934{
1935    DiskArbAddCallbackHandler( kDA_DISK_APPEARED, callback, 0 );
1936}
1937
1938void DiskArbRegisterCallback_DiskAppearedWithMountpoint( DiskArbCallback_DiskAppearedWithMountpoint_t callback )
1939{
1940    DiskArbAddCallbackHandler( kDA_DISK_APPEARED_WITH_MT, callback, 0 );
1941}
1942
1943void DiskArbRegisterCallback_DiskChangedNotification( DiskArbCallback_DiskChangedNotification_t callback )
1944{
1945    DiskArbAddCallbackHandler( kDA_DISK_CHANGED, callback, 0 );
1946}
1947
1948void DiskArbRegisterCallback_DiskWillBeCheckedNotification( DiskArbCallback_DiskWillBeCheckedNotification_t callback )
1949{
1950    return;
1951}
1952
1953void DiskArbRegisterCallback_EjectPostNotification( DiskArbCallback_EjectPostNotification_t callback )
1954{
1955    DiskArbAddCallbackHandler( kDA_DISK_EJECT_POST_NOTIFY, callback, 0 );
1956}
1957
1958void DiskArbRegisterCallback_EjectPreNotification( DiskArbCallback_EjectPreNotification_t callback )
1959{
1960    DiskArbAddCallbackHandler( kDA_DISK_EJECT_PRE_NOTIFY, callback, 1 );
1961}
1962
1963void DiskArbRegisterCallback_NotificationComplete( DiskArbCallback_NotificationComplete_t callback )
1964{
1965    DiskArbAddCallbackHandler( kDA_NOTIFICATIONS_COMPLETE, callback, 0 );
1966}
1967
1968void DiskArbRegisterCallback_UnknownFileSystemNotification( DiskArbCallback_UnknownFileSystemNotification_t callback )
1969{
1970    return;
1971}
1972
1973void DiskArbRegisterCallback_UnmountPostNotification( DiskArbCallback_UnmountPostNotification_t callback )
1974{
1975    DiskArbAddCallbackHandler( kDA_DISK_UNMOUNT_POST_NOTIFY, callback, 0 );
1976}
1977
1978void DiskArbRegisterCallback_UnmountPreNotification( DiskArbCallback_UnmountPreNotification_t callback )
1979{
1980    DiskArbAddCallbackHandler( kDA_DISK_UNMOUNT_PRE_NOTIFY, callback, 1 );
1981}
1982
1983kern_return_t DiskArbReleaseClientReservationForDevice( char * disk )
1984{
1985    kern_return_t status;
1986
1987    status = KERN_FAILURE;
1988
1989    if ( disk )
1990    {
1991        DADiskRef _disk;
1992
1993        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
1994
1995        if ( _disk )
1996        {
1997            CFSetRemoveValue( __gDiskArbReservationList, _disk );
1998
1999            DADiskUnclaim( _disk );
2000
2001            status = KERN_SUCCESS;
2002
2003            CFRelease( _disk );
2004        }
2005    }
2006
2007    return status;
2008}
2009
2010void DiskArbRemoveCallbackHandler( int type, void * callback )
2011{
2012    if ( __gDiskArbCallbackList )
2013    {
2014        CFNumberRef key;
2015
2016        key = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &type );
2017
2018        if ( key )
2019        {
2020            CFMutableArrayRef callbacks;
2021
2022            callbacks = ( void * ) CFDictionaryGetValue( __gDiskArbCallbackList, key );
2023
2024            if ( callbacks )
2025            {
2026                ___CFArrayRemoveValue( callbacks, callback );
2027            }
2028
2029            CFRelease( key );
2030        }
2031    }
2032}
2033
2034kern_return_t DiskArbRequestDiskChange_auto( char * disk, char * name, int flags )
2035{
2036    kern_return_t status;
2037
2038    status = KERN_FAILURE;
2039
2040    if ( disk )
2041    {
2042        DADiskRef _disk;
2043
2044        _disk = NULL;
2045
2046        if ( strncmp( disk, "disk", strlen( "disk" ) ) )
2047        {
2048            struct statfs * fs;
2049
2050            fs = __DiskArbGetFileSystemStatus( disk );
2051
2052            if ( fs )
2053            {
2054                CFURLRef path;
2055
2056                path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) fs->f_mntonname, strlen( fs->f_mntonname ), TRUE );
2057
2058                if ( path )
2059                {
2060                    _disk = DADiskCreateFromVolumePath( kCFAllocatorDefault, __gDiskArbSession, path );
2061
2062                    CFRelease( path );
2063                }
2064            }
2065        }
2066        else
2067        {
2068            _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2069        }
2070
2071        if ( _disk )
2072        {
2073            CFStringRef string;
2074
2075            string = CFStringCreateWithCString( kCFAllocatorDefault, name, kCFStringEncodingUTF8 );
2076
2077            if ( string )
2078            {
2079///w:start
2080                __gDiskArbStatusLock = TRUE;
2081                __gDiskArbStatus = KERN_SUCCESS;
2082///w:stop
2083                DADiskRename( _disk, string, kDADiskRenameOptionDefault, __DiskArbDiskRenameCallback, ( void * ) flags );
2084
2085                status = KERN_SUCCESS;
2086///w:start
2087                status = __gDiskArbStatus ? KERN_FAILURE : KERN_SUCCESS;
2088                __gDiskArbStatusLock = FALSE;
2089///w:stop
2090
2091                CFRelease( string );
2092            }
2093
2094            CFRelease( _disk );
2095        }
2096    }
2097
2098    return status;
2099}
2100
2101kern_return_t DiskArbRequestMount_auto( char * disk )
2102{
2103    kern_return_t status;
2104
2105    status = KERN_FAILURE;
2106
2107    if ( disk )
2108    {
2109        DADiskRef _disk;
2110
2111        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2112
2113        if ( _disk )
2114        {
2115            DADiskRef whole;
2116
2117            whole = DADiskCopyWholeDisk( _disk );
2118
2119            if ( whole )
2120            {
2121                if ( CFEqual( whole, _disk ) )
2122                {
2123///w:start
2124                    __gDiskArbStatusLock = TRUE;
2125                    __gDiskArbStatus = KERN_SUCCESS;
2126///w:stop
2127                    DADiskMount( _disk, NULL, kDADiskMountOptionWhole, __DiskArbDiskMountCallback, ( void * ) 1 );
2128
2129                    status = KERN_SUCCESS;
2130///w:start
2131                    status = __gDiskArbStatus ? KERN_FAILURE : KERN_SUCCESS;
2132                    __gDiskArbStatusLock = FALSE;
2133///w:stop
2134                }
2135
2136                CFRelease( whole );
2137            }
2138
2139            if ( status )
2140            {
2141///w:start
2142                __gDiskArbStatusLock = TRUE;
2143                __gDiskArbStatus = KERN_SUCCESS;
2144///w:stop
2145                DADiskMount( _disk, NULL, kDADiskMountOptionDefault, __DiskArbDiskMountCallback, NULL );
2146
2147                status = KERN_SUCCESS;
2148///w:start
2149                status = __gDiskArbStatus ? KERN_FAILURE : KERN_SUCCESS;
2150                __gDiskArbStatusLock = FALSE;
2151///w:stop
2152            }
2153
2154            CFRelease( _disk );
2155        }
2156    }
2157
2158    return status;
2159}
2160
2161kern_return_t DiskArbRequestMountAndOwn_auto( char * disk )
2162{
2163    return DiskArbRequestMount_auto( disk );
2164}
2165
2166kern_return_t DiskArbRetainClientReservationForDevice( char * disk )
2167{
2168    kern_return_t status;
2169
2170    status = KERN_FAILURE;
2171
2172    if ( disk )
2173    {
2174        DADiskRef _disk;
2175
2176        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2177
2178        if ( _disk )
2179        {
2180            DADiskClaim( _disk, kDADiskClaimOptionDefault, __DiskArbDiskClaimReleaseCallback, NULL, __DiskArbDiskClaimCallback, NULL );
2181
2182            status = KERN_SUCCESS;
2183
2184            CFRelease( _disk );
2185        }
2186    }
2187
2188    return status;
2189}
2190
2191kern_return_t DiskArbSetCurrentUser_auto( int user )
2192{
2193    return KERN_FAILURE;
2194}
2195
2196kern_return_t DiskArbSetVolumeEncoding_auto( char * disk, int encoding )
2197{
2198    kern_return_t status;
2199
2200    status = KERN_FAILURE;
2201
2202    if ( disk )
2203    {
2204        DADiskRef _disk;
2205
2206        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2207
2208        if ( _disk )
2209        {
2210            status = _DADiskSetEncoding( _disk, encoding );
2211
2212            CFRelease( _disk );
2213        }
2214    }
2215
2216    return status;
2217}
2218
2219kern_return_t DiskArbStart( mach_port_t * port )
2220{
2221    kern_return_t status;
2222
2223    status = DiskArbInit( );
2224
2225    if ( status == KERN_SUCCESS )
2226    {
2227        DiskArbUpdateClientFlags( );
2228
2229        *port = _DASessionGetClientPort( __gDiskArbSession );
2230    }
2231
2232    return status;
2233}
2234
2235kern_return_t DiskArbUnmountAndEjectRequest_async_auto( char * disk, unsigned flags )
2236{
2237    return DiskArbUnmountRequest_async_auto( disk, flags | kDiskArbUnmountAndEjectFlag );
2238}
2239
2240kern_return_t DiskArbUnmountPreNotifyAck_async_auto( char * disk, int status )
2241{
2242    __gDiskArbAck = status;
2243
2244    return KERN_SUCCESS;
2245}
2246
2247kern_return_t DiskArbUnmountRequest_async_auto( char * disk, unsigned flags )
2248{
2249    kern_return_t status;
2250
2251    status = KERN_FAILURE;
2252
2253    if ( disk )
2254    {
2255        DADiskRef _disk;
2256
2257        _disk = NULL;
2258
2259        if ( strncmp( disk, "disk", strlen( "disk" ) ) )
2260        {
2261            struct statfs * fs;
2262
2263            fs = __DiskArbGetFileSystemStatus( disk );
2264
2265            if ( fs )
2266            {
2267                CFURLRef path;
2268
2269                path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) fs->f_mntonname, strlen( fs->f_mntonname ), TRUE );
2270
2271                if ( path )
2272                {
2273                    flags |=  kDiskArbUnmountOneFlag;
2274                    flags &= ~kDiskArbUnmountAndEjectFlag;
2275
2276                    if ( ( flags & kDiskArbNetworkUnmountFlag ) )
2277                    {
2278                        flags |= kDiskArbForceUnmountFlag;
2279                    }
2280
2281                    _disk = DADiskCreateFromVolumePath( kCFAllocatorDefault, __gDiskArbSession, path );
2282
2283                    CFRelease( path );
2284                }
2285            }
2286        }
2287        else
2288        {
2289            if ( ( flags & kDiskArbUnmountAndEjectFlag ) )
2290            {
2291                flags &= ~kDiskArbUnmountOneFlag;
2292            }
2293
2294            _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2295        }
2296
2297        if ( _disk )
2298        {
2299            DADiskUnmountOptions options = 0;
2300
2301            if ( ( flags & kDiskArbForceUnmountFlag ) )
2302            {
2303                options |= kDADiskUnmountOptionForce;
2304            }
2305
2306            if ( ( flags & kDiskArbUnmountOneFlag ) )
2307            {
2308///w:start
2309                __gDiskArbStatusLock = TRUE;
2310                __gDiskArbStatus = KERN_SUCCESS;
2311///w:stop
2312                DADiskUnmount( _disk, options, __DiskArbDiskUnmountCallback, ( void * ) kDiskArbUnmountOneFlag );
2313
2314                status = KERN_SUCCESS;
2315///w:start
2316                status = __gDiskArbStatus ? KERN_FAILURE : KERN_SUCCESS;
2317                __gDiskArbStatusLock = FALSE;
2318///w:stop
2319            }
2320            else
2321            {
2322                DADiskRef whole;
2323
2324                whole = DADiskCopyWholeDisk( _disk );
2325
2326                if ( whole )
2327                {
2328                    options |= kDADiskUnmountOptionWhole;
2329
2330///w:start
2331                    __gDiskArbStatusLock = TRUE;
2332                    __gDiskArbStatus = KERN_SUCCESS;
2333///w:stop
2334                    DADiskUnmount( whole, options, __DiskArbDiskUnmountCallback, ( void * ) ( flags & kDiskArbUnmountAndEjectFlag ) );
2335
2336                    status = KERN_SUCCESS;
2337///w:start
2338                    status = __gDiskArbStatus ? KERN_FAILURE : KERN_SUCCESS;
2339                    __gDiskArbStatusLock = FALSE;
2340///w:stop
2341
2342                    CFRelease( whole );
2343                }
2344            }
2345
2346            CFRelease( _disk );
2347        }
2348    }
2349
2350    return status;
2351}
2352
2353void DiskArbUpdateClientFlags( void )
2354{
2355    if ( __gDiskArbSession )
2356    {
2357        if ( __gDiskArbRegisterList )
2358        {
2359            CFIndex count;
2360            CFIndex index;
2361
2362            count = CFArrayGetCount( __gDiskArbRegisterList );
2363
2364            for ( index = 0; index < count; index++ )
2365            {
2366                CFNumberRef key;
2367
2368                key = CFArrayGetValueAtIndex( __gDiskArbRegisterList, index );
2369
2370                if ( key )
2371                {
2372                    int type;
2373
2374                    CFNumberGetValue( key, kCFNumberIntType, &type );
2375
2376                    switch ( type )
2377                    {
2378                        case kDA_DISK_APPEARED:
2379                        case kDA_DISK_APPEARED1:
2380                        case kDA_DISK_APPEARED_COMPLETE:
2381                        case kDA_DISK_APPEARED_WITH_MT:
2382                        case kDA_DISK_CHANGED:
2383                        case kDA_DISK_EJECT_POST_NOTIFY:
2384                        case kDA_DISK_UNMOUNT_POST_NOTIFY:
2385                        {
2386                            static Boolean registered = FALSE;
2387
2388                            if ( registered == FALSE )
2389                            {
2390                                DARegisterDiskDescriptionChangedCallback( __gDiskArbSession, NULL, NULL, __DiskArbDiskDescriptionChangedCallback, NULL );
2391
2392                                DARegisterDiskDisappearedCallback( __gDiskArbSession, NULL, __DiskArbDiskDisappearedCallback, NULL );
2393
2394                                DARegisterDiskAppearedCallback( __gDiskArbSession, NULL, __DiskArbDiskAppearedCallback, NULL );
2395
2396                                registered = TRUE;
2397                            }
2398
2399                            break;
2400                        }
2401                        case kDA_DISK_APPROVAL_NOTIFY:
2402                        {
2403                            DARegisterDiskMountApprovalCallback( ( void * ) __gDiskArbSession, NULL, __DiskArbDiskMountApprovalCallback, NULL );
2404
2405                            break;
2406                        }
2407                        case kDA_DISK_EJECT_PRE_NOTIFY:
2408                        {
2409                            DARegisterDiskEjectApprovalCallback( ( void * ) __gDiskArbSession, NULL, __DiskArbDiskEjectApprovalCallback, NULL );
2410
2411                            break;
2412                        }
2413                        case kDA_DISK_UNMOUNT_PRE_NOTIFY:
2414                        {
2415                            DARegisterDiskUnmountApprovalCallback( ( void * ) __gDiskArbSession, NULL, __DiskArbDiskUnmountApprovalCallback, NULL );
2416
2417                            break;
2418                        }
2419                        case kDA_NOTIFICATIONS_COMPLETE:
2420                        {
2421                            DARegisterIdleCallback( __gDiskArbSession, __DiskArbIdleCallback, NULL );
2422
2423                            break;
2424                        }
2425                    }
2426                }
2427            }
2428
2429            CFArrayRemoveAllValues( __gDiskArbRegisterList );
2430        }
2431    }
2432}
2433
2434kern_return_t DiskArbVSDBAdoptVolume_auto( char * disk )
2435{
2436    kern_return_t status;
2437
2438    status = KERN_FAILURE;
2439
2440    if ( disk )
2441    {
2442        DADiskRef _disk;
2443
2444        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2445
2446        if ( _disk )
2447        {
2448            status = _DADiskSetAdoption( _disk, TRUE );
2449
2450            CFRelease( _disk );
2451        }
2452    }
2453
2454    return status;
2455}
2456
2457kern_return_t DiskArbVSDBDisownVolume_auto( char * disk )
2458{
2459    kern_return_t status;
2460
2461    status = KERN_FAILURE;
2462
2463    if ( disk )
2464    {
2465        DADiskRef _disk;
2466
2467        _disk = DADiskCreateFromBSDName( kCFAllocatorDefault, __gDiskArbSession, disk );
2468
2469        if ( _disk )
2470        {
2471            status = _DADiskSetAdoption( _disk, FALSE );
2472
2473            CFRelease( _disk );
2474        }
2475    }
2476
2477    return status;
2478}
2479
2480int DiskArbVSDBGetVolumeStatus_auto( char * disk )
2481{
2482    struct statfs * fs;
2483
2484    fs = __DiskArbGetFileSystemStatus( disk );
2485
2486    return fs ? ( ( fs->f_flags & MNT_IGNORE_OWNERSHIP ) ? 2 : 1 ) : 0;
2487}
2488
2489#endif /* !__LP64__ */
2490
2491DAReturn _DADiskSetAdoption( DADiskRef disk, Boolean adoption )
2492{
2493    DAReturn status;
2494
2495    status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionDefault, disk, _kDAAuthorizeRightAdopt );
2496
2497    if ( status == kDAReturnSuccess )
2498    {
2499        status = _DAServerDiskSetAdoption( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), adoption );
2500    }
2501
2502    return status;
2503}
2504
2505DAReturn _DADiskSetEncoding( DADiskRef disk, UInt32 encoding )
2506{
2507    DAReturn status;
2508
2509    status = _DAAuthorize( _DADiskGetSession( disk ), _kDAAuthorizeOptionIsOwner, disk, _kDAAuthorizeRightEncode );
2510
2511    if ( status == kDAReturnSuccess )
2512    {
2513        status = _DAServerDiskSetEncoding( _DADiskGetSessionID( disk ), _DADiskGetID( disk ), encoding );
2514    }
2515
2516    return status;
2517}
2518
2519void DARegisterIdleCallback( DASessionRef session, DAIdleCallback callback, void * context )
2520{
2521    _DARegisterCallback( session, callback, context, _kDAIdleCallback, 0, NULL, NULL );
2522}
2523