Correct programmatic way to determine volume info

Currently we use stafs to determine the information about the filesystem volume we are on.


#include <string>
#include <iostream>
#include <sys/mount.h>
#include <sys/param.h>

void statFileSys(const std::string f)
{
    struct statfs fileStat;
    if(statfs(f.data(),&fileStat) == 0)
    {
        std::cout << "File type: " << fileStat.f_type <<'\n';
        std::cout << "File system name: "<<fileStat.f_fstypename << '\n';
    }
    else
    {
        std::cout << "statfs failed !!!"<<std::endl;
    }
}

int main()
{
    statFileSys("/some/network/path");
    statFileSys("/tmp");

    return 0;
}


We rely on


f_type


value to make decisions based on whether its HFS+ or APFS or network file system.


However, we are seeing following weird output on three different macOS systems for above small standalone reproducible code.

1]

macOS 10.12 + HFS+

File type: 25

File system name: autofs

File type: 23

File system name: hfs

2]

macOS 10.13 (beta) + HFS+

File type: 24

File system name: autofs

File type: 23

File system name: hfs


3]

macOS 10.13 (beta) + APFS

File type: 25

File system name: autofs

File type: 24

File system name: apfs


For 2] we get the f_type value for the network path (autofs) as 24 and while in 3] we get f_type as 24 for APFS whch doesnt seem consistent.

This brings us to the qustion, is using statfs the correct programmatic way to find the filesystem volume info ?

If its not, then what would be the right way to do the same ?

Disk Arbitration works pretty well.

https://developer.apple.com/library/content/documentation/DriversKernelHardware/Conceptual/DiskArbitrationProgGuide/ManipulatingDisks/ManipulatingDisks.html#//apple_ref/doc/uid/TP40009310-CH3-SW2

DASessionRef session = DASessionCreate(kCFAllocatorDefault);
CFURLRef mpURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/");

DADiskRef diskRef = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, mpURL);

CFDictionaryRef description = DADiskCopyDescription(diskRef);

From that you can get all sorts of info, such as the content hint, which maps back to the file system type through a UUID.

This allows me to fetch the info for "/" only. But I want the info for different paths irrespective of where it resides (network drive : /network/path/, local drive /tmp/ /usr etc.)

You can provide other mountpoints besides "/" by changing the input to the URL to be the same file system path you were using for the unix call.

I used following code with filesystem path "/tmp/" as below. I still get no answer.


#include <unistd.h>
#include <DiskArbitration/DiskArbitration.h>

int printDictionaryAsXML(CFDictionaryRef dict)
{
    CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault, (CFPropertyListRef)dict);
    if (!xml) return -1;
    write(STDOUT_FILENO, CFDataGetBytePtr(xml), CFDataGetLength(xml));
    CFRelease(xml);
    return 0;
}


#define OUT_ON_NULL(ptr, msg) \
    if (!ptr) { fprintf(stderr, "%s\n", msg); }
int main(int argc, char **argv)
{
    DASessionRef session = NULL;
    CFDictionaryRef diskInfo = NULL;
  // create a new Disk Arbitration session
    session = DASessionCreate(kCFAllocatorDefault);
    OUT_ON_NULL(session, "failed to create Disk Arbitration session");

    // create a new disk object from the given BSD device name
    CFURLRef mpURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/tmp/"),kCFURLPOSIXPathStyle,TRUE);
    DADiskRef diskRef = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, mpURL);
    //disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, diskName);
    OUT_ON_NULL(diskRef, "failed to create disk object");
    //
    // // obtain disk's description
    diskInfo = DADiskCopyDescription(diskRef);
    OUT_ON_NULL(diskInfo, "failed to retrieve disk description");
    //
    ret = printDictionaryAsXML(diskInfo);
    //
    if (diskInfo)
        CFRelease(diskInfo);
    if (disk)
        CFRelease(diskRef);
    if (session)
        CFRelease(session);

    return 0
}


Is there anything wrong with my code ?

I doubt that you're file system is mounted to /tmp.
It should be mounted to /tmp/fileSystemMtPt, where fileSystemMtPt is some folder you created for the purpose of being the top level of the file system.
/tmp is root:wheel and also mapped to another location, so it isn't a valid mountpoint.

What are these discussions you are making? Apple designed both filesystems to be opaque. Nothing at the level you are looking at is documented in any way and may change from one minor release to the next.

Correct programmatic way to determine volume info
 
 
Q