240 long size;
241 {
242 return ((size+511) >>9);
243 }
Функция nblock()
сообщает, сколько дисковых блоков использует файл. Это вычисление основано на размере файла, возвращенном stat()
. Размер блока V7 равен 512 байтам — размер физического сектора диска.
Вычисление в строке 242 выглядит несколько устрашающим. '>>9
' является сдвигом вправо на девять битов. Это осуществляет деление на 512 для получения числа блоков. (На раннем аппаратном обеспечении сдвиг вправо выполнялся гораздо быстрее деления.) Пока все хорошо. Теперь, файл даже размером в один байт все равно занимает целый дисковый блок. Однако, '1 / 512
' дает ноль (целое деление срезает), что неверно. Это объясняет 'size+511
'. Добавляя 511, этот код гарантирует, что сумма дает правильное число блоков при делении на 512.
Это вычисление, однако, лишь приблизительное. У очень больших файлов есть также дополнительные блоки. Несмотря на заявление в справочной странице V7
Более того, рассмотрите случай файла с большими дырами (созданными установкой указателя файла дальше конца файла с помощью lseek()
). Дыры не занимают дисковых блоков; однако, это не отражается в значении размера. Поэтому вычисления, выполненные nblock()
, будучи обычно верными, могут давать результаты больше или меньше реальных.
По этим причинам в struct stat
4 2 BSD были добавлены члены st_blocks
, которые затем были приняты для System V и POSIX.
245 int m1[] = { 1, S_IREAD>>0, 'r', '-' };
246 int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
247 int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
248 int m4[] = { 1, S_IREAD>>3, 'r', '-' };
249 int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
250 int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
251 int m7[] = { 1, S_IREAD>>6, 'r', '-' };
252 int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
253 int m9[] = { 2, S_ISVTX, ' t', S_IEXEC>>6, 'x', '-' };
254
255 int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9 };
256
257 pmode(aflag) /* void pmode(int aflag) */
258 {
259 register int **mp;
260
261 flags = aflag;
262 for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
263 select(*mp++);
264 }
265
266 select(pairp) /* void select(register int *pairp) */
267 register int *pairp;
268 {
269 register int n;
270
271 n = *pairp++;
272 while (--n>=0 && (flags&*pairp++)==0)
273 pairp++;
274 putchar(*pairp);
275 }
Строки 245–275 выдают права доступа к файлу. Код компактен и довольно элегантен, он требует тщательного изучения.
• Строки 245–253: массивы с m1
по m9
кодируют биты прав доступа для проверки вместе с соответствующими буквами для вывода. На каждую выводимую букву режима файла имеется один массив. Первый элемент каждого массива является числом пар (право доступа, буква), закодированных в данном конкретном массиве. Последний элемент является буквой, которая должна быть выведена в случае, если не найден ни один из битов прав доступа.
Обратите также внимание, что права доступа обозначены как 'I_READ>>0
', 'I_READ>>3
', 'I_READ>>6
' и т.д. Отдельные константы для каждого бита (S_IRUSR
, S_IRGRP
и т.п.) не были еще придуманы. (См. табл. 4.5 в разделе 4 6.1 «Указание начальных прав доступа к файлу».)
• Строка 255: массив m
указывает на каждый из массивов с m1
по m9
.
• Строки 257–264: функция pmode()
сначала устанавливает глобальную переменную flags
равной переданному параметру aflag
. Затем она просматривает в цикле массив m
, передавая каждый элемент функции select()
. Переданный элемент представляет один из массивов с m1
по m9
.
• Строки 266–275: функция select()
понимает структуру каждого из массивов с m1
по m9
. n
является числом пар в массиве (первый элемент); его устанавливает строка 271. Строки 272–273 ищут биты прав доступа, проверяя установленную ранее в строке 261 глобальную переменную flags
.
Обратите внимание на использование оператора ++
как в проверке цикла, так и в теле цикла. Результатом является пропуск пары в массиве, если в flags
не обнаружен бит доступа в первом элементе пары.