26 #ifdef HAVE_UTIME_H

27 # include

28 #endif

39

30 #include "full-write.h"

31 #include "safe-read.h"

32

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

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().

<p>5.5.4. Использование <code>fchown()</code> и <code>fchmod()</code> для обеспечения безопасности</p>
Перейти на страницу:

Похожие книги