Remove pywin32 from filenames.py

This commit is contained in:
Kovid Goyal 2020-10-16 18:10:25 +05:30
parent 5701a6c2c5
commit e087f086bd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 57 additions and 74 deletions

View File

@ -185,6 +185,7 @@ class BuildTest(unittest.TestCase):
self.assertRaises(OSError, winutil.delete_file, path)
self.assertRaises(OSError, winutil.create_file,
os.path.join(path, 'cannot'), winutil.GENERIC_READ, 0, winutil.OPEN_ALWAYS, winutil.FILE_ATTRIBUTE_NORMAL)
self.assertTrue(winutil.supports_hardlinks(os.path.abspath(os.getcwd())[0] + ':\\'))
sz = 23
data = os.urandom(sz)
open(path, 'wb').write(data)

View File

@ -9,7 +9,7 @@ import os
import shutil
import time
from math import ceil
from contextlib import suppress
from contextlib import suppress, closing
from calibre import force_unicode, isbytestring, prints, sanitize_file_name
from calibre.constants import (
@ -272,25 +272,19 @@ def windows_get_size(path):
''' On windows file sizes are only accurately stored in the actual file,
not in the directory entry (which could be out of date). So we open the
file, and get the actual size. '''
import win32file
from calibre_extensions import winutil
if isbytestring(path):
path = path.decode(filesystem_encoding)
h = win32file.CreateFileW(
path, 0, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE | win32file.FILE_SHARE_DELETE,
None, win32file.OPEN_EXISTING, 0, None)
try:
return win32file.GetFileSize(h)
finally:
win32file.CloseHandle(h)
with closing(winutil.create_file(
path, 0, winutil.FILE_SHARE_READ | winutil.FILE_SHARE_WRITE | winutil.FILE_SHARE_DELETE,
winutil.OPEN_EXISTING, 0)
) as h:
return winutil.get_file_size(h)
def windows_hardlink(src, dest):
import win32file, pywintypes
try:
win32file.CreateHardLink(dest, src)
except pywintypes.error as e:
msg = 'Creating hardlink from %s to %s failed: %%s' % (src, dest)
raise OSError(msg % e)
from calibre_extensions import winutil
winutil.create_hard_link(dest, src)
src_size = os.path.getsize(src)
# We open and close dest, to ensure its directory entry is updated
# see http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx
@ -311,12 +305,8 @@ def windows_hardlink(src, dest):
def windows_fast_hardlink(src, dest):
import win32file, pywintypes
try:
win32file.CreateHardLink(dest, src)
except pywintypes.error as e:
msg = 'Creating hardlink from %s to %s failed: %%s' % (src, dest)
raise OSError(msg % e)
from calibre_extensions import winutil
winutil.create_hard_link(dest, src)
ssz, dsz = windows_get_size(src), windows_get_size(dest)
if ssz != dsz:
msg = 'Creating hardlink from %s to %s failed: %%s' % (src, dest)
@ -324,15 +314,10 @@ def windows_fast_hardlink(src, dest):
def windows_nlinks(path):
import win32file
dwFlagsAndAttributes = win32file.FILE_FLAG_BACKUP_SEMANTICS if os.path.isdir(path) else 0
from calibre_extensions import winutil
if isbytestring(path):
path = path.decode(filesystem_encoding)
handle = win32file.CreateFileW(path, win32file.GENERIC_READ, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, dwFlagsAndAttributes, None)
try:
return win32file.GetFileInformationByHandle(handle)[7]
finally:
handle.Close()
return winutil.nlinks(path)
class WindowsAtomicFolderMove(object):
@ -346,11 +331,9 @@ class WindowsAtomicFolderMove(object):
'''
def __init__(self, path):
self.handle_map = {}
import win32file, winerror
from pywintypes import error
from collections import defaultdict
from calibre_extensions import winutil
self.handle_map = {}
if isbytestring(path):
path = path.decode(filesystem_encoding)
@ -368,18 +351,16 @@ class WindowsAtomicFolderMove(object):
f = os.path.normcase(os.path.abspath(os.path.join(path, x)))
if not os.path.isfile(f):
continue
try:
with suppress(OSError):
# Ensure the file is not read-only
win32file.SetFileAttributes(f, win32file.FILE_ATTRIBUTE_NORMAL)
except:
pass
winutil.set_file_attributes(f, winutil.FILE_ATTRIBUTE_NORMAL)
try:
h = win32file.CreateFileW(f, win32file.GENERIC_READ,
win32file.FILE_SHARE_DELETE, None,
win32file.OPEN_EXISTING, win32file.FILE_FLAG_SEQUENTIAL_SCAN, 0)
except error as e:
if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION:
h = winutil.create_file(f, winutil.GENERIC_READ,
winutil.FILE_SHARE_DELETE,
winutil.OPEN_EXISTING, winutil.FILE_FLAG_SEQUENTIAL_SCAN)
except OSError as e:
if e.winerror == winutil.ERROR_SHARING_VIOLATION:
# The file could be a hardlink to an already opened file,
# in which case we use the same handle for both files
fileid = name_to_fileid[x]
@ -395,7 +376,7 @@ class WindowsAtomicFolderMove(object):
continue
self.close_handles()
if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION:
if e.winerror == winutil.ERROR_SHARING_VIOLATION:
err = IOError(errno.EACCES,
_('File is open in another process'))
err.filename = f
@ -409,9 +390,9 @@ class WindowsAtomicFolderMove(object):
self.handle_map[f] = h
def copy_path_to(self, path, dest):
import win32file
from calibre_extensions import winutil
handle = None
for p, h in iteritems(self.handle_map):
for p, h in self.handle_map.items():
if samefile_windows(path, p):
handle = h
break
@ -421,18 +402,16 @@ class WindowsAtomicFolderMove(object):
' operation was started'%path)
else:
raise ValueError('The file %r does not exist'%path)
try:
with suppress(OSError):
windows_hardlink(path, dest)
return
except:
pass
win32file.SetFilePointer(handle, 0, win32file.FILE_BEGIN)
winutil.set_file_pointer(handle, 0, winutil.FILE_BEGIN)
with lopen(dest, 'wb') as f:
sz = 1024 * 1024
while True:
hr, raw = win32file.ReadFile(handle, 1024*1024)
if hr != 0:
raise IOError(hr, 'Error while reading from %r'%path)
raw = winutil.read_file(handle, sz)
if not raw:
break
f.write(raw)
@ -445,22 +424,20 @@ class WindowsAtomicFolderMove(object):
key = (p, h)
break
if key is not None:
import win32file
win32file.CloseHandle(key[1])
key[1].close()
remove = [f for f, h in iteritems(self.handle_map) if h is key[1]]
for x in remove:
self.handle_map.pop(x)
def close_handles(self):
import win32file
for h in itervalues(self.handle_map):
win32file.CloseHandle(h)
h.close()
self.handle_map = {}
def delete_originals(self):
import win32file
from calibre_extensions import winutil
for path in self.handle_map:
win32file.DeleteFileW(path)
winutil.delete_file(path)
self.close_handles()
@ -567,20 +544,12 @@ def copyfile(src, dest):
def get_hardlink_function(src, dest):
if iswindows:
import win32file, win32api
colon = b':' if isinstance(dest, bytes) else ':'
root = dest[0] + colon
try:
is_suitable = win32file.GetDriveType(root) not in (win32file.DRIVE_REMOTE, win32file.DRIVE_CDROM)
# See https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
supports_hard_links = win32api.GetVolumeInformation(root + os.sep)[3] & 0x00400000
except Exception:
supports_hard_links = is_suitable = False
hardlink = windows_fast_hardlink if is_suitable and supports_hard_links and src[0].lower() == dest[0].lower() else None
else:
hardlink = os.link
return hardlink
if not iswindows:
return os.link
from calibre_extensions import winutil
root = dest[0] + ':\\'
if src[0].lower() == dest[0].lower() and hasattr(winutil, 'supports_hardlinks') and winutil.supports_hardlinks(root):
return windows_fast_hardlink
def copyfile_using_links(path, dest, dest_is_dir=True, filecopyfunc=copyfile):

View File

@ -510,6 +510,18 @@ winutil_delete_file(PyObject *self, PyObject *args) {
Py_RETURN_NONE;
}
static PyObject*
supports_hardlinks(PyObject *self, PyObject *args) {
wchar_raii path;
if (!PyArg_ParseTuple(args, "O&", py_to_wchar_no_none, &path)) return NULL;
UINT dt = GetDriveType(path.ptr());
if (dt == DRIVE_REMOTE || dt == DRIVE_CDROM) Py_RETURN_FALSE;
DWORD max_component_length, flags;
if (!GetVolumeInformationW(path.ptr(), NULL, 0, NULL, &max_component_length, &flags, NULL, 0)) return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, PyTuple_GET_ITEM(args, 0));
if (flags & FILE_SUPPORTS_HARD_LINKS) Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static PyObject*
winutil_create_hard_link(PyObject *self, PyObject *args) {
wchar_raii path, existing_path;
@ -550,8 +562,8 @@ winutil_nlinks(PyObject *self, PyObject *args) {
static PyObject*
winutil_set_file_attributes(PyObject *self, PyObject *args) {
wchar_raii path; unsigned long attrs;
if (!PyArg_ParseTuple(args, "O&k", py_to_wchar_no_none, &path, &attrs)) return NULL;
wchar_raii path; unsigned long attrs = FILE_ATTRIBUTE_NORMAL;
if (!PyArg_ParseTuple(args, "O&|k", py_to_wchar_no_none, &path, &attrs)) return NULL;
if (!SetFileAttributes(path.ptr(), attrs)) return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, PyTuple_GET_ITEM(args, 0));
Py_RETURN_NONE;
}
@ -1026,6 +1038,7 @@ static PyMethodDef winutil_methods[] = {
M(is_wow64_process, METH_NOARGS),
M(get_dll_directory, METH_NOARGS),
M(create_mutex, METH_VARARGS),
M(supports_hardlinks, METH_VARARGS),
M(get_async_key_state, METH_VARARGS),
M(create_named_pipe, METH_VARARGS),
M(connect_named_pipe, METH_VARARGS),
@ -1125,7 +1138,7 @@ static PyMethodDef winutil_methods[] = {
},
{"read_file", (PyCFunction)winutil_read_file, METH_VARARGS,
"set_file_pointer(handle, chunk_size=16KB)\n\nWrapper for ReadFile"
"read_file(handle, chunk_size=16KB)\n\nWrapper for ReadFile"
},
{"get_disk_free_space", (PyCFunction)winutil_get_disk_free_space, METH_VARARGS,