Antonio Mika
·
2025-03-12
utils.go
1package utils
2
3import (
4 "encoding/base64"
5 "fmt"
6 "io"
7 "io/fs"
8 "log/slog"
9 "os"
10 "path/filepath"
11 "strconv"
12
13 "github.com/picosh/pico/pkg/pssh"
14)
15
16// NULL is an array with a single NULL byte.
17var NULL = []byte{'\x00'}
18
19// FileEntry is an Entry that reads from a Reader, defining a file and
20// its contents.
21type FileEntry struct {
22 Filepath string
23 Mode fs.FileMode
24 Size int64
25 Reader io.Reader
26 Atime int64
27 Mtime int64
28 Metadata map[string]string
29}
30
31// Write a file to the given writer.
32func (e *FileEntry) Write(w io.Writer) error {
33 if e.Mtime > 0 && e.Atime > 0 {
34 if _, err := fmt.Fprintf(w, "T%d 0 %d 0\n", e.Mtime, e.Atime); err != nil {
35 return fmt.Errorf("failed to write file: %q: %w", e.Filepath, err)
36 }
37 }
38 fname := filepath.Base(e.Filepath)
39 if _, err := fmt.Fprintf(w, "C%s %d %s\n", octalPerms(e.Mode), e.Size, fname); err != nil {
40 return fmt.Errorf("failed to write file: %q: %w", e.Filepath, err)
41 }
42
43 if _, err := io.Copy(w, e.Reader); err != nil {
44 return fmt.Errorf("failed to read file: %q: %w", e.Filepath, err)
45 }
46
47 if _, err := w.Write(NULL); err != nil {
48 return fmt.Errorf("failed to write file: %q: %w", e.Filepath, err)
49 }
50 return nil
51}
52
53func octalPerms(info fs.FileMode) string {
54 return "0" + strconv.FormatUint(uint64(info.Perm()), 8)
55}
56
57// CopyFromClientHandler is a handler that can be implemented to handle files
58// being copied from the client to the server.
59type CopyFromClientHandler interface {
60 // Write should write the given file.
61 Delete(*pssh.SSHServerConnSession, *FileEntry) error
62 Write(*pssh.SSHServerConnSession, *FileEntry) (string, error)
63 Read(*pssh.SSHServerConnSession, *FileEntry) (os.FileInfo, ReadAndReaderAtCloser, error)
64 List(*pssh.SSHServerConnSession, string, bool, bool) ([]os.FileInfo, error)
65 GetLogger(*pssh.SSHServerConnSession) *slog.Logger
66 Validate(*pssh.SSHServerConnSession) error
67}
68
69func KeyText(session *pssh.SSHServerConnSession) (string, error) {
70 if session.PublicKey() == nil {
71 return "", fmt.Errorf("session doesn't have public key")
72 }
73 kb := base64.StdEncoding.EncodeToString(session.PublicKey().Marshal())
74 return fmt.Sprintf("%s %s", session.PublicKey().Type(), kb), nil
75}
76
77func ErrorHandler(session *pssh.SSHServerConnSession, err error) {
78 _, _ = fmt.Fprint(session.Stderr(), err, "\r\n")
79 _ = session.Exit(1)
80 _ = session.Close()
81}
82
83func PrintMsg(session *pssh.SSHServerConnSession, stdout []string, stderr []error) {
84 output := ""
85 if len(stdout) > 0 {
86 for _, msg := range stdout {
87 if msg != "" {
88 output += fmt.Sprintf("%s\r\n", msg)
89 }
90 }
91 _, _ = fmt.Fprintln(session.Stderr(), output)
92 }
93
94 outputErr := ""
95 if len(stderr) > 0 {
96 for _, err := range stderr {
97 outputErr += fmt.Sprintf("%v\r\n", err)
98 }
99 _, _ = fmt.Fprintln(session.Stderr(), outputErr)
100 }
101}