• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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