Роббинс Арнольд
Шрифт:
Удивительно,
ls
не использует getpwuid
или getgrgid
. Вместо этого она использует преимущество того факта, что формат /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. 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
кодируют биты прав доступа для проверки вместе с соответствующими буквами для вывода. На каждую выводимую букву режима файла имеется один массив. Первый элемент каждого массива является числом пар (право доступа, буква), закодированных в данном конкретном массиве. Последний элемент является буквой, которая должна быть выведена в случае, если не найден ни один из битов прав доступа.