12633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include <sys/types.h> 22633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include <sys/stat.h> 32633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include <fcntl.h> 42633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include <stdio.h> 52633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include <stdlib.h> 62633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 72633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include "ext4.h" 82633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#include "ext4_utils.h" 92633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 102633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall#define SB_OFFSET 1024 112633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 122633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrallint main(int argc, char *argv[]) 132633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall{ 142633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall char me[] = "corrupt_gdt_free_blocks"; 152633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall int fd; 162633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall int block_size; 172633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall int num_bgs; 182633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall int i; 192633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall struct ext4_super_block sb; 202633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall struct ext2_group_desc gd; 212633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 222633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (argc != 2) { 232633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Usage: %s <ext4_block_device>\n", me, me); 242633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 252633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 262633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 272633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fd = open(argv[1], O_RDWR); 282633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 292633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (fd < 0) { 302633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot open block device %s\n", me, argv[1]); 312633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 322633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 332633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 342633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (lseek(fd, SB_OFFSET, SEEK_SET) == -1) { 352633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot lseek to superblock to read\n", me); 362633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 372633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 382633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 392633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { 402633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot read superblock\n", me); 412633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 422633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 432633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 442633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (sb.s_magic != 0xEF53) { 452633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: invalid superblock magic\n", me); 462633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 472633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 482633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 492633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall /* Make sure the block size is 2K or 4K */ 502633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if ((sb.s_log_block_size != 1) && (sb.s_log_block_size != 2)) { 512633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: block size not 2K or 4K\n", me); 522633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 532633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 542633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 552633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall block_size = 1 << (10 + sb.s_log_block_size); 562633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall num_bgs = DIV_ROUND_UP(sb.s_blocks_count_lo, sb.s_blocks_per_group); 572633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 582633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (sb.s_desc_size != sizeof(struct ext2_group_desc)) { 592633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Can't handle block group descriptor size of %d\n", 602633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall me, sb.s_desc_size); 612633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 622633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 632633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 642633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall /* read first block group descriptor, decrement free block count, and 652633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall * write it back out 662633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall */ 672633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (lseek(fd, block_size, SEEK_SET) == -1) { 682633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot lseek to block group descriptor table to read\n", me); 692633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 702633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 712633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 722633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall /* Read in block group descriptors till we read one that has at least one free block */ 732633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 742633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall for (i=0; i < num_bgs; i++) { 752633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (read(fd, &gd, sizeof(gd)) != sizeof(gd)) { 762633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot read group descriptor %d\n", me, i); 772633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 782633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 792633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (gd.bg_free_blocks_count) { 802633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall break; 812633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 822633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 832633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 842633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall gd.bg_free_blocks_count--; 852633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 862633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (lseek(fd, -sizeof(gd), SEEK_CUR) == -1) { 872633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot lseek to block group descriptor table to write\n", me); 882633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 892633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 902633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 912633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall if (write(fd, &gd, sizeof(gd)) != sizeof(gd)) { 922633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall fprintf(stderr, "%s: Cannot write modified group descriptor\n", me); 932633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall exit(1); 942633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall } 952633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 962633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall close(fd); 972633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 982633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall return 0; 992633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall} 1002633ce5ca5024d5565c9068c29ec39a8c3ed10e9Ken Sumrall 101