disk bsd name

Hello,


I am not sure if this is the right place to ask but here goes:

I need to know the (or a unique) name for the disk (not volume) which a file is on.

So far I have come up with this:


func GL_FileToDiskName( file:NSURL )->String?
  {
  var diskName:String?
  if let session = DASessionCreate( kCFAllocatorDefault )
       {
       var volumeURL:AnyObject?
       if file.getResourceValue( &volumeURL, forKey:NSURLVolumeURLKey, error:nil )
           {
            if let disk = DADiskCreateFromVolumePath( kCFAllocatorDefault, session.takeRetainedValue(), volumeURL as! NSURL )   
                 {
                 if let wholeDisk = DADiskCopyWholeDisk( disk.takeRetainedValue() )
                     {
                      let bsdName = DADiskGetBSDName( wholeDisk.takeRetainedValue() )
                      if bsdName != nil { diskName = String.fromCString( bsdName ) }
                     }
                 }
            }
        }
  return diskName
  }


Unfortunately it returns nil.

Any ideas?

I modified your code a little, and run it in Xcode 6.4 on 10.10.4.

func GL_FileToDiskName(file:NSURL) -> String? {
    var diskName:String?
    if let session = DASessionCreate(kCFAllocatorDefault)?.takeRetainedValue() {
        var volumeURL: AnyObject?
        if file.getResourceValue(&volumeURL, forKey:NSURLVolumeURLKey, error:nil) {
            if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as! NSURL)?.takeRetainedValue() {
                if let wholeDisk = DADiskCopyWholeDisk(disk)?.takeRetainedValue() {
                    let bsdName = DADiskGetBSDName(wholeDisk)
                    if bsdName != nil {
                        diskName = String.fromCString(bsdName)
                    }
                }
            }
        }
    }
    return diskName
}
let url = NSURL(fileURLWithPath: "/Users/dev/Desktop/IMG_1015.JPG")!
print(GL_FileToDiskName(url))

I got

Optional("disk0")


In Xcode 7, that should be:

func GL_FileToDiskName(file:NSURL) -> String? {
    var diskName: String?
    if let session = DASessionCreate(kCFAllocatorDefault) {
        var volumeURL:AnyObject?
        do {
            try file.getResourceValue(&volumeURL, forKey:NSURLVolumeURLKey)
            if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as! NSURL) {
                if let wholeDisk = DADiskCopyWholeDisk(disk) {
                    let bsdName = DADiskGetBSDName(wholeDisk)
                    if bsdName != nil {
                        diskName = String.fromCString(bsdName)
                    }
                }
            }
        } catch let error as NSError {
            NSLog("error=%@", error)
        }
    }
    return diskName
}

I need to know the (or a unique) name for the disk (not volume) which a file is on.

Why are you doing this? Running this through in my head I can think of various possible reasons but they all result in edge cases that make this much harder than a simple call to

DADiskCopyWholeDisk
.

For example, on my laptop, where the boot volume uses FileVault 2, running:

GL_FileToDiskName(NSURL(fileURLWithPath: "/"))

yields a value of

disk1
. That’s correct from one perspective but incorrect from another:
disk1
is the whole disk being presented to the OS by Core Storage, but the physical disk hosting that Core Storage volume is actually
disk0
.

You can run into similar problems with disk images, RAID, and so on.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

You are right, I should have stated my motive for this.

I want to optimize reading and writing of large files.

Unfortunately AVFoundation doesn't let me save a movie in place after modifying its metadata like I can in QuickTime.

OTOH it makes theaded movie processing a lot easier.


So I want to guard against reading/writing several movies simultaneously from/to partitions on the same physical disk.

Now that I know how to get the disk name and the whole disk name, how can I tell what is the phyical disk (or the RAID volume)?

TIA,

Jan E.

So all I needed to change was the location of the takeRetainedValue() calls. Duh...

Yes, you've done a good job, so it took less than 5 minutes to make your code work.

I just followed the principle: if you find Unmanaged, takeRetainedValue() or takeUnretaindValue() as soon as possible.

I want to optimize reading and writing of large files.

Ah, yes, that’s one of the “various possible reasons” I was mulling over.

The gotchas that spring to mind here are:

  • Core Storage, where one volume is outside of the volume group and one volume is inside

  • RAID

  • disk images

It’s possible to write code to do the right thing in each of these cases (you typically do it by taking the disk’s BSD name, mapping it to an IOMediaBSDClient in the I/O Registry, and grovelling around from there) but there are serious drawbacks:

  • it’s a whole bunch of ugly special case code

  • you will also find more special cases further down the path

Keep in mind that a lot of folks use SSDs these days (although maybe not as many in your market as in the general market) and doing multiple streaming operations on an SSD is not the horror show that it is on spinning rust.

All in all, it might be easier to use stick with your whole disk approach (-: That’s certainly a reasonable base heuristic.

Taking a step back, all the special cases, both good and bad, discussed above are an indication that perhaps a change of approach is in order. In situations like this I like to use an adaptive approach, so it does the right thing regardless of how things evolve in the future. For example, when starting a new export you could monitor the throughput of the previous export and if it drops more than you expect then you could suspend the new export. I’m not sure how feasible that is in the context of AVFoundation though.

Have fun!

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

In order to suspend, I think I would subclass AVAssetReaderTrackOutput, adding a Bool suspended and a semaphore

and have copyNextSampleBuffer method wait on the semaphore and reload the semaphore if not

suspended (or when suspended is set to false)

I don’t know enough about AVFoundation to say whether that’ll work or not. You might want to ask for advice over in Media > AVFoundation (Video and Camera).

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
disk bsd name
 
 
Q