blob: dfbfa208d27b7b96a9462b6a3b6e878a5c091d0a [file] [log] [blame]
/* Copyright 2016 Google Inc.
*
* 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 "region.hh"
#include <endian.h>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <string>
#include "dcdir_structs.h"
#include "image.hh"
using ::std::cerr;
using ::std::endl;
using ::std::string;
namespace dcdir
{
void Region::process_as_directory(const ImageBuffer &image)
{
uint32_t table_offset = offset() + base();
// Read in and verify the directory header.
DcDirDirectoryHeader *header;
image.pointer_to(table_offset, header);
if (memcmp(header->signature, DcDirDirectorySignature,
DcDirDirectorySignatureSize) != 0) {
cerr << "Corrupted directory \"" << name() << "\"." << endl;
exit(1);
}
// Compute the directory table size.
table_size_ = (header->size[0] << 0) |
(header->size[1] << 8) |
(header->size[2] << 16);
table_size_ = (table_size_ + 1) * 8;
assert(base() + table_size_ <= length());
uint32_t pos = table_offset + sizeof(DcDirDirectoryHeader);
// Process each entry in this directory.
const int label_length = 8;
char clabel[label_length + 1];
clabel[label_length] = '\0';
while (pos < table_offset + table_size_) {
uint64_t *label_ptr;
image.pointer_to(pos, label_ptr);
memcpy(clabel, label_ptr, label_length);
pos += label_length;
string label(clabel);
Region *sub_region = new Region(image, label, offset(), pos);
entries_.push_back(sub_region);
pos += sub_region->ptr_size();
}
}
Region::Region(const ImageBuffer &image, const string &new_name,
uint32_t new_base, uint32_t new_offset, uint32_t new_length,
bool new_directory) :
name_(new_name), base_(new_base),
offset_(new_offset), length_(new_length),
ptr_size_(0), type_(0), directory_(new_directory)
{
// We don't have to extract any information out of the pointer to this
// region, but we still need to process its contents if it's a
// directory.
if (directory())
process_as_directory(image);
}
Region::Region(const ImageBuffer &image, const string &new_name,
uint32_t dir_offset, uint32_t ptr_offset) :
name_(new_name), table_size_(0)
{
DcDirPointer *base_ptr;
image.pointer_to(ptr_offset, base_ptr);
// Decode some common fields in the pointer.
ptr_size_ = (base_ptr->size + 1) * 8;
directory_ = base_ptr->type & 0x1;
type_ = base_ptr->type >> 1;
// Decode fields in the pointer who's structure/location depend on the
// pointer's type.
switch (type_)
{
case DcDirOffset24Length24:
{
DcDirPointerOffset24Length24 *ptr;
image.pointer_to(ptr_offset, ptr);
base_ = 0;
offset_ = (ptr->offset[0] << 0) |
(ptr->offset[1] << 8) |
(ptr->offset[2] << 16);
length_ = ((ptr->length[0] << 0) |
(ptr->length[1] << 8) |
(ptr->length[2] << 16)) + 1;
}
break;
case DcDirBase32Offset32Length32:
{
DcDirPointerBase32Offset32Length32 *ptr;
image.pointer_to(ptr_offset, ptr);
base_ = le32toh(ptr->base);
offset_ = le32toh(ptr->offset);
length_ = le32toh(ptr->length) + 1;
}
break;
default:
cerr << "Bad pointer type " << type_ << "." << endl;
exit(1);
}
// Make the offset relative to the image rather than the
// parent directory.
offset_ += dir_offset;
// If this region is a directory, process its contents.
if (directory())
process_as_directory(image);
}
size_t Region::storage_overhead() const
{
// Non-directory regions have no intrinsic overhead.
if (!directory())
return 0;
// Directories have overhead from their tables, and also indirectly
// from the tables in their subdirectories.
size_t overhead = table_size_;
for (const auto &entry: entries_) {
assert(entry);
overhead += entry->storage_overhead();
}
return overhead;
}
} // namespace dcdir