summaryrefslogtreecommitdiff
path: root/test/test_custom_io.py
diff options
context:
space:
mode:
authorTofik Sonono <tofik.sonono@intel.com>2023-01-10 10:04:35 +0000
committerGitHub <noreply@github.com>2023-01-10 10:04:35 +0000
commit50c74e645928affa1af6e9a5a6ea6a3b9d3c52dc (patch)
tree58f7deff5dfca5ba8ec3a757ddcb04c535eea48e /test/test_custom_io.py
parentc0a344e3797844896d04efc4b565a2627067b67f (diff)
downloadfuse-50c74e645928affa1af6e9a5a6ea6a3b9d3c52dc.tar.gz
Support application-defined I/O functions for FUSE fd
The io for FUSE requests and responses can now be further customized by allowing to write custom functions for reading/writing the responses. This includes overriding the splice io. The reason for this addition is that having a custom file descriptor is not sufficient to allow custom io. Different types of file descriptor require different mechanisms of io interaction. For example, some file descriptor communication has boundaries (SOCK_DGRAM, EOF, etc...), while other types of fd:s might be unbounded (SOCK_STREAMS, ...). For unbounded communication, you have to read the header of the FUSE request first, and then read the remaining packet data. Furthermore, the one read call does not necessarily return all the data expected, requiring further calls in a loop.
Diffstat (limited to 'test/test_custom_io.py')
-rw-r--r--test/test_custom_io.py81
1 files changed, 81 insertions, 0 deletions
diff --git a/test/test_custom_io.py b/test/test_custom_io.py
new file mode 100644
index 0000000..737b939
--- /dev/null
+++ b/test/test_custom_io.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+
+if __name__ == '__main__':
+ import sys
+
+ import pytest
+ sys.exit(pytest.main([__file__] + sys.argv[1:]))
+
+import os
+import socket
+import struct
+import subprocess
+import sys
+import time
+from os.path import join as pjoin
+
+import pytest
+
+from util import base_cmdline, basename
+
+FUSE_OP_INIT = 26
+
+FUSE_MAJOR_VERSION = 7
+FUSE_MINOR_VERSION = 38
+
+fuse_in_header_fmt = '<IIQQIIII'
+fuse_out_header_fmt = '<IiQ'
+
+fuse_init_in_fmt = '<IIIII44x'
+fuse_init_out_fmt = '<IIIIHHIIHHI28x'
+
+
+def sock_recvall(sock: socket.socket, bufsize: int) -> bytes:
+ buf = bytes()
+ while len(buf) < bufsize:
+ buf += sock.recv(bufsize - len(buf))
+ return buf
+
+
+def tst_init(sock: socket.socket):
+ unique_req = 10
+ dummy_init_req_header = struct.pack(
+ fuse_in_header_fmt, struct.calcsize(fuse_in_header_fmt) +
+ struct.calcsize(fuse_init_in_fmt), FUSE_OP_INIT, unique_req, 0, 0, 0,
+ 0, 0)
+ dummy_init_req_payload = struct.pack(
+ fuse_init_in_fmt, FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION, 0, 0, 0)
+ dummy_init_req = dummy_init_req_header + dummy_init_req_payload
+
+ sock.sendall(dummy_init_req)
+
+ response_header = sock_recvall(sock, struct.calcsize(fuse_out_header_fmt))
+ packet_len, _, unique_res = struct.unpack(
+ fuse_out_header_fmt, response_header)
+ assert unique_res == unique_req
+
+ response_payload = sock_recvall(sock, packet_len - len(response_header))
+ response_payload = struct.unpack(fuse_init_out_fmt, response_payload)
+ assert response_payload[0] == FUSE_MAJOR_VERSION
+
+
+def test_hello_uds(output_checker):
+ cmdline = base_cmdline + [pjoin(basename, 'example', 'hello_ll_uds')]
+ print(cmdline)
+ uds_process = subprocess.Popen(cmdline, stdout=output_checker.fd,
+ stderr=output_checker.fd)
+ time.sleep(1)
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.settimeout(1)
+ sock.connect("/tmp/libfuse-hello-ll.sock")
+
+ tst_init(sock)
+
+ sock.close()
+ uds_process.terminate()
+ try:
+ uds_process.wait(1)
+ except subprocess.TimeoutExpired:
+ uds_process.kill()
+ os.remove("/tmp/libfuse-hello-ll.sock")