1 2 #include <ctype.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <stdint.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <unistd.h> 10 11 #define int8 int8_t 12 #define int16 int16_t 13 #define int32 int32_t 14 #define int64 int64_t 15 #define uint8 uint8_t 16 #define uint16 uint16_t 17 #define uint32 uint32_t 18 #define uint64 uint64_t 19 20 typedef int64 bfs_off_t; 21 22 struct block_run { 23 int32 allocation_group; 24 uint16 start; 25 uint16 length; 26 }; 27 28 typedef block_run inode_addr; 29 30 #define BFS_DISK_NAME_LENGTH 32 31 32 struct disk_super_block { 33 char name[BFS_DISK_NAME_LENGTH]; 34 int32 magic1; 35 int32 fs_byte_order; 36 uint32 block_size; 37 uint32 block_shift; 38 bfs_off_t num_blocks; 39 bfs_off_t used_blocks; 40 int32 inode_size; 41 int32 magic2; 42 int32 blocks_per_ag; 43 int32 ag_shift; 44 int32 num_ags; 45 int32 flags; 46 block_run log_blocks; 47 bfs_off_t log_start; 48 bfs_off_t log_end; 49 int32 magic3; 50 inode_addr root_dir; 51 inode_addr indices; 52 int32 pad[8]; 53 }; 54 55 #define SUPER_BLOCK_MAGIC1 'BFS1' /* BFS1 */ 56 57 const char *kHexDigits = "0123456789abcdef"; 58 59 60 static void 61 read_from(int fd, off_t pos, void *buffer, size_t size) 62 { 63 if (lseek(fd, pos, SEEK_SET) < 0 64 || read(fd, buffer, size) != (int)size) { 65 fprintf(stderr, "Error: Failed to read %lu bytes at offset %lld\n", 66 size, pos); 67 exit(1); 68 } 69 } 70 71 72 static void 73 write_to(int fd, off_t pos, const void *buffer, size_t size) 74 { 75 if (lseek(fd, pos, SEEK_SET) < 0 76 || write(fd, buffer, size) != (int)size) { 77 fprintf(stderr, "Error: Failed to write %lu bytes at offset %lld\n", 78 size, pos); 79 exit(1); 80 } 81 } 82 83 static int 84 count_bits(int value) 85 { 86 int count = 0; 87 88 while (value) { 89 if (value & 1) 90 count++; 91 value >>= 1; 92 } 93 94 return count; 95 } 96 97 int 98 main(int argc, const char *const *argv) 99 { 100 if (argc < 2 || argc > 3) { 101 fprintf(stderr, "Usage: %s <image> [ <hex OR pattern> ]\n", argv[0]); 102 exit(1); 103 } 104 105 const char *fileName = argv[1]; 106 const char *patternString = (argc >= 3 ? argv[2] : "0f"); 107 108 // skip leading "0x" in the pattern string 109 if (strncmp(patternString, "0x", 2) == 0) 110 patternString += 2; 111 112 // translate the pattern 113 uint8 *pattern = new uint8[strlen(patternString) / 2 + 1]; 114 int patternLen = 0; 115 for (; *patternString; patternString++) { 116 if (!isspace(*patternString)) { 117 char c = *patternString; 118 const char *digitPos = strchr(kHexDigits, tolower(c)); 119 if (!digitPos) { 120 fprintf(stderr, "Error: Invalid pattern character: \"%c\"\n", 121 c); 122 exit(1); 123 } 124 int digit = digitPos - kHexDigits; 125 126 if (patternLen & 1) 127 pattern[patternLen / 2] |= digit; 128 else 129 pattern[patternLen / 2] = digit << 4; 130 patternLen++; 131 } 132 } 133 134 if (patternLen == 0 || (patternLen & 1)) { 135 fprintf(stderr, "Error: Invalid pattern! Must have even number (>= 2) " 136 "of hex digits.\n"); 137 exit(1); 138 } 139 patternLen /= 2; // is now length in bytes 140 141 printf("bfs_fragmenter: using pattern: 0x"); 142 for (int i = 0; i < patternLen; i++) 143 printf("%02x", pattern[i]); 144 printf("\n"); 145 146 // open file 147 int fd = open(fileName, O_RDWR); 148 if (fd < 0) { 149 fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, 150 strerror(errno)); 151 exit(1); 152 } 153 154 // read super block 155 disk_super_block superBlock; 156 read_from(fd, 512, &superBlock, sizeof(superBlock)); 157 158 if (superBlock.magic1 != SUPER_BLOCK_MAGIC1) { 159 fprintf(stderr, "Error: Bad super block magic. This is probably not a " 160 "BFS image.\n"); 161 exit(1); 162 } 163 int blockSize = superBlock.block_size; 164 165 // stat the image 166 struct stat st; 167 if (fstat(fd, &st) < 0) { 168 fprintf(stderr, "Error: Failed to stat image: %s\n", strerror(errno)); 169 exit(1); 170 } 171 172 int64 blockCount = st.st_size / blockSize; 173 if (blockCount != superBlock.num_blocks) { 174 fprintf(stderr, "Error: Number of blocks in image and the number in " 175 "the super block differ: %lld vs. %lld\n", blockCount, 176 superBlock.num_blocks); 177 exit(1); 178 } 179 180 181 // iterate through the block bitmap blocks and or the bytes with 0x0f 182 uint8 *block = new uint8[blockSize]; 183 int64 occupiedBlocks = 0; 184 int64 bitmapByteCount = blockCount / 8; // round down, we ignore the 185 // last partial byte 186 int64 bitmapBlockCount = (bitmapByteCount + blockSize - 1) / blockSize; 187 188 int bitmapByteIndex = 0; 189 for (int i = 1; i < bitmapBlockCount + 1; i++) { 190 off_t offset = i * blockSize; 191 read_from(fd, offset, block, blockSize); 192 193 int toProcess = blockSize; 194 if (toProcess > bitmapByteCount - bitmapByteIndex) 195 toProcess = (bitmapByteCount - bitmapByteIndex); 196 197 for (int k = 0; k < toProcess; k++) { 198 uint8 patternChar = pattern[bitmapByteIndex % patternLen]; 199 occupiedBlocks += count_bits(~block[k] & patternChar); 200 block[k] |= patternChar; 201 bitmapByteIndex++; 202 } 203 204 write_to(fd, offset, block, blockSize); 205 } 206 207 printf("bfs_fragmenter: marked %lld blocks used\n", occupiedBlocks); 208 209 // write back the super block 210 superBlock.used_blocks += occupiedBlocks; 211 write_to(fd, 512, &superBlock, sizeof(superBlock)); 212 213 return 0; 214 } 215 216