Шрифт:
66 Нам все еще нужно обновить prev_level и, возможно, передать
67 некоторые суммы выше по иерархии. */
68 size = 0;
69 print = 0;
70 }
71 else
72 {
73 size = (apparent_size
74 ? sb->st_size
75 : ST_NBLOCKS (*sb) * ST_NBLOCKSIZE);
76 }
Теперь становится интересно. По умолчанию
du
подсчитывает пространство, занимаемое прямыми ссылками, лишь одни раз. Опция – -count-links
заставляет ее подсчитывать пространство для каждой ссылки; переменная opt_count_all
равна true, когда указана – -count-links
. Для отслеживания ссылок du
содержит хэш-таблицу [87] уже встречавшихся пар (устройство, индекс).87
Хэш-таблица является структурой данных, позволяющей быстрое получение сохраненной информации, подробности выходят за рамки данной книги — Примеч. автора.
Строки 60–63 проверяют, следует ли не включать файл в подсчет, либо из-за того, что он был исключен (
info->skip
равно true, строка 60), либо потому что не была указана – -count-links
(строка 61) и у файла несколько ссылок (строка 62) и файл уже находится в хеш-таблице (строка 63). В этом случае размер устанавливается в 0, поэтому он не входит в конечную сумму, a print
также устанавливается в false (строки 68–69). Если ни одно из этих условий не отмечается, размер вычисляется либо в соответствии с размером в
struct stat
, либо в соответствии с числом блоков диска (строки 73–75) Это решение основывается на переменной apparent_size
, которая установлена при использовании опции – -apparent-size
.
78 if (first_call)
79 {
80 n_alloc = info->level + 10; /* Allocate arrays */
81 sum_ent = XCALLOC(uintmax_t, n_alloc); /* to hold sums */
82 sum_subdir = XCALLOC(uintmax_t, n_alloc);
83 }
84 else
85 {
86 /* FIXME: Стыдно, что нам нужно приводить к типу size_t для избежания
87 предупреждений gcc о 'сравнении между знаковым и беззнаковым'.
88 Возможно, неизбежно, при условии, что члены структуры FTW
89 имеют тип 'int' (исторически), так как мне нужно, чтобы переменные
90 вроде n_alloc и prev_level имели осмысленные типы. */
91 if (n_alloc <= (size_t)info->level)
92 {
93 n_alloc = info->level * 2; /* Удвоить сумму */
94 sum_ent = XREALLOC(sum_ent, uintmax_t, realloc); /* И выделить повторно */
95 sum_subdir = XREALLOC(sum_subdir, uintmax_t, n_alloc);
96 }
97 }
98
99 size_to_print = size;
Строки 78–97 управляют динамической памятью, используемой для хранения статистики о размере файла,
first_call
является статической переменной (строка 12), которая равна true при первом вызове process_file
. В этом случае вызывается calloc
(через упаковывающий макрос в строках 81–82; это обсуждалось в разделе 3.2.1.8 «Пример чтение строк произвольной длины»). Остальную часть времени first_call
равно false, и используется realloc
(снова через упаковывающий макрос, строки 91–96). Строка 99 заносит значение
size
в size_to_print
; эта переменная может обновляться в зависимости от того, должна ли она включать размеры дочерних элементов. Хотя size
могла бы использоваться повторно, отдельная переменная упрощает чтение кода.
101 if (!first_call)
102 {
103 if ((size_t)info->level == prev_level)
104 {
105 /* Обычно самый частый случай. Ничего не делать. */
106 }
107 else if ((size_t)info->level > prev_level)
108 {
109 /* Нисхождение по иерархии.
110 Очистить аккумуляторы для *всех* уровней между prev_level
111 и текущим. Глубина может значительно меняться,
112 например, от 1 до 10. */
113 int i;
114 for (i = prev_level +1; i <= info->level; i++)