Feat: support apply append mode and overwrite mode for FileStream

pull/1107/head
HFO4 2 years ago
parent 285611baf7
commit 118d738797

@ -1 +1 @@
Subproject commit b90a49ba5d809e3042bce801ac28fb7cde74c878 Subproject commit eb3f32922ab9cd2f9fbef4860b93fec759a7054d

@ -308,7 +308,7 @@ func (fs *FileSystem) Decompress(ctx context.Context, src, dst string) error {
Size: uint64(size), Size: uint64(size),
Name: path.Base(dst), Name: path.Base(dst),
VirtualPath: path.Dir(dst), VirtualPath: path.Dir(dst),
Mode: fsctx.Create, Mode: 0,
}) })
fileStream.Close() fileStream.Close()
if err != nil { if err != nil {

@ -93,7 +93,7 @@ func (handler Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
dst := util.RelativePath(filepath.FromSlash(fileInfo.SavePath)) dst := util.RelativePath(filepath.FromSlash(fileInfo.SavePath))
// 如果非 Overwrite则检查是否有重名冲突 // 如果非 Overwrite则检查是否有重名冲突
if fileInfo.Mode == fsctx.Create { if fileInfo.Mode&fsctx.Overwrite != fsctx.Overwrite {
if util.Exists(dst) { if util.Exists(dst) {
util.Log().Warning("物理同名文件已存在或不可用: %s", dst) util.Log().Warning("物理同名文件已存在或不可用: %s", dst)
return errors.New("物理同名文件已存在或不可用") return errors.New("物理同名文件已存在或不可用")
@ -115,21 +115,21 @@ func (handler Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
err error err error
) )
if fileInfo.Mode == fsctx.Append { openMode := os.O_CREATE | os.O_RDWR
// 如果是追加模式,则直接打开文件 if fileInfo.Mode&fsctx.Append == fsctx.Append {
out, err = os.OpenFile(dst, os.O_APPEND|os.O_CREATE|os.O_WRONLY, Perm) openMode |= os.O_APPEND
} else { } else {
// 创建或覆盖目标文件 openMode |= os.O_TRUNC
out, err = os.Create(dst)
} }
out, err = os.OpenFile(dst, openMode, Perm)
if err != nil { if err != nil {
util.Log().Warning("无法打开或创建文件,%s", err) util.Log().Warning("无法打开或创建文件,%s", err)
return err return err
} }
defer out.Close() defer out.Close()
if fileInfo.Mode == fsctx.Append { if fileInfo.Mode&fsctx.Append == fsctx.Append {
stat, err := out.Stat() stat, err := out.Stat()
if err != nil { if err != nil {
util.Log().Warning("无法读取文件信息,%s", err) util.Log().Warning("无法读取文件信息,%s", err)
@ -144,7 +144,7 @@ func (handler Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
return fmt.Errorf("覆盖分片时发生错误: %w", err) return fmt.Errorf("覆盖分片时发生错误: %w", err)
} }
out, err = os.OpenFile(dst, os.O_APPEND|os.O_CREATE|os.O_WRONLY, Perm) out, err = os.OpenFile(dst, openMode, Perm)
defer out.Close() defer out.Close()
if err != nil { if err != nil {
util.Log().Warning("无法打开或创建文件,%s", err) util.Log().Warning("无法打开或创建文件,%s", err)

@ -260,9 +260,9 @@ func (client *Client) UploadChunk(ctx context.Context, uploadURL string, chunk *
func (client *Client) Upload(ctx context.Context, file fsctx.FileHeader) error { func (client *Client) Upload(ctx context.Context, file fsctx.FileHeader) error {
fileInfo := file.Info() fileInfo := file.Info()
// 决定是否覆盖文件 // 决定是否覆盖文件
overwrite := "replace" overwrite := "fail"
if fileInfo.Mode != fsctx.Create { if fileInfo.Mode&fsctx.Overwrite == fsctx.Overwrite {
overwrite = "fail" overwrite = "replace"
} }
size := int(fileInfo.Size) size := int(fileInfo.Size)

@ -237,11 +237,7 @@ func (handler Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600) credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600)
// 是否允许覆盖 // 是否允许覆盖
overwrite := true overwrite := fileInfo.Mode&fsctx.Overwrite == fsctx.Overwrite
if fileInfo.Mode == fsctx.Create {
overwrite = false
}
options := []oss.Option{ options := []oss.Option{
oss.Expires(time.Now().Add(time.Duration(credentialTTL) * time.Second)), oss.Expires(time.Now().Add(time.Duration(credentialTTL) * time.Second)),
oss.ForbidOverWrite(!overwrite), oss.ForbidOverWrite(!overwrite),

@ -173,9 +173,9 @@ func (handler Driver) Put(ctx context.Context, file fsctx.FileHeader) error {
fileName := url.QueryEscape(path.Base(fileInfo.SavePath)) fileName := url.QueryEscape(path.Base(fileInfo.SavePath))
// 决定是否要禁用文件覆盖 // 决定是否要禁用文件覆盖
overwrite := "true" overwrite := "false"
if fileInfo.Mode != fsctx.Create { if fileInfo.Mode&fsctx.Overwrite == fsctx.Overwrite {
overwrite = "false" overwrite = "true"
} }
// 上传文件 // 上传文件

@ -8,11 +8,10 @@ import (
type WriteMode int type WriteMode int
const ( const (
Overwrite WriteMode = iota Overwrite WriteMode = 0x00001
// Append 只适用于本地策略 // Append 只适用于本地策略
Append Append = 0x00002
Create Nop = 0x00004
Nop
) )
type UploadTaskInfo struct { type UploadTaskInfo struct {

@ -151,6 +151,7 @@ func HookCleanFileContent(ctx context.Context, fs *FileSystem, file fsctx.FileHe
File: ioutil.NopCloser(strings.NewReader("")), File: ioutil.NopCloser(strings.NewReader("")),
SavePath: file.Info().SavePath, SavePath: file.Info().SavePath,
Size: 0, Size: 0,
Model: fsctx.Overwrite,
}) })
} }

@ -51,7 +51,7 @@ func (fs *FileSystem) Upload(ctx context.Context, file *fsctx.FileStream) (err e
go fs.CancelUpload(ctx, savePath, file) go fs.CancelUpload(ctx, savePath, file)
// 保存文件 // 保存文件
if file.Mode != fsctx.Nop { if file.Mode&fsctx.Nop != fsctx.Nop {
err = fs.Handler.Put(ctx, file) err = fs.Handler.Put(ctx, file)
if err != nil { if err != nil {
fs.Trigger(ctx, "AfterUploadFailed", file) fs.Trigger(ctx, "AfterUploadFailed", file)
@ -73,7 +73,7 @@ func (fs *FileSystem) Upload(ctx context.Context, file *fsctx.FileStream) (err e
return err return err
} }
if file.Mode == fsctx.Create { if file.Mode&fsctx.Overwrite == 0 {
fileInfo := file.Info() fileInfo := file.Info()
util.Log().Info( util.Log().Info(
"新文件PUT:%s , 大小:%d, 上传者:%s", "新文件PUT:%s , 大小:%d, 上传者:%s",

@ -7,7 +7,6 @@ import (
model "github.com/cloudreve/Cloudreve/v3/models" model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
"github.com/cloudreve/Cloudreve/v3/pkg/util" "github.com/cloudreve/Cloudreve/v3/pkg/util"
) )
@ -107,7 +106,7 @@ func (job *CompressTask) Do() {
job.TaskModel.SetProgress(TransferringProgress) job.TaskModel.SetProgress(TransferringProgress)
// 上传文件 // 上传文件
err = fs.UploadFromPath(ctx, zipFile, job.TaskProps.Dst, true, fsctx.Create) err = fs.UploadFromPath(ctx, zipFile, job.TaskProps.Dst, true, 0)
if err != nil { if err != nil {
job.SetErrorMsg(err.Error()) job.SetErrorMsg(err.Error())
return return

@ -119,7 +119,6 @@ func (job *TransferTask) Do() {
err = fs.Handler.Put(context.Background(), &fsctx.FileStream{ err = fs.Handler.Put(context.Background(), &fsctx.FileStream{
File: file, File: file,
Mode: fsctx.Create,
SavePath: job.Req.Dst, SavePath: job.Req.Dst,
Size: uint64(size), Size: uint64(size),
}) })

@ -123,11 +123,10 @@ func (job *TransferTask) Do() {
Size: job.TaskProps.SrcSizes[file], Size: job.TaskProps.SrcSizes[file],
Name: path.Base(dst), Name: path.Base(dst),
VirtualPath: path.Dir(dst), VirtualPath: path.Dir(dst),
Mode: fsctx.Create,
}) })
} else { } else {
// 主机节点中转 // 主机节点中转
err = fs.UploadFromPath(context.Background(), file, dst, true, fsctx.Create) err = fs.UploadFromPath(context.Background(), file, dst, true, 0)
} }
if err != nil { if err != nil {

@ -355,6 +355,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request, fs *filesyst
fs.Use("AfterValidateFailed", filesystem.HookCleanFileContent) fs.Use("AfterValidateFailed", filesystem.HookCleanFileContent)
fs.Use("AfterValidateFailed", filesystem.HookClearFileSize) fs.Use("AfterValidateFailed", filesystem.HookClearFileSize)
ctx = context.WithValue(ctx, fsctx.FileModelCtx, *originFile) ctx = context.WithValue(ctx, fsctx.FileModelCtx, *originFile)
fileData.Mode |= fsctx.Overwrite
} else { } else {
// 给文件系统分配钩子 // 给文件系统分配钩子
fs.Use("BeforeUpload", filesystem.HookValidateFile) fs.Use("BeforeUpload", filesystem.HookValidateFile)
@ -364,9 +365,6 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request, fs *filesyst
fs.Use("AfterUpload", filesystem.GenericAfterUpload) fs.Use("AfterUpload", filesystem.GenericAfterUpload)
fs.Use("AfterUpload", filesystem.HookGenerateThumb) fs.Use("AfterUpload", filesystem.HookGenerateThumb)
fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile) fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile)
// 禁止覆盖
fileData.Mode = fsctx.Create
} }
// 执行上传 // 执行上传

@ -73,10 +73,10 @@ func SlaveUpload(c *gin.Context) {
fs.Use("AfterUpload", filesystem.SlaveAfterUpload) fs.Use("AfterUpload", filesystem.SlaveAfterUpload)
fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile) fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile)
// 是否允许覆盖 //// 是否允许覆盖
if c.Request.Header.Get("X-Cr-Overwrite") == "false" { //if c.Request.Header.Get("X-Cr-Overwrite") == "false" {
fileData.Mode = fsctx.Create // fileData.Mode = fsctx.Create
} //}
// 执行上传 // 执行上传
err = fs.Upload(ctx, &fileData) err = fs.Upload(ctx, &fileData)

@ -65,7 +65,6 @@ func (service *SingleFileService) Create(c *gin.Context) serializer.Response {
Size: 0, Size: 0,
VirtualPath: path.Dir(service.Path), VirtualPath: path.Dir(service.Path),
Name: path.Base(service.Path), Name: path.Base(service.Path),
Mode: fsctx.Create,
}) })
if err != nil { if err != nil {
return serializer.Err(serializer.CodeUploadFailed, err.Error(), err) return serializer.Err(serializer.CodeUploadFailed, err.Error(), err)
@ -375,6 +374,7 @@ func (service *FileIDService) PutContent(ctx context.Context, c *gin.Context) se
MIMEType: c.Request.Header.Get("Content-Type"), MIMEType: c.Request.Header.Get("Content-Type"),
File: c.Request.Body, File: c.Request.Body,
Size: fileSize, Size: fileSize,
Model: fsctx.Overwrite,
} }
// 创建文件系统 // 创建文件系统

@ -148,7 +148,7 @@ func processChunkUpload(ctx context.Context, c *gin.Context, fs *filesystem.File
Name: session.Name, Name: session.Name,
VirtualPath: session.VirtualPath, VirtualPath: session.VirtualPath,
SavePath: session.SavePath, SavePath: session.SavePath,
Mode: fsctx.Append, Mode: fsctx.Append | fsctx.Overwrite,
AppendStart: chunkSize * uint64(index), AppendStart: chunkSize * uint64(index),
Model: file, Model: file,
LastModified: session.LastModified, LastModified: session.LastModified,

Loading…
Cancel
Save