diff options
author | toonn <toonn@toonn.io> | 2020-07-08 17:20:37 +0200 |
---|---|---|
committer | toonn <toonn@toonn.io> | 2020-07-08 17:27:34 +0200 |
commit | f9e0a77f6711ba111b15fcbfa58d7d84d0804232 (patch) | |
tree | f637d0bd6d7e72b4a61771b889afaeea450461b4 /ranger | |
parent | d6853cbfb8e05a63afe626e8dbc2ed191d838b9b (diff) | |
download | ranger-f9e0a77f6711ba111b15fcbfa58d7d84d0804232.tar.gz |
Add path to cache hash
Without the `st_dev` the `st_ino` is no longer enough to uniquely identify a file. A disadvantage of including the mtime in the hash is that changed previews don't overwrite the old cache path so the cached grows faster. We use the path to the file to uniquely identify a device. We concatenate it with the `st_ino` which ensures that replacing a file is not enough to cause a collision. This is hashed to create the cache path. Every time we check whether a preview is cached we verify that the file being preview is as old or older than the cached preview. The only differences from the original scheme are the algorithm (SHA-512 now), accepting previews of with the same mtime as the original file and including the inode identifier in the hash.
Diffstat (limited to 'ranger')
-rw-r--r-- | ranger/core/actions.py | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/ranger/core/actions.py b/ranger/core/actions.py index 8ba17657..f2a52451 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -17,7 +17,6 @@ import tempfile from inspect import cleandoc from stat import S_IEXEC from hashlib import sha512 -from struct import pack from logging import getLogger import ranger @@ -1048,13 +1047,12 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m return True @staticmethod - def sha512_encode(path): - stat_ = stat(path) - # How I arrived at the pack format string: - # < -> little-endian - # L -> st_ino: unsigned int (ditto) - # d -> st_mtime: double in python - sha = sha512(pack('<Ld', stat_.st_ino, stat_.st_mtime)) + def sha512_encode(path, inode=None): + if not inode: + inode = stat(path).st_ino + sha = sha512( + os.path.join(path, str(inode)).encode('utf-8','backslashescape') + ) return '{0}.jpg'.format(sha.hexdigest()) def get_preview(self, fobj, width, height): # pylint: disable=too-many-return-statements @@ -1123,9 +1121,13 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m if not os.path.exists(ranger.args.cachedir): os.makedirs(ranger.args.cachedir) - cacheimg = os.path.join(ranger.args.cachedir, self.sha512_encode(path)) - if self.settings.preview_images and \ - os.path.isfile(cacheimg): + fobj.load_if_outdated() + cacheimg = os.path.join( + ranger.args.cachedir, + self.sha512_encode(path, inode=fobj.stat.st_ino) + ) + if (self.settings.preview_images and os.path.isfile(cacheimg) + and fobj.stat.st_mtime <= os.path.getmtime(cacheimg)): data['foundpreview'] = True data['imagepreview'] = True pager.set_image(cacheimg) |