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