github.com/pkg/sftp@v1.13.6/packet.go (about)

     1  package sftp
     2  
     3  import (
     4  	"bytes"
     5  	"encoding"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"reflect"
    12  )
    13  
    14  var (
    15  	errLongPacket            = errors.New("packet too long")
    16  	errShortPacket           = errors.New("packet too short")
    17  	errUnknownExtendedPacket = errors.New("unknown extended packet")
    18  )
    19  
    20  const (
    21  	maxMsgLength           = 256 * 1024
    22  	debugDumpTxPacket      = false
    23  	debugDumpRxPacket      = false
    24  	debugDumpTxPacketBytes = false
    25  	debugDumpRxPacketBytes = false
    26  )
    27  
    28  func marshalUint32(b []byte, v uint32) []byte {
    29  	return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
    30  }
    31  
    32  func marshalUint64(b []byte, v uint64) []byte {
    33  	return marshalUint32(marshalUint32(b, uint32(v>>32)), uint32(v))
    34  }
    35  
    36  func marshalString(b []byte, v string) []byte {
    37  	return append(marshalUint32(b, uint32(len(v))), v...)
    38  }
    39  
    40  func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
    41  	// attributes variable struct, and also variable per protocol version
    42  	// spec version 3 attributes:
    43  	// uint32   flags
    44  	// uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
    45  	// uint32   uid            present only if flag SSH_FILEXFER_ATTR_UIDGID
    46  	// uint32   gid            present only if flag SSH_FILEXFER_ATTR_UIDGID
    47  	// uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
    48  	// uint32   atime          present only if flag SSH_FILEXFER_ACMODTIME
    49  	// uint32   mtime          present only if flag SSH_FILEXFER_ACMODTIME
    50  	// uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
    51  	// string   extended_type
    52  	// string   extended_data
    53  	// ...      more extended data (extended_type - extended_data pairs),
    54  	// 	   so that number of pairs equals extended_count
    55  
    56  	flags, fileStat := fileStatFromInfo(fi)
    57  
    58  	b = marshalUint32(b, flags)
    59  	if flags&sshFileXferAttrSize != 0 {
    60  		b = marshalUint64(b, fileStat.Size)
    61  	}
    62  	if flags&sshFileXferAttrUIDGID != 0 {
    63  		b = marshalUint32(b, fileStat.UID)
    64  		b = marshalUint32(b, fileStat.GID)
    65  	}
    66  	if flags&sshFileXferAttrPermissions != 0 {
    67  		b = marshalUint32(b, fileStat.Mode)
    68  	}
    69  	if flags&sshFileXferAttrACmodTime != 0 {
    70  		b = marshalUint32(b, fileStat.Atime)
    71  		b = marshalUint32(b, fileStat.Mtime)
    72  	}
    73  
    74  	if flags&sshFileXferAttrExtended != 0 {
    75  		b = marshalUint32(b, uint32(len(fileStat.Extended)))
    76  
    77  		for _, attr := range fileStat.Extended {
    78  			b = marshalString(b, attr.ExtType)
    79  			b = marshalString(b, attr.ExtData)
    80  		}
    81  	}
    82  
    83  	return b
    84  }
    85  
    86  func marshalStatus(b []byte, err StatusError) []byte {
    87  	b = marshalUint32(b, err.Code)
    88  	b = marshalString(b, err.msg)
    89  	b = marshalString(b, err.lang)
    90  	return b
    91  }
    92  
    93  func marshal(b []byte, v interface{}) []byte {
    94  	if v == nil {
    95  		return b
    96  	}
    97  	switch v := v.(type) {
    98  	case uint8:
    99  		return append(b, v)
   100  	case uint32:
   101  		return marshalUint32(b, v)
   102  	case uint64:
   103  		return marshalUint64(b, v)
   104  	case string:
   105  		return marshalString(b, v)
   106  	case os.FileInfo:
   107  		return marshalFileInfo(b, v)
   108  	default:
   109  		switch d := reflect.ValueOf(v); d.Kind() {
   110  		case reflect.Struct:
   111  			for i, n := 0, d.NumField(); i < n; i++ {
   112  				b = marshal(b, d.Field(i).Interface())
   113  			}
   114  			return b
   115  		case reflect.Slice:
   116  			for i, n := 0, d.Len(); i < n; i++ {
   117  				b = marshal(b, d.Index(i).Interface())
   118  			}
   119  			return b
   120  		default:
   121  			panic(fmt.Sprintf("marshal(%#v): cannot handle type %T", v, v))
   122  		}
   123  	}
   124  }
   125  
   126  func unmarshalUint32(b []byte) (uint32, []byte) {
   127  	v := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
   128  	return v, b[4:]
   129  }
   130  
   131  func unmarshalUint32Safe(b []byte) (uint32, []byte, error) {
   132  	var v uint32
   133  	if len(b) < 4 {
   134  		return 0, nil, errShortPacket
   135  	}
   136  	v, b = unmarshalUint32(b)
   137  	return v, b, nil
   138  }
   139  
   140  func unmarshalUint64(b []byte) (uint64, []byte) {
   141  	h, b := unmarshalUint32(b)
   142  	l, b := unmarshalUint32(b)
   143  	return uint64(h)<<32 | uint64(l), b
   144  }
   145  
   146  func unmarshalUint64Safe(b []byte) (uint64, []byte, error) {
   147  	var v uint64
   148  	if len(b) < 8 {
   149  		return 0, nil, errShortPacket
   150  	}
   151  	v, b = unmarshalUint64(b)
   152  	return v, b, nil
   153  }
   154  
   155  func unmarshalString(b []byte) (string, []byte) {
   156  	n, b := unmarshalUint32(b)
   157  	return string(b[:n]), b[n:]
   158  }
   159  
   160  func unmarshalStringSafe(b []byte) (string, []byte, error) {
   161  	n, b, err := unmarshalUint32Safe(b)
   162  	if err != nil {
   163  		return "", nil, err
   164  	}
   165  	if int64(n) > int64(len(b)) {
   166  		return "", nil, errShortPacket
   167  	}
   168  	return string(b[:n]), b[n:], nil
   169  }
   170  
   171  func unmarshalAttrs(b []byte) (*FileStat, []byte) {
   172  	flags, b := unmarshalUint32(b)
   173  	return unmarshalFileStat(flags, b)
   174  }
   175  
   176  func unmarshalFileStat(flags uint32, b []byte) (*FileStat, []byte) {
   177  	var fs FileStat
   178  	if flags&sshFileXferAttrSize == sshFileXferAttrSize {
   179  		fs.Size, b, _ = unmarshalUint64Safe(b)
   180  	}
   181  	if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
   182  		fs.UID, b, _ = unmarshalUint32Safe(b)
   183  	}
   184  	if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
   185  		fs.GID, b, _ = unmarshalUint32Safe(b)
   186  	}
   187  	if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions {
   188  		fs.Mode, b, _ = unmarshalUint32Safe(b)
   189  	}
   190  	if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime {
   191  		fs.Atime, b, _ = unmarshalUint32Safe(b)
   192  		fs.Mtime, b, _ = unmarshalUint32Safe(b)
   193  	}
   194  	if flags&sshFileXferAttrExtended == sshFileXferAttrExtended {
   195  		var count uint32
   196  		count, b, _ = unmarshalUint32Safe(b)
   197  		ext := make([]StatExtended, count)
   198  		for i := uint32(0); i < count; i++ {
   199  			var typ string
   200  			var data string
   201  			typ, b, _ = unmarshalStringSafe(b)
   202  			data, b, _ = unmarshalStringSafe(b)
   203  			ext[i] = StatExtended{
   204  				ExtType: typ,
   205  				ExtData: data,
   206  			}
   207  		}
   208  		fs.Extended = ext
   209  	}
   210  	return &fs, b
   211  }
   212  
   213  func unmarshalStatus(id uint32, data []byte) error {
   214  	sid, data := unmarshalUint32(data)
   215  	if sid != id {
   216  		return &unexpectedIDErr{id, sid}
   217  	}
   218  	code, data := unmarshalUint32(data)
   219  	msg, data, _ := unmarshalStringSafe(data)
   220  	lang, _, _ := unmarshalStringSafe(data)
   221  	return &StatusError{
   222  		Code: code,
   223  		msg:  msg,
   224  		lang: lang,
   225  	}
   226  }
   227  
   228  type packetMarshaler interface {
   229  	marshalPacket() (header, payload []byte, err error)
   230  }
   231  
   232  func marshalPacket(m encoding.BinaryMarshaler) (header, payload []byte, err error) {
   233  	if m, ok := m.(packetMarshaler); ok {
   234  		return m.marshalPacket()
   235  	}
   236  
   237  	header, err = m.MarshalBinary()
   238  	return
   239  }
   240  
   241  // sendPacket marshals p according to RFC 4234.
   242  func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error {
   243  	header, payload, err := marshalPacket(m)
   244  	if err != nil {
   245  		return fmt.Errorf("binary marshaller failed: %w", err)
   246  	}
   247  
   248  	length := len(header) + len(payload) - 4 // subtract the uint32(length) from the start
   249  	if debugDumpTxPacketBytes {
   250  		debug("send packet: %s %d bytes %x%x", fxp(header[4]), length, header[5:], payload)
   251  	} else if debugDumpTxPacket {
   252  		debug("send packet: %s %d bytes", fxp(header[4]), length)
   253  	}
   254  
   255  	binary.BigEndian.PutUint32(header[:4], uint32(length))
   256  
   257  	if _, err := w.Write(header); err != nil {
   258  		return fmt.Errorf("failed to send packet: %w", err)
   259  	}
   260  
   261  	if len(payload) > 0 {
   262  		if _, err := w.Write(payload); err != nil {
   263  			return fmt.Errorf("failed to send packet payload: %w", err)
   264  		}
   265  	}
   266  
   267  	return nil
   268  }
   269  
   270  func recvPacket(r io.Reader, alloc *allocator, orderID uint32) (uint8, []byte, error) {
   271  	var b []byte
   272  	if alloc != nil {
   273  		b = alloc.GetPage(orderID)
   274  	} else {
   275  		b = make([]byte, 4)
   276  	}
   277  	if _, err := io.ReadFull(r, b[:4]); err != nil {
   278  		return 0, nil, err
   279  	}
   280  	length, _ := unmarshalUint32(b)
   281  	if length > maxMsgLength {
   282  		debug("recv packet %d bytes too long", length)
   283  		return 0, nil, errLongPacket
   284  	}
   285  	if length == 0 {
   286  		debug("recv packet of 0 bytes too short")
   287  		return 0, nil, errShortPacket
   288  	}
   289  	if alloc == nil {
   290  		b = make([]byte, length)
   291  	}
   292  	if _, err := io.ReadFull(r, b[:length]); err != nil {
   293  		// ReadFull only returns EOF if it has read no bytes.
   294  		// In this case, that means a partial packet, and thus unexpected.
   295  		if err == io.EOF {
   296  			err = io.ErrUnexpectedEOF
   297  		}
   298  		debug("recv packet %d bytes: err %v", length, err)
   299  		return 0, nil, err
   300  	}
   301  	if debugDumpRxPacketBytes {
   302  		debug("recv packet: %s %d bytes %x", fxp(b[0]), length, b[1:length])
   303  	} else if debugDumpRxPacket {
   304  		debug("recv packet: %s %d bytes", fxp(b[0]), length)
   305  	}
   306  	return b[0], b[1:length], nil
   307  }
   308  
   309  type extensionPair struct {
   310  	Name string
   311  	Data string
   312  }
   313  
   314  func unmarshalExtensionPair(b []byte) (extensionPair, []byte, error) {
   315  	var ep extensionPair
   316  	var err error
   317  	ep.Name, b, err = unmarshalStringSafe(b)
   318  	if err != nil {
   319  		return ep, b, err
   320  	}
   321  	ep.Data, b, err = unmarshalStringSafe(b)
   322  	return ep, b, err
   323  }
   324  
   325  // Here starts the definition of packets along with their MarshalBinary
   326  // implementations.
   327  // Manually writing the marshalling logic wins us a lot of time and
   328  // allocation.
   329  
   330  type sshFxInitPacket struct {
   331  	Version    uint32
   332  	Extensions []extensionPair
   333  }
   334  
   335  func (p *sshFxInitPacket) MarshalBinary() ([]byte, error) {
   336  	l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
   337  	for _, e := range p.Extensions {
   338  		l += 4 + len(e.Name) + 4 + len(e.Data)
   339  	}
   340  
   341  	b := make([]byte, 4, l)
   342  	b = append(b, sshFxpInit)
   343  	b = marshalUint32(b, p.Version)
   344  
   345  	for _, e := range p.Extensions {
   346  		b = marshalString(b, e.Name)
   347  		b = marshalString(b, e.Data)
   348  	}
   349  
   350  	return b, nil
   351  }
   352  
   353  func (p *sshFxInitPacket) UnmarshalBinary(b []byte) error {
   354  	var err error
   355  	if p.Version, b, err = unmarshalUint32Safe(b); err != nil {
   356  		return err
   357  	}
   358  	for len(b) > 0 {
   359  		var ep extensionPair
   360  		ep, b, err = unmarshalExtensionPair(b)
   361  		if err != nil {
   362  			return err
   363  		}
   364  		p.Extensions = append(p.Extensions, ep)
   365  	}
   366  	return nil
   367  }
   368  
   369  type sshFxVersionPacket struct {
   370  	Version    uint32
   371  	Extensions []sshExtensionPair
   372  }
   373  
   374  type sshExtensionPair struct {
   375  	Name, Data string
   376  }
   377  
   378  func (p *sshFxVersionPacket) MarshalBinary() ([]byte, error) {
   379  	l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
   380  	for _, e := range p.Extensions {
   381  		l += 4 + len(e.Name) + 4 + len(e.Data)
   382  	}
   383  
   384  	b := make([]byte, 4, l)
   385  	b = append(b, sshFxpVersion)
   386  	b = marshalUint32(b, p.Version)
   387  
   388  	for _, e := range p.Extensions {
   389  		b = marshalString(b, e.Name)
   390  		b = marshalString(b, e.Data)
   391  	}
   392  
   393  	return b, nil
   394  }
   395  
   396  func marshalIDStringPacket(packetType byte, id uint32, str string) ([]byte, error) {
   397  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   398  		4 + len(str)
   399  
   400  	b := make([]byte, 4, l)
   401  	b = append(b, packetType)
   402  	b = marshalUint32(b, id)
   403  	b = marshalString(b, str)
   404  
   405  	return b, nil
   406  }
   407  
   408  func unmarshalIDString(b []byte, id *uint32, str *string) error {
   409  	var err error
   410  	*id, b, err = unmarshalUint32Safe(b)
   411  	if err != nil {
   412  		return err
   413  	}
   414  	*str, _, err = unmarshalStringSafe(b)
   415  	return err
   416  }
   417  
   418  type sshFxpReaddirPacket struct {
   419  	ID     uint32
   420  	Handle string
   421  }
   422  
   423  func (p *sshFxpReaddirPacket) id() uint32 { return p.ID }
   424  
   425  func (p *sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
   426  	return marshalIDStringPacket(sshFxpReaddir, p.ID, p.Handle)
   427  }
   428  
   429  func (p *sshFxpReaddirPacket) UnmarshalBinary(b []byte) error {
   430  	return unmarshalIDString(b, &p.ID, &p.Handle)
   431  }
   432  
   433  type sshFxpOpendirPacket struct {
   434  	ID   uint32
   435  	Path string
   436  }
   437  
   438  func (p *sshFxpOpendirPacket) id() uint32 { return p.ID }
   439  
   440  func (p *sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
   441  	return marshalIDStringPacket(sshFxpOpendir, p.ID, p.Path)
   442  }
   443  
   444  func (p *sshFxpOpendirPacket) UnmarshalBinary(b []byte) error {
   445  	return unmarshalIDString(b, &p.ID, &p.Path)
   446  }
   447  
   448  type sshFxpLstatPacket struct {
   449  	ID   uint32
   450  	Path string
   451  }
   452  
   453  func (p *sshFxpLstatPacket) id() uint32 { return p.ID }
   454  
   455  func (p *sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
   456  	return marshalIDStringPacket(sshFxpLstat, p.ID, p.Path)
   457  }
   458  
   459  func (p *sshFxpLstatPacket) UnmarshalBinary(b []byte) error {
   460  	return unmarshalIDString(b, &p.ID, &p.Path)
   461  }
   462  
   463  type sshFxpStatPacket struct {
   464  	ID   uint32
   465  	Path string
   466  }
   467  
   468  func (p *sshFxpStatPacket) id() uint32 { return p.ID }
   469  
   470  func (p *sshFxpStatPacket) MarshalBinary() ([]byte, error) {
   471  	return marshalIDStringPacket(sshFxpStat, p.ID, p.Path)
   472  }
   473  
   474  func (p *sshFxpStatPacket) UnmarshalBinary(b []byte) error {
   475  	return unmarshalIDString(b, &p.ID, &p.Path)
   476  }
   477  
   478  type sshFxpFstatPacket struct {
   479  	ID     uint32
   480  	Handle string
   481  }
   482  
   483  func (p *sshFxpFstatPacket) id() uint32 { return p.ID }
   484  
   485  func (p *sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
   486  	return marshalIDStringPacket(sshFxpFstat, p.ID, p.Handle)
   487  }
   488  
   489  func (p *sshFxpFstatPacket) UnmarshalBinary(b []byte) error {
   490  	return unmarshalIDString(b, &p.ID, &p.Handle)
   491  }
   492  
   493  type sshFxpClosePacket struct {
   494  	ID     uint32
   495  	Handle string
   496  }
   497  
   498  func (p *sshFxpClosePacket) id() uint32 { return p.ID }
   499  
   500  func (p *sshFxpClosePacket) MarshalBinary() ([]byte, error) {
   501  	return marshalIDStringPacket(sshFxpClose, p.ID, p.Handle)
   502  }
   503  
   504  func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error {
   505  	return unmarshalIDString(b, &p.ID, &p.Handle)
   506  }
   507  
   508  type sshFxpRemovePacket struct {
   509  	ID       uint32
   510  	Filename string
   511  }
   512  
   513  func (p *sshFxpRemovePacket) id() uint32 { return p.ID }
   514  
   515  func (p *sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
   516  	return marshalIDStringPacket(sshFxpRemove, p.ID, p.Filename)
   517  }
   518  
   519  func (p *sshFxpRemovePacket) UnmarshalBinary(b []byte) error {
   520  	return unmarshalIDString(b, &p.ID, &p.Filename)
   521  }
   522  
   523  type sshFxpRmdirPacket struct {
   524  	ID   uint32
   525  	Path string
   526  }
   527  
   528  func (p *sshFxpRmdirPacket) id() uint32 { return p.ID }
   529  
   530  func (p *sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
   531  	return marshalIDStringPacket(sshFxpRmdir, p.ID, p.Path)
   532  }
   533  
   534  func (p *sshFxpRmdirPacket) UnmarshalBinary(b []byte) error {
   535  	return unmarshalIDString(b, &p.ID, &p.Path)
   536  }
   537  
   538  type sshFxpSymlinkPacket struct {
   539  	ID uint32
   540  
   541  	// The order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed.
   542  	// Unfortunately, the reversal was not noticed until the server was widely deployed.
   543  	// Covered in Section 4.1 of https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
   544  
   545  	Targetpath string
   546  	Linkpath   string
   547  }
   548  
   549  func (p *sshFxpSymlinkPacket) id() uint32 { return p.ID }
   550  
   551  func (p *sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) {
   552  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   553  		4 + len(p.Targetpath) +
   554  		4 + len(p.Linkpath)
   555  
   556  	b := make([]byte, 4, l)
   557  	b = append(b, sshFxpSymlink)
   558  	b = marshalUint32(b, p.ID)
   559  	b = marshalString(b, p.Targetpath)
   560  	b = marshalString(b, p.Linkpath)
   561  
   562  	return b, nil
   563  }
   564  
   565  func (p *sshFxpSymlinkPacket) UnmarshalBinary(b []byte) error {
   566  	var err error
   567  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   568  		return err
   569  	} else if p.Targetpath, b, err = unmarshalStringSafe(b); err != nil {
   570  		return err
   571  	} else if p.Linkpath, _, err = unmarshalStringSafe(b); err != nil {
   572  		return err
   573  	}
   574  	return nil
   575  }
   576  
   577  type sshFxpHardlinkPacket struct {
   578  	ID      uint32
   579  	Oldpath string
   580  	Newpath string
   581  }
   582  
   583  func (p *sshFxpHardlinkPacket) id() uint32 { return p.ID }
   584  
   585  func (p *sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) {
   586  	const ext = "hardlink@openssh.com"
   587  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   588  		4 + len(ext) +
   589  		4 + len(p.Oldpath) +
   590  		4 + len(p.Newpath)
   591  
   592  	b := make([]byte, 4, l)
   593  	b = append(b, sshFxpExtended)
   594  	b = marshalUint32(b, p.ID)
   595  	b = marshalString(b, ext)
   596  	b = marshalString(b, p.Oldpath)
   597  	b = marshalString(b, p.Newpath)
   598  
   599  	return b, nil
   600  }
   601  
   602  type sshFxpReadlinkPacket struct {
   603  	ID   uint32
   604  	Path string
   605  }
   606  
   607  func (p *sshFxpReadlinkPacket) id() uint32 { return p.ID }
   608  
   609  func (p *sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
   610  	return marshalIDStringPacket(sshFxpReadlink, p.ID, p.Path)
   611  }
   612  
   613  func (p *sshFxpReadlinkPacket) UnmarshalBinary(b []byte) error {
   614  	return unmarshalIDString(b, &p.ID, &p.Path)
   615  }
   616  
   617  type sshFxpRealpathPacket struct {
   618  	ID   uint32
   619  	Path string
   620  }
   621  
   622  func (p *sshFxpRealpathPacket) id() uint32 { return p.ID }
   623  
   624  func (p *sshFxpRealpathPacket) MarshalBinary() ([]byte, error) {
   625  	return marshalIDStringPacket(sshFxpRealpath, p.ID, p.Path)
   626  }
   627  
   628  func (p *sshFxpRealpathPacket) UnmarshalBinary(b []byte) error {
   629  	return unmarshalIDString(b, &p.ID, &p.Path)
   630  }
   631  
   632  type sshFxpNameAttr struct {
   633  	Name     string
   634  	LongName string
   635  	Attrs    []interface{}
   636  }
   637  
   638  func (p *sshFxpNameAttr) MarshalBinary() ([]byte, error) {
   639  	var b []byte
   640  	b = marshalString(b, p.Name)
   641  	b = marshalString(b, p.LongName)
   642  	for _, attr := range p.Attrs {
   643  		b = marshal(b, attr)
   644  	}
   645  	return b, nil
   646  }
   647  
   648  type sshFxpNamePacket struct {
   649  	ID        uint32
   650  	NameAttrs []*sshFxpNameAttr
   651  }
   652  
   653  func (p *sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) {
   654  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   655  		4
   656  
   657  	b := make([]byte, 4, l)
   658  	b = append(b, sshFxpName)
   659  	b = marshalUint32(b, p.ID)
   660  	b = marshalUint32(b, uint32(len(p.NameAttrs)))
   661  
   662  	var payload []byte
   663  	for _, na := range p.NameAttrs {
   664  		ab, err := na.MarshalBinary()
   665  		if err != nil {
   666  			return nil, nil, err
   667  		}
   668  
   669  		payload = append(payload, ab...)
   670  	}
   671  
   672  	return b, payload, nil
   673  }
   674  
   675  func (p *sshFxpNamePacket) MarshalBinary() ([]byte, error) {
   676  	header, payload, err := p.marshalPacket()
   677  	return append(header, payload...), err
   678  }
   679  
   680  type sshFxpOpenPacket struct {
   681  	ID     uint32
   682  	Path   string
   683  	Pflags uint32
   684  	Flags  uint32 // ignored
   685  }
   686  
   687  func (p *sshFxpOpenPacket) id() uint32 { return p.ID }
   688  
   689  func (p *sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
   690  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   691  		4 + len(p.Path) +
   692  		4 + 4
   693  
   694  	b := make([]byte, 4, l)
   695  	b = append(b, sshFxpOpen)
   696  	b = marshalUint32(b, p.ID)
   697  	b = marshalString(b, p.Path)
   698  	b = marshalUint32(b, p.Pflags)
   699  	b = marshalUint32(b, p.Flags)
   700  
   701  	return b, nil
   702  }
   703  
   704  func (p *sshFxpOpenPacket) UnmarshalBinary(b []byte) error {
   705  	var err error
   706  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   707  		return err
   708  	} else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
   709  		return err
   710  	} else if p.Pflags, b, err = unmarshalUint32Safe(b); err != nil {
   711  		return err
   712  	} else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil {
   713  		return err
   714  	}
   715  	return nil
   716  }
   717  
   718  type sshFxpReadPacket struct {
   719  	ID     uint32
   720  	Len    uint32
   721  	Offset uint64
   722  	Handle string
   723  }
   724  
   725  func (p *sshFxpReadPacket) id() uint32 { return p.ID }
   726  
   727  func (p *sshFxpReadPacket) MarshalBinary() ([]byte, error) {
   728  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   729  		4 + len(p.Handle) +
   730  		8 + 4 // uint64 + uint32
   731  
   732  	b := make([]byte, 4, l)
   733  	b = append(b, sshFxpRead)
   734  	b = marshalUint32(b, p.ID)
   735  	b = marshalString(b, p.Handle)
   736  	b = marshalUint64(b, p.Offset)
   737  	b = marshalUint32(b, p.Len)
   738  
   739  	return b, nil
   740  }
   741  
   742  func (p *sshFxpReadPacket) UnmarshalBinary(b []byte) error {
   743  	var err error
   744  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   745  		return err
   746  	} else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
   747  		return err
   748  	} else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil {
   749  		return err
   750  	} else if p.Len, _, err = unmarshalUint32Safe(b); err != nil {
   751  		return err
   752  	}
   753  	return nil
   754  }
   755  
   756  // We need allocate bigger slices with extra capacity to avoid a re-allocation in sshFxpDataPacket.MarshalBinary
   757  // So, we need: uint32(length) + byte(type) + uint32(id) + uint32(data_length)
   758  const dataHeaderLen = 4 + 1 + 4 + 4
   759  
   760  func (p *sshFxpReadPacket) getDataSlice(alloc *allocator, orderID uint32) []byte {
   761  	dataLen := p.Len
   762  	if dataLen > maxTxPacket {
   763  		dataLen = maxTxPacket
   764  	}
   765  
   766  	if alloc != nil {
   767  		// GetPage returns a slice with capacity = maxMsgLength this is enough to avoid new allocations in
   768  		// sshFxpDataPacket.MarshalBinary
   769  		return alloc.GetPage(orderID)[:dataLen]
   770  	}
   771  
   772  	// allocate with extra space for the header
   773  	return make([]byte, dataLen, dataLen+dataHeaderLen)
   774  }
   775  
   776  type sshFxpRenamePacket struct {
   777  	ID      uint32
   778  	Oldpath string
   779  	Newpath string
   780  }
   781  
   782  func (p *sshFxpRenamePacket) id() uint32 { return p.ID }
   783  
   784  func (p *sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
   785  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   786  		4 + len(p.Oldpath) +
   787  		4 + len(p.Newpath)
   788  
   789  	b := make([]byte, 4, l)
   790  	b = append(b, sshFxpRename)
   791  	b = marshalUint32(b, p.ID)
   792  	b = marshalString(b, p.Oldpath)
   793  	b = marshalString(b, p.Newpath)
   794  
   795  	return b, nil
   796  }
   797  
   798  func (p *sshFxpRenamePacket) UnmarshalBinary(b []byte) error {
   799  	var err error
   800  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   801  		return err
   802  	} else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
   803  		return err
   804  	} else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
   805  		return err
   806  	}
   807  	return nil
   808  }
   809  
   810  type sshFxpPosixRenamePacket struct {
   811  	ID      uint32
   812  	Oldpath string
   813  	Newpath string
   814  }
   815  
   816  func (p *sshFxpPosixRenamePacket) id() uint32 { return p.ID }
   817  
   818  func (p *sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) {
   819  	const ext = "posix-rename@openssh.com"
   820  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   821  		4 + len(ext) +
   822  		4 + len(p.Oldpath) +
   823  		4 + len(p.Newpath)
   824  
   825  	b := make([]byte, 4, l)
   826  	b = append(b, sshFxpExtended)
   827  	b = marshalUint32(b, p.ID)
   828  	b = marshalString(b, ext)
   829  	b = marshalString(b, p.Oldpath)
   830  	b = marshalString(b, p.Newpath)
   831  
   832  	return b, nil
   833  }
   834  
   835  type sshFxpWritePacket struct {
   836  	ID     uint32
   837  	Length uint32
   838  	Offset uint64
   839  	Handle string
   840  	Data   []byte
   841  }
   842  
   843  func (p *sshFxpWritePacket) id() uint32 { return p.ID }
   844  
   845  func (p *sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) {
   846  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   847  		4 + len(p.Handle) +
   848  		8 + // uint64
   849  		4
   850  
   851  	b := make([]byte, 4, l)
   852  	b = append(b, sshFxpWrite)
   853  	b = marshalUint32(b, p.ID)
   854  	b = marshalString(b, p.Handle)
   855  	b = marshalUint64(b, p.Offset)
   856  	b = marshalUint32(b, p.Length)
   857  
   858  	return b, p.Data, nil
   859  }
   860  
   861  func (p *sshFxpWritePacket) MarshalBinary() ([]byte, error) {
   862  	header, payload, err := p.marshalPacket()
   863  	return append(header, payload...), err
   864  }
   865  
   866  func (p *sshFxpWritePacket) UnmarshalBinary(b []byte) error {
   867  	var err error
   868  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   869  		return err
   870  	} else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
   871  		return err
   872  	} else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil {
   873  		return err
   874  	} else if p.Length, b, err = unmarshalUint32Safe(b); err != nil {
   875  		return err
   876  	} else if uint32(len(b)) < p.Length {
   877  		return errShortPacket
   878  	}
   879  
   880  	p.Data = b[:p.Length]
   881  	return nil
   882  }
   883  
   884  type sshFxpMkdirPacket struct {
   885  	ID    uint32
   886  	Flags uint32 // ignored
   887  	Path  string
   888  }
   889  
   890  func (p *sshFxpMkdirPacket) id() uint32 { return p.ID }
   891  
   892  func (p *sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
   893  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   894  		4 + len(p.Path) +
   895  		4 // uint32
   896  
   897  	b := make([]byte, 4, l)
   898  	b = append(b, sshFxpMkdir)
   899  	b = marshalUint32(b, p.ID)
   900  	b = marshalString(b, p.Path)
   901  	b = marshalUint32(b, p.Flags)
   902  
   903  	return b, nil
   904  }
   905  
   906  func (p *sshFxpMkdirPacket) UnmarshalBinary(b []byte) error {
   907  	var err error
   908  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   909  		return err
   910  	} else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
   911  		return err
   912  	} else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil {
   913  		return err
   914  	}
   915  	return nil
   916  }
   917  
   918  type sshFxpSetstatPacket struct {
   919  	ID    uint32
   920  	Flags uint32
   921  	Path  string
   922  	Attrs interface{}
   923  }
   924  
   925  type sshFxpFsetstatPacket struct {
   926  	ID     uint32
   927  	Flags  uint32
   928  	Handle string
   929  	Attrs  interface{}
   930  }
   931  
   932  func (p *sshFxpSetstatPacket) id() uint32  { return p.ID }
   933  func (p *sshFxpFsetstatPacket) id() uint32 { return p.ID }
   934  
   935  func (p *sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) {
   936  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   937  		4 + len(p.Path) +
   938  		4 // uint32
   939  
   940  	b := make([]byte, 4, l)
   941  	b = append(b, sshFxpSetstat)
   942  	b = marshalUint32(b, p.ID)
   943  	b = marshalString(b, p.Path)
   944  	b = marshalUint32(b, p.Flags)
   945  
   946  	payload := marshal(nil, p.Attrs)
   947  
   948  	return b, payload, nil
   949  }
   950  
   951  func (p *sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
   952  	header, payload, err := p.marshalPacket()
   953  	return append(header, payload...), err
   954  }
   955  
   956  func (p *sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) {
   957  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
   958  		4 + len(p.Handle) +
   959  		4 // uint32
   960  
   961  	b := make([]byte, 4, l)
   962  	b = append(b, sshFxpFsetstat)
   963  	b = marshalUint32(b, p.ID)
   964  	b = marshalString(b, p.Handle)
   965  	b = marshalUint32(b, p.Flags)
   966  
   967  	payload := marshal(nil, p.Attrs)
   968  
   969  	return b, payload, nil
   970  }
   971  
   972  func (p *sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) {
   973  	header, payload, err := p.marshalPacket()
   974  	return append(header, payload...), err
   975  }
   976  
   977  func (p *sshFxpSetstatPacket) UnmarshalBinary(b []byte) error {
   978  	var err error
   979  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   980  		return err
   981  	} else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
   982  		return err
   983  	} else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil {
   984  		return err
   985  	}
   986  	p.Attrs = b
   987  	return nil
   988  }
   989  
   990  func (p *sshFxpFsetstatPacket) UnmarshalBinary(b []byte) error {
   991  	var err error
   992  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
   993  		return err
   994  	} else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
   995  		return err
   996  	} else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil {
   997  		return err
   998  	}
   999  	p.Attrs = b
  1000  	return nil
  1001  }
  1002  
  1003  type sshFxpHandlePacket struct {
  1004  	ID     uint32
  1005  	Handle string
  1006  }
  1007  
  1008  func (p *sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
  1009  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  1010  		4 + len(p.Handle)
  1011  
  1012  	b := make([]byte, 4, l)
  1013  	b = append(b, sshFxpHandle)
  1014  	b = marshalUint32(b, p.ID)
  1015  	b = marshalString(b, p.Handle)
  1016  
  1017  	return b, nil
  1018  }
  1019  
  1020  type sshFxpStatusPacket struct {
  1021  	ID uint32
  1022  	StatusError
  1023  }
  1024  
  1025  func (p *sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
  1026  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  1027  		4 +
  1028  		4 + len(p.StatusError.msg) +
  1029  		4 + len(p.StatusError.lang)
  1030  
  1031  	b := make([]byte, 4, l)
  1032  	b = append(b, sshFxpStatus)
  1033  	b = marshalUint32(b, p.ID)
  1034  	b = marshalStatus(b, p.StatusError)
  1035  
  1036  	return b, nil
  1037  }
  1038  
  1039  type sshFxpDataPacket struct {
  1040  	ID     uint32
  1041  	Length uint32
  1042  	Data   []byte
  1043  }
  1044  
  1045  func (p *sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) {
  1046  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  1047  		4
  1048  
  1049  	b := make([]byte, 4, l)
  1050  	b = append(b, sshFxpData)
  1051  	b = marshalUint32(b, p.ID)
  1052  	b = marshalUint32(b, p.Length)
  1053  
  1054  	return b, p.Data, nil
  1055  }
  1056  
  1057  // MarshalBinary encodes the receiver into a binary form and returns the result.
  1058  // To avoid a new allocation the Data slice must have a capacity >= Length + 9
  1059  //
  1060  // This is hand-coded rather than just append(header, payload...),
  1061  // in order to try and reuse the r.Data backing store in the packet.
  1062  func (p *sshFxpDataPacket) MarshalBinary() ([]byte, error) {
  1063  	b := append(p.Data, make([]byte, dataHeaderLen)...)
  1064  	copy(b[dataHeaderLen:], p.Data[:p.Length])
  1065  	// b[0:4] will be overwritten with the length in sendPacket
  1066  	b[4] = sshFxpData
  1067  	binary.BigEndian.PutUint32(b[5:9], p.ID)
  1068  	binary.BigEndian.PutUint32(b[9:13], p.Length)
  1069  	return b, nil
  1070  }
  1071  
  1072  func (p *sshFxpDataPacket) UnmarshalBinary(b []byte) error {
  1073  	var err error
  1074  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1075  		return err
  1076  	} else if p.Length, b, err = unmarshalUint32Safe(b); err != nil {
  1077  		return err
  1078  	} else if uint32(len(b)) < p.Length {
  1079  		return errShortPacket
  1080  	}
  1081  
  1082  	p.Data = b[:p.Length]
  1083  	return nil
  1084  }
  1085  
  1086  type sshFxpStatvfsPacket struct {
  1087  	ID   uint32
  1088  	Path string
  1089  }
  1090  
  1091  func (p *sshFxpStatvfsPacket) id() uint32 { return p.ID }
  1092  
  1093  func (p *sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
  1094  	const ext = "statvfs@openssh.com"
  1095  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  1096  		4 + len(ext) +
  1097  		4 + len(p.Path)
  1098  
  1099  	b := make([]byte, 4, l)
  1100  	b = append(b, sshFxpExtended)
  1101  	b = marshalUint32(b, p.ID)
  1102  	b = marshalString(b, ext)
  1103  	b = marshalString(b, p.Path)
  1104  
  1105  	return b, nil
  1106  }
  1107  
  1108  // A StatVFS contains statistics about a filesystem.
  1109  type StatVFS struct {
  1110  	ID      uint32
  1111  	Bsize   uint64 /* file system block size */
  1112  	Frsize  uint64 /* fundamental fs block size */
  1113  	Blocks  uint64 /* number of blocks (unit f_frsize) */
  1114  	Bfree   uint64 /* free blocks in file system */
  1115  	Bavail  uint64 /* free blocks for non-root */
  1116  	Files   uint64 /* total file inodes */
  1117  	Ffree   uint64 /* free file inodes */
  1118  	Favail  uint64 /* free file inodes for to non-root */
  1119  	Fsid    uint64 /* file system id */
  1120  	Flag    uint64 /* bit mask of f_flag values */
  1121  	Namemax uint64 /* maximum filename length */
  1122  }
  1123  
  1124  // TotalSpace calculates the amount of total space in a filesystem.
  1125  func (p *StatVFS) TotalSpace() uint64 {
  1126  	return p.Frsize * p.Blocks
  1127  }
  1128  
  1129  // FreeSpace calculates the amount of free space in a filesystem.
  1130  func (p *StatVFS) FreeSpace() uint64 {
  1131  	return p.Frsize * p.Bfree
  1132  }
  1133  
  1134  // marshalPacket converts to ssh_FXP_EXTENDED_REPLY packet binary format
  1135  func (p *StatVFS) marshalPacket() ([]byte, []byte, error) {
  1136  	header := []byte{0, 0, 0, 0, sshFxpExtendedReply}
  1137  
  1138  	var buf bytes.Buffer
  1139  	err := binary.Write(&buf, binary.BigEndian, p)
  1140  
  1141  	return header, buf.Bytes(), err
  1142  }
  1143  
  1144  // MarshalBinary encodes the StatVFS as an SSH_FXP_EXTENDED_REPLY packet.
  1145  func (p *StatVFS) MarshalBinary() ([]byte, error) {
  1146  	header, payload, err := p.marshalPacket()
  1147  	return append(header, payload...), err
  1148  }
  1149  
  1150  type sshFxpFsyncPacket struct {
  1151  	ID     uint32
  1152  	Handle string
  1153  }
  1154  
  1155  func (p *sshFxpFsyncPacket) id() uint32 { return p.ID }
  1156  
  1157  func (p *sshFxpFsyncPacket) MarshalBinary() ([]byte, error) {
  1158  	const ext = "fsync@openssh.com"
  1159  	l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  1160  		4 + len(ext) +
  1161  		4 + len(p.Handle)
  1162  
  1163  	b := make([]byte, 4, l)
  1164  	b = append(b, sshFxpExtended)
  1165  	b = marshalUint32(b, p.ID)
  1166  	b = marshalString(b, ext)
  1167  	b = marshalString(b, p.Handle)
  1168  
  1169  	return b, nil
  1170  }
  1171  
  1172  type sshFxpExtendedPacket struct {
  1173  	ID              uint32
  1174  	ExtendedRequest string
  1175  	SpecificPacket  interface {
  1176  		serverRespondablePacket
  1177  		readonly() bool
  1178  	}
  1179  }
  1180  
  1181  func (p *sshFxpExtendedPacket) id() uint32 { return p.ID }
  1182  func (p *sshFxpExtendedPacket) readonly() bool {
  1183  	if p.SpecificPacket == nil {
  1184  		return true
  1185  	}
  1186  	return p.SpecificPacket.readonly()
  1187  }
  1188  
  1189  func (p *sshFxpExtendedPacket) respond(svr *Server) responsePacket {
  1190  	if p.SpecificPacket == nil {
  1191  		return statusFromError(p.ID, nil)
  1192  	}
  1193  	return p.SpecificPacket.respond(svr)
  1194  }
  1195  
  1196  func (p *sshFxpExtendedPacket) UnmarshalBinary(b []byte) error {
  1197  	var err error
  1198  	bOrig := b
  1199  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1200  		return err
  1201  	} else if p.ExtendedRequest, _, err = unmarshalStringSafe(b); err != nil {
  1202  		return err
  1203  	}
  1204  
  1205  	// specific unmarshalling
  1206  	switch p.ExtendedRequest {
  1207  	case "statvfs@openssh.com":
  1208  		p.SpecificPacket = &sshFxpExtendedPacketStatVFS{}
  1209  	case "posix-rename@openssh.com":
  1210  		p.SpecificPacket = &sshFxpExtendedPacketPosixRename{}
  1211  	case "hardlink@openssh.com":
  1212  		p.SpecificPacket = &sshFxpExtendedPacketHardlink{}
  1213  	default:
  1214  		return fmt.Errorf("packet type %v: %w", p.SpecificPacket, errUnknownExtendedPacket)
  1215  	}
  1216  
  1217  	return p.SpecificPacket.UnmarshalBinary(bOrig)
  1218  }
  1219  
  1220  type sshFxpExtendedPacketStatVFS struct {
  1221  	ID              uint32
  1222  	ExtendedRequest string
  1223  	Path            string
  1224  }
  1225  
  1226  func (p *sshFxpExtendedPacketStatVFS) id() uint32     { return p.ID }
  1227  func (p *sshFxpExtendedPacketStatVFS) readonly() bool { return true }
  1228  func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error {
  1229  	var err error
  1230  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1231  		return err
  1232  	} else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1233  		return err
  1234  	} else if p.Path, _, err = unmarshalStringSafe(b); err != nil {
  1235  		return err
  1236  	}
  1237  	return nil
  1238  }
  1239  
  1240  type sshFxpExtendedPacketPosixRename struct {
  1241  	ID              uint32
  1242  	ExtendedRequest string
  1243  	Oldpath         string
  1244  	Newpath         string
  1245  }
  1246  
  1247  func (p *sshFxpExtendedPacketPosixRename) id() uint32     { return p.ID }
  1248  func (p *sshFxpExtendedPacketPosixRename) readonly() bool { return false }
  1249  func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error {
  1250  	var err error
  1251  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1252  		return err
  1253  	} else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1254  		return err
  1255  	} else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
  1256  		return err
  1257  	} else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
  1258  		return err
  1259  	}
  1260  	return nil
  1261  }
  1262  
  1263  func (p *sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
  1264  	err := os.Rename(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath))
  1265  	return statusFromError(p.ID, err)
  1266  }
  1267  
  1268  type sshFxpExtendedPacketHardlink struct {
  1269  	ID              uint32
  1270  	ExtendedRequest string
  1271  	Oldpath         string
  1272  	Newpath         string
  1273  }
  1274  
  1275  // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
  1276  func (p *sshFxpExtendedPacketHardlink) id() uint32     { return p.ID }
  1277  func (p *sshFxpExtendedPacketHardlink) readonly() bool { return true }
  1278  func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
  1279  	var err error
  1280  	if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1281  		return err
  1282  	} else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1283  		return err
  1284  	} else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
  1285  		return err
  1286  	} else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
  1287  		return err
  1288  	}
  1289  	return nil
  1290  }
  1291  
  1292  func (p *sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket {
  1293  	err := os.Link(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath))
  1294  	return statusFromError(p.ID, err)
  1295  }