views:

89

answers:

3

Hola.

When I receive a list of MDItemRef items returned from a Spotlight query (in obj-c) I was wondering if there is an easy way to determine if they come from the OS install drive vs. an externally connected USB drive.

The basic premise is that I want to ignore anything from the local drive and only watch for files on external USB drives.

Thanks!

+3  A: 

Una sugerencía simple:

Grab the item's path and see if it's prefixed with "/Volumes/". If it is, then it's on an external device.

Example:

MDItemRef myItem = ...;
NSString * itemPath = (NSString *)MDItemCopyAttribute(myItem, kMDItemPath);
if ([itemPath hasPrefix:@"/Volumes/"]) {
  NSLog(@"Found external item");
} else {
  NSLog(@"Found internal item");
}
[itemPath release];
Dave DeLong
I'll give that a go...
Dave Martorana
A: 

Are you only looking on non-boot drives or on external drives (most of the time they mean the same, but they could be different on a on a system with multiple partitions or multiple internal drives (Mac Pro).

If you only want non-internal drives, you can look to see if the if the path is prefixed with a removable drive mount point.

Similar to Dave's code:

MDItemRef myItem = ...;
NSString * itemPath = (NSString *)MDItemCopyAttribute(myItem, kMDItemPath);
NSArray * removableVolumes = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
BOOL externalVolume = NO;

for (NSString *eachVolume in removableVolumes) {
    if ([itemPath hasPrefix: eachVolume]) {
        externalVolume = YES;
        break;
    }
}

Upside - ignores internal drives (if that's what you're going for).
Downside - includes mounted drive images (in your case, if they're Spotlight-indexed, I suppose).

This actually needs a bit of work - it could return a false positive if an internal drive mount point has the same prefix as an external drive - for example, internal drive mounted at "/Volumes/drive_2" and external drive "/Volumes/drive".

Jablair
+2  A: 

The problem with checking for paths in /Volumes is that it also includes internal partitions, like /Volumes/WINDOWS. Also, although rare, external drives can have mount points other than /Volumes

The more correct way is to use FSGetVolumeParms() to get a GetVolParmsInfoBuffer structure that contains information about the volume, like bIsEjectable, bIsRemovable, bIsOnInternalBus.

You can get the FSVolumeRefNum from a FSRef using FSGetCatalogInfo():

FSCatalogInfo info = {0};
OSErr status = FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &info, nil, nil, nil);
if (status == noErr)
{
    _volumeRefNum = info.volume;
}

With the volumeRef, you can get the volume params:

FSGetVolumeParms(_volumeRefNum, &_params, sizeof(_params));

_params is a GetVolParmsInfoBuffer structure that has info such as:

- (BOOL) isEjectable
{
    return (_params.vMExtendedAttributes & (1 << bIsEjectable)) != 0;
}

- (BOOL) isRemovable
{
    return (_params.vMExtendedAttributes & (1 << bIsRemovable)) != 0;
}

- (BOOL) isAutoMounted
{
    return (_params.vMExtendedAttributes & (1 << bIsAutoMounted)) != 0;
}

- (BOOL) isExternal
{
    return (_params.vMExtendedAttributes & (1 << bIsOnExternalBus)) != 0;   
}

- (BOOL) isInternal
{
    return (_params.vMExtendedAttributes & (1 << bIsOnInternalBus)) != 0;   
}
Darren