1/*
2 * Copyright (c) 2014 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 "open.h"
25
26#include <errno.h>
27#include <util.h>
28#include <DiskArbitration/DiskArbitration.h>
29#include <IOKit/storage/IOMedia.h>
30#include <IOKit/IOKitLibPrivate.h>
31
32static DASessionRef __GetSession( void )
33{
34    static dispatch_once_t once;
35    static DASessionRef session;
36
37    dispatch_once( &once, ^
38    {
39        session = DASessionCreate( kCFAllocatorDefault );
40
41        if ( session )
42        {
43            DASessionSetDispatchQueue( session, dispatch_get_main_queue( ) );
44        }
45    } );
46
47    return session;
48}
49
50static void __UnmountCallback( DADiskRef disk __unused, DADissenterRef dissenter __unused, void * context )
51{
52    dispatch_semaphore_t semaphore = ( __bridge id ) context;
53
54    dispatch_semaphore_signal( semaphore );
55}
56
57static void __Unmount( DADiskRef disk )
58{
59    dispatch_semaphore_t semaphore;
60
61    semaphore = dispatch_semaphore_create( 0 );
62
63    if ( semaphore )
64    {
65        DADiskUnmount( disk, kDADiskUnmountOptionDefault, __UnmountCallback, ( __bridge void * ) semaphore );
66
67        dispatch_semaphore_wait( semaphore, DISPATCH_TIME_FOREVER );
68    }
69}
70
71int _Open( io_service_t service, int oflag, uint64_t authorizationID )
72{
73    uint64_t _authorizationID = 0;
74    int fd = -1;
75    IOReturn status;
76
77    _IOServiceGetAuthorizationID( service, &_authorizationID );
78
79    if ( _authorizationID )
80    {
81        if ( _authorizationID == authorizationID )
82        {
83            if ( IOObjectConformsTo( service, kIOMediaClass ) )
84            {
85                DADiskRef disk;
86
87                disk = DADiskCreateFromIOMedia( kCFAllocatorDefault, __GetSession( ), service );
88
89                if ( disk )
90                {
91                    CFDictionaryRef description;
92
93                    description = DADiskCopyDescription( disk );
94
95                    if ( description )
96                    {
97                        if ( CFDictionaryGetValue( description, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue )
98                        {
99                            if ( CFDictionaryGetValue( description, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanFalse )
100                            {
101                                if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey ) )
102                                {
103                                    __Unmount( disk );
104                                }
105                            }
106                        }
107
108                        CFRelease( description );
109                    }
110
111                    description = DADiskCopyDescription( disk );
112
113                    if ( description )
114                    {
115                        if ( CFDictionaryGetValue( description, kDADiskDescriptionVolumePathKey ) == 0 )
116                        {
117                            fd = opendev( ( void * ) DADiskGetBSDName( disk ), oflag, 0, 0 );
118
119                            if ( fd == -1 )
120                            {
121                                status = unix_err( errno );
122                            }
123                            else
124                            {
125                                status = kIOReturnSuccess;
126                            }
127                        }
128                        else
129                        {
130                            status = unix_err( EBUSY );
131                        }
132
133                        CFRelease( description );
134                    }
135                    else
136                    {
137                        status = unix_err( EBUSY );
138                    }
139
140                    CFRelease( disk );
141                }
142                else
143                {
144                    status = unix_err( ENOTSUP );
145                }
146            }
147            else
148            {
149                status = unix_err( ENOTSUP );
150            }
151        }
152        else
153        {
154            status = unix_err( EPERM );
155        }
156    }
157    else
158    {
159        status = unix_err( EPERM );
160    }
161
162    if ( status )
163    {
164        if ( unix_err( err_get_code( status ) ) == status )
165        {
166            errno = err_get_code( status );
167        }
168    }
169
170    return fd;
171}
172