Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
09abcfd
feat: 添加对象掩码支持以处理虚拟对象和临时对象优化缓存
j2rong4cn Dec 2, 2025
29ad4b8
fix bug
j2rong4cn Dec 2, 2025
5957236
feat: 优化文件列表和获取功能,支持结果验证
j2rong4cn Dec 3, 2025
10abfab
fix: 更新获取对象的方法,修复潜在的错误
j2rong4cn Dec 4, 2025
05898d9
驱动实现driver.Getter时跳过文件名映射
j2rong4cn Dec 4, 2025
91a9d1e
fix: 修复对象掩码处理,确保临时对象不被错误标记
j2rong4cn Dec 4, 2025
b44e132
fix(crypt): 修复对象名称处理,确保正确解密文件和目录名称
j2rong4cn Dec 4, 2025
170f4fa
fix: 更新任务组处理,优化路径管理和钩子处理逻辑
j2rong4cn Dec 5, 2025
f1e1356
fix(cache): 优化缓存管理
j2rong4cn Dec 5, 2025
8463635
.
j2rong4cn Dec 5, 2025
e60105d
fix(fs): 优化逻辑
j2rong4cn Dec 7, 2025
816ce88
Merge branch 'main' into dev
j2rong4cn Dec 7, 2025
41bcd10
fix bug
j2rong4cn Dec 9, 2025
0afab7a
fix(fs): 添加跳过钩子的选项并优化对象更新逻辑
j2rong4cn Dec 9, 2025
156e65c
fix(task_group): 重命名函数并优化钩子处理逻辑
j2rong4cn Dec 9, 2025
7a2385d
fix(crypt): 修改Get方法以支持虚拟路径和文件夹加密的错误处理
j2rong4cn Dec 9, 2025
bb658bf
恢复 driver.PutURL接口
j2rong4cn Dec 9, 2025
9017fda
改进Put方法中的文件流关闭逻辑
j2rong4cn Dec 9, 2025
04ee177
fix(op): 改进Get方法中的对象查找逻辑,只在匹配到临时对象时刷新列表
j2rong4cn Dec 9, 2025
1b9dd7c
fix(op): 优化list函数,请求合并
j2rong4cn Dec 9, 2025
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
21 changes: 13 additions & 8 deletions drivers/alias/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
}
var ret *model.Object
provider := ""
var mask model.ObjMask
for _, dst := range dsts {
rawPath := stdpath.Join(dst, sub)
obj, err := fs.Get(ctx, rawPath, &fs.GetArgs{NoLog: true})
Expand All @@ -93,6 +94,8 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
}
storage, err := fs.GetStorage(rawPath, &fs.GetStoragesArgs{})
if ret == nil {
mask = model.GetObjMask(obj)
mask &^= model.Temp
ret = &model.Object{
Path: path,
Name: obj.GetName(),
Expand All @@ -114,14 +117,14 @@ func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
return nil, errs.ObjectNotFound
}
if provider != "" {
return &model.ObjectProvider{
return model.ObjAddMask(&model.ObjectProvider{
Object: *ret,
Provider: model.Provider{
Provider: provider,
},
}, nil
}, mask), nil
}
return ret, nil
return model.ObjAddMask(ret, mask), nil
}

