blob: abb808563090a0359dea0e631e8e534305a2a3b4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/inspect-vmo/block.h>
#include <lib/inspect-vmo/snapshot.h>
namespace inspect {
namespace vmo {
using internal::Block;
Snapshot::Snapshot(fbl::Array<uint8_t> buffer)
: buffer_(std::move(buffer)) {}
zx_status_t Snapshot::Create(const zx::vmo& vmo, Snapshot* out_snapshot) {
return Snapshot::Create(std::move(vmo), kDefaultOptions, out_snapshot);
}
zx_status_t Snapshot::Create(const zx::vmo& vmo, Options options, Snapshot* out_snapshot) {
return Snapshot::Create(std::move(vmo), std::move(options), nullptr, out_snapshot);
}
zx_status_t Snapshot::Create(const zx::vmo& vmo, Options options, ReadObserver read_observer,
Snapshot* out_snapshot) {
size_t tries_left = options.read_attempts;
zx_status_t status;
fbl::Array<uint8_t> buffer;
while (tries_left-- > 0) {
size_t size;
status = vmo.get_size(&size);
if (status != ZX_OK) {
return status;
}
if (size < sizeof(internal::Block)) {
return ZX_ERR_OUT_OF_RANGE;
}
if (buffer.size() != size) {
buffer.reset(new uint8_t[size], size);
}
status = Snapshot::Read(vmo, sizeof(internal::Block), buffer.begin());
if (status != ZX_OK) {
return status;
}
if (read_observer) {
read_observer(buffer.begin(), sizeof(internal::Block));
}
uint64_t generation;
status = Snapshot::ParseHeader(buffer.begin(), &generation);
if (status != ZX_OK) {
return status;
}
if (!options.skip_consistency_check && generation % 2 != 0) {
continue;
}
status = Snapshot::Read(vmo, size, buffer.begin());
if (status != ZX_OK) {
return status;
}
if (read_observer) {
read_observer(buffer.begin(), sizeof(size));
}
uint64_t new_generation;
status = Snapshot::ParseHeader(buffer.begin(), &new_generation);
if (status != ZX_OK) {
return status;
}
if (!options.skip_consistency_check && generation != new_generation) {
continue;
}
size_t new_size;
if (vmo.get_size(&new_size) != ZX_OK) {
return ZX_ERR_INTERNAL;
}
if (new_size != size) {
continue;
}
*out_snapshot = Snapshot(std::move(buffer));
return ZX_OK;
}
return ZX_ERR_INTERNAL;
}
zx_status_t Snapshot::Read(const zx::vmo& vmo, size_t size, uint8_t* buffer) {
memset(buffer, 0, size);
return vmo.read(buffer, 0, size);
}
zx_status_t Snapshot::ParseHeader(uint8_t* buffer, uint64_t* out_generation_count) {
Block* block = reinterpret_cast<Block*>(buffer);
if (memcmp(&block->header_data[4], kMagicNumber, 4) != 0) {
return ZX_ERR_INTERNAL;
}
*out_generation_count = block->payload.u64;
return ZX_OK;
}
internal::Block* Snapshot::GetBlock(internal::BlockIndex index) const {
if (index >= IndexForOffset(buffer_.size())) {
return nullptr;
}
return reinterpret_cast<internal::Block*>(buffer_.begin() + index * kMinOrderSize);
}
} // namespace vmo
} // namespace inspect