Logo Search packages:      
Sourcecode: partclone version File versions  Download package

jfsclone.c

/**
 * jfsclone.c - part of Partclone project
 *
 * Copyright (c) 2007~ Thomas Tsai <thomas at nchc org tw>
 *
 * read reiserfs super block and bitmap
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */


#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
#include <stdarg.h>
#include <getopt.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <sys/types.h>
#include <linux/types.h>

#include <jfs/jfs_types.h>
#include <jfs/jfs_superblock.h>
#include <jfs/jfs_dmap.h>
#include <jfs/jfs_imap.h>
#include <jfs/jfs_filsys.h>
#include <jfs/jfs_logmgr.h>
#include <jfs/jfs_dinode.h>
#include <jfs/jfs_xtree.h>
#include <jfs/jfs_byteorder.h>
#include <jfs/devices.h>

#include "partclone.h"
#include "jfsclone.h"
#include "progress.h"
#include "fs_common.h"

/* DMAP BLOCK TYPES     */
#define DMAP      -1
#define LEVEL0    0
#define LEVEL1    1
#define LEVEL2    2

/* DMAP BLOCK CALCULATIONS */
#define L0FACTOR  (LPERCTL + 1) //LPERCTL=1024
#define L1FACTOR  ((L0FACTOR * LPERCTL) + 1)
#define L1PAGE(l1)      (2 + ((l1) * L1FACTOR))
#define L0PAGE(l1, l0)  (L1PAGE(l1) + 1 + ((l0) * L0FACTOR))
#define DMAPPAGE(l1, l0, d)   (L0PAGE(l1, l0) + 1 + (d))

#define XT_CMP(CMP, K, X) \
{ \
    int64_t offset64 = offsetXAD(X); \
    (CMP) = ((K) >= offset64 + lengthXAD(X)) ? 1 : \
    ((K) < offset64) ? -1 : 0 ; \
}


static int decode_pagenum(int64_t page, int *l1, int *l0, int *dmap);
static int find_iag(unsigned iagnum, unsigned which_table, int64_t * address);
static int find_inode(unsigned inum, unsigned which_table, int64_t * address);
static int xRead(int64_t, unsigned, char *);
static int jfs_bit_inuse(unsigned *bitmap, uint64_t block);
static uint64_t get_all_used_blocks(uint64_t *total_blocks, uint64_t *used_blocks);

struct superblock sb;
FILE *fp;
int bsize;
short l2bsize;
unsigned jfs_type;

char *EXECNAME = "partclone.jfs";
extern fs_cmd_opt fs_opt;

/// open device
static void fs_open(char* device){
    fp = fopen(device, "r+");
    if (fp == NULL) {
      log_mesg(0, 1, 1, fs_opt.debug, "%s: Cannot open device %s.\n", __FILE__, device);
    }

    if (ujfs_get_superblk(fp, &sb, 1)) {
      log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading primary superblock\n", __FILE__);
      if (ujfs_get_superblk(fp, &sb, 0)) {
          log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading secondary superblock\n", __FILE__);
      } else
          log_mesg(1, 0, 0, fs_opt.debug, "%s: using secondary superblock\n", __FILE__);
    }
    jfs_type = sb.s_flag;
    l2bsize = sb.s_l2bsize;
    bsize = sb.s_bsize;

    log_mesg(1, 0, 0, fs_opt.debug, "%s: type = %u\n", __FILE__, sb.s_flag);
    log_mesg(1, 0, 0, fs_opt.debug, "%s: block size = %i\n", __FILE__, sb.s_bsize);
    log_mesg(1, 0, 0, fs_opt.debug, "%s: magic = %s\n", __FILE__, sb.s_magic);
    log_mesg(1, 0, 0, fs_opt.debug, "%s: version = %u\n", __FILE__, sb.s_version);
    log_mesg(1, 0, 0, fs_opt.debug, "%s: blocks = %lli\n", __FILE__, sb.s_size);
    log_mesg(1, 0, 0, fs_opt.debug, "%s: l2bsize = %i\n", __FILE__, sb.s_l2bsize);
}

