@@ -51,6 +51,30 @@ func MaxPacketChecked(size int) ClientOption {
51
51
}
52
52
}
53
53
54
+ // UseFstat sets whether to use Fstat or Stat when File.WriteTo is called
55
+ // (usually when copying files).
56
+ // Some servers limit the amount of open files and calling Stat after opening
57
+ // the file will throw an error From the server. Setting this flag will call
58
+ // Fstat instead of Stat which is suppose to be called on an open file handle.
59
+ //
60
+ // It has been found that that with IBM Sterling SFTP servers which have
61
+ // "extractability" level set to 1 which means only 1 file can be opened at
62
+ // any given time.
63
+ //
64
+ // If the server you are working with still has an issue with both Stat and
65
+ // Fstat calls you can always open a file and read it until the end.
66
+ //
67
+ // Another reason to read the file until its end and Fstat doesn't work is
68
+ // that in some servers, reading a full file will automatically delete the
69
+ // file as some of these mainframes map the file to a message in a queue.
70
+ // Once the file has been read it will get deleted.
71
+ func UseFstat (value bool ) ClientOption {
72
+ return func (c * Client ) error {
73
+ c .useFstat = value
74
+ return nil
75
+ }
76
+ }
77
+
54
78
// MaxPacketUnchecked sets the maximum size of the payload, measured in bytes.
55
79
// It accepts sizes larger than the 32768 bytes all servers should support.
56
80
// Only use a setting higher than 32768 if your application always connects to
@@ -161,6 +185,7 @@ type Client struct {
161
185
maxPacket int // max packet size read or written.
162
186
nextid uint32
163
187
maxConcurrentRequests int
188
+ useFstat bool
164
189
}
165
190
166
191
// 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) {
913
938
// maximise throughput for transferring the entire file (especially
914
939
// over high latency links).
915
940
func (f * File ) WriteTo (w io.Writer ) (int64 , error ) {
916
- fi , err := f .c .Stat (f .path )
917
- if err != nil {
918
- return 0 , err
941
+ var fileSize uint64
942
+ if f .c .useFstat {
943
+ fileStat , err := f .c .fstat (f .handle )
944
+ if err != nil {
945
+ return 0 , err
946
+ }
947
+ fileSize = fileStat .Size
948
+
949
+ } else {
950
+ fi , err := f .c .Stat (f .path )
951
+ if err != nil {
952
+ return 0 , err
953
+ }
954
+ fileSize = uint64 (fi .Size ())
919
955
}
956
+
920
957
inFlight := 0
921
958
desiredInFlight := 1
922
959
offset := f .offset
923
960
writeOffset := offset
924
- fileSize := uint64 (fi .Size ())
925
961
// see comment on same line in Read() above
926
962
ch := make (chan result , f .c .maxConcurrentRequests + 1 )
927
963
type inflightRead struct {
0 commit comments