SSHクライアントを介してファイルを送信するGoコードを読んでいました。
https://github.com/tmc/scp/blob/master/scp.go#L
それが行うことの1つはscp -t /remote/path
。それは何ですか -t
フラグ? man scp
、しかしそれは文書化されていないようです。コマンドをローカルで実行したところ、猫のように動作しているようです。
実行後scp -t
リモートで、コードは次のようにバイトをサーバーに送信します。
// 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")
このプロトコルは何ですか?どこに文書化されていますか?
申し訳ありませんが、scpプロトコルは scp.c
のソースコード以外のドキュメントには記載されていません。そのため、scp
の動作の概要を説明します。
ソースまたは宛先のいずれかがリモートマシンである場合、scp
はssh
を使用して接続し、scp
プログラムを開始します。コピー方向がリモートからローカルである場合、scp -f src
((from/source)、それ以外の場合はscp -t dst
(to/sink)として開始され、ローカルのscp
は反対の姿勢をとります。
この後、2つのscpプロセスがscp接続の両端で実行され、それをstdin/stdoutとして使用して、ファイルデータとメタデータを渡します。
両端では、次の応答を使用してメッセージを確認したり、エラー状態を通知したりできます。
"\0"
:OK
"\1%s\n", err_msg
:致命的でないエラー
"\2%s\n", err_msg
:致命的なエラー
転送は、to/sink scpが\0
(OK)ackを送信することから始まります。
次に、from/source scpは次のメッセージを使用します。
"C%04o %lld %s\n", mode, size, filename
:ファイルを作成
この後には、size
バイトのファイルデータとack(\0
= OK)が続きます。
"D%04o 0 %.1024s\n", mode, dirname
:ディレクトリの開始
C
、D
、またはT
メッセージが再帰的に続き、
"E\n"
:ディレクトリの終わり
"T%llu 0 %llu 0\n", mtime, atime
:ファイル時間
これは、-p
スイッチが使用された場合、C
またはD
メッセージの前に送信されます。
これらのメッセージは、ファイルデータを送信する前のC
とその後に送信されたackを含めて、先に進む前に相手側から確認応答を受ける必要があります。
上記のC
およびD
メッセージでは、ファイル/ディレクトリ名の改行およびその他の制御文字(\t
および\x7f
を除く)は、たとえば次のようにエスケープされます。 \^J
、ただし、宛先ではエスケープ解除されません。元の名前のリテラル\^J
または\^M
はそのまま残されます。
致命的なエラーと致命的でないエラーの違いは一貫していません。どちらかの側で\1
(致命的ではない)エラーのみが生成されますが、それらのいくつかは致命的と見なされ、scp
は送信または受信時に終了し、反対側は両方の部分を保持します。両側は\2
(致命的)エラーまたは予期しない何かで終了します。
Httpとは異なり、ファイルデータをチャンクで送信するための規定はありません。ソースscp
が、C
メッセージの後に送信を開始した大きなファイルを読み取ることができなくなった場合、\1
エラーメッセージ/ nakの前に、そのsize
NULバイトまで送信します。