package sftp import ( "encoding" "fmt" ) // all incoming packets type requestPacket interface { encoding.BinaryUnmarshaler id() uint32 } type responsePacket interface { encoding.BinaryMarshaler id() uint32 } // interfaces to group types type hasPath interface { requestPacket getPath() string } type hasHandle interface { requestPacket getHandle() string } type notReadOnly interface { notReadOnly() } //// 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 *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 } // 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 } // take raw incoming packet data and build packet objects func makePacket(p rxPacket) (requestPacket, error) { var pkt requestPacket switch p.pktType { case sshFxpInit: pkt = &sshFxInitPacket{} case sshFxpLstat: pkt = &sshFxpLstatPacket{} case sshFxpOpen: pkt = &sshFxpOpenPacket{} case sshFxpClose: pkt = &sshFxpClosePacket{} case sshFxpRead: pkt = &sshFxpReadPacket{} case sshFxpWrite: pkt = &sshFxpWritePacket{} case sshFxpFstat: pkt = &sshFxpFstatPacket{} case sshFxpSetstat: pkt = &sshFxpSetstatPacket{} case sshFxpFsetstat: pkt = &sshFxpFsetstatPacket{} case sshFxpOpendir: pkt = &sshFxpOpendirPacket{} case sshFxpReaddir: pkt = &sshFxpReaddirPacket{} case sshFxpRemove: pkt = &sshFxpRemovePacket{} case sshFxpMkdir: pkt = &sshFxpMkdirPacket{} case sshFxpRmdir: pkt = &sshFxpRmdirPacket{} case sshFxpRealpath: pkt = &sshFxpRealpathPacket{} case sshFxpStat: pkt = &sshFxpStatPacket{} case sshFxpRename: pkt = &sshFxpRenamePacket{} case sshFxpReadlink: pkt = &sshFxpReadlinkPacket{} case sshFxpSymlink: pkt = &sshFxpSymlinkPacket{} case sshFxpExtended: pkt = &sshFxpExtendedPacket{} default: return nil, fmt.Errorf("unhandled packet type: %s", p.pktType) } if err := pkt.UnmarshalBinary(p.pktBytes); err != nil { // Return partially unpacked packet to allow callers to return // error messages appropriately with necessary id() method. return pkt, err } return pkt, nil }