diff --git a/backend/pcloud/pcloud.go b/backend/pcloud/pcloud.go index 9761bfe66..2d2abab53 100644 --- a/backend/pcloud/pcloud.go +++ b/backend/pcloud/pcloud.go @@ -26,6 +26,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/hash" "github.com/rclone/rclone/lib/dircache" @@ -35,6 +36,8 @@ import ( "golang.org/x/oauth2" ) +const enc = encodings.Pcloud + const ( rcloneClientID = "DnONSzyJXpm" rcloneEncryptedClientSecret = "ej1OIF39VOQQ0PXaSdK9ztkLw3tdLNscW2157TKNQdQKkICR4uU7aFg4eFM" @@ -175,21 +178,6 @@ func shouldRetry(resp *http.Response, err error) (bool, error) { return doRetry || fserrors.ShouldRetry(err) || fserrors.ShouldRetryHTTP(resp, retryErrorCodes), err } -// substitute reserved characters for pcloud -// -// Generally all characters are allowed in filenames, except the NULL -// byte, forward and backslash (/,\ and \0) -func replaceReservedChars(x string) string { - // Backslash for FULLWIDTH REVERSE SOLIDUS - return strings.Replace(x, "\\", "\", -1) -} - -// restore reserved characters for pcloud -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) @@ -354,7 +342,7 @@ func (f *Fs) CreateDir(ctx context.Context, pathID, leaf string) (newID string, Path: "/createfolder", Parameters: url.Values{}, } - opts.Parameters.Set("name", replaceReservedChars(leaf)) + opts.Parameters.Set("name", enc.FromStandardName(leaf)) opts.Parameters.Set("folderid", dirIDtoNumber(pathID)) err = f.pacer.Call(func() (bool, error) { resp, err = f.srv.CallJSON(ctx, &opts, nil, &result) @@ -430,7 +418,7 @@ func (f *Fs) listAll(ctx context.Context, dirID string, directoriesOnly bool, fi continue } } - item.Name = restoreReservedChars(item.Name) + item.Name = enc.ToStandardName(item.Name) if fn(item) { found = true break @@ -622,7 +610,7 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, Parameters: url.Values{}, } opts.Parameters.Set("fileid", fileIDtoNumber(srcObj.id)) - opts.Parameters.Set("toname", replaceReservedChars(leaf)) + opts.Parameters.Set("toname", enc.FromStandardName(leaf)) opts.Parameters.Set("tofolderid", dirIDtoNumber(directoryID)) opts.Parameters.Set("mtime", fmt.Sprintf("%d", srcObj.modTime.Unix())) var resp *http.Response @@ -701,7 +689,7 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, Parameters: url.Values{}, } opts.Parameters.Set("fileid", fileIDtoNumber(srcObj.id)) - opts.Parameters.Set("toname", replaceReservedChars(leaf)) + opts.Parameters.Set("toname", enc.FromStandardName(leaf)) opts.Parameters.Set("tofolderid", dirIDtoNumber(directoryID)) var resp *http.Response var result api.ItemResult @@ -798,7 +786,7 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string Parameters: url.Values{}, } opts.Parameters.Set("folderid", dirIDtoNumber(srcID)) - opts.Parameters.Set("toname", replaceReservedChars(leaf)) + opts.Parameters.Set("toname", enc.FromStandardName(leaf)) opts.Parameters.Set("tofolderid", dirIDtoNumber(directoryID)) var resp *http.Response var result api.ItemResult @@ -1078,7 +1066,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op Parameters: url.Values{}, TransferEncoding: []string{"identity"}, // pcloud doesn't like chunked encoding } - leaf = replaceReservedChars(leaf) + leaf = enc.FromStandardName(leaf) opts.Parameters.Set("filename", leaf) opts.Parameters.Set("folderid", dirIDtoNumber(directoryID)) opts.Parameters.Set("nopartial", "1") diff --git a/docs/content/pcloud.md b/docs/content/pcloud.md index 47c206adf..1af400b38 100644 --- a/docs/content/pcloud.md +++ b/docs/content/pcloud.md @@ -94,6 +94,18 @@ be re-uploaded. pCloud supports MD5 and 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 | \ | + +Invalid UTF-8 bytes will also be [replaced](/overview/#invalid-utf8), +as they can't be used in JSON strings. + ### Deleting files ### Deleted files will be moved to the trash. Your subscription level diff --git a/fs/encodings/encodings.go b/fs/encodings/encodings.go index 2432c2c1f..2603a29d6 100644 --- a/fs/encodings/encodings.go +++ b/fs/encodings/encodings.go @@ -218,7 +218,8 @@ const OpenDrive = encoder.MultiEncoder( // // TODO: Investigate Unicode simplification (\ gets converted to \ server-side) const Pcloud = encoder.MultiEncoder( - uint(Base) | + uint(Display) | + encoder.EncodeBackSlash | encoder.EncodeInvalidUtf8) // ByName returns the encoder for a give backend name or nil