mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 06:40:54 +03:00
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:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user