func (d *Alias) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
Expand Down Expand Up @@ -150,21 +153,23 @@ func (d *Alias) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([
Modified: obj.ModTime(),
IsFolder: obj.IsDir(),
}
mask := model.GetObjMask(obj)
mask &^= model.Temp
if thumb, ok := model.GetThumb(obj); ok {
return &model.ObjThumb{
return model.ObjAddMask(&model.ObjThumb{
Object: objRes,
Thumbnail: model.Thumbnail{
Thumbnail: thumb,
},
}, nil
}, mask), nil
}
if details, ok := model.GetStorageDetails(obj); ok {
return &model.ObjStorageDetails{
return model.ObjAddMask(&model.ObjStorageDetails{
Obj: &objRes,
StorageDetailsWithName: *details,
}, nil
}, mask), nil
}
return &objRes, nil
return model.ObjAddMask(&objRes, mask), nil
})
}
if err == nil {
Expand Down
2 changes: 1 addition & 1 deletion drivers/alias/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (d *Alias) listRoot(ctx context.Context, withDetails, refresh bool) []model
Modified: d.Modified,
}
idx := len(objs)
objs = append(objs, &obj)
objs = append(objs, model.ObjAddMask(&obj, model.Virtual))
v := d.pathMap[k]
if !withDetails || len(v) != 1 {
continue
Expand Down
10 changes: 6 additions & 4 deletions drivers/chunk/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strconv"
"strings"

"github.com/OpenListTeam/OpenList/v4/internal/conf"
"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/errs"
"github.com/OpenListTeam/OpenList/v4/internal/fs"
Expand Down Expand Up @@ -426,17 +427,18 @@ func (d *Chunk) Put(ctx context.Context, dstDir model.Obj, file model.FileStream
UpdateProgress: up,
}
dst := stdpath.Join(remoteActualPath, dstDir.GetPath(), d.ChunkPrefix+file.GetName())
skipHookCtx := context.WithValue(ctx, conf.SkipHookKey, struct{}{})
if d.StoreHash {
for ht, value := range file.GetHash().All() {
_ = op.Put(ctx, remoteStorage, dst, &stream.FileStream{
_ = op.Put(skipHookCtx, remoteStorage, dst, &stream.FileStream{
Obj: &model.Object{
Name: fmt.Sprintf("hash_%s_%s%s", ht.Name, value, d.CustomExt),
Size: 1,
Modified: file.ModTime(),
},
Mimetype: "application/octet-stream",
Reader: bytes.NewReader([]byte{0}), // 兼容不支持空文件的驱动
}, nil, true)
}, nil)
}
}
fullPartCount := int(file.GetSize() / d.PartSize)
Expand All @@ -447,15 +449,15 @@ func (d *Chunk) Put(ctx context.Context, dstDir model.Obj, file model.FileStream
}
partIndex := 0
for partIndex < fullPartCount {
err = op.Put(ctx, remoteStorage, dst, &stream.FileStream{
err = op.Put(skipHookCtx, remoteStorage, dst, &stream.FileStream{
Obj: &model.Object{
Name: d.getPartName(partIndex),
Size: d.PartSize,
Modified: file.ModTime(),
},
Mimetype: file.GetMimetype(),
Reader: io.LimitReader(upReader, d.PartSize),
}, nil, true)
}, nil)
if err != nil {
_ = op.Remove(ctx, remoteStorage, dst)
return err
Expand Down
110 changes: 60 additions & 50 deletions drivers/crypt/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package crypt
import (
"bytes"
"context"
"errors"
"fmt"
"io"
stdpath "path"
Expand Down Expand Up @@ -109,43 +110,36 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([

result := make([]model.Obj, 0, len(objs))
for _, obj := range objs {
rawName := model.UnwrapObj(obj).GetName()
if obj.IsDir() {
name, err := d.cipher.DecryptDirName(rawName)
if err != nil {
// filter illegal files
continue
}
if !d.ShowHidden && strings.HasPrefix(name, ".") {
continue
size := obj.GetSize()
mask := model.GetObjMask(obj)
mask &^= model.Temp
name := obj.GetName()
if mask&model.Virtual == 0 {
rawName := model.UnwrapObjName(obj).GetName()
if obj.IsDir() {
name, err = d.cipher.DecryptDirName(rawName)
if err != nil {
// filter illegal files
continue
}
} else {
size, err = d.cipher.DecryptedSize(size)
if err != nil {
// filter illegal files
continue
}
name, err = d.cipher.DecryptFileName(rawName)
if err != nil {
// filter illegal files
continue
}
}
result = append(result, &model.Object{
Path: stdpath.Join(remoteFullPath, rawName),
Name: name,
Size: 0,
Modified: obj.ModTime(),
IsFolder: obj.IsDir(),
Ctime: obj.CreateTime(),
// discarding hash as it's encrypted
})
continue
}

size, err := d.cipher.DecryptedSize(obj.GetSize())
if err != nil {
// filter illegal files
continue
}
name, err := d.cipher.DecryptFileName(rawName)
if err != nil {
// filter illegal files
continue
}
if !d.ShowHidden && strings.HasPrefix(name, ".") {
continue
}
objRes := &model.Object{
Path: stdpath.Join(remoteFullPath, rawName),
Path: stdpath.Join(remoteFullPath, obj.GetName()),
Name: name,
Size: size,
Modified: obj.ModTime(),
Expand All @@ -154,20 +148,20 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([
// discarding hash as it's encrypted
}
if !d.Thumbnail || !strings.HasPrefix(args.ReqPath, "/") {
result = append(result, objRes)
result = append(result, model.ObjAddMask(objRes, mask))
continue
}
thumbPath := stdpath.Join(args.ReqPath, ".thumbnails", name+".webp")
thumb := fmt.Sprintf("%s/d%s?sign=%s",
common.GetApiUrl(ctx),
utils.EncodePath(thumbPath, true),
sign.Sign(thumbPath))
result = append(result, &model.ObjThumb{
result = append(result, model.ObjAddMask(&model.ObjThumb{
Object: *objRes,
Thumbnail: model.Thumbnail{
Thumbnail: thumb,
},
})
}, mask))
}

return result, nil
Expand All @@ -182,7 +176,14 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) {
remoteFullPath := stdpath.Join(d.RemotePath, d.encryptPath(path, firstTryIsFolder))
remoteObj, err := fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true})
if err != nil {
if secondTry && errs.IsObjectNotFound(err) {
if errors.Is(err, errs.StorageNotFound) {
remoteFullPath = stdpath.Join(d.RemotePath, path)
remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true})
if err != nil {
// 可能是 虚拟路径+开启文件夹加密:返回NotSupport让op.Get去尝试op.List查找
return nil, errs.NotSupport
}
} else if secondTry && errs.IsObjectNotFound(err) {
// try the opposite
remoteFullPath = stdpath.Join(d.RemotePath, d.encryptPath(path, !firstTryIsFolder))
remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true})
Expand All @@ -195,20 +196,28 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) {
}

size := remoteObj.GetSize()
name := model.UnwrapObj(remoteObj).GetName()
if !remoteObj.IsDir() {
size, err = d.cipher.DecryptedSize(size)
if err != nil {
log.Warnf("DecryptedSize failed for %s ,will use original size, err:%s", path, err)
}
name, err = d.cipher.DecryptFileName(name)
if err != nil {
log.Warnf("DecryptFileName failed for %s ,will use original name, err:%s", path, err)
}
} else {
name, err = d.cipher.DecryptDirName(name)
if err != nil {
log.Warnf("DecryptDirName failed for %s ,will use original name, err:%s", path, err)
name := remoteObj.GetName()
mask := model.GetObjMask(remoteObj)
mask &^= model.Temp
if mask&model.Virtual == 0 {
rawName := model.UnwrapObjName(remoteObj).GetName()
if !remoteObj.IsDir() {
size, err = d.cipher.DecryptedSize(size)
if err != nil {
size = remoteObj.GetSize()
log.Warnf("DecryptedSize failed for %s ,will use original size, err:%s", path, err)
}
name, err = d.cipher.DecryptFileName(rawName)
if err != nil {
name = remoteObj.GetName()
log.Warnf("DecryptFileName failed for %s ,will use original name, err:%s", path, err)
}
} else {
name, err = d.cipher.DecryptDirName(rawName)
if err != nil {
name = remoteObj.GetName()
log.Warnf("DecryptDirName failed for %s ,will use original name, err:%s", path, err)
}
}
}
obj := &model.Object{
Expand All @@ -217,8 +226,9 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) {
Size: size,
Modified: remoteObj.ModTime(),
IsFolder: remoteObj.IsDir(),
Ctime: remoteObj.CreateTime(),
}
return obj, nil
return model.ObjAddMask(obj, mask), nil
}

// https://github.com/rclone/rclone/blob/v1.67.0/backend/crypt/cipher.go#L37
Expand Down
2 changes: 1 addition & 1 deletion internal/cache/keyed_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (c *KeyedCache[T]) Delete(key string) {
delete(c.entries, key)
}

func (c *KeyedCache[T]) Take(key string) (T, bool) {
func (c *KeyedCache[T]) Pop(key string) (T, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if entry, exists := c.entries[key]; exists {
Expand Down
3 changes: 2 additions & 1 deletion internal/conf/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const (
)

// ContextKey is the type of context keys.
type ContextKey int
type ContextKey int8

const (
_ ContextKey = iota
Expand All @@ -186,4 +186,5 @@ const (
UserAgentKey
PathKey
SharingIDKey
SkipHookKey
)
9 changes: 0 additions & 9 deletions internal/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,6 @@ type PutURL interface {
PutURL(ctx context.Context, dstDir model.Obj, name, url string) error
}

//type WriteResult interface {
// MkdirResult
// MoveResult
// RenameResult
// CopyResult
// PutResult
// Remove
//}

type MkdirResult interface {
MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error)
}
Expand Down
Loading