1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <inttypes.h>
6
7 #include <fbl/unique_fd.h>
8
9 #include <utility>
10
11 #include "fvm-host/container.h"
12
Create(const char * path,off_t offset,off_t length,uint32_t flags,fbl::unique_ptr<Container> * container)13 zx_status_t Container::Create(const char* path, off_t offset, off_t length,
14 uint32_t flags, fbl::unique_ptr<Container>* container) {
15 if ((flags & ~fvm::kSparseFlagAllValid) != 0) {
16 fprintf(stderr, "Invalid flags: %08" PRIx32 "\n", flags);
17 return -1;
18 }
19
20 fbl::unique_fd fd(open(path, O_RDONLY));
21 if (!fd) {
22 fprintf(stderr, "Unable to open path %s\n", path);
23 return -1;
24 }
25
26 uint8_t data[HEADER_SIZE];
27 if (lseek(fd.get(), offset, SEEK_SET) < 0) {
28 fprintf(stderr, "Error seeking block device\n");
29 return -1;
30 }
31
32 if (read(fd.get(), data, sizeof(data)) != sizeof(data)) {
33 fprintf(stderr, "Error reading block device\n");
34 return -1;
35 }
36
37 if (!memcmp(data, fvm_magic, sizeof(fvm_magic))) {
38 fvm::fvm_t* sb = reinterpret_cast<fvm::fvm_t*>(data);
39
40 // Found fvm container
41 fbl::unique_ptr<Container> fvmContainer(new FvmContainer(path, sb->slice_size,
42 offset, length));
43 *container = std::move(fvmContainer);
44 return ZX_OK;
45 }
46
47 fvm::sparse_image_t* image = reinterpret_cast<fvm::sparse_image_t*>(data);
48 if (image->magic == fvm::kSparseFormatMagic) {
49 if (offset > 0) {
50 fprintf(stderr, "Invalid offset for sparse file\n");
51 return ZX_ERR_INVALID_ARGS;
52 }
53
54 // Found sparse container
55 fbl::unique_ptr<Container> sparseContainer(new SparseContainer(path, image->slice_size,
56 flags));
57 *container = std::move(sparseContainer);
58 return ZX_OK;
59 }
60
61 fprintf(stderr, "File format not supported\n");
62 return ZX_ERR_NOT_SUPPORTED;
63 }
64
Container(const char * path,size_t slice_size,uint32_t flags)65 Container::Container(const char* path, size_t slice_size, uint32_t flags)
66 : slice_size_(slice_size), flags_(flags) {
67 path_.AppendPrintf("%s", path);
68 }
69
~Container()70 Container::~Container() {}
71
CalculateDiskSizeForSlices(size_t slice_count) const72 uint64_t Container::CalculateDiskSizeForSlices(size_t slice_count) const {
73 uint64_t data_size = slice_count * slice_size_;
74 uint64_t total_size = 0;
75 size_t metadata_size = 0;
76
77 // This loop will necessarily break at some point. The re-calculation of total_size and
78 // metadata_size will cause both of these values to increase, except on the last iteration
79 // where metadata_size will not change, causing the loop condition to become false.
80 // metadata_size *must* stop increasing at some point, since the data_size is always a fixed
81 // value, and the metadata by itself will not grow fast enough to necessitate its continued
82 // growth at the same or higher rate.
83 // As an example, with the current metadata size calculation and a slice size of 8192 bytes,
84 // around ~8mb of disk space will require metadata growth of only ~8kb. Even if the
85 // metadata_size grows very quickly at first, this amount will diminish very quickly until it
86 // reaches 0.
87 do {
88 total_size = data_size + (metadata_size * 2);
89 metadata_size = fvm::MetadataSize(total_size, slice_size_);
90 } while (total_size - (metadata_size * 2) < data_size);
91
92 return total_size;
93 }
94