Чтение онлайн

ЖАНРЫ

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

66 || fsync(fd) < 0

67 */

68 || (st.st_size == 0 && ftruncate(fd, st.st_size) < 0)

69 || close(fd) < 0)

70 status = -1;

71 return status;

72 #endif

73 }

74

75 int

76 rpl_utime(const char *file, const struct utimbuf *times)

77 {

78 if (times)

79 return utime(file, times);

80

81 return utime_null(file);

82 }

Строки 33–41

определяют структуру
struct utimbuf
; как сказано в комментарии, некоторые системы не объявляют эту структуру. Работу осуществляет функция
utime_null
. Используется системный вызов
utimes
, если он доступен (
utimes
является сходным, но более развитым системным вызовом, который рассматривается в разделе 14.3.2 «Файловое время в микросекундах:
utimes
.» Он допускает также в качестве второго аргумента
NULL
, что означает использование текущего времени.)

В случае, когда время должно обновляться вручную, код осуществляет обновление, прочитав сначала из файла байт, а затем записав его обратно. (Первоначальный touch Unix работал таким способом.) Операции следующие:

1. Открыть файл, строка 58.

2. Вызвать для файла

stat
, строка 60.

3. Прочесть один байт, строка 61 Для наших целей

safe_read
действует подобно
read
; это объясняется в разделе 10.4.4 «Повторно запускаемые системные вызовы»).

4. Переместиться обратно на начало файла с помощью

lseek
, строка 62. Это сделано для записи только что прочитанного байта обратно поверх себя.

5. Записать байт обратно, строка 63.

full_write
действует подобно
write
; это также рассматривается в разделе 10.4.4 «Повторно запускаемые системные вызовы»).

6. Если файл имеет нулевой размер, использовать

ftruncate
для установки его размера в ноль (строка 68). Это не изменяет файл, но имеет побочный эффект обновления времени доступа и изменения (
ftruncate
была описана в разделе 4 8 «Установка длины файла».)

7. Закрыть файл, строка 69.

Все эти шаги осуществляются в одной длинной последовательной цепи проверок внутри

if
. Проверки сделаны так, что если любое сравнение неверно,
utime_null
возвращает -1, как обычный системный вызов,
errno
автоматически устанавливается системой для использования кодом более высокого уровня.

Функция

rpl_utime
(строки 75–82) является «заместителем
utime
». Если второй аргумент не равен
NULL
, она вызывает настоящую
utime
. В противном случае она вызывает
utime_null
.

5.5.4. Использование

fchown
и
fchmod
для обеспечения безопасности

В исходных системах Unix были только системные вызовы

chown
и
chmod
. Однако, на сильно загруженных системах эти системные вызовы попадают в условия состязания, посредством чего злоумышленник может организовать замещение другим файлом файла, у которого изменяется владелец или права доступа.

Однако, после открытия файла условие состязания больше не представляет проблему. Программа может использовать

stat
с именем файла для получения информации о файле. Если получены сведения, которые ожидались, после открытия файла
fstat
может проверить, что файл тот же самый (сравнив поля
st_dev
и
st_ino
структур
struct stat
«до» и «после»).

Когда программа знает, что файлы те же самые, владение или права доступа могут быть изменены с помощью

fchown
или
fchmod
.

Эти системные вызовы, также как

lchown
, сравнительно недавние; [63] в старых системах Unix их не было, хотя в современных совместимых с POSIX системах они есть.

Соответствующих функций

futime
или
lutime
нет. В случае
futime
это (очевидно) потому, что временные отметки не являются критическими для безопасности системы в том же отношении, что для владения и прав доступа,
lutime
отсутствует потому, что временные отметки неуместны для символических ссылок.

63

fchown
и
fchmod
были введены в 4 2 BSD, но не включались в System V до выпуска 4 — Примеч. автора.

5.6. Резюме

• Иерархия файлов и каталогов, как она видится пользователю, является одним логическим деревом, корень которого находится в

/
. Оно составлено из одного или более разделов, каждый из которых содержит файловую систему. Внутри файловой системы в индексах хранятся данные о файлах (метаданные), включая размещение блоков данных.

• Каталоги осуществляют связь между именами файлов и индексами. Концептуально содержимое каталога, которое является просто последовательностью пар (индекс, имя). Каждый элемент каталога для файла называется (прямой) ссылкой, а файлы могут иметь множество ссылок. Прямые ссылки, поскольку они работают лишь по номеру индекса, все должны находиться в одной файловой системе. Символические ссылки являются указателями на файлы или каталоги и работают на основе имени файла, а не номера индекса, поэтому их использование не ограничено одной и той же файловой системой.

• Прямые ссылки создаются с помощью

link
, символические ссылки создаются с помощью
symlink
, ссылки удаляются с помощью
unlink
, а переименовываются файлы (с возможным перемещением в другой каталог) с помощью
rename
. Блоки данных файла не освобождаются до тех пор, пока счетчик ссылок не достигнет нуля и не закроется последний открытый дескриптор файла.

• Каталоги создаются с помощью

mkdir
, а удаляются с помощью
rmdir
; перед удалением каталог должен быть пустым (не оставлено ничего, кроме '
.
' и '
..
'). GNU/Linux версия функции ISO С
remove
вызывает соответствующие функции
unlink
или
rmdir
.

• Каталоги обрабатываются с помощью функций

opendir
,
readdir
,
rewinddir
и
closedir
.
struct dirent
содержит номер индекса и имя файла. Максимально переносимый код использует в члене
d_name
только имя файла. Функции BSD
telldir
и
seekdir
для сохранения и восстановления текущего положения в каталоге широко доступны, но не полностью переносимы, как другие функции работы с каталогами.

• Вспомогательные данные получаются с помощью семейства системных вызовов

stat
, структура
struct stat
содержит всю информацию о файле за исключением имени файла. (В самом деле, поскольку у файла может быть множество имен или он может совсем не иметь ссылок, невозможно сделать имя доступным.)

• Макрос

S_ISxxx
в
<sys/stat.h>
дает возможность определить тип файла. Функции
major
и
minor
из
<sys/sysmacros.h>
дают возможность расшифровки значений
dev_t
, представляющих блочные и символьные устройства.

• Символические ссылки можно проверить, использовав

lstat
, а поле
st_size
структуры
struct stat
для символической ссылки возвращает число байтов, необходимых для размещения имени указываемого файла. Содержимое символической ссылки читают с помощью
readlink
. Нужно позаботиться о том, чтобы размер буфера был правильным и чтобы завершить полученное имя файла нулевым байтом, чтобы можно было его использовать в качестве строки С.

Поделиться с друзьями: