mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 02:14:42 +01:00
onedrive: fix upload of zero length files #1716
Unfortunately multi part upload can't upload zero length files so bring back the single part upload for zero length files only. This was broken when we made all uploads multipart uploads.
This commit is contained in:
parent
a9e386b153
commit
d4cca8d9f9
@ -1112,7 +1112,7 @@ func (o *Object) createUploadSession(modTime time.Time) (response *api.CreateUpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uploadFragment uploads a part
|
// uploadFragment uploads a part
|
||||||
func (o *Object) uploadFragment(url string, start int64, totalSize int64, chunk io.ReadSeeker, chunkSize int64, info *api.Item) (err error) {
|
func (o *Object) uploadFragment(url string, start int64, totalSize int64, chunk io.ReadSeeker, chunkSize int64) (info *api.Item, err error) {
|
||||||
opts := rest.Opts{
|
opts := rest.Opts{
|
||||||
Method: "PUT",
|
Method: "PUT",
|
||||||
RootURL: url,
|
RootURL: url,
|
||||||
@ -1131,12 +1131,13 @@ func (o *Object) uploadFragment(url string, start int64, totalSize int64, chunk
|
|||||||
// we are done :)
|
// we are done :)
|
||||||
// read the item
|
// read the item
|
||||||
defer fs.CheckClose(resp.Body, &err)
|
defer fs.CheckClose(resp.Body, &err)
|
||||||
|
info = &api.Item{}
|
||||||
return false, json.NewDecoder(resp.Body).Decode(info)
|
return false, json.NewDecoder(resp.Body).Decode(info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retry, err
|
return retry, err
|
||||||
})
|
})
|
||||||
return err
|
return info, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancelUploadSession cancels an upload session
|
// cancelUploadSession cancels an upload session
|
||||||
@ -1155,16 +1156,16 @@ func (o *Object) cancelUploadSession(url string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uploadMultipart uploads a file using multipart upload
|
// uploadMultipart uploads a file using multipart upload
|
||||||
func (o *Object) uploadMultipart(in io.Reader, size int64, modTime time.Time, info *api.Item) (err error) {
|
func (o *Object) uploadMultipart(in io.Reader, size int64, modTime time.Time) (info *api.Item, err error) {
|
||||||
if chunkSize%(320*1024) != 0 {
|
if chunkSize%(320*1024) != 0 {
|
||||||
return errors.Errorf("chunk size %d is not a multiple of 320k", chunkSize)
|
return nil, errors.Errorf("chunk size %d is not a multiple of 320k", chunkSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create upload session
|
// Create upload session
|
||||||
fs.Debugf(o, "Starting multipart upload")
|
fs.Debugf(o, "Starting multipart upload")
|
||||||
session, err := o.createUploadSession(modTime)
|
session, err := o.createUploadSession(modTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
uploadURL := session.UploadURL
|
uploadURL := session.UploadURL
|
||||||
|
|
||||||
@ -1189,15 +1190,44 @@ func (o *Object) uploadMultipart(in io.Reader, size int64, modTime time.Time, in
|
|||||||
}
|
}
|
||||||
seg := readers.NewRepeatableReader(io.LimitReader(in, n))
|
seg := readers.NewRepeatableReader(io.LimitReader(in, n))
|
||||||
fs.Debugf(o, "Uploading segment %d/%d size %d", position, size, n)
|
fs.Debugf(o, "Uploading segment %d/%d size %d", position, size, n)
|
||||||
err = o.uploadFragment(uploadURL, position, size, seg, n, info)
|
info, err = o.uploadFragment(uploadURL, position, size, seg, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
remaining -= n
|
remaining -= n
|
||||||
position += n
|
position += n
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// uploadSinglepart uploads a file as a single part
|
||||||
|
func (o *Object) uploadSinglepart(in io.Reader, size int64, modTime time.Time) (info *api.Item, err error) {
|
||||||
|
var resp *http.Response
|
||||||
|
opts := rest.Opts{
|
||||||
|
Method: "PUT",
|
||||||
|
Path: "/root:/" + rest.URLPathEscape(o.srvPath()) + ":/content",
|
||||||
|
ContentLength: &size,
|
||||||
|
Body: in,
|
||||||
|
}
|
||||||
|
// for go1.8 (see release notes) we must nil the Body if we want a
|
||||||
|
// "Content-Length: 0" header which onedrive requires for all files.
|
||||||
|
if size == 0 {
|
||||||
|
opts.Body = nil
|
||||||
|
}
|
||||||
|
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
|
||||||
|
resp, err = o.fs.srv.CallJSON(&opts, nil, &info)
|
||||||
|
return shouldRetry(resp, err)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = o.setMetaData(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Set the mod time now and read metadata
|
||||||
|
return o.setModTime(modTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the object with the contents of the io.Reader, modTime and size
|
// Update the object with the contents of the io.Reader, modTime and size
|
||||||
@ -1210,8 +1240,13 @@ func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOptio
|
|||||||
size := src.Size()
|
size := src.Size()
|
||||||
modTime := src.ModTime()
|
modTime := src.ModTime()
|
||||||
|
|
||||||
info := &api.Item{}
|
var info *api.Item
|
||||||
err = o.uploadMultipart(in, size, modTime, info)
|
if size <= 0 {
|
||||||
|
// This is for 0 length files, or files with an unknown size
|
||||||
|
info, err = o.uploadSinglepart(in, size, modTime)
|
||||||
|
} else {
|
||||||
|
info, err = o.uploadMultipart(in, size, modTime)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user