1 /* Detecting file changes using modification times.
2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <file_change_detection.h>
20
21 #include <errno.h>
22 #include <stddef.h>
23
24 bool
__file_is_unchanged(const struct file_change_detection * left,const struct file_change_detection * right)25 __file_is_unchanged (const struct file_change_detection *left,
26 const struct file_change_detection *right)
27 {
28 if (left->size < 0 || right->size < 0)
29 /* Negative sizes are used as markers and never match. */
30 return false;
31 else if (left->size == 0 && right->size == 0)
32 /* Both files are empty or do not exist, so they have the same
33 content, no matter what the other fields indicate. */
34 return true;
35 else
36 return left->size == right->size
37 && left->ino == right->ino
38 && left->mtime.tv_sec == right->mtime.tv_sec
39 && left->mtime.tv_nsec == right->mtime.tv_nsec
40 && left->ctime.tv_sec == right->ctime.tv_sec
41 && left->ctime.tv_nsec == right->ctime.tv_nsec;
42 }
libc_hidden_def(__file_is_unchanged)43 libc_hidden_def (__file_is_unchanged)
44
45 void
46 __file_change_detection_for_stat (struct file_change_detection *file,
47 const struct __stat64_t64 *st)
48 {
49 if (S_ISDIR (st->st_mode))
50 /* Treat as empty file. */
51 file->size = 0;
52 else if (!S_ISREG (st->st_mode))
53 /* Non-regular files cannot be cached. */
54 file->size = -1;
55 else
56 {
57 file->size = st->st_size;
58 file->ino = st->st_ino;
59 file->mtime = (struct __timespec64) { st->st_mtim.tv_sec,
60 st->st_mtim.tv_nsec };
61 file->ctime = (struct __timespec64) { st->st_ctim.tv_sec,
62 st->st_ctim.tv_nsec };
63 }
64 }
libc_hidden_def(__file_change_detection_for_stat)65 libc_hidden_def (__file_change_detection_for_stat)
66
67 bool
68 __file_change_detection_for_path (struct file_change_detection *file,
69 const char *path)
70 {
71 struct __stat64_t64 st;
72 if (__stat64_time64 (path, &st) != 0)
73 switch (errno)
74 {
75 case EACCES:
76 case EISDIR:
77 case ELOOP:
78 case ENOENT:
79 case ENOTDIR:
80 case EPERM:
81 /* Ignore errors due to file system contents. Instead, treat
82 the file as empty. */
83 file->size = 0;
84 return true;
85 default:
86 /* Other errors are fatal. */
87 return false;
88 }
89 else /* stat64 was successfull. */
90 {
91 __file_change_detection_for_stat (file, &st);
92 return true;
93 }
94 }
libc_hidden_def(__file_change_detection_for_path)95 libc_hidden_def (__file_change_detection_for_path)
96
97 bool
98 __file_change_detection_for_fp (struct file_change_detection *file,
99 FILE *fp)
100 {
101 if (fp == NULL)
102 {
103 /* The file does not exist. */
104 file->size = 0;
105 return true;
106 }
107 else
108 {
109 struct __stat64_t64 st;
110 if (__fstat64_time64 (__fileno (fp), &st) != 0)
111 /* If we already have a file descriptor, all errors are fatal. */
112 return false;
113 else
114 {
115 __file_change_detection_for_stat (file, &st);
116 return true;
117 }
118 }
119 }
120 libc_hidden_def (__file_change_detection_for_fp)
121