atomic upload mode: remove temporary file on error

If a transfer error is detected, then the partial temporary file will
be removed and not renamed to requested path
This commit is contained in:
Nicola Murino
2019-09-10 18:47:21 +02:00
parent 7010f513e3
commit c1effdf701
5 changed files with 107 additions and 18 deletions

View File

@@ -40,8 +40,9 @@ type Transfer struct {
// For example network or client issues
func (t *Transfer) TransferError(err error) {
t.transferError = err
elapsed := time.Since(t.start).Nanoseconds() / 1000000
logger.Warn(logSender, t.connectionID, "Unexpected error for transfer, path: %#v, error: \"%v\" bytes sent: %v, "+
"bytes received: %v", t.path, t.transferError, t.bytesSent, t.bytesReceived)
"bytes received: %v transfer running since %v ms", t.path, t.transferError, t.bytesSent, t.bytesReceived, elapsed)
}
// ReadAt reads len(p) bytes from the File to download starting at byte offset off and updates the bytes sent.
@@ -65,19 +66,37 @@ func (t *Transfer) WriteAt(p []byte, off int64) (n int, err error) {
}
// Close it is called when the transfer is completed.
// It closes the underlying file, log the transfer info, update the user quota, for uploads, and execute any defined actions.
// It closes the underlying file, log the transfer info, update the user quota (for uploads)
// and execute any defined actions.
// If there is an error no action will be executed and, in atomic mode, we try to delete
// the temporary file
func (t *Transfer) Close() error {
err := t.file.Close()
if t.isFinished {
return err
}
if t.transferType == transferUpload && t.file.Name() != t.path {
err = os.Rename(t.file.Name(), t.path)
logger.Debug(logSender, t.connectionID, "atomic upload completed, rename: %#v -> %#v, error: %v",
t.file.Name(), t.path, err)
t.isFinished = true
numFiles := 0
if t.isNewFile {
numFiles = 1
}
if t.transferType == transferUpload && t.file.Name() != t.path {
if t.transferError == nil {
err = os.Rename(t.file.Name(), t.path)
logger.Debug(logSender, t.connectionID, "atomic upload completed, rename: %#v -> %#v, error: %v",
t.file.Name(), t.path, err)
} else {
err = os.Remove(t.file.Name())
logger.Warn(logSender, t.connectionID, "atomic upload completed with error: \"%v\", delete temporary file: %#v, "+
"deletion error: %v", t.transferError, t.file.Name(), err)
if err == nil {
numFiles--
t.bytesReceived = 0
}
}
}
elapsed := time.Since(t.start).Nanoseconds() / 1000000
if t.transferError == nil {
elapsed := time.Since(t.start).Nanoseconds() / 1000000
if t.transferType == transferDownload {
logger.TransferLog(downloadLogSender, t.path, elapsed, t.bytesSent, t.user.Username, t.connectionID, t.protocol)
executeAction(operationDownload, t.user.Username, t.path, "")
@@ -87,14 +106,9 @@ func (t *Transfer) Close() error {
}
}
removeTransfer(t)
if t.transferType == transferUpload {
numFiles := 0
if t.isNewFile {
numFiles = 1
}
if t.transferType == transferUpload && (numFiles != 0 || t.bytesReceived > 0) {
dataprovider.UpdateUserQuota(dataProvider, t.user, numFiles, t.bytesReceived, false)
}
t.isFinished = true
return err
}