Browse Source

Switch to st_mtime_ns when available

Jonas Borgström 12 years ago
parent
commit
ad08664b65
5 changed files with 27 additions and 16 deletions
  1. 6 5
      darc/archive.py
  2. 1 1
      darc/archiver.py
  3. 5 5
      darc/cache.py
  4. 9 1
      darc/helpers.py
  5. 6 4
      darc/test.py

+ 6 - 5
darc/archive.py

@@ -12,7 +12,7 @@ import xattr
 
 
 from .chunker import chunkify
 from .chunker import chunkify
 from .helpers import uid2user, user2uid, gid2group, group2gid, \
 from .helpers import uid2user, user2uid, gid2group, group2gid, \
-    Statistics, decode_dict
+    Statistics, decode_dict, st_mtime_ns
 
 
 ITEMS_BUFFER = 1024 * 1024
 ITEMS_BUFFER = 1024 * 1024
 CHUNK_MIN = 1024
 CHUNK_MIN = 1024
@@ -20,6 +20,7 @@ WINDOW_SIZE = 0xfff
 CHUNK_MASK = 0xffff
 CHUNK_MASK = 0xffff
 
 
 utime_supports_fd = os.utime in getattr(os, 'supports_fd', {})
 utime_supports_fd = os.utime in getattr(os, 'supports_fd', {})
+has_mtime_ns = sys.version >= '3.3'
 has_lchmod = hasattr(os, 'lchmod')
 has_lchmod = hasattr(os, 'lchmod')
 
 
 
 
@@ -304,11 +305,11 @@ class Archive(object):
         elif has_lchmod:  # Not available on Linux
         elif has_lchmod:  # Not available on Linux
             os.lchmod(path, item[b'mode'])
             os.lchmod(path, item[b'mode'])
         if fd and utime_supports_fd:  # Python >= 3.3
         if fd and utime_supports_fd:  # Python >= 3.3
-            os.utime(fd, (item[b'mtime'], item[b'mtime']))
+            os.utime(fd, None, ns=(item[b'mtime'], item[b'mtime']))
         elif utime_supports_fd:  # Python >= 3.3
         elif utime_supports_fd:  # Python >= 3.3
-            os.utime(path, (item[b'mtime'], item[b'mtime']), follow_symlinks=False)
+            os.utime(path, None, ns=(item[b'mtime'], item[b'mtime']), follow_symlinks=False)
         elif not symlink:
         elif not symlink:
-            os.utime(path, (item[b'mtime'], item[b'mtime']))
+            os.utime(path, (item[b'mtime'] / 10**9, item[b'mtime'] / 10**9))
 
 
     def verify_file(self, item, start, result, peek=None):
     def verify_file(self, item, start, result, peek=None):
         if not item[b'chunks']:
         if not item[b'chunks']:
@@ -347,7 +348,7 @@ class Archive(object):
             b'mode': st.st_mode,
             b'mode': st.st_mode,
             b'uid': st.st_uid, b'user': uid2user(st.st_uid),
             b'uid': st.st_uid, b'user': uid2user(st.st_uid),
             b'gid': st.st_gid, b'group': gid2group(st.st_gid),
             b'gid': st.st_gid, b'group': gid2group(st.st_gid),
-            b'mtime': st.st_mtime,
+            b'mtime': st_mtime_ns(st),
         }
         }
         if self.numeric_owner:
         if self.numeric_owner:
             item[b'user'] = item[b'group'] = None
             item[b'user'] = item[b'group'] = None

+ 1 - 1
darc/archiver.py

@@ -195,7 +195,7 @@ class Archiver(object):
                         size = sum(size for _, size, _ in item[b'chunks'])
                         size = sum(size for _, size, _ in item[b'chunks'])
                     except KeyError:
                     except KeyError:
                         pass
                         pass
-                mtime = format_time(datetime.fromtimestamp(item[b'mtime']))
+                mtime = format_time(datetime.fromtimestamp(item[b'mtime'] / 10**9))
                 if b'source' in item:
                 if b'source' in item:
                     if type == 'l':
                     if type == 'l':
                         extra = ' -> %s' % item[b'source']
                         extra = ' -> %s' % item[b'source']

+ 5 - 5
darc/cache.py

@@ -6,7 +6,7 @@ import os
 from binascii import hexlify, unhexlify
 from binascii import hexlify, unhexlify
 import shutil
 import shutil
 
 
-from .helpers import get_cache_dir, decode_dict
+from .helpers import get_cache_dir, decode_dict, st_mtime_ns
 from .hashindex import ChunkIndex
 from .hashindex import ChunkIndex
 
 
 
 
@@ -190,7 +190,7 @@ class Cache(object):
         if self.files is None:
         if self.files is None:
             self._read_files()
             self._read_files()
         entry = self.files.get(path_hash)
         entry = self.files.get(path_hash)
-        if (entry and entry[3] == st.st_mtime
+        if (entry and entry[3] == st_mtime_ns(st)
             and entry[2] == st.st_size and entry[1] == st.st_ino):
             and entry[2] == st.st_size and entry[1] == st.st_ino):
             # reset entry age
             # reset entry age
             self.files[path_hash][0] = 0
             self.files[path_hash][0] = 0
@@ -200,6 +200,6 @@ class Cache(object):
 
 
     def memorize_file(self, path_hash, st, ids):
     def memorize_file(self, path_hash, st, ids):
         # Entry: Age, inode, size, mtime, chunk ids
         # Entry: Age, inode, size, mtime, chunk ids
-        self.files[path_hash] = 0, st.st_ino, st.st_size, st.st_mtime, ids
-        self._newest_mtime = max(self._newest_mtime, st.st_mtime)
-
+        mtime_ns = st_mtime_ns(st)
+        self.files[path_hash] = 0, st.st_ino, st.st_size, mtime_ns, ids
+        self._newest_mtime = max(self._newest_mtime, mtime_ns)

+ 9 - 1
darc/helpers.py

@@ -375,4 +375,12 @@ def decode_dict(d, keys, encoding='utf-8', errors='surrogateescape'):
 
 
 
 
 def remove_surrogates(s, errors='replace'):
 def remove_surrogates(s, errors='replace'):
-    return s.encode('utf-8', errors).decode('utf-8')
+    return s.encode('utf-8', errors).decode('utf-8')
+
+
+if sys.version < '3.3':
+    def st_mtime_ns(st):
+        return int(st.st_mtime * 10**9)
+else:
+    def st_mtime_ns(st):
+        return st.st_mtime_ns

+ 6 - 4
darc/test.py

@@ -16,6 +16,7 @@ from .key import suite as KeySuite
 from .store import Store, suite as StoreSuite
 from .store import Store, suite as StoreSuite
 from .remote import Store, suite as RemoteStoreSuite
 from .remote import Store, suite as RemoteStoreSuite
 
 
+has_mtime_ns = sys.version >= '3.3'
 utime_supports_fd = os.utime in getattr(os, 'supports_fd', {})
 utime_supports_fd = os.utime in getattr(os, 'supports_fd', {})
 
 
 
 
@@ -89,12 +90,13 @@ class Test(unittest.TestCase):
             s2 = os.lstat(path2)
             s2 = os.lstat(path2)
             attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev']
             attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev']
             if not os.path.islink(path1) or utime_supports_fd:
             if not os.path.islink(path1) or utime_supports_fd:
-                attrs.append('st_mtime')
+                attrs.append('st_mtime_ns' if has_mtime_ns else 'st_mtime')
             d1 = [filename] + [getattr(s1, a) for a in attrs]
             d1 = [filename] + [getattr(s1, a) for a in attrs]
             d2 = [filename] + [getattr(s2, a) for a in attrs]
             d2 = [filename] + [getattr(s2, a) for a in attrs]
-            if(len(d1) == 6):
-                d1[-1] = int(d1[-1])
-                d2[-1] = int(d2[-1])
+            # 'st_mtime precision is limited'
+            if attrs[-1] == 'st_mtime':
+                d1[-1] = round(d1[-1], 4)
+                d2[-1] = round(d2[-1], 4)
             d1.append(self.get_xattrs(path1))
             d1.append(self.get_xattrs(path1))
             d2.append(self.get_xattrs(path2))
             d2.append(self.get_xattrs(path2))
             self.assertEqual(d1, d2)
             self.assertEqual(d1, d2)