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

Archive Download this file

Revision: 460