. Вместо этого она использует преимущество того факта, что формат
/etc/passwd
и
/etc/group
идентичен для трех первых полей (имя, пароль, числовой ID) и что оба используют в качестве разделителя двоеточие.
Строки 216–232 реализуют линейный поиск по файлу.
j
содержит число обнаруженных до сих пор двоеточий: 0 для имени и 2 для ID. Таким образом, при сканировании строки она заполняет как имя, так и ID.
Строки 233–235 завершают буфер
name
, устанавливают в глобальной
lastuid
последний найденный ID и возвращают 0 для обозначения успеха.
238 long /* long nblock(long size) */
239 nblock(size)
240 long size;
241 {
242 return ((size+511) >>9);
243 }
Функция
nblock
сообщает, сколько дисковых блоков использует файл. Это вычисление основано на размере файла, возвращенном
stat
. Размер блока V7 равен 512 байтам — размер физического сектора диска.
Вычисление в строке 242 выглядит несколько устрашающим. '
>>9
' является сдвигом вправо на девять битов. Это осуществляет деление на 512 для получения числа блоков. (На раннем аппаратном обеспечении сдвиг вправо выполнялся гораздо быстрее деления.) Пока все хорошо. Теперь, файл даже размером в один байт все равно занимает целый дисковый блок. Однако, '
1 / 512
' дает ноль (целое деление срезает), что неверно. Это объясняет '
size+511
'. Добавляя 511, этот код гарантирует, что сумма дает правильное число блоков при делении на 512.
Это вычисление, однако, лишь приблизительное. У очень больших файлов есть также дополнительные блоки. Несмотря на заявление в справочной странице V7 ls(1), данное вычисление не принимает в расчет дополнительные блоки.
Более того, рассмотрите случай файла с большими дырами (созданными установкой указателя файла дальше конца файла с помощью
lseek
). Дыры не занимают дисковых блоков; однако, это не отражается в значении размера. Поэтому вычисления, выполненные
nblock
, будучи обычно верными, могут давать результаты больше или меньше реальных.
По этим причинам в
struct stat
4 2 BSD были добавлены члены
st_blocks
, которые затем были приняты для System V и POSIX.
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
.
Обратите внимание на использование оператора
++
как в проверке цикла, так и в теле цикла. Результатом является пропуск пары в массиве, если в