191   else

192    printf("%71d", p->lsize); /* - Размер в байтах */

193   cp = ctime(&p->lmtime);

194   if (p->lmtime < year) /* - Время изменения */

195    printf(" %-7.7s %-4.4s ", cp+4, cp+20); else

196    printf(" %-12.12s ", cp+4);

197  }

198  if (p->lflags & ISARG) /* - Имя файла */

199   printf("%s\n", p->ln.namep);

200  else

201   printf("%.14s\n", p->ln.lname);

202 }

Строки 178–197 обрабатывают опцию -l. Строки 179–181 выводят тип файла, права доступа и число ссылок. Строки 182–184 устанавливают t на ID владельца или группы, в зависимости от опции -g. Строки 185–188 получают соответствующее имя и выводят его, если оно доступно. В противном случае программа выводит числовое значение.

Строки 189–192 проверяют, является ли файл блочным или символьным устройством. Если да, они выводят старшее и младшее номера устройств, извлеченные с помощью макросов major() и minor(). В противном случае они выводят размер файла.

Строки 193–196 выводят соответствующее время. Если оно старше шести месяцев, код выводит месяц, день и год. В противном случае, выводятся месяц, день и время (формат результата с time() см. раздел 6.1.3.1 «Простое форматирование времени: asctime() и ctime()»).

Наконец, строки 198–201 выводят имя файла. Мы знаем, что для аргумента командной строки это завершающаяся нулем строка, и может быть использована %s. Для файла, прочитанного из каталога, оно может не завершаться нулем, поэтому должна использоваться явно указанная точность, %.14s.

204 getname(uid, buf) /* int getname(int uid, char buf[]) */

205 int uid;

206 char buf[];

207 {

208  int j, c, n, i;

209

210  if (uid==lastuid) /* Простое кэширование, см. текст */

211   return(0);

212  if (pwdf == NULL) /* Проверка безопасности */

213   return(-1);

214  rewind(pwdf); /* Начать с начала файла */

215  lastuid = -1;

216  do {

217   i = 0; /* Индекс в массиве buf */

218   j = 0; /* Число полей в строке */

219   n = 0; /* Преобразование числового значения */

220   while ((c=fgetc(pwdf)) != '\n') { /* Прочесть строки */

221    if (c==EOF)

222     return(-1);

223    if (c==':') { /* Число полей*/

224     j++;

225     c = '0';

226    }

227    if (j==0) /* первое поле - имя */

228     buf[i++] = c;

229    if (j==2) /* Третье поле - числовой ID */

230     n = n*10 + c - '0';

231   }

232  } while (n != uid); /* Продолжать до обнаружения ID */

233  buf[i++] = '\0';

234  lastuid = aid;

235  return(0);

236 }

Функция getname() преобразует ID владельца или группы в соответствующее имя. Она реализует простую схему кэширования; если переданное uid то же самое, которое находится в глобальной переменной lastuid, функция возвращает 0 (все нормально), буфер уже содержит имя (строки 210–211). lastuid инициализируется в -1 (строка 33), поэтому этот тест не проходит, когда getname() вызывается первый раз.

pwdf уже открыт либо в /etc/passwd, либо в /etc/group (см. строки 126–130). Код здесь проверяет, что открытие было успешным, и если нет, возвращает -1 (строки 212–213).

Удивительно, 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)

Перейти на страницу:

Похожие книги