【问题标题】:Why stat and fstat return the st_size == 0?为什么 stat 和 fstat 返回 st_size == 0?
【发布时间】:2014-11-12 16:05:32
【问题描述】:

我正在测试来自 APUE 的代码,在内存映射文件的第 14 章(高级 I/O)中,fstat() 始终将fdinst_size 返回为零,我改为尝试stat(),也得到了相同的结果。我列出了下面的代码(我已经删除了 apue.h 依赖项):

#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;
}

然后我尝试了 Python os.stat,它也得到了零结果,为什么会这样?我已经尝试过这些并在 Mac OS(Darwin 内核 13.4)和 Ubuntu(内核 3.13)上得到了相同的结果。


更新: 哦,有一个拼写错误,我应该参考fdoutargv[2]O_TRUNC 标志肯定会使fdin 归零。我应该关闭还是删除这个问题?

Python的os.stat()也返回(stat.st_size == 0)的原因是我通过同一个测试文件argv[1])来测试,文件之前已经被截断为零(我没有'在传递给os.stat()之前不要使用ls -lh检查它的大小),当然os.stat()返回零。

不要在睡前或匆忙中问 SO 问题。

【问题讨论】:

  • 当您打开 fdout 时,O_TRUNC 会截断它。由于fdoutfdin 都引用相同的文件名(argv[1]),因此大小当然为零 - 你只是截断了它。
  • +1 stackoverflow 的官方目标之一是rubber duck problem solving,所以不要感到羞耻 - 你做得对,好问题。
  • 干得好。您很可能会发布自己问题的答案。
  • 我同意 Paulo Scardine 和其他人的观点,我认为您应该发布自己问题的答案。我真的很高兴你能认出如何这个错字是怎么发生的,以及为什么你一开始就错过了它。我认为记录可能会帮助下一个偶然发现此问题或类似问题的人(我们都制造此类错误),并展示如何检查/修复/避免它们绝对有用。 :)

标签: c linux stat


【解决方案1】:

好的,真正的问题是双重open 相同的输入文件,这不会导致任何构建或运行时错误,直到ftruncate()

第一个open 获得只读fdin,第二个open 创建一个新文件(fdout 并被截断)以通过内存映射从fdin 复制,第二个打开截断第一个文件 (argv[1]),并清理了其所有内容。但是fdin 仍在工作fstat(当然),这让我很难找到原因。

第二部分是我总是使用同一个文件进行测试(通过dd生成)并且没有检查大小,所以os.stat(/path/to/file)stat(/path/to/file)也返回st_size == 0 ,这让我相信这一定是一些操作系统级别的协议定义了行为,我冲到Mac OS(使用相同的错字代码),并得到了相同的结果(它们在POSIX级别上真的一致,事件错误!),最后,我来寻求帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 2015-07-08
    • 2014-06-03
    • 1970-01-01
    • 2019-08-05
    • 1970-01-01
    相关资源
    最近更新 更多