/// close device
static void fs_close(){
    fclose(fp);
}

/// readbitmap - read bitmap
extern void readbitmap(char* device, image_head image_hdr, char*bitmap, int pui){

    int64_t lblock = 0;
    int64_t address;
    int64_t cntl_addr;
    int ret = 1;
    struct dinode bmap_inode;
    struct dbmap cntl_page;
    int dmap_l2bpp;
    int64_t d_address;
    struct dmap d_map;
    int dmap_i, l0, l1;
    int next = 1;
    int64_t btotal, bfree;
    int64_t tub;
    int64_t tb=0;
    int64_t pb = 1;
    int64_t block_used = 0;
    int64_t block_free = 0;
    uint64_t logloc = 0;
    int logsize = 0;
    int dmap_level = 0;
    int64_t dn_mapsize = 0;

    int start = 0;
    int bit_size = 1;

    fs_open(device);
    /// Read Blocal Allocation Map  Inode 
    ret = find_inode(BMAP_I, AGGREGATE_I, &address);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):find_node error.\n", __FILE__, __LINE__);
    }

    ret = xRead(address, sizeof(struct dinode), (char *) &bmap_inode);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__);
    }

    /// Read overall control page for the map 
    ret = ujfs_rwdaddr(fp, &cntl_addr, &bmap_inode, (int64_t) 0, GET, bsize);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__);
    }

    ret = xRead(cntl_addr, sizeof(struct dbmap), (char *) &cntl_page);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error %i\n", __FILE__, __LINE__);
    }
    dn_mapsize = cntl_page.dn_mapsize;
    dmap_level = BMAPSZTOLEV(cntl_page.dn_mapsize);
    dmap_l2bpp = cntl_page.dn_l2nbperpage;

    /// display leaf 

    lblock = 0; //control page
    decode_pagenum(lblock, &l1, &l0, &dmap_i);
    ret = ujfs_rwdaddr(fp, &d_address, &bmap_inode, (lblock) << dmap_l2bpp, GET, bsize);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__);
    }

    ret = xRead(d_address, sizeof(struct dmap), (char *)&d_map);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__);
    }

    /// ujfs_swap_dmap(&d_map); fixme

    log_mesg(2, 0, 0, fs_opt.debug, "%s: Dmap page at block %lld\n", __FILE__, (long long) (d_address >> sb.s_l2bsize));
    log_mesg(2, 0, 0, fs_opt.debug, "%s: control nblocks %d\n", __FILE__, d_map.nblocks);
    log_mesg(2, 0, 0, fs_opt.debug, "%s: control nfree %d\n", __FILE__, d_map.nfree);
    lblock = 4; //First map page

    logloc  = addressPXD(&(sb.s_logpxd));
    logsize = lengthPXD(&(sb.s_logpxd));
    log_mesg(1, 0, 0, fs_opt.debug, "%s: logloc %lli, logsize %i\n", __FILE__, logloc, logsize);

    /// init progress
    progress_bar        prog;           /// progress_bar structure defined in progress.h
    progress_init(&prog, start, image_hdr.totalblock, bit_size);
    memset(bitmap, 1, image_hdr.totalblock);

    while(next){
      block_used = 0;
      block_free = 0;
      log_mesg(2, 0, 0, fs_opt.debug, "%s:lblock = %lli\n", __FILE__, lblock);
      decode_pagenum(lblock, &l1, &l0, &dmap_i);
      ret = ujfs_rwdaddr(fp, &d_address, &bmap_inode, (lblock) << dmap_l2bpp, GET, bsize);
      if (ret){
          log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__);
      }

      ret = xRead(d_address, sizeof(struct dmap), (char *)&d_map);
      if (ret){
          log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__);
      }

      ///ujfs_swap_dmap(&d_map);

      log_mesg(2, 0, 0, fs_opt.debug, "%s: Dmap page at block %lld\n", __FILE__, (long long) (d_address >> sb.s_l2bsize));
      log_mesg(2, 0, 0, fs_opt.debug, "%s: nblocks %d\n", __FILE__, d_map.nblocks);
      log_mesg(2, 0, 0, fs_opt.debug, "%s: nfree %d\n", __FILE__, d_map.nfree);

      /// bitmap information not cover all partition

      /// display bitmap  

      for (pb = 0; (pb < d_map.nblocks) && (tb < dn_mapsize); pb++){

          if (jfs_bit_inuse(d_map.wmap, pb) == 1){
            block_used++;
            log_mesg(3, 0, 0, fs_opt.debug, "%s: used pb = %lli tb = %lli\n", __FILE__, pb, tb);
            bitmap[tb] = 1;
          } else {
            block_free++;
            log_mesg(3, 0, 0, fs_opt.debug, "%s: free pb = %lli tb = %lli\n", __FILE__, pb, tb);
            bitmap[tb] = 0;
          }
          tb++;
          update_pui(&prog, tb, 0);//keep update

      }
      log_mesg(2, 0, 0, fs_opt.debug, "%s:block_used %lli block_free %lli\n", __FILE__, block_used, block_free);
      tub += block_used;

        next = 0;
      if (dmap_i < LPERCTL - 1){
          lblock = DMAPPAGE(l1, l0, dmap_i + 1);
          next = 1;
        }
        if (dmap_level > 0) {
            if (l0 < LPERCTL - 1){
                lblock = DMAPPAGE(l1, l0+1, 0);
                next = 1;
            }
            if ((dmap_level == 2) && (l1 < LPERCTL - 1)) {
                lblock = DMAPPAGE(l1+1, 0, 0);
                next = 1;
            }
        }

        if (tb >= dn_mapsize)
            next = 0;

      if (d_map.nblocks == 0)
          next = 0;
    }

    /// log
    for (;tb <= image_hdr.totalblock; tb++){

      if ((tb >= logloc) && (tb < (logloc+logsize))){
          bitmap[tb] = 1;
          block_used++;
          log_mesg(3, 0, 0, fs_opt.debug, "%s: log used pb = %lli tb = %lli\n", __FILE__, pb, tb);
      }
      update_pui(&prog, tb, 0);//keep update

    }

    log_mesg(2, 0, 0, fs_opt.debug, "%s:total_used = %lli\n", __FILE__, tub);
    fs_close();
    update_pui(&prog, 1, 1);//finish

}


