Chameleon Applications

Chameleon Applications Svn Source Tree

Root/trunk/ChameleonPrefPane/Sources/PartitionInfoElement.mm

1//
2// PartitionInfoElement.mm
3// ChameleonPrefPane
4//
5// Powerful Partition Info class utility
6//
7// Created by Rekursor on 11-11-12.
8//
9
10#import "PartitionInfoElement.h"
11#import "ShellProcess.h"
12#include "string_util.h"
13
14static NSUInteger sHdRedirTable[MAX_HD];
15
16@implementation PartitionInfoElement
17
18@synthesize descDict, bsdName, vUUID, vKind, vName, vPath, mediaPath, mediaRemovable, devInternal, devProtocol;
19@synthesize vAliasName, hidden, bootInfo;
20
21/// Create a list of all bsd partitions
22+(NSArray*) createBSDPartitionList
23{
24NSMutableArray* arr = [[[NSMutableArray alloc] init] autorelease];
25
26char line[256];
27ShellProcess p;
28
29p.open("ls -1 /dev/disk*");
30while( p.get_line(line, sizeof(line)-1))
31{
32size_t l = strlen(line);
33if (l==0 || strstr(line, "ls:")!=NULL) continue;
34if (line[l-1]) line[l-1]='\0';
35const char * p = strstr(line, "disk");
36NSString* s = [NSString stringWithUTF8String: p] ;
37[arr addObject: s];
38
39}
40p.close();
41
42return arr;
43}
44/// extract version info from boot files when possible
45- (NSString*) cmdInfoForFile:(NSString*) file
46 withFilter:(NSString*) filter
47 withPath:(NSString*) path
48{
49 std::string p = [path UTF8String];
50 p += [file UTF8String];
51
52 if (!fileExists(p)) return @"";
53
54 NSString *cmd = [NSString stringWithFormat:@"strings \"%@%@\" | sed -nE '%@'",
55 path, file, filter];
56 // NSLog(@"cmd to run is %@", cmd);
57 return [NSString stringWithUTF8String: ShellProcess([cmd UTF8String]).get_line().c_str()];
58}
59
60/// Get the boot information string, for chameleon only for now ...
61-(NSString*) bootDescription
62{
63 if (bootInfo != nil) return bootInfo;
64
65 NSString* path = [[self.vPath
66 stringByReplacingOccurrencesOfString: @"file://localhost"
67 withString:@""]
68 stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
69 NSString *cmdCham = [self cmdInfoForFile: @"boot"
70 withFilter: @"s!^Darwin/x86 boot v.+\\ -\\ (.+)!\\1!p"
71 withPath: path];
72 NSString *cmdDarwin = [self cmdInfoForFile: @"mach_kernel"
73 withFilter: @"s!^(Darwin Kernel Version.+)(\\: .*$)!\\1!p"
74 withPath: path];
75 NSString *cmdWindows = (cmdDarwin==nil) ? @"" :
76 [self cmdInfoForFile: @"boot.ini"
77 withFilter: @"s!^multi.+WIN.+=\\\"(.+)(\\\".+$)!\\1!p"
78 withPath: path];
79
80 NSString * result = [[cmdCham stringByAppendingString: cmdDarwin]
81 stringByAppendingString:cmdWindows];
82 result = [result stringByTrimmingCharactersInSet:
83 [NSCharacterSet whitespaceAndNewlineCharacterSet] ];
84
85 return (bootInfo = [result length] > 0 ? result : nil);
86}
87
88
89/// redirection table for disk swapping
90+(NSUInteger*) hdRedirTable
91{
92return sHdRedirTable;
93}
94
95/// redirection table for disk swapping
96/// extract disk number from bsdname spec
97-(int) diskNumber
98{
99int newDiskNum = (diskNum>=0 && diskNum <MAX_HD) ? sHdRedirTable[diskNum] : diskNum;
100return newDiskNum;
101}
102
103/// extract partition number from bsdname spec
104-(int) partitionNumber
105{
106return partNum; // todo extract d num from bsdname
107}
108
109-(NSString*) hdString
110{
111return [NSString stringWithFormat:@"hd(%d,%d)", [self diskNumber], [self partitionNumber]];
112}
113
114-(void) setDiskNumber: (int) d
115{
116diskNum = d;
117}
118
119-(void) setPartitionNumber:(int) p
120{
121partNum = p;
122}
123/// return true if partition extraction successfully executed, false otherwise
124-(bool) isValid
125{
126
127return (
128err==0
129&& [self isBootable]
130// with chameleon as much as possible
131&& ![[self devProtocol] isEqual:@"Virtual Interface"]
132);
133}
134
135/// Extract a particular information from the disk partition dictionary from a key, generate a string value output
136-(NSString*) stringValueWithKey: (NSString*) key
137{
138if (err) return @"";
139CFTypeRef o = [descDict objectForKey: key];
140if (o==nil) return @"";
141CFStringRef sref = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), o);
142NSString* s = [[((NSString*) sref) copy] autorelease];
143CFRelease(sref);
144return s;
145}
146
147/// main extraction method create a dictionary containing all needed information from disk arbitration API
148- (int) extractInfoWithBSDName: (NSString*) name withinSession:(DASessionRef) session
149{
150err = 0;
151
152NSRange rDisk = [name rangeOfString:@"disk"];
153NSRange rS = [name rangeOfString:@"s" options:NSBackwardsSearch] ;
154
155if (name == nil
156|| [name length] < 7
157|| rDisk.location == NSNotFound
158|| rS.location <5)
159{
160err = EINVAL;
161return err;
162}
163
164// extract disk and partition number
165int pos = rDisk.location+rDisk.length;
166int pos2 = rS.location+rS.length;
167NSString* sDisk = [name substringWithRange:
168 NSMakeRange(pos, rS.location - pos) ];
169NSString* sPart = [name substringFromIndex: pos2 ];
170
171bool mustRelease = (session == nil) ? true : false;
172
173if (session == nil)
174{
175session = DASessionCreate(NULL);
176}
177
178if (session == NULL)err = EINVAL;
179
180if (err == 0) {
181DADiskRef disk = DADiskCreateFromBSDName(NULL, session, [name UTF8String] );
182if (disk == NULL) err = EINVAL;
183 else
184 {
185 [self cleanup];
186 CFDictionaryRefdr = DADiskCopyDescription(disk);
187 if (dr!=NULL)
188 {
189 descDict = (NSDictionary*) dr;
190 CFRelease(dr);
191 }
192 }
193 if (disk) CFRelease(disk);
194}
195
196if (err == 0) {
197diskNum = [sDiskintValue];
198partNum = [sPartintValue];
199
200self.vUUID = [self stringValueWithKey: @"DAVolumeUUID"];
201self.vName = [self stringValueWithKey: @"DAVolumeName"];
202self.vPath = [self stringValueWithKey: @"DAVolumePath"];
203if (self.vName == nil || [vName length]==0)
204self.vName = [[self.vPath lastPathComponent ] stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
205self.vAliasName = self.vName; // by default renamed = original part name
206self.vKind = [self stringValueWithKey: @"DAVolumeKind"];
207self.mediaPath = [self stringValueWithKey: @"DAMediaPath"];
208self.devProtocol = [self stringValueWithKey: @"DADeviceProtocol"];
209self.bsdName = [NSString stringWithString:name];
210
211self.devInternal = (bool) [[descDict objectForKey: @"DADeviceInternal"] boolValue];
212self.mediaRemovable = (bool) [[descDict objectForKey: @"DAMediaRemovable"] boolValue];
213
214}
215
216// Clean up.
217
218if (session != NULL && mustRelease) CFRelease(session);
219
220return err;
221}
222
223+(NSMutableArray*)extractInfoWithBSDNames: (NSArray*) bsdNames
224{
225return [PartitionInfoElement extractInfoWithBSDNames:bsdNames withArray: nil];
226}
227
228/// main extraction method create a dictionary of PartitionInfoElement objects containing all needed information from disk arbitration API
229+ (NSMutableArray*) extractInfoWithBSDNames: (NSArray*) names withArray:(NSMutableArray*) arr
230{
231NSArray* partArr = [PartitionInfoElement createBSDPartitionList];
232if (arr == nil)
233arr = [[[NSMutableArray alloc ] init] autorelease];
234
235if (partArr!=nil && [partArr count]>0)
236{
237DASessionRef session = DASessionCreate(NULL);
238for (NSString* part in partArr)
239{
240PartitionInfoElement* elt =
241[[[PartitionInfoElement alloc] initWithBSDName: part withinSession: session] autorelease];
242if (elt!=nil && [[elt vName] length] >0 && [elt isValid] )
243[arr addObject: elt];
244}
245if (session!=nil) CFRelease(session);
246}
247return arr;
248}
249
250- (int) extractInfoWithBSDName: (NSString*) name
251{
252return [self extractInfoWithBSDName:name withinSession: nil];
253}
254
255-(bool) isBootable
256{
257bool bootable = false;
258NSFileManager* mgr = [NSFileManager defaultManager];
259NSString *fmt = @"/Volumes/%@%s";
260NSRange r = [vPath rangeOfString:@"file://localhost/Volumes/"];
261NSString * vol = [NSString stringWithFormat: @"%@/",vName];
262
263//
264if (r.location != NSNotFound) {
265vol = [[vPath substringFromIndex:r.location+r.length] stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
266}
267
268// that Windows is the name of WIN32 bootable disk dir ...
269if(
270[mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "System/Library/Extensions" ]] ||
271 [mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "ntldr" ]] ||
272[mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "bootmgr" ]] ||
273[mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "boot/bcd" ]] ||
274[mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "pagefile.sys" ]] ||
275[mgr fileExistsAtPath: [NSString stringWithFormat: fmt, vol, "hiberfil.sys" ]]
276 )
277bootable=true;
278else if ([vName rangeOfString:@"ext"].location != NSNotFound) // linux ?
279bootable = true;
280return bootable;
281}
282
283/// Return the partition image index according to its file system
284-(int) imageIndexFromFs
285{
286
287if ( [[self vKind] rangeOfString:@"hfs"].location != NSNotFound )
288return 0; // Mac
289if ( [[self vKind] rangeOfString:@"fat"].location != NSNotFound ||
290 [[self vKind] rangeOfString:@"ntfs"].location != NSNotFound ||
291 [[self vKind] rangeOfString:@"dos"].location != NSNotFound )
292return 1; // Windows
293if ( [[self vKind] rangeOfString:@"ext"].location != NSNotFound )
294return 2; // Linux
295
296return 10; // unknown
297}
298
299/// Volume label trimming utility function
300+(NSString*) removesSpacesFromLabel:(NSString*) label
301{
302if (label == nil || [label length]==0) return label;
303return [label stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
304}
305
306/// make the object description available for NSLog() debug purpose
307-(NSString*) description
308{
309NSString* format =
310@"(\n"
311 " bsdName %@\n deviceProtocol %@\n deviceInternal %i\n"
312 " volumeName %@\n volumeKind %@\n volumeUUID %@\n"
313 " volumePath %@\n mediaPath %@\n mediaRemovable %i\n"
314 ")";
315NSString* value = [NSString stringWithFormat: format,
316 self.bsdName, self.devProtocol, self.devInternal,
317 self.vName, self.vKind, self.vUUID,
318 self.vPath, self.mediaPath, self.mediaRemovable ];
319return value;
320}
321
322
323/// initialize a partition element with DA partition info
324-(id) initWithBSDName:(NSString*) name
325{
326self = [super init];
327diskNum = partNum = -1;
328err = [self extractInfoWithBSDName: name withinSession: nil];
329return self;
330}
331
332/// initialize a partition element with DA partition info and an optional opened session
333-(id) initWithBSDName:(NSString*) name withinSession:(DASessionRef) session
334{
335self = [super init];
336diskNum = partNum = -1;
337err = [self extractInfoWithBSDName: name withinSession: session];
338
339return self;
340}
341
342-(void) cleanup
343{
344
345if (descDict != nil) CFRelease(descDict);
346if (bsdName != nil) [bsdName release];
347if (vUUID != nil) [vUUID release];
348if (vKind != nil) [vKind release];
349if (vName != nil) [vName release];
350if (mediaPath != nil) [mediaPath release];
351if (devProtocol != nil) [devProtocol release];
352if (vAliasName != nil) [vAliasName release];
353if (bootInfo != nil) [bootInfo release];
354bsdName = vUUID = vKind = vName = mediaPath = devProtocol = vAliasName = bootInfo = nil;
355descDict = nil;
356}
357
358/// release created objects
359-(void) dealloc
360{
361[self cleanup];
362[super dealloc];
363}
364
365@end
366

Archive Download this file

Revision: 466