summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/pkg/sftp/attrs.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pkg/sftp/attrs.go')
-rw-r--r--vendor/github.com/pkg/sftp/attrs.go241
1 files changed, 241 insertions, 0 deletions
diff --git a/vendor/github.com/pkg/sftp/attrs.go b/vendor/github.com/pkg/sftp/attrs.go
new file mode 100644
index 00000000..18412e33
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/attrs.go
@@ -0,0 +1,241 @@
+package sftp
+
+// ssh_FXP_ATTRS support
+// see http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+const (
+ ssh_FILEXFER_ATTR_SIZE = 0x00000001
+ ssh_FILEXFER_ATTR_UIDGID = 0x00000002
+ ssh_FILEXFER_ATTR_PERMISSIONS = 0x00000004
+ ssh_FILEXFER_ATTR_ACMODTIME = 0x00000008
+ ssh_FILEXFER_ATTR_EXTENDED = 0x80000000
+)
+
+// fileInfo is an artificial type designed to satisfy os.FileInfo.
+type fileInfo struct {
+ name string
+ size int64
+ mode os.FileMode
+ mtime time.Time
+ sys interface{}
+}
+
+// Name returns the base name of the file.
+func (fi *fileInfo) Name() string { return fi.name }
+
+// Size returns the length in bytes for regular files; system-dependent for others.
+func (fi *fileInfo) Size() int64 { return fi.size }
+
+// Mode returns file mode bits.
+func (fi *fileInfo) Mode() os.FileMode { return fi.mode }
+
+// ModTime returns the last modification time of the file.
+func (fi *fileInfo) ModTime() time.Time { return fi.mtime }
+
+// IsDir returns true if the file is a directory.
+func (fi *fileInfo) IsDir() bool { return fi.Mode().IsDir() }
+
+func (fi *fileInfo) Sys() interface{} { return fi.sys }
+
+// FileStat holds the original unmarshalled values from a call to READDIR or *STAT.
+// It is exported for the purposes of accessing the raw values via os.FileInfo.Sys()
+type FileStat struct {
+ Size uint64
+ Mode uint32
+ Mtime uint32
+ Atime uint32
+ UID uint32
+ GID uint32
+ Extended []StatExtended
+}
+
+// StatExtended contains additional, extended information for a FileStat.
+type StatExtended struct {
+ ExtType string
+ ExtData string
+}
+
+func fileInfoFromStat(st *FileStat, name string) os.FileInfo {
+ fs := &fileInfo{
+ name: name,
+ size: int64(st.Size),
+ mode: toFileMode(st.Mode),
+ mtime: time.Unix(int64(st.Mtime), 0),
+ sys: st,
+ }
+ return fs
+}
+
+func fileStatFromInfo(fi os.FileInfo) (uint32, FileStat) {
+ mtime := fi.ModTime().Unix()
+ atime := mtime
+ var flags uint32 = ssh_FILEXFER_ATTR_SIZE |
+ ssh_FILEXFER_ATTR_PERMISSIONS |
+ ssh_FILEXFER_ATTR_ACMODTIME
+
+ fileStat := FileStat{
+ Size: uint64(fi.Size()),
+ Mode: fromFileMode(fi.Mode()),
+ Mtime: uint32(mtime),
+ Atime: uint32(atime),
+ }
+
+ // os specific file stat decoding
+ fileStatFromInfoOs(fi, &flags, &fileStat)
+
+ return flags, fileStat
+}
+
+func unmarshalAttrs(b []byte) (*FileStat, []byte) {
+ flags, b := unmarshalUint32(b)
+ return getFileStat(flags, b)
+}
+
+func getFileStat(flags uint32, b []byte) (*FileStat, []byte) {
+ var fs FileStat
+ if flags&ssh_FILEXFER_ATTR_SIZE == ssh_FILEXFER_ATTR_SIZE {
+ fs.Size, b = unmarshalUint64(b)
+ }
+ if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
+ fs.UID, b = unmarshalUint32(b)
+ }
+ if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
+ fs.GID, b = unmarshalUint32(b)
+ }
+ if flags&ssh_FILEXFER_ATTR_PERMISSIONS == ssh_FILEXFER_ATTR_PERMISSIONS {
+ fs.Mode, b = unmarshalUint32(b)
+ }
+ if flags&ssh_FILEXFER_ATTR_ACMODTIME == ssh_FILEXFER_ATTR_ACMODTIME {
+ fs.Atime, b = unmarshalUint32(b)
+ fs.Mtime, b = unmarshalUint32(b)
+ }
+ if flags&ssh_FILEXFER_ATTR_EXTENDED == ssh_FILEXFER_ATTR_EXTENDED {
+ var count uint32
+ count, b = unmarshalUint32(b)
+ ext := make([]StatExtended, count)
+ for i := uint32(0); i < count; i++ {
+ var typ string
+ var data string
+ typ, b = unmarshalString(b)
+ data, b = unmarshalString(b)
+ ext[i] = StatExtended{typ, data}
+ }
+ fs.Extended = ext
+ }
+ return &fs, b
+}
+
+func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
+ // attributes variable struct, and also variable per protocol version
+ // spec version 3 attributes:
+ // uint32 flags
+ // uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
+ // uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ // uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ // uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+ // uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
+ // uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
+ // uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+ // string extended_type
+ // string extended_data
+ // ... more extended data (extended_type - extended_data pairs),
+ // so that number of pairs equals extended_count
+
+ flags, fileStat := fileStatFromInfo(fi)
+
+ b = marshalUint32(b, flags)
+ if flags&ssh_FILEXFER_ATTR_SIZE != 0 {
+ b = marshalUint64(b, fileStat.Size)
+ }
+ if flags&ssh_FILEXFER_ATTR_UIDGID != 0 {
+ b = marshalUint32(b, fileStat.UID)
+ b = marshalUint32(b, fileStat.GID)
+ }
+ if flags&ssh_FILEXFER_ATTR_PERMISSIONS != 0 {
+ b = marshalUint32(b, fileStat.Mode)
+ }
+ if flags&ssh_FILEXFER_ATTR_ACMODTIME != 0 {
+ b = marshalUint32(b, fileStat.Atime)
+ b = marshalUint32(b, fileStat.Mtime)
+ }
+
+ return b
+}
+
+// toFileMode converts sftp filemode bits to the os.FileMode specification
+func toFileMode(mode uint32) os.FileMode {
+ var fm = os.FileMode(mode & 0777)
+ switch mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fm |= os.ModeDevice
+ case syscall.S_IFCHR:
+ fm |= os.ModeDevice | os.ModeCharDevice
+ case syscall.S_IFDIR:
+ fm |= os.ModeDir
+ case syscall.S_IFIFO:
+ fm |= os.ModeNamedPipe
+ case syscall.S_IFLNK:
+ fm |= os.ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fm |= os.ModeSocket
+ }
+ if mode&syscall.S_ISGID != 0 {
+ fm |= os.ModeSetgid
+ }
+ if mode&syscall.S_ISUID != 0 {
+ fm |= os.ModeSetuid
+ }
+ if mode&syscall.S_ISVTX != 0 {
+ fm |= os.ModeSticky
+ }
+ return fm
+}
+
+// fromFileMode converts from the os.FileMode specification to sftp filemode bits
+func fromFileMode(mode os.FileMode) uint32 {
+ ret := uint32(0)
+
+ if mode&os.ModeDevice != 0 {
+ if mode&os.ModeCharDevice != 0 {
+ ret |= syscall.S_IFCHR
+ } else {
+ ret |= syscall.S_IFBLK
+ }
+ }
+ if mode&os.ModeDir != 0 {
+ ret |= syscall.S_IFDIR
+ }
+ if mode&os.ModeSymlink != 0 {
+ ret |= syscall.S_IFLNK
+ }
+ if mode&os.ModeNamedPipe != 0 {
+ ret |= syscall.S_IFIFO
+ }
+ if mode&os.ModeSetgid != 0 {
+ ret |= syscall.S_ISGID
+ }
+ if mode&os.ModeSetuid != 0 {
+ ret |= syscall.S_ISUID
+ }
+ if mode&os.ModeSticky != 0 {
+ ret |= syscall.S_ISVTX
+ }
+ if mode&os.ModeSocket != 0 {
+ ret |= syscall.S_IFSOCK
+ }
+
+ if mode&os.ModeType == 0 {
+ ret |= syscall.S_IFREG
+ }
+ ret |= uint32(mode & os.ModePerm)
+
+ return ret
+}