switch (spname(argv[i], buf)) {
case -1: /* no match possible */
fp = efopen(argv[i], "r");
break;
case 1: /* corrected */
fprintf(stderr, "\"%s\"? ", buf);
if (ttyin() == 'n')
break;
argv[i] = buf; /* fall through... */
case 0: /* exact match */
fp = efopen(argv[i], "r");
print(fp, pagesize);
fclose(fp);
}
exit(0);
}
Функции по коррекции написания не следует слепо применять к каждой программе, которая использует имена файлов. Они хорошо сочетаются с
p
, так как
p
— диалоговая программа, но подходят и для недиалоговых программ.
Упражнение 7.5
Насколько вы можете улучшить эвристику для выявления наилучшего совпадения в
spname
? Например, неразумно рассматривать регулярный файл так, как если бы он был каталогом; текущая версия это допускает.
Упражнение: 7.6
Имя
tx
совпадает с каким-либо именем
tc
, которое оказывается последним в каталоге для любого одиночного символа
с
. Можете ли вы придумать лучшую меру расстояния? Реализуйте ее и посмотрите, насколько хорошо эта конструкция работает с реальными пользователями.
Упражнение 7.7
Работает ли
p
ощутимо быстрее, если чтение каталога выполняется большими порциями?
Упражнение 7.8
Модифицируйте
spname
, чтобы возвращать имя, которое является префиксом желаемого имени, если нельзя найти более точного совпадения. Как следует разрешить ситуацию, если несколько имен совпадают с префиксом?
Упражнение 7.9
Какую пользу могли бы извлечь другие программы из
spname
? Сконструируйте отдельную программу, которая корректировала бы другие аргументы прежде, чем передать их другой программе, как в
$ fix prog filenames...
Можете написать версию
cd
, которая использует
spname
? Как бы вы ее встроили?
7.3 Файловая система: индексные дескрипторы
Теперь мы обсудим системные вызовы применительно к файловой системе, в частности к такой информации о файлах, как размеры, даты изменений, права доступа и т.д. Эти системные вызовы позволяют получить полностью всю информацию, о которой упоминалось во второй главе.
Для начала разберемся в самом индексном дескрипторе. Часть индексного дескриптора описывается структурой stat, определенной в
<sys/stat.h>
:
struct stat /* структура, возвращаемая stat */
{
dev_t st_dev; /* устройство, содержащее файл */
ino_t st_ino; /* индекс */
short st_mod; /* биты режима */
short st_nlink; /* число связей файла */
short st_uid; /* пользовательский идентификатор
владельца */
short st_gid; /* идентификатор группы владельцев */
dev_t st_rdev; /* для специальных файлов */
off_t st_size; /* размер файла в символах */
time_t st_atime; /* время последнего чтения файла */
time_t st_mtime; /* время последней записи
или создания файла */
time_t st_ctime; /* время последнего изменения
индексного дескриптора или файла */
}
Большинство полей поясняются примечаниями. Типы вроде
dev_t
и
ino_t
определены в
<sys/types.h>
, как отмечено выше. Поле
st_mode
содержит множество флагов, описывающих файл; для удобства определения флагов также являются частью файла
<sys/stat.h>
:
#define S_IFMT 0170000 /* тип файла */
#define S_IFDIR 0040000 /* каталог */
#define S_IFCHR 0020000 /* байт-ориентированный */
#define S_IFBLK 0060000 /* блок-ориентированный */
#define S_IFREG 0100000 /* регулярный */
#define S_SUID 0004000 /* установка идентификатора пользователя при
выполнении */
#define S_ISGID 0002000 /* установка идентификатора группы
при выполнении */
#define S_ISVTX 0001000 /* сохранить выгруженный текст даже после
использования */
#define S_IREAD 0000400 /* разрешение читать, владелец */
#define S_IWRITE 0000200 /* разрешение писать, владелец */
#define S_IEXEC 0000100 /* разрешение на выполнение/поиск, владелец */
Индексный дескриптор для файла доступен двум системным вызовам
stat
и
fstat
. При вызове
stat
параметром является имя файла, а результатом — информация из индексного дескриптора для этого файла (или — 1 при наличии ошибки).
Fstat
выполняет те же функции в отношении дескриптора открытого файла (не в отношении указателя на
FILE
). Иными словами,
char *name;
int fd;