mirror of https://github.com/containers/podman.git
122 lines
2.2 KiB
Go
122 lines
2.2 KiB
Go
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
|
|
}
|