include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / mountmgr.sys / diskarb.c
blobd33f6c60afbd598b0e6319537a33c36297a792d3
1 /*
2 * Devices support using the MacOS Disk Arbitration library.
4 * Copyright 2006 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #ifdef __APPLE__
35 #include <DiskArbitration/DiskArbitration.h>
36 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
37 #include <SystemConfiguration/SCNetworkConfiguration.h>
38 #endif
40 #include "mountmgr.h"
41 #define USE_WS_PREFIX
42 #include "winsock2.h"
43 #include "ws2ipdef.h"
44 #include "dhcpcsdk.h"
45 #include "unixlib.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
51 #ifdef __APPLE__
53 typedef struct
55 uint64_t bus;
56 uint64_t port;
57 uint64_t target;
58 uint64_t lun;
59 } dk_scsi_identify_t;
61 #define DKIOCSCSIIDENTIFY _IOR('d', 254, dk_scsi_identify_t)
63 static void appeared_callback( DADiskRef disk, void *context )
65 CFDictionaryRef dict = DADiskCopyDescription( disk );
66 const void *ref;
67 char device[64];
68 CFURLRef volume_url;
69 char mount_point[PATH_MAX];
70 size_t model_len = 0;
71 GUID guid, *guid_ptr = NULL;
72 enum device_type type = DEVICE_UNKNOWN;
73 struct scsi_info scsi_info = { 0 };
74 BOOL removable = FALSE;
75 int fd;
77 if (!dict) return;
79 if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumeUUID") )))
81 CFUUIDBytes bytes = CFUUIDGetUUIDBytes( ref );
82 memcpy( &guid, &bytes, sizeof(guid) );
83 guid_ptr = &guid;
86 /* get device name */
87 if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done;
88 strcpy( device, "/dev/r" );
89 CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII );
91 if ((volume_url = CFDictionaryGetValue( dict, CFSTR("DAVolumePath") )))
92 CFURLGetFileSystemRepresentation( volume_url, true, (UInt8 *)mount_point, sizeof(mount_point) );
93 else
95 TRACE( "ignoring volume %s, uuid %s: no macOS volume path\n", device, wine_dbgstr_guid(guid_ptr) );
96 goto done;
99 if (CFURLCopyResourcePropertyForKey( volume_url, kCFURLVolumeIsBrowsableKey, &ref, NULL ))
101 Boolean is_browsable = CFBooleanGetValue( ref );
102 CFRelease( ref );
104 if (!is_browsable)
106 TRACE( "ignoring volume %s, uuid %s: not browsable\n", device, wine_dbgstr_guid(guid_ptr) );
107 goto done;
111 if ((ref = CFDictionaryGetValue( dict, CFSTR("DAMediaKind") )))
113 if (!CFStringCompare( ref, CFSTR("IOCDMedia"), 0 ))
115 type = DEVICE_CDROM;
116 scsi_info.type = 5;
118 if (!CFStringCompare( ref, CFSTR("IODVDMedia"), 0 ) ||
119 !CFStringCompare( ref, CFSTR("IOBDMedia"), 0 ))
121 type = DEVICE_DVD;
122 scsi_info.type = 5;
124 if (!CFStringCompare( ref, CFSTR("IOMedia"), 0 ))
125 type = DEVICE_HARDDISK;
128 if ((ref = CFDictionaryGetValue( dict, CFSTR("DADeviceVendor") )))
130 CFIndex i;
132 CFStringGetCString( ref, scsi_info.model, sizeof(scsi_info.model), kCFStringEncodingASCII );
133 model_len += CFStringGetLength( ref );
134 /* Pad to 8 characters */
135 for (i = 0; i < (CFIndex)8 - CFStringGetLength( ref ); ++i)
136 scsi_info.model[model_len++] = ' ';
138 if ((ref = CFDictionaryGetValue( dict, CFSTR("DADeviceModel") )))
140 CFIndex i;
142 CFStringGetCString( ref, scsi_info.model+model_len, sizeof(scsi_info.model)-model_len, kCFStringEncodingASCII );
143 model_len += CFStringGetLength( ref );
144 /* Pad to 16 characters */
145 for (i = 0; i < (CFIndex)16 - CFStringGetLength( ref ); ++i)
146 scsi_info.model[model_len++] = ' ';
148 if ((ref = CFDictionaryGetValue( dict, CFSTR("DADeviceRevision") )))
150 CFIndex i;
152 CFStringGetCString( ref, scsi_info.model+model_len, sizeof(scsi_info.model)-model_len, kCFStringEncodingASCII );
153 model_len += CFStringGetLength( ref );
154 /* Pad to 4 characters */
155 for (i = 0; i < (CFIndex)4 - CFStringGetLength( ref ); ++i)
156 scsi_info.model[model_len++] = ' ';
159 TRACE( "got mount notification for '%s' on '%s' uuid %s\n",
160 device, mount_point, wine_dbgstr_guid(guid_ptr) );
162 if ((ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )))
163 removable = CFBooleanGetValue( ref );
165 if (!access( device, R_OK ) &&
166 (fd = open( device, O_RDONLY )) >= 0)
168 dk_scsi_identify_t dsi;
170 if (ioctl( fd, DKIOCSCSIIDENTIFY, &dsi ) >= 0)
172 scsi_info.addr.PortNumber = dsi.bus;
173 scsi_info.addr.PathId = dsi.port;
174 scsi_info.addr.TargetId = dsi.target;
175 scsi_info.addr.Lun = dsi.lun;
176 scsi_info.init_id = 255; /* FIXME */
177 strcpy( scsi_info.driver, "WINE SCSI" ); /* FIXME */
179 close( fd );
182 if (removable)
183 queue_device_op( ADD_DOS_DEVICE, device, device, mount_point, type, guid_ptr, NULL, &scsi_info );
184 else
185 if (guid_ptr) queue_device_op( ADD_VOLUME, device, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL, &scsi_info );
187 done:
188 CFRelease( dict );
191 static void changed_callback( DADiskRef disk, CFArrayRef keys, void *context )
193 appeared_callback( disk, context );
196 static void disappeared_callback( DADiskRef disk, void *context )
198 CFDictionaryRef dict = DADiskCopyDescription( disk );
199 const void *ref;
200 char device[100];
202 if (!dict) return;
204 /* get device name */
205 if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done;
206 strcpy( device, "/dev/r" );
207 CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII );
209 TRACE( "got unmount notification for '%s'\n", device );
211 queue_device_op( REMOVE_DEVICE, device, NULL, NULL, 0, NULL, NULL, NULL );
213 done:
214 CFRelease( dict );
217 void run_diskarbitration_loop(void)
219 DASessionRef session = DASessionCreate( NULL );
221 if (!session) return;
223 DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
224 DARegisterDiskAppearedCallback( session, kDADiskDescriptionMatchVolumeMountable,
225 appeared_callback, NULL );
226 DARegisterDiskDisappearedCallback( session, kDADiskDescriptionMatchVolumeMountable,
227 disappeared_callback, NULL );
228 DARegisterDiskDescriptionChangedCallback( session, kDADiskDescriptionMatchVolumeMountable,
229 kDADiskDescriptionWatchVolumePath, changed_callback, NULL );
230 CFRunLoopRun();
231 DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
232 CFRelease( session );
235 #else /* __APPLE__ */
237 void run_diskarbitration_loop(void)
239 TRACE( "Skipping, Disk Arbitration support not compiled in\n" );
242 #endif /* __APPLE__ */
244 #if defined(__APPLE__)
246 static UInt8 map_option( unsigned int option )
248 switch (option)
250 case OPTION_SUBNET_MASK: return 1;
251 case OPTION_ROUTER_ADDRESS: return 3;
252 case OPTION_HOST_NAME: return 12;
253 case OPTION_DOMAIN_NAME: return 15;
254 case OPTION_BROADCAST_ADDRESS: return 28;
255 case OPTION_MSFT_IE_PROXY: return 252;
256 default:
257 FIXME( "unhandled option %u\n", option );
258 return 0;
262 static CFStringRef find_service_id( const char *unix_name )
264 SCPreferencesRef prefs;
265 SCNetworkSetRef set = NULL;
266 CFArrayRef services = NULL;
267 CFStringRef id, ret = NULL;
268 CFIndex i;
270 if (!(prefs = SCPreferencesCreate( NULL, CFSTR("mountmgr.sys"), NULL ))) return NULL;
271 if (!(set = SCNetworkSetCopyCurrent( prefs ))) goto done;
272 if (!(services = SCNetworkSetCopyServices( set ))) goto done;
274 for (i = 0; i < CFArrayGetCount( services ); i++)
276 SCNetworkServiceRef service;
277 char buf[16];
278 CFStringRef name;
280 service = CFArrayGetValueAtIndex( services, i );
281 name = SCNetworkInterfaceGetBSDName( SCNetworkServiceGetInterface(service) );
282 if (name && CFStringGetCString( name, buf, sizeof(buf), kCFStringEncodingUTF8 ))
284 if (!strcmp( buf, unix_name ) && (id = SCNetworkServiceGetServiceID( service )))
286 ret = CFStringCreateCopy( NULL, id );
287 break;
292 done:
293 if (services) CFRelease( services );
294 if (set) CFRelease( set );
295 CFRelease( prefs );
296 return ret;
299 NTSTATUS dhcp_request( void *args )
301 const struct dhcp_request_params *params = args;
302 CFStringRef service_id = find_service_id( params->unix_name );
303 CFDictionaryRef dict;
304 CFDataRef value;
305 DWORD ret = 0;
306 CFIndex len;
308 params->req->offset = 0;
309 params->req->size = 0;
310 *params->ret_size = 0;
312 if (!service_id) return 0;
313 if (!(dict = SCDynamicStoreCopyDHCPInfo( NULL, service_id )))
315 CFRelease( service_id );
316 return STATUS_SUCCESS;
318 CFRelease( service_id );
319 if (!(value = DHCPInfoGetOptionData( dict, map_option(params->req->id) )))
321 CFRelease( dict );
322 return STATUS_SUCCESS;
324 len = CFDataGetLength( value );
326 switch (params->req->id)
328 case OPTION_SUBNET_MASK:
329 case OPTION_ROUTER_ADDRESS:
330 case OPTION_BROADCAST_ADDRESS:
332 unsigned int *ptr = (unsigned int *)(params->buffer + params->offset);
333 if (len == sizeof(*ptr) && params->size >= sizeof(*ptr))
335 CFDataGetBytes( value, CFRangeMake(0, len), (UInt8 *)ptr );
336 params->req->offset = params->offset;
337 params->req->size = sizeof(*ptr);
338 TRACE( "returning %08x\n", *ptr );
340 ret = sizeof(*ptr);
341 break;
343 case OPTION_HOST_NAME:
344 case OPTION_DOMAIN_NAME:
345 case OPTION_MSFT_IE_PROXY:
347 char *ptr = params->buffer + params->offset;
348 if (params->size >= len)
350 CFDataGetBytes( value, CFRangeMake(0, len), (UInt8 *)ptr );
351 params->req->offset = params->offset;
352 params->req->size = len;
353 TRACE( "returning %s\n", debugstr_an(ptr, len) );
355 ret = len;
356 break;
358 default:
359 FIXME( "option %u not supported\n", (unsigned int)params->req->id );
360 break;
363 CFRelease( dict );
364 *params->ret_size = ret;
365 return STATUS_SUCCESS;
368 #elif !defined(SONAME_LIBDBUS_1)
370 NTSTATUS dhcp_request( void *args )
372 return STATUS_NOT_SUPPORTED;
375 #endif