pointer receivers and statusFromError(uint32, error)

This commit is contained in:
Cassondra Foesch 2021-02-22 12:00:27 +00:00
parent 1d73fd92d5
commit 861a8eaf5c
14 changed files with 283 additions and 274 deletions

View File

@ -235,7 +235,7 @@ func (c *Client) Create(path string) (*File, error) {
const sftpProtocolVersion = 3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 const sftpProtocolVersion = 3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
func (c *Client) sendInit() error { func (c *Client) sendInit() error {
return c.clientConn.conn.sendPacket(sshFxInitPacket{ return c.clientConn.conn.sendPacket(&sshFxInitPacket{
Version: sftpProtocolVersion, // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 Version: sftpProtocolVersion, // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
}) })
} }
@ -297,7 +297,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
var done = false var done = false
for !done { for !done {
id := c.nextID() id := c.nextID()
typ, data, err1 := c.sendPacket(nil, sshFxpReaddirPacket{ typ, data, err1 := c.sendPacket(nil, &sshFxpReaddirPacket{
ID: id, ID: id,
Handle: handle, Handle: handle,
}) })
@ -340,7 +340,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
func (c *Client) opendir(path string) (string, error) { func (c *Client) opendir(path string) (string, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpOpendirPacket{ typ, data, err := c.sendPacket(nil, &sshFxpOpendirPacket{
ID: id, ID: id,
Path: path, Path: path,
}) })
@ -366,7 +366,7 @@ func (c *Client) opendir(path string) (string, error) {
// If 'p' is a symbolic link, the returned FileInfo structure describes the referent file. // If 'p' is a symbolic link, the returned FileInfo structure describes the referent file.
func (c *Client) Stat(p string) (os.FileInfo, error) { func (c *Client) Stat(p string) (os.FileInfo, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpStatPacket{ typ, data, err := c.sendPacket(nil, &sshFxpStatPacket{
ID: id, ID: id,
Path: p, Path: p,
}) })
@ -392,7 +392,7 @@ func (c *Client) Stat(p string) (os.FileInfo, error) {
// If 'p' is a symbolic link, the returned FileInfo structure describes the symbolic link. // If 'p' is a symbolic link, the returned FileInfo structure describes the symbolic link.
func (c *Client) Lstat(p string) (os.FileInfo, error) { func (c *Client) Lstat(p string) (os.FileInfo, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpLstatPacket{ typ, data, err := c.sendPacket(nil, &sshFxpLstatPacket{
ID: id, ID: id,
Path: p, Path: p,
}) })
@ -417,7 +417,7 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) {
// ReadLink reads the target of a symbolic link. // ReadLink reads the target of a symbolic link.
func (c *Client) ReadLink(p string) (string, error) { func (c *Client) ReadLink(p string) (string, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpReadlinkPacket{ typ, data, err := c.sendPacket(nil, &sshFxpReadlinkPacket{
ID: id, ID: id,
Path: p, Path: p,
}) })
@ -446,7 +446,7 @@ func (c *Client) ReadLink(p string) (string, error) {
// Link creates a hard link at 'newname', pointing at the same inode as 'oldname' // Link creates a hard link at 'newname', pointing at the same inode as 'oldname'
func (c *Client) Link(oldname, newname string) error { func (c *Client) Link(oldname, newname string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpHardlinkPacket{ typ, data, err := c.sendPacket(nil, &sshFxpHardlinkPacket{
ID: id, ID: id,
Oldpath: oldname, Oldpath: oldname,
Newpath: newname, Newpath: newname,
@ -465,7 +465,7 @@ func (c *Client) Link(oldname, newname string) error {
// Symlink creates a symbolic link at 'newname', pointing at target 'oldname' // Symlink creates a symbolic link at 'newname', pointing at target 'oldname'
func (c *Client) Symlink(oldname, newname string) error { func (c *Client) Symlink(oldname, newname string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpSymlinkPacket{ typ, data, err := c.sendPacket(nil, &sshFxpSymlinkPacket{
ID: id, ID: id,
Linkpath: newname, Linkpath: newname,
Targetpath: oldname, Targetpath: oldname,
@ -483,7 +483,7 @@ func (c *Client) Symlink(oldname, newname string) error {
func (c *Client) setfstat(handle string, flags uint32, attrs interface{}) error { func (c *Client) setfstat(handle string, flags uint32, attrs interface{}) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpFsetstatPacket{ typ, data, err := c.sendPacket(nil, &sshFxpFsetstatPacket{
ID: id, ID: id,
Handle: handle, Handle: handle,
Flags: flags, Flags: flags,
@ -503,7 +503,7 @@ func (c *Client) setfstat(handle string, flags uint32, attrs interface{}) error
// setstat is a convience wrapper to allow for changing of various parts of the file descriptor. // setstat is a convience wrapper to allow for changing of various parts of the file descriptor.
func (c *Client) setstat(path string, flags uint32, attrs interface{}) error { func (c *Client) setstat(path string, flags uint32, attrs interface{}) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpSetstatPacket{ typ, data, err := c.sendPacket(nil, &sshFxpSetstatPacket{
ID: id, ID: id,
Path: path, Path: path,
Flags: flags, Flags: flags,
@ -569,7 +569,7 @@ func (c *Client) OpenFile(path string, f int) (*File, error) {
func (c *Client) open(path string, pflags uint32) (*File, error) { func (c *Client) open(path string, pflags uint32) (*File, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpOpenPacket{ typ, data, err := c.sendPacket(nil, &sshFxpOpenPacket{
ID: id, ID: id,
Path: path, Path: path,
Pflags: pflags, Pflags: pflags,
@ -597,7 +597,7 @@ func (c *Client) open(path string, pflags uint32) (*File, error) {
// immediately after this request has been sent. // immediately after this request has been sent.
func (c *Client) close(handle string) error { func (c *Client) close(handle string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpClosePacket{ typ, data, err := c.sendPacket(nil, &sshFxpClosePacket{
ID: id, ID: id,
Handle: handle, Handle: handle,
}) })
@ -614,7 +614,7 @@ func (c *Client) close(handle string) error {
func (c *Client) fstat(handle string) (*FileStat, error) { func (c *Client) fstat(handle string) (*FileStat, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpFstatPacket{ typ, data, err := c.sendPacket(nil, &sshFxpFstatPacket{
ID: id, ID: id,
Handle: handle, Handle: handle,
}) })
@ -643,7 +643,7 @@ func (c *Client) fstat(handle string) (*FileStat, error) {
func (c *Client) StatVFS(path string) (*StatVFS, error) { func (c *Client) StatVFS(path string) (*StatVFS, error) {
// send the StatVFS packet to the server // send the StatVFS packet to the server
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpStatvfsPacket{ typ, data, err := c.sendPacket(nil, &sshFxpStatvfsPacket{
ID: id, ID: id,
Path: path, Path: path,
}) })
@ -698,7 +698,7 @@ func (c *Client) Remove(path string) error {
func (c *Client) removeFile(path string) error { func (c *Client) removeFile(path string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpRemovePacket{ typ, data, err := c.sendPacket(nil, &sshFxpRemovePacket{
ID: id, ID: id,
Filename: path, Filename: path,
}) })
@ -716,7 +716,7 @@ func (c *Client) removeFile(path string) error {
// RemoveDirectory removes a directory path. // RemoveDirectory removes a directory path.
func (c *Client) RemoveDirectory(path string) error { func (c *Client) RemoveDirectory(path string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpRmdirPacket{ typ, data, err := c.sendPacket(nil, &sshFxpRmdirPacket{
ID: id, ID: id,
Path: path, Path: path,
}) })
@ -734,7 +734,7 @@ func (c *Client) RemoveDirectory(path string) error {
// Rename renames a file. // Rename renames a file.
func (c *Client) Rename(oldname, newname string) error { func (c *Client) Rename(oldname, newname string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpRenamePacket{ typ, data, err := c.sendPacket(nil, &sshFxpRenamePacket{
ID: id, ID: id,
Oldpath: oldname, Oldpath: oldname,
Newpath: newname, Newpath: newname,
@ -754,7 +754,7 @@ func (c *Client) Rename(oldname, newname string) error {
// which will replace newname if it already exists. // which will replace newname if it already exists.
func (c *Client) PosixRename(oldname, newname string) error { func (c *Client) PosixRename(oldname, newname string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpPosixRenamePacket{ typ, data, err := c.sendPacket(nil, &sshFxpPosixRenamePacket{
ID: id, ID: id,
Oldpath: oldname, Oldpath: oldname,
Newpath: newname, Newpath: newname,
@ -772,7 +772,7 @@ func (c *Client) PosixRename(oldname, newname string) error {
func (c *Client) realpath(path string) (string, error) { func (c *Client) realpath(path string) (string, error) {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpRealpathPacket{ typ, data, err := c.sendPacket(nil, &sshFxpRealpathPacket{
ID: id, ID: id,
Path: path, Path: path,
}) })
@ -809,7 +809,7 @@ func (c *Client) Getwd() (string, error) {
// parent folder does not exist (the method cannot create complete paths). // parent folder does not exist (the method cannot create complete paths).
func (c *Client) Mkdir(path string) error { func (c *Client) Mkdir(path string) error {
id := c.nextID() id := c.nextID()
typ, data, err := c.sendPacket(nil, sshFxpMkdirPacket{ typ, data, err := c.sendPacket(nil, &sshFxpMkdirPacket{
ID: id, ID: id,
Path: path, Path: path,
}) })
@ -916,7 +916,7 @@ func (f *File) Read(b []byte) (int, error) {
func (f *File) readChunkAt(ch chan result, b []byte, off int64) (n int, err error) { func (f *File) readChunkAt(ch chan result, b []byte, off int64) (n int, err error) {
for err == nil && n < len(b) { for err == nil && n < len(b) {
id := f.c.nextID() id := f.c.nextID()
typ, data, err := f.c.sendPacket(ch, sshFxpReadPacket{ typ, data, err := f.c.sendPacket(ch, &sshFxpReadPacket{
ID: id, ID: id,
Handle: f.handle, Handle: f.handle,
Offset: uint64(off) + uint64(n), Offset: uint64(off) + uint64(n),
@ -1282,7 +1282,7 @@ func (f *File) Write(b []byte) (int, error) {
} }
func (f *File) writeChunkAt(ch chan result, b []byte, off int64) (int, error) { func (f *File) writeChunkAt(ch chan result, b []byte, off int64) (int, error) {
typ, data, err := f.c.sendPacket(ch, sshFxpWritePacket{ typ, data, err := f.c.sendPacket(ch, &sshFxpWritePacket{
ID: f.c.nextID(), ID: f.c.nextID(),
Handle: f.handle, Handle: f.handle,
Offset: uint64(off), Offset: uint64(off),
@ -1674,7 +1674,7 @@ func (f *File) Chmod(mode os.FileMode) error {
// Sync requires the server to support the fsync@openssh.com extension. // Sync requires the server to support the fsync@openssh.com extension.
func (f *File) Sync() error { func (f *File) Sync() error {
id := f.c.nextID() id := f.c.nextID()
typ, data, err := f.c.sendPacket(nil, sshFxpFsyncPacket{ typ, data, err := f.c.sendPacket(nil, &sshFxpFsyncPacket{
ID: id, ID: id,
Handle: f.handle, Handle: f.handle,
}) })

View File

@ -186,6 +186,6 @@ type serverConn struct {
conn conn
} }
func (s *serverConn) sendError(p ider, err error) error { func (s *serverConn) sendError(id uint32, err error) error {
return s.sendPacket(statusFromError(p, err)) return s.sendPacket(statusFromError(id, err))
} }

View File

@ -34,51 +34,51 @@ type notReadOnly interface {
//// define types by adding methods //// define types by adding methods
// hasPath // hasPath
func (p sshFxpLstatPacket) getPath() string { return p.Path } func (p *sshFxpLstatPacket) getPath() string { return p.Path }
func (p sshFxpStatPacket) getPath() string { return p.Path } func (p *sshFxpStatPacket) getPath() string { return p.Path }
func (p sshFxpRmdirPacket) getPath() string { return p.Path } func (p *sshFxpRmdirPacket) getPath() string { return p.Path }
func (p sshFxpReadlinkPacket) getPath() string { return p.Path } func (p *sshFxpReadlinkPacket) getPath() string { return p.Path }
func (p sshFxpRealpathPacket) getPath() string { return p.Path } func (p *sshFxpRealpathPacket) getPath() string { return p.Path }
func (p sshFxpMkdirPacket) getPath() string { return p.Path } func (p *sshFxpMkdirPacket) getPath() string { return p.Path }
func (p sshFxpSetstatPacket) getPath() string { return p.Path } func (p *sshFxpSetstatPacket) getPath() string { return p.Path }
func (p sshFxpStatvfsPacket) getPath() string { return p.Path } func (p *sshFxpStatvfsPacket) getPath() string { return p.Path }
func (p sshFxpRemovePacket) getPath() string { return p.Filename } func (p *sshFxpRemovePacket) getPath() string { return p.Filename }
func (p sshFxpRenamePacket) getPath() string { return p.Oldpath } func (p *sshFxpRenamePacket) getPath() string { return p.Oldpath }
func (p sshFxpSymlinkPacket) getPath() string { return p.Targetpath } func (p *sshFxpSymlinkPacket) getPath() string { return p.Targetpath }
func (p sshFxpOpendirPacket) getPath() string { return p.Path } func (p *sshFxpOpendirPacket) getPath() string { return p.Path }
func (p sshFxpOpenPacket) getPath() string { return p.Path } func (p *sshFxpOpenPacket) getPath() string { return p.Path }
func (p sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath } func (p *sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath }
func (p sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath } func (p *sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath }
// getHandle // getHandle
func (p sshFxpFstatPacket) getHandle() string { return p.Handle } func (p *sshFxpFstatPacket) getHandle() string { return p.Handle }
func (p sshFxpFsetstatPacket) getHandle() string { return p.Handle } func (p *sshFxpFsetstatPacket) getHandle() string { return p.Handle }
func (p sshFxpReadPacket) getHandle() string { return p.Handle } func (p *sshFxpReadPacket) getHandle() string { return p.Handle }
func (p sshFxpWritePacket) getHandle() string { return p.Handle } func (p *sshFxpWritePacket) getHandle() string { return p.Handle }
func (p sshFxpReaddirPacket) getHandle() string { return p.Handle } func (p *sshFxpReaddirPacket) getHandle() string { return p.Handle }
func (p sshFxpClosePacket) getHandle() string { return p.Handle } func (p *sshFxpClosePacket) getHandle() string { return p.Handle }
// notReadOnly // notReadOnly
func (p sshFxpWritePacket) notReadOnly() {} func (p *sshFxpWritePacket) notReadOnly() {}
func (p sshFxpSetstatPacket) notReadOnly() {} func (p *sshFxpSetstatPacket) notReadOnly() {}
func (p sshFxpFsetstatPacket) notReadOnly() {} func (p *sshFxpFsetstatPacket) notReadOnly() {}
func (p sshFxpRemovePacket) notReadOnly() {} func (p *sshFxpRemovePacket) notReadOnly() {}
func (p sshFxpMkdirPacket) notReadOnly() {} func (p *sshFxpMkdirPacket) notReadOnly() {}
func (p sshFxpRmdirPacket) notReadOnly() {} func (p *sshFxpRmdirPacket) notReadOnly() {}
func (p sshFxpRenamePacket) notReadOnly() {} func (p *sshFxpRenamePacket) notReadOnly() {}
func (p sshFxpSymlinkPacket) notReadOnly() {} func (p *sshFxpSymlinkPacket) notReadOnly() {}
func (p sshFxpExtendedPacketPosixRename) notReadOnly() {} func (p *sshFxpExtendedPacketPosixRename) notReadOnly() {}
func (p sshFxpExtendedPacketHardlink) notReadOnly() {} func (p *sshFxpExtendedPacketHardlink) notReadOnly() {}
// some packets with ID are missing id() // some packets with ID are missing id()
func (p sshFxpDataPacket) id() uint32 { return p.ID } func (p *sshFxpDataPacket) id() uint32 { return p.ID }
func (p sshFxpStatusPacket) id() uint32 { return p.ID } func (p *sshFxpStatusPacket) id() uint32 { return p.ID }
func (p sshFxpStatResponse) id() uint32 { return p.ID } func (p *sshFxpStatResponse) id() uint32 { return p.ID }
func (p sshFxpNamePacket) id() uint32 { return p.ID } func (p *sshFxpNamePacket) id() uint32 { return p.ID }
func (p sshFxpHandlePacket) id() uint32 { return p.ID } func (p *sshFxpHandlePacket) id() uint32 { return p.ID }
func (p StatVFS) id() uint32 { return p.ID } func (p *StatVFS) id() uint32 { return p.ID }
func (p sshFxVersionPacket) id() uint32 { return 0 } func (p *sshFxVersionPacket) id() uint32 { return 0 }
// take raw incoming packet data and build packet objects // take raw incoming packet data and build packet objects
func makePacket(p rxPacket) (requestPacket, error) { func makePacket(p rxPacket) (requestPacket, error) {

142
packet.go
View File

@ -218,7 +218,7 @@ type sshFxInitPacket struct {
Extensions []extensionPair Extensions []extensionPair
} }
func (p sshFxInitPacket) MarshalBinary() ([]byte, error) { func (p *sshFxInitPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version) l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
for _, e := range p.Extensions { for _, e := range p.Extensions {
l += 4 + len(e.Name) + 4 + len(e.Data) l += 4 + len(e.Name) + 4 + len(e.Data)
@ -261,7 +261,7 @@ type sshExtensionPair struct {
Name, Data string Name, Data string
} }
func (p sshFxVersionPacket) MarshalBinary() ([]byte, error) { func (p *sshFxVersionPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version) l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
for _, e := range p.Extensions { for _, e := range p.Extensions {
l += 4 + len(e.Name) + 4 + len(e.Data) l += 4 + len(e.Name) + 4 + len(e.Data)
@ -306,9 +306,9 @@ type sshFxpReaddirPacket struct {
Handle string Handle string
} }
func (p sshFxpReaddirPacket) id() uint32 { return p.ID } func (p *sshFxpReaddirPacket) id() uint32 { return p.ID }
func (p sshFxpReaddirPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpReaddir, p.ID, p.Handle) return marshalIDStringPacket(sshFxpReaddir, p.ID, p.Handle)
} }
@ -321,9 +321,9 @@ type sshFxpOpendirPacket struct {
Path string Path string
} }
func (p sshFxpOpendirPacket) id() uint32 { return p.ID } func (p *sshFxpOpendirPacket) id() uint32 { return p.ID }
func (p sshFxpOpendirPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpOpendir, p.ID, p.Path) return marshalIDStringPacket(sshFxpOpendir, p.ID, p.Path)
} }
@ -336,9 +336,9 @@ type sshFxpLstatPacket struct {
Path string Path string
} }
func (p sshFxpLstatPacket) id() uint32 { return p.ID } func (p *sshFxpLstatPacket) id() uint32 { return p.ID }
func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpLstat, p.ID, p.Path) return marshalIDStringPacket(sshFxpLstat, p.ID, p.Path)
} }
@ -351,9 +351,9 @@ type sshFxpStatPacket struct {
Path string Path string
} }
func (p sshFxpStatPacket) id() uint32 { return p.ID } func (p *sshFxpStatPacket) id() uint32 { return p.ID }
func (p sshFxpStatPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpStatPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpStat, p.ID, p.Path) return marshalIDStringPacket(sshFxpStat, p.ID, p.Path)
} }
@ -366,9 +366,9 @@ type sshFxpFstatPacket struct {
Handle string Handle string
} }
func (p sshFxpFstatPacket) id() uint32 { return p.ID } func (p *sshFxpFstatPacket) id() uint32 { return p.ID }
func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpFstat, p.ID, p.Handle) return marshalIDStringPacket(sshFxpFstat, p.ID, p.Handle)
} }
@ -381,9 +381,9 @@ type sshFxpClosePacket struct {
Handle string Handle string
} }
func (p sshFxpClosePacket) id() uint32 { return p.ID } func (p *sshFxpClosePacket) id() uint32 { return p.ID }
func (p sshFxpClosePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpClosePacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpClose, p.ID, p.Handle) return marshalIDStringPacket(sshFxpClose, p.ID, p.Handle)
} }
@ -396,9 +396,9 @@ type sshFxpRemovePacket struct {
Filename string Filename string
} }
func (p sshFxpRemovePacket) id() uint32 { return p.ID } func (p *sshFxpRemovePacket) id() uint32 { return p.ID }
func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpRemove, p.ID, p.Filename) return marshalIDStringPacket(sshFxpRemove, p.ID, p.Filename)
} }
@ -411,9 +411,9 @@ type sshFxpRmdirPacket struct {
Path string Path string
} }
func (p sshFxpRmdirPacket) id() uint32 { return p.ID } func (p *sshFxpRmdirPacket) id() uint32 { return p.ID }
func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpRmdir, p.ID, p.Path) return marshalIDStringPacket(sshFxpRmdir, p.ID, p.Path)
} }
@ -427,9 +427,9 @@ type sshFxpSymlinkPacket struct {
Linkpath string Linkpath string
} }
func (p sshFxpSymlinkPacket) id() uint32 { return p.ID } func (p *sshFxpSymlinkPacket) id() uint32 { return p.ID }
func (p sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Targetpath) + 4 + len(p.Targetpath) +
4 + len(p.Linkpath) 4 + len(p.Linkpath)
@ -461,9 +461,9 @@ type sshFxpHardlinkPacket struct {
Newpath string Newpath string
} }
func (p sshFxpHardlinkPacket) id() uint32 { return p.ID } func (p *sshFxpHardlinkPacket) id() uint32 { return p.ID }
func (p sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) {
const ext = "hardlink@openssh.com" const ext = "hardlink@openssh.com"
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(ext) + 4 + len(ext) +
@ -485,9 +485,9 @@ type sshFxpReadlinkPacket struct {
Path string Path string
} }
func (p sshFxpReadlinkPacket) id() uint32 { return p.ID } func (p *sshFxpReadlinkPacket) id() uint32 { return p.ID }
func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpReadlink, p.ID, p.Path) return marshalIDStringPacket(sshFxpReadlink, p.ID, p.Path)
} }
@ -500,9 +500,9 @@ type sshFxpRealpathPacket struct {
Path string Path string
} }
func (p sshFxpRealpathPacket) id() uint32 { return p.ID } func (p *sshFxpRealpathPacket) id() uint32 { return p.ID }
func (p sshFxpRealpathPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpRealpathPacket) MarshalBinary() ([]byte, error) {
return marshalIDStringPacket(sshFxpRealpath, p.ID, p.Path) return marshalIDStringPacket(sshFxpRealpath, p.ID, p.Path)
} }
@ -516,7 +516,7 @@ type sshFxpNameAttr struct {
Attrs []interface{} Attrs []interface{}
} }
func (p sshFxpNameAttr) MarshalBinary() ([]byte, error) { func (p *sshFxpNameAttr) MarshalBinary() ([]byte, error) {
var b []byte var b []byte
b = marshalString(b, p.Name) b = marshalString(b, p.Name)
b = marshalString(b, p.LongName) b = marshalString(b, p.LongName)
@ -528,10 +528,10 @@ func (p sshFxpNameAttr) MarshalBinary() ([]byte, error) {
type sshFxpNamePacket struct { type sshFxpNamePacket struct {
ID uint32 ID uint32
NameAttrs []sshFxpNameAttr NameAttrs []*sshFxpNameAttr
} }
func (p sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 4
@ -553,7 +553,7 @@ func (p sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) {
return b, payload, nil return b, payload, nil
} }
func (p sshFxpNamePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpNamePacket) MarshalBinary() ([]byte, error) {
header, payload, err := p.marshalPacket() header, payload, err := p.marshalPacket()
return append(header, payload...), err return append(header, payload...), err
} }
@ -565,9 +565,9 @@ type sshFxpOpenPacket struct {
Flags uint32 // ignored Flags uint32 // ignored
} }
func (p sshFxpOpenPacket) id() uint32 { return p.ID } func (p *sshFxpOpenPacket) id() uint32 { return p.ID }
func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Path) + 4 + len(p.Path) +
4 + 4 4 + 4
@ -603,9 +603,9 @@ type sshFxpReadPacket struct {
Handle string Handle string
} }
func (p sshFxpReadPacket) id() uint32 { return p.ID } func (p *sshFxpReadPacket) id() uint32 { return p.ID }
func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpReadPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Handle) + 4 + len(p.Handle) +
8 + 4 // uint64 + uint32 8 + 4 // uint64 + uint32
@ -655,9 +655,9 @@ type sshFxpRenamePacket struct {
Newpath string Newpath string
} }
func (p sshFxpRenamePacket) id() uint32 { return p.ID } func (p *sshFxpRenamePacket) id() uint32 { return p.ID }
func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Oldpath) + 4 + len(p.Oldpath) +
4 + len(p.Newpath) 4 + len(p.Newpath)
@ -689,9 +689,9 @@ type sshFxpPosixRenamePacket struct {
Newpath string Newpath string
} }
func (p sshFxpPosixRenamePacket) id() uint32 { return p.ID } func (p *sshFxpPosixRenamePacket) id() uint32 { return p.ID }
func (p sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) {
const ext = "posix-rename@openssh.com" const ext = "posix-rename@openssh.com"
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(ext) + 4 + len(ext) +
@ -716,9 +716,9 @@ type sshFxpWritePacket struct {
Data []byte Data []byte
} }
func (p sshFxpWritePacket) id() uint32 { return p.ID } func (p *sshFxpWritePacket) id() uint32 { return p.ID }
func (p sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Handle) + 4 + len(p.Handle) +
8 + // uint64 8 + // uint64
@ -734,7 +734,7 @@ func (p sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) {
return b, p.Data, nil return b, p.Data, nil
} }
func (p sshFxpWritePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpWritePacket) MarshalBinary() ([]byte, error) {
header, payload, err := p.marshalPacket() header, payload, err := p.marshalPacket()
return append(header, payload...), err return append(header, payload...), err
} }
@ -763,9 +763,9 @@ type sshFxpMkdirPacket struct {
Path string Path string
} }
func (p sshFxpMkdirPacket) id() uint32 { return p.ID } func (p *sshFxpMkdirPacket) id() uint32 { return p.ID }
func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Path) + 4 + len(p.Path) +
4 // uint32 4 // uint32
@ -805,10 +805,10 @@ type sshFxpFsetstatPacket struct {
Attrs interface{} Attrs interface{}
} }
func (p sshFxpSetstatPacket) id() uint32 { return p.ID } func (p *sshFxpSetstatPacket) id() uint32 { return p.ID }
func (p sshFxpFsetstatPacket) id() uint32 { return p.ID } func (p *sshFxpFsetstatPacket) id() uint32 { return p.ID }
func (p sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Path) + 4 + len(p.Path) +
4 // uint32 4 // uint32
@ -824,12 +824,12 @@ func (p sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) {
return b, payload, nil return b, payload, nil
} }
func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
header, payload, err := p.marshalPacket() header, payload, err := p.marshalPacket()
return append(header, payload...), err return append(header, payload...), err
} }
func (p sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Handle) + 4 + len(p.Handle) +
4 // uint32 4 // uint32
@ -845,7 +845,7 @@ func (p sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) {
return b, payload, nil return b, payload, nil
} }
func (p sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) {
header, payload, err := p.marshalPacket() header, payload, err := p.marshalPacket()
return append(header, payload...), err return append(header, payload...), err
} }
@ -881,7 +881,7 @@ type sshFxpHandlePacket struct {
Handle string Handle string
} }
func (p sshFxpHandlePacket) MarshalBinary() ([]byte, error) { func (p *sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(p.Handle) 4 + len(p.Handle)
@ -898,7 +898,7 @@ type sshFxpStatusPacket struct {
StatusError StatusError
} }
func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + 4 +
4 + len(p.StatusError.msg) + 4 + len(p.StatusError.msg) +
@ -918,7 +918,7 @@ type sshFxpDataPacket struct {
Data []byte Data []byte
} }
func (p sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 4
@ -935,7 +935,7 @@ func (p sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) {
// //
// This is hand-coded rather than just append(header, payload...), // This is hand-coded rather than just append(header, payload...),
// in order to try and reuse the r.Data backing store in the packet. // in order to try and reuse the r.Data backing store in the packet.
func (p sshFxpDataPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpDataPacket) MarshalBinary() ([]byte, error) {
b := append(p.Data, make([]byte, dataHeaderLen)...) b := append(p.Data, make([]byte, dataHeaderLen)...)
copy(b[dataHeaderLen:], p.Data[:p.Length]) copy(b[dataHeaderLen:], p.Data[:p.Length])
// b[0:4] will be overwritten with the length in sendPacket // b[0:4] will be overwritten with the length in sendPacket
@ -964,9 +964,9 @@ type sshFxpStatvfsPacket struct {
Path string Path string
} }
func (p sshFxpStatvfsPacket) id() uint32 { return p.ID } func (p *sshFxpStatvfsPacket) id() uint32 { return p.ID }
func (p sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
const ext = "statvfs@openssh.com" const ext = "statvfs@openssh.com"
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(ext) + 4 + len(ext) +
@ -1027,9 +1027,9 @@ type sshFxpFsyncPacket struct {
Handle string Handle string
} }
func (p sshFxpFsyncPacket) id() uint32 { return p.ID } func (p *sshFxpFsyncPacket) id() uint32 { return p.ID }
func (p sshFxpFsyncPacket) MarshalBinary() ([]byte, error) { func (p *sshFxpFsyncPacket) MarshalBinary() ([]byte, error) {
const ext = "fsync@openssh.com" const ext = "fsync@openssh.com"
l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
4 + len(ext) + 4 + len(ext) +
@ -1053,17 +1053,17 @@ type sshFxpExtendedPacket struct {
} }
} }
func (p sshFxpExtendedPacket) id() uint32 { return p.ID } func (p *sshFxpExtendedPacket) id() uint32 { return p.ID }
func (p sshFxpExtendedPacket) readonly() bool { func (p *sshFxpExtendedPacket) readonly() bool {
if p.SpecificPacket == nil { if p.SpecificPacket == nil {
return true return true
} }
return p.SpecificPacket.readonly() return p.SpecificPacket.readonly()
} }
func (p sshFxpExtendedPacket) respond(svr *Server) responsePacket { func (p *sshFxpExtendedPacket) respond(svr *Server) responsePacket {
if p.SpecificPacket == nil { if p.SpecificPacket == nil {
return statusFromError(p, nil) return statusFromError(p.ID, nil)
} }
return p.SpecificPacket.respond(svr) return p.SpecificPacket.respond(svr)
} }
@ -1098,8 +1098,8 @@ type sshFxpExtendedPacketStatVFS struct {
Path string Path string
} }
func (p sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID } func (p *sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID }
func (p sshFxpExtendedPacketStatVFS) readonly() bool { return true } func (p *sshFxpExtendedPacketStatVFS) readonly() bool { return true }
func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error { func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error {
var err error var err error
if p.ID, b, err = unmarshalUint32Safe(b); err != nil { if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
@ -1119,8 +1119,8 @@ type sshFxpExtendedPacketPosixRename struct {
Newpath string Newpath string
} }
func (p sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID } func (p *sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID }
func (p sshFxpExtendedPacketPosixRename) readonly() bool { return false } func (p *sshFxpExtendedPacketPosixRename) readonly() bool { return false }
func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error { func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error {
var err error var err error
if p.ID, b, err = unmarshalUint32Safe(b); err != nil { if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
@ -1135,9 +1135,9 @@ func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error {
return nil return nil
} }
func (p sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket { func (p *sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
err := os.Rename(p.Oldpath, p.Newpath) err := os.Rename(p.Oldpath, p.Newpath)
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
type sshFxpExtendedPacketHardlink struct { type sshFxpExtendedPacketHardlink struct {
@ -1148,8 +1148,8 @@ type sshFxpExtendedPacketHardlink struct {
} }
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
func (p sshFxpExtendedPacketHardlink) id() uint32 { return p.ID } func (p *sshFxpExtendedPacketHardlink) id() uint32 { return p.ID }
func (p sshFxpExtendedPacketHardlink) readonly() bool { return true } func (p *sshFxpExtendedPacketHardlink) readonly() bool { return true }
func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error { func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
var err error var err error
if p.ID, b, err = unmarshalUint32Safe(b); err != nil { if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
@ -1164,7 +1164,7 @@ func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
return nil return nil
} }
func (p sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket { func (p *sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket {
err := os.Link(p.Oldpath, p.Newpath) err := os.Link(p.Oldpath, p.Newpath)
return statusFromError(p, err) return statusFromError(p.ID, err)
} }

View File

@ -142,20 +142,20 @@ var sendPacketTests = []struct {
p encoding.BinaryMarshaler p encoding.BinaryMarshaler
want []byte want []byte
}{ }{
{sshFxInitPacket{ {&sshFxInitPacket{
Version: 3, Version: 3,
Extensions: []extensionPair{ Extensions: []extensionPair{
{"posix-rename@openssh.com", "1"}, {"posix-rename@openssh.com", "1"},
}, },
}, []byte{0x0, 0x0, 0x0, 0x26, 0x1, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x18, 0x70, 0x6f, 0x73, 0x69, 0x78, 0x2d, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0x0, 0x1, 0x31}}, }, []byte{0x0, 0x0, 0x0, 0x26, 0x1, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x18, 0x70, 0x6f, 0x73, 0x69, 0x78, 0x2d, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0x0, 0x1, 0x31}},
{sshFxpOpenPacket{ {&sshFxpOpenPacket{
ID: 1, ID: 1,
Path: "/foo", Path: "/foo",
Pflags: flags(os.O_RDONLY), Pflags: flags(os.O_RDONLY),
}, []byte{0x0, 0x0, 0x0, 0x15, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x4, 0x2f, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0}}, }, []byte{0x0, 0x0, 0x0, 0x15, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x4, 0x2f, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0}},
{sshFxpWritePacket{ {&sshFxpWritePacket{
ID: 124, ID: 124,
Handle: "foo", Handle: "foo",
Offset: 13, Offset: 13,
@ -163,7 +163,7 @@ var sendPacketTests = []struct {
Data: []byte("bar"), Data: []byte("bar"),
}, []byte{0x0, 0x0, 0x0, 0x1b, 0x6, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x3, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x3, 0x62, 0x61, 0x72}}, }, []byte{0x0, 0x0, 0x0, 0x1b, 0x6, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x3, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x3, 0x62, 0x61, 0x72}},
{sshFxpSetstatPacket{ {&sshFxpSetstatPacket{
ID: 31, ID: 31,
Path: "/bar", Path: "/bar",
Flags: flags(os.O_WRONLY), Flags: flags(os.O_WRONLY),
@ -195,7 +195,7 @@ var recvPacketTests = []struct {
want uint8 want uint8
rest []byte rest []byte
}{ }{
{sp(sshFxInitPacket{ {sp(&sshFxInitPacket{
Version: 3, Version: 3,
Extensions: []extensionPair{ Extensions: []extensionPair{
{"posix-rename@openssh.com", "1"}, {"posix-rename@openssh.com", "1"},
@ -299,7 +299,7 @@ func TestSSHFxpOpenPackethasPflags(t *testing.T) {
func BenchmarkMarshalInit(b *testing.B) { func BenchmarkMarshalInit(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sp(sshFxInitPacket{ sp(&sshFxInitPacket{
Version: 3, Version: 3,
Extensions: []extensionPair{ Extensions: []extensionPair{
{"posix-rename@openssh.com", "1"}, {"posix-rename@openssh.com", "1"},
@ -310,7 +310,7 @@ func BenchmarkMarshalInit(b *testing.B) {
func BenchmarkMarshalOpen(b *testing.B) { func BenchmarkMarshalOpen(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sp(sshFxpOpenPacket{ sp(&sshFxpOpenPacket{
ID: 1, ID: 1,
Path: "/home/test/some/random/path", Path: "/home/test/some/random/path",
Pflags: flags(os.O_RDONLY), Pflags: flags(os.O_RDONLY),
@ -321,7 +321,7 @@ func BenchmarkMarshalOpen(b *testing.B) {
func BenchmarkMarshalWriteWorstCase(b *testing.B) { func BenchmarkMarshalWriteWorstCase(b *testing.B) {
data := make([]byte, 32*1024) data := make([]byte, 32*1024)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sp(sshFxpWritePacket{ sp(&sshFxpWritePacket{
ID: 1, ID: 1,
Handle: "someopaquehandle", Handle: "someopaquehandle",
Offset: 0, Offset: 0,
@ -334,7 +334,7 @@ func BenchmarkMarshalWriteWorstCase(b *testing.B) {
func BenchmarkMarshalWrite1k(b *testing.B) { func BenchmarkMarshalWrite1k(b *testing.B) {
data := make([]byte, 1024) data := make([]byte, 1024)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sp(sshFxpWritePacket{ sp(&sshFxpWritePacket{
ID: 1, ID: 1,
Handle: "someopaquehandle", Handle: "someopaquehandle",
Offset: 0, Offset: 0,

View File

@ -193,10 +193,10 @@ func (rs *RequestServer) packetWorker(
var rpkt responsePacket var rpkt responsePacket
switch pkt := pkt.requestPacket.(type) { switch pkt := pkt.requestPacket.(type) {
case *sshFxInitPacket: case *sshFxInitPacket:
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions} rpkt = &sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions}
case *sshFxpClosePacket: case *sshFxpClosePacket:
handle := pkt.getHandle() handle := pkt.getHandle()
rpkt = statusFromError(pkt, rs.closeRequest(handle)) rpkt = statusFromError(pkt.ID, rs.closeRequest(handle))
case *sshFxpRealpathPacket: case *sshFxpRealpathPacket:
rpkt = cleanPacketPath(pkt) rpkt = cleanPacketPath(pkt)
case *sshFxpOpendirPacket: case *sshFxpOpendirPacket:
@ -219,7 +219,7 @@ func (rs *RequestServer) packetWorker(
handle := pkt.getHandle() handle := pkt.getHandle()
request, ok := rs.getRequest(handle) request, ok := rs.getRequest(handle)
if !ok { if !ok {
rpkt = statusFromError(pkt, EBADF) rpkt = statusFromError(pkt.ID, EBADF)
} else { } else {
request = NewRequest("Stat", request.Filepath) request = NewRequest("Stat", request.Filepath)
rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID)
@ -228,7 +228,7 @@ func (rs *RequestServer) packetWorker(
handle := pkt.getHandle() handle := pkt.getHandle()
request, ok := rs.getRequest(handle) request, ok := rs.getRequest(handle)
if !ok { if !ok {
rpkt = statusFromError(pkt, EBADF) rpkt = statusFromError(pkt.ID, EBADF)
} else { } else {
request = NewRequest("Setstat", request.Filepath) request = NewRequest("Setstat", request.Filepath)
rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID)
@ -244,7 +244,7 @@ func (rs *RequestServer) packetWorker(
handle := pkt.getHandle() handle := pkt.getHandle()
request, ok := rs.getRequest(handle) request, ok := rs.getRequest(handle)
if !ok { if !ok {
rpkt = statusFromError(pkt, EBADF) rpkt = statusFromError(pkt.id(), EBADF)
} else { } else {
rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID)
} }
@ -253,7 +253,7 @@ func (rs *RequestServer) packetWorker(
rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID)
request.close() request.close()
default: default:
rpkt = statusFromError(pkt, ErrSSHFxOpUnsupported) rpkt = statusFromError(pkt.id(), ErrSSHFxOpUnsupported)
} }
rs.pktMgr.readyPacket( rs.pktMgr.readyPacket(
@ -267,11 +267,13 @@ func cleanPacketPath(pkt *sshFxpRealpathPacket) responsePacket {
path := cleanPath(pkt.getPath()) path := cleanPath(pkt.getPath())
return &sshFxpNamePacket{ return &sshFxpNamePacket{
ID: pkt.id(), ID: pkt.id(),
NameAttrs: []sshFxpNameAttr{{ NameAttrs: []*sshFxpNameAttr{
Name: path, &sshFxpNameAttr{
LongName: path, Name: path,
Attrs: emptyFileStat, LongName: path,
}}, Attrs: emptyFileStat,
},
},
} }
} }

View File

@ -219,7 +219,7 @@ func (r *Request) call(handlers Handlers, pkt requestPacket, alloc *allocator, o
case "Stat", "Lstat", "Readlink": case "Stat", "Lstat", "Readlink":
return filestat(handlers.FileList, r, pkt) return filestat(handlers.FileList, r, pkt)
default: default:
return statusFromError(pkt, return statusFromError(pkt.id(),
errors.Errorf("unexpected method: %s", r.Method)) errors.Errorf("unexpected method: %s", r.Method))
} }
} }
@ -228,6 +228,8 @@ func (r *Request) call(handlers Handlers, pkt requestPacket, alloc *allocator, o
func (r *Request) open(h Handlers, pkt requestPacket) responsePacket { func (r *Request) open(h Handlers, pkt requestPacket) responsePacket {
flags := r.Pflags() flags := r.Pflags()
id := pkt.id()
switch { switch {
case flags.Write, flags.Append, flags.Creat, flags.Trunc: case flags.Write, flags.Append, flags.Creat, flags.Trunc:
if flags.Read { if flags.Read {
@ -235,36 +237,37 @@ func (r *Request) open(h Handlers, pkt requestPacket) responsePacket {
r.Method = "Open" r.Method = "Open"
rw, err := openFileWriter.OpenFile(r) rw, err := openFileWriter.OpenFile(r)
if err != nil { if err != nil {
return statusFromError(pkt, err) return statusFromError(id, err)
} }
r.state.writerReaderAt = rw r.state.writerReaderAt = rw
return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} return &sshFxpHandlePacket{ID: id, Handle: r.handle}
} }
} }
r.Method = "Put" r.Method = "Put"
wr, err := h.FilePut.Filewrite(r) wr, err := h.FilePut.Filewrite(r)
if err != nil { if err != nil {
return statusFromError(pkt, err) return statusFromError(id, err)
} }
r.state.writerAt = wr r.state.writerAt = wr
case flags.Read: case flags.Read:
r.Method = "Get" r.Method = "Get"
rd, err := h.FileGet.Fileread(r) rd, err := h.FileGet.Fileread(r)
if err != nil { if err != nil {
return statusFromError(pkt, err) return statusFromError(id, err)
} }
r.state.readerAt = rd r.state.readerAt = rd
default: default:
return statusFromError(pkt, errors.New("bad file flags")) return statusFromError(id, errors.New("bad file flags"))
} }
return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} return &sshFxpHandlePacket{ID: id, Handle: r.handle}
} }
func (r *Request) opendir(h Handlers, pkt requestPacket) responsePacket { func (r *Request) opendir(h Handlers, pkt requestPacket) responsePacket {
r.Method = "List" r.Method = "List"
la, err := h.FileList.Filelist(r) la, err := h.FileList.Filelist(r)
if err != nil { if err != nil {
return statusFromError(pkt, wrapPathError(r.Filepath, err)) return statusFromError(pkt.id(), wrapPathError(r.Filepath, err))
} }
r.state.listerAt = la r.state.listerAt = la
return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle}
@ -276,14 +279,14 @@ func fileget(h FileReader, r *Request, pkt requestPacket, alloc *allocator, orde
reader := r.state.readerAt reader := r.state.readerAt
r.state.RUnlock() r.state.RUnlock()
if reader == nil { if reader == nil {
return statusFromError(pkt, errors.New("unexpected read packet")) return statusFromError(pkt.id(), errors.New("unexpected read packet"))
} }
data, offset, _ := packetData(pkt, alloc, orderID) data, offset, _ := packetData(pkt, alloc, orderID)
n, err := reader.ReadAt(data, offset) n, err := reader.ReadAt(data, offset)
// only return EOF error if no data left to read // only return EOF error if no data left to read
if err != nil && (err != io.EOF || n == 0) { if err != nil && (err != io.EOF || n == 0) {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
return &sshFxpDataPacket{ return &sshFxpDataPacket{
ID: pkt.id(), ID: pkt.id(),
@ -298,12 +301,12 @@ func fileput(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, orde
writer := r.state.writerAt writer := r.state.writerAt
r.state.RUnlock() r.state.RUnlock()
if writer == nil { if writer == nil {
return statusFromError(pkt, errors.New("unexpected write packet")) return statusFromError(pkt.id(), errors.New("unexpected write packet"))
} }
data, offset, _ := packetData(pkt, alloc, orderID) data, offset, _ := packetData(pkt, alloc, orderID)
_, err := writer.WriteAt(data, offset) _, err := writer.WriteAt(data, offset)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
// wrap OpenFileWriter handler // wrap OpenFileWriter handler
@ -312,7 +315,7 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o
writerReader := r.state.writerReaderAt writerReader := r.state.writerReaderAt
r.state.RUnlock() r.state.RUnlock()
if writerReader == nil { if writerReader == nil {
return statusFromError(pkt, errors.New("unexpected write and read packet")) return statusFromError(pkt.id(), errors.New("unexpected write and read packet"))
} }
switch p := pkt.(type) { switch p := pkt.(type) {
case *sshFxpReadPacket: case *sshFxpReadPacket:
@ -320,7 +323,7 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o
n, err := writerReader.ReadAt(data, offset) n, err := writerReader.ReadAt(data, offset)
// only return EOF error if no data left to read // only return EOF error if no data left to read
if err != nil && (err != io.EOF || n == 0) { if err != nil && (err != io.EOF || n == 0) {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
return &sshFxpDataPacket{ return &sshFxpDataPacket{
ID: pkt.id(), ID: pkt.id(),
@ -330,9 +333,9 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o
case *sshFxpWritePacket: case *sshFxpWritePacket:
data, offset := p.Data, int64(p.Offset) data, offset := p.Data, int64(p.Offset)
_, err := writerReader.WriteAt(data, offset) _, err := writerReader.WriteAt(data, offset)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
default: default:
return statusFromError(pkt, errors.New("unexpected packet type for read or write")) return statusFromError(pkt.id(), errors.New("unexpected packet type for read or write"))
} }
} }
@ -358,30 +361,30 @@ func filecmd(h FileCmder, r *Request, pkt requestPacket) responsePacket {
if r.Method == "PosixRename" { if r.Method == "PosixRename" {
if posixRenamer, ok := h.(PosixRenameFileCmder); ok { if posixRenamer, ok := h.(PosixRenameFileCmder); ok {
err := posixRenamer.PosixRename(r) err := posixRenamer.PosixRename(r)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
// PosixRenameFileCmder not implemented handle this request as a Rename // PosixRenameFileCmder not implemented handle this request as a Rename
r.Method = "Rename" r.Method = "Rename"
err := h.Filecmd(r) err := h.Filecmd(r)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
if r.Method == "StatVFS" { if r.Method == "StatVFS" {
if statVFSCmdr, ok := h.(StatVFSFileCmder); ok { if statVFSCmdr, ok := h.(StatVFSFileCmder); ok {
stat, err := statVFSCmdr.StatVFS(r) stat, err := statVFSCmdr.StatVFS(r)
if err != nil { if err != nil {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
stat.ID = pkt.id() stat.ID = pkt.id()
return stat return stat
} }
return statusFromError(pkt, ErrSSHFxOpUnsupported) return statusFromError(pkt.id(), ErrSSHFxOpUnsupported)
} }
err := h.Filecmd(r) err := h.Filecmd(r)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
// wrap FileLister handler // wrap FileLister handler
@ -389,7 +392,7 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket {
var err error var err error
lister := r.getLister() lister := r.getLister()
if lister == nil { if lister == nil {
return statusFromError(pkt, errors.New("unexpected dir packet")) return statusFromError(pkt.id(), errors.New("unexpected dir packet"))
} }
offset := r.lsNext() offset := r.lsNext()
@ -402,16 +405,16 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket {
switch r.Method { switch r.Method {
case "List": case "List":
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
if err == io.EOF && n == 0 { if err == io.EOF && n == 0 {
return statusFromError(pkt, io.EOF) return statusFromError(pkt.id(), io.EOF)
} }
dirname := filepath.ToSlash(path.Base(r.Filepath)) dirname := filepath.ToSlash(path.Base(r.Filepath))
ret := &sshFxpNamePacket{ID: pkt.id()} ret := &sshFxpNamePacket{ID: pkt.id()}
for _, fi := range finfo { for _, fi := range finfo {
ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ ret.NameAttrs = append(ret.NameAttrs, &sshFxpNameAttr{
Name: fi.Name(), Name: fi.Name(),
LongName: runLs(dirname, fi), LongName: runLs(dirname, fi),
Attrs: []interface{}{fi}, Attrs: []interface{}{fi},
@ -420,7 +423,7 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket {
return ret return ret
default: default:
err = errors.Errorf("unexpected method: %s", r.Method) err = errors.Errorf("unexpected method: %s", r.Method)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
} }
@ -440,7 +443,7 @@ func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket {
lister, err = h.Filelist(r) lister, err = h.Filelist(r)
} }
if err != nil { if err != nil {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
finfo := make([]os.FileInfo, 1) finfo := make([]os.FileInfo, 1)
n, err := lister.ListAt(finfo, 0) n, err := lister.ListAt(finfo, 0)
@ -449,12 +452,12 @@ func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket {
switch r.Method { switch r.Method {
case "Stat", "Lstat": case "Stat", "Lstat":
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
if n == 0 { if n == 0 {
err = &os.PathError{Op: strings.ToLower(r.Method), Path: r.Filepath, err = &os.PathError{Op: strings.ToLower(r.Method), Path: r.Filepath,
Err: syscall.ENOENT} Err: syscall.ENOENT}
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
return &sshFxpStatResponse{ return &sshFxpStatResponse{
ID: pkt.id(), ID: pkt.id(),
@ -462,25 +465,27 @@ func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket {
} }
case "Readlink": case "Readlink":
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
if n == 0 { if n == 0 {
err = &os.PathError{Op: "readlink", Path: r.Filepath, err = &os.PathError{Op: "readlink", Path: r.Filepath,
Err: syscall.ENOENT} Err: syscall.ENOENT}
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
filename := finfo[0].Name() filename := finfo[0].Name()
return &sshFxpNamePacket{ return &sshFxpNamePacket{
ID: pkt.id(), ID: pkt.id(),
NameAttrs: []sshFxpNameAttr{{ NameAttrs: []*sshFxpNameAttr{
Name: filename, &sshFxpNameAttr{
LongName: filename, Name: filename,
Attrs: emptyFileStat, LongName: filename,
}}, Attrs: emptyFileStat,
},
},
} }
default: default:
err = errors.Errorf("unexpected method: %s", r.Method) err = errors.Errorf("unexpected method: %s", r.Method)
return statusFromError(pkt, err) return statusFromError(pkt.id(), err)
} }
} }

View File

@ -118,11 +118,11 @@ func (h *Handlers) returnError(err error) {
} }
func getStatusMsg(p interface{}) string { func getStatusMsg(p interface{}) string {
pkt := p.(sshFxpStatusPacket) pkt := p.(*sshFxpStatusPacket)
return pkt.StatusError.msg return pkt.StatusError.msg
} }
func checkOkStatus(t *testing.T, p interface{}) { func checkOkStatus(t *testing.T, p interface{}) {
pkt := p.(sshFxpStatusPacket) pkt := p.(*sshFxpStatusPacket)
assert.Equal(t, pkt.StatusError.Code, uint32(sshFxOk), assert.Equal(t, pkt.StatusError.Code, uint32(sshFxOk),
"sshFxpStatusPacket not OK\n", pkt.StatusError.msg) "sshFxpStatusPacket not OK\n", pkt.StatusError.msg)
} }
@ -166,7 +166,7 @@ func TestRequestCustomError(t *testing.T) {
cmdErr := errors.New("stat not supported") cmdErr := errors.New("stat not supported")
handlers.returnError(cmdErr) handlers.returnError(cmdErr)
rpkt := request.call(handlers, pkt, nil, 0) rpkt := request.call(handlers, pkt, nil, 0)
assert.Equal(t, rpkt, statusFromError(rpkt, cmdErr)) assert.Equal(t, rpkt, statusFromError(pkt.myid, cmdErr))
} }
// XXX can't just set method to Get, need to use Open to setup Get/Put // XXX can't just set method to Get, need to use Open to setup Get/Put
@ -194,7 +194,7 @@ func TestRequestCmdr(t *testing.T) {
handlers.returnError(errTest) handlers.returnError(errTest)
rpkt = request.call(handlers, pkt, nil, 0) rpkt = request.call(handlers, pkt, nil, 0)
assert.Equal(t, rpkt, statusFromError(rpkt, errTest)) assert.Equal(t, rpkt, statusFromError(pkt.myid, errTest))
} }
func TestRequestInfoStat(t *testing.T) { func TestRequestInfoStat(t *testing.T) {
@ -227,7 +227,7 @@ func TestRequestInfoReadlink(t *testing.T) {
rpkt := request.call(handlers, pkt, nil, 0) rpkt := request.call(handlers, pkt, nil, 0)
npkt, ok := rpkt.(*sshFxpNamePacket) npkt, ok := rpkt.(*sshFxpNamePacket)
if assert.True(t, ok) { if assert.True(t, ok) {
assert.IsType(t, sshFxpNameAttr{}, npkt.NameAttrs[0]) assert.IsType(t, &sshFxpNameAttr{}, npkt.NameAttrs[0])
assert.Equal(t, npkt.NameAttrs[0].Name, "request_test.go") assert.Equal(t, npkt.NameAttrs[0].Name, "request_test.go")
} }
} }

120
server.go
View File

@ -152,7 +152,7 @@ func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error {
// return permission denied // return permission denied
if !readonly && svr.readOnly { if !readonly && svr.readOnly {
svr.pktMgr.readyPacket( svr.pktMgr.readyPacket(
svr.pktMgr.newOrderedResponse(statusFromError(pkt, syscall.EPERM), pkt.orderID()), svr.pktMgr.newOrderedResponse(statusFromError(pkt.id(), syscall.EPERM), pkt.orderID()),
) )
continue continue
} }
@ -169,29 +169,29 @@ func handlePacket(s *Server, p orderedRequest) error {
orderID := p.orderID() orderID := p.orderID()
switch p := p.requestPacket.(type) { switch p := p.requestPacket.(type) {
case *sshFxInitPacket: case *sshFxInitPacket:
rpkt = sshFxVersionPacket{ rpkt = &sshFxVersionPacket{
Version: sftpProtocolVersion, Version: sftpProtocolVersion,
Extensions: sftpExtensions, Extensions: sftpExtensions,
} }
case *sshFxpStatPacket: case *sshFxpStatPacket:
// stat the requested file // stat the requested file
info, err := os.Stat(p.Path) info, err := os.Stat(p.Path)
rpkt = sshFxpStatResponse{ rpkt = &sshFxpStatResponse{
ID: p.ID, ID: p.ID,
info: info, info: info,
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpLstatPacket: case *sshFxpLstatPacket:
// stat the requested file // stat the requested file
info, err := os.Lstat(p.Path) info, err := os.Lstat(p.Path)
rpkt = sshFxpStatResponse{ rpkt = &sshFxpStatResponse{
ID: p.ID, ID: p.ID,
info: info, info: info,
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpFstatPacket: case *sshFxpFstatPacket:
f, ok := s.getHandle(p.Handle) f, ok := s.getHandle(p.Handle)
@ -199,71 +199,75 @@ func handlePacket(s *Server, p orderedRequest) error {
var info os.FileInfo var info os.FileInfo
if ok { if ok {
info, err = f.Stat() info, err = f.Stat()
rpkt = sshFxpStatResponse{ rpkt = &sshFxpStatResponse{
ID: p.ID, ID: p.ID,
info: info, info: info,
} }
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpMkdirPacket: case *sshFxpMkdirPacket:
// TODO FIXME: ignore flags field // TODO FIXME: ignore flags field
err := os.Mkdir(p.Path, 0755) err := os.Mkdir(p.Path, 0755)
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpRmdirPacket: case *sshFxpRmdirPacket:
err := os.Remove(p.Path) err := os.Remove(p.Path)
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpRemovePacket: case *sshFxpRemovePacket:
err := os.Remove(p.Filename) err := os.Remove(p.Filename)
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpRenamePacket: case *sshFxpRenamePacket:
err := os.Rename(p.Oldpath, p.Newpath) err := os.Rename(p.Oldpath, p.Newpath)
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpSymlinkPacket: case *sshFxpSymlinkPacket:
err := os.Symlink(p.Targetpath, p.Linkpath) err := os.Symlink(p.Targetpath, p.Linkpath)
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpClosePacket: case *sshFxpClosePacket:
rpkt = statusFromError(p, s.closeHandle(p.Handle)) rpkt = statusFromError(p.ID, s.closeHandle(p.Handle))
case *sshFxpReadlinkPacket: case *sshFxpReadlinkPacket:
f, err := os.Readlink(p.Path) f, err := os.Readlink(p.Path)
rpkt = sshFxpNamePacket{ rpkt = &sshFxpNamePacket{
ID: p.ID, ID: p.ID,
NameAttrs: []sshFxpNameAttr{{ NameAttrs: []*sshFxpNameAttr{
Name: f, &sshFxpNameAttr{
LongName: f, Name: f,
Attrs: emptyFileStat, LongName: f,
}}, Attrs: emptyFileStat,
},
},
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpRealpathPacket: case *sshFxpRealpathPacket:
f, err := filepath.Abs(p.Path) f, err := filepath.Abs(p.Path)
f = cleanPath(f) f = cleanPath(f)
rpkt = sshFxpNamePacket{ rpkt = &sshFxpNamePacket{
ID: p.ID, ID: p.ID,
NameAttrs: []sshFxpNameAttr{{ NameAttrs: []*sshFxpNameAttr{
Name: f, &sshFxpNameAttr{
LongName: f, Name: f,
Attrs: emptyFileStat, LongName: f,
}}, Attrs: emptyFileStat,
},
},
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpOpendirPacket: case *sshFxpOpendirPacket:
if stat, err := os.Stat(p.Path); err != nil { if stat, err := os.Stat(p.Path); err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} else if !stat.IsDir() { } else if !stat.IsDir() {
rpkt = statusFromError(p, &os.PathError{ rpkt = statusFromError(p.ID, &os.PathError{
Path: p.Path, Err: syscall.ENOTDIR}) Path: p.Path, Err: syscall.ENOTDIR})
} else { } else {
rpkt = sshFxpOpenPacket{ rpkt = (&sshFxpOpenPacket{
ID: p.ID, ID: p.ID,
Path: p.Path, Path: p.Path,
Pflags: sshFxfRead, Pflags: sshFxfRead,
}.respond(s) }).respond(s)
} }
case *sshFxpReadPacket: case *sshFxpReadPacket:
var err error = EBADF var err error = EBADF
@ -275,7 +279,7 @@ func handlePacket(s *Server, p orderedRequest) error {
if _err != nil && (_err != io.EOF || n == 0) { if _err != nil && (_err != io.EOF || n == 0) {
err = _err err = _err
} }
rpkt = sshFxpDataPacket{ rpkt = &sshFxpDataPacket{
ID: p.ID, ID: p.ID,
Length: uint32(n), Length: uint32(n),
Data: data[:n], Data: data[:n],
@ -283,7 +287,7 @@ func handlePacket(s *Server, p orderedRequest) error {
} }
} }
if err != nil { if err != nil {
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
} }
case *sshFxpWritePacket: case *sshFxpWritePacket:
@ -292,10 +296,10 @@ func handlePacket(s *Server, p orderedRequest) error {
if ok { if ok {
_, err = f.WriteAt(p.Data, int64(p.Offset)) _, err = f.WriteAt(p.Data, int64(p.Offset))
} }
rpkt = statusFromError(p, err) rpkt = statusFromError(p.ID, err)
case *sshFxpExtendedPacket: case *sshFxpExtendedPacket:
if p.SpecificPacket == nil { if p.SpecificPacket == nil {
rpkt = statusFromError(p, ErrSSHFxOpUnsupported) rpkt = statusFromError(p.ID, ErrSSHFxOpUnsupported)
} else { } else {
rpkt = p.respond(s) rpkt = p.respond(s)
} }
@ -375,14 +379,14 @@ type ider interface {
} }
// The init packet has no ID, so we just return a zero-value ID // The init packet has no ID, so we just return a zero-value ID
func (p sshFxInitPacket) id() uint32 { return 0 } func (p *sshFxInitPacket) id() uint32 { return 0 }
type sshFxpStatResponse struct { type sshFxpStatResponse struct {
ID uint32 ID uint32
info os.FileInfo info os.FileInfo
} }
func (p sshFxpStatResponse) marshalPacket() ([]byte, []byte, error) { func (p *sshFxpStatResponse) marshalPacket() ([]byte, []byte, error) {
l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(id) l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(id)
b := make([]byte, 4, l) b := make([]byte, 4, l)
@ -395,18 +399,18 @@ func (p sshFxpStatResponse) marshalPacket() ([]byte, []byte, error) {
return b, payload, nil return b, payload, nil
} }
func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) { func (p *sshFxpStatResponse) MarshalBinary() ([]byte, error) {
header, payload, err := p.marshalPacket() header, payload, err := p.marshalPacket()
return append(header, payload...), err return append(header, payload...), err
} }
var emptyFileStat = []interface{}{uint32(0)} var emptyFileStat = []interface{}{uint32(0)}
func (p sshFxpOpenPacket) readonly() bool { func (p *sshFxpOpenPacket) readonly() bool {
return !p.hasPflags(sshFxfWrite) return !p.hasPflags(sshFxfWrite)
} }
func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool { func (p *sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
for _, f := range flags { for _, f := range flags {
if p.Pflags&f == 0 { if p.Pflags&f == 0 {
return false return false
@ -415,7 +419,7 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
return true return true
} }
func (p sshFxpOpenPacket) respond(svr *Server) responsePacket { func (p *sshFxpOpenPacket) respond(svr *Server) responsePacket {
var osFlags int var osFlags int
if p.hasPflags(sshFxfRead, sshFxfWrite) { if p.hasPflags(sshFxfRead, sshFxfWrite) {
osFlags |= os.O_RDWR osFlags |= os.O_RDWR
@ -425,7 +429,7 @@ func (p sshFxpOpenPacket) respond(svr *Server) responsePacket {
osFlags |= os.O_RDONLY osFlags |= os.O_RDONLY
} else { } else {
// how are they opening? // how are they opening?
return statusFromError(p, syscall.EINVAL) return statusFromError(p.ID, syscall.EINVAL)
} }
// Don't use O_APPEND flag as it conflicts with WriteAt. // Don't use O_APPEND flag as it conflicts with WriteAt.
@ -443,28 +447,28 @@ func (p sshFxpOpenPacket) respond(svr *Server) responsePacket {
f, err := os.OpenFile(p.Path, osFlags, 0644) f, err := os.OpenFile(p.Path, osFlags, 0644)
if err != nil { if err != nil {
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
handle := svr.nextHandle(f) handle := svr.nextHandle(f)
return sshFxpHandlePacket{ID: p.id(), Handle: handle} return &sshFxpHandlePacket{ID: p.ID, Handle: handle}
} }
func (p sshFxpReaddirPacket) respond(svr *Server) responsePacket { func (p *sshFxpReaddirPacket) respond(svr *Server) responsePacket {
f, ok := svr.getHandle(p.Handle) f, ok := svr.getHandle(p.Handle)
if !ok { if !ok {
return statusFromError(p, EBADF) return statusFromError(p.ID, EBADF)
} }
dirname := f.Name() dirname := f.Name()
dirents, err := f.Readdir(128) dirents, err := f.Readdir(128)
if err != nil { if err != nil {
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
ret := sshFxpNamePacket{ID: p.ID} ret := &sshFxpNamePacket{ID: p.ID}
for _, dirent := range dirents { for _, dirent := range dirents {
ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ ret.NameAttrs = append(ret.NameAttrs, &sshFxpNameAttr{
Name: dirent.Name(), Name: dirent.Name(),
LongName: runLs(dirname, dirent), LongName: runLs(dirname, dirent),
Attrs: []interface{}{dirent}, Attrs: []interface{}{dirent},
@ -473,7 +477,7 @@ func (p sshFxpReaddirPacket) respond(svr *Server) responsePacket {
return ret return ret
} }
func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket { func (p *sshFxpSetstatPacket) respond(svr *Server) responsePacket {
// additional unmarshalling is required for each possibility here // additional unmarshalling is required for each possibility here
b := p.Attrs.([]byte) b := p.Attrs.([]byte)
var err error var err error
@ -512,13 +516,13 @@ func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
} }
} }
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket { func (p *sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
f, ok := svr.getHandle(p.Handle) f, ok := svr.getHandle(p.Handle)
if !ok { if !ok {
return statusFromError(p, EBADF) return statusFromError(p.ID, EBADF)
} }
// additional unmarshalling is required for each possibility here // additional unmarshalling is required for each possibility here
@ -559,12 +563,12 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
} }
} }
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
func statusFromError(p ider, err error) sshFxpStatusPacket { func statusFromError(id uint32, err error) *sshFxpStatusPacket {
ret := sshFxpStatusPacket{ ret := &sshFxpStatusPacket{
ID: p.id(), ID: id,
StatusError: StatusError{ StatusError: StatusError{
// sshFXOk = 0 // sshFXOk = 0
// sshFXEOF = 1 // sshFXEOF = 1

View File

@ -9,21 +9,20 @@ import (
"syscall" "syscall"
) )
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket {
retPkt, err := getStatVFSForPath(p.Path) retPkt, err := getStatVFSForPath(p.Path)
if err != nil { if err != nil {
return statusFromError(p, err) return statusFromError(p.ID, err)
} }
retPkt.ID = p.ID
return retPkt return retPkt
} }
func getStatVFSForPath(name string) (*StatVFS, error) { func getStatVFSForPath(name string) (*StatVFS, error) {
stat := &syscall.Statfs_t{} var stat syscall.Statfs_t
if err := syscall.Statfs(name, stat); err != nil { if err := syscall.Statfs(name, &stat); err != nil {
return nil, err return nil, err
} }
return statvfsFromStatfst(stat) return statvfsFromStatfst(&stat)
} }

View File

@ -4,8 +4,8 @@ import (
"syscall" "syscall"
) )
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket {
return statusFromError(p, syscall.EPLAN9) return statusFromError(p.ID, syscall.EPLAN9)
} }
func getStatVFSForPath(name string) (*StatVFS, error) { func getStatVFSForPath(name string) (*StatVFS, error) {

View File

@ -6,8 +6,8 @@ import (
"syscall" "syscall"
) )
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket {
return statusFromError(p, syscall.ENOTSUP) return statusFromError(p.ID, syscall.ENOTSUP)
} }
func getStatVFSForPath(name string) (*StatVFS, error) { func getStatVFSForPath(name string) (*StatVFS, error) {

View File

@ -281,10 +281,10 @@ func TestConcurrentRequests(t *testing.T) {
func TestStatusFromError(t *testing.T) { func TestStatusFromError(t *testing.T) {
type test struct { type test struct {
err error err error
pkt sshFxpStatusPacket pkt *sshFxpStatusPacket
} }
tpkt := func(id, code uint32) sshFxpStatusPacket { tpkt := func(id, code uint32) *sshFxpStatusPacket {
return sshFxpStatusPacket{ return &sshFxpStatusPacket{
ID: id, ID: id,
StatusError: StatusError{Code: code}, StatusError: StatusError{Code: code},
} }
@ -301,7 +301,7 @@ func TestStatusFromError(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc.pkt.StatusError.msg = tc.err.Error() tc.pkt.StatusError.msg = tc.err.Error()
assert.Equal(t, tc.pkt, statusFromError(tc.pkt, tc.err)) assert.Equal(t, tc.pkt, statusFromError(tc.pkt.ID, tc.err))
} }
} }
@ -327,13 +327,13 @@ func TestOpenStatRace(t *testing.T) {
pflags := flags(os.O_RDWR | os.O_CREATE | os.O_TRUNC) pflags := flags(os.O_RDWR | os.O_CREATE | os.O_TRUNC)
ch := make(chan result, 3) ch := make(chan result, 3)
id1 := client.nextID() id1 := client.nextID()
client.dispatchRequest(ch, sshFxpOpenPacket{ client.dispatchRequest(ch, &sshFxpOpenPacket{
ID: id1, ID: id1,
Path: tmppath, Path: tmppath,
Pflags: pflags, Pflags: pflags,
}) })
id2 := client.nextID() id2 := client.nextID()
client.dispatchRequest(ch, sshFxpLstatPacket{ client.dispatchRequest(ch, &sshFxpLstatPacket{
ID: id2, ID: id2,
Path: tmppath, Path: tmppath,
}) })
@ -370,8 +370,8 @@ func TestStatNonExistent(t *testing.T) {
} }
func TestServerWithBrokenClient(t *testing.T) { func TestServerWithBrokenClient(t *testing.T) {
validInit := sp(sshFxInitPacket{Version: 3}) validInit := sp(&sshFxInitPacket{Version: 3})
brokenOpen := sp(sshFxpOpenPacket{Path: "foo"}) brokenOpen := sp(&sshFxpOpenPacket{Path: "foo"})
brokenOpen = brokenOpen[:len(brokenOpen)-2] brokenOpen = brokenOpen[:len(brokenOpen)-2]
for _, clientInput := range [][]byte{ for _, clientInput := range [][]byte{

View File

@ -10,7 +10,6 @@ import (
) )
func TestErrFxCode(t *testing.T) { func TestErrFxCode(t *testing.T) {
ider := sshFxpStatusPacket{ID: 1}
table := []struct { table := []struct {
err error err error
fx fxerr fx fxerr
@ -22,7 +21,7 @@ func TestErrFxCode(t *testing.T) {
{err: io.EOF, fx: ErrSSHFxEOF}, {err: io.EOF, fx: ErrSSHFxEOF},
} }
for _, tt := range table { for _, tt := range table {
statusErr := statusFromError(ider, tt.err).StatusError statusErr := statusFromError(1, tt.err).StatusError
assert.Equal(t, statusErr.FxCode(), tt.fx) assert.Equal(t, statusErr.FxCode(), tt.fx)
} }
} }