From 0ec96bae403fd482009a1b9f6c1a120ea8d9a5d7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 28 Mar 2013 16:45:25 +0530 Subject: [PATCH] Fix a regression that caused chaning the case of title/authors to no longer change the case of the actual files in the filesystem if the filesystem is case-insensitive --- src/calibre/db/backend.py | 37 +++++++++++++++++++++--------- src/calibre/db/tests/filesystem.py | 6 +++++ src/calibre/library/database2.py | 37 +++++++++++++++++++++--------- 3 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index 155e21d819..19f8b0247f 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -947,23 +947,38 @@ class DB(object): if not isinstance(dest, basestring): raise Exception("Error, you must pass the dest as a path when" " using windows_atomic_move") - if dest and not samefile(dest, path): - windows_atomic_move.copy_path_to(path, dest) + if dest: + if samefile(dest, path): + # Ensure that the file has the same case as dest + try: + os.rename(path, dest) + except: + pass # Nothing too catastrophic happened, the cases mismatch, that's all + else: + windows_atomic_move.copy_path_to(path, dest) else: if hasattr(dest, 'write'): with lopen(path, 'rb') as f: shutil.copyfileobj(f, dest) if hasattr(dest, 'flush'): dest.flush() - elif dest and not samefile(dest, path): - if use_hardlink: - try: - hardlink_file(path, dest) - return True - except: - pass - with lopen(path, 'rb') as f, lopen(dest, 'wb') as d: - shutil.copyfileobj(f, d) + elif dest: + if samefile(dest, path): + if not self.is_case_sensitive: + # Ensure that the file has the same case as dest + try: + os.rename(path, dest) + except: + pass # Nothing too catastrophic happened, the cases mismatch, that's all + else: + if use_hardlink: + try: + hardlink_file(path, dest) + return True + except: + pass + with lopen(path, 'rb') as f, lopen(dest, 'wb') as d: + shutil.copyfileobj(f, d) return True def windows_check_if_files_in_use(self, paths): diff --git a/src/calibre/db/tests/filesystem.py b/src/calibre/db/tests/filesystem.py index 93f4891ac0..168eec53a4 100644 --- a/src/calibre/db/tests/filesystem.py +++ b/src/calibre/db/tests/filesystem.py @@ -60,6 +60,12 @@ class FilesystemTest(BaseTest): fpath = c.format_abspath(1, 'FMT1').replace(os.sep, '/').split('/') ae(fpath[-3:], ['Moved', 'Moved (1)', 'Moved - Moved.fmt1']) af(os.path.exists(os.path.dirname(orig_fpath)), 'Original book folder still exists') + # Check that the filesystem reflects fpath (especially on + # case-insensitive systems). + for x in range(1, 4): + base = os.sep.join(fpath[:-x]) + part = fpath[-x:][0] + self.assertIn(part, os.listdir(base)) @unittest.skipUnless(iswindows, 'Windows only') def test_windows_atomic_move(self): diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 914de2358b..d398c3da3d 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1343,23 +1343,38 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if not isinstance(dest, basestring): raise Exception("Error, you must pass the dest as a path when" " using windows_atomic_move") - if dest and not samefile(dest, path): - windows_atomic_move.copy_path_to(path, dest) + if dest: + if samefile(path, dest): + # Ensure that the file has the same case as dest + try: + os.rename(path, dest) + except: + pass # Nothing too catastrophic happened, the cases mismatch, that's all + else: + windows_atomic_move.copy_path_to(path, dest) else: if hasattr(dest, 'write'): with lopen(path, 'rb') as f: shutil.copyfileobj(f, dest) if hasattr(dest, 'flush'): dest.flush() - elif dest and not samefile(dest, path): - if use_hardlink: - try: - hardlink_file(path, dest) - return - except: - pass - with lopen(path, 'rb') as f, lopen(dest, 'wb') as d: - shutil.copyfileobj(f, d) + elif dest: + if samefile(dest, path): + if not self.is_case_sensitive: + # Ensure that the file has the same case as dest + try: + os.rename(path, dest) + except: + pass # Nothing too catastrophic happened, the cases mismatch, that's all + else: + if use_hardlink: + try: + hardlink_file(path, dest) + return + except: + pass + with lopen(path, 'rb') as f, lopen(dest, 'wb') as d: + shutil.copyfileobj(f, d) def copy_cover_to(self, index, dest, index_is_id=False, windows_atomic_move=None, use_hardlink=False):