mirror of
https://github.com/etcd-io/bbolt.git
synced 2025-05-01 13:13:32 +00:00
This commit adds checksums to the meta pages on every write. When the database loads, it verifies the checksums on the meta pages and returns an error if either one is corrupt. In the future, it should fallback to the previous meta page but for right now it just hard fails. This is at least preferable to opening the database and getting a random error or further corruption. Fixes #25.
70 lines
1.5 KiB
Go
70 lines
1.5 KiB
Go
package bolt
|
|
|
|
import (
|
|
"errors"
|
|
"hash/fnv"
|
|
"unsafe"
|
|
)
|
|
|
|
const magic uint32 = 0xED0CDAED
|
|
|
|
var (
|
|
// ErrInvalid is returned when a data file is not a Bolt-formatted database.
|
|
ErrInvalid = errors.New("invalid database")
|
|
|
|
// ErrVersionMismatch is returned when the data file was created with a
|
|
// different version of Bolt.
|
|
ErrVersionMismatch = errors.New("version mismatch")
|
|
|
|
// ErrChecksum is returned when either meta page checksum does not match.
|
|
ErrChecksum = errors.New("checksum error")
|
|
)
|
|
|
|
type meta struct {
|
|
magic uint32
|
|
version uint32
|
|
pageSize uint32
|
|
flags uint32
|
|
buckets pgid
|
|
freelist pgid
|
|
pgid pgid
|
|
txid txid
|
|
checksum uint64
|
|
}
|
|
|
|
// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
|
|
func (m *meta) validate() error {
|
|
if m.checksum != 0 && m.checksum != m.sum64() {
|
|
return ErrChecksum
|
|
} else if m.magic != magic {
|
|
return ErrInvalid
|
|
} else if m.version != version {
|
|
return ErrVersionMismatch
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// copy copies one meta object to another.
|
|
func (m *meta) copy(dest *meta) {
|
|
*dest = *m
|
|
}
|
|
|
|
// write writes the meta onto a page.
|
|
func (m *meta) write(p *page) {
|
|
// Page id is either going to be 0 or 1 which we can determine by the transaction ID.
|
|
p.id = pgid(m.txid % 2)
|
|
p.flags |= metaPageFlag
|
|
|
|
// Calculate the checksum.
|
|
m.checksum = m.sum64()
|
|
|
|
m.copy(p.meta())
|
|
}
|
|
|
|
// generates the checksum for the meta.
|
|
func (m *meta) sum64() uint64 {
|
|
var h = fnv.New64a()
|
|
_, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
|
|
return h.Sum64()
|
|
}
|