From ba7c2ac443233ec4b73eed1054bd68c59eb3d8dd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2019 08:47:17 +0100 Subject: [PATCH] drive: make sure that drive root ID is always canonical Before this change we used the id "root" as an alias for the root drive ID. However this causes problems when we receive IDs back from drive which are not in this format and have been expanded to their canonical ID. This change looks up the ID "root" and stores it in the "drive_folder_id" parameter in the config file. This helps with - Notifying changes at the root - Files shared with me at the root See #3639 --- backend/drive/drive.go | 57 ++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/backend/drive/drive.go b/backend/drive/drive.go index 018fef2b9..a933e124e 100644 --- a/backend/drive/drive.go +++ b/backend/drive/drive.go @@ -214,7 +214,15 @@ func init() { }}, }, { Name: "root_folder_id", - Help: "ID of the root folder\nLeave blank normally.\nFill in to access \"Computers\" folders. (see docs).", + Help: `ID of the root folder +Leave blank normally. + +Fill in to access "Computers" folders (see docs), or for rclone to use +a non root folder as its starting point. + +Note that if this is blank, the first time rclone runs it will fill it +in with the ID of the root folder. +`, }, { Name: "service_account_file", Help: "Service Account Credentials JSON file path \nLeave blank normally.\nNeeded only if you want use SA instead of interactive login.", @@ -581,6 +589,23 @@ func containsString(slice []string, s string) bool { return false } +// getRootID returns the canonical ID for the "root" ID +func (f *Fs) getRootID() (string, error) { + var info *drive.File + var err error + err = f.pacer.CallNoRetry(func() (bool, error) { + info, err = f.svc.Files.Get("root"). + Fields("id"). + SupportsAllDrives(true). + Do() + return shouldRetry(err) + }) + if err != nil { + return "", errors.Wrap(err, "couldn't find root directory ID") + } + return info.Id, nil +} + // Lists the directory required calling the user function on each item found // // If the user fn ever returns true then it early exits with found = true @@ -998,13 +1023,17 @@ func NewFs(name, path string, m configmap.Mapper) (fs.Fs, error) { // set root folder for a team drive or query the user root folder if f.isTeamDrive { f.rootFolderID = f.opt.TeamDriveID - } else { - f.rootFolderID = "root" - } - - // override root folder if set in the config - if opt.RootFolderID != "" { + } else if opt.RootFolderID != "" { + // override root folder if set or cached in the config f.rootFolderID = opt.RootFolderID + } else { + // Look up the root ID and cache it in the config + rootID, err := f.getRootID() + if err != nil { + return nil, err + } + f.rootFolderID = rootID + m.Set("root_folder_id", rootID) } f.dirCache = dircache.New(root, f.rootFolderID, f) @@ -1554,20 +1583,6 @@ func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) ( if err != nil { return err } - if directoryID == "root" { - var info *drive.File - err = f.pacer.CallNoRetry(func() (bool, error) { - info, err = f.svc.Files.Get("root"). - Fields("id"). - SupportsAllDrives(true). - Do() - return shouldRetry(err) - }) - if err != nil { - return err - } - directoryID = info.Id - } mu := sync.Mutex{} // protects in and overflow wg := sync.WaitGroup{}