/* * Copyright 2026 Oleg Borodin */ package fileoper import ( "context" "net/http" "path/filepath" "regexp" "strings" "mstore/pkg/descr" "mstore/pkg/filecli" ) // Check files type CheckFilesParams struct { Path string PathType string `param:"pathType"` } type CheckFilesResult struct { Files []descr.File `json:"files,omitempty"` } func (oper *Operator) CheckFiles(ctx context.Context, operatorID string, params *CheckFilesParams) (int, *CheckFilesResult, error) { var code int res := &CheckFilesResult{ Files: make([]descr.File, 0), } var err error code = http.StatusOK // Check existing and size files, err := oper.listFiles(ctx, params.PathType, params.Path) if err != nil { code = http.StatusInternalServerError return code, res, err } for _, file := range files { exists, size, err := oper.store.FileExists(file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } fullpath := filepath.Join(file.Collection, file.Name) if !exists { oper.logg.Warningf("File not exists: %s", fullpath) res.Files = append(res.Files, file) err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } } if size != file.Size { oper.logg.Warningf("Delete file with incorrect size: %s", fullpath) res.Files = append(res.Files, file) err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } err = oper.store.DeleteFile(file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } } } // Check hashs files, err = oper.listFiles(ctx, params.PathType, params.Path) if err != nil { code = http.StatusInternalServerError return code, res, err } for _, file := range files { sum, err := oper.store.GetFileCheksum(file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } fullpath := filepath.Join(file.Collection, file.Name) if sum != file.Checksum { oper.logg.Warningf("Delete file with incorrect digest: %s", fullpath) res.Files = append(res.Files, file) err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } err = oper.store.DeleteFile(file.Collection, file.Name) if err != nil { code := http.StatusInternalServerError return code, res, err } } } // Find orphans filelist, err := oper.store.ListAllFiles() if err != nil { code = http.StatusInternalServerError return code, res, err } for _, fullpath := range filelist { switch params.PathType { case filecli.PathTypeRegexp: re, err := regexp.Compile(params.Path) if err != nil { code = http.StatusInternalServerError return code, res, err } if !re.MatchString(fullpath) { continue } case filecli.PathTypePrefix: prefix, err := cleanFilepath(params.Path) if err != nil { code = http.StatusInternalServerError return code, res, err } if !strings.HasPrefix(fullpath, prefix) { continue } default: collection, err := cleanFilepath(params.Path) if err != nil { code = http.StatusInternalServerError return code, res, err } if filepath.Dir(fullpath) != collection { continue } } filename := filepath.Base(fullpath) collection := filepath.Dir(fullpath) exists, _, err := oper.mdb.GetFileByCollectionName(ctx, collection, filename) if err != nil { code = http.StatusInternalServerError return code, res, err } if !exists { oper.logg.Warningf("Delete orphan file: %s", fullpath) err = oper.store.DeleteFile(collection, filename) if err != nil { code := http.StatusInternalServerError return code, res, err } } } return code, res, err }