storj/storagenode/orders/ordersfile/v0.go
Moby von Briesen 53ba01b1f1 storagenode/orders/ordersfile/v0.go: Return ErrEntryCorrupt on pb.Unmarshal failure
In V0 orders files, unexpected EOF is correctly treated as a file
corruption, but pb.Unmarshal can also fail, and this is not treated as a
file corruption. This commit fixes that.

Change-Id: I6b446a10f4b1a5a44e832cbcc9bf8b2548cfcfeb
2020-10-26 17:38:22 +00:00

127 lines
2.9 KiB
Go

// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package ordersfile
import (
"encoding/binary"
"errors"
"io"
"os"
"storj.io/common/pb"
)
// fileV0 is a version 0 orders file.
type fileV0 struct {
f *os.File
}
// OpenWritableV0 opens for writing the unsent or archived orders file at a given path.
func OpenWritableV0(path string) (Writable, error) {
// create file if not exists or append
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, Error.Wrap(err)
}
return &fileV0{
f: f,
}, nil
}
// OpenReadableV0 opens for reading the unsent or archived orders file at a given path.
func OpenReadableV0(path string) (Readable, error) {
f, err := os.Open(path)
if err != nil {
return nil, Error.Wrap(err)
}
return &fileV0{
f: f,
}, nil
}
// Append writes limit and order to the file as
// [limitSize][limitBytes][orderSize][orderBytes].
func (of *fileV0) Append(info *Info) error {
toWrite := []byte{}
limitSerialized, err := pb.Marshal(info.Limit)
if err != nil {
return Error.Wrap(err)
}
orderSerialized, err := pb.Marshal(info.Order)
if err != nil {
return Error.Wrap(err)
}
limitSizeBytes := [4]byte{}
binary.LittleEndian.PutUint32(limitSizeBytes[:], uint32(len(limitSerialized)))
orderSizeBytes := [4]byte{}
binary.LittleEndian.PutUint32(orderSizeBytes[:], uint32(len(orderSerialized)))
toWrite = append(toWrite, limitSizeBytes[:]...)
toWrite = append(toWrite, limitSerialized...)
toWrite = append(toWrite, orderSizeBytes[:]...)
toWrite = append(toWrite, orderSerialized...)
if _, err = of.f.Write(toWrite); err != nil {
return Error.New("Couldn't write serialized order and limit: %w", err)
}
return nil
}
// ReadOne reads one entry from the file.
func (of *fileV0) ReadOne() (info *Info, err error) {
defer func() {
if errors.Is(err, io.ErrUnexpectedEOF) {
err = ErrEntryCorrupt.Wrap(err)
}
}()
sizeBytes := [4]byte{}
_, err = io.ReadFull(of.f, sizeBytes[:])
if err != nil {
return nil, Error.Wrap(err)
}
limitSize := binary.LittleEndian.Uint32(sizeBytes[:])
limitSerialized := make([]byte, limitSize)
_, err = io.ReadFull(of.f, limitSerialized)
if err != nil {
return nil, Error.Wrap(err)
}
limit := &pb.OrderLimit{}
err = pb.Unmarshal(limitSerialized, limit)
if err != nil {
return nil, Error.Wrap(err)
}
_, err = io.ReadFull(of.f, sizeBytes[:])
if err != nil {
return nil, Error.Wrap(err)
}
orderSize := binary.LittleEndian.Uint32(sizeBytes[:])
orderSerialized := make([]byte, orderSize)
_, err = io.ReadFull(of.f, orderSerialized)
if err != nil {
return nil, Error.Wrap(err)
}
order := &pb.Order{}
err = pb.Unmarshal(orderSerialized, order)
if err != nil {
// if there is an error unmarshalling, the file must be corrupt
return nil, ErrEntryCorrupt.Wrap(err)
}
return &Info{
Limit: limit,
Order: order,
}, nil
}
// Close closes the file.
func (of *fileV0) Close() error {
return of.f.Close()
}