Search code examples
craspbianstat

stat64 a large (~5GB) file


On raspbian, I am trying to do stat/stat64 a large file: 5.4G /tmp/some.mpg. Here's the code:

#include <stdio.h>
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <sys/stat.h>

int main(){
    char filename[] = "/tmp/some.mpg";
    struct stat64 myst;
    int x = stat64(filename, &myst );
    if ( x < 0 ){
        printf("x is %d\n", x);
        perror("stat failure");
    }
    printf("%s size: %ld\n", filename, myst.st_size);

    return 0;
}

It it however displaying erroneous info when I run it:

$ gcc bigsize.c -D_FILE_OFFSET_BITS=64  -o bigsize
$ ./bigsize 
/tmp/some.mpg size: 1435916040
$ ls -ltr /tmp/some.mpg 
-rw-r--r-- 1 XXX YYYY 5730883336 Jul 27 08:44 /tmp/some.mpg

On x86_64 this seems to work OK, not on armv7l

Please show me the right way to accomplish this, thanks!

Update 1

this seems to work, after changing printf from ld to llu

#include <stdio.h>
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <sys/stat.h>

int main(){
        char filename[] = "/tmp/some.mpg";
        struct stat64 myst;
        int x = stat64(filename, &myst );
        if ( x < 0 ){
                printf("x is %d\n", x);
                perror("stat failure");
        }
        printf("%s size: %llu\n", filename, myst.st_size);

        return 0;
}

Update 2

This works, after reading up the answers:

#include <stdio.h>
#include <inttypes.h>

#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <sys/stat.h>

int main(){
    char filename[] = "/tmp/some.mpg";
    struct stat64 myst;
    int x = stat64(filename, &myst );
    if ( x < 0 ){
        printf("x is %d\n", x);
        perror("stat failure");
    }
    printf("%s size: %llu\n", filename, myst.st_size);
    printf("%s size: %jd\n", filename, (intmax_t)myst.st_size);
    printf("file %s is %" PRIdMAX " bytes.\n", filename, (intmax_t)myst.st_size);

    return 0;
}

Compiled thusly:

$ gcc bigsize.c  -o bigsize -Wall -Wextra ; echo $?
0

Run:

 $ ./bigsize 
/tmp/some.mpg size: 5730883336
/tmp/some.mpg size: 5730883336
file /tmp/some.mpg is 5730883336 bytes.

Thanks to all!


Solution

  • The issue is you telling printf() that you're giving it an argument that's a long, but then actually passing it an argument that is in this case a long long, causing undefined behavior when the two types are different sizes. It works on the x86_64 system because long and long long are both 64-bit, but I bet the arm system uses 32-bit longs and 64-bit long longs.

    One portable approach when you don't know the exact type to print out is to cast it to the largest possible one (intmax_t from <stdint.h>, and use the print macros from <inttypes.h> to display it:

    printf("file %s is %" PRIdMAX " bytes.\n", filename, (intmax_t)myst.st_size);