forked from TrueCloudLab/frostfs-node
[#399] object/fmt: Check expiration epoch in tombstone body and header
According to nspcc-dev/neofs-api#136 tombstone body should store the same attribute as in object header. If they are different, then check is failed with `errTombstoneExpiration`. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
3ed0065455
commit
e6cdf3fbf5
1 changed files with 34 additions and 11 deletions
|
@ -38,6 +38,10 @@ var errNilID = errors.New("missing identifier")
|
||||||
|
|
||||||
var errNilCID = errors.New("missing container identifier")
|
var errNilCID = errors.New("missing container identifier")
|
||||||
|
|
||||||
|
var errNoExpirationEpoch = errors.New("missing expiration epoch attribute")
|
||||||
|
|
||||||
|
var errTombstoneExpiration = errors.New("tombstone body and header contain different expiration values")
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
return new(cfg)
|
return new(cfg)
|
||||||
}
|
}
|
||||||
|
@ -132,6 +136,17 @@ func (v *FormatValidator) ValidateContent(o *Object) error {
|
||||||
return errors.Wrapf(err, "(%T) could not unmarshal tombstone content", v)
|
return errors.Wrapf(err, "(%T) could not unmarshal tombstone content", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if tombstone has the same expiration in body and header
|
||||||
|
exp, err := expirationEpochAttribute(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp != tombstone.ExpirationEpoch() {
|
||||||
|
return errTombstoneExpiration
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark all objects from tombstone body as removed in storage engine
|
||||||
cid := o.ContainerID()
|
cid := o.ContainerID()
|
||||||
idList := tombstone.Members()
|
idList := tombstone.Members()
|
||||||
addrList := make([]*object.Address, 0, len(idList))
|
addrList := make([]*object.Address, 0, len(idList))
|
||||||
|
@ -177,24 +192,32 @@ func (v *FormatValidator) ValidateContent(o *Object) error {
|
||||||
var errExpired = errors.New("object has expired")
|
var errExpired = errors.New("object has expired")
|
||||||
|
|
||||||
func (v *FormatValidator) checkExpiration(obj *Object) error {
|
func (v *FormatValidator) checkExpiration(obj *Object) error {
|
||||||
|
exp, err := expirationEpochAttribute(obj)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, errNoExpirationEpoch) {
|
||||||
|
return nil // objects without expiration attribute are valid
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp < v.netState.CurrentEpoch() {
|
||||||
|
return errExpired
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expirationEpochAttribute(obj *Object) (uint64, error) {
|
||||||
for _, a := range obj.Attributes() {
|
for _, a := range obj.Attributes() {
|
||||||
if a.Key() != objectV2.SysAttributeExpEpoch {
|
if a.Key() != objectV2.SysAttributeExpEpoch {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
exp, err := strconv.ParseUint(a.Value(), 10, 64)
|
return strconv.ParseUint(a.Value(), 10, 64)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp < v.netState.CurrentEpoch() {
|
|
||||||
return errExpired
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return 0, errNoExpirationEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNetState returns options to set network state interface.
|
// WithNetState returns options to set network state interface.
|
||||||
|
|
Loading…
Reference in a new issue