diff options
author | Helmut Grohne <helmut@subdivi.de> | 2024-05-28 09:28:23 +0200 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2024-05-28 09:28:23 +0200 |
commit | e409043556c6fe54efc213daa083d679a37c2a03 (patch) | |
tree | 569990296cfadc2354920f3c2d3aaf209b69bf9f /linuxnamespaces | |
parent | 9b4ff5641a583ca4fa305165e460213d8201b2d9 (diff) | |
download | python-linuxnamespaces-e409043556c6fe54efc213daa083d679a37c2a03.tar.gz |
support sendfile in async_copyfd
Diffstat (limited to 'linuxnamespaces')
-rw-r--r-- | linuxnamespaces/__init__.py | 41 |
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 |