I am currently working on a project that involves server-side file copy operations using Paramiko's SFTP on the server side. I am seeking guidance on how to implement server-side file copy operations with Paramiko. Specifically, I want to add a custom extension or hook to Paramiko that supports a "copy-file" operation.
Details:
Observations:
I have explored the Paramiko documentation and examples, but I couldn't find clear guidance on implementing server-side file copy operations. I attempted to modify the extension_pairs
in paramiko/sftp.py
(line 161) to ["copy-file", "md5,sha1"], but it doesn't seem to be recognized. I suspect this is definitely not be the correct approach, and I'm looking for guidance on the proper way to add a custom extension.
here's what I think the useful part of the log of client side to represent it's not working
debug2: channel_input_status_confirm: type 99 id 0
debug2: subsystem request accepted on channel 0
debug2: Remote version: 3
debug2: Unrecognised server extension "copy-data"
Connected to 127.0.0.1.
debug2: Sending SSH2_FXP_REALPATH "."
debug3: Sent message fd 6 T:16 I:1
debug3: SSH2_FXP_REALPATH . -> /
sftp> cp foo bart
Server does not support copy-data extension
Questions:
Thanks to anyone who can guide me on the right path or provide insights into implementing server-side file copy with Paramiko.
This question is also asked on github issue: https://github.com/paramiko/paramiko/issues/2336
Paramiko SFTPServer
class does not seem to have any mechanism to implement custom extensions.
All you can do is to override the _process
method and handle the t == CMD_EXTENDED
on your own. But you will have to implement all (both) existing extensions again.
Something like:
class MySFTPServer(SFTPServer):
def _process(self, t, request_number, msg):
if t == CMD_EXTENDED:
# Copy of CMD_EXTENDED implementation from SFTPServer._process
tag = msg.get_text()
if tag == "check-file":
self._check_file(request_number, msg)
elif tag == "posix-rename@openssh.com":
oldpath = msg.get_text()
newpath = msg.get_text()
self._send_status(
request_number, self.server.posix_rename(oldpath, newpath)
)
elif tag == "copy-file":
oldpath = msg.get_text()
newpath = msg.get_text()
# Your copy-file implementation
# ...
else:
self._send_status(request_number, SFTP_OP_UNSUPPORTED)
else:
super(SFTPServer, self)._process(t, request_number, msg)
(untested)
And similarly you need to reimplement _send_server_version
to announce copy-file
support. What you have tried already, but with wrong syntax. It's not obvious to me, what the right syntax is though. Maybe:
extension_pairs = [["check-file", "md5,sha1"], ["copy-data", "1"]]
Though note that the OpenSSH sftp
client does not support the copy-file
extension. It supports the copy-data
.