vendor: update c/{common,storage}

Closes: https://github.com/containers/podman/issues/25572

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2025-03-26 11:24:16 +01:00
parent b58250b35d
commit 7f592742b8
27 changed files with 759 additions and 277 deletions

80
vendor/github.com/pkg/sftp/client.go generated vendored
View File

@@ -17,6 +17,8 @@ import (
"github.com/kr/fs"
"golang.org/x/crypto/ssh"
"github.com/pkg/sftp/internal/encoding/ssh/filexfer/openssh"
)
var (
@@ -758,20 +760,39 @@ func (c *Client) Join(elem ...string) string { return path.Join(elem...) }
// file or directory with the specified path exists, or if the specified directory
// is not empty.
func (c *Client) Remove(path string) error {
err := c.removeFile(path)
// some servers, *cough* osx *cough*, return EPERM, not ENODIR.
// serv-u returns ssh_FX_FILE_IS_A_DIRECTORY
// EPERM is converted to os.ErrPermission so it is not a StatusError
if err, ok := err.(*StatusError); ok {
switch err.Code {
case sshFxFailure, sshFxFileIsADirectory:
return c.RemoveDirectory(path)
errF := c.removeFile(path)
if errF == nil {
return nil
}
errD := c.RemoveDirectory(path)
if errD == nil {
return nil
}
// Both failed: figure out which error to return.
if errF, ok := errF.(*os.PathError); ok {
// The only time it makes sense to compare errors, is when both are `*os.PathError`.
// We cannot test these directly with errF == errD, as that would be a pointer comparison.
if errD, ok := errD.(*os.PathError); ok && errors.Is(errF.Err, errD.Err) {
// If they are both pointers to PathError,
// and the same underlying error, then return that.
return errF
}
}
if os.IsPermission(err) {
return c.RemoveDirectory(path)
fi, err := c.Stat(path)
if err != nil {
return err
}
return err
if fi.IsDir() {
return errD
}
return errF
}
func (c *Client) removeFile(path string) error {
@@ -785,7 +806,15 @@ func (c *Client) removeFile(path string) error {
}
switch typ {
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
err = normaliseError(unmarshalStatus(id, data))
if err == nil {
return nil
}
return &os.PathError{
Op: "remove",
Path: path,
Err: err,
}
default:
return unimplementedPacketErr(typ)
}
@@ -803,7 +832,15 @@ func (c *Client) RemoveDirectory(path string) error {
}
switch typ {
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
err = normaliseError(unmarshalStatus(id, data))
if err == nil {
return nil
}
return &os.PathError{
Op: "remove",
Path: path,
Err: err,
}
default:
return unimplementedPacketErr(typ)
}
@@ -1805,7 +1842,8 @@ func (f *File) readFromWithConcurrency(r io.Reader, concurrency int) (read int64
off := f.offset
for {
n, err := r.Read(b)
// Fill the entire buffer.
n, err := io.ReadFull(r, b)
if n > 0 {
read += int64(n)
@@ -1831,7 +1869,7 @@ func (f *File) readFromWithConcurrency(r io.Reader, concurrency int) (read int64
}
if err != nil {
if err != io.EOF {
if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
errCh <- rwErr{off, err}
}
return
@@ -1985,7 +2023,8 @@ func (f *File) ReadFrom(r io.Reader) (int64, error) {
var read int64
for {
n, err := r.Read(b)
// Fill the entire buffer.
n, err := io.ReadFull(r, b)
if n < 0 {
panic("sftp.File: reader returned negative count from Read")
}
@@ -2002,7 +2041,7 @@ func (f *File) ReadFrom(r io.Reader) (int64, error) {
}
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return read, nil // return nil explicitly.
}
@@ -2122,6 +2161,13 @@ func (f *File) Sync() error {
return os.ErrClosed
}
if data, ok := f.c.HasExtension(openssh.ExtensionFSync().Name); !ok || data != "1" {
return &StatusError{
Code: sshFxOPUnsupported,
msg: "fsync not supported",
}
}
id := f.c.nextID()
typ, data, err := f.c.sendPacket(context.Background(), nil, &sshFxpFsyncPacket{
ID: id,

View File

@@ -0,0 +1,73 @@
package openssh
import (
sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
)
const extensionFSync = "fsync@openssh.com"
// RegisterExtensionFSync registers the "fsync@openssh.com" extended packet with the encoding/ssh/filexfer package.
func RegisterExtensionFSync() {
sshfx.RegisterExtendedPacketType(extensionFSync, func() sshfx.ExtendedData {
return new(FSyncExtendedPacket)
})
}
// ExtensionFSync returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket.
func ExtensionFSync() *sshfx.ExtensionPair {
return &sshfx.ExtensionPair{
Name: extensionFSync,
Data: "1",
}
}
// FSyncExtendedPacket defines the fsync@openssh.com extend packet.
type FSyncExtendedPacket struct {
Handle string
}
// Type returns the SSH_FXP_EXTENDED packet type.
func (ep *FSyncExtendedPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtended
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
func (ep *FSyncExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionFSync,
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the fsync@openssh.com extended packet-specific data.
func (ep *FSyncExtendedPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendString(ep.Handle)
}
// MarshalBinary encodes ep into the binary encoding of the fsync@openssh.com extended packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet.
func (ep *FSyncExtendedPacket) MarshalBinary() ([]byte, error) {
// string(handle)
size := 4 + len(ep.Handle)
buf := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(buf)
return buf.Bytes(), nil
}
// UnmarshalFrom decodes the fsync@openssh.com extended packet-specific data from buf.
func (ep *FSyncExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = FSyncExtendedPacket{
Handle: buf.ConsumeString(),
}
return buf.Err
}
// UnmarshalBinary decodes the fsync@openssh.com extended packet-specific data into ep.
func (ep *FSyncExtendedPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}

View File

@@ -0,0 +1,76 @@
package openssh
import (
sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
)
const extensionHardlink = "hardlink@openssh.com"
// RegisterExtensionHardlink registers the "hardlink@openssh.com" extended packet with the encoding/ssh/filexfer package.
func RegisterExtensionHardlink() {
sshfx.RegisterExtendedPacketType(extensionHardlink, func() sshfx.ExtendedData {
return new(HardlinkExtendedPacket)
})
}
// ExtensionHardlink returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket.
func ExtensionHardlink() *sshfx.ExtensionPair {
return &sshfx.ExtensionPair{
Name: extensionHardlink,
Data: "1",
}
}
// HardlinkExtendedPacket defines the hardlink@openssh.com extend packet.
type HardlinkExtendedPacket struct {
OldPath string
NewPath string
}
// Type returns the SSH_FXP_EXTENDED packet type.
func (ep *HardlinkExtendedPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtended
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
func (ep *HardlinkExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionHardlink,
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
func (ep *HardlinkExtendedPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendString(ep.OldPath)
buf.AppendString(ep.NewPath)
}
// MarshalBinary encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet.
func (ep *HardlinkExtendedPacket) MarshalBinary() ([]byte, error) {
// string(oldpath) + string(newpath)
size := 4 + len(ep.OldPath) + 4 + len(ep.NewPath)
buf := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(buf)
return buf.Bytes(), nil
}
// UnmarshalFrom decodes the hardlink@openssh.com extended packet-specific data from buf.
func (ep *HardlinkExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = HardlinkExtendedPacket{
OldPath: buf.ConsumeString(),
NewPath: buf.ConsumeString(),
}
return buf.Err
}
// UnmarshalBinary decodes the hardlink@openssh.com extended packet-specific data into ep.
func (ep *HardlinkExtendedPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}

View File

@@ -0,0 +1,2 @@
// Package openssh implements the openssh secsh-filexfer extensions as described in https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
package openssh

View File

@@ -0,0 +1,76 @@
package openssh
import (
sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
)
const extensionPOSIXRename = "posix-rename@openssh.com"
// RegisterExtensionPOSIXRename registers the "posix-rename@openssh.com" extended packet with the encoding/ssh/filexfer package.
func RegisterExtensionPOSIXRename() {
sshfx.RegisterExtendedPacketType(extensionPOSIXRename, func() sshfx.ExtendedData {
return new(POSIXRenameExtendedPacket)
})
}
// ExtensionPOSIXRename returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket.
func ExtensionPOSIXRename() *sshfx.ExtensionPair {
return &sshfx.ExtensionPair{
Name: extensionPOSIXRename,
Data: "1",
}
}
// POSIXRenameExtendedPacket defines the posix-rename@openssh.com extend packet.
type POSIXRenameExtendedPacket struct {
OldPath string
NewPath string
}
// Type returns the SSH_FXP_EXTENDED packet type.
func (ep *POSIXRenameExtendedPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtended
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
func (ep *POSIXRenameExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionPOSIXRename,
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
func (ep *POSIXRenameExtendedPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendString(ep.OldPath)
buf.AppendString(ep.NewPath)
}
// MarshalBinary encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet.
func (ep *POSIXRenameExtendedPacket) MarshalBinary() ([]byte, error) {
// string(oldpath) + string(newpath)
size := 4 + len(ep.OldPath) + 4 + len(ep.NewPath)
buf := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(buf)
return buf.Bytes(), nil
}
// UnmarshalFrom decodes the hardlink@openssh.com extended packet-specific data from buf.
func (ep *POSIXRenameExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = POSIXRenameExtendedPacket{
OldPath: buf.ConsumeString(),
NewPath: buf.ConsumeString(),
}
return buf.Err
}
// UnmarshalBinary decodes the hardlink@openssh.com extended packet-specific data into ep.
func (ep *POSIXRenameExtendedPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}

View File

@@ -0,0 +1,236 @@
package openssh
import (
sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
)
const extensionStatVFS = "statvfs@openssh.com"
// RegisterExtensionStatVFS registers the "statvfs@openssh.com" extended packet with the encoding/ssh/filexfer package.
func RegisterExtensionStatVFS() {
sshfx.RegisterExtendedPacketType(extensionStatVFS, func() sshfx.ExtendedData {
return new(StatVFSExtendedPacket)
})
}
// ExtensionStatVFS returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket.
func ExtensionStatVFS() *sshfx.ExtensionPair {
return &sshfx.ExtensionPair{
Name: extensionStatVFS,
Data: "2",
}
}
// StatVFSExtendedPacket defines the statvfs@openssh.com extend packet.
type StatVFSExtendedPacket struct {
Path string
}
// Type returns the SSH_FXP_EXTENDED packet type.
func (ep *StatVFSExtendedPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtended
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
func (ep *StatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionStatVFS,
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
func (ep *StatVFSExtendedPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendString(ep.Path)
}
// MarshalBinary encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet.
func (ep *StatVFSExtendedPacket) MarshalBinary() ([]byte, error) {
size := 4 + len(ep.Path) // string(path)
buf := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(buf)
return buf.Bytes(), nil
}
// UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep.
func (ep *StatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = StatVFSExtendedPacket{
Path: buf.ConsumeString(),
}
return buf.Err
}
// UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep.
func (ep *StatVFSExtendedPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}
const extensionFStatVFS = "fstatvfs@openssh.com"
// RegisterExtensionFStatVFS registers the "fstatvfs@openssh.com" extended packet with the encoding/ssh/filexfer package.
func RegisterExtensionFStatVFS() {
sshfx.RegisterExtendedPacketType(extensionFStatVFS, func() sshfx.ExtendedData {
return new(FStatVFSExtendedPacket)
})
}
// ExtensionFStatVFS returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket.
func ExtensionFStatVFS() *sshfx.ExtensionPair {
return &sshfx.ExtensionPair{
Name: extensionFStatVFS,
Data: "2",
}
}
// FStatVFSExtendedPacket defines the fstatvfs@openssh.com extend packet.
type FStatVFSExtendedPacket struct {
Path string
}
// Type returns the SSH_FXP_EXTENDED packet type.
func (ep *FStatVFSExtendedPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtended
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
func (ep *FStatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionFStatVFS,
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
func (ep *FStatVFSExtendedPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendString(ep.Path)
}
// MarshalBinary encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet.
func (ep *FStatVFSExtendedPacket) MarshalBinary() ([]byte, error) {
size := 4 + len(ep.Path) // string(path)
buf := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(buf)
return buf.Bytes(), nil
}
// UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep.
func (ep *FStatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = FStatVFSExtendedPacket{
Path: buf.ConsumeString(),
}
return buf.Err
}
// UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep.
func (ep *FStatVFSExtendedPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}
// The values for the MountFlags field.
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
const (
MountFlagsReadOnly = 0x1 // SSH_FXE_STATVFS_ST_RDONLY
MountFlagsNoSUID = 0x2 // SSH_FXE_STATVFS_ST_NOSUID
)
// StatVFSExtendedReplyPacket defines the extended reply packet for statvfs@openssh.com and fstatvfs@openssh.com requests.
type StatVFSExtendedReplyPacket struct {
BlockSize uint64 /* f_bsize: file system block size */
FragmentSize uint64 /* f_frsize: fundamental fs block size / fagment size */
Blocks uint64 /* f_blocks: number of blocks (unit f_frsize) */
BlocksFree uint64 /* f_bfree: free blocks in filesystem */
BlocksAvail uint64 /* f_bavail: free blocks for non-root */
Files uint64 /* f_files: total file inodes */
FilesFree uint64 /* f_ffree: free file inodes */
FilesAvail uint64 /* f_favail: free file inodes for to non-root */
FilesystemID uint64 /* f_fsid: file system id */
MountFlags uint64 /* f_flag: bit mask of mount flag values */
MaxNameLength uint64 /* f_namemax: maximum filename length */
}
// Type returns the SSH_FXP_EXTENDED_REPLY packet type.
func (ep *StatVFSExtendedReplyPacket) Type() sshfx.PacketType {
return sshfx.PacketTypeExtendedReply
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended reply packet.
func (ep *StatVFSExtendedReplyPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedReplyPacket{
Data: ep,
}
return p.MarshalPacket(reqid, b)
}
// UnmarshalPacketBody returns ep as a two-part binary encoding of the full extended reply packet.
func (ep *StatVFSExtendedReplyPacket) UnmarshalPacketBody(buf *sshfx.Buffer) (err error) {
p := &sshfx.ExtendedReplyPacket{
Data: ep,
}
return p.UnmarshalPacketBody(buf)
}
// MarshalInto encodes ep into the binary encoding of the (f)statvfs@openssh.com extended reply packet-specific data.
func (ep *StatVFSExtendedReplyPacket) MarshalInto(buf *sshfx.Buffer) {
buf.AppendUint64(ep.BlockSize)
buf.AppendUint64(ep.FragmentSize)
buf.AppendUint64(ep.Blocks)
buf.AppendUint64(ep.BlocksFree)
buf.AppendUint64(ep.BlocksAvail)
buf.AppendUint64(ep.Files)
buf.AppendUint64(ep.FilesFree)
buf.AppendUint64(ep.FilesAvail)
buf.AppendUint64(ep.FilesystemID)
buf.AppendUint64(ep.MountFlags)
buf.AppendUint64(ep.MaxNameLength)
}
// MarshalBinary encodes ep into the binary encoding of the (f)statvfs@openssh.com extended reply packet-specific data.
//
// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended reply packet.
func (ep *StatVFSExtendedReplyPacket) MarshalBinary() ([]byte, error) {
size := 11 * 8 // 11 × uint64(various)
b := sshfx.NewBuffer(make([]byte, 0, size))
ep.MarshalInto(b)
return b.Bytes(), nil
}
// UnmarshalFrom decodes the fstatvfs@openssh.com extended reply packet-specific data into ep.
func (ep *StatVFSExtendedReplyPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) {
*ep = StatVFSExtendedReplyPacket{
BlockSize: buf.ConsumeUint64(),
FragmentSize: buf.ConsumeUint64(),
Blocks: buf.ConsumeUint64(),
BlocksFree: buf.ConsumeUint64(),
BlocksAvail: buf.ConsumeUint64(),
Files: buf.ConsumeUint64(),
FilesFree: buf.ConsumeUint64(),
FilesAvail: buf.ConsumeUint64(),
FilesystemID: buf.ConsumeUint64(),
MountFlags: buf.ConsumeUint64(),
MaxNameLength: buf.ConsumeUint64(),
}
return buf.Err
}
// UnmarshalBinary decodes the fstatvfs@openssh.com extended reply packet-specific data into ep.
func (ep *StatVFSExtendedReplyPacket) UnmarshalBinary(data []byte) (err error) {
return ep.UnmarshalFrom(sshfx.NewBuffer(data))
}