cap filename length when attaching media to cards

https://anki.tenderapp.com/discussions/ankidesktop/30953-can-not-paste-or-upload-images-into-deck
This commit is contained in:
Damien Elmes 2018-11-27 14:45:38 +10:00
parent 7e2305ac0c
commit 7b96e90db7

View file

@ -8,6 +8,7 @@ import urllib.request, urllib.parse, urllib.error
import unicodedata import unicodedata
import sys import sys
import zipfile import zipfile
import pathlib
from io import StringIO from io import StringIO
from anki.utils import checksum, isWin, isMac, json from anki.utils import checksum, isWin, isMac, json
@ -159,8 +160,8 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0);
# make sure we write it in NFC form (pre-APFS Macs will autoconvert to NFD), # make sure we write it in NFC form (pre-APFS Macs will autoconvert to NFD),
# and return an NFC-encoded reference # and return an NFC-encoded reference
fname = unicodedata.normalize("NFC", fname) fname = unicodedata.normalize("NFC", fname)
# remove any dangerous characters # ensure it's a valid filename
base = self.stripIllegal(fname) base = self.cleanFilename(fname)
(root, ext) = os.path.splitext(base) (root, ext) = os.path.splitext(base)
def repl(match): def repl(match):
n = int(match.group(1)) n = int(match.group(1))
@ -345,7 +346,7 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0);
def have(self, fname): def have(self, fname):
return os.path.exists(os.path.join(self.dir(), fname)) return os.path.exists(os.path.join(self.dir(), fname))
# Illegal characters # Illegal characters and paths
########################################################################## ##########################################################################
_illegalCharReg = re.compile(r'[][><:"/?*^\\|\0\r\n]') _illegalCharReg = re.compile(r'[][><:"/?*^\\|\0\r\n]')
@ -362,6 +363,53 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0);
return True return True
return False return False
def cleanFilename(self, fname):
fname = self.stripIllegal(fname)
fname = self._cleanWin32Filename(fname)
fname = self._cleanLongFilename(fname)
if not fname:
fname = "renamed"
return fname
def _cleanWin32Filename(self, fname):
if not isWin:
return fname
# deal with things like con/prn/etc
p = pathlib.WindowsPath(fname)
if p.is_reserved():
fname = "renamed" + fname
assert not pathlib.WindowsPath(fname).is_reserved()
return fname
def _cleanLongFilename(self, fname):
# a fairly safe limit that should work on typical windows
# paths and on eCryptfs partitions, even with a duplicate
# suffix appended
namemax = 136
if isWin:
pathmax = 240
else:
pathmax = 1024
# cap namemax based on absolute path
dirlen = len(os.path.dirname(os.path.abspath(fname)))
remaining = pathmax - dirlen
namemax = min(remaining, namemax)
assert namemax > 0
if len(fname) > namemax:
head, ext = os.path.splitext(fname)
headmax = namemax - len(ext)
head = head[0:headmax]
fname = head + ext
assert(len(fname) <= namemax)
return fname
# Tracking changes # Tracking changes
########################################################################## ##########################################################################