def copy_cover_to(self, path, dest, windows_atomic_move=None, use_hardlink=False): path = os.path.abspath(os.path.join(self.library_path, path, 'cover.jpg')) if windows_atomic_move is not None: if not isinstance(dest, basestring): raise Exception("Error, you must pass the dest as a path when" " using windows_atomic_move") if os.access(path, os.R_OK) and dest and not samefile(dest, path): windows_atomic_move.copy_path_to(path, dest) return True else: if os.access(path, os.R_OK): try: f = lopen(path, 'rb') except (IOError, OSError): time.sleep(0.2) f = lopen(path, 'rb') with f: if hasattr(dest, 'write'): shutil.copyfileobj(f, dest) if hasattr(dest, 'flush'): dest.flush() return True elif dest and not samefile(dest, path): if use_hardlink: try: hardlink_file(path, dest) return True except: pass with lopen(dest, 'wb') as d: shutil.copyfileobj(f, d) return True return False
def test_windows_atomic_move(self): 'Test book file open in another process when changing metadata' cl = self.cloned_library cache = self.init_cache(cl) fpath = cache.format_abspath(1, 'FMT1') f = open(fpath, 'rb') with self.assertRaises(IOError): cache.set_field('title', {1:'Moved'}) with self.assertRaises(IOError): cache.remove_books({1}) f.close() self.assertNotEqual(cache.field_for('title', 1), 'Moved', 'Title was changed despite file lock') # Test on folder with hardlinks from calibre.ptempfile import TemporaryDirectory from calibre.utils.filenames import hardlink_file, WindowsAtomicFolderMove raw = b'xxx' with TemporaryDirectory() as tdir1, TemporaryDirectory() as tdir2: a, b = os.path.join(tdir1, 'a'), os.path.join(tdir1, 'b') a = os.path.join(tdir1, 'a') with open(a, 'wb') as f: f.write(raw) hardlink_file(a, b) wam = WindowsAtomicFolderMove(tdir1) wam.copy_path_to(a, os.path.join(tdir2, 'a')) wam.copy_path_to(b, os.path.join(tdir2, 'b')) wam.delete_originals() self.assertEqual([], os.listdir(tdir1)) self.assertEqual({'a', 'b'}, set(os.listdir(tdir2))) self.assertEqual(raw, open(os.path.join(tdir2, 'a'), 'rb').read()) self.assertEqual(raw, open(os.path.join(tdir2, 'b'), 'rb').read())
def test_windows_atomic_move(self): "Test book file open in another process when changing metadata" cl = self.cloned_library cache = self.init_cache(cl) fpath = cache.format_abspath(1, "FMT1") f = open(fpath, "rb") with self.assertRaises(IOError): cache.set_field("title", {1: "Moved"}) with self.assertRaises(IOError): cache.remove_books({1}) f.close() self.assertNotEqual(cache.field_for("title", 1), "Moved", "Title was changed despite file lock") # Test on folder with hardlinks from calibre.ptempfile import TemporaryDirectory from calibre.utils.filenames import hardlink_file, WindowsAtomicFolderMove raw = b"xxx" with TemporaryDirectory() as tdir1, TemporaryDirectory() as tdir2: a, b = os.path.join(tdir1, "a"), os.path.join(tdir1, "b") a = os.path.join(tdir1, "a") with open(a, "wb") as f: f.write(raw) hardlink_file(a, b) wam = WindowsAtomicFolderMove(tdir1) wam.copy_path_to(a, os.path.join(tdir2, "a")) wam.copy_path_to(b, os.path.join(tdir2, "b")) wam.delete_originals() self.assertEqual([], os.listdir(tdir1)) self.assertEqual({"a", "b"}, set(os.listdir(tdir2))) self.assertEqual(raw, open(os.path.join(tdir2, "a"), "rb").read()) self.assertEqual(raw, open(os.path.join(tdir2, "b"), "rb").read())
def clone_dir(src, dest): ' Clone a directory using hard links for the files, dest must already exist ' for x in os.listdir(src): dpath = os.path.join(dest, x) spath = os.path.join(src, x) if os.path.isdir(spath): os.mkdir(dpath) clone_dir(spath, dpath) else: try: hardlink_file(spath, dpath) except: shutil.copy2(spath, dpath)
def copy_format_to(self, book_id, fmt, fname, path, dest, windows_atomic_move=None, use_hardlink=False): path = self.format_abspath(book_id, fmt, fname, path) if path is None: return False if windows_atomic_move is not None: if not isinstance(dest, basestring): raise Exception("Error, you must pass the dest as a path when" " using windows_atomic_move") if dest: if samefile(dest, path): # Ensure that the file has the same case as dest try: if path != dest: 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: if samefile(dest, path): if not self.is_case_sensitive and 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: 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 copy_cover_to(self, path, dest, windows_atomic_move=None, use_hardlink=False): path = os.path.abspath( os.path.join(self.library_path, path, 'cover.jpg')) if windows_atomic_move is not None: if not isinstance(dest, basestring): raise Exception("Error, you must pass the dest as a path when" " using windows_atomic_move") if os.access(path, os.R_OK) and dest and not samefile(dest, path): windows_atomic_move.copy_path_to(path, dest) return True else: if os.access(path, os.R_OK): try: f = lopen(path, 'rb') except (IOError, OSError): time.sleep(0.2) f = lopen(path, 'rb') with f: if hasattr(dest, 'write'): shutil.copyfileobj(f, dest) if hasattr(dest, 'flush'): dest.flush() return True elif dest and not samefile(dest, path): if use_hardlink: try: hardlink_file(path, dest) return True except: pass with lopen(dest, 'wb') as d: shutil.copyfileobj(f, d) return True return False