summaryrefslogtreecommitdiff
path: root/vendor/github.com/dtylman/scp
diff options
context:
space:
mode:
authorcdoern <cdoern@redhat.com>2021-06-25 14:26:33 -0400
committercdoern <cdoern@redhat.com>2021-07-30 17:19:24 -0400
commit1d10ca739f3599b9bd746783ad15c8f51ce9f75c (patch)
tree28565571d2e564fc367ca6ad97eccc9ffc3c9d19 /vendor/github.com/dtylman/scp
parentec5ab591ddbb905b69b3daa6012e9c0dfde9fcec (diff)
downloadpodman-1d10ca739f3599b9bd746783ad15c8f51ce9f75c.tar.gz
podman-1d10ca739f3599b9bd746783ad15c8f51ce9f75c.tar.bz2
podman-1d10ca739f3599b9bd746783ad15c8f51ce9f75c.zip
Created scp.go image_scp_test.go and podman-image-scp.1.md
added functionality for image secure copying from local to remote. Also moved system connection add code around a bit so functions within that file can be used by scp. Signed-off-by: cdoern <cdoern@redhat.com>
Diffstat (limited to 'vendor/github.com/dtylman/scp')
-rw-r--r--vendor/github.com/dtylman/scp/.gitignore25
-rw-r--r--vendor/github.com/dtylman/scp/LICENSE21
-rw-r--r--vendor/github.com/dtylman/scp/README.md42
-rw-r--r--vendor/github.com/dtylman/scp/msg.go121
-rw-r--r--vendor/github.com/dtylman/scp/scp.go153
5 files changed, 362 insertions, 0 deletions
diff --git a/vendor/github.com/dtylman/scp/.gitignore b/vendor/github.com/dtylman/scp/.gitignore
new file mode 100644
index 000000000..6e1690ed6
--- /dev/null
+++ b/vendor/github.com/dtylman/scp/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+example/example
diff --git a/vendor/github.com/dtylman/scp/LICENSE b/vendor/github.com/dtylman/scp/LICENSE
new file mode 100644
index 000000000..6565de59d
--- /dev/null
+++ b/vendor/github.com/dtylman/scp/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Danny
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/dtylman/scp/README.md b/vendor/github.com/dtylman/scp/README.md
new file mode 100644
index 000000000..48cfefe02
--- /dev/null
+++ b/vendor/github.com/dtylman/scp/README.md
@@ -0,0 +1,42 @@
+# scp
+
+[![Go Report Card](https://goreportcard.com/badge/github.com/dtylman/scp)](https://goreportcard.com/report/github.com/dtylman/scp)
+
+A Simple `go` SCP client library.
+
+## Usage
+
+```go
+import (
+ "github.com/dtylman/scp"
+ "golang.org/x/crypto/ssh"
+)
+```
+
+## Sending Files
+
+Copies `/var/log/messages` to remote `/tmp/lala`:
+
+```go
+var sc* ssh.Client
+// establish ssh connection into sc here...
+n,err:=scp.CopyTo(sc, "/var/log/messages", "/tmp/lala")
+if err==nil{
+ fmt.Printf("Sent %v bytes",n)
+}
+```
+
+## Receiving Files
+
+Copies remote `/var/log/message` to local `/tmp/lala`:
+
+```go
+var sc* ssh.Client
+// establish ssh connection into sc here...
+n,err:=scp.CopyFrom(sc, "/var/log/message", "/tmp/lala")
+if err==nil{
+ fmt.Printf("Sent %v bytes",n)
+}
+```
+
+
diff --git a/vendor/github.com/dtylman/scp/msg.go b/vendor/github.com/dtylman/scp/msg.go
new file mode 100644
index 000000000..6dfc53535
--- /dev/null
+++ b/vendor/github.com/dtylman/scp/msg.go
@@ -0,0 +1,121 @@
+package scp
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strconv"
+ "strings"
+)
+
+const (
+ //CopyMessage Copy Message Opcode
+ CopyMessage = 'C'
+ //ErrorMessage Error OpCode
+ ErrorMessage = 0x1
+ //WarnMessage Warning Opcode
+ WarnMessage = 0x2
+)
+
+//Message is scp control message
+type Message struct {
+ Type byte
+ Error error
+ Mode string
+ Size int64
+ FileName string
+}
+
+func (m *Message) readByte(reader io.Reader) (byte, error) {
+ buff := make([]byte, 1)
+ _, err := io.ReadFull(reader, buff)
+ if err != nil {
+ return 0, err
+ }
+ return buff[0], nil
+
+}
+
+func (m *Message) readOpCode(reader io.Reader) error {
+ var err error
+ m.Type, err = m.readByte(reader)
+ return err
+}
+
+//ReadError reads an error message
+func (m *Message) ReadError(reader io.Reader) error {
+ msg, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return err
+ }
+ m.Error = errors.New(strings.TrimSpace(string(msg)))
+ return nil
+}
+
+func (m *Message) readLine(reader io.Reader) (string, error) {
+ line := ""
+ b, err := m.readByte(reader)
+ if err != nil {
+ return "", err
+ }
+ for b != 10 {
+ line += string(b)
+ b, err = m.readByte(reader)
+ if err != nil {
+ return "", err
+ }
+ }
+ return line, nil
+}
+
+func (m *Message) readCopy(reader io.Reader) error {
+ line, err := m.readLine(reader)
+ if err != nil {
+ return err
+ }
+ parts := strings.Split(line, " ")
+ if len(parts) < 2 {
+ return errors.New("Invalid copy line: " + line)
+ }
+ m.Mode = parts[0]
+ m.Size, err = strconv.ParseInt(parts[1], 10, 0)
+ if err != nil {
+ return err
+ }
+ m.FileName = parts[2]
+ return nil
+}
+
+//ReadFrom reads message from reader
+func (m *Message) ReadFrom(reader io.Reader) (int64, error) {
+ err := m.readOpCode(reader)
+ if err != nil {
+ return 0, err
+ }
+ switch m.Type {
+ case CopyMessage:
+ err = m.readCopy(reader)
+ if err != nil {
+ return 0, err
+ }
+ case ErrorMessage, WarnMessage:
+ err = m.ReadError(reader)
+ if err != nil {
+ return 0, err
+ }
+ default:
+ return 0, fmt.Errorf("Unsupported opcode: %v", m.Type)
+ }
+ return m.Size, nil
+}
+
+//NewMessageFromReader constructs a new message from a data in reader
+func NewMessageFromReader(reader io.Reader) (*Message, error) {
+ m := new(Message)
+ _, err := m.ReadFrom(reader)
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
diff --git a/vendor/github.com/dtylman/scp/scp.go b/vendor/github.com/dtylman/scp/scp.go
new file mode 100644
index 000000000..841c16965
--- /dev/null
+++ b/vendor/github.com/dtylman/scp/scp.go
@@ -0,0 +1,153 @@
+package scp
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+
+ log "github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh"
+)
+
+const (
+ fileMode = "0644"
+ buffSize = 1024 * 256
+)
+
+//CopyTo copy from local to remote
+func CopyTo(sshClient *ssh.Client, local string, remote string) (int64, error) {
+ session, err := sshClient.NewSession()
+ if err != nil {
+ return 0, err
+ }
+ defer session.Close()
+ stderr := &bytes.Buffer{}
+ session.Stderr = stderr
+ stdout := &bytes.Buffer{}
+ session.Stdout = stdout
+ writer, err := session.StdinPipe()
+ if err != nil {
+ return 0, err
+ }
+ defer writer.Close()
+ err = session.Start("scp -t " + filepath.Dir(remote))
+ if err != nil {
+ return 0, err
+ }
+
+ localFile, err := os.Open(local)
+ if err != nil {
+ return 0, err
+ }
+ fileInfo, err := localFile.Stat()
+ if err != nil {
+ return 0, err
+ }
+ _, err = fmt.Fprintf(writer, "C%s %d %s\n", fileMode, fileInfo.Size(), filepath.Base(remote))
+ if err != nil {
+ return 0, err
+ }
+ n, err := copyN(writer, localFile, fileInfo.Size())
+ if err != nil {
+ return 0, err
+ }
+ err = ack(writer)
+ if err != nil {
+ return 0, err
+ }
+
+ err = session.Wait()
+ log.Debugf("Copied %v bytes out of %v. err: %v stdout:%v. stderr:%v", n, fileInfo.Size(), err, stdout, stderr)
+ //NOTE: Process exited with status 1 is not an error, it just how scp work. (waiting for the next control message and we send EOF)
+ return n, nil
+}
+
+//CopyFrom copy from remote to local
+func CopyFrom(sshClient *ssh.Client, remote string, local string) (int64, error) {
+ session, err := sshClient.NewSession()
+ if err != nil {
+ return 0, err
+ }
+ defer session.Close()
+ stderr := &bytes.Buffer{}
+ session.Stderr = stderr
+ writer, err := session.StdinPipe()
+ if err != nil {
+ return 0, err
+ }
+ defer writer.Close()
+ reader, err := session.StdoutPipe()
+ if err != nil {
+ return 0, err
+ }
+ err = session.Start("scp -f " + remote)
+ if err != nil {
+ return 0, err
+ }
+ err = ack(writer)
+ if err != nil {
+ return 0, err
+ }
+ msg, err := NewMessageFromReader(reader)
+ if err != nil {
+ return 0, err
+ }
+ if msg.Type == ErrorMessage || msg.Type == WarnMessage {
+ return 0, msg.Error
+ }
+ log.Debugf("Receiving %v", msg)
+
+ err = ack(writer)
+ if err != nil {
+ return 0, err
+ }
+ outFile, err := os.Create(local)
+ if err != nil {
+ return 0, err
+ }
+ defer outFile.Close()
+ n, err := copyN(outFile, reader, msg.Size)
+ if err != nil {
+ return 0, err
+ }
+ err = outFile.Sync()
+ if err != nil {
+ return 0, err
+ }
+ err = outFile.Close()
+ if err != nil {
+ return 0, err
+ }
+ err = session.Wait()
+ log.Debugf("Copied %v bytes out of %v. err: %v stderr:%v", n, msg.Size, err, stderr)
+ return n, nil
+}
+
+func ack(writer io.Writer) error {
+ var msg = []byte{0, 0, 10, 13}
+ n, err := writer.Write(msg)
+ if err != nil {
+ return err
+ }
+ if n < len(msg) {
+ return errors.New("Failed to write ack buffer")
+ }
+ return nil
+}
+
+func copyN(writer io.Writer, src io.Reader, size int64) (int64, error) {
+ reader := io.LimitReader(src, size)
+ var total int64
+ for total < size {
+ n, err := io.CopyBuffer(writer, reader, make([]byte, buffSize))
+ log.Debugf("Copied chunk %v total: %v out of %v err: %v ", n, total, size, err)
+ if err != nil {
+ return 0, err
+ }
+ total += n
+ }
+ return total, nil
+}