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
read_from(int fd,off_t pos,void * buffer,size_t size)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
write_to(int fd,off_t pos,const void * buffer,size_t size)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
count_bits(int value)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
main(int argc,const char * const * argv)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 superblock
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 superblock 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 superblock 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 superblock
210 superBlock.used_blocks += occupiedBlocks;
211 write_to(fd, 512, &superBlock, sizeof(superBlock));
212
213 return 0;
214 }
215
216