func (fa *FileAttrs) ModTime() time.Time {
	return time.Unix(int64(fa.mtime), 0)
}
ModTime return the remote file modified time.
package sftp
import (
	"encoding/binary"
	"io"
	"io/fs"
	"time"
)
const (
	fileModeSticky      uint32 = 0001000
	fileModeSetgid      uint32 = 0002000
	fileModeSetuid      uint32 = 0004000
	fileTypeFifo        uint32 = 0010000
	fileTypeCharDevice  uint32 = 0020000
	fileTypeDirectory   uint32 = 0040000
	fileTypeBlockDevice uint32 = 0060000
	fileTypeRegular     uint32 = 0100000
	fileTypeSymlink     uint32 = 0120000
	fileTypeSocket      uint32 = 0140000
	fileTypeMask        uint32 = 0170000
)
const (
	attr_SIZE        uint32 = 0x00000001
	attr_UIDGID      uint32 = 0x00000002
	attr_PERMISSIONS uint32 = 0x00000004
	attr_ACMODTIME   uint32 = 0x00000008
	attr_EXTENDED    uint32 = 0x80000000
)
type FileAttrs struct {
	name        string
	flags       uint32
	size        uint64      
	uid         uint32      
	gid         uint32      
	permissions uint32      
	atime       uint32      
	mtime       uint32      
	exts        extensions  
	fsMode      fs.FileMode
}
func NewFileAttrs(fi fs.FileInfo) (fa *FileAttrs) {
	fa = &FileAttrs{
		name: fi.Name(),
	}
	mode := fi.Mode()
	mtime := fi.ModTime()
	fa.SetSize(uint64(fi.Size()))
	fa.SetPermissions(uint32(mode.Perm()))
	fa.SetModifiedTime(uint32(mtime.Unix()))
	return fa
}
func newFileAttrs() (fa *FileAttrs) {
	return &FileAttrs{}
}
func unpackFileAttrs(payload []byte) (fa *FileAttrs, length int) {
	fa = &FileAttrs{}
	fa.flags = binary.BigEndian.Uint32(payload)
	payload = payload[4:]
	length += 4
	if fa.flags&attr_SIZE != 0 {
		fa.size = binary.BigEndian.Uint64(payload)
		payload = payload[8:]
		length += 8
	}
	if fa.flags&attr_UIDGID != 0 {
		fa.uid = binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
		fa.gid = binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
	}
	if fa.flags&attr_PERMISSIONS != 0 {
		fa.permissions = binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
		fa.updateFsmode()
	}
	if fa.flags&attr_ACMODTIME != 0 {
		fa.atime = binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
		fa.mtime = binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
	}
	if fa.flags&attr_EXTENDED != 0 {
		n := binary.BigEndian.Uint32(payload)
		payload = payload[4:]
		length += 4
		fa.exts = make(extensions, n)
		for x := uint32(0); x < n; x++ {
			size := binary.BigEndian.Uint32(payload)
			payload = payload[4:]
			length += 4
			name := string(payload[:size])
			payload = payload[size:]
			length += int(size)
			size = binary.BigEndian.Uint32(payload)
			payload = payload[4:]
			length += 4
			data := string(payload[:size])
			payload = payload[size:]
			length += int(size)
			fa.exts[name] = data
		}
	}
	return fa, length
}
func (fa *FileAttrs) pack(w io.Writer) {
	_ = binary.Write(w, binary.BigEndian, fa.flags)
	if fa.flags&attr_SIZE != 0 {
		_ = binary.Write(w, binary.BigEndian, fa.size)
	}
	if fa.flags&attr_UIDGID != 0 {
		_ = binary.Write(w, binary.BigEndian, fa.uid)
		_ = binary.Write(w, binary.BigEndian, fa.gid)
	}
	if fa.flags&attr_PERMISSIONS != 0 {
		_ = binary.Write(w, binary.BigEndian, fa.permissions)
	}
	if fa.flags&attr_ACMODTIME != 0 {
		_ = binary.Write(w, binary.BigEndian, fa.atime)
		_ = binary.Write(w, binary.BigEndian, fa.mtime)
	}
	if fa.flags&attr_EXTENDED != 0 {
		n := uint32(len(fa.exts))
		_ = binary.Write(w, binary.BigEndian, n)
		for k, v := range fa.exts {
			_ = binary.Write(w, binary.BigEndian, uint32(len(k)))
			_, _ = w.Write([]byte(k))
			_ = binary.Write(w, binary.BigEndian, uint32(len(v)))
			_, _ = w.Write([]byte(v))
		}
	}
}
func (fa *FileAttrs) AccessTime() uint32 {
	return fa.atime
}
func (fa *FileAttrs) Extensions() map[string]string {
	return map[string]string(fa.exts)
}
func (fa *FileAttrs) Gid() uint32 {
	return fa.gid
}
func (fa *FileAttrs) IsDir() bool {
	return fa.fsMode.IsDir()
}