1 Star 0 Fork 0

h79 / goutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
reply.go 4.15 KB
一键复制 编辑 原始数据 按行查看 历史
huqiuyun 提交于 2023-04-05 16:09 . scp
package ssh
import (
"bufio"
"bytes"
"errors"
"fmt"
"go.uber.org/zap"
"io"
"strings"
"time"
)
type Header struct {
Type ReplyType
}
type FileHeader struct {
FileInfo
}
type DirHeader struct {
FileInfo
}
type EndDirHeader struct {
}
type TimeHeader struct {
Mtime time.Time
Atime time.Time
}
func readReply(r io.Reader) error {
reply, err := ParseReply(r)
if err != nil {
return err
}
if reply.IsFailure() {
return reply
}
return nil
}
type ReplyType uint8
func (rt ReplyType) String() string {
switch rt {
case hCopyFile:
return "copyfile"
case hStartDirectory:
return "startDirectory"
case hEndDirectory:
return "endDirectory"
case hTime:
return "time"
case Ok:
return "Ok"
case Warning:
return "Warning"
case Error:
return "Error"
}
return fmt.Sprintf("Type(%d)", rt)
}
const (
Ok ReplyType = 0
Warning ReplyType = 1
Error ReplyType = 2
hCopyFile = ReplyType('C')
hStartDirectory = ReplyType('D')
hEndDirectory = ReplyType('E')
hTime = ReplyType('T')
)
type Reply struct {
Type ReplyType
Message string
}
func ParseReply(reader io.Reader) (Reply, error) {
buff := bufio.NewReader(reader)
replyType, err := buff.ReadByte()
if err != nil {
return Reply{}, err
}
message := ""
if replyType > 0 {
message, err = buff.ReadString('\n')
if err != nil {
return Reply{}, err
}
message = strings.TrimSuffix(message, "\n")
}
zap.L().Debug("SSH:", zap.String("Type", ReplyType(replyType).String()), zap.String("Body", message))
return Reply{ReplyType(replyType), message}, nil
}
func (r Reply) Parse() (interface{}, error) {
switch r.Type {
case hCopyFile:
return r.parseFileInfo()
case hStartDirectory:
return r.parseDirInfo()
case hEndDirectory:
return &EndDirHeader{}, nil
case hTime:
return r.parseTimeInfo()
case Ok:
fallthrough
case Warning:
fallthrough
case Error:
return &Header{Type: r.Type}, nil
default:
return nil, fmt.Errorf("invalid scp message type: %v", r.Type)
}
}
func (r Reply) IsOk() bool {
return r.Type == Ok
}
func (r Reply) IsWarning() bool {
return r.Type == Warning
}
// IsError returns true when the remote responded with an error.
func (r Reply) IsError() bool {
return r.Type == Error
}
// IsFailure returns true when the remote answered with a warning or an error.
func (r Reply) IsFailure() bool {
return r.IsWarning() || r.IsError()
}
// GetMessage returns the message the remote sent back.
func (r Reply) GetMessage() string {
return r.Message
}
func (r Reply) Error() string {
return r.Message
}
func (r Reply) parseFileInfo() (*FileHeader, error) {
var (
info = FileHeader{}
buf = bytes.NewBuffer([]byte(r.Message))
)
n, err := fmt.Fscanf(buf, "%04o %d %s", &info.Mode, &info.Size, &info.Name)
if err != nil {
return nil, fmt.Errorf("failed to read scp file message header: err=%s", err)
}
if n != 3 {
return nil, fmt.Errorf("unexpected count in reading file message header: n=%d", 3)
}
return &info, nil
}
func (r Reply) parseDirInfo() (*DirHeader, error) {
var (
info = DirHeader{}
buf = bytes.NewBuffer([]byte(r.Message))
)
n, err := fmt.Fscanf(buf, "%04o %d %s", &info.Mode, &info.Size, &info.Name)
if err != nil {
return nil, fmt.Errorf("failed to read scp file message header: err=%s", err)
}
if n != 3 {
return nil, fmt.Errorf("unexpected count in reading file message header: n=%d", 3)
}
return &info, nil
}
func (r Reply) parseTimeInfo() (*TimeHeader, error) {
var (
ms int64
mus int
as int64
aus int
info = TimeHeader{}
buf = bytes.NewBuffer([]byte(r.Message))
)
n, err := fmt.Fscanf(buf, "%d %d %d %d", &ms, &mus, &as, &aus)
if err != nil {
return nil, fmt.Errorf("failed to read scp file message header: err=%s", err)
}
if n != 4 {
return nil, fmt.Errorf("unexpected count in reading file message header: n=%d", 3)
}
info.Mtime = fromSecondsAndMicroseconds(ms, mus)
info.Atime = fromSecondsAndMicroseconds(as, aus)
return &info, nil
}
func fromSecondsAndMicroseconds(seconds int64, microseconds int) time.Time {
return time.Unix(seconds, int64(microseconds)*(int64(time.Microsecond)/int64(time.Nanosecond)))
}
var fileErr = errors.New("unable to parse message as file infos")
Go
1
https://gitee.com/h79/goutils.git
git@gitee.com:h79/goutils.git
h79
goutils
goutils
v1.20.57

搜索帮助

53164aa7 5694891 3bd8fe86 5694891