mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add a couple more win32file functions
This commit is contained in:
parent
216c5a3629
commit
1754c87256
@ -147,6 +147,7 @@ class BuildTest(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(iswindows, 'winutil is windows only')
|
||||
def test_winutil(self):
|
||||
import tempfile
|
||||
from calibre.constants import plugins
|
||||
from calibre import strftime
|
||||
winutil = plugins['winutil'][0]
|
||||
@ -213,6 +214,41 @@ class BuildTest(unittest.TestCase):
|
||||
self.assertRaises(OSError, winutil.delete_file, npath)
|
||||
winutil.set_file_attributes(npath, winutil.FILE_ATTRIBUTE_NORMAL)
|
||||
winutil.delete_file(npath)
|
||||
self.assertGreater(min(winutil.get_disk_free_space(None)), 0)
|
||||
open(path, 'wb').close()
|
||||
open(npath, 'wb').close()
|
||||
winutil.move_file(path, npath, winutil.MOVEFILE_WRITE_THROUGH | winutil.MOVEFILE_REPLACE_EXISTING)
|
||||
self.assertFalse(os.path.exists(path))
|
||||
os.remove(npath)
|
||||
dpath = tempfile.mkdtemp(dir=os.path.dirname(path))
|
||||
dh = winutil.create_file(
|
||||
dpath, winutil.FILE_LIST_DIRECTORY, winutil.FILE_SHARE_READ, winutil.OPEN_EXISTING, winutil.FILE_FLAG_BACKUP_SEMANTICS,
|
||||
)
|
||||
from threading import Thread
|
||||
events = []
|
||||
|
||||
def read_changes():
|
||||
buffer = b'0' * 8192
|
||||
events.extend(winutil.read_directory_changes(
|
||||
dh, buffer, True,
|
||||
winutil.FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||
winutil.FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
winutil.FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
winutil.FILE_NOTIFY_CHANGE_SIZE |
|
||||
winutil.FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
winutil.FILE_NOTIFY_CHANGE_SECURITY
|
||||
))
|
||||
t = Thread(target=read_changes, daemon=True)
|
||||
t.start()
|
||||
testp = os.path.join(dpath, 'test')
|
||||
open(testp, 'w').close()
|
||||
t.join(2)
|
||||
self.assertTrue(events)
|
||||
for actions, path in events:
|
||||
self.assertEqual(os.path.join(dpath, path), testp)
|
||||
winutil.close_handle(dh)
|
||||
os.remove(testp)
|
||||
os.rmdir(dpath)
|
||||
|
||||
def test_sqlite(self):
|
||||
import sqlite3
|
||||
|
@ -225,15 +225,6 @@ winutil_set_max_stdio(PyObject *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
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};
|
||||
@ -392,6 +383,9 @@ extern PyObject *winutil_set_file_attributes(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_get_file_size(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_set_file_pointer(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_read_file(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_get_disk_free_space(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_move_file(PyObject *self, PyObject *args);
|
||||
extern PyObject *winutil_read_directory_changes(PyObject *self, PyObject *args);
|
||||
|
||||
static PyMethodDef winutil_methods[] = {
|
||||
{"special_folder_path", winutil_folder_path, METH_VARARGS,
|
||||
@ -503,6 +497,10 @@ be a unicode string. Returns unicode strings."
|
||||
"set_file_pointer(handle, chunk_size=16KB)\n\nWrapper for ReadFile"
|
||||
},
|
||||
|
||||
{"get_disk_free_space", (PyCFunction)winutil_get_disk_free_space, METH_VARARGS,
|
||||
"get_disk_free_space(path)\n\nWrapper for GetDiskFreeSpaceEx"
|
||||
},
|
||||
|
||||
{"close_handle", (PyCFunction)winutil_close_handle, METH_O,
|
||||
"close_handle(handle)\n\nWrapper for CloseHandle"
|
||||
},
|
||||
@ -523,6 +521,14 @@ be a unicode string. Returns unicode strings."
|
||||
"set_file_attributes(path, attrs)\n\nWrapper for SetFileAttributes"
|
||||
},
|
||||
|
||||
{"move_file", (PyCFunction)winutil_move_file, METH_VARARGS,
|
||||
"move_file(a, b, flags)\n\nWrapper for MoveFileEx"
|
||||
},
|
||||
|
||||
{"read_directory_changes", (PyCFunction)winutil_read_directory_changes, METH_VARARGS,
|
||||
"read_directory_changes(handle, buffer, subtree, flags)\n\nWrapper for ReadDirectoryChangesW"
|
||||
},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
@ -586,6 +592,27 @@ CALIBRE_MODINIT_FUNC PyInit_winutil(void) {
|
||||
PyModule_AddIntConstant(m, "FILE_BEGIN", FILE_BEGIN);
|
||||
PyModule_AddIntConstant(m, "FILE_CURRENT", FILE_CURRENT);
|
||||
PyModule_AddIntConstant(m, "FILE_END", FILE_END);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_COPY_ALLOWED", MOVEFILE_COPY_ALLOWED);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_CREATE_HARDLINK", MOVEFILE_CREATE_HARDLINK);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_DELAY_UNTIL_REBOOT", MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_FAIL_IF_NOT_TRACKABLE", MOVEFILE_FAIL_IF_NOT_TRACKABLE);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_REPLACE_EXISTING", MOVEFILE_REPLACE_EXISTING);
|
||||
PyModule_AddIntConstant(m, "MOVEFILE_WRITE_THROUGH", MOVEFILE_WRITE_THROUGH);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_FILE_NAME", FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_DIR_NAME", FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_ATTRIBUTES", FILE_NOTIFY_CHANGE_ATTRIBUTES);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_SIZE", FILE_NOTIFY_CHANGE_SIZE);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_LAST_WRITE", FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_LAST_ACCESS", FILE_NOTIFY_CHANGE_LAST_ACCESS);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_CREATION", FILE_NOTIFY_CHANGE_CREATION);
|
||||
PyModule_AddIntConstant(m, "FILE_NOTIFY_CHANGE_SECURITY", FILE_NOTIFY_CHANGE_SECURITY);
|
||||
PyModule_AddIntConstant(m, "FILE_ACTION_ADDED", FILE_ACTION_ADDED);
|
||||
PyModule_AddIntConstant(m, "FILE_ACTION_REMOVED", FILE_ACTION_REMOVED);
|
||||
PyModule_AddIntConstant(m, "FILE_ACTION_MODIFIED", FILE_ACTION_MODIFIED);
|
||||
PyModule_AddIntConstant(m, "FILE_ACTION_RENAMED_OLD_NAME", FILE_ACTION_RENAMED_OLD_NAME);
|
||||
PyModule_AddIntConstant(m, "FILE_ACTION_RENAMED_NEW_NAME", FILE_ACTION_RENAMED_NEW_NAME);
|
||||
PyModule_AddIntConstant(m, "FILE_LIST_DIRECTORY", FILE_LIST_DIRECTORY);
|
||||
PyModule_AddIntConstant(m, "FILE_FLAG_BACKUP_SEMANTICS", FILE_FLAG_BACKUP_SEMANTICS);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -165,6 +165,25 @@ set_error_from_file_handle(HANDLE h) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
PyObject*
|
||||
winutil_move_file(PyObject *self, PyObject *args) {
|
||||
wchar_raii a, b;
|
||||
unsigned int flags = MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH;
|
||||
if (!PyArg_ParseTuple(args, "O&O&|I", py_to_wchar_no_none, &a, py_to_wchar_no_none, &b, &flags)) return NULL;
|
||||
if (!MoveFileExW(a.ptr(), b.ptr(), flags))
|
||||
return PyErr_SetExcFromWindowsErrWithFilenameObjects(PyExc_OSError, 0, PyTuple_GET_ITEM(args, 0), PyTuple_GET_ITEM(args, 1));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
winutil_get_disk_free_space(PyObject *self, PyObject *args) {
|
||||
wchar_raii path;
|
||||
if (!PyArg_ParseTuple(args, "O&", py_to_wchar, &path)) return NULL;
|
||||
ULARGE_INTEGER bytes_available_to_caller, total_bytes, total_free_bytes;
|
||||
if (!GetDiskFreeSpaceEx(path.ptr(), &bytes_available_to_caller, &total_bytes, &total_free_bytes)) return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, PyTuple_GET_ITEM(args, 0));
|
||||
return Py_BuildValue("KKK", bytes_available_to_caller.QuadPart, total_bytes.QuadPart, total_free_bytes.QuadPart);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
winutil_read_file(PyObject *self, PyObject *args) {
|
||||
unsigned long chunk_size = 16 * 1024;
|
||||
@ -181,6 +200,38 @@ winutil_read_file(PyObject *self, PyObject *args) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
winutil_read_directory_changes(PyObject *self, PyObject *args) {
|
||||
PyObject *buffer, *handle; int watch_subtree; unsigned long filter;
|
||||
if (!PyArg_ParseTuple(args, "O!O!pk", &PyLong_Type, &handle, &PyBytes_Type, &buffer, &watch_subtree, &filter)) return NULL;
|
||||
DWORD bytes_returned;
|
||||
BOOL ok;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
ok = ReadDirectoryChangesW(PyLong_AsVoidPtr(handle), PyBytes_AS_STRING(buffer), (DWORD)PyBytes_GET_SIZE(buffer), watch_subtree, filter, &bytes_returned, NULL, NULL);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (!ok) return set_error_from_file_handle(PyLong_AsVoidPtr(handle));
|
||||
PFILE_NOTIFY_INFORMATION p;
|
||||
size_t offset = 0;
|
||||
PyObject *ans = PyList_New(0);
|
||||
if (!ans) return NULL;
|
||||
if (bytes_returned) {
|
||||
do {
|
||||
p = (PFILE_NOTIFY_INFORMATION)(PyBytes_AS_STRING(buffer) + offset);
|
||||
offset += p->NextEntryOffset;
|
||||
if (p->FileNameLength) {
|
||||
PyObject *temp = Py_BuildValue("ku#", p->Action, p->FileName, p->FileNameLength / sizeof(wchar_t));
|
||||
if (!temp) { Py_DECREF(ans); return NULL; }
|
||||
int ret = PyList_Append(ans, temp);
|
||||
Py_DECREF(temp);
|
||||
if (ret != 0) { Py_DECREF(ans); return NULL; }
|
||||
}
|
||||
} while(p->NextEntryOffset);
|
||||
} else {
|
||||
Py_CLEAR(ans);
|
||||
PyErr_SetString(PyExc_OverflowError, "the change events buffer overflowed, something has changed");
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
winutil_get_file_size(PyObject *self, PyObject *pyhandle) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user