/// read super block and write to image head
extern void initial_image_hdr(char* device, image_head* image_hdr){
    uint64_t used_blocks = 0;
    uint64_t total_blocks = 0;
    fs_open(device);
    get_all_used_blocks(&total_blocks, &used_blocks);
    strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE);
    strncpy(image_hdr->fs, jfs_MAGIC, FS_MAGIC_SIZE);
    image_hdr->block_size = (int)sb.s_bsize;
    image_hdr->totalblock = (unsigned long long)total_blocks;
    image_hdr->usedblocks = (unsigned long long)used_blocks;
    image_hdr->device_size =(unsigned long long)(total_blocks * sb.s_bsize);
    fs_close();
}

/// get_all_used_blocks
extern uint64_t get_all_used_blocks(uint64_t *total_blocks, uint64_t *used_blocks){

    int64_t lblock = 0;
    int64_t address;
    int64_t cntl_addr;
    int ret = 1;
    struct dinode bmap_inode;
    struct dbmap cntl_page;
    int dmap_l2bpp;
    int64_t d_address;
    struct dmap d_map;
    int dmap, l0, l1;
    int next = 1;
    int64_t btotal, bfree;
    int64_t tub;
    int64_t tb=0;
    int64_t pb = 0;
    int64_t block_used = 0;
    int64_t block_free = 0;
    int64_t bytes_on_device = 0;
    int logsize = 0;


    /// Read Blocal Allocation Map  Inode 
    ret = find_inode(BMAP_I, AGGREGATE_I, &address);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):find_node error.\n", __FILE__, __LINE__);
    }

    ret = xRead(address, sizeof(struct dinode), (char *) &bmap_inode);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__);
    }

    /// Read overall control page for the map 
    ret = ujfs_rwdaddr(fp, &cntl_addr, &bmap_inode, (int64_t) 0, GET, bsize);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__);
    }

    ret = xRead(cntl_addr, sizeof(struct dbmap), (char *) &cntl_page);
    if (ret){
      log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__);
    }
    logsize = lengthPXD(&(sb.s_logpxd));
    ret = ujfs_get_dev_size(fp, &bytes_on_device);
    *total_blocks = bytes_on_device / sb.s_bsize;
    *used_blocks = (cntl_page.dn_mapsize - cntl_page.dn_nfree + logsize);

    log_mesg(2, 0, 0, fs_opt.debug, "%s: dn.mapsize = %lli\n", __FILE__, cntl_page.dn_mapsize);
    log_mesg(2, 0, 0, fs_opt.debug, "%s: total_blocks = %lli\n", __FILE__, *total_blocks);
    log_mesg(2, 0, 0, fs_opt.debug, "%s: free_blocks = %lli\n", __FILE__, cntl_page.dn_nfree);
    log_mesg(2, 0, 0, fs_opt.debug, "%s: log_blocks = %i\n", __FILE__, logsize);

}



