Hello!
I have flash storage with exFAT filesystem and I need to get it filesystem UUID. How can I do it programmatically?
I attempt to get it via ioreg, and I think that Filesystem UUID is "Content" property of partition. Below we can think that filesystem UUID is EBD0A0A2-B9E5-4433-87C0-68B6B72699C7.
+-o IOBlockStorageServices <class IORegistryEntry:IOService:IOBlockStorageDevice:IOBlockStorageServices, id 0x10000129c, registered, matched, active, busy 0 (73 ms), retain 6>
| {
| "IOMinimumSegmentAlignmentByteCount" = 4
| "device-type" = "Generic"
| "Protocol Characteristics" = {"Physical Interconnect"="USB","Read Time Out Duration"=30000,"SCSI Logical Unit Number"=0,"Physical Interconnect Location"="External","Write Time Out Duration"=30000,"Retry Count"=20}
| "Device Characteristics" = {"Vendor Name"="Kingston","Product Name"="DataTraveler 2.0","Product Revision Level"="1.00"}
| }
|
+-o IOBlockStorageDriver <class IORegistryEntry:IOService:IOStorage:IOBlockStorageDriver, id 0x10000129d, registered, matched, active, busy 0 (72 ms), retain 8>
| {
| "IOPropertyMatch" = {"device-type"="Generic"}
| "CFBundleIdentifier" = "com.apple.iokit.IOStorageFamily"
| "IOProviderClass" = "IOBlockStorageDevice"
| "IOClass" = "IOBlockStorageDriver"
| "IOProbeScore" = 0
| "CFBundleIdentifierKernel" = "com.apple.iokit.IOStorageFamily"
| "Statistics" = {"Operations (Write)"=338,"Latency Time (Write)"=0,"Bytes (Read)"=532992,"Errors (Write)"=0,"Total Time (Read)"=147844763,"Latency Time (Read)"=0,"Retries (Read)"=0,"Errors (Read)"=0,"Total Time (Write)"=3660822621,"Bytes (Write)"=1882624,"Operations (Read)"=101,"Retries (Write)"=0}
| "IOMatchCategory" = "IODefaultMatchCategory"
| "IOGeneralInterest" = "IOCommand is not serializable"
| }
|
+-o Kingston DataTraveler 2.0 Media <class IORegistryEntry:IOService:IOStorage:IOMedia, id 0x1000012b3, registered, matched, active, busy 0 (72 ms), retain 12>
| {
| "Content" = "GUID_partition_scheme"
| "Removable" = Yes
| "Whole" = Yes
| "Leaf" = No
| "BSD Name" = "disk2"
| "Ejectable" = Yes
| "Preferred Block Size" = 512
| "IOMediaIcon" = {"IOBundleResourceFile"="Removable.icns","CFBundleIdentifier"="com.apple.iokit.IOStorageFamily"}
| "BSD Minor" = 9
| "IOGeneralInterest" = "IOCommand is not serializable"
| "Writable" = Yes
| "BSD Major" = 1
| "Size" = 15500574720
| "IOBusyInterest" = "IOCommand is not serializable"
| "Open" = Yes
| "Content Hint" = ""
| "BSD Unit" = 2
| }
|
+-o IOMediaBSDClient <class IORegistryEntry:IOService:IOMediaBSDClient, id 0x1000012b8, registered, matched, active, busy 0 (0 ms), retain 6>
| {
| "IOProbeScore" = 30000
| "CFBundleIdentifier" = "com.apple.iokit.IOStorageFamily"
| "IOMatchCategory" = "IOMediaBSDClient"
| "IOClass" = "IOMediaBSDClient"
| "IOProviderClass" = "IOMedia"
| "CFBundleIdentifierKernel" = "com.apple.iokit.IOStorageFamily"
| "IOResourceMatch" = "IOBSD"
| }
|
+-o IOGUIDPartitionScheme <class IORegistryEntry:IOService:IOStorage:IOPartitionScheme:IOGUIDPartitionScheme, id 0x1000012ba, !registered, !matched, active, busy 0 (0 ms), retain 6>
| {
| "IOProbeScore" = 4000
| "IOPropertyMatch" = {"Whole"=Yes}
| "IOMatchCategory" = "IOStorage"
| "IOClass" = "IOGUIDPartitionScheme"
| "IOProviderClass" = "IOMedia"
| "CFBundleIdentifier" = "com.apple.iokit.IOStorageFamily"
| "CFBundleIdentifierKernel" = "com.apple.iokit.IOStorageFamily"
| "UUID" = "DB6A5DED-C145-4F28-B80E-5DA726D76AF2"
| "Content Mask" = "GUID_partition_scheme"
| }
|
+-o Microsoft Basic Data@1 <class IORegistryEntry:IOService:IOStorage:IOMedia, id 0x1000012be, registered, matched, active, busy 0 (0 ms), retain 11>
| {
| "Open" = Yes
| "Preferred Block Size" = 512
| "Base" = 1048576
| "Writable" = Yes
| "IOBusyInterest" = "IOCommand is not serializable"
| "Size" = 15499509248
| "Content" = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"
| "BSD Minor" = 10
| "Whole" = No
| "Removable" = Yes
| "UUID" = "E704A750-5562-4578-9F97-D4D0E0326C7A"
| "BSD Unit" = 2
| "BSD Major" = 1
| "Ejectable" = Yes
| "BSD Name" = "disk2s1"
| "Partition ID" = 1
| "IOGeneralInterest" = "IOCommand is not serializable"
| "GPT Attributes" = 0
| "Content Hint" = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"
| "Leaf" = Yes
| }
|
+-o IOMediaBSDClient <class IORegistryEntry:IOService:IOMediaBSDClient, id 0x1000012bf, registered, matched, active, busy 0 (0 ms), retain 7>
{
"IOProbeScore" = 30000
"CFBundleIdentifier" = "com.apple.iokit.IOStorageFamily"
"IOMatchCategory" = "IOMediaBSDClient"
"IOClass" = "IOMediaBSDClient"
"IOProviderClass" = "IOMedia"
"CFBundleIdentifierKernel" = "com.apple.iokit.IOStorageFamily"
"IOResourceMatch" = "IOBSD"
}
BUT when I try to check it via diskutil, I've get two ID's with similiar names - volume, disk/partition:
diskutil info disk2s1 | grep UUID
Volume UUID: C1E39943-2F19-369A-A22F-11027887EBC8
Disk / Partition UUID: E704A750-5562-4578-9F97-D4D0E0326C7A
And one of these UUIDs is not present in ioreg output - C1E39943-2F19-369A-A22F-11027887EBC8. Very interesting. I'd check in Disk Utility (with GUI) and in information about partition I see that (Filesystem UUID: C1E39943-2F19-369A-A22F-11027887EBC8):
https://i.ibb.co/pKrqs3r/Screenshot-2020-02-11-at-10-45-34.png
And for more information here is output of blkid in Linux:
sudo blkid /dev/sdf1
/dev/sdf1: LABEL="exFAT" UUID="9CAD-0C6D" TYPE="exfat" PARTLABEL="Microsoft Basic Data" PARTUUID="e704a750-5562-4578-9f97-d4d0e0326c7a"
We can see that partition UUID is equal, but filesystem UUID - is not.
Someone can explain me:
1. how I can get Filesystem UUID of volume programmatically?
2. why results in Linux and macOS are different?
3. why in some places C1E39943-2F19-369A-A22F-11027887EBC8 is Volume UUID, but in some places - Filesystem UUID? After all It really different things!
Thanks!
To understand what’s going on here, you need to learn more about how GPT and exFAT work. I can cover some basics here but most of this stuff is not Apple-specific.
Anyway, with regards the UUIDs in the I/O Registry:
is the GPT partition type GUID. The value EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 is for a basic data partition. The will be the same for all FAT-like volumes.Content
is the GPT unique partition GUID. As the name suggests, this should be globally unique.UUID
The
Volume UUID
reported by
diskutil
matches the value returned by DiskArbitration for the
kDADiskDescriptionVolumeUUIDKey
property. For example:
import DiskArbitration
func uuidForDisk(_ bsdName: String) -> UUID? {
guard
let session = DASessionCreate(nil),
let disk = DADiskCreateFromBSDName(nil, session, bsdName),
let descCF = DADiskCopyDescription(disk),
let desc = descCF as? [String:Any],
let uuidCF = desc[kDADiskDescriptionVolumeUUIDKey as String] as CFTypeRef?,
CFGetTypeID(uuidCF) == CFUUIDGetTypeID(),
let uuidStr = CFUUIDCreateString(nil, (uuidCF as! CFUUID)) as String?,
let uuid = UUID(uuidString: uuidStr)
else {
return nil
}
return uuid
}
For Apple file systems (like APFS and HFS Plus) this UUID is stored on the volume. The VFS plug-in makes it available to the rest of the system via
ATTR_VOL_UUID
(see the
getattrlist
man page).
I’m not an expert on exFAT, but I believe it has a similar affordance. Specifically, it looks like there is a Volume GUID directory entry to store this. If that entry is missing, I believe that our exFAT VFS plug-in will synthesise a UUID by hashing the volume serial number.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"