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.
|
meaning as possible.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os, errno, time, shutil
|
import errno
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import time
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
from calibre import sanitize_file_name, isbytestring, force_unicode, prints
|
from calibre import force_unicode, isbytestring, prints, sanitize_file_name
|
||||||
from calibre.constants import (preferred_encoding, iswindows,
|
from calibre.constants import (
|
||||||
filesystem_encoding)
|
filesystem_encoding, iswindows, plugins, preferred_encoding
|
||||||
|
)
|
||||||
from calibre.utils.localization import get_udc
|
from calibre.utils.localization import get_udc
|
||||||
|
|
||||||
|
|
||||||
@ -476,15 +480,30 @@ def nlinks_file(path):
|
|||||||
return os.stat(path).st_nlink
|
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):
|
def atomic_rename(oldpath, newpath):
|
||||||
'''Replace the file newpath with the file oldpath. Can fail if the files
|
'''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
|
are on different volumes. If succeeds, guaranteed to be atomic. newpath may
|
||||||
or may not exist. If it exists, it is replaced. '''
|
or may not exist. If it exists, it is replaced. '''
|
||||||
if iswindows:
|
if iswindows:
|
||||||
import win32file
|
|
||||||
for i in xrange(10):
|
for i in xrange(10):
|
||||||
try:
|
try:
|
||||||
win32file.MoveFileEx(oldpath, newpath, win32file.MOVEFILE_REPLACE_EXISTING|win32file.MOVEFILE_WRITE_THROUGH)
|
rename_file(oldpath, newpath)
|
||||||
break
|
break
|
||||||
except Exception:
|
except Exception:
|
||||||
if i > 8:
|
if i > 8:
|
||||||
|
@ -239,6 +239,15 @@ winutil_getenv(PyObject *self, PyObject *args) {
|
|||||||
return PyUnicode_FromWideChar(ans, wcslen(ans));
|
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 *
|
static PyObject *
|
||||||
winutil_username(PyObject *self) {
|
winutil_username(PyObject *self) {
|
||||||
wchar_t buf[UNLEN + 1] = {0};
|
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."
|
"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}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -491,4 +504,3 @@ initwinutil(void) {
|
|||||||
PyModule_AddIntConstant(m, "CSIDL_PROFILE", CSIDL_PROFILE);
|
PyModule_AddIntConstant(m, "CSIDL_PROFILE", CSIDL_PROFILE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user