worm grace period and retention time support (#6404)
Signed-off-by: lou <alex1988@outlook.com>
This commit is contained in:
@@ -3,12 +3,14 @@ package mount
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mount/meta_cache"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (wfs *WFS) subscribeFilerConfEvents() (*meta_cache.MetadataFollower, error) {
|
||||
@@ -73,18 +75,32 @@ func (wfs *WFS) subscribeFilerConfEvents() (*meta_cache.MetadataFollower, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (wfs *WFS) wormEnabledForEntry(path util.FullPath, entry *filer_pb.Entry) bool {
|
||||
if entry == nil || entry.Attributes == nil {
|
||||
return false
|
||||
}
|
||||
if wfs.FilerConf == nil {
|
||||
return false
|
||||
func (wfs *WFS) wormEnforcedForEntry(path util.FullPath, entry *filer_pb.Entry) (wormEnforced, wormEnabled bool) {
|
||||
if entry == nil || wfs.FilerConf == nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
rule := wfs.FilerConf.MatchStorageRule(string(path))
|
||||
if !rule.Worm {
|
||||
return false
|
||||
return false, false
|
||||
}
|
||||
|
||||
return entry.Attributes.FileSize > 0 || entry.Attributes.Crtime != entry.Attributes.Mtime
|
||||
// worm is not enforced
|
||||
if entry.WormEnforcedAtTsNs == 0 {
|
||||
return false, true
|
||||
}
|
||||
|
||||
// worm will never expire
|
||||
if rule.WormRetentionTimeSeconds == 0 {
|
||||
return true, true
|
||||
}
|
||||
|
||||
enforcedAt := time.Unix(0, entry.WormEnforcedAtTsNs)
|
||||
|
||||
// worm is expired
|
||||
if time.Now().Sub(enforcedAt).Seconds() >= float64(rule.WormRetentionTimeSeconds) {
|
||||
return false, true
|
||||
}
|
||||
|
||||
return true, true
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
|
||||
@@ -42,7 +43,7 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
|
||||
}
|
||||
|
||||
path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
|
||||
if status != fuse.OK {
|
||||
if status != fuse.OK || entry == nil {
|
||||
return status
|
||||
}
|
||||
if fh != nil {
|
||||
@@ -50,7 +51,12 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
|
||||
defer fh.entryLock.Unlock()
|
||||
}
|
||||
|
||||
if size, ok := input.GetSize(); ok && entry != nil {
|
||||
wormEnforced, wormEnabled := wfs.wormEnforcedForEntry(path, entry)
|
||||
if wormEnforced {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
if size, ok := input.GetSize(); ok {
|
||||
glog.V(4).Infof("%v setattr set size=%v chunks=%d", path, size, len(entry.GetChunks()))
|
||||
if size < filer.FileSize(entry) {
|
||||
// fmt.Printf("truncate %v \n", fullPath)
|
||||
@@ -85,6 +91,11 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
|
||||
}
|
||||
|
||||
if mode, ok := input.GetMode(); ok {
|
||||
// commit the file to worm when it is set to readonly at the first time
|
||||
if entry.WormEnforcedAtTsNs == 0 && wormEnabled && !hasWritePermission(mode) {
|
||||
entry.WormEnforcedAtTsNs = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
// glog.V(4).Infof("setAttr mode %o", mode)
|
||||
entry.Attributes.FileMode = chmod(entry.Attributes.FileMode, mode)
|
||||
if input.NodeId == 1 {
|
||||
@@ -216,6 +227,14 @@ func chmod(existing uint32, mode uint32) uint32 {
|
||||
return existing&^07777 | mode&07777
|
||||
}
|
||||
|
||||
const ownerWrite = 0o200
|
||||
const groupWrite = 0o020
|
||||
const otherWrite = 0o002
|
||||
|
||||
func hasWritePermission(mode uint32) bool {
|
||||
return (mode&ownerWrite != 0) || (mode&groupWrite != 0) || (mode&otherWrite != 0)
|
||||
}
|
||||
|
||||
func toSyscallMode(mode os.FileMode) uint32 {
|
||||
return toSyscallType(mode) | uint32(mode)
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ func (wfs *WFS) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name strin
|
||||
return code
|
||||
}
|
||||
|
||||
if wfs.wormEnabledForEntry(entryFullPath, entry) {
|
||||
if wormEnforced, _ := wfs.wormEnforcedForEntry(entryFullPath, entry); wormEnforced {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ func (wfs *WFS) AcquireHandle(inode uint64, flags, uid, gid uint32) (fileHandle
|
||||
var path util.FullPath
|
||||
path, _, entry, status = wfs.maybeReadEntry(inode)
|
||||
if status == fuse.OK {
|
||||
if wfs.wormEnabledForEntry(path, entry) && flags&fuse.O_ANYWRITE != 0 {
|
||||
if wormEnforced, _ := wfs.wormEnforcedForEntry(path, entry); wormEnforced && flags&fuse.O_ANYWRITE != 0 {
|
||||
return nil, fuse.EPERM
|
||||
}
|
||||
// need to AcquireFileHandle again to ensure correct handle counter
|
||||
|
||||
@@ -49,7 +49,7 @@ func (wfs *WFS) Link(cancel <-chan struct{}, in *fuse.LinkIn, name string, out *
|
||||
}
|
||||
|
||||
// hardlink is not allowed in WORM mode
|
||||
if wfs.wormEnabledForEntry(oldEntryPath, oldEntry) {
|
||||
if wormEnforced, _ := wfs.wormEnforcedForEntry(oldEntryPath, oldEntry); wormEnforced {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -161,11 +161,13 @@ func (wfs *WFS) Rename(cancel <-chan struct{}, in *fuse.RenameIn, oldName string
|
||||
}
|
||||
newPath := newDir.Child(newName)
|
||||
|
||||
if wfs.FilerConf != nil {
|
||||
rule := wfs.FilerConf.MatchStorageRule(string(oldPath))
|
||||
if rule.Worm {
|
||||
return fuse.EPERM
|
||||
}
|
||||
oldEntry, status := wfs.maybeLoadEntry(oldPath)
|
||||
if status != fuse.OK {
|
||||
return status
|
||||
}
|
||||
|
||||
if wormEnforced, _ := wfs.wormEnforcedForEntry(oldPath, oldEntry); wormEnforced {
|
||||
return fuse.EPERM
|
||||
}
|
||||
|
||||
glog.V(4).Infof("dir Rename %s => %s", oldPath, newPath)
|
||||
|
||||
Reference in New Issue
Block a user