summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2018-06-12 21:04:50 (GMT)
committerGitHub <noreply@github.com>2018-06-12 21:04:50 (GMT)
commit4a172ccc739065bb658c75e8929774a8e94af9e9 (patch)
tree7f76b26eccd0de5d4b697138fdbe120028d03e9e /Modules
parent33cd058f21d0673253c88cea70388282918992bc (diff)
downloadcpython-4a172ccc739065bb658c75e8929774a8e94af9e9.zip
cpython-4a172ccc739065bb658c75e8929774a8e94af9e9.tar.gz
cpython-4a172ccc739065bb658c75e8929774a8e94af9e9.tar.bz2
bpo-33671: efficient zero-copy for shutil.copy* functions (Linux, OSX and Win) (#7160)
* have shutil.copyfileobj use sendfile() if possible * refactoring: use ctx manager * add test with non-regular file obj * emulate case where file size can't be determined * reference _copyfileobj_sendfile directly * add test for offset() at certain position * add test for empty file * add test for non regular file dst * small refactoring * leave copyfileobj() alone in order to not introduce any incompatibility * minor refactoring * remove old test * update docstring * update docstring; rename exception class * detect platforms which only support file to socket zero copy * don't run test on platforms where file-to-file zero copy is not supported * use tempfiles * reset verbosity * add test for smaller chunks * add big file size test * add comment * update doc * update whatsnew doc * update doc * catch Exception * remove unused import * add test case for error on second sendfile() call * turn docstring into comment * add one more test * update comment * add Misc/NEWS entry * get rid of COPY_BUFSIZE; it belongs to another PR * update doc * expose posix._fcopyfile() for OSX * merge from linux branch * merge from linux branch * expose fcopyfile * arg clinic for the win implementation * convert path type to path_t * expose CopyFileW * fix windows tests * release GIL * minor refactoring * update doc * update comment * update docstrings * rename functions * rename test classes * update doc * update doc * update docstrings and comments * avoid do import nt|posix modules if unnecessary * set nt|posix modules to None if not available * micro speedup * update description * add doc note * use better wording in doc * rename function using 'fastcopy' prefix instead of 'zerocopy' * use :ref: in rst doc * change wording in doc * add test to make sure sendfile() doesn't get called aymore in case it doesn't support file to file copies * move CopyFileW in _winapi and actually expose CopyFileExW instead * fix line endings * add tests for mode bits * add docstring * remove test file mode class; let's keep it for later when Istart addressing OSX fcopyfile() specific copies * update doc to reflect new changes * update doc * adjust tests on win * fix argument clinic error * update doc * OSX: expose copyfile(3) instead of fcopyfile(3); also expose flags arg to python * osx / copyfile: use path_t instead of char * do not set dst name in the OSError exception in order to remain consistent with platforms which cannot do that (e.g. linux) * add same file test * add test for same file * have osx copyfile() pre-emptively check if src and dst are the same, otherwise it will return immedialtey and src file content gets deleted * turn PermissionError into appropriate SameFileError * expose ERROR_SHARING_VIOLATION in order to raise more appropriate SameFileError * honour follow_symlinks arg when using CopyFileEx * update Misc/NEWS * expose CreateDirectoryEx mock * change C type * CreateDirectoryExW actual implementation * provide specific makedirs() implementation for win * fix typo * skeleton for SetNamedSecurityInfo * get security info for src path * finally set security attrs * add unit tests * mimick os.makedirs() behavior and raise if dst dir exists * set 2 paths for OSError object * set 2 paths for OSError object * expand windows test * in case of exception on os.sendfile() set filename and filename2 exception attributes * set 2 filenames (src, dst) for OSError in case copyfile() fails on OSX * update doc * do not use CreateDirectoryEx() in copytree() if source dir is a symlink (breaks test_copytree_symlink_dir); instead just create a plain dir and remain consistent with POSIX implementation * use bytearray() and readinto() * use memoryview() with bytearray() * refactoring + introduce a new _fastcopy_binfileobj() fun * remove CopyFileEx and other C wrappers * remove code related to CopyFileEx * Recognize binary files in copyfileobj() ...and use fastest _fastcopy_binfileobj() when possible * set 1MB copy bufsize on win; also add a global _COPY_BUFSIZE variable * use ctx manager for memoryview() * update doc * remove outdated doc * remove last CopyFileEx remnants * OSX - use fcopyfile(3) instead of copyfile(3) ...as an extra safety measure: in case src/dst are "exotic" files (non regular or living on a network fs etc.) we better fail on open() instead of copyfile(3) as we're not quite sure what's gonna happen in that case. * update doc
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_winapi.c3
-rw-r--r--Modules/clinic/posixmodule.c.h40
-rw-r--r--Modules/posixmodule.c37
3 files changed, 78 insertions, 2 deletions
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index c596cba..75d1f06 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -163,6 +163,7 @@ create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "')
create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
create_converter('LPCTSTR', 's')
+create_converter('LPCWSTR', 'u')
create_converter('LPWSTR', 'u')
create_converter('UINT', 'I') # F_UINT used previously (always 'I')
@@ -186,7 +187,7 @@ class DWORD_return_converter(CReturnConverter):
data.return_conversion.append(
'return_value = Py_BuildValue("k", _return_value);\n')
[python start generated code]*/
-/*[python end generated code: output=da39a3ee5e6b4b0d input=4527052fe06e5823]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=27456f8555228b62]*/
#include "clinic/_winapi.c.h"
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index e4bbd08..c41d131 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -3853,6 +3853,40 @@ exit:
return return_value;
}
+#if defined(__APPLE__)
+
+PyDoc_STRVAR(os__fcopyfile__doc__,
+"_fcopyfile($module, infd, outfd, flags, /)\n"
+"--\n"
+"\n"
+"Efficiently copy content or metadata of 2 regular file descriptors (OSX).");
+
+#define OS__FCOPYFILE_METHODDEF \
+ {"_fcopyfile", (PyCFunction)os__fcopyfile, METH_FASTCALL, os__fcopyfile__doc__},
+
+static PyObject *
+os__fcopyfile_impl(PyObject *module, int infd, int outfd, int flags);
+
+static PyObject *
+os__fcopyfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int infd;
+ int outfd;
+ int flags;
+
+ if (!_PyArg_ParseStack(args, nargs, "iii:_fcopyfile",
+ &infd, &outfd, &flags)) {
+ goto exit;
+ }
+ return_value = os__fcopyfile_impl(module, infd, outfd, flags);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(__APPLE__) */
+
PyDoc_STRVAR(os_fstat__doc__,
"fstat($module, /, fd)\n"
"--\n"
@@ -6414,6 +6448,10 @@ exit:
#define OS_PREADV_METHODDEF
#endif /* !defined(OS_PREADV_METHODDEF) */
+#ifndef OS__FCOPYFILE_METHODDEF
+ #define OS__FCOPYFILE_METHODDEF
+#endif /* !defined(OS__FCOPYFILE_METHODDEF) */
+
#ifndef OS_PIPE_METHODDEF
#define OS_PIPE_METHODDEF
#endif /* !defined(OS_PIPE_METHODDEF) */
@@ -6589,4 +6627,4 @@ exit:
#ifndef OS_GETRANDOM_METHODDEF
#define OS_GETRANDOM_METHODDEF
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
-/*[clinic end generated code: output=8d3d9dddf254c3c2 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b5d1ec71bc6f0651 input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 247af1b..24d8be6 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -97,6 +97,10 @@ corresponding Unix manual entries for more information on calls.");
#include <sys/sendfile.h>
#endif
+#if defined(__APPLE__)
+#include <copyfile.h>
+#endif
+
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
@@ -8742,6 +8746,34 @@ done:
#endif /* HAVE_SENDFILE */
+#if defined(__APPLE__)
+/*[clinic input]
+os._fcopyfile
+
+ infd: int
+ outfd: int
+ flags: int
+ /
+
+Efficiently copy content or metadata of 2 regular file descriptors (OSX).
+[clinic start generated code]*/
+
+static PyObject *
+os__fcopyfile_impl(PyObject *module, int infd, int outfd, int flags)
+/*[clinic end generated code: output=8e8885c721ec38e3 input=aeb9456804eec879]*/
+{
+ int ret;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcopyfile(infd, outfd, NULL, flags);
+ Py_END_ALLOW_THREADS
+ if (ret < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+
/*[clinic input]
os.fstat
@@ -12918,6 +12950,7 @@ static PyMethodDef posix_methods[] = {
OS_UTIME_METHODDEF
OS_TIMES_METHODDEF
OS__EXIT_METHODDEF
+ OS__FCOPYFILE_METHODDEF
OS_EXECV_METHODDEF
OS_EXECVE_METHODDEF
OS_SPAWNV_METHODDEF
@@ -13537,6 +13570,10 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
#endif
+#if defined(__APPLE__)
+ if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1;
+#endif
+
return 0;
}