/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "verity/build_verity_tree.h"
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <sparse/sparse.h>
#undef NDEBUG
bool generate_verity_tree(const std::string& data_filename,
const std::string& verity_filename,
HashTreeBuilder* builder,
const std::vector<unsigned char>& salt_content,
size_t block_size, bool sparse, bool verbose) {
android::base::unique_fd data_fd(open(data_filename.c_str(), O_RDONLY));
if (data_fd == -1) {
PLOG(ERROR) << "failed to open " << data_filename;
return false;
}
struct sparse_file* file;
if (sparse) {
file = sparse_file_import(data_fd, false, false);
} else {
file = sparse_file_import_auto(data_fd, false, verbose);
}
if (!file) {
LOG(ERROR) << "failed to read file " << data_filename;
return false;
}
int64_t len = sparse_file_len(file, false, false);
if (len % block_size != 0) {
LOG(ERROR) << "file size " << len << " is not a multiple of " << block_size
<< " byte";
return false;
}
// Initialize the builder to compute the hash tree.
if (!builder->Initialize(len, salt_content)) {
LOG(ERROR) << "Failed to initialize HashTreeBuilder";
return false;
}
auto hash_callback = [](void* priv, const void* data, size_t len) {
auto sparse_hasher = static_cast<HashTreeBuilder*>(priv);
return sparse_hasher->Update(static_cast<const unsigned char*>(data), len)
? 0
: 1;
};
sparse_file_callback(file, false, false, hash_callback, builder);
sparse_file_destroy(file);
if (!builder->BuildHashTree()) {
return false;
}
return builder->WriteHashTreeToFile(verity_filename);
}