]> git.ipfire.org Git - thirdparty/glibc.git/blame - include/file_change_detection.h
<fd_to_filename.h>: Add type safety and port to Hurd
[thirdparty/glibc.git] / include / file_change_detection.h
CommitLineData
6c80c6e8
FW
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 <errno.h>
20#include <stdbool.h>
21#include <stddef.h>
22#include <stdio.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25
26/* Items for identifying a particular file version. Excerpt from
27 struct stat64. */
28struct file_change_detection
29{
30 /* Special values: 0 if file does not exist. -1 to force mismatch
31 with the next comparison. */
32 off64_t size;
33
34 ino64_t ino;
35 struct timespec mtime;
36 struct timespec ctime;
37};
38
39/* Returns true if *LEFT and *RIGHT describe the same version of the
40 same file. */
41static bool __attribute__ ((unused))
42file_is_unchanged (const struct file_change_detection *left,
43 const struct file_change_detection *right)
44{
45 if (left->size < 0 || right->size < 0)
46 /* Negative sizes are used as markers and never match. */
47 return false;
48 else if (left->size == 0 && right->size == 0)
49 /* Both files are empty or do not exist, so they have the same
50 content, no matter what the other fields indicate. */
51 return true;
52 else
53 return left->size == right->size
54 && left->ino == right->ino
55 && left->mtime.tv_sec == right->mtime.tv_sec
56 && left->mtime.tv_nsec == right->mtime.tv_nsec
57 && left->ctime.tv_sec == right->ctime.tv_sec
58 && left->ctime.tv_nsec == right->ctime.tv_nsec;
59}
60
61/* Extract file change information to *FILE from the stat buffer
62 *ST. */
63static void __attribute__ ((unused))
64file_change_detection_for_stat (struct file_change_detection *file,
65 const struct stat64 *st)
66{
67 if (S_ISDIR (st->st_mode))
68 /* Treat as empty file. */
69 file->size = 0;
70 else if (!S_ISREG (st->st_mode))
71 /* Non-regular files cannot be cached. */
72 file->size = -1;
73 else
74 {
75 file->size = st->st_size;
76 file->ino = st->st_ino;
77 file->mtime = st->st_mtim;
78 file->ctime = st->st_ctim;
79 }
80}
81
82/* Writes file change information for PATH to *FILE. Returns true on
83 success. For benign errors, *FILE is cleared, and true is
84 returned. For errors indicating resource outages and the like,
85 false is returned. */
86static bool __attribute__ ((unused))
87file_change_detection_for_path (struct file_change_detection *file,
88 const char *path)
89{
90 struct stat64 st;
91 if (stat64 (path, &st) != 0)
92 switch (errno)
93 {
94 case EACCES:
95 case EISDIR:
96 case ELOOP:
97 case ENOENT:
98 case ENOTDIR:
99 case EPERM:
100 /* Ignore errors due to file system contents. Instead, treat
101 the file as empty. */
102 file->size = 0;
103 return true;
104 default:
105 /* Other errors are fatal. */
106 return false;
107 }
108 else /* stat64 was successfull. */
109 {
110 file_change_detection_for_stat (file, &st);
111 return true;
112 }
113}
114
115/* Writes file change information for the stream FP to *FILE. Returns
116 ture on success, false on failure. If FP is NULL, treat the file
117 as non-existing. */
118static bool __attribute__ ((unused))
119file_change_detection_for_fp (struct file_change_detection *file,
120 FILE *fp)
121{
122 if (fp == NULL)
123 {
124 /* The file does not exist. */
125 file->size = 0;
126 return true;
127 }
128 else
129 {
130 struct stat64 st;
131 if (fstat64 (__fileno (fp), &st) != 0)
132 /* If we already have a file descriptor, all errors are fatal. */
133 return false;
134 else
135 {
136 file_change_detection_for_stat (file, &st);
137 return true;
138 }
139 }
140}