watch this The wheels are turning, slowly turning. home
Hard time 2005-04-28

I discovered the hard way that, even with stat_float_times enabled, mtime does not have a very great resolution. About a millisecond on my machine (actually ever so slightly worse, but it seems to vary with CPU clock speed). This would be fine, if I were not relying on being able to compare times retrieved from the mtime field of file metadata and times retrieved from gettimeofday(2) with each other. Too bad for me.

What this ended up leading to was this fun sequence:

x = time.time()
y = modifyAFileAndReturnMTime()
z = time.time()

assert x <= y <= z # Woops, this fails

Woe is me. So after a few hours of figuring that it was mtime resolution that was getting me, I figured I’d just cludge it and stuff time.time() into the mtime field at the crucial moment. This works because the field itself is capable of precision down to the nanosecond level, the operating system just doesn’t keep track of it that carefully. Having replaced the actual mtime with my app’s concept of the mtime, all my times will sort correctly and I won’t accidentally toss files out the window.

So how do I do this? Well, utimes(2) of course. Heck, it’s even wrapped in Python:

>>> import os
>>> os.stat_float_times(True)
>>> os.path.getmtime('.')
1114739528.5010293
>>> os.utime('.', (1114739528.75, 1114739528.75)) # atime, mtime
>>> os.path.getmtime('.')
1114739528.0
>>> 

Ack! So much for nanosecond precision! Where the hell’d my fractional parts go? utimes(2) certainly supports this:

>>> import os
>>> os.stat_float_times(True)
>>> import dl, array, struct
>>> libc = dl.open('libc.so.6')
>>> buf = array.array('c', struct.pack('IIII', 1114739528, 750000, 1114739528, 750000))
>>> libc.call('utimes', '.', buf.buffer_info()[0])
0
>>> os.path.getmtime('.')
1114739528.75
>>> 

Okay, so Python’s screwed up :( A little digging later, I see that actually maybe it’s just Ubuntu’s build of Python. HAVE_UTIMES isn’t being defined, so all my nice double precision floating goodness is being dropped on the floor and only the integer parts carried over. Time to file a bug report…

Unfortunately, having these times be accurate is somewhat important to the application. I think maybe I can fudge it by either adding or subtracting a few seconds from each mtime (I’m not sure which yet… hopefully adding, because subtraction is hard). At worst this should mean I copy a few extra files… I hope. More thought is required.