/* blocklist.c - print the block list of a file */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2006,2007 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include #include #include #include #include VAS_EBOOT_MOD_LICENSE ("GPLv3+"); /* Context for VasEBoot_cmd_blocklist. */ struct blocklist_ctx { unsigned long start_sector; unsigned num_sectors; int num_entries; VasEBoot_disk_addr_t part_start; }; /* Helper for VasEBoot_cmd_blocklist. */ static void print_blocklist (VasEBoot_disk_addr_t sector, unsigned num, unsigned offset, unsigned length, struct blocklist_ctx *ctx) { if (ctx->num_entries++) VasEBoot_printf (","); VasEBoot_printf ("%llu", (unsigned long long) (sector - ctx->part_start)); if (num > 0) VasEBoot_printf ("+%u", num); if (offset != 0 || length != 0) VasEBoot_printf ("[%u-%u]", offset, offset + length); } /* Helper for VasEBoot_cmd_blocklist. */ static VasEBoot_err_t read_blocklist (VasEBoot_disk_addr_t sector, unsigned offset, unsigned length, char *buf __attribute__ ((unused)), void *data) { struct blocklist_ctx *ctx = data; if (ctx->num_sectors > 0) { if (ctx->start_sector + ctx->num_sectors == sector && offset == 0 && length >= VAS_EBOOT_DISK_SECTOR_SIZE) { ctx->num_sectors += length >> VAS_EBOOT_DISK_SECTOR_BITS; sector += length >> VAS_EBOOT_DISK_SECTOR_BITS; length &= (VAS_EBOOT_DISK_SECTOR_SIZE - 1); } if (!length) return VAS_EBOOT_ERR_NONE; print_blocklist (ctx->start_sector, ctx->num_sectors, 0, 0, ctx); ctx->num_sectors = 0; } if (offset) { unsigned l = length + offset; l &= (VAS_EBOOT_DISK_SECTOR_SIZE - 1); l -= offset; print_blocklist (sector, 0, offset, l, ctx); length -= l; sector++; offset = 0; } if (!length) return VAS_EBOOT_ERR_NONE; if (length & (VAS_EBOOT_DISK_SECTOR_SIZE - 1)) { if (length >> VAS_EBOOT_DISK_SECTOR_BITS) { print_blocklist (sector, length >> VAS_EBOOT_DISK_SECTOR_BITS, 0, 0, ctx); sector += length >> VAS_EBOOT_DISK_SECTOR_BITS; } print_blocklist (sector, 0, 0, length & (VAS_EBOOT_DISK_SECTOR_SIZE - 1), ctx); } else { ctx->start_sector = sector; ctx->num_sectors = length >> VAS_EBOOT_DISK_SECTOR_BITS; } return VAS_EBOOT_ERR_NONE; } static VasEBoot_err_t VasEBoot_cmd_blocklist (VasEBoot_command_t cmd __attribute__ ((unused)), int argc, char **args) { VasEBoot_file_t file; char buf[VAS_EBOOT_DISK_SECTOR_SIZE]; struct blocklist_ctx ctx = { .start_sector = 0, .num_sectors = 0, .num_entries = 0, .part_start = 0 }; if (argc < 1) return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, N_("filename expected")); file = VasEBoot_file_open (args[0], VAS_EBOOT_FILE_TYPE_PRINT_BLOCKLIST | VAS_EBOOT_FILE_TYPE_NO_DECOMPRESS); if (! file) return VasEBoot_errno; if (! file->device->disk) return VasEBoot_error (VAS_EBOOT_ERR_BAD_DEVICE, "this command is available only for disk devices"); ctx.part_start = VasEBoot_partition_get_start (file->device->disk->partition); file->read_hook = read_blocklist; file->read_hook_data = &ctx; while (VasEBoot_file_read (file, buf, sizeof (buf)) > 0) ; if (ctx.num_sectors > 0) print_blocklist (ctx.start_sector, ctx.num_sectors, 0, 0, &ctx); VasEBoot_file_close (file); return VasEBoot_errno; } static VasEBoot_command_t cmd; VAS_EBOOT_MOD_INIT(blocklist) { cmd = VasEBoot_register_command ("blocklist", VasEBoot_cmd_blocklist, N_("FILE"), N_("Print a block list.")); } VAS_EBOOT_MOD_FINI(blocklist) { VasEBoot_unregister_command (cmd); }