@@ -51,6 +51,23 @@ 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 (usually when copying files).
55
+ // Some servers limit the amount of open files and calling Stat after opening the file will throw an error
56
+ // From the server. Setting this flag will call Fstat instead of Stat which is suppose to be called on an
57
+ // open file handle.
58
+ //
59
+ // From our experience it happens often with IBM Sterling SFTP servers that have "extractability" level
60
+ // set to 1 which means only 1 file can be open at any given time.
61
+ //
62
+ // If the server you are working with still has an issue with both Stat and Fstat calls you can always
63
+ // open a file and just loop through multiple Read calls until the file is completely read.
64
+ func UseFstat (value bool ) ClientOption {
65
+ return func (c * Client ) error {
66
+ c .useFstat = value
67
+ return nil
68
+ }
69
+ }
70
+
54
71
// MaxPacketUnchecked sets the maximum size of the payload, measured in bytes.
55
72
// It accepts sizes larger than the 32768 bytes all servers should support.
56
73
// Only use a setting higher than 32768 if your application always connects to
@@ -161,6 +178,7 @@ type Client struct {
161
178
maxPacket int // max packet size read or written.
162
179
nextid uint32
163
180
maxConcurrentRequests int
181
+ useFstat bool
164
182
}
165
183
166
184
// Create creates the named file mode 0666 (before umask), truncating it if it
@@ -913,15 +931,27 @@ func (f *File) Read(b []byte) (int, error) {
913
931
// maximise throughput for transferring the entire file (especially
914
932
// over high latency links).
915
933
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
934
+ var err error
935
+ fileSize := uint64 (0 )
936
+ if f .c .useFstat {
937
+ var fileStat * FileStat
938
+ if fileStat , err = f .c .fstat (f .handle ); err != nil {
939
+ return 0 , err
940
+ }
941
+ fileSize = uint64 (fileStat .Size )
942
+
943
+ } else {
944
+ var fi os.FileInfo
945
+ if fi , err = f .c .Stat (f .path ); err != nil {
946
+ return 0 , err
947
+ }
948
+ fileSize = uint64 (fi .Size ())
919
949
}
950
+
920
951
inFlight := 0
921
952
desiredInFlight := 1
922
953
offset := f .offset
923
954
writeOffset := offset
924
- fileSize := uint64 (fi .Size ())
925
955
// see comment on same line in Read() above
926
956
ch := make (chan result , f .c .maxConcurrentRequests + 1 )
927
957
type inflightRead struct {
0 commit comments