Литмир - Электронная Библиотека
A
A

ЗАМЕЧАНИЕ. В новом коде вы можете захотеть использовать вызов

utimes()
(обратите внимание на s в имени), который описан далее в книге, в разделе 14.3.2 «Файловое время в микросекундах:
utimes()
»

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
автоматически устанавливается системой для использования кодом более высокого уровня.

62
{"b":"576259","o":1}