1 /* 2 * PROJECT: Mke2fs 3 * FILE: Memory.c 4 * PROGRAMMER: Matt Wu <mattwu@163.com> 5 * HOMEPAGE: http://ext2.yeah.net 6 */ 7 8 /* INCLUDES **************************************************************/ 9 10 #include "Mke2fs.h" 11 #include <debug.h> 12 13 /* DEFINITIONS ***********************************************************/ 14 15 extern char *device_name; 16 17 /* FUNCTIONS *************************************************************/ 18 19 20 /* 21 * Return the group # of an inode number 22 */ 23 int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino) 24 { 25 return (ino - 1) / fs->ext2_sb->s_inodes_per_group; 26 } 27 28 /* 29 * Return the group # of a block 30 */ 31 int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk) 32 { 33 return (blk - fs->ext2_sb->s_first_data_block) / 34 fs->ext2_sb->s_blocks_per_group; 35 } 36 37 void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino, 38 int inuse, int isdir) 39 { 40 int group = ext2_group_of_ino(fs, ino); 41 42 if (inuse > 0) 43 ext2_mark_inode_bitmap(fs->inode_map, ino); 44 else 45 ext2_unmark_inode_bitmap(fs->inode_map, ino); 46 47 fs->group_desc[group].bg_free_inodes_count -= inuse; 48 49 if (isdir) 50 fs->group_desc[group].bg_used_dirs_count += inuse; 51 52 fs->ext2_sb->s_free_inodes_count -= inuse; 53 } 54 55 56 void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse) 57 { 58 ext2_inode_alloc_stats2(fs, ino, inuse, 0); 59 } 60 61 void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse) 62 { 63 int group = ext2_group_of_blk(fs, blk); 64 65 if (inuse > 0) 66 ext2_mark_block_bitmap(fs->block_map, blk); 67 else 68 ext2_unmark_block_bitmap(fs->block_map, blk); 69 70 fs->group_desc[group].bg_free_blocks_count -= inuse; 71 fs->ext2_sb->s_free_blocks_count -= inuse; 72 } 73 74 75 bool ext2_allocate_tables(PEXT2_FILESYS Ext2Sys) 76 { 77 bool retval; 78 ULONG i; 79 80 for (i = 0; i < Ext2Sys->group_desc_count; i++) 81 { 82 retval = ext2_allocate_group_table(Ext2Sys, i, Ext2Sys->block_map); 83 84 if (!retval) 85 return retval; 86 } 87 88 return true; 89 } 90 91 92 bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group, 93 PEXT2_BLOCK_BITMAP bmap) 94 { 95 bool retval; 96 ULONG group_blk, start_blk, last_blk, new_blk, blk, j; 97 98 group_blk = fs->ext2_sb->s_first_data_block + 99 (group * fs->ext2_sb->s_blocks_per_group); 100 101 last_blk = group_blk + fs->ext2_sb->s_blocks_per_group; 102 if (last_blk >= fs->ext2_sb->s_blocks_count) 103 last_blk = fs->ext2_sb->s_blocks_count - 1; 104 105 start_blk = group_blk + 3 + fs->desc_blocks; 106 if (start_blk > last_blk) 107 start_blk = group_blk; 108 109 if (!bmap) 110 bmap = fs->block_map; 111 112 /* 113 * Allocate the inode table 114 */ 115 if (!fs->group_desc[group].bg_inode_table) 116 { 117 retval = ext2_get_free_blocks(fs, start_blk, last_blk, 118 fs->inode_blocks_per_group, 119 bmap, &new_blk); 120 if (!retval) 121 return retval; 122 123 for (j=0, blk = new_blk; 124 j < fs->inode_blocks_per_group; 125 j++, blk++) 126 ext2_mark_block_bitmap(bmap, blk); 127 128 fs->group_desc[group].bg_inode_table = new_blk; 129 } 130 131 /* 132 * Allocate the block and inode bitmaps, if necessary 133 */ 134 if (fs->stride) 135 { 136 start_blk += fs->inode_blocks_per_group; 137 start_blk += ((fs->stride * group) % 138 (last_blk - start_blk)); 139 if (start_blk > last_blk) 140 /* should never happen */ 141 start_blk = group_blk; 142 } 143 else 144 { 145 start_blk = group_blk; 146 } 147 148 if (!fs->group_desc[group].bg_block_bitmap) 149 { 150 retval = ext2_get_free_blocks(fs, start_blk, last_blk, 151 1, bmap, &new_blk); 152 153 if (!retval) 154 retval = ext2_get_free_blocks(fs, group_blk, 155 last_blk, 1, bmap, &new_blk); 156 157 if (!retval) 158 return retval; 159 160 ext2_mark_block_bitmap(bmap, new_blk); 161 fs->group_desc[group].bg_block_bitmap = new_blk; 162 } 163 164 if (!fs->group_desc[group].bg_inode_bitmap) 165 { 166 retval = ext2_get_free_blocks(fs, start_blk, last_blk, 167 1, bmap, &new_blk); 168 if (!retval) 169 retval = ext2_get_free_blocks(fs, group_blk, 170 last_blk, 1, bmap, &new_blk); 171 if (!retval) 172 return retval; 173 174 ext2_mark_block_bitmap(bmap, new_blk); 175 fs->group_desc[group].bg_inode_bitmap = new_blk; 176 } 177 178 return true; 179 } 180 181 182 bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish, 183 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret) 184 { 185 ULONG b = start; 186 187 if (!map) 188 map = fs->block_map; 189 190 if (!map) 191 return false; 192 193 if (!b) 194 b = fs->ext2_sb->s_first_data_block; 195 196 if (!finish) 197 finish = start; 198 199 if (!num) 200 num = 1; 201 202 do 203 { 204 if (b+num-1 > fs->ext2_sb->s_blocks_count) 205 b = fs->ext2_sb->s_first_data_block; 206 207 if (ext2_test_block_bitmap_range(map, b, num)) 208 { 209 *ret = b; 210 return true; 211 } 212 213 b++; 214 215 } while (b != finish); 216 217 return false; 218 } 219 220 221 bool write_inode_tables(PEXT2_FILESYS fs) 222 { 223 bool retval; 224 ULONG blk, num; 225 int i; 226 227 for (i = 0; (ULONG)i < fs->group_desc_count; i++) 228 { 229 blk = fs->group_desc[i].bg_inode_table; 230 num = fs->inode_blocks_per_group; 231 232 retval = zero_blocks(fs, blk, num, &blk, &num); 233 if (!retval) 234 { 235 DPRINT1("\nMke2fs: Could not write %lu blocks " 236 "in inode table starting at %lu.\n", 237 num, blk); 238 239 zero_blocks(0, 0, 0, 0, 0); 240 return false; 241 } 242 } 243 244 zero_blocks(0, 0, 0, 0, 0); 245 246 return true; 247 } 248 249 250 /* 251 * Stupid algorithm --- we now just search forward starting from the 252 * goal. Should put in a smarter one someday.... 253 */ 254 bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal, 255 PEXT2_BLOCK_BITMAP map, ULONG *ret) 256 { 257 ULONG i; 258 259 if (!map) 260 map = fs->block_map; 261 262 if (!map) 263 return false; 264 265 if (!goal || (goal >= fs->ext2_sb->s_blocks_count)) 266 goal = fs->ext2_sb->s_first_data_block; 267 268 i = goal; 269 270 do 271 { 272 if (!ext2_test_block_bitmap(map, i)) 273 { 274 *ret = i; 275 return true; 276 } 277 278 i++; 279 280 if (i >= fs->ext2_sb->s_blocks_count) 281 i = fs->ext2_sb->s_first_data_block; 282 283 } while (i != goal); 284 285 return false; 286 } 287 288 289 /* 290 * This function zeros out the allocated block, and updates all of the 291 * appropriate filesystem records. 292 */ 293 bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret) 294 { 295 bool retval; 296 ULONG block; 297 char *buf = NULL; 298 299 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize); 300 if (!buf) 301 return false; 302 303 if (!fs->block_map) 304 { 305 retval = ext2_read_block_bitmap(fs); 306 if (!retval) 307 goto fail; 308 } 309 310 retval = ext2_new_block(fs, goal, 0, &block); 311 312 if (!retval) 313 goto fail; 314 315 retval = NT_SUCCESS(Ext2WriteDisk( 316 fs, 317 ((LONGLONG)block * fs->blocksize), 318 fs->blocksize, (unsigned char *)buf)); 319 320 if (!retval) 321 { 322 goto fail; 323 } 324 325 ext2_block_alloc_stats(fs, block, +1); 326 *ret = block; 327 328 if (buf) 329 { 330 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 331 } 332 333 return true; 334 335 fail: 336 337 if (buf) 338 { 339 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 340 } 341 342 return false; 343 } 344 345 346 /* 347 * Create new directory block 348 */ 349 bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino, 350 ULONG parent_ino, char **block) 351 { 352 PEXT2_DIR_ENTRY dir = NULL; 353 char *buf; 354 int rec_len; 355 int filetype = 0; 356 357 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize); 358 if (!buf) 359 return false; 360 361 dir = (PEXT2_DIR_ENTRY) buf; 362 dir->rec_len = fs->blocksize; 363 364 if (dir_ino) 365 { 366 if (fs->ext2_sb->s_feature_incompat & 367 EXT2_FEATURE_INCOMPAT_FILETYPE) 368 filetype = EXT2_FT_DIR << 8; 369 /* 370 * Set up entry for '.' 371 */ 372 dir->inode = dir_ino; 373 dir->name_len = 1 | filetype; 374 dir->name[0] = '.'; 375 rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1); 376 dir->rec_len = EXT2_DIR_REC_LEN(1); 377 378 /* 379 * Set up entry for '..' 380 */ 381 dir = (struct ext2_dir_entry *) (buf + dir->rec_len); 382 dir->rec_len = rec_len; 383 dir->inode = parent_ino; 384 dir->name_len = 2 | filetype; 385 dir->name[0] = '.'; 386 dir->name[1] = '.'; 387 } 388 389 *block = buf; 390 391 return true; 392 } 393 394 bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf) 395 { 396 bool retval = false; 397 398 retval = NT_SUCCESS(Ext2WriteDisk( 399 fs, 400 ((ULONGLONG)block * fs->blocksize), 401 fs->blocksize, (unsigned char *)inbuf)); 402 403 return retval; 404 } 405 406 bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf) 407 { 408 bool retval = false; 409 410 retval = NT_SUCCESS(Ext2ReadDisk( 411 fs, 412 ((ULONGLONG)block * fs->blocksize), 413 fs->blocksize, (unsigned char *)inbuf)); 414 415 return retval; 416 } 417