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

ЖАНРЫ

Linux программирование в примерах
Шрифт:

5.5.3.1. Подделка

utime(file, NULL)

Некоторые более старые системы не устанавливают значения времени доступа и изменения равным текущему времени, когда второй аргумент

utime
равен
NULL
. Однако код более высокого уровня (такой, как GNU
touch
) проще, если он может полагаться на один стандартизованный интерфейс.

Поэтому библиотека GNU Coreutils содержит замещающую функцию для

utime
, которая обрабатывает этот случай, которую потом может вызвать код более высокого уровня. Это отражает принцип проектирования «выбор лучшего интерфейса для работы», который мы описали
в разделе 1.5 «Возвращаясь к переносимости».

Замещающая функция находится в файле

lib/utime.c
в дистрибутиве Coreutils Следующий код является версией из Coreutils 5.0. Номера строк относятся к началу файла:

24 #include <sys/types.h>

25

26 #ifdef HAVE_UTIME_H

27 # include <utime.h>

28 #endif

39

30 #include "full-write.h"

31 #include "safe-read.h"

32

33 /* Некоторые системы (даже имеющие <utime.h>) нигде не объявляют

34 эту структуру. */

35 #ifndef HAVE_STRUCT_UTIMBUF

36 struct utimbuf

37 {

38 long actime;

39 long modtime;

40 };

41 #endif

42

43 /* Эмулировать utime(file, NULL) для систем (подобных 4.3BSD),

44 которые не устанавливают в этом случае текущее время для времени

45 доступа и изменения file. Вернуть 0, если успешно, -1 если нет. */

46

47 static int

48 utime_null(const char *file)

49 {

50 #if HAVE_UTIMES_NULL

51 return utimes(file, 0);

52 #else

53 int fd;

54 char c;

55 int status = 0;

56 struct stat sb;

57

58 fd = open(file, O_RDWR);

59 if (fd < 0

60 || fstat(fd, &sb) < 0

61 || safe_read(fd, &c, sizeof c) == SAFE_READ_ERROR

62 || lseek(fd, (off_t)0, SEEK_SET) < 0

63 || full_write(fd, &c, sizeof c) != sizeof с

64 /* Можно сделать - это необходимо на SunOS4.1.3 с некоторой комбинацией

65 заплат, но та система не использует этот код: у нее есть utimes.

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
«до» и «после»).

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