blob: cfbb711bdad88d0d88803eb7c2c4dac9f4797430 [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 <fcntl.h>
#include <lib/fdio/io.h>
#include <stdio.h>
#include <zircon/syscalls.h>
#include <digest/digest.h>
#include <digest/merkle-tree.h>
#include <fbl/string.h>
#include <fbl/unique_fd.h>
#include <fs-test-utils/blobfs/blobfs.h>
namespace fs_test_utils {
using digest::Digest;
using digest::MerkleTreeCreator;
using digest::MerkleTreeVerifier;
using BlobSrcFunction = void (*)(char* data, size_t length);
void RandomFill(char* data, size_t length) {
static unsigned int seed = static_cast<unsigned int>(zx_ticks_get());
// TODO(US-286): Make this easier to reproduce with reliably generated prng.
printf("RandomFill of %zu bytes with seed: %u\n", length, seed);
for (size_t i = 0; i < length; i++) {
data[i] = (char)rand_r(&seed);
}
}
// Creates, writes, reads (to verify) and operates on a blob.
// Returns the result of the post-processing 'func' (true == success).
bool GenerateBlob(BlobSrcFunction sourceCb, fbl::String mount_path, size_t size_data,
std::unique_ptr<BlobInfo>* out) {
std::unique_ptr<BlobInfo> info(new BlobInfo);
info->data.reset(new char[size_data]);
sourceCb(info->data.get(), size_data);
info->size_data = size_data;
// Generate the Merkle Tree
Digest digest;
std::unique_ptr<uint8_t[]> tree;
zx_status_t status = MerkleTreeCreator::Create(info->data.get(), info->size_data, &tree,
&info->size_merkle, &digest);
info->merkle.reset(reinterpret_cast<char*>(tree.release()));
if (status != ZX_OK) {
printf("Couldn't create Merkle Tree\n");
return false;
}
snprintf(info->path, sizeof(info->path), "%s/%s", mount_path.c_str(), digest.ToString().c_str());
// Sanity-check the merkle tree
status = MerkleTreeVerifier::Verify(info->data.get(), info->size_data, 0, info->size_data,
info->merkle.get(), info->size_merkle, digest);
if (status != ZX_OK) {
printf("Failed to validate Merkle Tree\n");
return false;
}
*out = std::move(info);
return true;
}
bool GenerateRandomBlob(fbl::String mount_path, size_t size_data, std::unique_ptr<BlobInfo>* out) {
return GenerateBlob(RandomFill, mount_path, size_data, out);
}
bool VerifyContents(int fd, const char* data, size_t size_data) {
// Verify the contents of the Blob.
constexpr size_t kReadSize = 8192;
std::unique_ptr<char[]> buffer(new char[kReadSize]);
if (lseek(fd, 0, SEEK_SET) != 0) {
printf("Failed to seek to start\n");
return false;
}
size_t total_read = 0;
while (total_read != size_data) {
ssize_t result = read(fd, buffer.get(), kReadSize);
if (result <= 0) {
printf("Failed to read file. Result: %li\n", result);
return false;
}
if (memcmp(buffer.get(), &data[total_read], result) != 0) {
printf("Blob contents differ\n");
return false;
}
total_read += result;
}
return true;
}
} // namespace fs_test_utils