ficher: use lib/encoder

This commit is contained in:
Nick Craig-Wood 2019-09-23 12:55:49 +01:00
parent 4098907511
commit 8d8fad724b
7 changed files with 70 additions and 104 deletions

View File

@ -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")

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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":

View File

@ -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