mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
ficher: use lib/encoder
This commit is contained in:
parent
4098907511
commit
8d8fad724b
@ -107,6 +107,10 @@ func (f *Fs) listFiles(ctx context.Context, directoryID int) (filesList *FilesLi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "couldn't list files")
|
return nil, errors.Wrap(err, "couldn't list files")
|
||||||
}
|
}
|
||||||
|
for i := range filesList.Items {
|
||||||
|
item := &filesList.Items[i]
|
||||||
|
item.Filename = enc.ToStandardName(item.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
return filesList, nil
|
return filesList, nil
|
||||||
}
|
}
|
||||||
@ -131,6 +135,11 @@ func (f *Fs) listFolders(ctx context.Context, directoryID int) (foldersList *Fol
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "couldn't list folders")
|
return nil, errors.Wrap(err, "couldn't list folders")
|
||||||
}
|
}
|
||||||
|
foldersList.Name = enc.ToStandardName(foldersList.Name)
|
||||||
|
for i := range foldersList.SubFolders {
|
||||||
|
folder := &foldersList.SubFolders[i]
|
||||||
|
folder.Name = enc.ToStandardName(folder.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// fs.Debugf(f, "Got FoldersList for id `%s`", directoryID)
|
// fs.Debugf(f, "Got FoldersList for id `%s`", directoryID)
|
||||||
|
|
||||||
@ -166,7 +175,6 @@ func (f *Fs) listDir(ctx context.Context, dir string) (entries fs.DirEntries, er
|
|||||||
entries = make([]fs.DirEntry, len(files.Items)+len(folders.SubFolders))
|
entries = make([]fs.DirEntry, len(files.Items)+len(folders.SubFolders))
|
||||||
|
|
||||||
for i, item := range files.Items {
|
for i, item := range files.Items {
|
||||||
item.Filename = restoreReservedChars(item.Filename)
|
|
||||||
entries[i] = f.newObjectFromFile(ctx, dir, item)
|
entries[i] = f.newObjectFromFile(ctx, dir, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +184,6 @@ func (f *Fs) listDir(ctx context.Context, dir string) (entries fs.DirEntries, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
folder.Name = restoreReservedChars(folder.Name)
|
|
||||||
fullPath := getRemote(dir, folder.Name)
|
fullPath := getRemote(dir, folder.Name)
|
||||||
folderID := strconv.Itoa(folder.ID)
|
folderID := strconv.Itoa(folder.ID)
|
||||||
|
|
||||||
@ -206,7 +213,7 @@ func getRemote(dir, fileName string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fs) makeFolder(ctx context.Context, leaf string, folderID int) (response *MakeFolderResponse, err error) {
|
func (f *Fs) makeFolder(ctx context.Context, leaf string, folderID int) (response *MakeFolderResponse, err error) {
|
||||||
name := replaceReservedChars(leaf)
|
name := enc.FromStandardName(leaf)
|
||||||
// fs.Debugf(f, "Creating folder `%s` in id `%s`", name, directoryID)
|
// fs.Debugf(f, "Creating folder `%s` in id `%s`", name, directoryID)
|
||||||
|
|
||||||
request := MakeFolderRequest{
|
request := MakeFolderRequest{
|
||||||
@ -316,7 +323,7 @@ func (f *Fs) getUploadNode(ctx context.Context) (response *GetUploadNodeResponse
|
|||||||
func (f *Fs) uploadFile(ctx context.Context, in io.Reader, size int64, fileName, folderID, uploadID, node string) (response *http.Response, err error) {
|
func (f *Fs) uploadFile(ctx context.Context, in io.Reader, size int64, fileName, folderID, uploadID, node string) (response *http.Response, err error) {
|
||||||
// fs.Debugf(f, "Uploading File `%s`", fileName)
|
// fs.Debugf(f, "Uploading File `%s`", fileName)
|
||||||
|
|
||||||
fileName = replaceReservedChars(fileName)
|
fileName = enc.FromStandardName(fileName)
|
||||||
|
|
||||||
if len(uploadID) > 10 || !isAlphaNumeric(uploadID) {
|
if len(uploadID) > 10 || !isAlphaNumeric(uploadID) {
|
||||||
return nil, errors.New("Invalid UploadID")
|
return nil, errors.New("Invalid UploadID")
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/fs/config/configmap"
|
"github.com/rclone/rclone/fs/config/configmap"
|
||||||
"github.com/rclone/rclone/fs/config/configstruct"
|
"github.com/rclone/rclone/fs/config/configstruct"
|
||||||
|
"github.com/rclone/rclone/fs/encodings"
|
||||||
"github.com/rclone/rclone/fs/fshttp"
|
"github.com/rclone/rclone/fs/fshttp"
|
||||||
"github.com/rclone/rclone/fs/hash"
|
"github.com/rclone/rclone/fs/hash"
|
||||||
"github.com/rclone/rclone/lib/dircache"
|
"github.com/rclone/rclone/lib/dircache"
|
||||||
@ -28,6 +29,8 @@ const (
|
|||||||
decayConstant = 2 // bigger for slower decay, exponential
|
decayConstant = 2 // bigger for slower decay, exponential
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const enc = encodings.Fichier
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
fs.Register(&fs.RegInfo{
|
fs.Register(&fs.RegInfo{
|
||||||
Name: "fichier",
|
Name: "fichier",
|
||||||
@ -142,7 +145,7 @@ func (f *Fs) Features() *fs.Features {
|
|||||||
// On Windows avoid single character remote names as they can be mixed
|
// On Windows avoid single character remote names as they can be mixed
|
||||||
// up with drive letters.
|
// up with drive letters.
|
||||||
func NewFs(name string, rootleaf string, config configmap.Mapper) (fs.Fs, error) {
|
func NewFs(name string, rootleaf string, config configmap.Mapper) (fs.Fs, error) {
|
||||||
root := replaceReservedChars(rootleaf)
|
root := enc.FromStandardPath(rootleaf)
|
||||||
opt := new(Options)
|
opt := new(Options)
|
||||||
err := configstruct.Set(config, opt)
|
err := configstruct.Set(config, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Translate file names for 1fichier
|
|
||||||
|
|
||||||
1Fichier reserved characters
|
|
||||||
|
|
||||||
The following characters are 1Fichier reserved characters, and can't
|
|
||||||
be used in 1Fichier folder and file names.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
package fichier
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// charMap holds replacements for characters
|
|
||||||
//
|
|
||||||
// 1Fichier has a restricted set of characters compared to other cloud
|
|
||||||
// storage systems, so we to map these to the FULLWIDTH unicode
|
|
||||||
// equivalents
|
|
||||||
//
|
|
||||||
// http://unicode-search.net/unicode-namesearch.pl?term=SOLIDUS
|
|
||||||
var (
|
|
||||||
charMap = map[rune]rune{
|
|
||||||
'\\': '\', // FULLWIDTH REVERSE SOLIDUS
|
|
||||||
'<': '<', // FULLWIDTH LESS-THAN SIGN
|
|
||||||
'>': '>', // FULLWIDTH GREATER-THAN SIGN
|
|
||||||
'"': '"', // FULLWIDTH QUOTATION MARK - not on the list but seems to be reserved
|
|
||||||
'\'': ''', // FULLWIDTH APOSTROPHE
|
|
||||||
'$': '$', // FULLWIDTH DOLLAR SIGN
|
|
||||||
'`': '`', // FULLWIDTH GRAVE ACCENT
|
|
||||||
' ': '␠', // SYMBOL FOR SPACE
|
|
||||||
}
|
|
||||||
invCharMap map[rune]rune
|
|
||||||
fixStartingWithSpace = regexp.MustCompile(`(/|^) `)
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Create inverse charMap
|
|
||||||
invCharMap = make(map[rune]rune, len(charMap))
|
|
||||||
for k, v := range charMap {
|
|
||||||
invCharMap[v] = k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replaceReservedChars takes a path and substitutes any reserved
|
|
||||||
// characters in it
|
|
||||||
func replaceReservedChars(in string) string {
|
|
||||||
// file names can't start with space either
|
|
||||||
in = fixStartingWithSpace.ReplaceAllString(in, "$1"+string(charMap[' ']))
|
|
||||||
// Replace reserved characters
|
|
||||||
return strings.Map(func(c rune) rune {
|
|
||||||
if replacement, ok := charMap[c]; ok && c != ' ' {
|
|
||||||
return replacement
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}, in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// restoreReservedChars takes a path and undoes any substitutions
|
|
||||||
// made by replaceReservedChars
|
|
||||||
func restoreReservedChars(in string) string {
|
|
||||||
return strings.Map(func(c rune) rune {
|
|
||||||
if replacement, ok := invCharMap[c]; ok {
|
|
||||||
return replacement
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}, in)
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package fichier
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestReplace(t *testing.T) {
|
|
||||||
for _, test := range []struct {
|
|
||||||
in string
|
|
||||||
out string
|
|
||||||
}{
|
|
||||||
{"", ""},
|
|
||||||
{"abc 123", "abc 123"},
|
|
||||||
{"\"'<>/\\$`", `"'<>/\$``},
|
|
||||||
{" leading space", "␠leading space"},
|
|
||||||
} {
|
|
||||||
got := replaceReservedChars(test.in)
|
|
||||||
if got != test.out {
|
|
||||||
t.Errorf("replaceReservedChars(%q) want %q got %q", test.in, test.out, got)
|
|
||||||
}
|
|
||||||
got2 := restoreReservedChars(got)
|
|
||||||
if got2 != test.in {
|
|
||||||
t.Errorf("restoreReservedChars(%q) want %q got %q", got, test.in, got2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -87,11 +87,31 @@ normal file system).
|
|||||||
Duplicated files cause problems with the syncing and you will see
|
Duplicated files cause problems with the syncing and you will see
|
||||||
messages in the log about duplicates.
|
messages in the log about duplicates.
|
||||||
|
|
||||||
### Forbidden characters ###
|
#### Restricted filename characters
|
||||||
|
|
||||||
1Fichier does not support the characters ``\ < > " ' ` $`` and spaces at the beginning of folder names.
|
In addition to the [default restricted characters set](/overview/#restricted-characters)
|
||||||
`rclone` automatically escapes these to a unicode equivalent. The exception is `/`,
|
the following characters are also replaced:
|
||||||
which cannot be escaped and will therefore lead to errors.
|
|
||||||
|
| Character | Value | Replacement |
|
||||||
|
| --------- |:-----:|:-----------:|
|
||||||
|
| \ | 0x5C | \ |
|
||||||
|
| < | 0x3C | < |
|
||||||
|
| > | 0x3E | > |
|
||||||
|
| " | 0x22 | " |
|
||||||
|
| $ | 0x24 | $ |
|
||||||
|
| ` | 0x60 | ` |
|
||||||
|
| ' | 0x27 | ' |
|
||||||
|
|
||||||
|
File names can also not start or end with the following characters.
|
||||||
|
These only get replaced if they are first or 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.
|
||||||
|
|
||||||
<!--- autogenerated options start - DO NOT EDIT, instead edit fs.RegInfo in backend/fichier/fichier.go then run make backenddocs -->
|
<!--- autogenerated options start - DO NOT EDIT, instead edit fs.RegInfo in backend/fichier/fichier.go then run make backenddocs -->
|
||||||
### Standard Options
|
### Standard Options
|
||||||
|
@ -229,6 +229,31 @@ const Pcloud = encoder.MultiEncoder(
|
|||||||
encoder.EncodeBackSlash |
|
encoder.EncodeBackSlash |
|
||||||
encoder.EncodeInvalidUtf8)
|
encoder.EncodeInvalidUtf8)
|
||||||
|
|
||||||
|
// Fichier is the encoding used by the fichier backend
|
||||||
|
//
|
||||||
|
// Characters that need escaping
|
||||||
|
//
|
||||||
|
// '\\': '\', // FULLWIDTH REVERSE SOLIDUS
|
||||||
|
// '<': '<', // FULLWIDTH LESS-THAN SIGN
|
||||||
|
// '>': '>', // FULLWIDTH GREATER-THAN SIGN
|
||||||
|
// '"': '"', // FULLWIDTH QUOTATION MARK - not on the list but seems to be reserved
|
||||||
|
// '\'': ''', // FULLWIDTH APOSTROPHE
|
||||||
|
// '$': '$', // FULLWIDTH DOLLAR SIGN
|
||||||
|
// '`': '`', // FULLWIDTH GRAVE ACCENT
|
||||||
|
//
|
||||||
|
// Leading space and trailing space
|
||||||
|
const Fichier = encoder.MultiEncoder(
|
||||||
|
uint(Display) |
|
||||||
|
encoder.EncodeBackSlash |
|
||||||
|
encoder.EncodeSingleQuote |
|
||||||
|
encoder.EncodeBackQuote |
|
||||||
|
encoder.EncodeDoubleQuote |
|
||||||
|
encoder.EncodeLtGt |
|
||||||
|
encoder.EncodeDollar |
|
||||||
|
encoder.EncodeLeftSpace |
|
||||||
|
encoder.EncodeRightSpace |
|
||||||
|
encoder.EncodeInvalidUtf8)
|
||||||
|
|
||||||
// FTP is the encoding used by the ftp backend
|
// FTP is the encoding used by the ftp backend
|
||||||
//
|
//
|
||||||
// The FTP protocal can't handle trailing spaces (for instance
|
// The FTP protocal can't handle trailing spaces (for instance
|
||||||
@ -298,6 +323,8 @@ func ByName(name string) encoder.Encoder {
|
|||||||
case "dropbox":
|
case "dropbox":
|
||||||
return Dropbox
|
return Dropbox
|
||||||
//case "ftp":
|
//case "ftp":
|
||||||
|
case "ficher":
|
||||||
|
return Fichier
|
||||||
case "googlecloudstorage":
|
case "googlecloudstorage":
|
||||||
return GoogleCloudStorage
|
return GoogleCloudStorage
|
||||||
//case "http":
|
//case "http":
|
||||||
|
@ -15,11 +15,13 @@ const (
|
|||||||
LocalUnix = Base
|
LocalUnix = Base
|
||||||
LocalWindows = Base
|
LocalWindows = Base
|
||||||
AmazonCloudDrive = Base
|
AmazonCloudDrive = Base
|
||||||
|
AzureBlob = Base
|
||||||
B2 = Base
|
B2 = Base
|
||||||
Box = Base
|
Box = Base
|
||||||
Drive = Base
|
Drive = Base
|
||||||
Dropbox = Base
|
Dropbox = Base
|
||||||
FTP = Base
|
FTP = Base
|
||||||
|
Fichier = Base
|
||||||
GoogleCloudStorage = Base
|
GoogleCloudStorage = Base
|
||||||
JottaCloud = Base
|
JottaCloud = Base
|
||||||
Koofr = Base
|
Koofr = Base
|
||||||
@ -27,7 +29,9 @@ const (
|
|||||||
OneDrive = Base
|
OneDrive = Base
|
||||||
OpenDrive = Base
|
OpenDrive = Base
|
||||||
Pcloud = Base
|
Pcloud = Base
|
||||||
|
QingStor = Base
|
||||||
S3 = Base
|
S3 = Base
|
||||||
|
Swift = Base
|
||||||
)
|
)
|
||||||
|
|
||||||
// ByName returns the encoder for a give backend name or nil
|
// ByName returns the encoder for a give backend name or nil
|
||||||
|
Loading…
Reference in New Issue
Block a user