blob: 80184b8399b3889694aeb8f62103c374ddf895b1 [file] [log] [blame]
// Copyright 2017 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 <inttypes.h>
#include <fbl/unique_fd.h>
#include <utility>
#include "fvm-host/container.h"
zx_status_t Container::Create(const char* path, off_t offset, off_t length,
uint32_t flags, fbl::unique_ptr<Container>* container) {
if ((flags & ~fvm::kSparseFlagAllValid) != 0) {
fprintf(stderr, "Invalid flags: %08" PRIx32 "\n", flags);
return -1;
}
fbl::unique_fd fd(open(path, O_RDONLY));
if (!fd) {
fprintf(stderr, "Unable to open path %s\n", path);
return -1;
}
uint8_t data[HEADER_SIZE];
if (lseek(fd.get(), offset, SEEK_SET) < 0) {
fprintf(stderr, "Error seeking block device\n");
return -1;
}
if (read(fd.get(), data, sizeof(data)) != sizeof(data)) {
fprintf(stderr, "Error reading block device\n");
return -1;
}
if (!memcmp(data, fvm_magic, sizeof(fvm_magic))) {
fvm::fvm_t* sb = reinterpret_cast<fvm::fvm_t*>(data);
// Found fvm container
fbl::unique_ptr<Container> fvmContainer(new FvmContainer(path, sb->slice_size,
offset, length));
*container = std::move(fvmContainer);
return ZX_OK;
}
fvm::sparse_image_t* image = reinterpret_cast<fvm::sparse_image_t*>(data);
if (image->magic == fvm::kSparseFormatMagic) {
if (offset > 0) {
fprintf(stderr, "Invalid offset for sparse file\n");
return ZX_ERR_INVALID_ARGS;
}
// Found sparse container
fbl::unique_ptr<Container> sparseContainer(new SparseContainer(path, image->slice_size,
flags));
*container = std::move(sparseContainer);
return ZX_OK;
}
fprintf(stderr, "File format not supported\n");
return ZX_ERR_NOT_SUPPORTED;
}
Container::Container(const char* path, size_t slice_size, uint32_t flags)
: slice_size_(slice_size), flags_(flags) {
path_.AppendPrintf("%s", path);
}
Container::~Container() {}
uint64_t Container::CalculateDiskSizeForSlices(size_t slice_count) const {
uint64_t data_size = slice_count * slice_size_;
uint64_t total_size = 0;
size_t metadata_size = 0;
// This loop will necessarily break at some point. The re-calculation of total_size and
// metadata_size will cause both of these values to increase, except on the last iteration
// where metadata_size will not change, causing the loop condition to become false.
// metadata_size *must* stop increasing at some point, since the data_size is always a fixed
// value, and the metadata by itself will not grow fast enough to necessitate its continued
// growth at the same or higher rate.
// As an example, with the current metadata size calculation and a slice size of 8192 bytes,
// around ~8mb of disk space will require metadata growth of only ~8kb. Even if the
// metadata_size grows very quickly at first, this amount will diminish very quickly until it
// reaches 0.
do {
total_size = data_size + (metadata_size * 2);
metadata_size = fvm::MetadataSize(total_size, slice_size_);
} while (total_size - (metadata_size * 2) < data_size);
return total_size;
}