WriteFile reads size bytes from the reader and writes them to a file on the remote machine
(reader io.Reader, size int64, etargetFile string)
| 482 | |
| 483 | // WriteFile reads size bytes from the reader and writes them to a file on the remote machine |
| 484 | func (ssh_conf *MakeConfig) WriteFile(reader io.Reader, size int64, etargetFile string) error { |
| 485 | targetFile := filepath.Base(etargetFile) |
| 486 | // Reject characters that would either inject extra SCP control records |
| 487 | // (\n, \r) or terminate the filename field early (\x00). The remote-side |
| 488 | // scp command is invoked through the user's shell, so etargetFile is |
| 489 | // single-quoted below to neutralise shell metacharacters. |
| 490 | if strings.ContainsAny(etargetFile, "\x00\n\r") || strings.ContainsAny(targetFile, "\x00\n\r") { |
| 491 | return ErrInvalidTargetFile |
| 492 | } |
| 493 | |
| 494 | session, client, err := ssh_conf.Connect() |
| 495 | if err != nil { |
| 496 | return err |
| 497 | } |
| 498 | defer func() { _ = client.Close() }() |
| 499 | defer func() { _ = session.Close() }() |
| 500 | |
| 501 | w, err := session.StdinPipe() |
| 502 | if err != nil { |
| 503 | return err |
| 504 | } |
| 505 | |
| 506 | copyF := func() error { |
| 507 | _, err := fmt.Fprintln(w, "C0644", size, targetFile) |
| 508 | if err != nil { |
| 509 | return err |
| 510 | } |
| 511 | |
| 512 | if size > 0 { |
| 513 | _, err = io.Copy(w, reader) |
| 514 | if err != nil { |
| 515 | return err |
| 516 | } |
| 517 | } |
| 518 | |
| 519 | _, err = fmt.Fprint(w, "\x00") |
| 520 | if err != nil { |
| 521 | return err |
| 522 | } |
| 523 | |
| 524 | return nil |
| 525 | } |
| 526 | |
| 527 | copyErrC := make(chan error, 1) |
| 528 | go func() { |
| 529 | defer func() { _ = w.Close() }() |
| 530 | copyErrC <- copyF() |
| 531 | }() |
| 532 | |
| 533 | err = session.Run("scp -tr " + shellQuote(etargetFile)) |
| 534 | if err != nil { |
| 535 | return err |
| 536 | } |
| 537 | |
| 538 | err = <-copyErrC |
| 539 | return err |
| 540 | } |
| 541 |