48 // |
48 // |
49 // Also notice that this works as determined experimentally in 10.4.9, there's no official docs I could find. |
49 // Also notice that this works as determined experimentally in 10.4.9, there's no official docs I could find. |
50 // YMMV, and it may stop working in any new version of Mac OS X. |
50 // YMMV, and it may stop working in any new version of Mac OS X. |
51 |
51 |
52 static NSString* CheckParents(io_object_t thing,NSString* part,NSMutableDictionary* dict) { |
52 static NSString* CheckParents(io_object_t thing,NSString* part,NSMutableDictionary* dict) { |
53 NSString* result = part; |
53 NSString* result = part; |
54 io_iterator_t parentsIterator = 0; |
54 io_iterator_t parentsIterator = 0; |
55 kern_return_t kernResult = IORegistryEntryGetParentIterator(thing,kIOServicePlane,&parentsIterator); |
55 kern_return_t kernResult = IORegistryEntryGetParentIterator(thing,kIOServicePlane,&parentsIterator); |
56 if ((kernResult==KERN_SUCCESS)&&parentsIterator) { |
56 if ((kernResult==KERN_SUCCESS)&&parentsIterator) { |
57 io_object_t nextParent = 0; |
57 io_object_t nextParent = 0; |
58 while ((nextParent = IOIteratorNext(parentsIterator))) { |
58 while ((nextParent = IOIteratorNext(parentsIterator))) { |
59 NSDictionary* props = nil; |
59 NSDictionary* props = nil; |
60 NSString* image = nil; |
60 NSString* image = nil; |
61 NSString* partition = nil; |
61 NSString* partition = nil; |
62 NSString* connection = nil; |
62 NSString* connection = nil; |
63 kernResult = IORegistryEntryCreateCFProperties(nextParent,(CFMutableDictionaryRef*)&props,kCFAllocatorDefault,0); |
63 kernResult = IORegistryEntryCreateCFProperties(nextParent,(CFMutableDictionaryRef*)&props,kCFAllocatorDefault,0); |
64 if (IOObjectConformsTo(nextParent,"IOApplePartitionScheme")) { |
64 if (IOObjectConformsTo(nextParent,"IOApplePartitionScheme")) { |
65 partition = [props objectForKey:@"Content Mask"]; |
65 partition = [props objectForKey:@"Content Mask"]; |
66 } else if (IOObjectConformsTo(nextParent,"IOMedia")) { |
66 } else if (IOObjectConformsTo(nextParent,"IOMedia")) { |
67 partition = [props objectForKey:@"Content"]; |
67 partition = [props objectForKey:@"Content"]; |
68 } else if (IOObjectConformsTo(nextParent,"IODiskImageBlockStorageDeviceOutKernel")) { |
68 } else if (IOObjectConformsTo(nextParent,"IODiskImageBlockStorageDeviceOutKernel")) { |
69 NSData* data = nil; |
69 NSData* data = nil; |
70 if ((data = [[props objectForKey:@"Protocol Characteristics"] objectForKey:@"Virtual Interface Location Path"])) { |
70 if ((data = [[props objectForKey:@"Protocol Characteristics"] objectForKey:@"Virtual Interface Location Path"])) { |
71 image = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding] autorelease]; |
71 image = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding] autorelease]; |
72 } |
72 } |
73 } else if (IOObjectConformsTo(nextParent,"IOHDIXHDDriveInKernel")) { |
73 } else if (IOObjectConformsTo(nextParent,"IOHDIXHDDriveInKernel")) { |
74 image = [props objectForKey:@"KDIURLPath"]; |
74 image = [props objectForKey:@"KDIURLPath"]; |
75 } |
75 } |
76 NSDictionary* subdict; |
76 NSDictionary* subdict; |
77 if ((subdict = [props objectForKey:@"Protocol Characteristics"])) { |
77 if ((subdict = [props objectForKey:@"Protocol Characteristics"])) { |
78 connection = [subdict objectForKey:@"Physical Interconnect"]; |
78 connection = [subdict objectForKey:@"Physical Interconnect"]; |
79 } else { |
79 } else { |
80 connection = [props objectForKey:@"Physical Interconnect"]; |
80 connection = [props objectForKey:@"Physical Interconnect"]; |
81 } |
81 } |
82 if (connection) { |
82 if (connection) { |
83 [dict setObject:AddPart([dict objectForKey:NSWorkspace_RBconnectiontype],connection) forKey:NSWorkspace_RBconnectiontype]; |
83 [dict setObject:AddPart([dict objectForKey:NSWorkspace_RBconnectiontype],connection) forKey:NSWorkspace_RBconnectiontype]; |
84 } |
84 } |
85 if (partition) { |
85 if (partition) { |
86 [dict setObject:partition forKey:NSWorkspace_RBpartitionscheme]; |
86 [dict setObject:partition forKey:NSWorkspace_RBpartitionscheme]; |
87 } |
87 } |
88 if (image) { |
88 if (image) { |
89 [dict setObject:image forKey:NSWorkspace_RBimagefilepath]; |
89 [dict setObject:image forKey:NSWorkspace_RBimagefilepath]; |
90 } |
90 } |
91 NSString* value; |
91 NSString* value; |
92 if ((subdict = [props objectForKey:@"Device Characteristics"])) { |
92 if ((subdict = [props objectForKey:@"Device Characteristics"])) { |
93 if ((value = [subdict objectForKey:@"Product Name"])) { |
93 if ((value = [subdict objectForKey:@"Product Name"])) { |
94 result = AddPart(result,value); |
94 result = AddPart(result,value); |
95 } |
95 } |
96 if ((value = [subdict objectForKey:@"Product Revision Level"])) { |
96 if ((value = [subdict objectForKey:@"Product Revision Level"])) { |
97 result = AddPart(result,value); |
97 result = AddPart(result,value); |
98 } |
98 } |
99 if ((value = [subdict objectForKey:@"Vendor Name"])) { |
99 if ((value = [subdict objectForKey:@"Vendor Name"])) { |
100 result = AddPart(result,value); |
100 result = AddPart(result,value); |
101 } |
101 } |
102 } |
102 } |
103 if ((value = [props objectForKey:@"USB Serial Number"])) { |
103 if ((value = [props objectForKey:@"USB Serial Number"])) { |
104 result = AddPart(result,value); |
104 result = AddPart(result,value); |
105 } |
105 } |
106 if ((value = [props objectForKey:@"USB Vendor Name"])) { |
106 if ((value = [props objectForKey:@"USB Vendor Name"])) { |
107 result = AddPart(result,value); |
107 result = AddPart(result,value); |
108 } |
108 } |
109 NSString* cls = [(NSString*)IOObjectCopyClass(nextParent) autorelease]; |
109 NSString* cls = [(NSString*)IOObjectCopyClass(nextParent) autorelease]; |
110 if (![cls isEqualToString:@"IOPCIDevice"]) { |
110 if (![cls isEqualToString:@"IOPCIDevice"]) { |
111 |
111 |
112 // Uncomment the following line to have the device tree dumped to the console. |
112 // Uncomment the following line to have the device tree dumped to the console. |
113 // NSLog(@"=================================> %@:%@\n",cls,props); |
113 // NSLog(@"=================================> %@:%@\n",cls,props); |
114 |
114 |
115 result = CheckParents(nextParent,result,dict); |
115 result = CheckParents(nextParent,result,dict); |
116 } |
116 } |
117 IOObjectRelease(nextParent); |
117 IOObjectRelease(nextParent); |
118 } |
118 } |
119 } |
119 } |
120 if (parentsIterator) { |
120 if (parentsIterator) { |
121 IOObjectRelease(parentsIterator); |
121 IOObjectRelease(parentsIterator); |
122 } |
122 } |
123 return result; |
123 return result; |
124 } |
124 } |
125 |
125 |
126 // This formats the (partially undocumented) AFPXMountInfo info into a string. |
126 // This formats the (partially undocumented) AFPXMountInfo info into a string. |
127 |
127 |
128 /* |
128 /* |
129 static NSString* FormatAFPURL(AFPXVolMountInfoPtr mountInfo,NSString** devdesc) { |
129 static NSString* FormatAFPURL(AFPXVolMountInfoPtr mountInfo,NSString** devdesc) { |
130 UInt8* work = ((UInt8*)mountInfo)+mountInfo->serverNameOffset; |
130 UInt8* work = ((UInt8*)mountInfo)+mountInfo->serverNameOffset; |
131 if (devdesc) { |
131 if (devdesc) { |
132 *devdesc = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease]; |
132 *devdesc = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease]; |
133 } |
133 } |
134 work = ((UInt8*)mountInfo)+mountInfo->volNameOffset; |
134 work = ((UInt8*)mountInfo)+mountInfo->volNameOffset; |
135 NSString* volname = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease]; |
135 NSString* volname = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease]; |
136 work = ((UInt8*)mountInfo)+mountInfo->alternateAddressOffset; |
136 work = ((UInt8*)mountInfo)+mountInfo->alternateAddressOffset; |
137 AFPAlternateAddress* afpa = (AFPAlternateAddress*)work; |
137 AFPAlternateAddress* afpa = (AFPAlternateAddress*)work; |
138 AFPTagData* afpta = (AFPTagData*)(&afpa->fAddressList); |
138 AFPTagData* afpta = (AFPTagData*)(&afpa->fAddressList); |
139 NSString* ip = nil; |
139 NSString* ip = nil; |
140 NSString* dns = nil; |
140 NSString* dns = nil; |
141 int i = afpa->fAddressCount; |
141 int i = afpa->fAddressCount; |
142 while ((i-->0)) { |
142 while ((i-->0)) { |
143 switch (afpta->fType) { |
143 switch (afpta->fType) { |
144 case kAFPTagTypeIP: |
144 case kAFPTagTypeIP: |
145 if (!ip) { |
145 if (!ip) { |
146 ip = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease]; |
146 ip = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease]; |
147 } |
147 } |
148 break; |
148 break; |
149 case kAFPTagTypeIPPort: |
149 case kAFPTagTypeIPPort: |
150 ip = [NSString stringWithFormat:@"%u.%u.%u.%u:%u",afpta->fData[0],afpta->fData[1],afpta->fData[2],afpta->fData[3],OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4])]; |
150 ip = [NSString stringWithFormat:@"%u.%u.%u.%u:%u",afpta->fData[0],afpta->fData[1],afpta->fData[2],afpta->fData[3],OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4])]; |
151 break; |
151 break; |
152 case kAFPTagTypeDNS: |
152 case kAFPTagTypeDNS: |
153 dns = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease]; |
153 dns = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease]; |
154 break; |
154 break; |
155 case 0x07: |
155 case 0x07: |
156 ip = [NSString stringWithFormat:@"[%x:%x:%x:%x:%x:%x:%x:%x]",OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[0]), |
156 ip = [NSString stringWithFormat:@"[%x:%x:%x:%x:%x:%x:%x:%x]",OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[0]), |
157 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[2]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4]), |
157 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[2]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4]), |
158 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[6]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[8]), |
158 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[6]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[8]), |
159 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[10]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[12]), |
159 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[10]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[12]), |
160 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[14])]; |
160 OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[14])]; |
161 break; |
161 break; |
162 } |
162 } |
163 afpta = (AFPTagData*)((char*)afpta+afpta->fLength); |
163 afpta = (AFPTagData*)((char*)afpta+afpta->fLength); |
164 } |
164 } |
165 return [NSString stringWithFormat:@"afp://%@/%@",dns?:(ip?:@""),volname]; |
165 return [NSString stringWithFormat:@"afp://%@/%@",dns?:(ip?:@""),volname]; |
166 } |
166 } |
167 */ |
167 */ |
168 |
168 |
169 @implementation NSWorkspace (NSWorkspace_RBAdditions) |
169 @implementation NSWorkspace (NSWorkspace_RBAdditions) |
170 |
170 |
171 // Returns a NSDictionary with properties for the path. See details in the .h file. |
171 // Returns a NSDictionary with properties for the path. See details in the .h file. |
172 // This assumes that the length of path is less than PATH_MAX (currently 1024 characters). |
172 // This assumes that the length of path is less than PATH_MAX (currently 1024 characters). |
173 |
173 |
174 - (NSDictionary*)propertiesForPath:(NSString*)path { |
174 - (NSDictionary*)propertiesForPath:(NSString*)path { |
175 const char* ccpath = (const char*)[path fileSystemRepresentation]; |
175 const char* ccpath = (const char*)[path fileSystemRepresentation]; |
176 NSMutableDictionary* result = nil; |
176 NSMutableDictionary* result = nil; |
177 struct statfs fs; |
177 struct statfs fs; |
178 if (!statfs(ccpath,&fs)) { |
178 if (!statfs(ccpath,&fs)) { |
179 NSString* from = [NSString stringWithUTF8String:fs.f_mntfromname]; |
179 NSString* from = [NSString stringWithUTF8String:fs.f_mntfromname]; |
180 result = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
180 result = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
181 [NSString stringWithUTF8String:fs.f_fstypename],NSWorkspace_RBfstypename, |
181 [NSString stringWithUTF8String:fs.f_fstypename],NSWorkspace_RBfstypename, |
182 [NSString stringWithUTF8String:fs.f_mntonname],NSWorkspace_RBmntonname, |
182 [NSString stringWithUTF8String:fs.f_mntonname],NSWorkspace_RBmntonname, |
183 nil]; |
183 nil]; |
184 if (strncmp(fs.f_mntfromname,"/dev/",5)==0) { |
184 if (strncmp(fs.f_mntfromname,"/dev/",5)==0) { |
185 // For a local volume,get the IO registry tree and search it for further info. |
185 // For a local volume,get the IO registry tree and search it for further info. |
186 mach_port_t masterPort = 0; |
186 mach_port_t masterPort = 0; |
187 io_iterator_t mediaIterator = 0; |
187 io_iterator_t mediaIterator = 0; |
188 kern_return_t kernResult = IOMasterPort(bootstrap_port,&masterPort); |
188 kern_return_t kernResult = IOMasterPort(bootstrap_port,&masterPort); |
189 if (kernResult==KERN_SUCCESS) { |
189 if (kernResult==KERN_SUCCESS) { |
190 CFMutableDictionaryRef classesToMatch = IOBSDNameMatching(masterPort,0,&fs.f_mntfromname[5]); |
190 CFMutableDictionaryRef classesToMatch = IOBSDNameMatching(masterPort,0,&fs.f_mntfromname[5]); |
191 if (classesToMatch) { |
191 if (classesToMatch) { |
192 kernResult = IOServiceGetMatchingServices(masterPort,classesToMatch,&mediaIterator); |
192 kernResult = IOServiceGetMatchingServices(masterPort,classesToMatch,&mediaIterator); |
193 if ((kernResult==KERN_SUCCESS)&&mediaIterator) { |
193 if ((kernResult==KERN_SUCCESS)&&mediaIterator) { |
194 io_object_t firstMedia = 0; |
194 io_object_t firstMedia = 0; |
195 while ((firstMedia = IOIteratorNext(mediaIterator))) { |
195 while ((firstMedia = IOIteratorNext(mediaIterator))) { |
196 NSString* stuff = CheckParents(firstMedia,nil,result); |
196 NSString* stuff = CheckParents(firstMedia,nil,result); |
197 if (stuff) { |
197 if (stuff) { |
198 [result setObject:stuff forKey:NSWorkspace_RBdeviceinfo]; |
198 [result setObject:stuff forKey:NSWorkspace_RBdeviceinfo]; |
199 } |
199 } |
200 IOObjectRelease(firstMedia); |
200 IOObjectRelease(firstMedia); |
201 } |
201 } |
202 } |
202 } |
203 } |
203 } |
204 } |
204 } |
205 if (mediaIterator) { |
205 if (mediaIterator) { |
206 IOObjectRelease(mediaIterator); |
206 IOObjectRelease(mediaIterator); |
207 } |
207 } |
208 if (masterPort) { |
208 if (masterPort) { |
209 mach_port_deallocate(mach_task_self(),masterPort); |
209 mach_port_deallocate(mach_task_self(),masterPort); |
210 } |
210 } |
211 } |
211 } |
212 //Don't need this for disk images, gets around warnings for some deprecated functions |
212 //Don't need this for disk images, gets around warnings for some deprecated functions |
213 |
213 |
214 /* else { |
214 /* else { |
215 // For a network volume, get the volume reference number and use to get the server URL. |
215 // For a network volume, get the volume reference number and use to get the server URL. |
216 FSRef ref; |
216 FSRef ref; |
217 if (FSPathMakeRef((const UInt8*)ccpath,&ref,NULL)==noErr) { |
217 if (FSPathMakeRef((const UInt8*)ccpath,&ref,NULL)==noErr) { |
218 FSCatalogInfo info; |
218 FSCatalogInfo info; |
219 if (FSGetCatalogInfo(&ref,kFSCatInfoVolume,&info,NULL,NULL,NULL)==noErr) { |
219 if (FSGetCatalogInfo(&ref,kFSCatInfoVolume,&info,NULL,NULL,NULL)==noErr) { |
220 ParamBlockRec pb; |
220 ParamBlockRec pb; |
221 UInt16 vmisize = 0; |
221 UInt16 vmisize = 0; |
222 VolumeMountInfoHeaderPtr mountInfo = NULL; |
222 VolumeMountInfoHeaderPtr mountInfo = NULL; |
223 pb.ioParam.ioCompletion = NULL; |
223 pb.ioParam.ioCompletion = NULL; |
224 pb.ioParam.ioNamePtr = NULL; |
224 pb.ioParam.ioNamePtr = NULL; |
225 pb.ioParam.ioVRefNum = info.volume; |
225 pb.ioParam.ioVRefNum = info.volume; |
226 pb.ioParam.ioBuffer = (Ptr)&vmisize; |
226 pb.ioParam.ioBuffer = (Ptr)&vmisize; |
227 pb.ioParam.ioReqCount = sizeof(vmisize); |
227 pb.ioParam.ioReqCount = sizeof(vmisize); |
228 if ((PBGetVolMountInfoSize(&pb)==noErr)&&vmisize) { |
228 if ((PBGetVolMountInfoSize(&pb)==noErr)&&vmisize) { |
229 mountInfo = (VolumeMountInfoHeaderPtr)malloc(vmisize); |
229 mountInfo = (VolumeMountInfoHeaderPtr)malloc(vmisize); |
230 if (mountInfo) { |
230 if (mountInfo) { |
231 pb.ioParam.ioBuffer = (Ptr)mountInfo; |
231 pb.ioParam.ioBuffer = (Ptr)mountInfo; |
232 pb.ioParam.ioReqCount = vmisize; |
232 pb.ioParam.ioReqCount = vmisize; |
233 if (PBGetVolMountInfo(&pb)==noErr) { |
233 if (PBGetVolMountInfo(&pb)==noErr) { |
234 NSString* url = nil; |
234 NSString* url = nil; |
235 switch (mountInfo->media) { |
235 switch (mountInfo->media) { |
236 case AppleShareMediaType: |
236 case AppleShareMediaType: |
237 url = FormatAFPURL((AFPXVolMountInfoPtr)mountInfo,&from); |
237 url = FormatAFPURL((AFPXVolMountInfoPtr)mountInfo,&from); |
238 break; |
238 break; |
239 case 'http': |
239 case 'http': |
240 url = from; |
240 url = from; |
241 break; |
241 break; |
242 case 'crbm': |
242 case 'crbm': |
243 case 'nfs_': |
243 case 'nfs_': |
244 case 'cifs': |
244 case 'cifs': |
245 url = [NSString stringWithUTF8String:(char*)mountInfo+sizeof(VolumeMountInfoHeader)+sizeof(OSType)]; |
245 url = [NSString stringWithUTF8String:(char*)mountInfo+sizeof(VolumeMountInfoHeader)+sizeof(OSType)]; |
246 break; |
246 break; |
247 } |
247 } |
248 if (url) { |
248 if (url) { |
249 [result setObject:url forKey:NSWorkspace_RBserverURL]; |
249 [result setObject:url forKey:NSWorkspace_RBserverURL]; |
250 } |
250 } |
251 } |
251 } |
252 } |
252 } |
253 free(mountInfo); |
253 free(mountInfo); |
254 } |
254 } |
255 } |
255 } |
256 } |
256 } |
257 }*/ |
257 }*/ |
258 [result setObject:from forKey:NSWorkspace_RBmntfromname]; |
258 [result setObject:from forKey:NSWorkspace_RBmntfromname]; |
259 } |
259 } |
260 return result; |
260 return result; |
261 } |
261 } |
262 |
262 |
263 @end |
263 @end |