Created
February 9, 2024 20:39
-
-
Save rdnajac/cc327902deb54098dd474076c60e16cc to your computer and use it in GitHub Desktop.
debugging tool for EZFS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <time.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#define timespec64 timespec | |
#include "../ezfs.h" | |
static void print_sb(struct ezfs_super_block *sb); | |
static void print_inode(struct ezfs_inode *inode); | |
static void print_inode_store(struct ezfs_super_block *sb, struct ezfs_inode *inode_store, int inode_n); | |
static void print_dentries(struct ezfs_dir_entry *dentries); | |
static void usage_and_exit(const char *argv0) | |
{ | |
fprintf(stderr, "Usage: %s [-s | -i [<inode_number>] | -d <inode_number> | [-b | -n] <block_number>] [DEVICE_NAME]\n", argv0); | |
exit(EXIT_FAILURE); | |
} | |
static void die(const char *s) | |
{ | |
perror(s); | |
exit(EXIT_FAILURE); | |
} | |
void *read_block(int fd) | |
{ | |
void *block = malloc(EZFS_BLOCK_SIZE); | |
if (block == NULL || read(fd, block, EZFS_BLOCK_SIZE) == -1) { | |
free(block); | |
die(__func__); | |
} | |
return block; | |
} | |
static void print_help(const char *argv0) | |
{ | |
printf("Usage: %s [-s | -i [<inode_number>] | -d <inode_number> | -b <block_number>] [DEVICE_NAME]\n", argv0); | |
printf("Options:\n"); | |
printf(" -s Print super block information\n"); | |
printf(" -i [<inode_number>] Print information for a specific inode number (default: prints all)\n"); | |
printf(" -d <inode_number> Print directory entries at a specific inode number\n"); | |
printf(" -b <block_number> Print data block data for a specific block number\n"); | |
printf(" -n <block_number> Print list of blocks in indirect_blk_n"); | |
printf(" -h Print this help message\n"); | |
printf("DEVICE_NAME Optional device name (default: /dev/loop0)\n"); | |
exit(EXIT_SUCCESS); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int option, print_super = 0, inode_n = 0, dir_inode = 0, blk_n = 0, iblk_n = 0; | |
uint64_t offset = 0, blk_data = 0; | |
while ((option = getopt(argc, argv, "si::d:b:n:h")) != -1) { | |
switch (option) { | |
case 's': | |
print_super = 1; | |
break; | |
case 'i': | |
inode_n = (optarg != NULL) ? atoi(optarg) : -1; | |
break; | |
case 'd': | |
dir_inode = atoi(optarg); | |
break; | |
case 'b': | |
blk_n = atoi(optarg); | |
break; | |
case 'n': | |
iblk_n = atoi(optarg); | |
break; | |
case 'h': | |
print_help(argv[0]); | |
default: | |
usage_and_exit(argv[0]); | |
} | |
} | |
const char *filename = (optind < argc) ? argv[optind] : "/dev/loop0"; | |
int fd = open(filename, O_RDONLY); | |
if (fd == -1) | |
die("Error opening the device"); | |
struct ezfs_super_block *sb = read_block(fd); | |
struct ezfs_inode *inode_store = read_block(fd); | |
if (print_super) | |
print_sb(sb); | |
if (inode_n) | |
print_inode_store(sb, inode_store, inode_n); | |
if (dir_inode) { | |
if (IS_SET(sb->free_inodes, dir_inode - 1)) { | |
offset = EZFS_BLOCK_SIZE * (inode_store[dir_inode - 1].direct_blk_n - 2); | |
lseek(fd, offset, SEEK_CUR); | |
struct ezfs_dir_entry *dentries = read_block(fd); | |
printf("Directory Entries for Inode %d:\n", dir_inode); | |
print_dentries(dentries); | |
free(dentries); | |
} else { | |
die("Invalid or unused directory inode number"); | |
} | |
} | |
if (blk_n >= 2) { | |
offset = (blk_n - 2) * EZFS_BLOCK_SIZE; | |
lseek(fd, offset, SEEK_CUR); | |
printf("Data at blk_n = %d (offset = %lu);\n", blk_n, offset); | |
for (uint64_t bytes = 0; bytes < EZFS_BLOCK_SIZE; ) { | |
bytes += read(fd, &blk_data, sizeof(blk_data)); | |
if (!((bytes / sizeof(uint64_t)) % 8)) | |
printf("\n0x%03lx\t", bytes); | |
printf("%016lx ", blk_data); | |
} | |
printf("\n"); | |
} | |
if (iblk_n >= 2) { | |
offset = (iblk_n - 2) * EZFS_BLOCK_SIZE; | |
lseek(fd, offset, SEEK_CUR); | |
printf("Data at indirect_blk_n = %d (offset = %lu):\n", iblk_n, offset); | |
for (uint64_t bytes = 0; bytes < EZFS_BLOCK_SIZE; ) { | |
bytes += read(fd, &blk_data, sizeof(blk_data)); | |
if (!blk_data) | |
break; | |
printf("%lu\n", blk_data); | |
} | |
printf("\n"); | |
} | |
free(sb); | |
free(inode_store); | |
close(fd); | |
return EXIT_SUCCESS; | |
} | |
static void print_sb(struct ezfs_super_block *sb) | |
{ | |
int count = 0; | |
printf("ezfs_super_block info:\n"); | |
printf("version: %lu\n", sb->version); | |
printf("magic: 0x%lx\n", sb->magic); | |
printf("disk_blks: %lu\n", sb->disk_blks); | |
printf("EZFS_BLOCK_SIZE: %d\n", EZFS_BLOCK_SIZE); | |
printf("EZFS_MAX_INODES = EZFS_BLOCK_SIZE / sizeof(struct ezfs_inode) = %d / %lu = %lu\n", | |
EZFS_BLOCK_SIZE, sizeof(struct ezfs_inode), EZFS_MAX_INODES); | |
printf("EZFS_MAX_CHILDREN = EZFS_BLOCK_SIZE / sizeof(struct ezfs_dir_entry) = %d / %lu = %lu\n", | |
EZFS_BLOCK_SIZE, sizeof(struct ezfs_dir_entry), EZFS_MAX_CHILDREN); | |
printf("EZFS_MAX_DATA_BLKS: %lu\n", EZFS_MAX_DATA_BLKS); | |
printf("\ninode bit vector: "); | |
for (size_t i = 0; i < EZFS_MAX_INODES; i++) { | |
if (IS_SET(sb->free_inodes, i)) { | |
printf("1"); | |
count++; | |
} else { | |
printf("0"); | |
} | |
} | |
printf("\t %d/%ld free", count, EZFS_MAX_INODES); | |
printf("\n\ndata block bit vector:\n"); | |
for (size_t i = 0; i < sb->disk_blks; ++i) { | |
if (i % 64 == 0) | |
printf("\n0x%03lx\t", i); | |
printf("%d", IS_SET(sb->free_data_blocks, i) ? 1 : 0); | |
if (i % 32 == 31) | |
printf(" "); | |
} | |
printf("\n"); | |
} | |
static void print_inode_store(struct ezfs_super_block *sb, | |
struct ezfs_inode *inode_store, int inode_n) | |
{ | |
if (inode_n > 0) { | |
if (IS_SET(sb->free_inodes, inode_n - 1)) { | |
printf("Inode %d:\n", inode_n); | |
print_inode(&inode_store[inode_n - 1]); | |
} else { | |
die("Invalid or unused inode number"); | |
} | |
} | |
if (inode_n == -1) { | |
for (int i = 0; i < EZFS_MAX_INODES; ++i) { | |
if (IS_SET(sb->free_inodes, i)) { | |
printf("Inode %d:\n", i + 1); | |
print_inode(&inode_store[i]); | |
} | |
} | |
} | |
} | |
static void print_inode(struct ezfs_inode *inode) | |
{ | |
printf("Mode: %o\n", inode->mode); | |
printf("UID: %u\n", inode->uid); | |
printf("GID: %u\n", inode->gid); | |
printf("Access Time: %ld\n", inode->i_atime.tv_sec); | |
printf("Modified Time: %ld\n", inode->i_mtime.tv_sec); | |
printf("Change Time: %ld\n", inode->i_ctime.tv_sec); | |
printf("Number of Links: %u\n", inode->nlink); | |
printf("Direct Block Number: %lu\n", inode->direct_blk_n); | |
printf("Indirect Block Number: %lu\n", inode->indirect_blk_n); | |
printf("File Size: %lu\n", inode->file_size); | |
printf("Number of Blocks: %lu\n", inode->nblocks); | |
printf("\n"); | |
} | |
static void print_dentries(struct ezfs_dir_entry *dentry) | |
{ | |
for (int i = 0; i < EZFS_MAX_CHILDREN; i++) | |
printf("%d:\tinode_no: %lu\tfilename: %s\t%s\n", | |
i, dentry[i].inode_no, dentry[i].filename, | |
dentry[i].active ? "active" : "inactive"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment