Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 69 additions & 11 deletions drivers/alias/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/url"
stdpath "path"
"strings"
"unicode/utf16"

"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/errs"
Expand Down Expand Up @@ -117,8 +118,12 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
return nil, errs.ObjectNotFound
}
for idx, root := range roots {
rawPath := stdpath.Join(root, sub)
rawPath := stdpath.Join(root, d.escapeFilenamePath(sub))
obj, err := fs.Get(ctx, rawPath, &fs.GetArgs{NoLog: true})
if err != nil && errs.IsObjectNotFound(err) && rawPath != stdpath.Join(root, sub) {
rawPath = stdpath.Join(root, sub)
obj, err = fs.Get(ctx, rawPath, &fs.GetArgs{NoLog: true})
}
if err != nil {
continue
}
Expand All @@ -129,7 +134,7 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
}
ret := model.Object{
Path: rawPath,
Name: obj.GetName(),
Name: d.escapeFilename(obj.GetName(), false),
Size: obj.GetSize(),
Modified: obj.ModTime(),
IsFolder: obj.IsDir(),
Expand Down Expand Up @@ -159,9 +164,9 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
if idx > 0 {
objs = append(objs, nil)
}
for _, d := range roots {
for _, root := range roots {
objs = append(objs, &tempObj{model.Object{
Path: stdpath.Join(d, sub),
Path: stdpath.Join(root, d.escapeFilenamePath(sub)),
}})
}
Comment on lines +167 to 171

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

escape是一对一,unescape应该设计成多对一解析替换所有出现的_xHHHH_,期望的get逻辑应该匹配所有unescape后match的文件,对多个unescape后相同的文件操作时可以继承alias对于多个后端操作时的相同逻辑。

return objs, nil
Expand Down Expand Up @@ -192,14 +197,20 @@ func (d *Alias) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([
continue
}
for _, obj := range tmp {
name := obj.GetName()
rawName, name := obj.GetName(), d.escapeFilename(obj.GetName(), false)
escapedName := d.escapeFilename(name, true)
if d.FilenameAutoRename && escapedName != rawName {
if err := fs.Rename(ctx, stdpath.Join(dirPath, rawName), escapedName); err == nil {
rawName = escapedName
}
}
if _, exists := objMap[name]; exists {
continue
}
mask := model.GetObjMask(obj) &^ model.Temp
objRes := model.Object{
Name: name,
Path: stdpath.Join(dirPath, name),
Path: stdpath.Join(dirPath, rawName),
Size: obj.GetSize(),
Modified: obj.ModTime(),
IsFolder: obj.IsDir(),
Expand Down Expand Up @@ -362,7 +373,7 @@ func (d *Alias) MakeDir(ctx context.Context, parentDir model.Obj, dirName string
objs, err := d.getWriteObjs(ctx, parentDir)
if err == nil {
for _, obj := range objs {
err = errors.Join(err, fs.MakeDir(ctx, stdpath.Join(obj.GetPath(), dirName)))
err = errors.Join(err, fs.MakeDir(ctx, stdpath.Join(obj.GetPath(), d.escapeFilename(dirName, true))))
}
}
return err
Expand All @@ -389,7 +400,7 @@ func (d *Alias) Rename(ctx context.Context, srcObj model.Obj, newName string) er
objs, err := d.getWriteObjs(ctx, srcObj)
if err == nil {
for _, obj := range objs {
err = errors.Join(err, fs.Rename(ctx, obj.GetPath(), newName))
err = errors.Join(err, fs.Rename(ctx, obj.GetPath(), d.escapeFilename(newName, true)))
}
}
return err
Expand Down Expand Up @@ -426,7 +437,7 @@ func (d *Alias) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer,
return err
}
return op.Put(ctx, storage, reqActualPath, &stream.FileStream{
Obj: s,
Obj: d.escapeObjName(s),
Mimetype: s.GetMimetype(),
Reader: s,
}, up)
Expand All @@ -439,7 +450,7 @@ func (d *Alias) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer,
up(100 / count)
for i, obj := range objs {
err = errors.Join(err, fs.PutDirectly(ctx, obj.GetPath(), &stream.FileStream{
Obj: s,
Obj: d.escapeObjName(s),
Mimetype: s.GetMimetype(),
Reader: file,
}))
Expand All @@ -459,7 +470,7 @@ func (d *Alias) PutURL(ctx context.Context, dstDir model.Obj, name, url string)
objs, err := d.getPutObjs(ctx, dstDir)
if err == nil {
for _, obj := range objs {
err = errors.Join(err, fs.PutURL(ctx, obj.GetPath(), name, url))
err = errors.Join(err, fs.PutURL(ctx, obj.GetPath(), d.escapeFilename(name, true), url))
}
return err
}
Expand Down Expand Up @@ -576,4 +587,51 @@ func (d *Alias) ResolveLinkCacheMode(path string) driver.LinkCacheMode {
return 0
}

func (d *Alias) escapeObjName(obj model.Obj) model.Obj {
name := d.escapeFilename(obj.GetName(), true)
if name == obj.GetName() {
return obj
}
return &model.ObjWrapName{Name: name, Obj: obj}
}

func (d *Alias) escapeFilenamePath(path string) string {
parts := strings.Split(path, "/")
for i := range parts {
parts[i] = d.escapeFilename(parts[i], true)
}
return strings.Join(parts, "/")
}

func (d *Alias) escapeFilename(name string, encode bool) string {
if !d.FilenameEscape {
return name
}
var protected, characters []string
Comment on lines +606 to +610
for char := range strings.SplitSeq(d.FilenameEscapeChars, "\n") {
char = strings.TrimSuffix(char, "\r")
if char == "" {
continue
}
runes := []rune(char)
var escaped string
for _, unit := range utf16.Encode(runes[:1]) {
escaped += fmt.Sprintf("_x%04X_", unit)
}
escaped += string(runes[1:])
safeToken := "_x005F_" + escaped[1:]
if encode {
protected = append(protected, escaped, safeToken)
characters = append(characters, char, escaped)
} else {
protected = append(protected, safeToken, escaped)
characters = append(characters, escaped, char)
}
}
if len(protected) == 0 {
return name
}
return strings.NewReplacer(append(protected, characters...)...).Replace(name)
}

var _ driver.Driver = (*Alias)(nil)
3 changes: 3 additions & 0 deletions drivers/alias/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type Addition struct {
DownloadPartSize int `json:"download_part_size" default:"0" type:"number" required:"false" help:"Need to enable proxy. Unit: KB"`
ProviderPassThrough bool `json:"provider_pass_through" type:"bool" default:"false"`
DetailsPassThrough bool `json:"details_pass_through" type:"bool" default:"false"`
FilenameEscape bool `json:"filename_escape" type:"bool" default:"false"`
FilenameEscapeChars string `json:"filename_escape_chars" type:"text" help:"Strings to escape by replacing the first character with _xHHHH_ UTF-16 code units, one per line"`
FilenameAutoRename bool `json:"filename_auto_rename" type:"bool" default:"false" help:"Automatically rename matching existing backend objects when listing directories"`
}

var config = driver.Config{
Expand Down