Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 228 lines (194 sloc) 7.532 kb
dc5be1c Initial check-in.
uli authored
1 //
2 // NSWorkspace+TypeOfVolumeAtPath.m
3 // MovieTheatre
4 //
5 // Created by Uli Kusterer on 12.06.05.
720b0e7 @uliwitness Added licensing information to the source files.
authored
6 // Copyright 2005 M. Uli Kusterer.
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not be
22 // misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
dc5be1c Initial check-in.
uli authored
26 //
27
28 #import "NSWorkspace+TypeOfVolumeAtPath.h"
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <CoreServices/CoreServices.h>
31 #include <IOKit/IOKitLib.h>
32 #include <IOKit/storage/IOMedia.h>
33 #include <IOKit/storage/IOCDMedia.h>
34 #include <IOKit/storage/IODVDMedia.h>
35 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
36 #include <IOKit/usb/IOUSBLib.h>
1ef6795 @uliwitness Modernized NSWorkspace typeOfVolumeAtPath so it doesn't use deprecated c...
authored
37 #import "NSString+CarbonUtilities.h"
dc5be1c Initial check-in.
uli authored
38
39
40
41 NSString* IsWholeMedia(io_service_t service)
42 {
43 //
44 // Determine if the object passed in represents an IOMedia (or subclass) object.
45 // If it does, retrieve the "Whole" property.
46 // If this is the whole media object, find out if it is a CD, DVD, or something else.
47 // If it isn't the whole media object, iterate across its parents in the IORegistry
48 // until the whole media object is found.
49 //
50 // Note that media types other than CD and DVD are not distinguished by class name
51 // but are generic IOMedia objects.
52 //
53
54 NSString* mediaType = nil;
55 Boolean isWholeMedia = false;
56 io_name_t className;
57 kern_return_t kernResult;
58
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
59 if( IOObjectConformsTo(service, kIOMediaClass) )
60 {
dc5be1c Initial check-in.
uli authored
61 CFTypeRef wholeMedia;
62
63 // Find out whether it's a whole media:
64 wholeMedia = IORegistryEntryCreateCFProperty(service,
65 CFSTR(kIOMediaWholeKey),
66 kCFAllocatorDefault,
67 0);
68
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
69 if( NULL == wholeMedia )
70 {
dc5be1c Initial check-in.
uli authored
71 printf("Could not retrieve Whole property\n");
72 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
73 else
74 {
dc5be1c Initial check-in.
uli authored
75 isWholeMedia = CFBooleanGetValue(wholeMedia);
76 CFRelease(wholeMedia);
77 }
78 }
79
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
80 if( isWholeMedia )
dc5be1c Initial check-in.
uli authored
81 {
82 kernResult = IOObjectGetClass(service, className);
83 mediaType = [NSString stringWithUTF8String: className];
84 }
85
86 return mediaType;
87 }
88
89 NSString* FindWholeMedia(io_service_t service)
90 {
91 kern_return_t kernResult;
92 io_iterator_t iter;
93 NSString* mediaType = nil;
94
95 // Create an iterator across all parents of the service object passed in.
96 kernResult = IORegistryEntryCreateIterator(service,
97 kIOServicePlane,
98 kIORegistryIterateRecursively | kIORegistryIterateParents,
99 &iter);
100
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
101 if (KERN_SUCCESS != kernResult)
102 {
dc5be1c Initial check-in.
uli authored
103 printf("IORegistryEntryCreateIterator returned %d\n", kernResult);
104 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
105 else if (IO_OBJECT_NULL == iter)
106 {
dc5be1c Initial check-in.
uli authored
107 printf("IORegistryEntryCreateIterator returned a NULL iterator\n");
108 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
109 else
110 {
dc5be1c Initial check-in.
uli authored
111 // A reference on the initial service object is released in the do-while loop below,
112 // so add a reference to balance
113 IOObjectRetain(service);
114
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
115 do
116 {
dc5be1c Initial check-in.
uli authored
117 mediaType = IsWholeMedia(service);
118 IOObjectRelease(service);
119 } while ((service = IOIteratorNext(iter)) && !mediaType);
120
121 IOObjectRelease(iter);
122 }
123
124 return mediaType;
125 }
126
127
128 @implementation NSWorkspace (TypeOfVolumeAtPath)
129
130 -(NSArray*) mountedMediaOfType: (NSString*)mediaType
131 {
132 NSEnumerator* enny = [[self mountedRemovableMedia] objectEnumerator];
133 NSString* path = nil;
134 NSMutableArray* result = [NSMutableArray array];
135
136 while( (path = [enny nextObject]) )
137 {
138 if( [[self typeOfVolumeAtPath: path] isEqualToString: mediaType] )
139 [result addObject: path];
140 }
141
142 return result;
143 }
144
145 -(NSString*) typeOfVolumeAtPath: (NSString*)path
146 {
147 OSStatus err;
148 FSRef fileRef;
149 FSCatalogInfo catInfo;
150 GetVolParmsInfoBuffer volumeParms;
151 kern_return_t kernResult;
152
153 if( ![path getFSRef: &fileRef] )
154 NSLog( @"Couldn't get FSRef" );
155
156 err = FSGetCatalogInfo( &fileRef, kFSCatInfoVolume, &catInfo, NULL, NULL, NULL );
157 if( err != noErr )
158 NSLog( @"FSGetCatalogInfo returned %ld", err );
159
160 // A version 4 GetVolParmsInfoBuffer contains the BSD node name in the vMDeviceID field.
161 // It is actually a char * value. This is mentioned in the header CoreServices/CarbonCore/Files.h.
1ef6795 @uliwitness Modernized NSWorkspace typeOfVolumeAtPath so it doesn't use deprecated c...
authored
162 err = FSGetVolumeParms( catInfo.volume, &volumeParms, sizeof(volumeParms) );
dc5be1c Initial check-in.
uli authored
163 if( err != noErr )
1ef6795 @uliwitness Modernized NSWorkspace typeOfVolumeAtPath so it doesn't use deprecated c...
authored
164 NSLog( @"FSGetVolumeParms returned %ld", err );
dc5be1c Initial check-in.
uli authored
165
166 char *bsdName = (char *) volumeParms.vMDeviceID;
167 CFMutableDictionaryRef matchingDict;
168 io_iterator_t iter;
169 io_service_t service;
170 NSString* mediaType = nil;
171 io_name_t theName;
172
173 static mach_port_t gMasterPort = 0;
174 if( gMasterPort == 0 )
175 {
176 kernResult = IOMasterPort(MACH_PORT_NULL, &gMasterPort);
177 if (KERN_SUCCESS != kernResult)
178 NSLog( @"IOMasterPort returned %d\n", kernResult);
179 }
180
1ef6795 @uliwitness Modernized NSWorkspace typeOfVolumeAtPath so it doesn't use deprecated c...
authored
181 NSLog(@"volume path & BSD name: %@ %s",path,bsdName);
dc5be1c Initial check-in.
uli authored
182 matchingDict = IOBSDNameMatching( gMasterPort, 0, bsdName );
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
183 if (NULL == matchingDict)
184 {
dc5be1c Initial check-in.
uli authored
185 printf("IOBSDNameMatching returned a NULL dictionary.\n");
186 }
187 else {
188 // Return an iterator across all objects with the matching BSD node name. Note that there
189 // should only be one match!
190 kernResult = IOServiceGetMatchingServices(gMasterPort, matchingDict, &iter);
191
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
192 if (KERN_SUCCESS != kernResult)
193 {
dc5be1c Initial check-in.
uli authored
194 printf("IOServiceGetMatchingServices returned %d\n", kernResult);
195 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
196 else if (IO_OBJECT_NULL == iter)
197 {
dc5be1c Initial check-in.
uli authored
198 printf("IOServiceGetMatchingServices returned a NULL iterator\n");
199 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
200 else
201 {
dc5be1c Initial check-in.
uli authored
202 service = IOIteratorNext(iter);
203
204 // Release this now because we only expect the iterator to contain
205 // a single io_service_t.
206 IOObjectRelease(iter);
207
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
208 if (IO_OBJECT_NULL == service)
209 {
dc5be1c Initial check-in.
uli authored
210 printf("IOIteratorNext returned NULL\n");
211 }
bca242f @uliwitness Make the TypeOfVolumeAtPath NSWorkspace category build with only one war...
authored
212 else
213 {
dc5be1c Initial check-in.
uli authored
214 mediaType = FindWholeMedia(service);
215 NSMutableDictionary* propDict = nil;
216 IORegistryEntryCreateCFProperties( service, (CFMutableDictionaryRef*) &propDict, kCFAllocatorDefault, 0 );
217 [propDict autorelease];
218 NSLog( @"%@",propDict );
219 IOObjectRelease(service);
220 }
221 }
222 }
223
224 return mediaType;
225 }
226
227 @end
Something went wrong with that request. Please try again.