xref: /haiku/src/tests/add-ons/kernel/file_systems/bfs/fragmenter/fragmenter.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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