Mercurial > xfs_ino_scan
view ino_scan.c @ 18:c515cc303bed
cleanup copy data condition
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sat, 22 Mar 2008 18:43:58 -0400 |
parents | c10bdd3261be |
children | 068a4a28bde6 |
line wrap: on
line source
/* * Copyright (c) 2008 Josef 'Jeff' Sipek * * Licensed under GPL version 2. */ #define _XOPEN_SOURCE 500 #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> typedef unsigned int uint; typedef unsigned short ushort; #include <xfs/libxfs.h> #define FNAME "test.img" #define DUMPDIR "dump" #define BLKSIZE 4096 #define BLKDEV_SIZE (104857600 / BLKSIZE) #define INOSIZE 256 /* * Should inode data be copied off the device into DUMPDIR? * * defined: yes * undefined: no */ //#define COPY_DATA int fd; /* device fd */ int ffd = 0; /* file fd */ static inline __uint16_t swap16(__uint16_t in) { return ((in & 0xff) << 8) | (in >> 8); } static inline __uint32_t swap32(__uint32_t in) { return ((in & 0x000000ff) << 24) | ((in & 0x0000ff00) << 8) | ((in & 0x00ff0000) >> 8) | ((in & 0xff000000) >> 24); } static inline __uint64_t swap64(__uint64_t in) { return ((in & 0x00000000000000ffULL) << 56) | ((in & 0x000000000000ff00ULL) << 40) | ((in & 0x0000000000ff0000ULL) << 24) | ((in & 0x00000000ff000000ULL) << 8) | ((in & 0x000000ff00000000ULL) >> 8) | ((in & 0x0000ff0000000000ULL) >> 24) | ((in & 0x00ff000000000000ULL) >> 40) | ((in & 0xff00000000000000ULL) >> 56); } #define die() do_die(__FILE__, __LINE__) void do_die(char *file, int line) { printf("fatal: %s:%d: %s\n", file, line, strerror(errno)); fflush(stdout); exit(1); } void hexdump(unsigned char *p, int len) { int i; for(i=0;i<len;i+=16,p+=16) printf("%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } void convert_extent_rec(xfs_bmbt_rec_t *rec, xfs_bmbt_irec_t *irec) { __int64_t *p = (__int64_t*) rec; __int64_t tmp; tmp = swap64(*p); irec->br_state = (tmp) >> 63; irec->br_startoff = ((tmp) & 0x7fffffffffffffffULL) >> 9; irec->br_startblock = (tmp) << 55; p++; tmp = swap64(*p); irec->br_startblock |= (tmp) >> 21; irec->br_blockcount = (tmp) & 0x1fffffULL; } void copy_extent_data(struct xfs_bmbt_irec *irec) { if (!ffd) return; #ifdef COPY_DATA char buf[BLKSIZE]; int ret; int i; for(i=0; i<irec->br_blockcount; i++) { ret = pread64(fd, buf, BLKSIZE, (irec->br_startblock + i) * BLKSIZE); if (ret == -1) die(); ret = pwrite64(ffd, buf, BLKSIZE, (irec->br_startoff + i) * BLKSIZE); if (ret == -1) die(); } #endif } void process_reclist(xfs_bmbt_rec_t *rec, __uint32_t nexts) { struct xfs_bmbt_irec irec; __uint32_t i; printf(">> [startoff,startblock,blockcount,extentflag]\n"); for(i=0; i<nexts; i++, rec++) { convert_extent_rec(rec, &irec); printf(">> %u: [%llu,%llu,%llu,%d]\n", i, irec.br_startoff, irec.br_startblock, irec.br_blockcount, irec.br_state); copy_extent_data(&irec); } } void scan_lbtree(__uint64_t blk, __uint16_t level); void scan_bmap(xfs_bmbt_block_t *block, __uint16_t level) { xfs_bmbt_ptr_t *ptr; int i; if (!level) { process_reclist(XFS_BTREE_REC_ADDR(0, xfs_bmbt, block, 1, 0), swap16(block->bb_numrecs)); return; } ptr = XFS_BTREE_PTR_ADDR(0, xfs_bmbt, block, 1, XFS_BTREE_BLOCK_MAXRECS(BLKSIZE, xfs_bmbt, level != 0)); for(i=0; i<swap16(block->bb_numrecs); i++) scan_lbtree(swap64(ptr[i]), swap16(block->bb_level)); } void scan_lbtree(__uint64_t blk, __uint16_t level) { char buf[BLKSIZE]; int ret; ret = pread64(fd, buf, BLKSIZE, blk * BLKSIZE); if (ret == -1) die(); if (memcmp(buf, "BMAP", 4)) die(); scan_bmap((xfs_bmbt_block_t*) buf, level - 1); } static inline int get_dfork_size(struct xfs_dinode *inode) { if (inode->di_core.di_forkoff) return ((int)inode->di_core.di_forkoff) << 3; return INOSIZE - sizeof(struct xfs_dinode_core) - sizeof(xfs_agino_t); } void process_btinode(struct xfs_dinode *inode) { xfs_bmdr_block_t *block; xfs_bmbt_ptr_t *ptr; int i; block = (void*)XFS_DFORK_PTR(inode, XFS_DATA_FORK); if (!swap16(block->bb_level)) { xfs_bmbt_rec_t *rec; rec = XFS_BTREE_REC_ADDR(0, xfs_bmdr, block, 1, XFS_BTREE_BLOCK_MAXRECS(get_dfork_size(inode), xfs_bmdr, 1)); process_reclist(rec, swap16(block->bb_numrecs)); return; } ptr = (void*)XFS_BTREE_PTR_ADDR(0, xfs_bmdr, block, 1, XFS_BTREE_BLOCK_MAXRECS(get_dfork_size(inode), xfs_bmdr, 0)); for(i=0;i<swap16(block->bb_numrecs);i++) scan_lbtree(swap64(ptr[i]), swap16(block->bb_level)); } int diformat_valid(__uint8_t fmt) { switch(fmt) { case XFS_DINODE_FMT_DEV: case XFS_DINODE_FMT_LOCAL: case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_BTREE: case XFS_DINODE_FMT_UUID: return 1; } return 0; } char *diformat_str(__uint8_t fmt) { switch(fmt) { case XFS_DINODE_FMT_DEV: return "XFS_DINODE_FMT_DEV"; case XFS_DINODE_FMT_LOCAL: return "XFS_DINODE_FMT_LOCAL"; case XFS_DINODE_FMT_EXTENTS: return "XFS_DINODE_FMT_EXTENTS"; case XFS_DINODE_FMT_BTREE: return "XFS_DINODE_FMT_BTREE"; case XFS_DINODE_FMT_UUID: return "XFS_DINODE_FMT_UUID"; } return "(unknown format)"; } void do_print_inode(struct xfs_dinode *inode) { printf("> di_imode %o\n", swap16(inode->di_core.di_mode)); printf("> di_version %u\n", inode->di_core.di_version); printf("> di_format %u (%s)\n", inode->di_core.di_format, diformat_str(inode->di_core.di_format)); printf("> di_forkoff %u\n", inode->di_core.di_forkoff); printf("> di_uid %u\n", swap32(inode->di_core.di_uid)); printf("> di_gid %u\n", swap32(inode->di_core.di_gid)); printf("> di_nlink %u\n", swap32(inode->di_core.di_nlink)); printf("> di_size %llu\n", swap64(inode->di_core.di_size)); printf("> di_nextents %u\n", swap32(inode->di_core.di_nextents)); if (!swap32(inode->di_core.di_nextents)) { printf(">> Skipping nextents == 0\n"); return; } if (!diformat_valid(inode->di_core.di_format) || (inode->di_core.di_version > 2)) { printf(">> Skipping format/version is invalid\n"); return; } switch(inode->di_core.di_format) { case XFS_DINODE_FMT_EXTENTS: process_reclist((void*) XFS_DFORK_PTR(inode, XFS_DATA_FORK), swap32(inode->di_core.di_nextents)); break; case XFS_DINODE_FMT_BTREE: process_btinode(inode); break; default: printf(">> Unknown data fork format %d\n", inode->di_core.di_format); break; } } void print_inode(loff_t blk) { #ifdef COPY_DATA char fname[PATH_MAX]; #endif unsigned char buf[INOSIZE]; struct xfs_dinode *inode = (void*) buf; off_t off; int ret; printf("Found inode magic at block %llu\n", blk); for(off=0; off<(BLKSIZE/INOSIZE); off++) { ret = pread64(fd, buf, INOSIZE, blk * BLKSIZE + off * INOSIZE); if (ret == -1) { perror("pread64"); return; } printf("Inode @ block %llu, inode within blk %lu\n", blk, off); #ifdef COPY_DATA if (swap16(inode->di_core.di_mode) & S_IFREG) { snprintf(fname, PATH_MAX, "%s/%08llx-%08lx", DUMPDIR, blk, off); ffd = open(fname, O_CREAT | O_LARGEFILE | O_WRONLY, swap16(inode->di_core.di_mode) & 0777); if (ffd == -1) die(); } #endif do_print_inode(inode); #ifdef COPY_DATA if (swap16(inode->di_core.di_mode) & S_IFREG) { ret = ftruncate(ffd, swap64(inode->di_core.di_size)); if (ret == -1) die(); ret = close(ffd); if (ret == -1) die(); ffd = 0; } #endif } } int main(int argc, char **argv) { int ret; char buf[2]; loff_t off; printf("Assuming inode size = %d, block size = %d\n", INOSIZE, BLKSIZE); fd = open(FNAME, O_LARGEFILE | O_RDONLY); if (fd == -1) { perror("open"); return 1; } for(off = 0; off < BLKDEV_SIZE; off++) { ret = pread64(fd, buf, 2, off * BLKSIZE); if (ret == -1) { perror("pread64"); return 1; } if (buf[0] == 'I' && buf[1] == 'N') print_inode(off); } return 0; }