unpack tar files copied via sftp subsystem, too (not just older scp)
For compatibility with OpenSSH ≥ 9
This commit is contained in:
parent
7dbbe9b4b3
commit
48c5124500
62
scp.go
62
scp.go
@ -66,36 +66,9 @@ func scpSink(channel ssh.Channel, req *ssh.Request, cmdline []string) error {
|
|||||||
|
|
||||||
// Retrieve file contents
|
// Retrieve file contents
|
||||||
var cw countingWriter
|
var cw countingWriter
|
||||||
tr := tar.NewReader(io.TeeReader(channel, &cw))
|
if err := unpackTar(io.TeeReader(channel, &cw)); err != nil {
|
||||||
for {
|
|
||||||
h, err := tr.Next()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("extracting %q", h.Name)
|
|
||||||
if err := os.MkdirAll(filepath.Dir(h.Name), 0700); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(h.Name, "/") {
|
|
||||||
continue // directory, don’t try to OpenFile() it
|
|
||||||
}
|
|
||||||
mode := h.FileInfo().Mode() & os.ModePerm
|
|
||||||
out, err := renameio.NewPendingFile(h.Name, renameio.WithStaticPermissions(mode))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := io.Copy(out, tr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := out.CloseAtomicallyReplace(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rest := size - int64(cw); rest > 0 {
|
if rest := size - int64(cw); rest > 0 {
|
||||||
buf := make([]byte, rest)
|
buf := make([]byte, rest)
|
||||||
if _, err := channel.Read(buf); err != nil {
|
if _, err := channel.Read(buf); err != nil {
|
||||||
@ -125,3 +98,36 @@ func scpSink(channel ssh.Channel, req *ssh.Request, cmdline []string) error {
|
|||||||
req.Reply(true, nil)
|
req.Reply(true, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unpackTar(r io.Reader) error {
|
||||||
|
tr := tar.NewReader(r)
|
||||||
|
for {
|
||||||
|
h, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("extracting %q", h.Name)
|
||||||
|
if err := os.MkdirAll(filepath.Dir(h.Name), 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(h.Name, "/") {
|
||||||
|
continue // directory, don’t try to OpenFile() it
|
||||||
|
}
|
||||||
|
mode := h.FileInfo().Mode() & os.ModePerm
|
||||||
|
out, err := renameio.NewPendingFile(h.Name, renameio.WithStaticPermissions(mode))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(out, tr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := out.CloseAtomicallyReplace(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
29
ssh.go
29
ssh.go
@ -292,9 +292,34 @@ func (s *session) request(ctx context.Context, req *ssh.Request) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://tools.ietf.org/html/rfc4254#section-6.10
|
// Special case for breakglass usage: unpack all .tar files that were
|
||||||
_, err = s.channel.SendRequest("exit-status", false /* wantReply */, ssh.Marshal(exitStatus{exitCode}))
|
// transferred into $PWD (which is a /tmp/breakglass… temporary
|
||||||
|
// directory), so that the binaries included in the tar file can be used
|
||||||
|
// for debugging.
|
||||||
|
dirents, err := os.ReadDir(".")
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
for _, dirent := range dirents {
|
||||||
|
if !strings.HasSuffix(dirent.Name(), ".tar") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f, err := os.Open(dirent.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if err := unpackTar(f); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://tools.ietf.org/html/rfc4254#section-6.10
|
||||||
|
if _, err := s.channel.SendRequest("exit-status", false /* wantReply */, ssh.Marshal(exitStatus{exitCode})); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
case "shell":
|
case "shell":
|
||||||
req.Payload = []byte("\x00\x00\x00\x02sh")
|
req.Payload = []byte("\x00\x00\x00\x02sh")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user