summaryrefslogtreecommitdiff
path: root/linuxnamespaces
diff options
context:
space:
mode:
Diffstat (limited to 'linuxnamespaces')
-rw-r--r--linuxnamespaces/__init__.py41
1 files changed, 37 insertions, 4 deletions
diff --git a/linuxnamespaces/__init__.py b/linuxnamespaces/__init__.py
index a39ab1d..65dfc8d 100644
--- a/linuxnamespaces/__init__.py
+++ b/linuxnamespaces/__init__.py
@@ -585,6 +585,39 @@ def unshare_user_idmap_nohelper(
newidmaps(-1, [uidmap], [gidmap], False)
+class _AsyncFilesender:
+ bs = 65536
+
+ def __init__(self, from_fd: int, to_fd: int, count: int | None = None):
+ self.from_fd = from_fd
+ self.to_fd = to_fd
+ self.copied = 0
+ self.remain = count
+ self.loop = asyncio.get_running_loop()
+ self.fut: asyncio.Future[int] = self.loop.create_future()
+ self.loop.add_writer(self.to_fd, self.handle_write)
+
+ def handle_write(self) -> None:
+ try:
+ ret = os.sendfile(
+ self.to_fd,
+ self.from_fd,
+ None,
+ self.bs if self.remain is None else min(self.bs, self.remain),
+ )
+ except OSError as err:
+ if err.errno != errno.EAGAIN:
+ self.loop.remove_writer(self.to_fd)
+ self.fut.set_exception(err)
+ else:
+ self.copied += ret
+ if self.remain is not None:
+ self.remain -= ret
+ if ret == 0 or self.remain == 0:
+ self.loop.remove_writer(self.to_fd)
+ self.fut.set_result(self.copied)
+
+
class _AsyncSplicer:
bs = 65536
@@ -703,10 +736,10 @@ def async_copyfd(
binary. An efficient implementation is chosen depending on the file type
of file descriptors.
"""
- if (
- stat.S_ISFIFO(os.fstat(from_fd).st_mode)
- or stat.S_ISFIFO(os.fstat(to_fd).st_mode)
- ):
+ from_mode = os.fstat(from_fd).st_mode
+ if stat.S_ISREG(from_mode):
+ return _AsyncFilesender(from_fd, to_fd, count).fut
+ if stat.S_ISFIFO(from_mode) or stat.S_ISFIFO(os.fstat(to_fd).st_mode):
return _AsyncSplicer(from_fd, to_fd, count).fut
return _AsyncCopier(from_fd, to_fd, count).fut