Re: FSGetVolumeMountInfoSize returns error -36?
Re: FSGetVolumeMountInfoSize returns error -36?
- Subject: Re: FSGetVolumeMountInfoSize returns error -36?
- From: James Bucanek <email@hidden>
- Date: Thu, 19 Aug 2010 09:10:35 -0700
Chris Suter <mailto:email@hidden> wrote (Thursday, August
19, 2010 6:36 PM +1000):
On Thu, Aug 19, 2010 at 8:33 AM, James Bucanek <email@hidden>wrote:
James Bucanek <mailto:email@hidden> wrote (Tuesday, August 17,
2010 11:04 AM -0700):
For anyone stumbling across this thread in the future, it's actually even
simpler than I imagined. All you have to do is ...
<clip>
That seems a whole lot more complicated than just calling statfs and looking
at f_mntfromname. For example:
Chris,
I agree that your solution is simpler, and (in retrospect) I'm
sure it would work just fine. I considered something like that
when I began, but that solution makes an awful lot of
assumptions--assumptions about how the OS names devices,
assumptions about how those names relate to hierarchal
organization of those devices, and so on. That was more
assumptions that I was conformable making.
Ultimately, it turns out that you probably can safely make these
assumptions, much the way code with hard-coded paths to /tmp
(written thirty years ago) still compile and runs today.
I would hope that the solution that I settled on is more robust,
future-proof, and "correct" even if it's not more effective. I'm
not a stickler about these things--I freely admit to using
property lists to update the contents of loginwindow.plist (3
lines of Objective-C code), instead of the "correct" and
official solution which is to use AppleScript (what seems like 5
pages of dense, nearly indecipherable, Carbon gibberish).
Since we're sharing, here's my final solution. This is a method
in my CarbonVolume class, an Objective-C wrapper around all
things FSVolumeRefNum:
- (id)wholeDeviceIdentifier
{
// Returns an immutable object, suitable for use as a
dictionary key, that acts as a unique identifier for the
// logical device that contains the receiver's volume.
// For a hard disk, CD, or RAID this will be the device
name of the (logical) drive that contains the partition
// that contains the receiver's volume. For volumes not
associated with a "whole" media object, it returns the
// volume's filesystem identifier (as an NSNumber).
// Use the return value to compare with the
wholeDeviceIdentifier for other volumes to determine if the two volumes
// are known to share a common, physical, device.
// Begin by obtaining the default value, which is the
filesystem identifier for the volume.
// If *anything* goes wrong trying to locate the whole
IOMedia object in the I/O Registry,
// return this value instead.
id identifier = [[self fileManagerAttributes] objectForKey:NSFileSystemNumber];
const char* deviceName = [self deviceName];
if (deviceName[0]=='\0' || deviceName[0]=='/')
return identifier; // there is no BSD device name
or it's a network path
// This section of code was liberally copied from the
VolumeToBSDNode example project.
// Create a matching dictionary that will find the I/O
Registry node corresponding to the volume.
CFMutableDictionaryRef matchingDict = IOBSDNameMatching(kIOMasterPortDefault,0,deviceName);
if (matchingDict==NULL)
return identifier; // could not create match
criteria (unlikely)
io_service_t service;
service = IOServiceGetMatchingService(kIOMasterPortDefault,matchingDict);
if (service==IO_OBJECT_NULL)
return identifier; // this volume does not have an
IOMedia node in the registry
// Create an iterator across all parents of the service object
kern_return_t kernResult;
io_iterator_t iter;
kernResult = IORegistryEntryCreateIterator(service,
kIOServicePlane,
kIORegistryIterateRecursively | kIORegistryIterateParents,
&iter);
if (kernResult!=KERN_SUCCESS || iter==IO_OBJECT_NULL)
return identifier; // unable to create iterator (unlikely)
// Walk the I/O registry nodes looking for the whole media object
Boolean isWholeMedia = false;
do {
if (IOObjectConformsTo(service,kIOMediaClass))
{
// Found an IOMedia node in the registry tree
// See if it's a "whole" media node
CFTypeRef wholeMedia;
wholeMedia = IORegistryEntryCreateCFProperty(service,
CFSTR(kIOMediaWholeKey),
kCFAllocatorDefault,
0);
if (wholeMedia!=NULL)
{
isWholeMedia = CFBooleanGetValue(wholeMedia);
CFRelease(wholeMedia);
}
if (isWholeMedia)
{
// Get the device name of the whole media node
CFTypeRef bsdName;
bsdName = IORegistryEntryCreateCFProperty(service,
CFSTR(kIOBSDNameKey),
kCFAllocatorDefault,
0);
if (bsdName!=NULL)
{
// Success! Return the drive's BSD device
name as a string and exit
identifier = [(id)bsdName autorelease];
}
}
}
IOObjectRelease(service);
} while ( (service=IOIteratorNext(iter))!=IO_OBJECT_NULL &&
!isWholeMedia );
if (service!=IO_OBJECT_NULL)
IOObjectRelease(service);
IOObjectRelease(iter);
return identifier; // return the whole media device name,
or the default (if while loop falls through)
}
--
James Bucanek
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Filesystem-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden