1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7 /* This file is ALSO:
8 * Copyright 2001-2004 David Abrahams.
9 * Copyright 2020 Nikita Kniazev.
10 * Distributed under the Boost Software License, Version 1.0.
11 * (See accompanying file LICENSE_1_0.txt or
12 * http://www.boost.org/LICENSE_1_0.txt)
13 */
14
15 /*
16 * timestamp.c - get the timestamp of a file or archive member
17 *
18 * External routines:
19 * timestamp_from_path() - return timestamp for a path, if present
20 * timestamp_done() - free timestamp tables
21 *
22 * Internal routines:
23 * free_timestamps() - worker function for freeing timestamp table contents
24 */
25
26 #include "jam.h"
27 #include "timestamp.h"
28
29 #include "filesys.h"
30 #include "hash.h"
31 #include "object.h"
32 #include "pathsys.h"
33 #include "jam_strings.h"
34 #include "output.h"
35
36
37 /*
38 * BINDING - all known files
39 */
40
41 typedef struct _binding
42 {
43 OBJECT * name;
44 short flags;
45
46 #define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
47
48 short progress;
49
50 #define BIND_INIT 0 /* never seen */
51 #define BIND_NOENTRY 1 /* timestamp requested but file never found */
52 #define BIND_SPOTTED 2 /* file found but not timed yet */
53 #define BIND_MISSING 3 /* file found but can not get timestamp */
54 #define BIND_FOUND 4 /* file found and time stamped */
55
56 /* update time - cleared if the there is nothing to bind */
57 timestamp time;
58 } BINDING;
59
60 static struct hash * bindhash = 0;
61
62
63 #ifdef OS_NT
64 /*
65 * timestamp_from_filetime() - Windows FILETIME --> timestamp conversion
66 *
67 * Lifted shamelessly from the CPython implementation.
68 */
69
timestamp_from_filetime(timestamp * const t,FILETIME const * const ft)70 void timestamp_from_filetime( timestamp * const t, FILETIME const * const ft )
71 {
72 /* Seconds between 1.1.1601 and 1.1.1970 */
73 static __int64 const secs_between_epochs = 11644473600;
74
75 /* We can not simply cast and dereference a FILETIME, since it might not be
76 * aligned properly. __int64 type variables are expected to be aligned to an
77 * 8 byte boundary while FILETIME structures may be aligned to any 4 byte
78 * boundary. Using an incorrectly aligned __int64 variable may cause a
79 * performance penalty on some platforms or even exceptions on others
80 * (documented on MSDN).
81 */
82 __int64 in;
83 memcpy( &in, ft, sizeof( in ) );
84
85 /* FILETIME resolution: 100ns. */
86 timestamp_init( t, (time_t)( ( in / 10000000 ) - secs_between_epochs ),
87 (int)( in % 10000000 ) * 100 );
88 }
89 #endif /* OS_NT */
90
91
timestamp_clear(timestamp * const time)92 void timestamp_clear( timestamp * const time )
93 {
94 time->secs = time->nsecs = 0;
95 }
96
97
timestamp_cmp(timestamp const * const lhs,timestamp const * const rhs)98 int timestamp_cmp( timestamp const * const lhs, timestamp const * const rhs )
99 {
100 return int(
101 lhs->secs == rhs->secs
102 ? lhs->nsecs - rhs->nsecs
103 : lhs->secs - rhs->secs );
104 }
105
106
timestamp_copy(timestamp * const target,timestamp const * const source)107 void timestamp_copy( timestamp * const target, timestamp const * const source )
108 {
109 target->secs = source->secs;
110 target->nsecs = source->nsecs;
111 }
112
113
timestamp_current(timestamp * const t)114 void timestamp_current( timestamp * const t )
115 {
116 #ifdef OS_NT
117 /* GetSystemTimeAsFileTime()'s resolution seems to be about 15 ms on Windows
118 * XP and under a millisecond on Windows 7.
119 */
120 FILETIME ft;
121 GetSystemTimeAsFileTime( &ft );
122 timestamp_from_filetime( t, &ft );
123 #elif defined(_POSIX_TIMERS) && defined(CLOCK_REALTIME) && \
124 (!defined(__GLIBC__) || (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))
125 /* Some older versions of XCode define _POSIX_TIMERS, but don't actually
126 * have clock_gettime. Check CLOCK_REALTIME as well. Prior to glibc 2.17,
127 * clock_gettime requires -lrt. This is a non-critical feature, so
128 * we just disable it to keep bootstrapping simple.
129 */
130 struct timespec ts;
131 clock_gettime( CLOCK_REALTIME, &ts );
132 timestamp_init( t, ts.tv_sec, ts.tv_nsec );
133 #else /* OS_NT */
134 timestamp_init( t, time( 0 ), 0 );
135 #endif /* OS_NT */
136 }
137
138
timestamp_empty(timestamp const * const time)139 int timestamp_empty( timestamp const * const time )
140 {
141 return !time->secs && !time->nsecs;
142 }
143
144
145 /*
146 * timestamp_from_path() - return timestamp for a path, if present
147 */
148
timestamp_from_path(timestamp * const time,OBJECT * const path)149 void timestamp_from_path( timestamp * const time, OBJECT * const path )
150 {
151 PROFILE_ENTER( timestamp );
152
153 if ( file_time( path, time ) < 0 )
154 timestamp_clear( time );
155
156 PROFILE_EXIT( timestamp );
157 }
158
159
timestamp_init(timestamp * const time,time_t const secs,int const nsecs)160 void timestamp_init( timestamp * const time, time_t const secs, int const nsecs
161 )
162 {
163 time->secs = secs;
164 time->nsecs = nsecs;
165 }
166
167
timestamp_max(timestamp * const max,timestamp const * const lhs,timestamp const * const rhs)168 void timestamp_max( timestamp * const max, timestamp const * const lhs,
169 timestamp const * const rhs )
170 {
171 if ( timestamp_cmp( lhs, rhs ) > 0 )
172 timestamp_copy( max, lhs );
173 else
174 timestamp_copy( max, rhs );
175 }
176
177
timestamp_formatstr(timestamp const * const time,char const * const format)178 static char const * timestamp_formatstr( timestamp const * const time,
179 char const * const format )
180 {
181 static char result1[ 500 ];
182 static char result2[ 500 ];
183 strftime( result1, sizeof( result1 ) / sizeof( *result1 ), format, gmtime(
184 &time->secs ) );
185 sprintf( result2, result1, time->nsecs );
186 return result2;
187 }
188
189
timestamp_str(timestamp const * const time)190 char const * timestamp_str( timestamp const * const time )
191 {
192 return timestamp_formatstr( time, "%Y-%m-%d %H:%M:%S.%%09d +0000" );
193 }
194
195
timestamp_timestr(timestamp const * const time)196 char const * timestamp_timestr( timestamp const * const time )
197 {
198 return timestamp_formatstr( time, "%H:%M:%S.%%09d" );
199 }
200
201
202 /*
203 * free_timestamps() - worker function for freeing timestamp table contents
204 */
205
free_timestamps(void * xbinding,void * data)206 static void free_timestamps( void * xbinding, void * data )
207 {
208 object_free( ( (BINDING *)xbinding )->name );
209 }
210
211
212 /*
213 * timestamp_done() - free timestamp tables
214 */
215
timestamp_done()216 void timestamp_done()
217 {
218 if ( bindhash )
219 {
220 hashenumerate( bindhash, free_timestamps, 0 );
221 hashdone( bindhash );
222 }
223 }
224
225 /*
226 * timestamp_delta_seconds() - seconds from time a to b.
227 */
timestamp_delta_seconds(timestamp const * const a,timestamp const * const b)228 double timestamp_delta_seconds( timestamp const * const a , timestamp const * const b )
229 {
230 return difftime(b->secs, a->secs) + (b->nsecs - a->nsecs) * 1.0E-9;
231 }
232