mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make atomic_rename() work on windows systems with filenames that cannot be encoded using the system codepage
This commit is contained in:
parent
f258b3d53e
commit
ece8f680c3
@ -3,12 +3,16 @@ Make strings safe for use as ASCII filenames, while trying to preserve as much
|
||||
meaning as possible.
|
||||
'''
|
||||
|
||||
import os, errno, time, shutil
|
||||
import errno
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from math import ceil
|
||||
|
||||
from calibre import sanitize_file_name, isbytestring, force_unicode, prints
|
||||
from calibre.constants import (preferred_encoding, iswindows,
|
||||
filesystem_encoding)
|
||||
from calibre import force_unicode, isbytestring, prints, sanitize_file_name
|
||||
from calibre.constants import (
|
||||
filesystem_encoding, iswindows, plugins, preferred_encoding
|
||||
)
|
||||
from calibre.utils.localization import get_udc
|
||||
|
||||
|
||||
@ -476,15 +480,30 @@ def nlinks_file(path):
|
||||
return os.stat(path).st_nlink
|
||||
|
||||
|
||||
if iswindows:
|
||||
def rename_file(a, b):
|
||||
move_file = getattr(plugins['winutil'][0], 'move_file', None)
|
||||
if move_file is None:
|
||||
import win32file
|
||||
|
||||
def mf_impl(a, b):
|
||||
win32file.MoveFileEx(a, b, win32file.MOVEFILE_REPLACE_EXISTING|win32file.MOVEFILE_WRITE_THROUGH)
|
||||
move_file = mf_impl
|
||||
if isinstance(a, bytes):
|
||||
a = a.decode('mbcs')
|
||||
if isinstance(b, bytes):
|
||||
b = b.decode('mbcs')
|
||||
move_file(a, b)
|
||||
|
||||
|
||||
def atomic_rename(oldpath, newpath):
|
||||
'''Replace the file newpath with the file oldpath. Can fail if the files
|
||||
are on different volumes. If succeeds, guaranteed to be atomic. newpath may
|
||||
or may not exist. If it exists, it is replaced. '''
|
||||
if iswindows:
|
||||
import win32file
|
||||
for i in xrange(10):
|
||||
try:
|
||||
win32file.MoveFileEx(oldpath, newpath, win32file.MOVEFILE_REPLACE_EXISTING|win32file.MOVEFILE_WRITE_THROUGH)
|
||||
rename_file(oldpath, newpath)
|
||||
break
|
||||
except Exception:
|
||||
if i > 8:
|
||||
|
@ -239,6 +239,15 @@ winutil_getenv(PyObject *self, PyObject *args) {
|
||||
return PyUnicode_FromWideChar(ans, wcslen(ans));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
winutil_move_file(PyObject *self, PyObject *args) {
|
||||
Py_UNICODE *a, *b;
|
||||
unsigned int flags = MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH;
|
||||
if (!PyArg_ParseTuple(args, "uu|I", &a, &b, &flags)) return NULL;
|
||||
if (!MoveFileExW(a, b, flags)) { PyErr_SetFromWindowsErr(0); return NULL; }
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
winutil_username(PyObject *self) {
|
||||
wchar_t buf[UNLEN + 1] = {0};
|
||||
@ -459,6 +468,10 @@ be a unicode string. Returns unicode strings."
|
||||
"localeconv()\n\nGet the locale conventions as unicode strings."
|
||||
},
|
||||
|
||||
{"move_file", (PyCFunction)winutil_move_file, METH_VARARGS,
|
||||
"move_file()\n\nRename the specified file."
|
||||
},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
@ -491,4 +504,3 @@ initwinutil(void) {
|
||||
PyModule_AddIntConstant(m, "CSIDL_PROFILE", CSIDL_PROFILE);
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user