/* * Copyright 2000-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include #endif #include "debugreiserfs.h" #include "misc/unaligned.h" #include "util/device.h" #include "util/misc.h" #include #include #include #define print_usage_and_exit() misc_die ("Usage: %s [-v] [-b filename] device\n\ -v prints blocks number of every block unpacked\n\ -b filename saves bitmap of blocks unpacked to filename\n\ -j filename stores journal in the filename\n", argv[0]); /* when super block gets unpacked for the first time - create a bitmap and mark in it what have been unpacked. Save that bitmap at the end */ reiserfs_bitmap_t * what_unpacked = 0; int leaves, full; int verbose = 0; int Default_journal = 1; static void unpack_offset (struct packed_item * pi, reiserfs_ih_t * ih, int blocksize) { if (get_pi_mask(pi) & OFFSET_BITS_64) { __u64 v64; if (reiserfs_ih_get_format (ih) != KEY_FORMAT_2) misc_die ("unpack_offset: key format is not set or wrong"); fread_le64 (&v64); reiserfs_key_set_off (KEY_FORMAT_2, &ih->ih_key, v64); return; } if (get_pi_mask(pi) & OFFSET_BITS_32) { __u32 v32; fread_le32 (&v32); reiserfs_key_set_off (reiserfs_ih_get_format (ih), &ih->ih_key, v32); return; } if ((get_pi_mask(pi) & DIR_ID) == 0 && (get_pi_mask(pi) & OBJECT_ID) == 0) { /* offset was not sent, as it can be calculated looking at the previous item */ if (reiserfs_ih_stat (ih - 1)) reiserfs_key_set_off (reiserfs_ih_get_format (ih), &ih->ih_key, 1); if (reiserfs_ih_ext (ih - 1)) reiserfs_key_set_off(reiserfs_ih_get_format (ih), &ih->ih_key, reiserfs_key_get_off (&(ih - 1)->ih_key) + reiserfs_leaf_ibytes (ih - 1, blocksize)); } // offset is 0 return; } static void unpack_type (struct packed_item * pi, reiserfs_ih_t * ih) { reiserfs_key_set_type (reiserfs_ih_get_format (ih), &ih->ih_key, get_pi_type(pi)); if (reiserfs_key_unkn (&ih->ih_key)) reiserfs_panic ("unpack_type: unknown type %d unpacked for %H\n", get_pi_type(pi), ih); } /* direntry item comes in the following format: for each entry mask - 8 bits entry length - 16 bits entry itself deh_objectid - 32 bits maybe deh_dir_id (32 bits) maybe gencounter (16) maybe deh_state (16) */ static void unpack_direntry (struct packed_item * pi, reiserfs_bh_t * bh, reiserfs_ih_t * ih, hashf_t hash_func) { __u16 entry_count, namelen, gen_counter, entry_len; __u8 mask; int i; reiserfs_deh_t * deh; int location; char * item; /* if (!hash_func) misc_die ("unpack_direntry: hash function is not set");*/ if (!(get_pi_mask(pi) & IH_FREE_SPACE)) misc_die ("ih_entry_count must be packed for directory items"); entry_count = reiserfs_ih_get_entries (ih); /* if (!entry_count) reiserfs_panic ("unpack_direntry: entry count should be set already");*/ item = bh->b_data + reiserfs_ih_get_loc (ih); deh = (reiserfs_deh_t *)item; location = get_pi_item_len(pi); for (i = 0; i < entry_count; i ++, deh ++) { fread8 (&mask); fread_le16 (&entry_len); location -= entry_len; reiserfs_deh_set_loc (deh, location); fread (item + location, entry_len, 1, stdin); /* find name length */ namelen = strlen (item + location); if (namelen > entry_len) namelen = entry_len; fread32 (&deh->deh2_objectid); if (mask & HAS_DIR_ID) fread32 (&deh->deh2_dir_id); else reiserfs_deh_set_did (deh, reiserfs_key_get_oid (&ih->ih_key)); if (*(item + location) == '.' && namelen == 1) { /* old or new "." */ reiserfs_deh_set_off (deh, OFFSET_DOT); } else if (*(item + location) == '.' && *(item + location + 1) == '.' && namelen == 2) { /* old or new ".." */ reiserfs_deh_set_off (deh, OFFSET_DOT_DOT); } else if (hash_func) { reiserfs_deh_set_off (deh, reiserfs_hash_value(hash_func, item + location, namelen)); } if (mask & HAS_GEN_COUNTER) { fread_le16 (&gen_counter); reiserfs_deh_set_off (deh, reiserfs_deh_get_off (deh) | gen_counter); } if (mask & HAS_STATE) fread16 (&deh->deh2_state); else reiserfs_deh_set_state (deh, (1 << DEH_Visible2)); } return; } /* struct packed_item is already unpacked */ static void unpack_stat_data (struct packed_item * pi, reiserfs_bh_t * bh, reiserfs_ih_t * ih) { if (!(get_pi_mask(pi) & IH_FREE_SPACE)) { /* ih_free_space was not packed - set default */ reiserfs_ih_set_entries (ih, 0xffff); } if (reiserfs_ih_get_format (ih) == KEY_FORMAT_1) { /* stat data comes in the following format: if this is old stat data: mode - 16 bits nlink - 16 bits size - 32 bits blocks/rdev - 32 bits maybe first_direct byte 32 bits */ reiserfs_sd_v1_t * sd; sd = (reiserfs_sd_v1_t *)reiserfs_item_by_ih (bh, ih); memset (sd, 0, sizeof (sd)); fread16 (&sd->sd_mode); fread16 (&sd->sd_nlink); fread32 (&sd->sd_size); fread32 (&sd->u.sd_blocks); if (get_pi_mask(pi) & WITH_SD_FIRST_DIRECT_BYTE) { fread32 (&sd->sd_fdb); } else { sd->sd_fdb = 0xffffffff; } } else { /* for new stat data mode - 16 bits nlink in either 16 or 32 bits size in either 32 or 64 bits blocks - 32 bits */ reiserfs_sd_t * sd; sd = (reiserfs_sd_t *)reiserfs_item_by_ih (bh, ih); memset (sd, 0, sizeof (sd)); fread16 (&sd->sd_mode); if (get_pi_mask(pi) & NLINK_BITS_32) { fread32 (&sd->sd_nlink); } else { __u16 nlink16; fread16 (&nlink16); reiserfs_set_sd_v2_nlink (sd, le16_to_cpu(nlink16)); } if (get_pi_mask(pi) & SIZE_BITS_64) { fread64 (&sd->sd_size); } else { __u32 size32; /* We need the endian conversions since sd->sd_size is 64 bit */ fread_le32 (&size32); reiserfs_set_sd_v2_size (sd, size32 ); } fread32 (&sd->sd_blocks); } return; } /* extent item comes either in packed form or as is. ih_free_space can go first */ static void unpack_extent (struct packed_item * pi, reiserfs_bh_t * bh, reiserfs_ih_t * ih) { __u32 * ind_item, * end; int i; __u16 v16; if (!(get_pi_mask(pi) & IH_FREE_SPACE)) { /* ih_free_space was not packed - set default */ reiserfs_ih_set_entries (ih, 0); } ind_item = (__u32 *)reiserfs_item_by_ih (bh, ih); if (get_pi_mask(pi) & SAFE_LINK) { d32_put(ind_item, 0, reiserfs_key_get_did(&ih->ih_key)); reiserfs_key_set_did(&ih->ih_key, (__u32)-1); return; } if (get_pi_mask(pi) & WHOLE_EXTENT) { fread (ind_item, get_pi_item_len(pi), 1, stdin); return; } end = ind_item + reiserfs_ext_count (ih); while (ind_item < end) { __u32 base; fread32 (ind_item); fread_le16 (&v16); base = d32_get(ind_item, 0); for (i = 1; i < v16; i ++) { if (base != 0) d32_put(ind_item, i, base + i); else d32_put(ind_item, i, 0); } ind_item += i; } return; } // FIXME: we have no way to preserve symlinks static void unpack_direct (struct packed_item * pi, reiserfs_bh_t * bh, reiserfs_ih_t * ih) { __u32 * d_item = (__u32 *)reiserfs_item_by_ih (bh, ih); if (!(get_pi_mask(pi) & IH_FREE_SPACE)) /* ih_free_space was not packed - set default */ reiserfs_ih_set_entries (ih, 0xffff); if (get_pi_mask(pi) & SAFE_LINK) { d32_put(d_item, 0, reiserfs_key_get_did(&ih->ih_key)); reiserfs_key_set_did(&ih->ih_key, (__u32)-1); } else { memset (d_item, 'a', get_pi_item_len(pi)); } return; } static void unpack_leaf (int dev, hashf_t hash_func, __u16 blocksize) { static int unpacked_leaves = 0; reiserfs_bh_t * bh; struct packed_item pi; reiserfs_ih_t * ih; int i; __u16 v16; __u32 v32; /* block number */ fread_le32 (&v32); /* item number */ fread_le16 (&v16); if (verbose) reiserfs_warning (stderr, "leaf %d: %d items\n", v32, v16); bh = reiserfs_buffer_open (dev, v32, blocksize); if (!bh) misc_die ("unpack_leaf: reiserfs_buffer_open failed"); reiserfs_nh_set_items (NODE_HEAD (bh), v16); reiserfs_nh_set_level (NODE_HEAD (bh), LEAF_LEVEL); reiserfs_nh_set_free (NODE_HEAD (bh), REISERFS_NODE_SPACE (bh->b_size)); ih = reiserfs_ih_at (bh, 0); for (i = 0; i < reiserfs_nh_get_items (NODE_HEAD (bh)); i ++, ih ++) { #if 0 fread32 (&v32); if (v32 != ITEM_START_MAGIC) misc_die ("unpack_leaf: no start item magic found: block %lu, item %i", bh->b_blocknr, i); #endif fread (&pi, sizeof (struct packed_item), 1, stdin); /* dir_id - if it is there */ if (get_pi_mask(&pi) & DIR_ID) { fread32 (&v32); reiserfs_key_set_did (&ih->ih_key, le32_to_cpu(v32)); } else { if (!i) misc_die ("unpack_leaf: dir_id is not set"); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); } /* object_id - if it is there */ if (get_pi_mask(&pi) & OBJECT_ID) { fread32 (&v32); reiserfs_key_set_oid (&ih->ih_key, le32_to_cpu(v32)); } else { if (!i) misc_die ("unpack_leaf: object_id is not set"); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); } // we need to set item format before offset unpacking reiserfs_ih_set_format (ih, (get_pi_mask(&pi) & NEW_FORMAT) ? KEY_FORMAT_2 : KEY_FORMAT_1); // offset unpack_offset (&pi, ih, bh->b_size); /* type */ unpack_type (&pi, ih); /* ih_free_space and ih_format */ if (get_pi_mask(&pi) & IH_FREE_SPACE) { fread16 (&v16); reiserfs_ih_set_entries (ih, le16_to_cpu(v16)); } if (get_pi_mask(&pi) & IH_FORMAT) fread16 (&ih->ih_format); /* item length and item location */ reiserfs_ih_set_len (ih, get_pi_item_len(&pi)); reiserfs_ih_set_loc (ih, (i ? reiserfs_ih_get_loc (ih - 1) : bh->b_size) - get_pi_item_len(&pi)); // item itself if (reiserfs_ih_direct (ih)) { unpack_direct (&pi, bh, ih); } else if (reiserfs_ih_ext (ih)) { unpack_extent (&pi, bh, ih); } else if (reiserfs_ih_dir (ih)) { unpack_direntry (&pi, bh, ih, hash_func); } else if (reiserfs_ih_stat (ih)) { unpack_stat_data (&pi, bh, ih); } reiserfs_nh_set_free (NODE_HEAD (bh), reiserfs_nh_get_free (NODE_HEAD (bh)) - (REISERFS_IH_SIZE + reiserfs_ih_get_len (ih))); #if 0 fread32 (&v32); if (v32 != ITEM_END_MAGIC) misc_die ("unpack_leaf: no end item magic found: block %lu, item %i", bh->b_blocknr, i); if (verbose) reiserfs_warning (stderr, "%d: %H\n", i, ih); #endif } fread_le16 (&v16); if (v16 != LEAF_END_MAGIC) misc_die ("unpack_leaf: wrong end signature found - %x, block %lu", v16, bh->b_blocknr); reiserfs_buffer_mkuptodate (bh, 1); reiserfs_buffer_mkdirty (bh); reiserfs_buffer_write (bh); /* if (reiserfs_fs_block(fs, bh->b_blocknr) == BT_UNKNOWN) data_blocks_unpacked ++; */ reiserfs_buffer_close (bh); if (what_unpacked) reiserfs_bitmap_set_bit (what_unpacked, bh->b_blocknr); /*unpacked ++;*/ if (!(++ unpacked_leaves % 10)) fprintf (stderr, "#"); } static void unpack_full_block (int dev, int blocksize) { static int full_blocks_unpacked = 0; __u32 block; reiserfs_bh_t * bh; fread_le32 (&block); if (verbose) fprintf (stderr, "full #%d\n", block); bh = reiserfs_buffer_open (dev, block, blocksize); if (!bh) misc_die ("unpack_full_block: reiserfs_buffer_open failed"); fread (bh->b_data, bh->b_size, 1, stdin); if (reiserfs_node_type (bh) == NT_SUPER && !what_unpacked) { unsigned long blocks; reiserfs_bh_t * tmp; blocks = reiserfs_sb_get_blocks ((reiserfs_sb_t *)(bh->b_data)); fprintf (stderr, "There were %lu blocks on the device\n", blocks); what_unpacked = reiserfs_bitmap_create (blocks); /* make file as long as filesystem is */ tmp = reiserfs_buffer_open (dev, blocks - 1, blocksize); reiserfs_buffer_mkdirty (tmp); reiserfs_buffer_mkuptodate (tmp, 0); reiserfs_buffer_write (tmp); reiserfs_buffer_close (tmp); } reiserfs_buffer_mkuptodate (bh, 1); reiserfs_buffer_mkdirty (bh); reiserfs_buffer_write (bh); /* if (reiserfs_fs_block(fs, bh->b_blocknr) == BT_UNKNOWN) data_blocks_unpacked ++; */ reiserfs_buffer_close (bh); if (what_unpacked) reiserfs_bitmap_set_bit (what_unpacked, block); /*unpacked ++;*/ if (!(++ full_blocks_unpacked % 50)) fprintf (stderr, "."); } /* just skip bitmaps of unformatted nodes */ static void unpack_unformatted_bitmap (int dev, int blocksize) { __u16 bmap_num; __u32 block_count; int i; char * buf; fread_le16 (&bmap_num); fread_le32 (&block_count); buf = malloc (blocksize); if (!buf) reiserfs_panic ("unpack_unformatted_bitmap: malloc failed: %m"); for (i = 0; i < bmap_num; i ++) { if (fread (buf, blocksize, 1, stdin) != 1) reiserfs_panic ("unpack_unformatted_bitmap: " "could not read bitmap #%d: %m", i); } free (buf); } // read packed reiserfs partition metadata from stdin void unpack_partition (int fd, int jfd) { __u32 magic32; long position; __u16 magic16; __u16 blocksize; int dev = fd; fread_le32 (&magic32); if (magic32 != REISERFS_SUPER_MAGIC) misc_die ("unpack_partition: reiserfs magic number (0x%x) not found - %x\n", REISERFS_SUPER_MAGIC, magic32); fread_le16 (&blocksize); if (verbose) fprintf (stderr, "Blocksize %d\n", blocksize); while (!feof (stdin)) { char c[2]; fread (c, 1, 1, stdin); switch (c[0]) { case '.': if (verbose) fprintf (stderr, "\".\" skipped\n"); continue; case '1': fread (c, 1, 1, stdin); /* that was 100%, read in first 0 */ case '2': case '4': case '6': case '8': fread (c, 1, 1, stdin); case '0': fread (c + 1, 1, 1, stdin); /* read % */ if (c[0] != '0' || c[1] != '%') misc_die ("0%% expected\n"); if (verbose) fprintf (stderr, "0%% skipped\n"); continue; } fread (c + 1, 1, 1, stdin); magic16 = le16_to_cpu(*(__u16 *)c); /*fread16 (&magic16);*/ switch (magic16 & 0xff) { case LEAF_START_MAGIC: leaves ++; unpack_leaf (dev, reiserfs_hash_func (magic16 >> 8), blocksize); break; case SEPARATED_JOURNAL_START_MAGIC: if (Default_journal) misc_die ("file name for separated journal has to be specified"); dev = jfd; break; case SEPARATED_JOURNAL_END_MAGIC: dev = fd; break; case FULL_BLOCK_START_MAGIC: full ++; unpack_full_block (dev, blocksize); break; case UNFORMATTED_BITMAP_START_MAGIC: fprintf (stderr, "\nBitmap of unformatted - ignored\n"); unpack_unformatted_bitmap (dev, blocksize); break; case END_MAGIC: goto out; default: position = ftell(stdin); if (position == ~(long)0) misc_die ("unpack_partition: bad magic found - %x", magic16 & 0xff); else misc_die ("unpack_partition: bad magic found - %x, position %lu", magic16 & 0xff, ftell(stdin)); } } out: fprintf (stderr, "Unpacked %d leaves, %d full blocks\n", leaves, full); /* fclose (block_list);*/ } int do_unpack(char *host, char *j_filename, char *filename, int verbose) { int fd, fdj = -2; struct rlimit lim = {RLIM_INFINITY, RLIM_INFINITY}; if (filename == NULL) filename = ".bitmap"; if (j_filename) Default_journal = 0; /* with this 2.4.0-test9's file_write does not send SIGXFSZ */ if (setrlimit (RLIMIT_FSIZE, &lim)) { fprintf (stderr, "sertlimit failed: %m\n"); } if (util_device_mounted(host) > 0) { fprintf(stderr, "%s seems mounted, umount it first\n", host); return 0; } fd = open (host, O_RDWR #ifdef O_LARGEFILE | O_LARGEFILE #endif ); if (fd == -1) { perror ("open failed"); return 0; } if (!Default_journal) { fdj = open (j_filename, O_RDWR #ifdef O_LARGEFILE | O_LARGEFILE #endif ); if (fdj == -1) { perror ("open failed"); return 0; } } unpack_partition (fd, fdj); if (what_unpacked && filename) { FILE * file = util_file_open(filename, "w+"); reiserfs_bitmap_save (file, what_unpacked); fclose (file); } close (fd); if (!Default_journal) close (fdj); return 0; }