mirror of https://github.com/pkg/sftp.git
added statvfs@openssh.com extension request
This commit is contained in:
parent
506297c901
commit
0b805e96f9
40
client.go
40
client.go
|
@ -7,6 +7,9 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"encoding/binary"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/kr/fs"
|
"github.com/kr/fs"
|
||||||
|
|
||||||
|
@ -420,6 +423,43 @@ func (c *Client) fstat(handle string) (*FileStat, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get vfs stats from remote host.
|
||||||
|
// Implementing statvfs@openssh.com SSH_FXP_EXTENDED feature
|
||||||
|
// from http://www.opensource.apple.com/source/OpenSSH/OpenSSH-175/openssh/PROTOCOL?txt
|
||||||
|
func (c *Client) StatVFS(path string) (*StatVFS, error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
// send the StatVFS packet to the server
|
||||||
|
id := c.nextId()
|
||||||
|
typ, data, err := c.sendRequest(sshFxpStatvfsPacket{
|
||||||
|
Id: id,
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ {
|
||||||
|
// server responded with valid data
|
||||||
|
case ssh_FXP_EXTENDED_REPLY:
|
||||||
|
var response StatVFS
|
||||||
|
err = binary.Read(bytes.NewReader(data), binary.BigEndian, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("can not parse reply")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
|
||||||
|
// the resquest failed
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
return nil, errors.New("statvfs@openssh.com failure")
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, unimplementedPacketErr(typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Join joins any number of path elements into a single path, adding a
|
// Join joins any number of path elements into a single path, adding a
|
||||||
// separating slash if necessary. The result is Cleaned; in particular, all
|
// separating slash if necessary. The result is Cleaned; in particular, all
|
||||||
// empty strings are ignored.
|
// empty strings are ignored.
|
||||||
|
|
42
packet.go
42
packet.go
|
@ -329,3 +329,45 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
|
||||||
b = marshal(b, p.Attrs)
|
b = marshal(b, p.Attrs)
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sshFxpStatvfsPacket struct {
|
||||||
|
Id uint32
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
|
||||||
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
|
len(p.Path) +
|
||||||
|
len("statvfs@openssh.com")
|
||||||
|
|
||||||
|
|
||||||
|
b := make([]byte, 0, l)
|
||||||
|
b = append(b, ssh_FXP_EXTENDED)
|
||||||
|
b = marshalUint32(b, p.Id)
|
||||||
|
b = marshalString(b, "statvfs@openssh.com")
|
||||||
|
b = marshalString(b, p.Path)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatVFS struct {
|
||||||
|
Id uint32
|
||||||
|
Bsize uint64 /* file system block size */
|
||||||
|
Frsize uint64 /* fundamental fs block size */
|
||||||
|
Blocks uint64 /* number of blocks (unit f_frsize) */
|
||||||
|
Bfree uint64 /* free blocks in file system */
|
||||||
|
Bavail uint64 /* free blocks for non-root */
|
||||||
|
Files uint64 /* total file inodes */
|
||||||
|
Ffree uint64 /* free file inodes */
|
||||||
|
Favail uint64 /* free file inodes for to non-root */
|
||||||
|
Fsid uint64 /* file system id */
|
||||||
|
Flag uint64 /* bit mask of f_flag values */
|
||||||
|
Namemax uint64 /* maximum filename length */
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StatVFS) TotalSpace() uint64 {
|
||||||
|
return p.Frsize * p.Blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StatVFS) FreeSpace() uint64 {
|
||||||
|
return p.Frsize * p.Bfree
|
||||||
|
}
|
Loading…
Reference in New Issue