Fix case of paths on case-insensitive device file systems. Can get incorrect case in lpath if a field in two books is spelled identically except for case and that field is used in a template.

This commit is contained in:
Charles Haley 2011-08-14 18:32:02 +01:00
parent 86cbac0d00
commit 285dfeca6c

View File

@ -13,7 +13,7 @@ for a particular device.
import os, re, time, json, uuid, functools import os, re, time, json, uuid, functools
from itertools import cycle from itertools import cycle
from calibre.constants import numeric_version from calibre.constants import numeric_version, iswindows
from calibre import prints, isbytestring from calibre import prints, isbytestring
from calibre.constants import filesystem_encoding, DEBUG from calibre.constants import filesystem_encoding, DEBUG
from calibre.devices.usbms.cli import CLI from calibre.devices.usbms.cli import CLI
@ -258,10 +258,10 @@ class USBMS(CLI, Device):
for i, infile in enumerate(files): for i, infile in enumerate(files):
mdata, fname = metadata.next(), names.next() mdata, fname = metadata.next(), names.next()
filepath = self.normalize_path(self.create_upload_path(path, mdata, fname)) filepath = self.normalize_path(self.create_upload_path(path, mdata, fname))
paths.append(filepath)
if not hasattr(infile, 'read'): if not hasattr(infile, 'read'):
infile = self.normalize_path(infile) infile = self.normalize_path(infile)
self.put_file(infile, filepath, replace_file=True) self.put_file(infile, filepath, replace_file=True)
paths.append(self.correct_case_of_filename(filepath))
try: try:
self.upload_cover(os.path.dirname(filepath), self.upload_cover(os.path.dirname(filepath),
os.path.splitext(os.path.basename(filepath))[0], os.path.splitext(os.path.basename(filepath))[0],
@ -276,6 +276,38 @@ class USBMS(CLI, Device):
debug_print('USBMS: finished uploading %d books'%(len(files))) debug_print('USBMS: finished uploading %d books'%(len(files)))
return zip(paths, cycle([on_card])) return zip(paths, cycle([on_card]))
# Get the real case of the underlying filename. Can differ from what we
# have on case-insensitive file systems.
def correct_case_of_filename(self, filepath):
path = os.path.abspath(filepath);
comps = path.split(os.sep)
if not comps:
return filepath
res = comps[0]
if iswindows:
# must put a \ after the prefix or it will read the current directory
res += os.sep
# read down the path directory by directory, doing a case-insensitive
# compare. Build a new path of the components with the case as on disk.
for comp in comps[1:]:
sc = os.listdir(res)
for c in sc:
if c.lower() == comp.lower():
res = os.path.join(res, c);
continue
# now see if the old and new path point at the same book. If we have
# a case-sensitive file system on the device, then we might have
# generated the wrong path. Books are considered the same if their
# mtime and size are the same.
before = os.stat(filepath)
after = os.stat(res)
if before.st_mtime == after.st_mtime and before.st_size == after.st_size:
# the same. the new path is valid. Might == the old one, but that is OK
return res
# not the same. The old path must be used.
return filepath
def upload_cover(self, path, filename, metadata, filepath): def upload_cover(self, path, filename, metadata, filepath):
''' '''
Upload book cover to the device. Default implementation does nothing. Upload book cover to the device. Default implementation does nothing.