Linux: Make some cache removal code robust against un-decodeable filenames in the cache directories

This commit is contained in:
Kovid Goyal 2019-11-10 17:42:22 +05:30
parent a1cc1d8a9d
commit ffab572a9e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 23 additions and 10 deletions

View File

@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import errno
import json
import os
import shutil
import tempfile
import time
from hashlib import sha1
@ -16,6 +15,7 @@ from calibre import walk
from calibre.constants import cache_dir, iswindows
from calibre.ptempfile import TemporaryFile
from calibre.srv.render_book import RENDER_VERSION
from calibre.utils.filenames import rmtree
from calibre.utils.ipc.simple_worker import start_pipe_worker
from calibre.utils.lock import ExclusiveFile
from calibre.utils.serialize import msgpack_dumps
@ -55,7 +55,7 @@ def robust_rmtree(x):
retries = 2 if iswindows else 1 # retry on windows to get around the idiotic mandatory file locking
for i in range(retries):
try:
shutil.rmtree(x)
rmtree(x)
return True
except EnvironmentError:
time.sleep(0.1)
@ -297,7 +297,7 @@ def find_tests():
book_cache_dir.override = os.path.join(self.tdir, 'ev2')
def tearDown(self):
shutil.rmtree(self.tdir)
rmtree(self.tdir)
del book_cache_dir.override
def test_viewer_cache(self):

View File

@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import errno
import json as jsonlib
import os
import shutil
import tempfile
import time
from functools import partial
@ -21,6 +20,7 @@ from calibre.srv.metadata import book_as_json
from calibre.srv.render_book import RENDER_VERSION
from calibre.srv.routes import endpoint, json
from calibre.srv.utils import get_db, get_library_data
from calibre.utils.filenames import rmtree
from calibre.utils.serialize import json_dumps
from polyglot.builtins import as_unicode, map
@ -66,7 +66,7 @@ def safe_remove(x, is_file=None):
if is_file is None:
is_file = os.path.isfile(x)
try:
os.remove(x) if is_file else shutil.rmtree(x, ignore_errors=True)
os.remove(x) if is_file else rmtree(x, ignore_errors=True)
except EnvironmentError:
pass

View File

@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import json
import os
import re
import shutil
import sys
import time
from collections import defaultdict
@ -15,10 +14,10 @@ from datetime import datetime
from functools import partial
from itertools import count
from math import ceil
from lxml.etree import Comment
from css_parser import replaceUrls
from css_parser.css import CSSRule
from lxml.etree import Comment
from calibre import detect_ncpus, force_unicode, prepare_string_for_xml
from calibre.constants import iswindows, plugins
@ -41,6 +40,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.srv.metadata import encode_datetime
from calibre.srv.opts import grouper
from calibre.utils.date import EPOCH
from calibre.utils.filenames import rmtree
from calibre.utils.ipc.simple_worker import start_pipe_worker
from calibre.utils.iso8601 import parse_iso8601
from calibre.utils.logging import default_log
@ -448,11 +448,11 @@ class RenderManager(object):
p.kill()
del self.workers
try:
shutil.rmtree(self.tdir)
rmtree(self.tdir)
except EnvironmentError:
time.sleep(0.1)
try:
shutil.rmtree(self.tdir)
rmtree(self.tdir)
except EnvironmentError:
pass
del self.tdir

View File

@ -12,7 +12,7 @@ from math import ceil
from calibre import force_unicode, isbytestring, prints, sanitize_file_name
from calibre.constants import (
filesystem_encoding, iswindows, plugins, preferred_encoding, isosx
filesystem_encoding, iswindows, plugins, preferred_encoding, isosx, ispy3
)
from calibre.utils.localization import get_udc
from polyglot.builtins import iteritems, itervalues, unicode_type, range
@ -627,3 +627,16 @@ def copytree_using_links(path, dest, dest_is_parent=True, filecopyfunc=copyfile)
hardlink(src, df)
except Exception:
filecopyfunc(src, df)
if not ispy3 and not iswindows:
# On POSIX in python2 if you pass a unicode path to rmtree
# it tries to decode all filenames it encounters while walking
# the tree which leads to unicode errors on Linux where there
# can be non-decodeable filenames.
def rmtree(x, **kw):
if not isinstance(x, bytes):
x = x.encode('utf-8')
return shutil.rmtree(x, **kw)
else:
rmtree = shutil.rmtree