I was reading some Go code that sends a file over an SSH client.
https://github.com/tmc/scp/blob/master/scp.go#L33
One of the things it does is a scp -t /remote/path
. What is that -t
flag for? I did a man scp
, but it doesn't seem to be documented. I ran the command locally and it seems to behave like cat.
After running scp -t
remotely, the code then sends bytes to the server like this.
// Some special control header? What is this?
fmt.Fprintf(w, "C%#o %d %s\n", mode, size, fileName)
// Send file bytes.
io.Copy(w, contents)
// Send termination signal?
fmt.Fprint(w, "\x00")
What is this protocol? Is it documented anywhere?
Best Answer
AFAIK, the scp protocol isn't documented anywhere else than it the source code of
scp.c
, so here is an attempt to an outline of howscp
works.When either the source or the destination is a remote machine,
scp
will usessh
to connect and start ascp
program on it: if the copy direction is from the remote to the local, it will be started asscp -f src
(from / source), otherwise it will be started asscp -t dst
(to / sink), and the localscp
will assume the opposite posture.After this the two scp processes are running on both ends of the scp connection, using it as their stdin/stdout and passing the file data and metadata over it.
Both ends could use the following responses to acknowledge messages or signal some error condition:
"\0"
: OK"\1%s\n", err_msg
: non-fatal error"\2%s\n", err_msg
: fatal errorThe transfer starts by the to / sink scp sending a
\0
(OK) ack.Then the from / source scp will use the following messages:
"C%04o %lld %s\n", mode, size, filename
: create a filethis is followed by
size
bytes of file data, and an ack (\0
= OK)"D%04o 0 %.1024s\n", mode, dirname
: start of directoryrecursively followed by
C
,D
orT
messages, until a"E\n"
: end of directory"T%llu 0 %llu 0\n", mtime, atime
: file timesthis is sent before the
C
orD
messages, if the-p
switch was used.These messages will have to be ack'ed by the other side before proceding further, including the
C
before sending the file data, and the ack sent after it.In the
C
andD
messages above, newlines and other control chars (except\t
and\x7f
) in the file/dir name will be escaped as eg.\^J
, but will not be unescaped at the destination; a literal\^J
or\^M
in the original name will be left as-is.The difference between fatal and non-fatal errors is not consistent; only
\1
(non-fatal) errors will be generated by either side, but some of them will be considered fatal, andscp
will exit upon sending or receiving them, leaving the other side to hold both pieces. Both sides will exit upon a\2
(fatal) error or anything unexpected.Unlike in http, there are no provisions for sending the file data by chunks; if the source
scp
is no longer able to read some big file it has started sending after theC
message, it will send up to itssize
NUL bytes before the\1
error message / nak.