/** * GFS2 helper tool to unformat re-formatted volume. * * Copywrite: 2014 PDNSoft Co. (www.pdnsoft.com). * * Authors: * Mahdi Hajimoradi (hajim@pdnsoft.com) * Hamid Jafarian (hamid.jafarian@pdnsoft.com) * * In our scenario, we recoverd a re-formatted volume (format with same * parameters that had been formatted for the first time). * * This program, searches volume to find "dinode" blocks, then marked them * in "bit-map" as meta-data (or inode). * After execution of the program, "fsck" could recover lost data. */ #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include #define GFS2_NBBY 4 #define GFS2_BIT_MASK 0x00000003 #define GFS2_BIT_SIZE 2 /* Size of gfs2_rgrb, structure of resource group meta data at the first of * first block in resource group blocks. * This structure contatins gfs2_meta_header plust some rg specific data. */ #define gfs2_rgrb_size 128 /* Size of gfs2_meta_header, structure of meta data at the first of * gfs2 blocks. */ #define gfs2_meta_header_size 24 /* Type of dinode block */ #define GFS2R_BLOCK_DINODE 4 /* Type of rg block */ #define GFS2R_BLOCK_RG 2 #define BLOCK_DEVICE "/dev/sdb" /* GFS2 block size in volume */ #define BLOCK_SIZE 4096 /* Number of GFS2 blocks in devcice */ #define BLOCK_NUM 439094496 #define BLOCK_READ BLOCK_SIZE /* Start block that search for dinodes should start from. * This number defines the first block after journal blocks. * You can retrive the last journal block by this command: * # gfs2_edit -p master /dev/sdb | grep quota */ #define BLOCK_START 264951 /* Bock number of RG that stores bitmap of block_start */ #define BLOCK_START_RG 201348 /* Number of Metadata Blocks in one RG */ #define BLOCK_RG_SIZE 5 #define BLOCK_READ_RG (BLOCK_SIZE * BLOCK_RG_SIZE) class RGBuf { public: RGBuf(unsigned long _offset) { offset = _offset; } void set_offset(unsigned long _offset) { offset = _offset; } unsigned long offset; unsigned char buf[BLOCK_READ_RG]; }; int dd; unsigned long bi = 0; list rglist; static void SIGTERM_handler(int signal) { printf("bi: %u \n", bi); cout << "rg size: " << rglist.size() << endl; for (list::iterator iter = rglist.begin(); iter != rglist.end(); ++iter) { cout << "rg offset " << (*iter)->offset << endl; } } int main() { bool rgHasInode = false; signal(SIGTERM, &SIGTERM_handler); signal(SIGINT, &SIGTERM_handler); unsigned char buf[BLOCK_SIZE]; /* Memory to store first RG */ RGBuf *rgb = new RGBuf(BLOCK_START_RG * BLOCK_SIZE); dd = open(BLOCK_DEVICE, O_RDONLY); int byte; if (dd < 0) { cout << "Error in open device" << endl; return 1; } lseek(dd, rgb->offset, SEEK_SET); read(dd, rgb->buf, BLOCK_READ_RG); lseek(dd, BLOCK_START * BLOCK_SIZE, SEEK_SET); for (bi = BLOCK_START; bi <= BLOCK_NUM; ++bi) { if ((byte = read(dd, buf, BLOCK_SIZE)) < -1) { return 2; } if ((buf[0] != 1) || (buf[1] != 22) || (buf[2] != 25) || (buf[3] != 112)) { /* block is not GFS2 block */ continue; } short block_type = buf[7]; if (block_type == GFS2R_BLOCK_RG) { cout << "rg_block = " << bi << endl; if (rgHasInode) { cout << "save previous rg " << endl; rglist.push_back(rgb); rgb = new RGBuf(bi * BLOCK_SIZE); } rgHasInode = false; rgb->set_offset(bi * BLOCK_SIZE); bcopy(buf, rgb->buf, BLOCK_SIZE); for (int _i = 1; _i < BLOCK_RG_SIZE; ++_i) { ++bi; read(dd, rgb->buf + _i * BLOCK_SIZE, BLOCK_SIZE); } continue; } if (block_type == GFS2R_BLOCK_DINODE) { cout << "dinode_block = " << bi << " "; rgHasInode = true; } else continue; unsigned long offset = bi - ((rgb->offset / BLOCK_SIZE ) + BLOCK_RG_SIZE); cout << "offset= " << offset << endl; int gi = 0; if (offset >= ((BLOCK_SIZE - gfs2_rgrb_size) * GFS2_NBBY)) { /* Byte corresponds to this block is out of first block, * So adjust offset to see all of resource blocks * idenically. */ offset += (gfs2_rgrb_size - gfs2_meta_header_size) * GFS2_NBBY; gi = offset / ((BLOCK_SIZE - gfs2_meta_header_size) * GFS2_NBBY); offset -= gi * ((BLOCK_SIZE - gfs2_meta_header_size) * GFS2_NBBY); unsigned int bytei = gi * BLOCK_SIZE + gfs2_meta_header_size + (offset / GFS2_NBBY); unsigned char byte = rgb->buf[bytei]; printf("byte = %x ", byte); int bit = (offset % GFS2_NBBY) * GFS2_BIT_SIZE; printf("map= %x ", (byte >> bit) & GFS2_BIT_MASK); rgb->buf[bytei] |= (GFS2_BIT_MASK << bit); } else { unsigned int bytei = gfs2_rgrb_size + (offset / GFS2_NBBY); unsigned char byte = rgb->buf[bytei]; printf("byte = %x\n", (short) byte); int bit = (offset % GFS2_NBBY) * GFS2_BIT_SIZE; printf("map= %x\n", (byte >> bit) & GFS2_BIT_MASK); rgb->buf[bytei] |= (GFS2_BIT_MASK << bit); } cout << endl; } /* For last rg */ if (rgHasInode) { cout << "save previous rg " << endl; rglist.push_back(rgb); } close(dd); /* Writing rg bit-maps. */ cout << "Writing rg# " << rglist.size() << endl; dd = open(BLOCK_DEVICE, O_WRONLY); for (list::iterator iter = rglist.begin(); iter != rglist.end(); ++iter) { lseek(dd, (*iter)->offset, SEEK_SET); write(dd, (*iter)->buf, BLOCK_READ_RG); } close(dd); return 0; }