hidrive: fix truncated file left behind when an upload hits --max-transfer
When an upload was stopped part way through by --max-transfer, HiDrive
kept the part of the file it had received, leaving a truncated file at
the destination, or replacing an existing file with a truncated one.
This was introduced in e8f421d28 which accounted the buffered start of
each upload as it was sent rather than as it was read, so the transfer
limit could abort the request which creates the file half way through.
Account the requests which create or replace a file in one go as they
are buffered once more, so the limit is hit before anything is sent.
The chunks of larger uploads are still accounted as they are sent.
This commit is contained in:
1 parent
f217c8a2aa
commit
9f0b40c7d2
2 files changed
+18
-9
No files matched your search
@@ -642,7 +642,7 @@ func (f *Fs) updateFileChunked(ctx context.Context, path string, content io.Read
|
||||
chunkReader *pool.RW
|
||||
bytesRead int64
|
||||
)
|
||||
chunkReader, bytesRead, readErr = readerForChunk(content, int64(chunkSize))
|
||||
chunkReader, bytesRead, readErr = readerForChunk(content, int64(chunkSize), true)
|
||||
if bytesRead < int64(chunkSize) {
|
||||
startMoreTransfers = false
|
||||
}
|
||||
@@ -869,14 +869,23 @@ func unwrapAccounting(reader io.Reader) (unwrapped io.Reader, acc *accounting.Ac
|
||||
// along with the number of bytes that have been read from reader.
|
||||
// Reaching the end of reader early is not an error.
|
||||
//
|
||||
// Any accounting on reader is applied when the buffer is read instead,
|
||||
// so the upload is what gets accounted.
|
||||
// If accountUpload is set, any accounting on reader is applied
|
||||
// when the buffer is read instead, so the upload is what gets accounted.
|
||||
//
|
||||
// This must not be set for a buffer which creates or replaces a file
|
||||
// in a single request. Accounting can fail part way through the upload,
|
||||
// for example when --max-transfer is reached, and HiDrive keeps
|
||||
// what it has received of an aborted request as the file.
|
||||
//
|
||||
// The caller must Close the buffer when done with it.
|
||||
func readerForChunk(reader io.Reader, length int64) (chunkReader *pool.RW, bytesRead int64, err error) {
|
||||
reader, acc := unwrapAccounting(reader)
|
||||
func readerForChunk(reader io.Reader, length int64, accountUpload bool) (chunkReader *pool.RW, bytesRead int64, err error) {
|
||||
chunkReader = multipart.NewRW()
|
||||
if acc != nil {
|
||||
chunkReader.SetAccounting(acc.AccountRead)
|
||||
if accountUpload {
|
||||
var acc *accounting.Account
|
||||
reader, acc = unwrapAccounting(reader)
|
||||
if acc != nil {
|
||||
chunkReader.SetAccounting(acc.AccountRead)
|
||||
}
|
||||
}
|
||||
|
||||
bytesRead, err = io.CopyN(chunkReader, reader, length)
|
||||
|
||||
@@ -522,7 +522,7 @@ func (f *Fs) PutUnchecked(ctx context.Context, in io.Reader, src fs.ObjectInfo,
|
||||
if size := src.Size(); size >= 0 && size < prefixSize {
|
||||
prefixSize = size
|
||||
}
|
||||
cutoffReader, bytesRead, err := readerForChunk(in, prefixSize)
|
||||
cutoffReader, bytesRead, err := readerForChunk(in, prefixSize, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -980,7 +980,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
info, metaErr = o.fs.fetchMetadataForPath(ctx, resolvedPath, api.HiDriveObjectWithMetadataFields)
|
||||
} else {
|
||||
var content *pool.RW
|
||||
content, _, err = readerForChunk(in, src.Size())
|
||||
content, _, err = readerForChunk(in, src.Size(), false)
|
||||
if err == nil {
|
||||
info, err = o.fs.overwriteFile(ctx, resolvedPath, content, modTime)
|
||||
_ = content.Close()
|
||||
|
||||
Reference in new issue
Block a user