简体   繁体   中英

Why stat and fstat return the st_size == 0?

I was testing a code from APUE, in chapter 14( Advanced I/O ) of memory map file, the fstat() always return the fdin 's st_size as zero, and I tried stat() instead, and also get the same result. I list the code below(I have removed the apue.h dependencies):

#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#define COPYINCR (1024*1024*1024) /* 1GB */

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("usage: %s <fromfile> <tofile>", argv[0]);
        exit(1);
    }

    int fdin, fdout;
    if ((fdin = open(argv[1], O_RDONLY)) < 0) {
        printf("can not open %s for reading", argv[1]);
        exit(1);
    }

    if ((fdout = open(argv[2] /* typo fix */, O_RDONLY | O_CREAT | O_TRUNC)) < 0) {
        printf("can not open %s for writing", argv[2]);
        exit(1);
    }

    struct stat sbuf;
    if (fstat(fdin, &sbuf) < 0) { /* need size fo input file */
        printf("fstat error");
        exit(1);
    }


    // always zero, and cause truncate error (parameter error)
    printf("input_file size: %lld\n", (long long)sbuf.st_size); 

    if (ftruncate(fdout, sbuf.st_size) < 0) { /* set output file size */
        printf("ftruncate error");
        exit(1);
    }

    void *src, *dst;
    off_t fsz = 0;
    size_t copysz;
    while (fsz < sbuf.st_size) {
        if (sbuf.st_size - fsz > COPYINCR)
            copysz = COPYINCR;
        else
            copysz = sbuf.st_size - fsz;

        if (MAP_FAILED == (src = mmap(0, copysz, PROT_READ,
                        MAP_SHARED, fdin, fsz))) {
            printf("mmap error for input\n");
            exit(1);
        }

        if (MAP_FAILED == (dst = mmap(0, copysz,
                            PROT_READ | PROT_WRITE,
                            MAP_SHARED, fdout, fsz))) {
            printf("mmap error for output\n");
            exit(1);
        }

        memcpy(dst, src, copysz);
        munmap(src, copysz);
        munmap(dst, copysz);

        fsz += copysz;
    }

    return 0;
}

And then I have tried the Python os.stat , it also get the zero result, why this happened? I have tried these and got the same result on Mac OS (Darwin kernel 13.4) and Ubuntu (kernel 3.13).


UPDATE : Oh, there was a typo error, I should refer to fdout to argv[2] , and the O_TRUNC flag certainly make the fdin to zero. Should I close or delete this question?

The reason why Python's os.stat() also return (stat.st_size == 0) is that I passed the same test file ( argv[1] ) to test, and the file has been previously truncated to zero (I haven't check its size using ls -lh before passing to os.stat() ), and certainly os.stat() return zero.

Do not ask SO questions before you go to bed or in a rush.

Ok, the real problem is double open the same input file, and this does not cause any build or runtime error until the ftruncate() .

The first open get a read-only fdin , the second open create a new file ( fdout and truncated) to copy from fdin via memory map, and the second open truncated the first file ( argv[1] ), and cleaned all its content. But the fdin still working with fstat (and certainly), this make me hard to find the reason.

The second part is I always use the same file for testing (generated via dd ) and have not checking the size, so the os.stat(/path/to/file) and stat(/path/to/file) also return st_size == 0 , this makes me believe that this must be some os-level-prolicy defined the behaviour, and I rushed to Mac OS (using the same typo code), and got the same result (they really consistent on POSIX level, event the bug!), and at last, I came to SO for help .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM