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

View File

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

View File

@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import json import json
import os import os
import re import re
import shutil
import sys import sys
import time import time
from collections import defaultdict from collections import defaultdict
@ -15,10 +14,10 @@ from datetime import datetime
from functools import partial from functools import partial
from itertools import count from itertools import count
from math import ceil from math import ceil
from lxml.etree import Comment
from css_parser import replaceUrls from css_parser import replaceUrls
from css_parser.css import CSSRule from css_parser.css import CSSRule
from lxml.etree import Comment
from calibre import detect_ncpus, force_unicode, prepare_string_for_xml from calibre import detect_ncpus, force_unicode, prepare_string_for_xml
from calibre.constants import iswindows, plugins 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.metadata import encode_datetime
from calibre.srv.opts import grouper from calibre.srv.opts import grouper
from calibre.utils.date import EPOCH 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.ipc.simple_worker import start_pipe_worker
from calibre.utils.iso8601 import parse_iso8601 from calibre.utils.iso8601 import parse_iso8601
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
@ -448,11 +448,11 @@ class RenderManager(object):
p.kill() p.kill()
del self.workers del self.workers
try: try:
shutil.rmtree(self.tdir) rmtree(self.tdir)
except EnvironmentError: except EnvironmentError:
time.sleep(0.1) time.sleep(0.1)
try: try:
shutil.rmtree(self.tdir) rmtree(self.tdir)
except EnvironmentError: except EnvironmentError:
pass pass
del self.tdir 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 import force_unicode, isbytestring, prints, sanitize_file_name
from calibre.constants import ( 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 calibre.utils.localization import get_udc
from polyglot.builtins import iteritems, itervalues, unicode_type, range 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) hardlink(src, df)
except Exception: except Exception:
filecopyfunc(src, df) 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