mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Use delete on close semantics on windows for cleanup post copy
This commit is contained in:
parent
c2e9a78ddf
commit
c3da25d112
@ -21,8 +21,9 @@ WindowsFileId = Tuple[int, int, int]
|
||||
|
||||
class UnixFileCopier:
|
||||
|
||||
def __init__(self, delete_all=False):
|
||||
def __init__(self, delete_all=False, allow_move=False):
|
||||
self.delete_all = delete_all
|
||||
self.allow_move = allow_move
|
||||
self.copy_map: Dict[str, str] = {}
|
||||
|
||||
def register(self, path: str, dest: str) -> None:
|
||||
@ -62,8 +63,9 @@ class WindowsFileCopier:
|
||||
Locks all files before starting the copy, ensuring other processes cannot interfere
|
||||
'''
|
||||
|
||||
def __init__(self, delete_all=False):
|
||||
def __init__(self, delete_all=False, allow_move=False):
|
||||
self.delete_all = delete_all
|
||||
self.allow_move = allow_move
|
||||
self.path_to_fileid_map : Dict[str, WindowsFileId] = {}
|
||||
self.fileid_to_paths_map: Dict[WindowsFileId, Set[str]] = defaultdict(set)
|
||||
self.path_to_handle_map: Dict[str, 'winutil.Handle'] = {}
|
||||
@ -87,9 +89,11 @@ class WindowsFileCopier:
|
||||
|
||||
def _open_file(self, path: str, retry_on_sharing_violation: bool = True, is_folder: bool = False) -> 'winutil.Handle':
|
||||
flags = winutil.FILE_FLAG_BACKUP_SEMANTICS if is_folder else winutil.FILE_FLAG_SEQUENTIAL_SCAN
|
||||
if self.delete_all:
|
||||
flags |= winutil.FILE_FLAG_DELETE_ON_CLOSE
|
||||
try:
|
||||
return winutil.create_file(make_long_path_useable(path), winutil.GENERIC_READ,
|
||||
winutil.FILE_SHARE_DELETE, winutil.OPEN_EXISTING, flags)
|
||||
winutil.FILE_SHARE_DELETE if self.allow_move else 0, winutil.OPEN_EXISTING, flags)
|
||||
except OSError as e:
|
||||
if e.winerror == winutil.ERROR_SHARING_VIOLATION:
|
||||
# The file could be a hardlink to an already opened file,
|
||||
@ -116,14 +120,10 @@ class WindowsFileCopier:
|
||||
self.folder_to_handle_map[path] = self._open_file(path, is_folder=True)
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
||||
try:
|
||||
if self.delete_all and exc_val is None:
|
||||
self.delete_all_source_files()
|
||||
finally:
|
||||
for h in self.path_to_handle_map.values():
|
||||
h.close()
|
||||
for h in self.folder_to_handle_map.values():
|
||||
h.close()
|
||||
for h in self.path_to_handle_map.values():
|
||||
h.close()
|
||||
for h in reversed(self.folder_to_handle_map.values()):
|
||||
h.close()
|
||||
|
||||
def copy_all(self) -> None:
|
||||
for src_path, dest_path in self.copy_map.items():
|
||||
@ -146,20 +146,14 @@ class WindowsFileCopier:
|
||||
for src_path, dest_path in self.copy_map.items():
|
||||
winutil.move_file(make_long_path_useable(src_path), make_long_path_useable(dest_path))
|
||||
|
||||
def delete_all_source_files(self) -> None:
|
||||
for src_path in self.copy_map:
|
||||
winutil.delete_file(make_long_path_useable(src_path))
|
||||
for path in reversed(self.folders):
|
||||
os.rmdir(make_long_path_useable(path))
|
||||
|
||||
|
||||
def get_copier(delete_all=False) -> Union[UnixFileCopier, WindowsFileCopier]:
|
||||
return WindowsFileCopier(delete_all) if iswindows else UnixFileCopier(delete_all)
|
||||
def get_copier(delete_all=False, allow_move=False) -> Union[UnixFileCopier, WindowsFileCopier]:
|
||||
return (WindowsFileCopier if iswindows else UnixFileCopier)(delete_all, allow_move)
|
||||
|
||||
|
||||
def rename_files(src_to_dest_map: Dict[str, str]) -> None:
|
||||
' Rename a bunch of files. On Windows all files are locked before renaming so no other process can interfere. '
|
||||
copier = get_copier()
|
||||
copier = get_copier(allow_move=True)
|
||||
for s, d in src_to_dest_map.items():
|
||||
copier.register(s, d)
|
||||
with copier:
|
||||
|
Loading…
x
Reference in New Issue
Block a user