2013-09-21 3 views
0

Я написал небольшой фрагмент кода, который использует системный вызов nftw для того, чтобы сделать дерево, идущее.общий размер каталога с nftw отличается от du output

int flags =0; 
flags = flags | FTW_MOUNT; 
int nopenfd = 10; 

if(nftw(argv[1], sum_sizes, nopenfd, flags) == -1) 
    return EXIT_FAILURE; 

С помощью этой опции, nftw не сканирует каталог, если это устанавливается точка и разыменовывает символическую ссылку (поведение по умолчанию).

На каждом файл nftw называют эту функцию:

/*total_size is the sum of each file/directory/link*/ 
long long int total_size, total_real_size = 0; 

static int sum_sizes(const char *pathname, const struct stat *statbuf, int typeflag, struct FTW *ftwbuf) 
{ 
/*if stat failed on the current file*/ 
if(typeflag == FTW_NS) 
{ 
    printf("No stats (permissions ?) on %s", pathname); 
    return 0; 
} 
total_size = total_size + (long long int) statbuf->st_size; 
total_real_size = total_real_size + (long long int) (statbuf->st_blocks * 512); 
return 0; 
} 

Так В конце концов, я показываю кумулятивные размеры:

printf("total size: %lld (%0.2lf K %0.2lf M)\n", total_size, (float)total_size /1024.0, (float)total_size /(1024.0*1024.0)); 
printf("total real size: %lld (%0.2lf K %0.2lf M)\n", total_real_size, (float)total_real_size /1024.0, (float)total_real_size /(1024.0*1024.0)); 

Когда я сравниваю значение с им У меня есть некоторые различия

time ./scan_dir ~/   
====> 
total size: 15208413390 (14851966.00 K 14503.87 M) 
total real size: 15708553216 (15340384.00 K 14980.84 M) 
block size : 4096/fond. block size : 4096 
fs size: 22.7895 G 
./scan_dir ~/ 0,03s user 0,24s system 98% cpu 0,277 total 


time du -s ~/  
15119876 /home/cedlemo/ 
du -s ~/ 0,07s user 0,22s system 98% cpu 0,287 total 

Примечание: после прочтения man-страницы du я знаю, что du имеет почти такое же поведение, что и мой l ittle application scan_dir (пропустить точки монтирования, символическую ссылку derefrences и использовать 1024 для вычисления значения в Ko)

Похоже, что более близкое значение, найденное в моем приложении, - это сумма реального размера (используемые блоки), но значение на самом деле не то же самое.

В чем может быть причина этой разницы? Что я делаю неправильно?

ответ

1

По умолчанию du делает не следует символическим ссылкам. Ваш код делает.

du -ks DIRECTORY/ 

эквивалентно

find DIRECTORY/ -printf '%k\n' | awk '{s+=$1} END { printf "%.0f\n", s }' 

который смотрит на каждой записи каталога только один раз, не следует симлинке, не пересекает точки монтирования, и выводит общую сумму st_blocks*2 (то есть, в 1024- байтовые единицы). Другими словами, количество 1024-байтных блоков, выделенных для содержимого файла и каталога - использование диска.

Сумма логических размеров файлов и каталогов, с другой стороны,

find DIRECTORY/ -printf '%s\n' | awk '{s+=$1} END { printf "%.0f\n", s/1024.0 }' 

, который не имеет ничего общего с использования диска, только на кажущуюся объем информации, хранящейся в файлах и каталогах. Обычно это измерение ограничивается только обычными файлами, то есть

find DIRECTORY/ -type f -printf '%s\n' | awk '{s+=$1} END { printf "%.0f\n", s/1024.0 }' 

поэтому в основном говорит пользователю, как большой файл, они получили бы, если бы они сцепить все свои файлы вместе в один большой файл. Является ли это значимым, спорным, но многие пользователи находят его информативным. Во всяком случае, это, безусловно, другое измерение использования диска.


В статистике файлов (см man 2 fstat), st_blocks описывает, сколько единиц 512 байт выделяются для содержимого файла, и st_size логического размера файла.

Поддержка большинства файловых систем редкие файлы. Это означает, что когда вы увеличиваете файл с помощью truncate() или записываете в более высокое смещение файла, чем текущий размер файла, файловая система вообще не сохраняет пропущенную часть. Однако, совершенно нормально читать эту часть; он всегда будет читаться как все нули. Поэтому огромный файл может потреблять только несколько блоков, если он в основном равен нулю. (Чтобы быть точными, «пропускаются нули». При создании файла, просто писать нули не производит разреженный файл. Ваше приложение должно пропустить запись, нулей, чтобы произвести разреженный файл.)

Это также возможно, количество блоков будет больше, чем одно из них будет предполагаться на основе размера файла из-за косвенных блоков, используемых некоторыми файлами в некоторых файловых системах. Может быть выделено и учтено «дополнительные блоки», поскольку файл фрагментирован или иным образом особым. И во всех типичных файловых системах количество выделенных блоков округляется до кратного размеру размещения файловой системы.


В вашем случае, total size логическая длина файла, если вы конкатенировать содержимое всех файлов и каталогов в один файл, в том числе любых дубликатов, на которые ссылаются симлинками.

В вашем случае, total real size описывает объем дискового пространства, выделяемого для всей суммы файлов и каталогов, если символьные ссылки были заменены копиями оригинальных файлов.

Если вы смените

flags = FTW_MOUNT | FTW_PHYS; 

вы должны получить total real size, который соответствует du -s.

+0

Спасибо за ваш ответ (очень впечатляет), вы решаете мою проблему (я неправильно понял поведение флагов FTW_PHYS). Мои новые значения: '14547636,00 K для моего небольшого приложения' и' 14547532 для du-s', поэтому на основе вывода du, разница незначительна: '((14547944 - 14547532) ÷ 14547532) × 100) = 0, 002832096% ' – cedlemo

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