summaryrefslogtreecommitdiff
path: root/io/file_change_detection.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2020-02-18 13:44:48 +0100
committerFlorian Weimer <fweimer@redhat.com>2020-02-18 13:44:48 +0100
commit631cf64bc1d8306e011ef39f60b8cb6de91bd271 (patch)
tree719100a2b1098d6921ef74397b681de93efcfa95 /io/file_change_detection.c
parentfa185f0d4529c6d70f690306f431ca23662b9138 (diff)
downloadglibc-631cf64bc1d8306e011ef39f60b8cb6de91bd271.tar.gz
Move implementation of <file_change_detection.h> into a C file
file_change_detection_for_stat partially initialize struct file_change_detection in some cases, when the size member alone determines the outcome of all comparisons. This results in maybe-uninitialized compiler warnings in case of sufficiently aggressive inlining. Once the implementation is moved into a separate C file, this kind of inlining is no longer possible, so the compiler warnings are gone.
Diffstat (limited to 'io/file_change_detection.c')
-rw-r--r--io/file_change_detection.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/io/file_change_detection.c b/io/file_change_detection.c
new file mode 100644
index 0000000000..c6d700ed05
--- /dev/null
+++ b/io/file_change_detection.c
@@ -0,0 +1,118 @@
+/* Detecting file changes using modification times.
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <file_change_detection.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+bool
+__file_is_unchanged (const struct file_change_detection *left,
+ const struct file_change_detection *right)
+{
+ if (left->size < 0 || right->size < 0)
+ /* Negative sizes are used as markers and never match. */
+ return false;
+ else if (left->size == 0 && right->size == 0)
+ /* Both files are empty or do not exist, so they have the same
+ content, no matter what the other fields indicate. */
+ return true;
+ else
+ return left->size == right->size
+ && left->ino == right->ino
+ && left->mtime.tv_sec == right->mtime.tv_sec
+ && left->mtime.tv_nsec == right->mtime.tv_nsec
+ && left->ctime.tv_sec == right->ctime.tv_sec
+ && left->ctime.tv_nsec == right->ctime.tv_nsec;
+}
+libc_hidden_def (__file_is_unchanged)
+
+void
+__file_change_detection_for_stat (struct file_change_detection *file,
+ const struct stat64 *st)
+{
+ if (S_ISDIR (st->st_mode))
+ /* Treat as empty file. */
+ file->size = 0;
+ else if (!S_ISREG (st->st_mode))
+ /* Non-regular files cannot be cached. */
+ file->size = -1;
+ else
+ {
+ file->size = st->st_size;
+ file->ino = st->st_ino;
+ file->mtime = st->st_mtim;
+ file->ctime = st->st_ctim;
+ }
+}
+libc_hidden_def (__file_change_detection_for_stat)
+
+bool
+__file_change_detection_for_path (struct file_change_detection *file,
+ const char *path)
+{
+ struct stat64 st;
+ if (stat64 (path, &st) != 0)
+ switch (errno)
+ {
+ case EACCES:
+ case EISDIR:
+ case ELOOP:
+ case ENOENT:
+ case ENOTDIR:
+ case EPERM:
+ /* Ignore errors due to file system contents. Instead, treat
+ the file as empty. */
+ file->size = 0;
+ return true;
+ default:
+ /* Other errors are fatal. */
+ return false;
+ }
+ else /* stat64 was successfull. */
+ {
+ __file_change_detection_for_stat (file, &st);
+ return true;
+ }
+}
+libc_hidden_def (__file_change_detection_for_path)
+
+bool
+__file_change_detection_for_fp (struct file_change_detection *file,
+ FILE *fp)
+{
+ if (fp == NULL)
+ {
+ /* The file does not exist. */
+ file->size = 0;
+ return true;
+ }
+ else
+ {
+ struct stat64 st;
+ if (fstat64 (__fileno (fp), &st) != 0)
+ /* If we already have a file descriptor, all errors are fatal. */
+ return false;
+ else
+ {
+ __file_change_detection_for_stat (file, &st);
+ return true;
+ }
+ }
+}
+libc_hidden_def (__file_change_detection_for_fp)