From 4e4feebf0a25cf5fefd2fa01698e593851708135 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 31 Jan 2019 10:39:13 +0000 Subject: [PATCH] drive: fix google docs in rclone mount in some circumstances #1732 Before this change any attempt to access a google doc in an rclone mount would give the error "partial downloads are not supported while exporting Google Documents" as the mount uses ranged requests to read data. This implements ranged requests for a limited number of scenarios, just enough so that Google docs can be cat-ed from an rclone mount. When they are cat-ed then they receive their correct size also. --- backend/drive/drive.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/backend/drive/drive.go b/backend/drive/drive.go index 243adb067..be7279194 100644 --- a/backend/drive/drive.go +++ b/backend/drive/drive.go @@ -39,6 +39,7 @@ import ( "github.com/ncw/rclone/lib/dircache" "github.com/ncw/rclone/lib/oauthutil" "github.com/ncw/rclone/lib/pacer" + "github.com/ncw/rclone/lib/readers" "github.com/pkg/errors" "golang.org/x/oauth2" "golang.org/x/oauth2/google" @@ -2494,16 +2495,32 @@ func (o *documentObject) Open(options ...fs.OpenOption) (in io.ReadCloser, err e // Update the size with what we are reading as it can change from // the HEAD in the listing to this GET. This stops rclone marking // the transfer as corrupted. + var offset, end int64 = 0, -1 + var newOptions = options[:0] for _, o := range options { + // Note that Range requests don't work on Google docs: // https://developers.google.com/drive/v3/web/manage-downloads#partial_download - if _, ok := o.(*fs.RangeOption); ok { - return nil, errors.New("partial downloads are not supported while exporting Google Documents") + // So do a subset of them manually + switch x := o.(type) { + case *fs.RangeOption: + offset, end = x.Start, x.End + case *fs.SeekOption: + offset, end = x.Offset, -1 + default: + newOptions = append(newOptions, o) } } + options = newOptions + if offset != 0 { + return nil, errors.New("partial downloads are not supported while exporting Google Documents") + } in, err = o.baseObject.open(o.url, options...) if in != nil { in = &openDocumentFile{o: o, in: in} } + if end >= 0 { + in = readers.NewLimitedReadCloser(in, end-offset+1) + } return } func (o *linkObject) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {