Mercurial > hg > octave-kai > gnulib-hg
annotate lib/utimecmp.c @ 11639:b2e769838448
hash: fix memory leak in last patch
* lib/hash.c (hash_rehash): Avoid memory leak.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Thu, 18 Jun 2009 15:24:38 -0600 |
parents | bbbbbf4cd1c5 |
children | 0ae159ba1adf |
rev | line source |
---|---|
5148 | 1 /* utimecmp.c -- compare file time stamps |
2 | |
8223
ca249819379f
* lib/getdate.h (includes): Include <time.h>, not "timespec.h".
Eric Blake <ebb9@byu.net>
parents:
7406
diff
changeset
|
3 Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. |
5148 | 4 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8223
diff
changeset
|
5 This program is free software: you can redistribute it and/or modify |
5148 | 6 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8223
diff
changeset
|
7 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8223
diff
changeset
|
8 (at your option) any later version. |
5148 | 9 |
10 This program 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 | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8223
diff
changeset
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
5148 | 17 |
18 /* Written by Paul Eggert. */ | |
19 | |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
7162
diff
changeset
|
20 #include <config.h> |
5148 | 21 |
22 #include "utimecmp.h" | |
23 | |
24 #include <limits.h> | |
25 #include <stdbool.h> | |
7162
19c2e5121b2f
Add and change modules to make it easier for coreutils to use
Paul Eggert <eggert@cs.ucla.edu>
parents:
6323
diff
changeset
|
26 #include <stdint.h> |
5148 | 27 #include <stdlib.h> |
8223
ca249819379f
* lib/getdate.h (includes): Include <time.h>, not "timespec.h".
Eric Blake <ebb9@byu.net>
parents:
7406
diff
changeset
|
28 #include <time.h> |
5148 | 29 #include "hash.h" |
5691
ec62790f0938
Factor int-properties macros into a single file, except for
Paul Eggert <eggert@cs.ucla.edu>
parents:
5148
diff
changeset
|
30 #include "intprops.h" |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
31 #include "stat-time.h" |
5148 | 32 #include "utimens.h" |
6323
af09cfa36fd5
* modules/exclude (Depends-on): Depend on verify.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6259
diff
changeset
|
33 #include "verify.h" |
5148 | 34 #include "xalloc.h" |
35 | |
36 #ifndef MAX | |
37 # define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
38 #endif | |
39 | |
40 enum { BILLION = 1000 * 1000 * 1000 }; | |
41 | |
42 /* Best possible resolution that utimens can set and stat can return, | |
43 due to system-call limitations. It must be a power of 10 that is | |
44 no greater than 1 billion. */ | |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
45 #if (HAVE_WORKING_UTIMES \ |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
46 && (defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC \ |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
47 || defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC \ |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
48 || defined HAVE_STRUCT_STAT_ST_ATIMENSEC \ |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
49 || defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC \ |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
50 || defined HAVE_STRUCT_STAT_ST_SPARE1)) |
5148 | 51 enum { SYSCALL_RESOLUTION = 1000 }; |
52 #else | |
53 enum { SYSCALL_RESOLUTION = BILLION }; | |
54 #endif | |
55 | |
56 /* Describe a file system and its time stamp resolution in nanoseconds. */ | |
57 struct fs_res | |
58 { | |
59 /* Device number of file system. */ | |
60 dev_t dev; | |
61 | |
62 /* An upper bound on the time stamp resolution of this file system, | |
63 ignoring any resolution that cannot be set via utimens. It is | |
64 represented by an integer count of nanoseconds. It must be | |
65 either 2 billion, or a power of 10 that is no greater than a | |
66 billion and is no less than SYSCALL_RESOLUTION. */ | |
67 int resolution; | |
68 | |
69 /* True if RESOLUTION is known to be exact, and is not merely an | |
70 upper bound on the true resolution. */ | |
71 bool exact; | |
72 }; | |
73 | |
74 /* Hash some device info. */ | |
75 static size_t | |
76 dev_info_hash (void const *x, size_t table_size) | |
77 { | |
78 struct fs_res const *p = x; | |
79 | |
80 /* Beware signed arithmetic gotchas. */ | |
81 if (TYPE_SIGNED (dev_t) && SIZE_MAX < MAX (INT_MAX, TYPE_MAXIMUM (dev_t))) | |
82 { | |
83 uintmax_t dev = p->dev; | |
84 return dev % table_size; | |
85 } | |
86 | |
87 return p->dev % table_size; | |
88 } | |
89 | |
90 /* Compare two dev_info structs. */ | |
91 static bool | |
92 dev_info_compare (void const *x, void const *y) | |
93 { | |
94 struct fs_res const *a = x; | |
95 struct fs_res const *b = y; | |
96 return a->dev == b->dev; | |
97 } | |
98 | |
99 /* Return -1, 0, 1 based on whether the destination file (with name | |
100 DST_NAME and status DST_STAT) is older than SRC_STAT, the same age | |
101 as SRC_STAT, or newer than SRC_STAT, respectively. | |
102 | |
103 If OPTIONS & UTIMECMP_TRUNCATE_SOURCE, do the comparison after SRC is | |
104 converted to the destination's timestamp resolution as filtered through | |
105 utimens. In this case, return -2 if the exact answer cannot be | |
106 determined; this can happen only if the time stamps are very close and | |
107 there is some trouble accessing the file system (e.g., the user does not | |
108 have permission to futz with the destination's time stamps). */ | |
109 | |
110 int | |
111 utimecmp (char const *dst_name, | |
112 struct stat const *dst_stat, | |
113 struct stat const *src_stat, | |
114 int options) | |
115 { | |
116 /* Things to watch out for: | |
117 | |
118 The code uses a static hash table internally and is not safe in the | |
119 presence of signals, multiple threads, etc. | |
120 | |
121 int and long int might be 32 bits. Many of the calculations store | |
122 numbers up to 2 billion, and multiply by 10; they have to avoid | |
123 multiplying 2 billion by 10, as this exceeds 32-bit capabilities. | |
124 | |
125 time_t might be unsigned. */ | |
126 | |
6323
af09cfa36fd5
* modules/exclude (Depends-on): Depend on verify.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6259
diff
changeset
|
127 verify (TYPE_IS_INTEGER (time_t)); |
af09cfa36fd5
* modules/exclude (Depends-on): Depend on verify.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6259
diff
changeset
|
128 verify (TYPE_TWOS_COMPLEMENT (int)); |
5148 | 129 |
130 /* Destination and source time stamps. */ | |
131 time_t dst_s = dst_stat->st_mtime; | |
132 time_t src_s = src_stat->st_mtime; | |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
133 int dst_ns = get_stat_mtime_ns (dst_stat); |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
134 int src_ns = get_stat_mtime_ns (src_stat); |
5148 | 135 |
136 if (options & UTIMECMP_TRUNCATE_SOURCE) | |
137 { | |
138 /* Look up the time stamp resolution for the destination device. */ | |
139 | |
140 /* Hash table for devices. */ | |
141 static Hash_table *ht; | |
142 | |
143 /* Information about the destination file system. */ | |
144 static struct fs_res *new_dst_res; | |
145 struct fs_res *dst_res; | |
146 | |
147 /* Time stamp resolution in nanoseconds. */ | |
148 int res; | |
149 | |
150 if (! ht) | |
151 ht = hash_initialize (16, NULL, dev_info_hash, dev_info_compare, free); | |
152 if (! new_dst_res) | |
153 { | |
154 new_dst_res = xmalloc (sizeof *new_dst_res); | |
155 new_dst_res->resolution = 2 * BILLION; | |
156 new_dst_res->exact = false; | |
157 } | |
158 new_dst_res->dev = dst_stat->st_dev; | |
159 dst_res = hash_insert (ht, new_dst_res); | |
160 if (! dst_res) | |
161 xalloc_die (); | |
162 | |
163 if (dst_res == new_dst_res) | |
164 { | |
165 /* NEW_DST_RES is now in use in the hash table, so allocate a | |
166 new entry next time. */ | |
167 new_dst_res = NULL; | |
168 } | |
169 | |
170 res = dst_res->resolution; | |
171 | |
172 if (! dst_res->exact) | |
173 { | |
174 /* This file system's resolution is not known exactly. | |
175 Deduce it, and store the result in the hash table. */ | |
176 | |
177 time_t dst_a_s = dst_stat->st_atime; | |
178 time_t dst_c_s = dst_stat->st_ctime; | |
179 time_t dst_m_s = dst_s; | |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
180 int dst_a_ns = get_stat_atime_ns (dst_stat); |
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
181 int dst_c_ns = get_stat_ctime_ns (dst_stat); |
5148 | 182 int dst_m_ns = dst_ns; |
183 | |
184 /* Set RES to an upper bound on the file system resolution | |
185 (after truncation due to SYSCALL_RESOLUTION) by inspecting | |
186 the atime, ctime and mtime of the existing destination. | |
187 We don't know of any file system that stores atime or | |
188 ctime with a higher precision than mtime, so it's valid to | |
189 look at them too. */ | |
190 { | |
191 bool odd_second = (dst_a_s | dst_c_s | dst_m_s) & 1; | |
192 | |
193 if (SYSCALL_RESOLUTION == BILLION) | |
194 { | |
195 if (odd_second | dst_a_ns | dst_c_ns | dst_m_ns) | |
196 res = BILLION; | |
197 } | |
198 else | |
199 { | |
200 int a = dst_a_ns; | |
201 int c = dst_c_ns; | |
202 int m = dst_m_ns; | |
203 | |
204 /* Write it this way to avoid mistaken GCC warning | |
205 about integer overflow in constant expression. */ | |
206 int SR10 = SYSCALL_RESOLUTION; SR10 *= 10; | |
207 | |
208 if ((a % SR10 | c % SR10 | m % SR10) != 0) | |
209 res = SYSCALL_RESOLUTION; | |
210 else | |
211 for (res = SR10, a /= SR10, c /= SR10, m /= SR10; | |
212 (res < dst_res->resolution | |
213 && (a % 10 | c % 10 | m % 10) == 0); | |
214 res *= 10, a /= 10, c /= 10, m /= 10) | |
215 if (res == BILLION) | |
216 { | |
217 if (! odd_second) | |
218 res *= 2; | |
219 break; | |
220 } | |
221 } | |
222 | |
223 dst_res->resolution = res; | |
224 } | |
225 | |
226 if (SYSCALL_RESOLUTION < res) | |
227 { | |
228 struct timespec timespec[2]; | |
229 struct stat dst_status; | |
230 | |
231 /* Ignore source time stamp information that must necessarily | |
232 be lost when filtered through utimens. */ | |
233 src_ns -= src_ns % SYSCALL_RESOLUTION; | |
234 | |
235 /* If the time stamps disagree widely enough, there's no need | |
236 to interrogate the file system to deduce the exact time | |
237 stamp resolution; return the answer directly. */ | |
238 { | |
239 time_t s = src_s & ~ (res == 2 * BILLION); | |
240 if (src_s < dst_s || (src_s == dst_s && src_ns <= dst_ns)) | |
241 return 1; | |
242 if (dst_s < s | |
243 || (dst_s == s && dst_ns < src_ns - src_ns % res)) | |
244 return -1; | |
245 } | |
246 | |
247 /* Determine the actual time stamp resolution for the | |
248 destination file system (after truncation due to | |
249 SYSCALL_RESOLUTION) by setting the access time stamp of the | |
250 destination to the existing access time, except with | |
251 trailing nonzero digits. */ | |
252 | |
253 timespec[0].tv_sec = dst_a_s; | |
254 timespec[0].tv_nsec = dst_a_ns; | |
255 timespec[1].tv_sec = dst_m_s | (res == 2 * BILLION); | |
256 timespec[1].tv_nsec = dst_m_ns + res / 9; | |
257 | |
258 /* Set the modification time. But don't try to set the | |
259 modification time of symbolic links; on many hosts this sets | |
260 the time of the pointed-to file. */ | |
261 if (S_ISLNK (dst_stat->st_mode) | |
262 || utimens (dst_name, timespec) != 0) | |
263 return -2; | |
264 | |
265 /* Read the modification time that was set. It's safe to call | |
266 'stat' here instead of worrying about 'lstat'; either the | |
267 caller used 'stat', or the caller used 'lstat' and found | |
268 something other than a symbolic link. */ | |
269 { | |
270 int stat_result = stat (dst_name, &dst_status); | |
271 | |
272 if (stat_result | |
273 | (dst_status.st_mtime ^ dst_m_s) | |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
274 | (get_stat_mtime_ns (&dst_status) ^ dst_m_ns)) |
5148 | 275 { |
276 /* The modification time changed, or we can't tell whether | |
277 it changed. Change it back as best we can. */ | |
278 timespec[1].tv_sec = dst_m_s; | |
279 timespec[1].tv_nsec = dst_m_ns; | |
280 utimens (dst_name, timespec); | |
281 } | |
282 | |
283 if (stat_result != 0) | |
284 return -2; | |
285 } | |
286 | |
287 /* Determine the exact resolution from the modification time | |
288 that was read back. */ | |
289 { | |
290 int old_res = res; | |
291 int a = (BILLION * (dst_status.st_mtime & 1) | |
6238
245950d70306
* utimecmp.c: Include stat-time.h.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
292 + get_stat_mtime_ns (&dst_status)); |
5148 | 293 |
294 res = SYSCALL_RESOLUTION; | |
295 | |
296 for (a /= res; a % 10 != 0; a /= 10) | |
297 { | |
298 if (res == BILLION) | |
299 { | |
300 res *= 2; | |
301 break; | |
302 } | |
303 res *= 10; | |
304 if (res == old_res) | |
305 break; | |
306 } | |
307 } | |
308 } | |
309 | |
310 dst_res->resolution = res; | |
311 dst_res->exact = true; | |
312 } | |
313 | |
314 /* Truncate the source's time stamp according to the resolution. */ | |
315 src_s &= ~ (res == 2 * BILLION); | |
316 src_ns -= src_ns % res; | |
317 } | |
318 | |
319 /* Compare the time stamps and return -1, 0, 1 accordingly. */ | |
320 return (dst_s < src_s ? -1 | |
321 : dst_s > src_s ? 1 | |
322 : dst_ns < src_ns ? -1 | |
323 : dst_ns > src_ns); | |
324 } |