mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Windows: Check if any of the files of a book are in use before changing the title/author, this (usually) prevents the creation of duplicate files if one of the files is open in another program
This commit is contained in:
parent
d24835bff8
commit
1db24f5192
@ -270,7 +270,7 @@ class AuthorsEdit(EditWithComplete):
|
||||
import traceback
|
||||
fname = err.filename if err.filename else 'file'
|
||||
error_dialog(self, _('Permission denied'),
|
||||
_('Could not open %s. Is it being used by another'
|
||||
_('Could not open "%s". Is it being used by another'
|
||||
' program?')%fname, det_msg=traceback.format_exc(),
|
||||
show=True)
|
||||
return False
|
||||
|
@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
|
||||
The database used to store ebook metadata
|
||||
'''
|
||||
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \
|
||||
json, uuid, hashlib, copy
|
||||
json, uuid, hashlib, copy, errno
|
||||
from collections import defaultdict
|
||||
import threading, random
|
||||
from itertools import repeat
|
||||
@ -30,7 +30,8 @@ from calibre.ptempfile import (PersistentTemporaryFile,
|
||||
base_dir, SpooledTemporaryFile)
|
||||
from calibre.customize.ui import run_plugins_on_import
|
||||
from calibre import isbytestring
|
||||
from calibre.utils.filenames import ascii_filename, samefile
|
||||
from calibre.utils.filenames import (ascii_filename, samefile,
|
||||
windows_is_folder_in_use)
|
||||
from calibre.utils.date import (utcnow, now as nowf, utcfromtimestamp,
|
||||
parse_only_date, UNDEFINED_DATE)
|
||||
from calibre.utils.config import prefs, tweaks, from_json, to_json
|
||||
@ -649,6 +650,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
spath = os.path.join(self.library_path, *current_path.split('/'))
|
||||
|
||||
if current_path and os.path.exists(spath): # Migrate existing files
|
||||
if iswindows:
|
||||
uf = windows_is_folder_in_use(spath)
|
||||
if uf is not None:
|
||||
err = IOError(errno.EACCES,
|
||||
_('File is open in another process'))
|
||||
err.filename = uf
|
||||
raise err
|
||||
cdata = self.cover(id, index_is_id=True)
|
||||
if cdata is not None:
|
||||
with lopen(os.path.join(tpath, 'cover.jpg'), 'wb') as f:
|
||||
|
@ -249,4 +249,32 @@ def samefile(src, dst):
|
||||
os.path.normcase(os.path.abspath(dst)))
|
||||
return samestring
|
||||
|
||||
def windows_is_file_opened(path):
|
||||
import win32file, winerror
|
||||
from pywintypes import error
|
||||
if isbytestring(path): path = path.decode(filesystem_encoding)
|
||||
try:
|
||||
h = win32file.CreateFile(path, win32file.GENERIC_READ, 0, None,
|
||||
win32file.OPEN_EXISTING, 0, 0)
|
||||
except error as e:
|
||||
if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION:
|
||||
return True
|
||||
else:
|
||||
win32file.CloseHandle(h)
|
||||
return False
|
||||
|
||||
def windows_is_folder_in_use(path):
|
||||
'''
|
||||
Returns the path to a file that is used in another process in the specified
|
||||
folder, or None if no such file exists. Note
|
||||
that this function is not a guarantee. A file may well be opened in the
|
||||
folder after this function returns. However, it is useful to handle the
|
||||
common case of a sharing violation gracefully most of the time.
|
||||
'''
|
||||
if isbytestring(path): path = path.decode(filesystem_encoding)
|
||||
for x in os.listdir(path):
|
||||
f = os.path.join(path, x)
|
||||
if windows_is_file_opened(f):
|
||||
return f
|
||||
return None
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user