* Copyright 2005, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "bfs.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
extern const char *__progname;
static const char *sProgramName = __progname;
static bool sDumpBlocks = false;
bool
disk_super_block::IsValid()
{
if (Magic1() != (int32)SUPER_BLOCK_MAGIC1
|| Magic2() != (int32)SUPER_BLOCK_MAGIC2
|| Magic3() != (int32)SUPER_BLOCK_MAGIC3
|| (int32)block_size != inode_size
|| ByteOrder() != SUPER_BLOCK_FS_LENDIAN
|| (1UL << BlockShift()) != BlockSize()
|| AllocationGroups() < 1
|| AllocationGroupShift() < 1
|| BlocksPerAllocationGroup() < 1
|| NumBlocks() < 10
|| AllocationGroups() != divide_roundup(NumBlocks(),
1L << AllocationGroupShift()))
return false;
return true;
}
off_t
toBlock(disk_super_block &superBlock, block_run run)
{
return ((((off_t)run.AllocationGroup()) << superBlock.AllocationGroupShift()) | (off_t)run.Start());
}
off_t
toOffset(disk_super_block &superBlock, block_run run)
{
return toBlock(superBlock, run) << superBlock.BlockShift();
}
void
dumpBlock(const char *buffer, int size)
{
const int blockSize = 16;
printf("\t");
for (int i = 0; i < size;) {
int start = i;
for (; i < start + blockSize; i++) {
if (!(i % 4))
printf(" ");
if (i >= size)
printf(" ");
else
printf("%02x", *(unsigned char *)(buffer+i));
}
printf(" ");
for (i = start; i < start + blockSize; i++) {
if (i < size) {
char c = *(buffer+i);
if (c < 30)
printf(".");
else
printf("%c", c);
}
else
break;
}
if (i < size)
printf("\n\t");
else
printf("\n");
}
}
void
dumpLogEntry(int device, disk_super_block &superBlock, int32 &start, uint8 *block)
{
int32 blockSize = superBlock.BlockSize();
int32 entry = 0;
off_t count = 1;
int32 arrayBlocks = 1;
off_t blockStart = start;
bool first = true;
int32 indexOffset = -1;
int32 index = 0;
off_t dataStart = blockStart;
off_t bitmapSize = superBlock.AllocationGroups() * superBlock.BlocksPerAllocationGroup();
uint8 *data = NULL;
if (sDumpBlocks)
data = (uint8 *)malloc(blockSize);
for (int32 i = 0; i < arrayBlocks; i++) {
off_t blockNumber = toBlock(superBlock, superBlock.log_blocks)
+ blockStart++ % superBlock.log_blocks.Length();
if (read_pos(device, blockNumber << superBlock.BlockShift(),
block, blockSize) != blockSize) {
fprintf(stderr, "%s: could not read block %lld.\n", sProgramName, blockNumber);
exit(-1);
}
off_t *array = (off_t *)block;
int32 arraySize = blockSize / sizeof(off_t);
if (first) {
count = array[0];
arrayBlocks = ((count + 1) * sizeof(off_t) + blockSize - 1) / blockSize;
arraySize--;
dataStart += arrayBlocks;
start += arrayBlocks + count;
printf("Entry %ld contains %lld blocks (entry starts at block %lld):\n", entry, count, blockNumber);
first = false;
} else
indexOffset += arraySize;
for (; index < count; index++) {
int32 arrayIndex = index - indexOffset;
if (arrayIndex >= arraySize)
break;
off_t value = array[arrayIndex];
printf("%7ld: %lld%s\n", index, value, value == 0 ? " (superblock)" :
value < bitmapSize + 1 ? " (bitmap block)" : "");
if (data != NULL) {
off_t blockNumber = toBlock(superBlock, superBlock.log_blocks)
+ ((dataStart + index) % superBlock.log_blocks.Length());
if (read_pos(device, blockNumber << superBlock.BlockShift(),
data, blockSize) != blockSize) {
fprintf(stderr, "%s: could not read block %lld.\n", sProgramName, blockNumber);
} else
dumpBlock((char *)data, blockSize);
}
}
}
free(data);
}
void
usage(void)
{
fprintf(stderr, "usage: %s [-d] bfs-volume\n"
" -d\tdump blocks in log\n", sProgramName);
exit(0);
}
int
main(int argc, char **argv)
{
if (argc < 2 || !strcmp(argv[1], "--help"))
usage();
while (*++argv) {
char *arg = *argv;
if (*arg == '-') {
while (*++arg && isalpha(*arg)) {
switch (*arg) {
case 'd':
sDumpBlocks = true;
break;
default:
usage();
}
}
}
else
break;
}
char *devicePath = argv[0];
int device = open(devicePath, O_RDONLY);
if (device < 0) {
fprintf(stderr, "%s: could not open device %s: %s\n",
sProgramName, devicePath, strerror(errno));
return -1;
}
disk_super_block superBlock;
if (read_pos(device, 512, &superBlock, sizeof(disk_super_block)) < (ssize_t)sizeof(disk_super_block)) {
fprintf(stderr, "%s: could not read superblock.\n", sProgramName);
return -1;
}
if (!superBlock.IsValid()) {
fprintf(stderr, "%s: invalid superblock!\n", sProgramName);
return -1;
}
if (superBlock.Flags() == SUPER_BLOCK_DISK_CLEAN) {
printf("volume is clean; log is empty.\n");
return 0;
}
off_t bitmapSize = superBlock.AllocationGroups() * superBlock.BlocksPerAllocationGroup();
printf("Log area = (%lld - %lld), current start = %lld, end = %lld, %lld bitmap blocks\n",
toBlock(superBlock, superBlock.log_blocks),
toBlock(superBlock, superBlock.log_blocks) + superBlock.log_blocks.Length(),
superBlock.LogStart(), superBlock.LogEnd(), bitmapSize);
uint8 *block = (uint8 *)malloc(superBlock.BlockSize());
if (block == NULL) {
fprintf(stderr, "%s: could not allocate block!\n", sProgramName);
return -1;
}
int32 start = superBlock.LogStart();
int32 lastStart = -1;
while (true) {
if (start == superBlock.LogEnd())
break;
if (start == lastStart)
break;
lastStart = start;
dumpLogEntry(device, superBlock, start, block);
}
close(device);
return 0;
}