@@ -341,7 +341,9 @@ static int outfile = -1;
341
341
static bool limited_faking = false;
342
342
static long callcounter = 0 ;
343
343
344
- static long long ft_keep_before_nsec_since_epoch = -1 ;
344
+ static bool ft_taper = 0 ;
345
+ static long long ft_taper_begin_nsec_since_epoch = -1 ;
346
+ static long long ft_taper_end_nsec_since_epoch = -1 ;
345
347
346
348
static long ft_start_after_secs = -1 ;
347
349
static long ft_stop_after_secs = -1 ;
@@ -1159,6 +1161,133 @@ int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct
1159
1161
}
1160
1162
#endif
1161
1163
1164
+ static long long faketime_offset () {
1165
+ return ((long long )user_offset .tv_sec ) * 1000000000 + (long long )user_offset .tv_nsec ;
1166
+ }
1167
+
1168
+ // (a * b + c) / d, but do something to avoid multiplication overflow
1169
+ // (only "mostly" prevents overflow, not if the values are already
1170
+ // over 2^62)
1171
+ //
1172
+ // precondition: a < d, r < d (b is not constrained)
1173
+ static long long mad_div_avoid_overflow_inner (long long a , long long b , long long c , long long d )
1174
+ {
1175
+ if (a <= 1 || b <= 1 ) {
1176
+ return (a * b + c ) / d ;
1177
+ }
1178
+ // how many multiples of [a] we need to make a full [d]
1179
+ long long k = (d + a - 1 ) / a ; // 2 <= k <= d/2+1
1180
+ long long rem_per_f = a * k - d ;
1181
+ // how many occurrences of [a*k] (and therefore [d]) we can
1182
+ // easily take from [a*b]
1183
+ long long f = b / k ;
1184
+ // remaining: rem_per_f * f + (b % k) * a + c
1185
+ long long rem = (b % k ) * a + c ;
1186
+ long long res = f + rem / d ;
1187
+ rem = rem % d ;
1188
+ return res + mad_div_avoid_overflow_inner (rem_per_f , f , rem , d );
1189
+ }
1190
+
1191
+ static long long mult_div_avoid_overflow (long long a , long long b , long long d )
1192
+ {
1193
+ long long res = a / d ;
1194
+ return res + mad_div_avoid_overflow_inner (a %d , b , 0 , d );
1195
+ }
1196
+
1197
+ static long long faketime_do_tapered_offset (long long t ) {
1198
+ if (!ft_taper ) {
1199
+ return t + faketime_offset ();
1200
+ }
1201
+ if (t <= ft_taper_begin_nsec_since_epoch ) {
1202
+ return t ;
1203
+ }
1204
+ if (t >= ft_taper_end_nsec_since_epoch ) {
1205
+ return t + faketime_offset ();
1206
+ }
1207
+ long long taper_range = ft_taper_end_nsec_since_epoch - ft_taper_begin_nsec_since_epoch ;
1208
+ long long offset_range = faketime_offset () + taper_range ;
1209
+ // [offset_range] virtual time passes over [taper_range] real time
1210
+ long long dt = t - ft_taper_begin_nsec_since_epoch ;
1211
+ // so we're looking for dt * offset_range / taper_range, doing
1212
+ long long dvt = mult_div_avoid_overflow (dt , offset_range , taper_range );
1213
+ // something complicated to avoid overflow.
1214
+ long long res = ft_taper_begin_nsec_since_epoch + dvt ;
1215
+ return res ;
1216
+ }
1217
+
1218
+ static long long faketime_undo_tapered_offset (long long t ) {
1219
+ if (!ft_taper ) {
1220
+ return t - faketime_offset ();
1221
+ }
1222
+ long long ft_reverse_taper_begin_nsec_since_epoch = ft_taper_begin_nsec_since_epoch ;
1223
+ long long ft_reverse_taper_end_nsec_since_epoch = ft_taper_end_nsec_since_epoch + faketime_offset ();
1224
+ if (t <= ft_reverse_taper_begin_nsec_since_epoch ) {
1225
+ return t ;
1226
+ }
1227
+ if (t >= ft_reverse_taper_end_nsec_since_epoch ) {
1228
+ return t - faketime_offset ();
1229
+ }
1230
+ long long taper_range = ft_reverse_taper_end_nsec_since_epoch - ft_reverse_taper_begin_nsec_since_epoch ;
1231
+ long long offset_range = taper_range - faketime_offset ();
1232
+ // [offset_range] virtual time passes over [taper_range] real time
1233
+ long long dt = t - ft_reverse_taper_begin_nsec_since_epoch ;
1234
+ // so we're looking for dt * offset_range / taper_range, doing
1235
+ long long dvt = mult_div_avoid_overflow (dt , offset_range , taper_range );
1236
+ // something complicated to avoid overflow.
1237
+ long long res = ft_reverse_taper_begin_nsec_since_epoch + dvt ;
1238
+ return res ;
1239
+ }
1240
+
1241
+ void faketime_div_mod (long long ns , long long d , long long * res , long long * rem ) {
1242
+ * res = ns / d ;
1243
+ * rem = ns % d ;
1244
+ if (* rem < 0 ) {
1245
+ (* rem ) += d ;
1246
+ (* res )-- ;
1247
+ }
1248
+ }
1249
+
1250
+ struct timeval faketime_undo_tapered_offset_timeval (struct timeval t ) {
1251
+ long long nsec = ((long long )t .tv_sec ) * 1000000000 + ((long long )t .tv_usec ) * 1000 ;
1252
+ nsec = faketime_undo_tapered_offset (nsec );
1253
+ long long sec ;
1254
+ long long nsec_rem ;
1255
+ faketime_div_mod (nsec , 1000000000 , & sec , & nsec_rem );
1256
+ t .tv_sec = sec ;
1257
+ t .tv_usec = nsec_rem / 1000 ;
1258
+ return t ;
1259
+ }
1260
+
1261
+ struct timespec faketime_undo_tapered_offset_timespec (struct timespec t ) {
1262
+ long long nsec = ((long long )t .tv_sec ) * 1000000000 + ((long long )t .tv_nsec );
1263
+ nsec = faketime_undo_tapered_offset (nsec );
1264
+ long long sec ;
1265
+ long long nsec_rem ;
1266
+ faketime_div_mod (nsec , 1000000000 , & sec , & nsec_rem );
1267
+ t .tv_sec = sec ;
1268
+ t .tv_nsec = nsec_rem ;
1269
+ return t ;
1270
+ }
1271
+
1272
+
1273
+ struct timespec faketime_do_tapered_offset_timespec (struct timespec t ) {
1274
+ long long nsec = ((long long )t .tv_sec ) * 1000000000 + ((long long )t .tv_nsec );
1275
+ nsec = faketime_do_tapered_offset (nsec );
1276
+ long long sec ;
1277
+ long long nsec_rem ;
1278
+ faketime_div_mod (nsec , 1000000000 , & sec , & nsec_rem );
1279
+ t .tv_sec = sec ;
1280
+ t .tv_nsec = nsec_rem ;
1281
+ return t ;
1282
+ }
1283
+
1284
+
1285
+ int faketime_undo_tapered_offset_sec (int t ) {
1286
+ long long nsec = ((long long )t ) * 1000000000 ;
1287
+ nsec = faketime_undo_tapered_offset (nsec );
1288
+ return nsec / 1000000000 ;
1289
+ }
1290
+
1162
1291
#ifdef FAKE_FILE_TIMESTAMPS
1163
1292
#ifdef MACOS_DYLD_INTERPOSE
1164
1293
int macos_utime (const char * filename , const struct utimbuf * times )
@@ -1184,17 +1313,9 @@ int utime(const char *filename, const struct utimbuf *times)
1184
1313
ntbuf .actime = times -> actime - user_offset .tv_sec ;
1185
1314
ntbuf .modtime = times -> modtime - user_offset .tv_sec ;
1186
1315
1187
- long long ac_nsec = ((long long )ntbuf .actime ) * 1000000000 ;
1188
- long long mod_nsec = ((long long )ntbuf .modtime ) * 1000000000 ;
1189
- if (ft_keep_before_nsec_since_epoch != -1 &&
1190
- ac_nsec < ft_keep_before_nsec_since_epoch )
1191
- {
1192
- ntbuf .actime = times -> actime ;
1193
- }
1194
- if (ft_keep_before_nsec_since_epoch != -1 &&
1195
- mod_nsec < ft_keep_before_nsec_since_epoch )
1196
- {
1197
- ntbuf .modtime = times -> modtime ;
1316
+ if (ft_taper ) {
1317
+ ntbuf .actime = faketime_undo_tapered_offset_sec (times -> actime );
1318
+ ntbuf .modtime = faketime_undo_tapered_offset_sec (times -> modtime );
1198
1319
}
1199
1320
1200
1321
times = & ntbuf ;
@@ -1234,17 +1355,9 @@ int utimes(const char *filename, const struct timeval times[2])
1234
1355
user_offset2 .tv_usec = user_offset .tv_nsec / 1000 ;
1235
1356
timersub (& times [0 ], & user_offset2 , & tn [0 ]);
1236
1357
timersub (& times [1 ], & user_offset2 , & tn [1 ]);
1237
- long long tn0_nsec = timernsec (& tn [0 ], u );
1238
- long long tn1_nsec = timernsec (& tn [1 ], u );
1239
- if (ft_keep_before_nsec_since_epoch != -1 &&
1240
- tn0_nsec < ft_keep_before_nsec_since_epoch )
1241
- {
1242
- tn [0 ] = times [0 ];
1243
- }
1244
- if (ft_keep_before_nsec_since_epoch != -1 &&
1245
- tn1_nsec < ft_keep_before_nsec_since_epoch )
1246
- {
1247
- tn [1 ] = times [1 ];
1358
+ if (ft_taper ) {
1359
+ tn [0 ] = faketime_undo_tapered_offset_timeval (times [0 ]);
1360
+ tn [1 ] = faketime_undo_tapered_offset_timeval (times [1 ]);
1248
1361
}
1249
1362
times = tn ;
1250
1363
}
@@ -1290,12 +1403,10 @@ static void fake_two_timespec(const struct timespec in_times[2], struct timespec
1290
1403
else
1291
1404
{
1292
1405
timersub2 (& in_times [j ], & user_offset , & out_times [j ], n );
1293
- long long out_nsec = timernsec (& out_times [j ], n );
1294
- if (ft_keep_before_nsec_since_epoch != -1 &&
1295
- out_nsec < ft_keep_before_nsec_since_epoch )
1296
- {
1297
- out_times [j ] = in_times [j ];
1406
+ if (ft_taper ) {
1407
+ out_times [j ] = faketime_undo_tapered_offset_timespec (in_times [j ]);
1298
1408
}
1409
+
1299
1410
}
1300
1411
}
1301
1412
}
@@ -2932,9 +3043,22 @@ static void ftpl_really_init(void)
2932
3043
}
2933
3044
}
2934
3045
2935
- if ((tmp_env = getenv ("FAKETIME_KEEP_BEFORE_NSEC_SINCE_EPOCH " )) != NULL )
3046
+ if ((tmp_env = getenv ("FAKETIME_TAPER_BEGIN_NSEC_SINCE_EPOCH " )) != NULL )
2936
3047
{
2937
- ft_keep_before_nsec_since_epoch = atoll (tmp_env );
3048
+ ft_taper_begin_nsec_since_epoch = atoll (tmp_env );
3049
+ if (!ft_taper ) {
3050
+ ft_taper = true;
3051
+ ft_taper_end_nsec_since_epoch = ft_taper_begin_nsec_since_epoch ;
3052
+ }
3053
+ limited_faking = true;
3054
+ }
3055
+ if ((tmp_env = getenv ("FAKETIME_TAPER_END_NSEC_SINCE_EPOCH" )) != NULL )
3056
+ {
3057
+ ft_taper_end_nsec_since_epoch = atoll (tmp_env );
3058
+ if (!ft_taper ) {
3059
+ ft_taper = true;
3060
+ ft_taper_begin_nsec_since_epoch = ft_taper_end_nsec_since_epoch ;
3061
+ }
2938
3062
limited_faking = true;
2939
3063
}
2940
3064
if ((tmp_env = getenv ("FAKETIME_START_AFTER_SECONDS" )) != NULL )
@@ -3262,15 +3386,6 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
3262
3386
}
3263
3387
if (limited_faking )
3264
3388
{
3265
- if (ft_keep_before_nsec_since_epoch != -1 )
3266
- {
3267
- long long tp_nsec = ((long long )tp -> tv_sec ) * 1000000000 + ((long long )tp -> tv_nsec );
3268
- if (tp_nsec < ft_keep_before_nsec_since_epoch )
3269
- {
3270
- ret = 0 ;
3271
- goto abort ;
3272
- }
3273
- }
3274
3389
/* Check whether we actually should be faking the returned timestamp. */
3275
3390
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
3276
3391
if (((ft_start_after_secs != -1 ) && (tmp_ts .tv_sec < ft_start_after_secs ))
@@ -3421,7 +3536,13 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
3421
3536
{
3422
3537
timeadj = tdiff ;
3423
3538
}
3424
- timespecadd (& user_faked_time_timespec , & timeadj , tp );
3539
+
3540
+ if (ft_taper ) {
3541
+ * tp = faketime_do_tapered_offset_timespec (* tp );
3542
+ }
3543
+ else {
3544
+ timespecadd (& user_faked_time_timespec , & timeadj , tp );
3545
+ }
3425
3546
}
3426
3547
break ;
3427
3548
0 commit comments