From 861a8eaf5c37b4ad5b2f1d0fc61004101bbdcb49 Mon Sep 17 00:00:00 2001 From: Cassondra Foesch Date: Mon, 22 Feb 2021 12:00:27 +0000 Subject: [PATCH] pointer receivers and statusFromError(uint32, error) --- client.go | 46 ++++++------- conn.go | 4 +- packet-typing.go | 76 ++++++++++----------- packet.go | 142 ++++++++++++++++++++-------------------- packet_test.go | 18 ++--- request-server.go | 24 +++---- request.go | 79 +++++++++++----------- request_test.go | 10 +-- server.go | 120 +++++++++++++++++---------------- server_statvfs_impl.go | 11 ++-- server_statvfs_plan9.go | 4 +- server_statvfs_stubs.go | 4 +- server_test.go | 16 ++--- sftp_test.go | 3 +- 14 files changed, 283 insertions(+), 274 deletions(-) diff --git a/client.go b/client.go index 8ea9261a..11bb0bc2 100644 --- a/client.go +++ b/client.go @@ -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 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 }) } @@ -297,7 +297,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) { var done = false for !done { id := c.nextID() - typ, data, err1 := c.sendPacket(nil, sshFxpReaddirPacket{ + typ, data, err1 := c.sendPacket(nil, &sshFxpReaddirPacket{ ID: id, Handle: handle, }) @@ -340,7 +340,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) { func (c *Client) opendir(path string) (string, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpOpendirPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpOpendirPacket{ ID: id, 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. func (c *Client) Stat(p string) (os.FileInfo, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpStatPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpStatPacket{ ID: id, 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. func (c *Client) Lstat(p string) (os.FileInfo, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpLstatPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpLstatPacket{ ID: id, Path: p, }) @@ -417,7 +417,7 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) { // ReadLink reads the target of a symbolic link. func (c *Client) ReadLink(p string) (string, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpReadlinkPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpReadlinkPacket{ ID: id, 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' func (c *Client) Link(oldname, newname string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpHardlinkPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpHardlinkPacket{ ID: id, Oldpath: oldname, 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' func (c *Client) Symlink(oldname, newname string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpSymlinkPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpSymlinkPacket{ ID: id, Linkpath: newname, 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 { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpFsetstatPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpFsetstatPacket{ ID: id, Handle: handle, 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. func (c *Client) setstat(path string, flags uint32, attrs interface{}) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpSetstatPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpSetstatPacket{ ID: id, Path: path, 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) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpOpenPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpOpenPacket{ ID: id, Path: path, Pflags: pflags, @@ -597,7 +597,7 @@ func (c *Client) open(path string, pflags uint32) (*File, error) { // immediately after this request has been sent. func (c *Client) close(handle string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpClosePacket{ + typ, data, err := c.sendPacket(nil, &sshFxpClosePacket{ ID: id, Handle: handle, }) @@ -614,7 +614,7 @@ func (c *Client) close(handle string) error { func (c *Client) fstat(handle string) (*FileStat, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpFstatPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpFstatPacket{ ID: id, Handle: handle, }) @@ -643,7 +643,7 @@ func (c *Client) fstat(handle string) (*FileStat, error) { func (c *Client) StatVFS(path string) (*StatVFS, error) { // send the StatVFS packet to the server id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpStatvfsPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpStatvfsPacket{ ID: id, Path: path, }) @@ -698,7 +698,7 @@ func (c *Client) Remove(path string) error { func (c *Client) removeFile(path string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpRemovePacket{ + typ, data, err := c.sendPacket(nil, &sshFxpRemovePacket{ ID: id, Filename: path, }) @@ -716,7 +716,7 @@ func (c *Client) removeFile(path string) error { // RemoveDirectory removes a directory path. func (c *Client) RemoveDirectory(path string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpRmdirPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpRmdirPacket{ ID: id, Path: path, }) @@ -734,7 +734,7 @@ func (c *Client) RemoveDirectory(path string) error { // Rename renames a file. func (c *Client) Rename(oldname, newname string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpRenamePacket{ + typ, data, err := c.sendPacket(nil, &sshFxpRenamePacket{ ID: id, Oldpath: oldname, Newpath: newname, @@ -754,7 +754,7 @@ func (c *Client) Rename(oldname, newname string) error { // which will replace newname if it already exists. func (c *Client) PosixRename(oldname, newname string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpPosixRenamePacket{ + typ, data, err := c.sendPacket(nil, &sshFxpPosixRenamePacket{ ID: id, Oldpath: oldname, Newpath: newname, @@ -772,7 +772,7 @@ func (c *Client) PosixRename(oldname, newname string) error { func (c *Client) realpath(path string) (string, error) { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpRealpathPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpRealpathPacket{ ID: id, Path: path, }) @@ -809,7 +809,7 @@ func (c *Client) Getwd() (string, error) { // parent folder does not exist (the method cannot create complete paths). func (c *Client) Mkdir(path string) error { id := c.nextID() - typ, data, err := c.sendPacket(nil, sshFxpMkdirPacket{ + typ, data, err := c.sendPacket(nil, &sshFxpMkdirPacket{ ID: id, 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) { for err == nil && n < len(b) { id := f.c.nextID() - typ, data, err := f.c.sendPacket(ch, sshFxpReadPacket{ + typ, data, err := f.c.sendPacket(ch, &sshFxpReadPacket{ ID: id, Handle: f.handle, 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) { - typ, data, err := f.c.sendPacket(ch, sshFxpWritePacket{ + typ, data, err := f.c.sendPacket(ch, &sshFxpWritePacket{ ID: f.c.nextID(), Handle: f.handle, 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. func (f *File) Sync() error { id := f.c.nextID() - typ, data, err := f.c.sendPacket(nil, sshFxpFsyncPacket{ + typ, data, err := f.c.sendPacket(nil, &sshFxpFsyncPacket{ ID: id, Handle: f.handle, }) diff --git a/conn.go b/conn.go index a70703c7..952a2be4 100644 --- a/conn.go +++ b/conn.go @@ -186,6 +186,6 @@ type serverConn struct { conn } -func (s *serverConn) sendError(p ider, err error) error { - return s.sendPacket(statusFromError(p, err)) +func (s *serverConn) sendError(id uint32, err error) error { + return s.sendPacket(statusFromError(id, err)) } diff --git a/packet-typing.go b/packet-typing.go index addd0e32..da5c2bc6 100644 --- a/packet-typing.go +++ b/packet-typing.go @@ -34,51 +34,51 @@ type notReadOnly interface { //// define types by adding methods // hasPath -func (p sshFxpLstatPacket) getPath() string { return p.Path } -func (p sshFxpStatPacket) getPath() string { return p.Path } -func (p sshFxpRmdirPacket) getPath() string { return p.Path } -func (p sshFxpReadlinkPacket) getPath() string { return p.Path } -func (p sshFxpRealpathPacket) getPath() string { return p.Path } -func (p sshFxpMkdirPacket) getPath() string { return p.Path } -func (p sshFxpSetstatPacket) getPath() string { return p.Path } -func (p sshFxpStatvfsPacket) getPath() string { return p.Path } -func (p sshFxpRemovePacket) getPath() string { return p.Filename } -func (p sshFxpRenamePacket) getPath() string { return p.Oldpath } -func (p sshFxpSymlinkPacket) getPath() string { return p.Targetpath } -func (p sshFxpOpendirPacket) getPath() string { return p.Path } -func (p sshFxpOpenPacket) getPath() string { return p.Path } +func (p *sshFxpLstatPacket) getPath() string { return p.Path } +func (p *sshFxpStatPacket) getPath() string { return p.Path } +func (p *sshFxpRmdirPacket) getPath() string { return p.Path } +func (p *sshFxpReadlinkPacket) getPath() string { return p.Path } +func (p *sshFxpRealpathPacket) getPath() string { return p.Path } +func (p *sshFxpMkdirPacket) getPath() string { return p.Path } +func (p *sshFxpSetstatPacket) getPath() string { return p.Path } +func (p *sshFxpStatvfsPacket) getPath() string { return p.Path } +func (p *sshFxpRemovePacket) getPath() string { return p.Filename } +func (p *sshFxpRenamePacket) getPath() string { return p.Oldpath } +func (p *sshFxpSymlinkPacket) getPath() string { return p.Targetpath } +func (p *sshFxpOpendirPacket) getPath() string { return p.Path } +func (p *sshFxpOpenPacket) getPath() string { return p.Path } -func (p sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath } -func (p sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath } +func (p *sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath } +func (p *sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath } // getHandle -func (p sshFxpFstatPacket) getHandle() string { return p.Handle } -func (p sshFxpFsetstatPacket) getHandle() string { return p.Handle } -func (p sshFxpReadPacket) getHandle() string { return p.Handle } -func (p sshFxpWritePacket) getHandle() string { return p.Handle } -func (p sshFxpReaddirPacket) getHandle() string { return p.Handle } -func (p sshFxpClosePacket) getHandle() string { return p.Handle } +func (p *sshFxpFstatPacket) getHandle() string { return p.Handle } +func (p *sshFxpFsetstatPacket) getHandle() string { return p.Handle } +func (p *sshFxpReadPacket) getHandle() string { return p.Handle } +func (p *sshFxpWritePacket) getHandle() string { return p.Handle } +func (p *sshFxpReaddirPacket) getHandle() string { return p.Handle } +func (p *sshFxpClosePacket) getHandle() string { return p.Handle } // notReadOnly -func (p sshFxpWritePacket) notReadOnly() {} -func (p sshFxpSetstatPacket) notReadOnly() {} -func (p sshFxpFsetstatPacket) notReadOnly() {} -func (p sshFxpRemovePacket) notReadOnly() {} -func (p sshFxpMkdirPacket) notReadOnly() {} -func (p sshFxpRmdirPacket) notReadOnly() {} -func (p sshFxpRenamePacket) notReadOnly() {} -func (p sshFxpSymlinkPacket) notReadOnly() {} -func (p sshFxpExtendedPacketPosixRename) notReadOnly() {} -func (p sshFxpExtendedPacketHardlink) notReadOnly() {} +func (p *sshFxpWritePacket) notReadOnly() {} +func (p *sshFxpSetstatPacket) notReadOnly() {} +func (p *sshFxpFsetstatPacket) notReadOnly() {} +func (p *sshFxpRemovePacket) notReadOnly() {} +func (p *sshFxpMkdirPacket) notReadOnly() {} +func (p *sshFxpRmdirPacket) notReadOnly() {} +func (p *sshFxpRenamePacket) notReadOnly() {} +func (p *sshFxpSymlinkPacket) notReadOnly() {} +func (p *sshFxpExtendedPacketPosixRename) notReadOnly() {} +func (p *sshFxpExtendedPacketHardlink) notReadOnly() {} // some packets with ID are missing id() -func (p sshFxpDataPacket) id() uint32 { return p.ID } -func (p sshFxpStatusPacket) id() uint32 { return p.ID } -func (p sshFxpStatResponse) id() uint32 { return p.ID } -func (p sshFxpNamePacket) id() uint32 { return p.ID } -func (p sshFxpHandlePacket) id() uint32 { return p.ID } -func (p StatVFS) id() uint32 { return p.ID } -func (p sshFxVersionPacket) id() uint32 { return 0 } +func (p *sshFxpDataPacket) id() uint32 { return p.ID } +func (p *sshFxpStatusPacket) id() uint32 { return p.ID } +func (p *sshFxpStatResponse) id() uint32 { return p.ID } +func (p *sshFxpNamePacket) id() uint32 { return p.ID } +func (p *sshFxpHandlePacket) id() uint32 { return p.ID } +func (p *StatVFS) id() uint32 { return p.ID } +func (p *sshFxVersionPacket) id() uint32 { return 0 } // take raw incoming packet data and build packet objects func makePacket(p rxPacket) (requestPacket, error) { diff --git a/packet.go b/packet.go index 55a6021d..4a686355 100644 --- a/packet.go +++ b/packet.go @@ -218,7 +218,7 @@ type sshFxInitPacket struct { Extensions []extensionPair } -func (p sshFxInitPacket) MarshalBinary() ([]byte, error) { +func (p *sshFxInitPacket) MarshalBinary() ([]byte, error) { l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version) for _, e := range p.Extensions { l += 4 + len(e.Name) + 4 + len(e.Data) @@ -261,7 +261,7 @@ type sshExtensionPair struct { 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) for _, e := range p.Extensions { l += 4 + len(e.Name) + 4 + len(e.Data) @@ -306,9 +306,9 @@ type sshFxpReaddirPacket struct { 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) } @@ -321,9 +321,9 @@ type sshFxpOpendirPacket struct { 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) } @@ -336,9 +336,9 @@ type sshFxpLstatPacket struct { 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) } @@ -351,9 +351,9 @@ type sshFxpStatPacket struct { 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) } @@ -366,9 +366,9 @@ type sshFxpFstatPacket struct { 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) } @@ -381,9 +381,9 @@ type sshFxpClosePacket struct { 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) } @@ -396,9 +396,9 @@ type sshFxpRemovePacket struct { 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) } @@ -411,9 +411,9 @@ type sshFxpRmdirPacket struct { 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) } @@ -427,9 +427,9 @@ type sshFxpSymlinkPacket struct { 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) 4 + len(p.Targetpath) + 4 + len(p.Linkpath) @@ -461,9 +461,9 @@ type sshFxpHardlinkPacket struct { 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" l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + len(ext) + @@ -485,9 +485,9 @@ type sshFxpReadlinkPacket struct { 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) } @@ -500,9 +500,9 @@ type sshFxpRealpathPacket struct { 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) } @@ -516,7 +516,7 @@ type sshFxpNameAttr struct { Attrs []interface{} } -func (p sshFxpNameAttr) MarshalBinary() ([]byte, error) { +func (p *sshFxpNameAttr) MarshalBinary() ([]byte, error) { var b []byte b = marshalString(b, p.Name) b = marshalString(b, p.LongName) @@ -528,10 +528,10 @@ func (p sshFxpNameAttr) MarshalBinary() ([]byte, error) { type sshFxpNamePacket struct { 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) 4 @@ -553,7 +553,7 @@ func (p sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) { return b, payload, nil } -func (p sshFxpNamePacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpNamePacket) MarshalBinary() ([]byte, error) { header, payload, err := p.marshalPacket() return append(header, payload...), err } @@ -565,9 +565,9 @@ type sshFxpOpenPacket struct { 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) 4 + len(p.Path) + 4 + 4 @@ -603,9 +603,9 @@ type sshFxpReadPacket struct { 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) 4 + len(p.Handle) + 8 + 4 // uint64 + uint32 @@ -655,9 +655,9 @@ type sshFxpRenamePacket struct { 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) 4 + len(p.Oldpath) + 4 + len(p.Newpath) @@ -689,9 +689,9 @@ type sshFxpPosixRenamePacket struct { 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" l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + len(ext) + @@ -716,9 +716,9 @@ type sshFxpWritePacket struct { 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) 4 + len(p.Handle) + 8 + // uint64 @@ -734,7 +734,7 @@ func (p sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) { return b, p.Data, nil } -func (p sshFxpWritePacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpWritePacket) MarshalBinary() ([]byte, error) { header, payload, err := p.marshalPacket() return append(header, payload...), err } @@ -763,9 +763,9 @@ type sshFxpMkdirPacket struct { 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) 4 + len(p.Path) + 4 // uint32 @@ -805,10 +805,10 @@ type sshFxpFsetstatPacket struct { Attrs interface{} } -func (p sshFxpSetstatPacket) id() uint32 { return p.ID } -func (p sshFxpFsetstatPacket) id() uint32 { return p.ID } +func (p *sshFxpSetstatPacket) 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) 4 + len(p.Path) + 4 // uint32 @@ -824,12 +824,12 @@ func (p sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) { return b, payload, nil } -func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { header, payload, err := p.marshalPacket() 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) 4 + len(p.Handle) + 4 // uint32 @@ -845,7 +845,7 @@ func (p sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) { return b, payload, nil } -func (p sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) { header, payload, err := p.marshalPacket() return append(header, payload...), err } @@ -881,7 +881,7 @@ type sshFxpHandlePacket struct { Handle string } -func (p sshFxpHandlePacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpHandlePacket) MarshalBinary() ([]byte, error) { l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + len(p.Handle) @@ -898,7 +898,7 @@ type sshFxpStatusPacket struct { StatusError } -func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) { +func (p *sshFxpStatusPacket) MarshalBinary() ([]byte, error) { l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + 4 + len(p.StatusError.msg) + @@ -918,7 +918,7 @@ type sshFxpDataPacket struct { 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) 4 @@ -935,7 +935,7 @@ func (p sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) { // // This is hand-coded rather than just append(header, payload...), // 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)...) copy(b[dataHeaderLen:], p.Data[:p.Length]) // b[0:4] will be overwritten with the length in sendPacket @@ -964,9 +964,9 @@ type sshFxpStatvfsPacket struct { 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" l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + len(ext) + @@ -1027,9 +1027,9 @@ type sshFxpFsyncPacket struct { 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" l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 4 + len(ext) + @@ -1053,17 +1053,17 @@ type sshFxpExtendedPacket struct { } } -func (p sshFxpExtendedPacket) id() uint32 { return p.ID } -func (p sshFxpExtendedPacket) readonly() bool { +func (p *sshFxpExtendedPacket) id() uint32 { return p.ID } +func (p *sshFxpExtendedPacket) readonly() bool { if p.SpecificPacket == nil { return true } return p.SpecificPacket.readonly() } -func (p sshFxpExtendedPacket) respond(svr *Server) responsePacket { +func (p *sshFxpExtendedPacket) respond(svr *Server) responsePacket { if p.SpecificPacket == nil { - return statusFromError(p, nil) + return statusFromError(p.ID, nil) } return p.SpecificPacket.respond(svr) } @@ -1098,8 +1098,8 @@ type sshFxpExtendedPacketStatVFS struct { Path string } -func (p sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID } -func (p sshFxpExtendedPacketStatVFS) readonly() bool { return true } +func (p *sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID } +func (p *sshFxpExtendedPacketStatVFS) readonly() bool { return true } func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error { var err error if p.ID, b, err = unmarshalUint32Safe(b); err != nil { @@ -1119,8 +1119,8 @@ type sshFxpExtendedPacketPosixRename struct { Newpath string } -func (p sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID } -func (p sshFxpExtendedPacketPosixRename) readonly() bool { return false } +func (p *sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID } +func (p *sshFxpExtendedPacketPosixRename) readonly() bool { return false } func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error { var err error if p.ID, b, err = unmarshalUint32Safe(b); err != nil { @@ -1135,9 +1135,9 @@ func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error { return nil } -func (p sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket { +func (p *sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket { err := os.Rename(p.Oldpath, p.Newpath) - return statusFromError(p, err) + return statusFromError(p.ID, err) } type sshFxpExtendedPacketHardlink struct { @@ -1148,8 +1148,8 @@ type sshFxpExtendedPacketHardlink struct { } // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL -func (p sshFxpExtendedPacketHardlink) id() uint32 { return p.ID } -func (p sshFxpExtendedPacketHardlink) readonly() bool { return true } +func (p *sshFxpExtendedPacketHardlink) id() uint32 { return p.ID } +func (p *sshFxpExtendedPacketHardlink) readonly() bool { return true } func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error { var err error if p.ID, b, err = unmarshalUint32Safe(b); err != nil { @@ -1164,7 +1164,7 @@ func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error { return nil } -func (p sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket { +func (p *sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket { err := os.Link(p.Oldpath, p.Newpath) - return statusFromError(p, err) + return statusFromError(p.ID, err) } diff --git a/packet_test.go b/packet_test.go index 8b16be6e..976f66fc 100644 --- a/packet_test.go +++ b/packet_test.go @@ -142,20 +142,20 @@ var sendPacketTests = []struct { p encoding.BinaryMarshaler want []byte }{ - {sshFxInitPacket{ + {&sshFxInitPacket{ Version: 3, Extensions: []extensionPair{ {"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}}, - {sshFxpOpenPacket{ + {&sshFxpOpenPacket{ ID: 1, Path: "/foo", 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}}, - {sshFxpWritePacket{ + {&sshFxpWritePacket{ ID: 124, Handle: "foo", Offset: 13, @@ -163,7 +163,7 @@ var sendPacketTests = []struct { 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}}, - {sshFxpSetstatPacket{ + {&sshFxpSetstatPacket{ ID: 31, Path: "/bar", Flags: flags(os.O_WRONLY), @@ -195,7 +195,7 @@ var recvPacketTests = []struct { want uint8 rest []byte }{ - {sp(sshFxInitPacket{ + {sp(&sshFxInitPacket{ Version: 3, Extensions: []extensionPair{ {"posix-rename@openssh.com", "1"}, @@ -299,7 +299,7 @@ func TestSSHFxpOpenPackethasPflags(t *testing.T) { func BenchmarkMarshalInit(b *testing.B) { for i := 0; i < b.N; i++ { - sp(sshFxInitPacket{ + sp(&sshFxInitPacket{ Version: 3, Extensions: []extensionPair{ {"posix-rename@openssh.com", "1"}, @@ -310,7 +310,7 @@ func BenchmarkMarshalInit(b *testing.B) { func BenchmarkMarshalOpen(b *testing.B) { for i := 0; i < b.N; i++ { - sp(sshFxpOpenPacket{ + sp(&sshFxpOpenPacket{ ID: 1, Path: "/home/test/some/random/path", Pflags: flags(os.O_RDONLY), @@ -321,7 +321,7 @@ func BenchmarkMarshalOpen(b *testing.B) { func BenchmarkMarshalWriteWorstCase(b *testing.B) { data := make([]byte, 32*1024) for i := 0; i < b.N; i++ { - sp(sshFxpWritePacket{ + sp(&sshFxpWritePacket{ ID: 1, Handle: "someopaquehandle", Offset: 0, @@ -334,7 +334,7 @@ func BenchmarkMarshalWriteWorstCase(b *testing.B) { func BenchmarkMarshalWrite1k(b *testing.B) { data := make([]byte, 1024) for i := 0; i < b.N; i++ { - sp(sshFxpWritePacket{ + sp(&sshFxpWritePacket{ ID: 1, Handle: "someopaquehandle", Offset: 0, diff --git a/request-server.go b/request-server.go index 72ee3b86..fe94ae25 100644 --- a/request-server.go +++ b/request-server.go @@ -193,10 +193,10 @@ func (rs *RequestServer) packetWorker( var rpkt responsePacket switch pkt := pkt.requestPacket.(type) { case *sshFxInitPacket: - rpkt = sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions} + rpkt = &sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions} case *sshFxpClosePacket: handle := pkt.getHandle() - rpkt = statusFromError(pkt, rs.closeRequest(handle)) + rpkt = statusFromError(pkt.ID, rs.closeRequest(handle)) case *sshFxpRealpathPacket: rpkt = cleanPacketPath(pkt) case *sshFxpOpendirPacket: @@ -219,7 +219,7 @@ func (rs *RequestServer) packetWorker( handle := pkt.getHandle() request, ok := rs.getRequest(handle) if !ok { - rpkt = statusFromError(pkt, EBADF) + rpkt = statusFromError(pkt.ID, EBADF) } else { request = NewRequest("Stat", request.Filepath) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) @@ -228,7 +228,7 @@ func (rs *RequestServer) packetWorker( handle := pkt.getHandle() request, ok := rs.getRequest(handle) if !ok { - rpkt = statusFromError(pkt, EBADF) + rpkt = statusFromError(pkt.ID, EBADF) } else { request = NewRequest("Setstat", request.Filepath) rpkt = request.call(rs.Handlers, pkt, rs.pktMgr.alloc, orderID) @@ -244,7 +244,7 @@ func (rs *RequestServer) packetWorker( handle := pkt.getHandle() request, ok := rs.getRequest(handle) if !ok { - rpkt = statusFromError(pkt, EBADF) + rpkt = statusFromError(pkt.id(), EBADF) } else { 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) request.close() default: - rpkt = statusFromError(pkt, ErrSSHFxOpUnsupported) + rpkt = statusFromError(pkt.id(), ErrSSHFxOpUnsupported) } rs.pktMgr.readyPacket( @@ -267,11 +267,13 @@ func cleanPacketPath(pkt *sshFxpRealpathPacket) responsePacket { path := cleanPath(pkt.getPath()) return &sshFxpNamePacket{ ID: pkt.id(), - NameAttrs: []sshFxpNameAttr{{ - Name: path, - LongName: path, - Attrs: emptyFileStat, - }}, + NameAttrs: []*sshFxpNameAttr{ + &sshFxpNameAttr{ + Name: path, + LongName: path, + Attrs: emptyFileStat, + }, + }, } } diff --git a/request.go b/request.go index 78f92588..44651027 100644 --- a/request.go +++ b/request.go @@ -219,7 +219,7 @@ func (r *Request) call(handlers Handlers, pkt requestPacket, alloc *allocator, o case "Stat", "Lstat", "Readlink": return filestat(handlers.FileList, r, pkt) default: - return statusFromError(pkt, + return statusFromError(pkt.id(), 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 { flags := r.Pflags() + id := pkt.id() + switch { case flags.Write, flags.Append, flags.Creat, flags.Trunc: if flags.Read { @@ -235,36 +237,37 @@ func (r *Request) open(h Handlers, pkt requestPacket) responsePacket { r.Method = "Open" rw, err := openFileWriter.OpenFile(r) if err != nil { - return statusFromError(pkt, err) + return statusFromError(id, err) } r.state.writerReaderAt = rw - return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} + return &sshFxpHandlePacket{ID: id, Handle: r.handle} } } r.Method = "Put" wr, err := h.FilePut.Filewrite(r) if err != nil { - return statusFromError(pkt, err) + return statusFromError(id, err) } r.state.writerAt = wr case flags.Read: r.Method = "Get" rd, err := h.FileGet.Fileread(r) if err != nil { - return statusFromError(pkt, err) + return statusFromError(id, err) } r.state.readerAt = rd 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 { r.Method = "List" la, err := h.FileList.Filelist(r) if err != nil { - return statusFromError(pkt, wrapPathError(r.Filepath, err)) + return statusFromError(pkt.id(), wrapPathError(r.Filepath, err)) } r.state.listerAt = la 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 r.state.RUnlock() 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) n, err := reader.ReadAt(data, offset) // only return EOF error if no data left to read if err != nil && (err != io.EOF || n == 0) { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } return &sshFxpDataPacket{ ID: pkt.id(), @@ -298,12 +301,12 @@ func fileput(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, orde writer := r.state.writerAt r.state.RUnlock() 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) _, err := writer.WriteAt(data, offset) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } // wrap OpenFileWriter handler @@ -312,7 +315,7 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o writerReader := r.state.writerReaderAt r.state.RUnlock() 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) { case *sshFxpReadPacket: @@ -320,7 +323,7 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o n, err := writerReader.ReadAt(data, offset) // only return EOF error if no data left to read if err != nil && (err != io.EOF || n == 0) { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } return &sshFxpDataPacket{ ID: pkt.id(), @@ -330,9 +333,9 @@ func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, o case *sshFxpWritePacket: data, offset := p.Data, int64(p.Offset) _, err := writerReader.WriteAt(data, offset) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) 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 posixRenamer, ok := h.(PosixRenameFileCmder); ok { err := posixRenamer.PosixRename(r) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } // PosixRenameFileCmder not implemented handle this request as a Rename r.Method = "Rename" err := h.Filecmd(r) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } if r.Method == "StatVFS" { if statVFSCmdr, ok := h.(StatVFSFileCmder); ok { stat, err := statVFSCmdr.StatVFS(r) if err != nil { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } stat.ID = pkt.id() return stat } - return statusFromError(pkt, ErrSSHFxOpUnsupported) + return statusFromError(pkt.id(), ErrSSHFxOpUnsupported) } err := h.Filecmd(r) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } // wrap FileLister handler @@ -389,7 +392,7 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket { var err error lister := r.getLister() if lister == nil { - return statusFromError(pkt, errors.New("unexpected dir packet")) + return statusFromError(pkt.id(), errors.New("unexpected dir packet")) } offset := r.lsNext() @@ -402,16 +405,16 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket { switch r.Method { case "List": if err != nil && err != io.EOF { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } if err == io.EOF && n == 0 { - return statusFromError(pkt, io.EOF) + return statusFromError(pkt.id(), io.EOF) } dirname := filepath.ToSlash(path.Base(r.Filepath)) ret := &sshFxpNamePacket{ID: pkt.id()} for _, fi := range finfo { - ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ + ret.NameAttrs = append(ret.NameAttrs, &sshFxpNameAttr{ Name: fi.Name(), LongName: runLs(dirname, fi), Attrs: []interface{}{fi}, @@ -420,7 +423,7 @@ func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket { return ret default: 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) } if err != nil { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } finfo := make([]os.FileInfo, 1) n, err := lister.ListAt(finfo, 0) @@ -449,12 +452,12 @@ func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket { switch r.Method { case "Stat", "Lstat": if err != nil && err != io.EOF { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } if n == 0 { err = &os.PathError{Op: strings.ToLower(r.Method), Path: r.Filepath, Err: syscall.ENOENT} - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } return &sshFxpStatResponse{ ID: pkt.id(), @@ -462,25 +465,27 @@ func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket { } case "Readlink": if err != nil && err != io.EOF { - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } if n == 0 { err = &os.PathError{Op: "readlink", Path: r.Filepath, Err: syscall.ENOENT} - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } filename := finfo[0].Name() return &sshFxpNamePacket{ ID: pkt.id(), - NameAttrs: []sshFxpNameAttr{{ - Name: filename, - LongName: filename, - Attrs: emptyFileStat, - }}, + NameAttrs: []*sshFxpNameAttr{ + &sshFxpNameAttr{ + Name: filename, + LongName: filename, + Attrs: emptyFileStat, + }, + }, } default: err = errors.Errorf("unexpected method: %s", r.Method) - return statusFromError(pkt, err) + return statusFromError(pkt.id(), err) } } diff --git a/request_test.go b/request_test.go index 9f1ed661..d3f7db06 100644 --- a/request_test.go +++ b/request_test.go @@ -118,11 +118,11 @@ func (h *Handlers) returnError(err error) { } func getStatusMsg(p interface{}) string { - pkt := p.(sshFxpStatusPacket) + pkt := p.(*sshFxpStatusPacket) return pkt.StatusError.msg } func checkOkStatus(t *testing.T, p interface{}) { - pkt := p.(sshFxpStatusPacket) + pkt := p.(*sshFxpStatusPacket) assert.Equal(t, pkt.StatusError.Code, uint32(sshFxOk), "sshFxpStatusPacket not OK\n", pkt.StatusError.msg) } @@ -166,7 +166,7 @@ func TestRequestCustomError(t *testing.T) { cmdErr := errors.New("stat not supported") handlers.returnError(cmdErr) 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 @@ -194,7 +194,7 @@ func TestRequestCmdr(t *testing.T) { handlers.returnError(errTest) 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) { @@ -227,7 +227,7 @@ func TestRequestInfoReadlink(t *testing.T) { rpkt := request.call(handlers, pkt, nil, 0) npkt, ok := rpkt.(*sshFxpNamePacket) 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") } } diff --git a/server.go b/server.go index 9502932e..cfebed73 100644 --- a/server.go +++ b/server.go @@ -152,7 +152,7 @@ func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error { // return permission denied if !readonly && svr.readOnly { svr.pktMgr.readyPacket( - svr.pktMgr.newOrderedResponse(statusFromError(pkt, syscall.EPERM), pkt.orderID()), + svr.pktMgr.newOrderedResponse(statusFromError(pkt.id(), syscall.EPERM), pkt.orderID()), ) continue } @@ -169,29 +169,29 @@ func handlePacket(s *Server, p orderedRequest) error { orderID := p.orderID() switch p := p.requestPacket.(type) { case *sshFxInitPacket: - rpkt = sshFxVersionPacket{ + rpkt = &sshFxVersionPacket{ Version: sftpProtocolVersion, Extensions: sftpExtensions, } case *sshFxpStatPacket: // stat the requested file info, err := os.Stat(p.Path) - rpkt = sshFxpStatResponse{ + rpkt = &sshFxpStatResponse{ ID: p.ID, info: info, } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpLstatPacket: // stat the requested file info, err := os.Lstat(p.Path) - rpkt = sshFxpStatResponse{ + rpkt = &sshFxpStatResponse{ ID: p.ID, info: info, } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpFstatPacket: f, ok := s.getHandle(p.Handle) @@ -199,71 +199,75 @@ func handlePacket(s *Server, p orderedRequest) error { var info os.FileInfo if ok { info, err = f.Stat() - rpkt = sshFxpStatResponse{ + rpkt = &sshFxpStatResponse{ ID: p.ID, info: info, } } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpMkdirPacket: // TODO FIXME: ignore flags field err := os.Mkdir(p.Path, 0755) - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpRmdirPacket: err := os.Remove(p.Path) - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpRemovePacket: err := os.Remove(p.Filename) - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpRenamePacket: err := os.Rename(p.Oldpath, p.Newpath) - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpSymlinkPacket: err := os.Symlink(p.Targetpath, p.Linkpath) - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpClosePacket: - rpkt = statusFromError(p, s.closeHandle(p.Handle)) + rpkt = statusFromError(p.ID, s.closeHandle(p.Handle)) case *sshFxpReadlinkPacket: f, err := os.Readlink(p.Path) - rpkt = sshFxpNamePacket{ + rpkt = &sshFxpNamePacket{ ID: p.ID, - NameAttrs: []sshFxpNameAttr{{ - Name: f, - LongName: f, - Attrs: emptyFileStat, - }}, + NameAttrs: []*sshFxpNameAttr{ + &sshFxpNameAttr{ + Name: f, + LongName: f, + Attrs: emptyFileStat, + }, + }, } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpRealpathPacket: f, err := filepath.Abs(p.Path) f = cleanPath(f) - rpkt = sshFxpNamePacket{ + rpkt = &sshFxpNamePacket{ ID: p.ID, - NameAttrs: []sshFxpNameAttr{{ - Name: f, - LongName: f, - Attrs: emptyFileStat, - }}, + NameAttrs: []*sshFxpNameAttr{ + &sshFxpNameAttr{ + Name: f, + LongName: f, + Attrs: emptyFileStat, + }, + }, } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpOpendirPacket: if stat, err := os.Stat(p.Path); err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } else if !stat.IsDir() { - rpkt = statusFromError(p, &os.PathError{ + rpkt = statusFromError(p.ID, &os.PathError{ Path: p.Path, Err: syscall.ENOTDIR}) } else { - rpkt = sshFxpOpenPacket{ + rpkt = (&sshFxpOpenPacket{ ID: p.ID, Path: p.Path, Pflags: sshFxfRead, - }.respond(s) + }).respond(s) } case *sshFxpReadPacket: var err error = EBADF @@ -275,7 +279,7 @@ func handlePacket(s *Server, p orderedRequest) error { if _err != nil && (_err != io.EOF || n == 0) { err = _err } - rpkt = sshFxpDataPacket{ + rpkt = &sshFxpDataPacket{ ID: p.ID, Length: uint32(n), Data: data[:n], @@ -283,7 +287,7 @@ func handlePacket(s *Server, p orderedRequest) error { } } if err != nil { - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) } case *sshFxpWritePacket: @@ -292,10 +296,10 @@ func handlePacket(s *Server, p orderedRequest) error { if ok { _, err = f.WriteAt(p.Data, int64(p.Offset)) } - rpkt = statusFromError(p, err) + rpkt = statusFromError(p.ID, err) case *sshFxpExtendedPacket: if p.SpecificPacket == nil { - rpkt = statusFromError(p, ErrSSHFxOpUnsupported) + rpkt = statusFromError(p.ID, ErrSSHFxOpUnsupported) } else { 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 -func (p sshFxInitPacket) id() uint32 { return 0 } +func (p *sshFxInitPacket) id() uint32 { return 0 } type sshFxpStatResponse struct { ID uint32 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) b := make([]byte, 4, l) @@ -395,18 +399,18 @@ func (p sshFxpStatResponse) marshalPacket() ([]byte, []byte, error) { return b, payload, nil } -func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) { +func (p *sshFxpStatResponse) MarshalBinary() ([]byte, error) { header, payload, err := p.marshalPacket() return append(header, payload...), err } var emptyFileStat = []interface{}{uint32(0)} -func (p sshFxpOpenPacket) readonly() bool { +func (p *sshFxpOpenPacket) readonly() bool { return !p.hasPflags(sshFxfWrite) } -func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool { +func (p *sshFxpOpenPacket) hasPflags(flags ...uint32) bool { for _, f := range flags { if p.Pflags&f == 0 { return false @@ -415,7 +419,7 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool { return true } -func (p sshFxpOpenPacket) respond(svr *Server) responsePacket { +func (p *sshFxpOpenPacket) respond(svr *Server) responsePacket { var osFlags int if p.hasPflags(sshFxfRead, sshFxfWrite) { osFlags |= os.O_RDWR @@ -425,7 +429,7 @@ func (p sshFxpOpenPacket) respond(svr *Server) responsePacket { osFlags |= os.O_RDONLY } else { // 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. @@ -443,28 +447,28 @@ func (p sshFxpOpenPacket) respond(svr *Server) responsePacket { f, err := os.OpenFile(p.Path, osFlags, 0644) if err != nil { - return statusFromError(p, err) + return statusFromError(p.ID, err) } 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) if !ok { - return statusFromError(p, EBADF) + return statusFromError(p.ID, EBADF) } dirname := f.Name() dirents, err := f.Readdir(128) 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 { - ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ + ret.NameAttrs = append(ret.NameAttrs, &sshFxpNameAttr{ Name: dirent.Name(), LongName: runLs(dirname, dirent), Attrs: []interface{}{dirent}, @@ -473,7 +477,7 @@ func (p sshFxpReaddirPacket) respond(svr *Server) responsePacket { return ret } -func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket { +func (p *sshFxpSetstatPacket) respond(svr *Server) responsePacket { // additional unmarshalling is required for each possibility here b := p.Attrs.([]byte) 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) if !ok { - return statusFromError(p, EBADF) + return statusFromError(p.ID, EBADF) } // 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 { - ret := sshFxpStatusPacket{ - ID: p.id(), +func statusFromError(id uint32, err error) *sshFxpStatusPacket { + ret := &sshFxpStatusPacket{ + ID: id, StatusError: StatusError{ // sshFXOk = 0 // sshFXEOF = 1 diff --git a/server_statvfs_impl.go b/server_statvfs_impl.go index 9dc793c8..2d467d1e 100644 --- a/server_statvfs_impl.go +++ b/server_statvfs_impl.go @@ -9,21 +9,20 @@ import ( "syscall" ) -func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { +func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { retPkt, err := getStatVFSForPath(p.Path) if err != nil { - return statusFromError(p, err) + return statusFromError(p.ID, err) } - retPkt.ID = p.ID return retPkt } func getStatVFSForPath(name string) (*StatVFS, error) { - stat := &syscall.Statfs_t{} - if err := syscall.Statfs(name, stat); err != nil { + var stat syscall.Statfs_t + if err := syscall.Statfs(name, &stat); err != nil { return nil, err } - return statvfsFromStatfst(stat) + return statvfsFromStatfst(&stat) } diff --git a/server_statvfs_plan9.go b/server_statvfs_plan9.go index 5a293237..e71a27d3 100644 --- a/server_statvfs_plan9.go +++ b/server_statvfs_plan9.go @@ -4,8 +4,8 @@ import ( "syscall" ) -func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { - return statusFromError(p, syscall.EPLAN9) +func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { + return statusFromError(p.ID, syscall.EPLAN9) } func getStatVFSForPath(name string) (*StatVFS, error) { diff --git a/server_statvfs_stubs.go b/server_statvfs_stubs.go index c1bb104a..fbf49068 100644 --- a/server_statvfs_stubs.go +++ b/server_statvfs_stubs.go @@ -6,8 +6,8 @@ import ( "syscall" ) -func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { - return statusFromError(p, syscall.ENOTSUP) +func (p *sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket { + return statusFromError(p.ID, syscall.ENOTSUP) } func getStatVFSForPath(name string) (*StatVFS, error) { diff --git a/server_test.go b/server_test.go index 6a78f897..ddfdd225 100644 --- a/server_test.go +++ b/server_test.go @@ -281,10 +281,10 @@ func TestConcurrentRequests(t *testing.T) { func TestStatusFromError(t *testing.T) { type test struct { err error - pkt sshFxpStatusPacket + pkt *sshFxpStatusPacket } - tpkt := func(id, code uint32) sshFxpStatusPacket { - return sshFxpStatusPacket{ + tpkt := func(id, code uint32) *sshFxpStatusPacket { + return &sshFxpStatusPacket{ ID: id, StatusError: StatusError{Code: code}, } @@ -301,7 +301,7 @@ func TestStatusFromError(t *testing.T) { } for _, tc := range testCases { 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) ch := make(chan result, 3) id1 := client.nextID() - client.dispatchRequest(ch, sshFxpOpenPacket{ + client.dispatchRequest(ch, &sshFxpOpenPacket{ ID: id1, Path: tmppath, Pflags: pflags, }) id2 := client.nextID() - client.dispatchRequest(ch, sshFxpLstatPacket{ + client.dispatchRequest(ch, &sshFxpLstatPacket{ ID: id2, Path: tmppath, }) @@ -370,8 +370,8 @@ func TestStatNonExistent(t *testing.T) { } func TestServerWithBrokenClient(t *testing.T) { - validInit := sp(sshFxInitPacket{Version: 3}) - brokenOpen := sp(sshFxpOpenPacket{Path: "foo"}) + validInit := sp(&sshFxInitPacket{Version: 3}) + brokenOpen := sp(&sshFxpOpenPacket{Path: "foo"}) brokenOpen = brokenOpen[:len(brokenOpen)-2] for _, clientInput := range [][]byte{ diff --git a/sftp_test.go b/sftp_test.go index 174a457c..4c1b080c 100644 --- a/sftp_test.go +++ b/sftp_test.go @@ -10,7 +10,6 @@ import ( ) func TestErrFxCode(t *testing.T) { - ider := sshFxpStatusPacket{ID: 1} table := []struct { err error fx fxerr @@ -22,7 +21,7 @@ func TestErrFxCode(t *testing.T) { {err: io.EOF, fx: ErrSSHFxEOF}, } for _, tt := range table { - statusErr := statusFromError(ider, tt.err).StatusError + statusErr := statusFromError(1, tt.err).StatusError assert.Equal(t, statusErr.FxCode(), tt.fx) } }