c++macosfilesystemsposixmacos-high-sierra

macOS : 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 statfs the correct programmatic way to find the filesystem volume info on macOS ?

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


Solution

  • According to the documentation for vfs_filetype, which is returned by vfs_statfs(), Apple regards the filesystem type numbers as an archaic mechanism. While this is not definitive for statfs(), vfs_statfs() is better documented:

    Filesystem type numbers are an old construct; most filesystems just get a number assigned based on the order in which they are registered with the system.

    As filesystem type numbers are now assigned at runtime in recent versions of MacOS, you must use f_fstypename to determine the type. You will note that in the signature for AppKit's getFileSystemInfoForPath method that filesystem type is represented as a string there as well. It seems the most official you're going to get is Apple's own API.

    #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)  
        {  
            if(!strcmp(fileStat.f_fstypename, "apfs") )
                std::cout << "File system is APFS" << std::endl;
            else if(!strcmp(fileStat.f_fstypename, "hfs") )
                std::cout << "File system is HFS+" << std::endl;
            else if(!strcmp(fileStat.f_fstypename, "nfs") )
                std::cout << "File system is NFS" << std::endl;
            else if(!strcmp(fileStat.f_fstypename, "cd9660") )
                std::cout << "File system is CD-ROM" << std::endl;
            else
                std::cout << "We weren't looking for a " 
                    << fileStat.f_fstypename << " were we?" << std::endl;
        }  
        else  
        {  
            std::cout << "statfs failed !!!" << std::endl;  
        }  
    }  
    
    int main()  
    {  
        statFileSys("/some/network/path");  
        statFileSys("/tmp");  
    
        return 0;  
    }