2014-11-12 6 views
2

Я тестировал код из APUE, в главе 14 (Advanced I/O) из файла карты памяти, то fstat() всегда возвращают fdin «s st_size как ноль, и я попытался stat() вместо этого, а также получить тот же результат , Я перечисляю код ниже (я удалил apue.h зависимостей):Почему stat и fstat возвращают st_size == 0?

#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).


UPDATE: О, там была ошибка опечатка, я должен обратиться к fdout к argv[2] и O_TRUNC флаг, конечно, сделать fdin к нулю. Должен ли я закрыть или удалить этот вопрос?

Причина Питона os.stat() также возвращает (stat.st_size == 0), что я прошел же тестовый файл (argv[1]), чтобы проверить, и файл был ранее усекается до нуля (я не проверить его размер с помощью ls -lh перед переходом к os.stat()), и, конечно, os.stat() return zero.

Не задавайте вопросов, прежде чем ложиться спать или спешить.

+4

Когда вы открываете 'fdout',' O_TRUNC' обрезает его. Поскольку и 'fdout', и' fdin' относятся к одному и тому же имени файла ('argv [1]'), конечно, размер будет равен нулю - вы просто усекали его. –

+1

+1 Одна из официальных целей stackoverflow - [решение проблемы резиновых уток] (http://blog.codinghorror.com/rubber-duck-problem-solving/), поэтому не стесняйтесь - вы сделали правильно, отлично вопрос. –

+1

Молодцы. Вы можете ответить на свой вопрос. – alk

ответ

0

Хорошо, реальная проблема заключается в том, что один и тот же входной файл равен open, и это не вызывает ошибки сборки или времени выполнения до ftruncate().

Первый open получить только для чтения fdin, второй open создать новый файл (fdout и усеченный), чтобы скопировать из fdin через карту памяти, а вторая открытая усечены первый файл (argv[1]), и очистить все свои содержание. Но fdinвсе еще работает с fstat (и, конечно), это заставляет меня трудно найти причину.

Вторая часть я всегда использую один и тот же файл для тестирования (выручено dd) и не проверять размер, поэтому os.stat(/path/to/file) и stat(/path/to/file)также возвращаютst_size == 0, это заставляет меня верить, что это должно быть какой-то ОС -level-prolicy определил поведение, и я бросился в Mac OS (используя тот же код опечатки) и получил тот же результат (они действительно согласованы на уровне POSIX, событие ошибка!), и, наконец, я пришел к SO для помощь.

Смежные вопросы