smb: fix "unverified packet returned" error when using multithread copy

Before this change, in the WriterAt method we removed the session
while the WriterAt handle was still open.

This meant that in long lived multithread copies the session was
closed which caused the "unverified packet returned" errors.

This fixes the problem by wrapping it in a custom Close to close
remove the session only when the WriterAt handle is closed.

See: https://forum.rclone.org/t/problems-copying-big-files-from-local-to-remote-using-rclone-rc/42169/
This commit is contained in:
Nick Craig-Wood 2023-10-09 11:22:09 +01:00
parent a752563842
commit 0731de6a51
1 changed files with 31 additions and 1 deletions

View File

@ -12,6 +12,7 @@ import (
"sync/atomic"
"time"
smb2 "github.com/hirochachacha/go-smb2"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config"
"github.com/rclone/rclone/fs/config/configmap"
@ -476,6 +477,26 @@ func (f *Fs) About(ctx context.Context) (_ *fs.Usage, err error) {
return usage, nil
}
// Wrap a smb2.File with a custom Close method
type closeSession struct {
*smb2.File
close func() error
closed bool
}
// Close the handle and call the custom code
func (c *closeSession) Close() error {
err := c.File.Close()
if !c.closed {
err2 := c.close()
if err == nil {
err = err2
}
c.closed = true
}
return err
}
// OpenWriterAt opens with a handle for random access writes
//
// Pass in the remote desired and the size if known.
@ -509,10 +530,19 @@ func (f *Fs) OpenWriterAt(ctx context.Context, remote string, size int64) (fs.Wr
fl, err := cn.smbShare.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil {
o.fs.putConnection(&cn)
return nil, fmt.Errorf("failed to open: %w", err)
}
return fl, nil
// Connection is returned in the closeSession.Close method
c := &closeSession{
File: fl,
close: func() error {
o.fs.putConnection(&cn)
return nil
},
}
return c, nil
}
// Shutdown the backend, closing any background tasks and any