Чтобы изменить только одну временную отметку, используйте оригинальное значение из
struct stat
. Например.
/* Для краткости проверка ошибок опущена */
struct stat sbuf;
struct utimbuf ut;
time_t now;
time(&now); /* Получить текущее время дня, см. след. главу */
stat("/some/file", &sbuf); /* Заполнить sbuf */
ut.actime = sbuf.st_atime; /*
Время доступа без изменений */
ut.modtime = now - (24 * 60 * 60);
/* Установить modtime на 24 часа позже */
utime("/some/file", &ut); /* Установить значения */
Вы можете спросить себя: «Почему может понадобиться кому-нибудь изменять времена доступа и изменения файла?» Хороший вопрос.
Чтобы на него ответить, рассмотрите случай программы, создающей дублирующие архивы, такой, как
tar
или
cpio
. Эти программы должны прочесть содержание файла, чтобы заархивировать его. Чтение файла, конечно, изменяет время доступа к файлу.
Однако, этот файл, возможно, не читался человеком в течение 10 лет. Некто, набрав '
ls -lu
', что отображает время доступа (вместо времени изменения по умолчанию), увидел бы, что последний раз данный файл просматривали 10 лет назад. Поэтому программа архивации должна сохранить оригинальные значения времени доступа и изменения, прочесть файл для архивации, а затем восстановить первоначальное время с помощью
utime
.
Аналогичным образом, рассмотрите случай архивирующей программы, восстанавливающей файл из архива. В архиве хранятся первоначальные значения времени доступа и изменения. Однако, когда файл извлечен из архива во вновь созданную копию на диске, новый файл имеет текущие дату и время для значений времени доступа и изменения.
Однако полезнее, когда вновь созданный файл выглядит, как если бы он имел тот же возраст, что и оригинальный файл в архиве. Поэтому архиватор должен иметь возможность устанавливать значения времени доступа и изменения в соответствии со значениями в архиве.
ЗАМЕЧАНИЕ. В новом коде вы можете захотеть использовать вызов
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.