int decode_pagenum(int64_t page, int *l1, int *l0, int *dmap)
{
    int remainder;

    if (page == 0)
      return -1;

    if (page == 1)
      return LEVEL2;

    *l1 = (page - 2) / L1FACTOR;
    remainder = (page - 2) % L1FACTOR;
    if (remainder == 0)
      return LEVEL1;

    *l0 = (remainder - 1) / L0FACTOR;
    remainder = (remainder - 1) % L0FACTOR;
    if (remainder == 0)
      return LEVEL0;

    *dmap = remainder - 1;
    return DMAP;
}


int find_inode(unsigned inum, unsigned which_table, int64_t * address)
{
    int extnum;
    struct iag iag;
    int iagnum;
    int64_t map_address;
    int rc;

    iagnum = INOTOIAG(inum);
    extnum = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT;
    if (find_iag(iagnum, which_table, &map_address) == 1)
      return 1;

    rc = ujfs_rw_diskblocks(fp, map_address, sizeof (struct iag), &iag, GET);
    if (rc) {
      log_mesg(1, 1, 1, fs_opt.debug, "%s: find_inode: Error reading iag\n", __FILE__);
      return 1;
    }

    /* swap if on big endian machine */
    ///ujfs_swap_iag(&iag);

    if (iag.inoext[extnum].len == 0)
      return 1;

    *address = (addressPXD(&iag.inoext[extnum]) << l2bsize) + ((inum & (INOSPEREXT - 1)) * sizeof (struct dinode));
    return 0;
}

int xRead(int64_t address, unsigned count, char *buffer)
{
    int64_t block_address;
    char *block_buffer;
    int64_t length;
    unsigned offset;

    offset = address & (bsize - 1);
    length = (offset + count + bsize - 1) & ~(bsize - 1);
    log_mesg(3, 0, 0, fs_opt.debug, "%s: offset %i, length %lli, count %i, address %lli\n", __FILE__, offset , length , count , address);

    if ((offset == 0) & (length == count))
      return ujfs_rw_diskblocks(fp, address, count, buffer, GET);

    block_address = address - offset;
    block_buffer = (char *) malloc(length);
    if (block_buffer == 0)
      return 1;

    if (ujfs_rw_diskblocks(fp, block_address, length, block_buffer, GET)) {
      log_mesg(3, 0, 0, fs_opt.debug, "%s: block_address %lli , length %lli , GET %i \n", __FILE__, block_address, length, GET);
      free(block_buffer);
      return 1;
    }
    memcpy(buffer, block_buffer + offset, count);
    free(block_buffer);
    log_mesg(3, 0, 0, fs_opt.debug, "%s: done: offset %i, length %lli, count %i, address %lli\n", __FILE__, offset , length , count , address);
    return 0;
}

int find_iag(unsigned iagnum, unsigned which_table, int64_t * address)
{
    int base;
    char buffer[PSIZE];
    int cmp;
    struct dinode fileset_inode;
    int64_t fileset_inode_address;
    int64_t iagblock;
    int index;
    int lim;
    xtpage_t *page;
    int rc;

    int64_t AIT_2nd_offset = addressPXD(&(sb.s_ait2)) * sb.s_bsize;

    if (which_table != FILESYSTEM_I &&
          which_table != AGGREGATE_I && which_table != AGGREGATE_2ND_I) {
      log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Invalid fileset, %d\n", __FILE__, which_table);
      return 1;
    }
    iagblock = IAGTOLBLK(iagnum, L2PSIZE - l2bsize);

    if (which_table == AGGREGATE_2ND_I) {
      fileset_inode_address = AIT_2nd_offset + sizeof (struct dinode);
    } else {
      fileset_inode_address = AGGR_INODE_TABLE_START + (which_table * sizeof (struct dinode));
    }
    rc = xRead(fileset_inode_address, sizeof (struct dinode), (char *) &fileset_inode);
    if (rc) {
      log_mesg(1, 1, 1, fs_opt.debug, "%s: find_inode: Error reading fileset inode\n", __FILE__);
      return 1;
    }

    page = (xtpage_t *) & (fileset_inode.di_btroot);

descend:
    /* Binary search */
    for (base = XTENTRYSTART,
          lim = __le16_to_cpu(page->header.nextindex) - XTENTRYSTART; lim; lim >>= 1) {
      index = base + (lim >> 1);
      XT_CMP(cmp, iagblock, &(page->xad[index]));
      if (cmp == 0) {
          /* HIT! */
          if (page->header.flag & BT_LEAF) {
            *address = (addressXAD(&(page->xad[index]))
                  + (iagblock - offsetXAD(&(page->xad[index]))))
                << l2bsize;
            return 0;
          } else {
            rc = xRead(addressXAD(&(page->xad[index])) << l2bsize,
                  PSIZE, buffer);
            if (rc) {
                log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Error reading btree node\n", __FILE__);
                return 1;
            }
            page = (xtpage_t *) buffer;

            goto descend;
          }
      } else if (cmp > 0) {
          base = index + 1;
          --lim;
      }
    }

    if (page->header.flag & BT_INTERNAL) {
      /* Traverse internal page, it might hit down there
       * If base is non-zero, decrement base by one to get the parent
       * entry of the child page to search.
       */
      index = base ? base - 1 : base;

      rc = xRead(addressXAD(&(page->xad[index])) << l2bsize, PSIZE, buffer);
      if (rc) {
          log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Error reading btree node\n", __FILE__);
          return 1;
      }
      page = (xtpage_t *) buffer;

      goto descend;
    }

    /* Not found! */
    log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag:  IAG %d not found!\n", __FILE__, iagnum);
    return 1;
}

int jfs_bit_inuse(unsigned *bitmap, uint64_t block){
    uint64_t byte = 0;
    int bit = 0;

    byte = block/32;
    bit  = 31 - (block%32);
    log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap = %08x\n", __FILE__, bitmap[byte]); 

    if(bitmap[byte] & (1<<bit))
      return 1;
    else
      return 0;
}



Generated by  Doxygen 1.6.0   Back to index