repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / send / utils
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}