gh-88745: Add _winapi.CopyFile2 and update shutil.copy2 to use it (GH-105055)

This commit is contained in:
Steve Dower 2023-05-30 11:00:29 +01:00 committed by GitHub
parent d14eb3433c
commit cda1bd3c9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 210 additions and 1 deletions

View file

@ -1947,6 +1947,7 @@ _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
return result;
}
/*[clinic input]
_winapi._mimetypes_read_windows_registry
@ -2075,6 +2076,67 @@ _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module,
return result;
}
/*[clinic input]
_winapi.CopyFile2
existing_file_name: LPCWSTR
new_file_name: LPCWSTR
flags: DWORD
progress_routine: object = None
Copies a file from one name to a new name.
This is implemented using the CopyFile2 API, which preserves all stat
and metadata information apart from security attributes.
progress_routine is reserved for future use, but is currently not
implemented. Its value is ignored.
[clinic start generated code]*/
static PyObject *
_winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name,
LPCWSTR new_file_name, DWORD flags,
PyObject *progress_routine)
/*[clinic end generated code: output=43d960d9df73d984 input=fb976b8d1492d130]*/
{
HRESULT hr;
COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) };
if (PySys_Audit("_winapi.CopyFile2", "uuI",
existing_file_name, new_file_name, flags) < 0) {
return NULL;
}
params.dwCopyFlags = flags;
/* For future implementation. We ignore the value for now so that
users only have to test for 'CopyFile2' existing and not whether
the additional parameter exists.
if (progress_routine != Py_None) {
params.pProgressRoutine = _winapi_CopyFile2ProgressRoutine;
params.pvCallbackContext = Py_NewRef(progress_routine);
}
*/
Py_BEGIN_ALLOW_THREADS;
hr = CopyFile2(existing_file_name, new_file_name, &params);
Py_END_ALLOW_THREADS;
/* For future implementation.
if (progress_routine != Py_None) {
Py_DECREF(progress_routine);
}
*/
if (FAILED(hr)) {
if ((hr & 0xFFFF0000) == 0x80070000) {
PyErr_SetFromWindowsErr(hr & 0xFFFF);
} else {
PyErr_SetFromWindowsErr(hr);
}
return NULL;
}
Py_RETURN_NONE;
}
static PyMethodDef winapi_functions[] = {
_WINAPI_CLOSEHANDLE_METHODDEF
_WINAPI_CONNECTNAMEDPIPE_METHODDEF
@ -2110,6 +2172,7 @@ static PyMethodDef winapi_functions[] = {
_WINAPI_GETFILETYPE_METHODDEF
_WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
_WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
_WINAPI_COPYFILE2_METHODDEF
{NULL, NULL}
};
@ -2146,6 +2209,7 @@ static int winapi_exec(PyObject *m)
WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
WINAPI_CONSTANT(F_DWORD, ERROR_ACCESS_DENIED);
WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
@ -2159,6 +2223,7 @@ static int winapi_exec(PyObject *m)
WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
WINAPI_CONSTANT(F_DWORD, ERROR_PRIVILEGE_NOT_HELD);
WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
@ -2252,6 +2317,34 @@ static int winapi_exec(PyObject *m)
WINAPI_CONSTANT(F_DWORD, LCMAP_TRADITIONAL_CHINESE);
WINAPI_CONSTANT(F_DWORD, LCMAP_UPPERCASE);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_ALLOW_DECRYPTED_DESTINATION);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_COPY_SYMLINK);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_FAIL_IF_EXISTS);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_BUFFERING);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_OFFLOAD);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_OPEN_SOURCE_FOR_WRITE);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESTARTABLE);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_SECURITY_PRIVILEGES);
WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESUME_FROM_PAUSE);
#ifndef COPY_FILE_REQUEST_COMPRESSED_TRAFFIC
// Only defined in newer WinSDKs
#define COPY_FILE_REQUEST_COMPRESSED_TRAFFIC 0x10000000
#endif
WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_COMPRESSED_TRAFFIC);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_STARTED);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_FINISHED);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_STARTED);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_FINISHED);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_POLL_CONTINUE);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_ERROR);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CONTINUE);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CANCEL);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_STOP);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_QUIET);
WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_PAUSE);
WINAPI_CONSTANT("i", NULL);
return 0;