diff --git a/backend/box/box.go b/backend/box/box.go index 1781f0d33..defe8e0eb 100644 --- a/backend/box/box.go +++ b/backend/box/box.go @@ -36,6 +36,7 @@ import ( "github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/configstruct" "github.com/rclone/rclone/fs/config/obscure" + "github.com/rclone/rclone/fs/encodings" "github.com/rclone/rclone/fs/fserrors" "github.com/rclone/rclone/fs/fshttp" "github.com/rclone/rclone/fs/hash" @@ -47,6 +48,8 @@ import ( "golang.org/x/oauth2/jws" ) +const enc = encodings.Box + const ( rcloneClientID = "d0374ba6pgmaguie02ge15sv1mllndho" rcloneEncryptedClientSecret = "sYbJYm99WB8jzeaLPU0OPDMJKIkZvD2qOn3SyEMfiJr03RdtDt3xcZEIudRhbIDL" @@ -298,18 +301,6 @@ func shouldRetry(resp *http.Response, err error) (bool, error) { return authRetry || fserrors.ShouldRetry(err) || fserrors.ShouldRetryHTTP(resp, retryErrorCodes), err } -// substitute reserved characters for box -func replaceReservedChars(x string) string { - // Backslash for FULLWIDTH REVERSE SOLIDUS - return strings.Replace(x, "\\", "\", -1) -} - -// restore reserved characters for box -func restoreReservedChars(x string) string { - // FULLWIDTH REVERSE SOLIDUS for Backslash - return strings.Replace(x, "\", "\\", -1) -} - // readMetaDataForPath reads the metadata from the path func (f *Fs) readMetaDataForPath(ctx context.Context, path string) (info *api.Item, err error) { // defer fs.Trace(f, "path=%q", path)("info=%+v, err=%v", &info, &err) @@ -497,7 +488,7 @@ func (f *Fs) CreateDir(ctx context.Context, pathID, leaf string) (newID string, Parameters: fieldsValue(), } mkdir := api.CreateFolder{ - Name: replaceReservedChars(leaf), + Name: enc.FromStandardName(leaf), Parent: api.Parent{ ID: pathID, }, @@ -563,7 +554,7 @@ OUTER: if item.ItemStatus != api.ItemStatusActive { continue } - item.Name = restoreReservedChars(item.Name) + item.Name = enc.ToStandardName(item.Name) if fn(item) { found = true break OUTER @@ -799,9 +790,8 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, Path: "/files/" + srcObj.id + "/copy", Parameters: fieldsValue(), } - replacedLeaf := replaceReservedChars(leaf) copyFile := api.CopyFile{ - Name: replacedLeaf, + Name: enc.FromStandardName(leaf), Parent: api.Parent{ ID: directoryID, }, @@ -840,7 +830,7 @@ func (f *Fs) move(ctx context.Context, endpoint, id, leaf, directoryID string) ( Parameters: fieldsValue(), } move := api.UpdateFileMove{ - Name: replaceReservedChars(leaf), + Name: enc.FromStandardName(leaf), Parent: api.Parent{ ID: directoryID, }, @@ -1041,11 +1031,6 @@ func (o *Object) Remote() string { return o.remote } -// srvPath returns a path for use in server -func (o *Object) srvPath() string { - return replaceReservedChars(o.fs.rootSlash() + o.remote) -} - // Hash returns the SHA-1 of an object returning a lowercase hex string func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) { if t != hash.SHA1 { @@ -1170,7 +1155,7 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read // This is recommended for less than 50 MB of content func (o *Object) upload(ctx context.Context, in io.Reader, leaf, directoryID string, modTime time.Time) (err error) { upload := api.UploadFile{ - Name: replaceReservedChars(leaf), + Name: enc.FromStandardName(leaf), ContentModifiedAt: api.Time(modTime), ContentCreatedAt: api.Time(modTime), Parent: api.Parent{ diff --git a/backend/box/upload.go b/backend/box/upload.go index d413a8483..e853f8f35 100644 --- a/backend/box/upload.go +++ b/backend/box/upload.go @@ -38,7 +38,7 @@ func (o *Object) createUploadSession(ctx context.Context, leaf, directoryID stri } else { opts.Path = "/files/upload_sessions" request.FolderID = directoryID - request.FileName = replaceReservedChars(leaf) + request.FileName = enc.FromStandardName(leaf) } var resp *http.Response err = o.fs.pacer.Call(func() (bool, error) { diff --git a/docs/content/box.md b/docs/content/box.md index cf13a5479..768b20df3 100644 --- a/docs/content/box.md +++ b/docs/content/box.md @@ -196,6 +196,25 @@ not. Box supports SHA1 type hashes, so you can use the `--checksum` flag. +#### Restricted filename characters + +In addition to the [default restricted characters set](/overview/#restricted-characters) +the following characters are also replaced: + +| Character | Value | Replacement | +| --------- |:-----:|:-----------:| +| \ | 0x5C | \ | + +File names can also not end with the following characters. +These only get replaced if they are last character in the name: + +| Character | Value | Replacement | +| --------- |:-----:|:-----------:| +| SP | 0x20 | ␠ | + +Invalid UTF-8 bytes will also be [replaced](/overview/#invalid-utf8), +as they can't be used in JSON strings. + ### Transfers ### For files above 50MB rclone will use a chunked transfer. Rclone will