]> git.ipfire.org Git - thirdparty/glibc.git/blob - io/file_change_detection.c
f52d8fecfa7e01c19297ffe723960596ec66341a
[thirdparty/glibc.git] / io / file_change_detection.c
1 /* Detecting file changes using modification times.
2 Copyright (C) 2017-2020 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
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 }
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 *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 = st->st_mtim;
60 file->ctime = st->st_ctim;
61 }
62 }
63 libc_hidden_def (__file_change_detection_for_stat)
64
65 bool
66 __file_change_detection_for_path (struct file_change_detection *file,
67 const char *path)
68 {
69 struct stat64 st;
70 if (__stat64 (path, &st) != 0)
71 switch (errno)
72 {
73 case EACCES:
74 case EISDIR:
75 case ELOOP:
76 case ENOENT:
77 case ENOTDIR:
78 case EPERM:
79 /* Ignore errors due to file system contents. Instead, treat
80 the file as empty. */
81 file->size = 0;
82 return true;
83 default:
84 /* Other errors are fatal. */
85 return false;
86 }
87 else /* stat64 was successfull. */
88 {
89 __file_change_detection_for_stat (file, &st);
90 return true;
91 }
92 }
93 libc_hidden_def (__file_change_detection_for_path)
94
95 bool
96 __file_change_detection_for_fp (struct file_change_detection *file,
97 FILE *fp)
98 {
99 if (fp == NULL)
100 {
101 /* The file does not exist. */
102 file->size = 0;
103 return true;
104 }
105 else
106 {
107 struct stat64 st;
108 if (__fstat64 (__fileno (fp), &st) != 0)
109 /* If we already have a file descriptor, all errors are fatal. */
110 return false;
111 else
112 {
113 __file_change_detection_for_stat (file, &st);
114 return true;
115 }
116 }
117 }
118 libc_hidden_def (__file_change_detection_for_fp)