diff --git a/backend/onedrive/onedrive.go b/backend/onedrive/onedrive.go index 1cbe12a06..068928010 100644 --- a/backend/onedrive/onedrive.go +++ b/backend/onedrive/onedrive.go @@ -1065,18 +1065,7 @@ func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) { if o.id == "" { return nil, errors.New("can't download - no id") } - for i := range options { - option := options[i] - if x, ok := option.(*fs.RangeOption); ok { - // Fix RangeOption if requesting a fetch from - // the end as it doesn't work with Onedrive. - // If start is < 0 then fetch from the end - if x.Start < 0 { - x = &fs.RangeOption{Start: o.size - x.End, End: -1} - options[i] = x - } - } - } + fs.FixRangeOption(options, o.size) var resp *http.Response opts := rest.Opts{ Method: "GET", diff --git a/fs/options.go b/fs/options.go index c8fec17e4..da6137318 100644 --- a/fs/options.go +++ b/fs/options.go @@ -62,6 +62,24 @@ func (o *RangeOption) Mandatory() bool { return false } +// FixRangeOption looks through the slice of options and adjusts any +// RangeOption~s found that request a fetch from the end into an +// absolute fetch using the size passed in. Some remotes (eg +// Onedrive, Box) don't support range requests which index from the +// end. +func FixRangeOption(options []OpenOption, size int64) { + for i := range options { + option := options[i] + if x, ok := option.(*RangeOption); ok { + // If start is < 0 then fetch from the end + if x.Start < 0 { + x = &RangeOption{Start: size - x.End, End: -1} + options[i] = x + } + } + } +} + // SeekOption defines an HTTP Range option with start only. type SeekOption struct { Offset int64