A panic while backing up to a SFTP storage

Please describe what you are doing to trigger the bug:

duplicacy backup -stats

Please describe what you expect to happen (but doesn’t):

Not a panic

Please describe what actually happens (the wrong behaviour):

A panic:

Repository set to /path
Storage set to sftp://...
RSA encryption is enabled
Last backup at revision 213 found
Indexing /path
Parsing filter file /path/.duplicacy/filters
Loaded 8 include/exclude pattern(s)
...
Skipped non-regular file ...
...
Skipped chunk 1 size 2328385, 2.22MB/s 00:24:26 0.0%
Skipped chunk 2 size 2008707, 4.14MB/s 00:13:07 0.1%
Encountered an error (failed to send packet: EOF); retry after 1 second(s)
Skipped chunk 4 size 5357339, 9.25MB/s 00:05:52 0.2%
Skipped chunk 5 size 4623303, 13.65MB/s 00:03:58 0.4%
runtime error: invalid memory address or nil pointer dereference
goroutine 23 [running]:
runtime/debug.Stack(0x41, 0x0, 0x0)
	/usr/local/go/src/runtime/debug/stack.go:24 +0x9d
runtime/debug.PrintStack()
	/usr/local/go/src/runtime/debug/stack.go:16 +0x22
github.com/gilbertchen/duplicacy/src.CatchLogException()
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_log.go:183 +0xee
panic(0x49199e0, 0x5284ef0)
	/usr/local/go/src/runtime/panic.go:522 +0x1b5
github.com/gilbertchen/duplicacy/vendor/github.com/pkg/sftp.(*Client).nextID(...)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/vendor/github.com/pkg/sftp/client.go:178
github.com/gilbertchen/duplicacy/vendor/github.com/pkg/sftp.(*Client).Stat(0x0, 0xc01ff4aa80, 0x29, 0x4796085, 0x28, 0x30, 0xc0207cc930)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/vendor/github.com/pkg/sftp/client.go:283 +0x3d
github.com/gilbertchen/duplicacy/src.(*SFTPStorage).UploadFile.func1(0x2, 0x2f39000000000068)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_sftpstorage.go:281 +0x5e
github.com/gilbertchen/duplicacy/src.(*SFTPStorage).retry(0xc000284510, 0xc019ca3cd0, 0xc01ff4aa80, 0x29)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_sftpstorage.go:125 +0x70
github.com/gilbertchen/duplicacy/src.(*SFTPStorage).UploadFile(0xc000284510, 0x0, 0xc020adb0e0, 0x48, 0xc02f040000, 0x1f9228, 0x2fa48b, 0x0, 0x0)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_sftpstorage.go:280 +0x1ba
github.com/gilbertchen/duplicacy/src.(*ChunkUploader).Upload(0xc0000cbc70, 0x0, 0xc02af493e0, 0x3, 0xc00003c301)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_chunkuploader.go:138 +0x246
github.com/gilbertchen/duplicacy/src.(*ChunkUploader).Start.func1(0xc0000cbc70, 0x0)
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_chunkuploader.go:60 +0x83
created by github.com/gilbertchen/duplicacy/src.(*ChunkUploader).Start
	/Users/chgang/zincbox/go/src/github.com/gilbertchen/duplicacy/src/duplicacy_chunkuploader.go:55 +0x48

It seems that the sftp.Client was set to nil during a retry then the followed reconnecting failed causing the getSFTPClient() returns nil thus the panic.

Proposal of change

Since every function wrapped by retry() calls getSFTPClient(), we could ensure the availablity of the client in retry() then do this instead:

err = storage.retry(func(client *sftp.Client) error {
    // or better, make *sftp.Client an interface to increase the testability.
    _, err := client.Stat(fullDir)
    return err
})

Fixed by Fix bugs in sftp retrying · gilbertchen/duplicacy@e888b6d · GitHub