@@ -341,7 +341,9 @@ static int outfile = -1;
341341static bool limited_faking = false;
342342static long callcounter = 0 ;
343343
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 ;
345347
346348static long ft_start_after_secs = -1 ;
347349static long ft_stop_after_secs = -1 ;
@@ -1159,6 +1161,133 @@ int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct
11591161}
11601162#endif
11611163
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+
11621291#ifdef FAKE_FILE_TIMESTAMPS
11631292#ifdef MACOS_DYLD_INTERPOSE
11641293int macos_utime (const char * filename , const struct utimbuf * times )
@@ -1184,17 +1313,9 @@ int utime(const char *filename, const struct utimbuf *times)
11841313 ntbuf .actime = times -> actime - user_offset .tv_sec ;
11851314 ntbuf .modtime = times -> modtime - user_offset .tv_sec ;
11861315
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 );
11981319 }
11991320
12001321 times = & ntbuf ;
@@ -1234,17 +1355,9 @@ int utimes(const char *filename, const struct timeval times[2])
12341355 user_offset2 .tv_usec = user_offset .tv_nsec / 1000 ;
12351356 timersub (& times [0 ], & user_offset2 , & tn [0 ]);
12361357 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 ]);
12481361 }
12491362 times = tn ;
12501363 }
@@ -1290,12 +1403,10 @@ static void fake_two_timespec(const struct timespec in_times[2], struct timespec
12901403 else
12911404 {
12921405 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 ]);
12981408 }
1409+
12991410 }
13001411 }
13011412}
@@ -2932,9 +3043,22 @@ static void ftpl_really_init(void)
29323043 }
29333044 }
29343045
2935- if ((tmp_env = getenv ("FAKETIME_KEEP_BEFORE_NSEC_SINCE_EPOCH " )) != NULL )
3046+ if ((tmp_env = getenv ("FAKETIME_TAPER_BEGIN_NSEC_SINCE_EPOCH " )) != NULL )
29363047 {
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+ }
29383062 limited_faking = true;
29393063 }
29403064 if ((tmp_env = getenv ("FAKETIME_START_AFTER_SECONDS" )) != NULL )
@@ -3262,15 +3386,6 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
32623386 }
32633387 if (limited_faking )
32643388 {
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- }
32743389 /* Check whether we actually should be faking the returned timestamp. */
32753390 /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
32763391 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)
34213536 {
34223537 timeadj = tdiff ;
34233538 }
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+ }
34253546 }
34263547 break ;
34273548
0 commit comments