Unverified Commit 56161820 authored by John Eikenberry's avatar John Eikenberry Committed by GitHub

Merge pull request #332 from peachfinance/Fstat-stat-options

Added a ClientOption to determine whetehr to use Fstat or Stat when File.WriteTo is being called to support strange behaviour on some servers
parents a5f5a4cb 77a4076c
......@@ -51,6 +51,30 @@ func MaxPacketChecked(size int) ClientOption {
// UseFstat sets whether to use Fstat or Stat when File.WriteTo is called
// (usually when copying files).
// Some servers limit the amount of open files and calling Stat after opening
// the file will throw an error From the server. Setting this flag will call
// Fstat instead of Stat which is suppose to be called on an open file handle.
// It has been found that that with IBM Sterling SFTP servers which have
// "extractability" level set to 1 which means only 1 file can be opened at
// any given time.
// If the server you are working with still has an issue with both Stat and
// Fstat calls you can always open a file and read it until the end.
// Another reason to read the file until its end and Fstat doesn't work is
// that in some servers, reading a full file will automatically delete the
// file as some of these mainframes map the file to a message in a queue.
// Once the file has been read it will get deleted.
func UseFstat(value bool) ClientOption {
return func(c *Client) error {
c.useFstat = value
return nil
// MaxPacketUnchecked sets the maximum size of the payload, measured in bytes.
// It accepts sizes larger than the 32768 bytes all servers should support.
// Only use a setting higher than 32768 if your application always connects to
......@@ -161,6 +185,7 @@ type Client struct {
maxPacket int // max packet size read or written.
nextid uint32
maxConcurrentRequests int
useFstat bool
// Create creates the named file mode 0666 (before umask), truncating it if it
......@@ -913,15 +938,26 @@ func (f *File) Read(b []byte) (int, error) {
// maximise throughput for transferring the entire file (especially
// over high latency links).
func (f *File) WriteTo(w io.Writer) (int64, error) {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
var fileSize uint64
if f.c.useFstat {
fileStat, err := f.c.fstat(f.handle)
if err != nil {
return 0, err
fileSize = fileStat.Size
} else {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
fileSize = uint64(fi.Size())
inFlight := 0
desiredInFlight := 1
offset := f.offset
writeOffset := offset
fileSize := uint64(fi.Size())
// see comment on same line in Read() above
ch := make(chan result, f.c.maxConcurrentRequests+1)
type inflightRead struct {
......@@ -194,3 +194,17 @@ func testMaxPacketOption(t *testing.T, o ClientOption, tt packetSizeTest) {
t.Errorf("MaxPacketChecked(%v)\n- want: %v\n- got: %v", tt.size, tt.size, c.maxPacket)
func testFstatOption(t *testing.T, o ClientOption, value bool) {
var c Client
err := o(&c)
if err == nil && c.useFstat != value {
t.Errorf("UseFStat(%v)\n- want: %v\n- got: %v", value, value, c.useFstat)
func TestUseFstatChecked(t *testing.T) {
testFstatOption(t, UseFstat(true), true)
testFstatOption(t, UseFstat(false), false)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment