diff --git a/attrs.go b/attrs.go index 2bb2d576..cb0987d7 100644 --- a/attrs.go +++ b/attrs.go @@ -1,7 +1,7 @@ package sftp // ssh_FXP_ATTRS support -// see http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5 +// see https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5 import ( "os" diff --git a/attrs_stubs.go b/attrs_stubs.go index c01f3367..d20348c1 100644 --- a/attrs_stubs.go +++ b/attrs_stubs.go @@ -1,3 +1,4 @@ +//go:build plan9 || windows || android // +build plan9 windows android package sftp diff --git a/attrs_unix.go b/attrs_unix.go index d1f44524..371ae9b9 100644 --- a/attrs_unix.go +++ b/attrs_unix.go @@ -1,3 +1,4 @@ +//go:build darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris || aix || js // +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix js package sftp diff --git a/client.go b/client.go index 975bb7a4..fb0a110b 100644 --- a/client.go +++ b/client.go @@ -259,11 +259,11 @@ func (c *Client) Create(path string) (*File, error) { return c.open(path, flags(os.O_RDWR|os.O_CREATE|os.O_TRUNC)) } -const sftpProtocolVersion = 3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 +const sftpProtocolVersion = 3 // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt func (c *Client) sendInit() error { return c.clientConn.conn.sendPacket(&sshFxInitPacket{ - Version: sftpProtocolVersion, // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 + Version: sftpProtocolVersion, // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt }) } diff --git a/debug.go b/debug.go index 3e264abe..f0db14d3 100644 --- a/debug.go +++ b/debug.go @@ -1,3 +1,4 @@ +//go:build debug // +build debug package sftp diff --git a/fuzz.go b/fuzz.go index 169aebc2..f2f1fc31 100644 --- a/fuzz.go +++ b/fuzz.go @@ -1,3 +1,4 @@ +//go:build gofuzz // +build gofuzz package sftp diff --git a/internal/encoding/ssh/filexfer/attrs.go b/internal/encoding/ssh/filexfer/attrs.go index eed61bfc..3aec937f 100644 --- a/internal/encoding/ssh/filexfer/attrs.go +++ b/internal/encoding/ssh/filexfer/attrs.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // Attributes related flags. const ( @@ -12,7 +12,7 @@ const ( // Attributes defines the file attributes type defined in draft-ietf-secsh-filexfer-02 // -// Defined in: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5 +// Defined in: https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5 type Attributes struct { Flags uint32 @@ -116,32 +116,32 @@ func (a *Attributes) Len() int { } // MarshalInto marshals e onto the end of the given Buffer. -func (a *Attributes) MarshalInto(b *Buffer) { - b.AppendUint32(a.Flags) +func (a *Attributes) MarshalInto(buf *Buffer) { + buf.AppendUint32(a.Flags) if a.Flags&AttrSize != 0 { - b.AppendUint64(a.Size) + buf.AppendUint64(a.Size) } if a.Flags&AttrUIDGID != 0 { - b.AppendUint32(a.UID) - b.AppendUint32(a.GID) + buf.AppendUint32(a.UID) + buf.AppendUint32(a.GID) } if a.Flags&AttrPermissions != 0 { - b.AppendUint32(uint32(a.Permissions)) + buf.AppendUint32(uint32(a.Permissions)) } if a.Flags&AttrACModTime != 0 { - b.AppendUint32(a.ATime) - b.AppendUint32(a.MTime) + buf.AppendUint32(a.ATime) + buf.AppendUint32(a.MTime) } if a.Flags&AttrExtended != 0 { - b.AppendUint32(uint32(len(a.ExtendedAttributes))) + buf.AppendUint32(uint32(len(a.ExtendedAttributes))) for _, ext := range a.ExtendedAttributes { - ext.MarshalInto(b) + ext.MarshalInto(buf) } } } @@ -156,74 +156,51 @@ func (a *Attributes) MarshalBinary() ([]byte, error) { // UnmarshalFrom unmarshals an Attributes from the given Buffer into e. // // NOTE: The values of fields not covered in the a.Flags are explicitly undefined. -func (a *Attributes) UnmarshalFrom(b *Buffer) (err error) { - flags, err := b.ConsumeUint32() - if err != nil { - return err - } +func (a *Attributes) UnmarshalFrom(buf *Buffer) (err error) { + flags := buf.ConsumeUint32() - return a.XXX_UnmarshalByFlags(flags, b) + return a.XXX_UnmarshalByFlags(flags, buf) } // XXX_UnmarshalByFlags uses the pre-existing a.Flags field to determine which fields to decode. // DO NOT USE THIS: it is an anti-corruption function to implement existing internal usage in pkg/sftp. // This function is not a part of any compatibility promise. -func (a *Attributes) XXX_UnmarshalByFlags(flags uint32, b *Buffer) (err error) { +func (a *Attributes) XXX_UnmarshalByFlags(flags uint32, buf *Buffer) (err error) { a.Flags = flags // Short-circuit dummy attributes. if a.Flags == 0 { - return nil + return buf.Err } if a.Flags&AttrSize != 0 { - if a.Size, err = b.ConsumeUint64(); err != nil { - return err - } + a.Size = buf.ConsumeUint64() } if a.Flags&AttrUIDGID != 0 { - if a.UID, err = b.ConsumeUint32(); err != nil { - return err - } - - if a.GID, err = b.ConsumeUint32(); err != nil { - return err - } + a.UID = buf.ConsumeUint32() + a.GID = buf.ConsumeUint32() } if a.Flags&AttrPermissions != 0 { - m, err := b.ConsumeUint32() - if err != nil { - return err - } - - a.Permissions = FileMode(m) + a.Permissions = FileMode(buf.ConsumeUint32()) } if a.Flags&AttrACModTime != 0 { - if a.ATime, err = b.ConsumeUint32(); err != nil { - return err - } - - if a.MTime, err = b.ConsumeUint32(); err != nil { - return err - } + a.ATime = buf.ConsumeUint32() + a.MTime = buf.ConsumeUint32() } if a.Flags&AttrExtended != 0 { - count, err := b.ConsumeUint32() - if err != nil { - return err - } + count := buf.ConsumeCount() a.ExtendedAttributes = make([]ExtendedAttribute, count) for i := range a.ExtendedAttributes { - a.ExtendedAttributes[i].UnmarshalFrom(b) + a.ExtendedAttributes[i].UnmarshalFrom(buf) } } - return nil + return buf.Err } // UnmarshalBinary decodes the binary encoding of Attributes into e. @@ -233,7 +210,7 @@ func (a *Attributes) UnmarshalBinary(data []byte) error { // ExtendedAttribute defines the extended file attribute type defined in draft-ietf-secsh-filexfer-02 // -// Defined in: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5 +// Defined in: https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5 type ExtendedAttribute struct { Type string Data string @@ -245,9 +222,9 @@ func (e *ExtendedAttribute) Len() int { } // MarshalInto marshals e onto the end of the given Buffer. -func (e *ExtendedAttribute) MarshalInto(b *Buffer) { - b.AppendString(e.Type) - b.AppendString(e.Data) +func (e *ExtendedAttribute) MarshalInto(buf *Buffer) { + buf.AppendString(e.Type) + buf.AppendString(e.Data) } // MarshalBinary returns e as the binary encoding of e. @@ -258,16 +235,13 @@ func (e *ExtendedAttribute) MarshalBinary() ([]byte, error) { } // UnmarshalFrom unmarshals an ExtendedAattribute from the given Buffer into e. -func (e *ExtendedAttribute) UnmarshalFrom(b *Buffer) (err error) { - if e.Type, err = b.ConsumeString(); err != nil { - return err +func (e *ExtendedAttribute) UnmarshalFrom(buf *Buffer) (err error) { + *e = ExtendedAttribute{ + Type: buf.ConsumeString(), + Data: buf.ConsumeString(), } - if e.Data, err = b.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // UnmarshalBinary decodes the binary encoding of ExtendedAttribute into e. @@ -290,11 +264,11 @@ func (e *NameEntry) Len() int { } // MarshalInto marshals e onto the end of the given Buffer. -func (e *NameEntry) MarshalInto(b *Buffer) { - b.AppendString(e.Filename) - b.AppendString(e.Longname) +func (e *NameEntry) MarshalInto(buf *Buffer) { + buf.AppendString(e.Filename) + buf.AppendString(e.Longname) - e.Attrs.MarshalInto(b) + e.Attrs.MarshalInto(buf) } // MarshalBinary returns e as the binary encoding of e. @@ -307,16 +281,13 @@ func (e *NameEntry) MarshalBinary() ([]byte, error) { // UnmarshalFrom unmarshals an NameEntry from the given Buffer into e. // // NOTE: The values of fields not covered in the a.Flags are explicitly undefined. -func (e *NameEntry) UnmarshalFrom(b *Buffer) (err error) { - if e.Filename, err = b.ConsumeString(); err != nil { - return err - } - - if e.Longname, err = b.ConsumeString(); err != nil { - return err +func (e *NameEntry) UnmarshalFrom(buf *Buffer) (err error) { + *e = NameEntry{ + Filename: buf.ConsumeString(), + Longname: buf.ConsumeString(), } - return e.Attrs.UnmarshalFrom(b) + return e.Attrs.UnmarshalFrom(buf) } // UnmarshalBinary decodes the binary encoding of NameEntry into e. diff --git a/internal/encoding/ssh/filexfer/attrs_test.go b/internal/encoding/ssh/filexfer/attrs_test.go index 6716a577..1e620faa 100644 --- a/internal/encoding/ssh/filexfer/attrs_test.go +++ b/internal/encoding/ssh/filexfer/attrs_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/buffer.go b/internal/encoding/ssh/filexfer/buffer.go index a6086036..bd4783bb 100644 --- a/internal/encoding/ssh/filexfer/buffer.go +++ b/internal/encoding/ssh/filexfer/buffer.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "encoding/binary" @@ -17,6 +17,7 @@ var ( type Buffer struct { b []byte off int + Err error } // NewBuffer creates and initializes a new buffer using buf as its initial contents. @@ -51,14 +52,17 @@ func (b *Buffer) Cap() int { return cap(b.b) } // Reset resets the buffer to be empty, but it retains the underlying storage for use by future Appends. func (b *Buffer) Reset() { - b.b = b.b[:0] - b.off = 0 + *b = Buffer{ + b: b.b[:0], + } } // StartPacket resets and initializes the buffer to be ready to start marshaling a packet into. // It truncates the buffer, reserves space for uint32(length), then appends the given packetType and requestID. func (b *Buffer) StartPacket(packetType PacketType, requestID uint32) { - b.b, b.off = append(b.b[:0], make([]byte, 4)...), 0 + *b = Buffer{ + b: append(b.b[:0], make([]byte, 4)...), + } b.AppendUint8(uint8(packetType)) b.AppendUint32(requestID) @@ -81,15 +85,21 @@ func (b *Buffer) Packet(payload []byte) (header, payloadPassThru []byte, err err } // ConsumeUint8 consumes a single byte from the buffer. -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeUint8() (uint8, error) { +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeUint8() uint8 { + if b.Err != nil { + return 0 + } + if b.Len() < 1 { - return 0, ErrShortPacket + b.off = len(b.b) + b.Err = ErrShortPacket + return 0 } var v uint8 v, b.off = b.b[b.off], b.off+1 - return v, nil + return v } // AppendUint8 appends a single byte into the buffer. @@ -98,14 +108,9 @@ func (b *Buffer) AppendUint8(v uint8) { } // ConsumeBool consumes a single byte from the buffer, and returns true if that byte is non-zero. -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeBool() (bool, error) { - v, err := b.ConsumeUint8() - if err != nil { - return false, err - } - - return v != 0, nil +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeBool() bool { + return b.ConsumeUint8() != 0 } // AppendBool appends a single bool into the buffer. @@ -119,15 +124,21 @@ func (b *Buffer) AppendBool(v bool) { } // ConsumeUint16 consumes a single uint16 from the buffer, in network byte order (big-endian). -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeUint16() (uint16, error) { +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeUint16() uint16 { + if b.Err != nil { + return 0 + } + if b.Len() < 2 { - return 0, ErrShortPacket + b.off = len(b.b) + b.Err = ErrShortPacket + return 0 } v := binary.BigEndian.Uint16(b.b[b.off:]) b.off += 2 - return v, nil + return v } // AppendUint16 appends single uint16 into the buffer, in network byte order (big-endian). @@ -146,15 +157,21 @@ func unmarshalUint32(b []byte) uint32 { } // ConsumeUint32 consumes a single uint32 from the buffer, in network byte order (big-endian). -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeUint32() (uint32, error) { +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeUint32() uint32 { + if b.Err != nil { + return 0 + } + if b.Len() < 4 { - return 0, ErrShortPacket + b.off = len(b.b) + b.Err = ErrShortPacket + return 0 } v := binary.BigEndian.Uint32(b.b[b.off:]) b.off += 4 - return v, nil + return v } // AppendUint32 appends a single uint32 into the buffer, in network byte order (big-endian). @@ -167,16 +184,33 @@ func (b *Buffer) AppendUint32(v uint32) { ) } +// ConsumeCount consumes a single uint32 count from the buffer, in network byte order (big-endian) as an int. +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeCount() int { + return int(b.ConsumeUint32()) +} + +// AppendCount appends a single int length as a uint32 into the buffer, in network byte order (big-endian). +func (b *Buffer) AppendCount(v int) { + b.AppendUint32(uint32(v)) +} + // ConsumeUint64 consumes a single uint64 from the buffer, in network byte order (big-endian). -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeUint64() (uint64, error) { +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeUint64() uint64 { + if b.Err != nil { + return 0 + } + if b.Len() < 8 { - return 0, ErrShortPacket + b.off = len(b.b) + b.Err = ErrShortPacket + return 0 } v := binary.BigEndian.Uint64(b.b[b.off:]) b.off += 8 - return v, nil + return v } // AppendUint64 appends a single uint64 into the buffer, in network byte order (big-endian). @@ -194,14 +228,9 @@ func (b *Buffer) AppendUint64(v uint64) { } // ConsumeInt64 consumes a single int64 from the buffer, in network byte order (big-endian) with two’s complement. -// If the buffer does not have enough data, it will return ErrShortPacket. -func (b *Buffer) ConsumeInt64() (int64, error) { - u, err := b.ConsumeUint64() - if err != nil { - return 0, err - } - - return int64(u), err +// If the buffer does not have enough data, it will set Err to ErrShortPacket. +func (b *Buffer) ConsumeInt64() int64 { + return int64(b.ConsumeUint64()) } // AppendInt64 appends a single int64 into the buffer, in network byte order (big-endian) with two’s complement. @@ -211,29 +240,52 @@ func (b *Buffer) AppendInt64(v int64) { // ConsumeByteSlice consumes a single string of raw binary data from the buffer. // A string is a uint32 length, followed by that number of raw bytes. -// If the buffer does not have enough data, or defines a length larger than available, it will return ErrShortPacket. +// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket. // // The returned slice aliases the buffer contents, and is valid only as long as the buffer is not reused // (that is, only until the next call to Reset, PutLength, StartPacket, or UnmarshalBinary). // // In no case will any Consume calls return overlapping slice aliases, // and Append calls are guaranteed to not disturb this slice alias. -func (b *Buffer) ConsumeByteSlice() ([]byte, error) { - length, err := b.ConsumeUint32() - if err != nil { - return nil, err +func (b *Buffer) ConsumeByteSlice() []byte { + length := int(b.ConsumeUint32()) + if b.Err != nil { + return nil } - if b.Len() < int(length) { - return nil, ErrShortPacket + if b.Len() < length || length < 0 { + b.off = len(b.b) + b.Err = ErrShortPacket + return nil } v := b.b[b.off:] - if len(v) > int(length) { + if len(v) > length || cap(v) > length { v = v[:length:length] } b.off += int(length) - return v, nil + return v +} + +// ConsumeByteSliceCopy consumes a single string of raw binary data as a copy from the buffer. +// A string is a uint32 length, followed by that number of raw bytes. +// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket. +// +// The returned slice does not alias any buffer contents, +// and will therefore be valid even if the buffer is later reused. +// +// If hint has sufficient capacity to hold the data, it will be reused and overwritten, +// otherwise a new backing slice will be allocated and returned. +func (b *Buffer) ConsumeByteSliceCopy(hint []byte) []byte { + data := b.ConsumeByteSlice() + + if grow := len(data) - len(hint); grow > 0 { + hint = append(hint, make([]byte, grow)...) + } + + n := copy(hint, data) + hint = hint[:n] + return hint } // AppendByteSlice appends a single string of raw binary data into the buffer. @@ -245,17 +297,12 @@ func (b *Buffer) AppendByteSlice(v []byte) { // ConsumeString consumes a single string of binary data from the buffer. // A string is a uint32 length, followed by that number of raw bytes. -// If the buffer does not have enough data, or defines a length larger than available, it will return ErrShortPacket. +// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket. // // NOTE: Go implicitly assumes that strings contain UTF-8 encoded data. // All caveats on using arbitrary binary data in Go strings applies. -func (b *Buffer) ConsumeString() (string, error) { - v, err := b.ConsumeByteSlice() - if err != nil { - return "", err - } - - return string(v), nil +func (b *Buffer) ConsumeString() string { + return string(b.ConsumeByteSlice()) } // AppendString appends a single string of binary data into the buffer. diff --git a/internal/encoding/ssh/filexfer/extended_packets.go b/internal/encoding/ssh/filexfer/extended_packets.go index 6b7b2cef..f7174253 100644 --- a/internal/encoding/ssh/filexfer/extended_packets.go +++ b/internal/encoding/ssh/filexfer/extended_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "encoding" @@ -86,8 +86,9 @@ func (p *ExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload // If the extension has not been registered, then a new Buffer will be allocated. // Then the request-specific-data will be unmarshaled from the rest of the buffer. func (p *ExtendedPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.ExtendedRequest, err = buf.ConsumeString(); err != nil { - return err + p.ExtendedRequest = buf.ConsumeString() + if buf.Err != nil { + return buf.Err } if p.Data == nil { diff --git a/internal/encoding/ssh/filexfer/extended_packets_test.go b/internal/encoding/ssh/filexfer/extended_packets_test.go index 0860773d..d7a54d3c 100644 --- a/internal/encoding/ssh/filexfer/extended_packets_test.go +++ b/internal/encoding/ssh/filexfer/extended_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" @@ -20,9 +20,9 @@ func (d *testExtendedData) MarshalBinary() ([]byte, error) { func (d *testExtendedData) UnmarshalBinary(data []byte) error { buf := NewBuffer(data) - v, err := buf.ConsumeUint8() - if err != nil { - return err + v := buf.ConsumeUint8() + if buf.Err != nil { + return buf.Err } d.value = v ^ 0x2a diff --git a/internal/encoding/ssh/filexfer/extensions.go b/internal/encoding/ssh/filexfer/extensions.go index 11c0b99c..c425780c 100644 --- a/internal/encoding/ssh/filexfer/extensions.go +++ b/internal/encoding/ssh/filexfer/extensions.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // ExtensionPair defines the extension-pair type defined in draft-ietf-secsh-filexfer-13. // This type is backwards-compatible with how draft-ietf-secsh-filexfer-02 defines extensions. @@ -29,15 +29,12 @@ func (e *ExtensionPair) MarshalBinary() ([]byte, error) { // UnmarshalFrom unmarshals an ExtensionPair from the given Buffer into e. func (e *ExtensionPair) UnmarshalFrom(buf *Buffer) (err error) { - if e.Name, err = buf.ConsumeString(); err != nil { - return err + *e = ExtensionPair{ + Name: buf.ConsumeString(), + Data: buf.ConsumeString(), } - if e.Data, err = buf.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // UnmarshalBinary decodes the binary encoding of ExtensionPair into e. diff --git a/internal/encoding/ssh/filexfer/extensions_test.go b/internal/encoding/ssh/filexfer/extensions_test.go index 453265b0..15f2a792 100644 --- a/internal/encoding/ssh/filexfer/extensions_test.go +++ b/internal/encoding/ssh/filexfer/extensions_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/filexfer.go b/internal/encoding/ssh/filexfer/filexfer.go index 1e5abf74..d3009994 100644 --- a/internal/encoding/ssh/filexfer/filexfer.go +++ b/internal/encoding/ssh/filexfer/filexfer.go @@ -1,5 +1,5 @@ -// Package filexfer implements the wire encoding for secsh-filexfer as described in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 -package filexfer +// Package sshfx implements the wire encoding for secsh-filexfer as described in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt +package sshfx // PacketMarshaller narrowly defines packets that will only be transmitted. // diff --git a/internal/encoding/ssh/filexfer/fx.go b/internal/encoding/ssh/filexfer/fx.go index 48f86986..9abcbafc 100644 --- a/internal/encoding/ssh/filexfer/fx.go +++ b/internal/encoding/ssh/filexfer/fx.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "fmt" @@ -10,7 +10,7 @@ type Status uint32 // Defines the various SSH_FX_* values. const ( // see draft-ietf-secsh-filexfer-02 - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-7 StatusOK = Status(iota) StatusEOF StatusNoSuchFile @@ -21,28 +21,28 @@ const ( StatusConnectionLost StatusOPUnsupported - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-03#section-7 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-03.txt#section-7 StatusV4InvalidHandle StatusV4NoSuchPath StatusV4FileAlreadyExists StatusV4WriteProtect - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-7 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-04.txt#section-7 StatusV4NoMedia - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-7 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-05.txt#section-7 StatusV5NoSpaceOnFilesystem StatusV5QuotaExceeded StatusV5UnknownPrincipal StatusV5LockConflict - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-06#section-8 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-06.txt#section-8 StatusV6DirNotEmpty StatusV6NotADirectory StatusV6InvalidFilename StatusV6LinkLoop - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-07#section-8 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-07.txt#section-8 StatusV6CannotDelete StatusV6InvalidParameter StatusV6FileIsADirectory @@ -50,10 +50,10 @@ const ( StatusV6ByteRangeLockRefused StatusV6DeletePending - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-08#section-8.1 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-08.txt#section-8.1 StatusV6FileCorrupt - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-10#section-9.1 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-10.txt#section-9.1 StatusV6OwnerInvalid StatusV6GroupInvalid diff --git a/internal/encoding/ssh/filexfer/fx_test.go b/internal/encoding/ssh/filexfer/fx_test.go index 3e8db1d4..95480591 100644 --- a/internal/encoding/ssh/filexfer/fx_test.go +++ b/internal/encoding/ssh/filexfer/fx_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bufio" @@ -9,7 +9,7 @@ import ( "testing" ) -// This string data is copied verbatim from https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 +// This string data is copied verbatim from https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-13.txt var fxStandardsText = ` SSH_FX_OK 0 SSH_FX_EOF 1 diff --git a/internal/encoding/ssh/filexfer/fxp.go b/internal/encoding/ssh/filexfer/fxp.go index 15caf6d2..78080021 100644 --- a/internal/encoding/ssh/filexfer/fxp.go +++ b/internal/encoding/ssh/filexfer/fxp.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "fmt" @@ -9,7 +9,7 @@ type PacketType uint8 // Request packet types. const ( - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 PacketTypeInit = PacketType(iota + 1) PacketTypeVersion PacketTypeOpen @@ -31,17 +31,17 @@ const ( PacketTypeReadLink PacketTypeSymlink - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-07#section-3.3 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-07.txt#section-3.3 PacketTypeV6Link - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-08#section-3.3 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-08.txt#section-3.3 PacketTypeV6Block PacketTypeV6Unblock ) // Response packet types. const ( - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 PacketTypeStatus = PacketType(iota + 101) PacketTypeHandle PacketTypeData @@ -51,7 +51,7 @@ const ( // Extended packet types. const ( - // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3 + // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 PacketTypeExtended = PacketType(iota + 200) PacketTypeExtendedReply ) @@ -122,3 +122,48 @@ func (f PacketType) String() string { return fmt.Sprintf("SSH_FXP_UNKNOWN(%d)", f) } } + +func newPacketFromType(typ PacketType) (Packet, error) { + switch typ { + case PacketTypeOpen: + return new(OpenPacket), nil + case PacketTypeClose: + return new(ClosePacket), nil + case PacketTypeRead: + return new(ReadPacket), nil + case PacketTypeWrite: + return new(WritePacket), nil + case PacketTypeLStat: + return new(LStatPacket), nil + case PacketTypeFStat: + return new(FStatPacket), nil + case PacketTypeSetstat: + return new(SetstatPacket), nil + case PacketTypeFSetstat: + return new(FSetstatPacket), nil + case PacketTypeOpenDir: + return new(OpenDirPacket), nil + case PacketTypeReadDir: + return new(ReadDirPacket), nil + case PacketTypeRemove: + return new(RemovePacket), nil + case PacketTypeMkdir: + return new(MkdirPacket), nil + case PacketTypeRmdir: + return new(RmdirPacket), nil + case PacketTypeRealPath: + return new(RealPathPacket), nil + case PacketTypeStat: + return new(StatPacket), nil + case PacketTypeRename: + return new(RenamePacket), nil + case PacketTypeReadLink: + return new(ReadLinkPacket), nil + case PacketTypeSymlink: + return new(SymlinkPacket), nil + case PacketTypeExtended: + return new(ExtendedPacket), nil + default: + return nil, fmt.Errorf("unexpected request packet type: %v", typ) + } +} diff --git a/internal/encoding/ssh/filexfer/fxp_test.go b/internal/encoding/ssh/filexfer/fxp_test.go index 14e8ff73..b0a3a830 100644 --- a/internal/encoding/ssh/filexfer/fxp_test.go +++ b/internal/encoding/ssh/filexfer/fxp_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bufio" @@ -8,7 +8,8 @@ import ( "testing" ) -// This string data is copied verbatim from https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 +// This string data is copied verbatim from https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-13.txt +// except where commented that it was taken from a different source. var fxpStandardsText = ` SSH_FXP_INIT 1 SSH_FXP_VERSION 2 diff --git a/internal/encoding/ssh/filexfer/handle_packets.go b/internal/encoding/ssh/filexfer/handle_packets.go index a1427712..44594acf 100644 --- a/internal/encoding/ssh/filexfer/handle_packets.go +++ b/internal/encoding/ssh/filexfer/handle_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // ClosePacket defines the SSH_FXP_CLOSE packet. type ClosePacket struct { @@ -27,18 +27,18 @@ func (p *ClosePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *ClosePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = ClosePacket{ + Handle: buf.ConsumeString(), } - return nil + return buf.Err } // ReadPacket defines the SSH_FXP_READ packet. type ReadPacket struct { Handle string Offset uint64 - Len uint32 + Length uint32 } // Type returns the SSH_FXP_xy value associated with this packet type. @@ -58,7 +58,7 @@ func (p *ReadPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by buf.StartPacket(PacketTypeRead, reqid) buf.AppendString(p.Handle) buf.AppendUint64(p.Offset) - buf.AppendUint32(p.Len) + buf.AppendUint32(p.Length) return buf.Packet(payload) } @@ -66,19 +66,13 @@ func (p *ReadPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *ReadPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = ReadPacket{ + Handle: buf.ConsumeString(), + Offset: buf.ConsumeUint64(), + Length: buf.ConsumeUint32(), } - if p.Offset, err = buf.ConsumeUint64(); err != nil { - return err - } - - if p.Len, err = buf.ConsumeUint32(); err != nil { - return err - } - - return nil + return buf.Err } // WritePacket defines the SSH_FXP_WRITE packet. @@ -121,26 +115,13 @@ func (p *WritePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // // This means this _does not_ alias any of the data buffer that is passed in. func (p *WritePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err - } - - if p.Offset, err = buf.ConsumeUint64(); err != nil { - return err - } - - data, err := buf.ConsumeByteSlice() - if err != nil { - return err - } - - if len(p.Data) < len(data) { - p.Data = make([]byte, len(data)) + *p = WritePacket{ + Handle: buf.ConsumeString(), + Offset: buf.ConsumeUint64(), + Data: buf.ConsumeByteSliceCopy(p.Data), } - n := copy(p.Data, data) - p.Data = p.Data[:n] - return nil + return buf.Err } // FStatPacket defines the SSH_FXP_FSTAT packet. @@ -170,11 +151,11 @@ func (p *FStatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *FStatPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = FStatPacket{ + Handle: buf.ConsumeString(), } - return nil + return buf.Err } // FSetstatPacket defines the SSH_FXP_FSETSTAT packet. @@ -207,8 +188,8 @@ func (p *FSetstatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *FSetstatPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = FSetstatPacket{ + Handle: buf.ConsumeString(), } return p.Attrs.UnmarshalFrom(buf) @@ -241,9 +222,9 @@ func (p *ReadDirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload [ // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *ReadDirPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = ReadDirPacket{ + Handle: buf.ConsumeString(), } - return nil + return buf.Err } diff --git a/internal/encoding/ssh/filexfer/handle_packets_test.go b/internal/encoding/ssh/filexfer/handle_packets_test.go index bd034a17..249ff323 100644 --- a/internal/encoding/ssh/filexfer/handle_packets_test.go +++ b/internal/encoding/ssh/filexfer/handle_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" @@ -58,7 +58,7 @@ func TestReadPacket(t *testing.T) { p := &ReadPacket{ Handle: "somehandle", Offset: offset, - Len: length, + Length: length, } buf, err := ComposePacket(p.MarshalPacket(id, nil)) @@ -94,8 +94,8 @@ func TestReadPacket(t *testing.T) { t.Errorf("UnmarshalPacketBody(): Offset was %x, but expected %x", p.Offset, offset) } - if p.Len != length { - t.Errorf("UnmarshalPacketBody(): Len was %x, but expected %x", p.Len, length) + if p.Length != length { + t.Errorf("UnmarshalPacketBody(): Length was %x, but expected %x", p.Length, length) } } diff --git a/internal/encoding/ssh/filexfer/init_packets.go b/internal/encoding/ssh/filexfer/init_packets.go index b0bc6f50..c553ee2e 100644 --- a/internal/encoding/ssh/filexfer/init_packets.go +++ b/internal/encoding/ssh/filexfer/init_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // InitPacket defines the SSH_FXP_INIT packet. type InitPacket struct { @@ -33,8 +33,8 @@ func (p *InitPacket) MarshalBinary() ([]byte, error) { func (p *InitPacket) UnmarshalBinary(data []byte) (err error) { buf := NewBuffer(data) - if p.Version, err = buf.ConsumeUint32(); err != nil { - return err + *p = InitPacket{ + Version: buf.ConsumeUint32(), } for buf.Len() > 0 { @@ -46,7 +46,7 @@ func (p *InitPacket) UnmarshalBinary(data []byte) (err error) { p.Extensions = append(p.Extensions, &ext) } - return nil + return buf.Err } // VersionPacket defines the SSH_FXP_VERSION packet. @@ -82,8 +82,8 @@ func (p *VersionPacket) MarshalBinary() ([]byte, error) { func (p *VersionPacket) UnmarshalBinary(data []byte) (err error) { buf := NewBuffer(data) - if p.Version, err = buf.ConsumeUint32(); err != nil { - return err + *p = VersionPacket{ + Version: buf.ConsumeUint32(), } for buf.Len() > 0 { diff --git a/internal/encoding/ssh/filexfer/init_packets_test.go b/internal/encoding/ssh/filexfer/init_packets_test.go index e7605f98..0c466bf1 100644 --- a/internal/encoding/ssh/filexfer/init_packets_test.go +++ b/internal/encoding/ssh/filexfer/init_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/open_packets.go b/internal/encoding/ssh/filexfer/open_packets.go index 13587114..896ba16e 100644 --- a/internal/encoding/ssh/filexfer/open_packets.go +++ b/internal/encoding/ssh/filexfer/open_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // SSH_FXF_* flags. const ( @@ -43,12 +43,9 @@ func (p *OpenPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *OpenPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Filename, err = buf.ConsumeString(); err != nil { - return err - } - - if p.PFlags, err = buf.ConsumeUint32(); err != nil { - return err + *p = OpenPacket{ + Filename: buf.ConsumeString(), + PFlags: buf.ConsumeUint32(), } return p.Attrs.UnmarshalFrom(buf) @@ -81,9 +78,9 @@ func (p *OpenDirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload [ // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *OpenDirPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = OpenDirPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } diff --git a/internal/encoding/ssh/filexfer/open_packets_test.go b/internal/encoding/ssh/filexfer/open_packets_test.go index a6b4ac08..a792bf45 100644 --- a/internal/encoding/ssh/filexfer/open_packets_test.go +++ b/internal/encoding/ssh/filexfer/open_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/openssh/fsync.go b/internal/encoding/ssh/filexfer/openssh/fsync.go index 7ecfb0c9..708a4ba7 100644 --- a/internal/encoding/ssh/filexfer/openssh/fsync.go +++ b/internal/encoding/ssh/filexfer/openssh/fsync.go @@ -60,11 +60,11 @@ func (ep *FSyncExtendedPacket) MarshalBinary() ([]byte, error) { // UnmarshalFrom decodes the fsync@openssh.com extended packet-specific data from buf. func (ep *FSyncExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.Handle, err = buf.ConsumeString(); err != nil { - return err + *ep = FSyncExtendedPacket{ + Handle: buf.ConsumeString(), } - return nil + return buf.Err } // UnmarshalBinary decodes the fsync@openssh.com extended packet-specific data into ep. diff --git a/internal/encoding/ssh/filexfer/openssh/hardlink.go b/internal/encoding/ssh/filexfer/openssh/hardlink.go index 17c34990..f48d25a2 100644 --- a/internal/encoding/ssh/filexfer/openssh/hardlink.go +++ b/internal/encoding/ssh/filexfer/openssh/hardlink.go @@ -62,15 +62,12 @@ func (ep *HardlinkExtendedPacket) MarshalBinary() ([]byte, error) { // UnmarshalFrom decodes the hardlink@openssh.com extended packet-specific data from buf. func (ep *HardlinkExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.OldPath, err = buf.ConsumeString(); err != nil { - return err + *ep = HardlinkExtendedPacket{ + OldPath: buf.ConsumeString(), + NewPath: buf.ConsumeString(), } - if ep.NewPath, err = buf.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // UnmarshalBinary decodes the hardlink@openssh.com extended packet-specific data into ep. diff --git a/internal/encoding/ssh/filexfer/openssh/posix-rename.go b/internal/encoding/ssh/filexfer/openssh/posix-rename.go index a3d3de52..5166489c 100644 --- a/internal/encoding/ssh/filexfer/openssh/posix-rename.go +++ b/internal/encoding/ssh/filexfer/openssh/posix-rename.go @@ -4,38 +4,38 @@ import ( sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" ) -const extensionPosixRename = "posix-rename@openssh.com" +const extensionPOSIXRename = "posix-rename@openssh.com" -// RegisterExtensionPosixRename registers the "posix-rename@openssh.com" extended packet with the encoding/ssh/filexfer package. -func RegisterExtensionPosixRename() { - sshfx.RegisterExtendedPacketType(extensionPosixRename, func() sshfx.ExtendedData { - return new(PosixRenameExtendedPacket) +// RegisterExtensionPOSIXRename registers the "posix-rename@openssh.com" extended packet with the encoding/ssh/filexfer package. +func RegisterExtensionPOSIXRename() { + sshfx.RegisterExtendedPacketType(extensionPOSIXRename, func() sshfx.ExtendedData { + return new(POSIXRenameExtendedPacket) }) } -// ExtensionPosixRename returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket. -func ExtensionPosixRename() *sshfx.ExtensionPair { +// ExtensionPOSIXRename returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket. +func ExtensionPOSIXRename() *sshfx.ExtensionPair { return &sshfx.ExtensionPair{ - Name: extensionPosixRename, + Name: extensionPOSIXRename, Data: "1", } } -// PosixRenameExtendedPacket defines the posix-rename@openssh.com extend packet. -type PosixRenameExtendedPacket struct { +// POSIXRenameExtendedPacket defines the posix-rename@openssh.com extend packet. +type POSIXRenameExtendedPacket struct { OldPath string NewPath string } // Type returns the SSH_FXP_EXTENDED packet type. -func (ep *PosixRenameExtendedPacket) Type() sshfx.PacketType { +func (ep *POSIXRenameExtendedPacket) Type() sshfx.PacketType { return sshfx.PacketTypeExtended } // MarshalPacket returns ep as a two-part binary encoding of the full extended packet. -func (ep *PosixRenameExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { +func (ep *POSIXRenameExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { p := &sshfx.ExtendedPacket{ - ExtendedRequest: extensionPosixRename, + ExtendedRequest: extensionPOSIXRename, Data: ep, } @@ -43,7 +43,7 @@ func (ep *PosixRenameExtendedPacket) MarshalPacket(reqid uint32, b []byte) (head } // MarshalInto encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data. -func (ep *PosixRenameExtendedPacket) MarshalInto(buf *sshfx.Buffer) { +func (ep *POSIXRenameExtendedPacket) MarshalInto(buf *sshfx.Buffer) { buf.AppendString(ep.OldPath) buf.AppendString(ep.NewPath) } @@ -51,7 +51,7 @@ func (ep *PosixRenameExtendedPacket) MarshalInto(buf *sshfx.Buffer) { // MarshalBinary encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data. // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. -func (ep *PosixRenameExtendedPacket) MarshalBinary() ([]byte, error) { +func (ep *POSIXRenameExtendedPacket) MarshalBinary() ([]byte, error) { // string(oldpath) + string(newpath) size := 4 + len(ep.OldPath) + 4 + len(ep.NewPath) @@ -61,19 +61,16 @@ func (ep *PosixRenameExtendedPacket) MarshalBinary() ([]byte, error) { } // UnmarshalFrom decodes the hardlink@openssh.com extended packet-specific data from buf. -func (ep *PosixRenameExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.OldPath, err = buf.ConsumeString(); err != nil { - return err +func (ep *POSIXRenameExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { + *ep = POSIXRenameExtendedPacket{ + OldPath: buf.ConsumeString(), + NewPath: buf.ConsumeString(), } - if ep.NewPath, err = buf.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // UnmarshalBinary decodes the hardlink@openssh.com extended packet-specific data into ep. -func (ep *PosixRenameExtendedPacket) UnmarshalBinary(data []byte) (err error) { +func (ep *POSIXRenameExtendedPacket) UnmarshalBinary(data []byte) (err error) { return ep.UnmarshalFrom(sshfx.NewBuffer(data)) } diff --git a/internal/encoding/ssh/filexfer/openssh/posix-rename_test.go b/internal/encoding/ssh/filexfer/openssh/posix-rename_test.go index 6bdb10d4..58e4fffb 100644 --- a/internal/encoding/ssh/filexfer/openssh/posix-rename_test.go +++ b/internal/encoding/ssh/filexfer/openssh/posix-rename_test.go @@ -7,20 +7,20 @@ import ( sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" ) -var _ sshfx.PacketMarshaller = &PosixRenameExtendedPacket{} +var _ sshfx.PacketMarshaller = &POSIXRenameExtendedPacket{} func init() { - RegisterExtensionPosixRename() + RegisterExtensionPOSIXRename() } -func TestPosixRenameExtendedPacket(t *testing.T) { +func TestPOSIXRenameExtendedPacket(t *testing.T) { const ( id = 42 oldpath = "/foo" newpath = "/bar" ) - ep := &PosixRenameExtendedPacket{ + ep := &POSIXRenameExtendedPacket{ OldPath: oldpath, NewPath: newpath, } @@ -50,13 +50,13 @@ func TestPosixRenameExtendedPacket(t *testing.T) { t.Fatal("unexpected error:", err) } - if p.ExtendedRequest != extensionPosixRename { - t.Errorf("UnmarshalPacketBody(): ExtendedRequest was %q, but expected %q", p.ExtendedRequest, extensionPosixRename) + if p.ExtendedRequest != extensionPOSIXRename { + t.Errorf("UnmarshalPacketBody(): ExtendedRequest was %q, but expected %q", p.ExtendedRequest, extensionPOSIXRename) } - ep, ok := p.Data.(*PosixRenameExtendedPacket) + ep, ok := p.Data.(*POSIXRenameExtendedPacket) if !ok { - t.Fatalf("UnmarshaledPacketBody(): Data was type %T, but expected *PosixRenameExtendedPacket", p.Data) + t.Fatalf("UnmarshaledPacketBody(): Data was type %T, but expected *POSIXRenameExtendedPacket", p.Data) } if ep.OldPath != oldpath { diff --git a/internal/encoding/ssh/filexfer/openssh/statvfs.go b/internal/encoding/ssh/filexfer/openssh/statvfs.go index 3e9015f7..51029ca0 100644 --- a/internal/encoding/ssh/filexfer/openssh/statvfs.go +++ b/internal/encoding/ssh/filexfer/openssh/statvfs.go @@ -61,11 +61,11 @@ func (ep *StatVFSExtendedPacket) MarshalBinary() ([]byte, error) { // UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep. func (ep *StatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.Path, err = buf.ConsumeString(); err != nil { - return err + *ep = StatVFSExtendedPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep. @@ -130,11 +130,11 @@ func (ep *FStatVFSExtendedPacket) MarshalBinary() ([]byte, error) { // UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep. func (ep *FStatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.Path, err = buf.ConsumeString(); err != nil { - return err + *ep = FStatVFSExtendedPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep. @@ -213,41 +213,21 @@ func (ep *StatVFSExtendedReplyPacket) MarshalBinary() ([]byte, error) { // UnmarshalFrom decodes the fstatvfs@openssh.com extended reply packet-specific data into ep. func (ep *StatVFSExtendedReplyPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { - if ep.BlockSize, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.FragmentSize, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.Blocks, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.BlocksFree, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.BlocksAvail, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.Files, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.FilesFree, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.FilesAvail, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.FilesystemID, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.MountFlags, err = buf.ConsumeUint64(); err != nil { - return err - } - if ep.MaxNameLength, err = buf.ConsumeUint64(); err != nil { - return err - } - - return nil + *ep = StatVFSExtendedReplyPacket{ + BlockSize: buf.ConsumeUint64(), + FragmentSize: buf.ConsumeUint64(), + Blocks: buf.ConsumeUint64(), + BlocksFree: buf.ConsumeUint64(), + BlocksAvail: buf.ConsumeUint64(), + Files: buf.ConsumeUint64(), + FilesFree: buf.ConsumeUint64(), + FilesAvail: buf.ConsumeUint64(), + FilesystemID: buf.ConsumeUint64(), + MountFlags: buf.ConsumeUint64(), + MaxNameLength: buf.ConsumeUint64(), + } + + return buf.Err } // UnmarshalBinary decodes the fstatvfs@openssh.com extended reply packet-specific data into ep. diff --git a/internal/encoding/ssh/filexfer/packets.go b/internal/encoding/ssh/filexfer/packets.go index 3f24e9c2..fdf65d05 100644 --- a/internal/encoding/ssh/filexfer/packets.go +++ b/internal/encoding/ssh/filexfer/packets.go @@ -1,59 +1,13 @@ -package filexfer +package sshfx import ( "errors" - "fmt" "io" ) // smallBufferSize is an initial allocation minimal capacity. const smallBufferSize = 64 -func newPacketFromType(typ PacketType) (Packet, error) { - switch typ { - case PacketTypeOpen: - return new(OpenPacket), nil - case PacketTypeClose: - return new(ClosePacket), nil - case PacketTypeRead: - return new(ReadPacket), nil - case PacketTypeWrite: - return new(WritePacket), nil - case PacketTypeLStat: - return new(LStatPacket), nil - case PacketTypeFStat: - return new(FStatPacket), nil - case PacketTypeSetstat: - return new(SetstatPacket), nil - case PacketTypeFSetstat: - return new(FSetstatPacket), nil - case PacketTypeOpenDir: - return new(OpenDirPacket), nil - case PacketTypeReadDir: - return new(ReadDirPacket), nil - case PacketTypeRemove: - return new(RemovePacket), nil - case PacketTypeMkdir: - return new(MkdirPacket), nil - case PacketTypeRmdir: - return new(RmdirPacket), nil - case PacketTypeRealPath: - return new(RealPathPacket), nil - case PacketTypeStat: - return new(StatPacket), nil - case PacketTypeRename: - return new(RenamePacket), nil - case PacketTypeReadLink: - return new(ReadLinkPacket), nil - case PacketTypeSymlink: - return new(SymlinkPacket), nil - case PacketTypeExtended: - return new(ExtendedPacket), nil - default: - return nil, fmt.Errorf("unexpected request packet type: %v", typ) - } -} - // RawPacket implements the general packet format from draft-ietf-secsh-filexfer-02 // // RawPacket is intended for use in clients receiving responses, @@ -63,7 +17,7 @@ func newPacketFromType(typ PacketType) (Packet, error) { // For servers expecting to receive arbitrary request packet types, // use RequestPacket. // -// Defined in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3 +// Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 type RawPacket struct { PacketType PacketType RequestID uint32 @@ -110,19 +64,14 @@ func (p *RawPacket) MarshalBinary() ([]byte, error) { // The Data field will alias the passed in Buffer, // so the buffer passed in should not be reused before RawPacket.Reset(). func (p *RawPacket) UnmarshalFrom(buf *Buffer) error { - typ, err := buf.ConsumeUint8() - if err != nil { - return err - } - - p.PacketType = PacketType(typ) - - if p.RequestID, err = buf.ConsumeUint32(); err != nil { - return err + *p = RawPacket{ + PacketType: PacketType(buf.ConsumeUint8()), + RequestID: buf.ConsumeUint32(), } p.Data = *buf - return nil + + return buf.Err } // UnmarshalBinary decodes a full raw packet out of the given data. @@ -225,7 +174,7 @@ func (p *RawPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) erro // where automatic unmarshaling of the packet body does not make sense, // use RawPacket. // -// Defined in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3 +// Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 type RequestPacket struct { RequestID uint32 @@ -268,18 +217,19 @@ func (p *RequestPacket) MarshalBinary() ([]byte, error) { // The Request field may alias the passed in Buffer, (e.g. SSH_FXP_WRITE), // so the buffer passed in should not be reused before RequestPacket.Reset(). func (p *RequestPacket) UnmarshalFrom(buf *Buffer) error { - typ, err := buf.ConsumeUint8() - if err != nil { - return err + typ := PacketType(buf.ConsumeUint8()) + if buf.Err != nil { + return buf.Err } - p.Request, err = newPacketFromType(PacketType(typ)) + req, err := newPacketFromType(typ) if err != nil { return err } - if p.RequestID, err = buf.ConsumeUint32(); err != nil { - return err + *p = RequestPacket{ + RequestID: buf.ConsumeUint32(), + Request: req, } return p.Request.UnmarshalPacketBody(buf) diff --git a/internal/encoding/ssh/filexfer/packets_test.go b/internal/encoding/ssh/filexfer/packets_test.go index 16009203..f6dac8e4 100644 --- a/internal/encoding/ssh/filexfer/packets_test.go +++ b/internal/encoding/ssh/filexfer/packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/path_packets.go b/internal/encoding/ssh/filexfer/path_packets.go index 5792d478..0180326f 100644 --- a/internal/encoding/ssh/filexfer/path_packets.go +++ b/internal/encoding/ssh/filexfer/path_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // LStatPacket defines the SSH_FXP_LSTAT packet. type LStatPacket struct { @@ -27,11 +27,11 @@ func (p *LStatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *LStatPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = LStatPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // SetstatPacket defines the SSH_FXP_SETSTAT packet. @@ -64,8 +64,8 @@ func (p *SetstatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload [ // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *SetstatPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = SetstatPacket{ + Path: buf.ConsumeString(), } return p.Attrs.UnmarshalFrom(buf) @@ -98,11 +98,11 @@ func (p *RemovePacket) MarshalPacket(reqid uint32, b []byte) (header, payload [] // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *RemovePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = RemovePacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // MkdirPacket defines the SSH_FXP_MKDIR packet. @@ -135,8 +135,8 @@ func (p *MkdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *MkdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = MkdirPacket{ + Path: buf.ConsumeString(), } return p.Attrs.UnmarshalFrom(buf) @@ -169,11 +169,11 @@ func (p *RmdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []b // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *RmdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = RmdirPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // RealPathPacket defines the SSH_FXP_REALPATH packet. @@ -203,11 +203,11 @@ func (p *RealPathPacket) MarshalPacket(reqid uint32, b []byte) (header, payload // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *RealPathPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = RealPathPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // StatPacket defines the SSH_FXP_STAT packet. @@ -237,11 +237,11 @@ func (p *StatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *StatPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = StatPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // RenamePacket defines the SSH_FXP_RENAME packet. @@ -274,15 +274,12 @@ func (p *RenamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload [] // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *RenamePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.OldPath, err = buf.ConsumeString(); err != nil { - return err + *p = RenamePacket{ + OldPath: buf.ConsumeString(), + NewPath: buf.ConsumeString(), } - if p.NewPath, err = buf.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // ReadLinkPacket defines the SSH_FXP_READLINK packet. @@ -312,11 +309,11 @@ func (p *ReadLinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *ReadLinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Path, err = buf.ConsumeString(); err != nil { - return err + *p = ReadLinkPacket{ + Path: buf.ConsumeString(), } - return nil + return buf.Err } // SymlinkPacket defines the SSH_FXP_SYMLINK packet. @@ -355,14 +352,11 @@ func (p *SymlinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload [ // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *SymlinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - // Arguments were inadvertently reversed. - if p.TargetPath, err = buf.ConsumeString(); err != nil { - return err - } - - if p.LinkPath, err = buf.ConsumeString(); err != nil { - return err + *p = SymlinkPacket{ + // Arguments were inadvertently reversed. + TargetPath: buf.ConsumeString(), + LinkPath: buf.ConsumeString(), } - return nil + return buf.Err } diff --git a/internal/encoding/ssh/filexfer/path_packets_test.go b/internal/encoding/ssh/filexfer/path_packets_test.go index bad85280..f016f7e9 100644 --- a/internal/encoding/ssh/filexfer/path_packets_test.go +++ b/internal/encoding/ssh/filexfer/path_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/internal/encoding/ssh/filexfer/permissions.go b/internal/encoding/ssh/filexfer/permissions.go index 2fe63d59..0143ec0c 100644 --- a/internal/encoding/ssh/filexfer/permissions.go +++ b/internal/encoding/ssh/filexfer/permissions.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx // FileMode represents a file’s mode and permission bits. // The bits are defined according to POSIX standards, diff --git a/internal/encoding/ssh/filexfer/response_packets.go b/internal/encoding/ssh/filexfer/response_packets.go index 7a9b3eae..311708ff 100644 --- a/internal/encoding/ssh/filexfer/response_packets.go +++ b/internal/encoding/ssh/filexfer/response_packets.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "fmt" @@ -6,7 +6,7 @@ import ( // StatusPacket defines the SSH_FXP_STATUS packet. // -// Specified in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 +// Specified in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-7 type StatusPacket struct { StatusCode Status ErrorMessage string @@ -19,7 +19,7 @@ func (p *StatusPacket) Error() string { return "sftp: " + p.StatusCode.String() } - return fmt.Sprintf("sftp: %q (%s)", p.ErrorMessage, p.StatusCode) + return fmt.Sprintf("sftp: %s: %q", p.StatusCode, p.ErrorMessage) } // Is returns true if target is a StatusPacket with the same StatusCode, @@ -57,21 +57,13 @@ func (p *StatusPacket) MarshalPacket(reqid uint32, b []byte) (header, payload [] // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *StatusPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - statusCode, err := buf.ConsumeUint32() - if err != nil { - return err + *p = StatusPacket{ + StatusCode: Status(buf.ConsumeUint32()), + ErrorMessage: buf.ConsumeString(), + LanguageTag: buf.ConsumeString(), } - p.StatusCode = Status(statusCode) - if p.ErrorMessage, err = buf.ConsumeString(); err != nil { - return err - } - - if p.LanguageTag, err = buf.ConsumeString(); err != nil { - return err - } - - return nil + return buf.Err } // HandlePacket defines the SSH_FXP_HANDLE packet. @@ -101,11 +93,11 @@ func (p *HandlePacket) MarshalPacket(reqid uint32, b []byte) (header, payload [] // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *HandlePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - if p.Handle, err = buf.ConsumeString(); err != nil { - return err + *p = HandlePacket{ + Handle: buf.ConsumeString(), } - return nil + return buf.Err } // DataPacket defines the SSH_FXP_DATA packet. @@ -143,18 +135,11 @@ func (p *DataPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by // // This means this _does not_ alias any of the data buffer that is passed in. func (p *DataPacket) UnmarshalPacketBody(buf *Buffer) (err error) { - data, err := buf.ConsumeByteSlice() - if err != nil { - return err + *p = DataPacket{ + Data: buf.ConsumeByteSliceCopy(p.Data), } - if len(p.Data) < len(data) { - p.Data = make([]byte, len(data)) - } - - n := copy(p.Data, data) - p.Data = p.Data[:n] - return nil + return buf.Err } // NamePacket defines the SSH_FXP_NAME packet. @@ -193,14 +178,16 @@ func (p *NamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []by // UnmarshalPacketBody unmarshals the packet body from the given Buffer. // It is assumed that the uint32(request-id) has already been consumed. func (p *NamePacket) UnmarshalPacketBody(buf *Buffer) (err error) { - count, err := buf.ConsumeUint32() - if err != nil { - return err + count := buf.ConsumeCount() + if buf.Err != nil { + return buf.Err } - p.Entries = make([]*NameEntry, 0, count) + *p = NamePacket{ + Entries: make([]*NameEntry, 0, count), + } - for i := uint32(0); i < count; i++ { + for i := 0; i < count; i++ { var e NameEntry if err := e.UnmarshalFrom(buf); err != nil { return err @@ -209,7 +196,7 @@ func (p *NamePacket) UnmarshalPacketBody(buf *Buffer) (err error) { p.Entries = append(p.Entries, &e) } - return nil + return buf.Err } // AttrsPacket defines the SSH_FXP_ATTRS packet. diff --git a/internal/encoding/ssh/filexfer/response_packets_test.go b/internal/encoding/ssh/filexfer/response_packets_test.go index fd006013..3f8c5b0e 100644 --- a/internal/encoding/ssh/filexfer/response_packets_test.go +++ b/internal/encoding/ssh/filexfer/response_packets_test.go @@ -1,4 +1,4 @@ -package filexfer +package sshfx import ( "bytes" diff --git a/ls_formatting_test.go b/ls_formatting_test.go index c9c63a1a..8d0fefbc 100644 --- a/ls_formatting_test.go +++ b/ls_formatting_test.go @@ -42,41 +42,41 @@ func TestRunLsWithLicensesFileWithOSLookup(t *testing.T) { } /* - The format of the `longname' field is unspecified by this protocol. - It MUST be suitable for use in the output of a directory listing - command (in fact, the recommended operation for a directory listing - command is to simply display this data). However, clients SHOULD NOT - attempt to parse the longname field for file attributes; they SHOULD - use the attrs field instead. - - The recommended format for the longname field is as follows: - - -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer - 1234567890 123 12345678 12345678 12345678 123456789012 - - Here, the first line is sample output, and the second field indicates - widths of the various fields. Fields are separated by spaces. The - first field lists file permissions for user, group, and others; the - second field is link count; the third field is the name of the user - who owns the file; the fourth field is the name of the group that - owns the file; the fifth field is the size of the file in bytes; the - sixth field (which actually may contain spaces, but is fixed to 12 - characters) is the file modification time, and the seventh field is - the file name. Each field is specified to be a minimum of certain - number of character positions (indicated by the second line above), - but may also be longer if the data does not fit in the specified - length. - - The SSH_FXP_ATTRS response has the following format: - - uint32 id - ATTRS attrs - - where `id' is the request identifier, and `attrs' is the returned - file attributes as described in Section ``File Attributes''. - - N.B.: FileZilla does parse this ls formatting, and so not rendering it - on any particular GOOS/GOARCH can cause compatibility issues with this client. +The format of the `longname' field is unspecified by this protocol. +It MUST be suitable for use in the output of a directory listing +command (in fact, the recommended operation for a directory listing +command is to simply display this data). However, clients SHOULD NOT +attempt to parse the longname field for file attributes; they SHOULD +use the attrs field instead. + + The recommended format for the longname field is as follows: + + -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer + 1234567890 123 12345678 12345678 12345678 123456789012 + +Here, the first line is sample output, and the second field indicates +widths of the various fields. Fields are separated by spaces. The +first field lists file permissions for user, group, and others; the +second field is link count; the third field is the name of the user +who owns the file; the fourth field is the name of the group that +owns the file; the fifth field is the size of the file in bytes; the +sixth field (which actually may contain spaces, but is fixed to 12 +characters) is the file modification time, and the seventh field is +the file name. Each field is specified to be a minimum of certain +number of character positions (indicated by the second line above), +but may also be longer if the data does not fit in the specified +length. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + +where `id' is the request identifier, and `attrs' is the returned +file attributes as described in Section “File Attributes”. + +N.B.: FileZilla does parse this ls formatting, and so not rendering it +on any particular GOOS/GOARCH can cause compatibility issues with this client. */ func runLsTestHelper(t *testing.T, result, expectedType, path string) { // using regular expressions to make tests work on all systems diff --git a/ls_plan9.go b/ls_plan9.go index a16a3ea0..b70b2942 100644 --- a/ls_plan9.go +++ b/ls_plan9.go @@ -1,3 +1,4 @@ +//go:build plan9 // +build plan9 package sftp diff --git a/ls_stub.go b/ls_stub.go index 6dec3937..f58abf78 100644 --- a/ls_stub.go +++ b/ls_stub.go @@ -1,3 +1,4 @@ +//go:build windows || android // +build windows android package sftp diff --git a/ls_unix.go b/ls_unix.go index 59ccffde..0beba32b 100644 --- a/ls_unix.go +++ b/ls_unix.go @@ -1,3 +1,4 @@ +//go:build aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris || js // +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris js package sftp diff --git a/packet-manager.go b/packet-manager.go index c740c4c8..647836ba 100644 --- a/packet-manager.go +++ b/packet-manager.go @@ -40,7 +40,7 @@ func newPktMgr(sender packetSender) *packetManager { return s } -//// packet ordering +// // packet ordering func (s *packetManager) newOrderID() uint32 { s.packetCount++ return s.packetCount @@ -89,7 +89,7 @@ func (o orderedPackets) Sort() { }) } -//// packet registry +// // packet registry // register incoming packets to be handled func (s *packetManager) incomingPacket(pkt orderedRequest) { s.working.Add(1) diff --git a/packet-typing.go b/packet-typing.go index f4f90529..fec88e7b 100644 --- a/packet-typing.go +++ b/packet-typing.go @@ -31,7 +31,7 @@ type notReadOnly interface { notReadOnly() } -//// define types by adding methods +// // define types by adding methods // hasPath func (p *sshFxpLstatPacket) getPath() string { return p.Path } func (p *sshFxpStatPacket) getPath() string { return p.Path } diff --git a/release.go b/release.go index b695528f..9ecedc44 100644 --- a/release.go +++ b/release.go @@ -1,3 +1,4 @@ +//go:build !debug // +build !debug package sftp diff --git a/request-plan9.go b/request-plan9.go index 0e3b4836..38f91bcd 100644 --- a/request-plan9.go +++ b/request-plan9.go @@ -1,3 +1,4 @@ +//go:build plan9 // +build plan9 package sftp diff --git a/request-readme.md b/request-readme.md index f887274d..f8b81f3a 100644 --- a/request-readme.md +++ b/request-readme.md @@ -28,7 +28,7 @@ then sends to the client. Handler for "Put" method and returns an io.Writer for the file which the server then writes the uploaded file to. The file opening "pflags" are currently preserved in the Request.Flags field as a 32bit bitmask value. See the [SFTP -spec](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.3) for +spec](https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-6.3) for details. ### Filecmd(*Request) error diff --git a/request-unix.go b/request-unix.go index d30b2569..e3e037d6 100644 --- a/request-unix.go +++ b/request-unix.go @@ -1,3 +1,4 @@ +//go:build !windows && !plan9 // +build !windows,!plan9 package sftp diff --git a/server.go b/server.go index a09741c6..503454e6 100644 --- a/server.go +++ b/server.go @@ -24,7 +24,7 @@ const ( // Server is an SSH File Transfer Protocol (sftp) server. // This is intended to provide the sftp subsystem to an ssh server daemon. // This implementation currently supports most of sftp server protocol version 3, -// as specified at http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 +// as specified at https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt type Server struct { *serverConn debugStream io.Writer diff --git a/server_statvfs_impl.go b/server_statvfs_impl.go index 94b6d832..a5470798 100644 --- a/server_statvfs_impl.go +++ b/server_statvfs_impl.go @@ -1,3 +1,4 @@ +//go:build darwin || linux // +build darwin linux // fill in statvfs structure with OS specific values diff --git a/server_statvfs_linux.go b/server_statvfs_linux.go index 1d180d47..615c4157 100644 --- a/server_statvfs_linux.go +++ b/server_statvfs_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package sftp diff --git a/server_statvfs_stubs.go b/server_statvfs_stubs.go index fbf49068..dd4705bb 100644 --- a/server_statvfs_stubs.go +++ b/server_statvfs_stubs.go @@ -1,3 +1,4 @@ +//go:build !darwin && !linux && !plan9 // +build !darwin,!linux,!plan9 package sftp diff --git a/sftp.go b/sftp.go index 9a63c39d..778c8f3d 100644 --- a/sftp.go +++ b/sftp.go @@ -1,5 +1,5 @@ // Package sftp implements the SSH File Transfer Protocol as described in -// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 +// https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt package sftp import ( diff --git a/syscall_fixed.go b/syscall_fixed.go index d4045777..e8443083 100644 --- a/syscall_fixed.go +++ b/syscall_fixed.go @@ -1,3 +1,4 @@ +//go:build plan9 || windows || (js && wasm) // +build plan9 windows js,wasm // Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of diff --git a/syscall_good.go b/syscall_good.go index 4c2b240c..50052189 100644 --- a/syscall_good.go +++ b/syscall_good.go @@ -1,4 +1,6 @@ -// +build !plan9,!windows +//go:build !plan9 && !windows && (!js || !wasm) +// +build !plan9 +// +build !windows // +build !js !wasm package sftp