#include #include #include #include #include #include #include #include #define int8 int8_t #define int16 int16_t #define int32 int32_t #define int64 int64_t #define uint8 uint8_t #define uint16 uint16_t #define uint32 uint32_t #define uint64 uint64_t typedef int64 bfs_off_t; struct block_run { int32 allocation_group; uint16 start; uint16 length; }; typedef block_run inode_addr; #define BFS_DISK_NAME_LENGTH 32 struct disk_super_block { char name[BFS_DISK_NAME_LENGTH]; int32 magic1; int32 fs_byte_order; uint32 block_size; uint32 block_shift; bfs_off_t num_blocks; bfs_off_t used_blocks; int32 inode_size; int32 magic2; int32 blocks_per_ag; int32 ag_shift; int32 num_ags; int32 flags; block_run log_blocks; bfs_off_t log_start; bfs_off_t log_end; int32 magic3; inode_addr root_dir; inode_addr indices; int32 pad[8]; }; #define SUPER_BLOCK_MAGIC1 'BFS1' /* BFS1 */ const char *kHexDigits = "0123456789abcdef"; static void read_from(int fd, off_t pos, void *buffer, size_t size) { if (lseek(fd, pos, SEEK_SET) < 0 || read(fd, buffer, size) != (int)size) { fprintf(stderr, "Error: Failed to read %lu bytes at offset %lld\n", size, pos); exit(1); } } static void write_to(int fd, off_t pos, const void *buffer, size_t size) { if (lseek(fd, pos, SEEK_SET) < 0 || write(fd, buffer, size) != (int)size) { fprintf(stderr, "Error: Failed to write %lu bytes at offset %lld\n", size, pos); exit(1); } } static int count_bits(int value) { int count = 0; while (value) { if (value & 1) count++; value >>= 1; } return count; } int main(int argc, const char *const *argv) { if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: %s [ ]\n", argv[0]); exit(1); } const char *fileName = argv[1]; const char *patternString = (argc >= 3 ? argv[2] : "0f"); // skip leading "0x" in the pattern string if (strncmp(patternString, "0x", 2) == 0) patternString += 2; // translate the pattern uint8 *pattern = new uint8[strlen(patternString) / 2 + 1]; int patternLen = 0; for (; *patternString; patternString++) { if (!isspace(*patternString)) { char c = *patternString; const char *digitPos = strchr(kHexDigits, tolower(c)); if (!digitPos) { fprintf(stderr, "Error: Invalid pattern character: \"%c\"\n", c); exit(1); } int digit = digitPos - kHexDigits; if (patternLen & 1) pattern[patternLen / 2] |= digit; else pattern[patternLen / 2] = digit << 4; patternLen++; } } if (patternLen == 0 || (patternLen & 1)) { fprintf(stderr, "Error: Invalid pattern! Must have even number (>= 2) " "of hex digits.\n"); exit(1); } patternLen /= 2; // is now length in bytes printf("bfs_fragmenter: using pattern: 0x"); for (int i = 0; i < patternLen; i++) printf("%02x", pattern[i]); printf("\n"); // open file int fd = open(fileName, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(errno)); exit(1); } // read superblock disk_super_block superBlock; read_from(fd, 512, &superBlock, sizeof(superBlock)); if (superBlock.magic1 != SUPER_BLOCK_MAGIC1) { fprintf(stderr, "Error: Bad superblock magic. This is probably not a " "BFS image.\n"); exit(1); } int blockSize = superBlock.block_size; // stat the image struct stat st; if (fstat(fd, &st) < 0) { fprintf(stderr, "Error: Failed to stat image: %s\n", strerror(errno)); exit(1); } int64 blockCount = st.st_size / blockSize; if (blockCount != superBlock.num_blocks) { fprintf(stderr, "Error: Number of blocks in image and the number in " "the superblock differ: %lld vs. %lld\n", blockCount, superBlock.num_blocks); exit(1); } // iterate through the block bitmap blocks and or the bytes with 0x0f uint8 *block = new uint8[blockSize]; int64 occupiedBlocks = 0; int64 bitmapByteCount = blockCount / 8; // round down, we ignore the // last partial byte int64 bitmapBlockCount = (bitmapByteCount + blockSize - 1) / blockSize; int bitmapByteIndex = 0; for (int i = 1; i < bitmapBlockCount + 1; i++) { off_t offset = i * blockSize; read_from(fd, offset, block, blockSize); int toProcess = blockSize; if (toProcess > bitmapByteCount - bitmapByteIndex) toProcess = (bitmapByteCount - bitmapByteIndex); for (int k = 0; k < toProcess; k++) { uint8 patternChar = pattern[bitmapByteIndex % patternLen]; occupiedBlocks += count_bits(~block[k] & patternChar); block[k] |= patternChar; bitmapByteIndex++; } write_to(fd, offset, block, blockSize); } printf("bfs_fragmenter: marked %lld blocks used\n", occupiedBlocks); // write back the superblock superBlock.used_blocks += occupiedBlocks; write_to(fd, 512, &superBlock, sizeof(superBlock)); return 0; }