Search code examples
clinuxglibc

How to use statfs64() in a 32bit program?


This is my code:

#include <stdio.h>
#include <sys/statfs.h>

int main(int argc, char** argv)
{
    struct statfs64 mystatfs64;
    statfs64("/", &mystatfs64);  
    return 0;
}

But I get this error:

error: storage size of ‘mystatfs64’ isn’t known
warning: implicit declaration of function ‘statfs64’; did you mean ‘statfs’?

On the man page it says: The glibc statfs() and fstatfs() wrapper functions transparently deal with the kernel differences.

So I changed my code to:

#include <stdio.h>
#include <sys/statfs.h>

int main(int argc, char** argv)
{
    struct statfs mystatfs;
    statfs("/", &mystatfs);
    return 0;
}

It now compiles but sizeof(((struct statfs*)0)->f_blocks) is 4 so I can't handle big file systems.

I also tried to define __USE_LARGEFILE64 and __USE_FILE_OFFSET64 without any success.


Solution

  • The __USE_* macros are for glibc's internal header features.h to define, not you. If you try to define them yourself, they won't work.

    You are instead supposed to define macros from a different set, called the "feature test macros" or "feature selection macros" and partially specified by POSIX. The most up-to-date and coherent documentation of the full set of feature test macros understood by glibc is in the Linux manpages: feature_test_macros(7). Note that most of these macros must be defined before you include any system headers.

    The best way to write the code you're trying to write is to use the _FILE_OFFSET_BITS feature test macro to make normal off_t, fsblkcnt_t, etc. be 64 bits wide:

    #define _FILE_OFFSET_BITS 64
    #include <inttypes.h>
    #include <stdio.h>
    #include <sys/statfs.h>
    
    int main(int argc, char** argv)
    {
        struct statfs mystatfs;
        statfs("/", &mystatfs);
        printf("block count: %"PRIu64"\n", mystatfs.f_blocks);
        return 0;
    }
    

    If you don't want to add this #define to the top of every .c file of your program, you may instead be able to add -D_FILE_OFFSET_BITS=64 to your compilation options in your Makefile or equivalent (for instance, add it to CPPFLAGS if you're using for Make's standard built-in compilation rules).

    You also have the option of using _LARGEFILE64_SOURCE to gain access to the xxx64 functions and types, but this is discouraged by the C library maintainers: note what it says about it in the manpage I linked above

    _LARGEFILE64_SOURCE
    Expose definitions for the alternative API specified by the LFS (Large File Summit) as a "transitional extension" to the Single UNIX Specification. (See ⟨https://www.opengroup.org/platform/lfs.html⟩.) The alternative API consists of a set of new objects (i.e., functions and types) whose names are suffixed with "64" (e.g., off64_t versus off_t, lseek64() versus lseek(), etc.). New programs should not employ this macro; instead _FILE_OFFSET_BITS=64 should be employed.

    (boldface: my emphasis)