commit: c6d2f47243bcedd4f491db5cbe316c2a261e4da3
Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Nov 9 19:56:54 2019 +0000
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Nov 9 20:42:26 2019 +0000
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=c6d2f472
FileCopier: native zero-copy and sparse file support
Use native copyfile for zero-copy and sparse file support, and copy
permission bits like shutil.copy.
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>
lib/portage/tests/util/test_file_copier.py | 4 ++++
lib/portage/util/_async/FileCopier.py | 16 +++++++++++++---
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/lib/portage/tests/util/test_file_copier.py
b/lib/portage/tests/util/test_file_copier.py
index 01dfba494..3f1ec6b78 100644
--- a/lib/portage/tests/util/test_file_copier.py
+++ b/lib/portage/tests/util/test_file_copier.py
@@ -4,6 +4,7 @@
import errno
import os
import shutil
+import stat
import tempfile
from portage.tests import TestCase
@@ -22,8 +23,10 @@ class FileCopierTestCase(TestCase):
src_path = os.path.join(tempdir, 'src')
dest_path = os.path.join(tempdir, 'dest')
content = b'foo'
+ file_mode = 0o600
with open(src_path, 'wb') as f:
f.write(content)
+ os.chmod(src_path, file_mode)
copier = FileCopier(src_path=src_path,
dest_path=dest_path, scheduler=loop)
copier.start()
loop.run_until_complete(copier.async_wait())
@@ -31,6 +34,7 @@ class FileCopierTestCase(TestCase):
copier.future.result()
with open(dest_path, 'rb') as f:
self.assertEqual(f.read(), content)
+ self.assertEqual(file_mode,
stat.S_IMODE(os.stat(dest_path).st_mode))
# failure due to nonexistent src_path
src_path = os.path.join(tempdir, 'does-not-exist')
diff --git a/lib/portage/util/_async/FileCopier.py
b/lib/portage/util/_async/FileCopier.py
index 3a0be4b63..d9077411d 100644
--- a/lib/portage/util/_async/FileCopier.py
+++ b/lib/portage/util/_async/FileCopier.py
@@ -1,7 +1,11 @@
# Copyright 2013-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
-from portage import shutil
+import os as _os
+
+from portage import _encodings, _unicode_encode
+from portage.util import apply_stat_permissions
+from portage.util.file_copy import copyfile
from portage.util.futures import asyncio
from portage.util.futures.executor.fork import ForkExecutor
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture
@@ -14,6 +18,12 @@ class FileCopier(AsyncTaskFuture):
__slots__ = ('src_path', 'dest_path')
def _start(self):
- self.future =
asyncio.ensure_future(self.scheduler.run_in_executor(ForkExecutor(loop=self.scheduler),
- shutil.copy, self.src_path, self.dest_path))
+ self.future =
asyncio.ensure_future(self.scheduler.run_in_executor(
+ ForkExecutor(loop=self.scheduler), self._run))
super(FileCopier, self)._start()
+
+ def _run(self):
+ src_path = _unicode_encode(self.src_path,
encoding=_encodings['fs'], errors='strict')
+ dest_path = _unicode_encode(self.dest_path,
encoding=_encodings['fs'], errors='strict')
+ copyfile(src_path, dest_path)
+ apply_stat_permissions(dest_path, _os.stat(src_path))