在Go中通过SSH发送文件

I found this answer before posting this question but the answer is not clear to me.

Here is the code of the answer:

conn, err := ssh.Dial("tcp", hostname+":22", config)
if err != nil {
    return err
}

session, err := conn.NewSession()
if err != nil {
    return err
}
defer session.Close()

r, err := session.StdoutPipe()
if err != nil {
    return err
}

name := fmt.Sprintf("%s/backup_folder_%v.tar.gz", path, time.Now().Unix())
file, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    return err
}
defer file.Close()

if err := session.Start(cmd); err != nil {
    return err
}

n, err := io.Copy(file, r)
if err != nil {
    return err
}

if err := session.Wait(); err != nil {
    return err
}

return nil

I don't understand relation between the cmd variable and io.Copy, where and how does it know which file to copy. I like the idea of using io.Copy but i do not know how to create the file via ssh and start sending content to it using io.Copy.

Here is a minimal example on how to use Go as an scp client:

config := &ssh.ClientConfig{
    User: "user",
    Auth: []ssh.AuthMethod{
        ssh.Password("pass"),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

client, _ := ssh.Dial("tcp", "remotehost:22", config)
defer client.Close()

session, _ := client.NewSession()
defer session.Close()

file, _ := os.Open("filetocopy")
defer file.Close()
stat, _ := file.Stat()

wg := sync.WaitGroup{}
wg.Add(1)

go func() {
    hostIn, _ := session.StdinPipe()
    defer hostIn.Close()
    fmt.Fprintf(hostIn, "C0664 %d %s
", stat.Size(), "filecopyname")
    io.Copy(hostIn, file)
    fmt.Fprint(hostIn, "\x00")
    wg.Done()
}()

session.Run("/usr/bin/scp -t /remotedirectory/")
wg.Wait()

Note that I have ignored all errors only for conciseness.

  1. session.StdinPipe() will create a writable pipe for the remote host.
  2. fmt.Fprintf(... "C0664 ...") will signal the start of a file with 0664 permission, stat.Size() size and the remote filename filecopyname.
  3. io.Copy(hostIn, file) will write the contents of file into hostIn.
  4. fmt.Fprint(hostIn, "\x00") will signal the end of the file.
  5. session.Run("/usr/bin/scp -qt /remotedirectory/") will run the scp command.

Edit: Added waitgroup per OP's request