|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <ctype.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <stdint.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <sys/types.h>
|
|
Packit Service |
360c39 |
#include <linux/types.h>
|
|
Packit Service |
360c39 |
#include <sys/stat.h>
|
|
Packit Service |
360c39 |
#include <fcntl.h>
|
|
Packit Service |
360c39 |
#include <unistd.h>
|
|
Packit Service |
360c39 |
#include <errno.h>
|
|
Packit Service |
360c39 |
#include <curses.h>
|
|
Packit Service |
360c39 |
#include <term.h>
|
|
Packit Service |
360c39 |
#include <sys/ioctl.h>
|
|
Packit Service |
360c39 |
#include <limits.h>
|
|
Packit Service |
360c39 |
#include <sys/time.h>
|
|
Packit Service |
360c39 |
#include <linux/gfs2_ondisk.h>
|
|
Packit Service |
360c39 |
#include <zlib.h>
|
|
Packit Service |
360c39 |
#include <time.h>
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <logging.h>
|
|
Packit Service |
360c39 |
#include "osi_list.h"
|
|
Packit Service |
360c39 |
#include "gfs2hex.h"
|
|
Packit Service |
360c39 |
#include "hexedit.h"
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#define DFT_SAVE_FILE "/tmp/gfsmeta.XXXXXX"
|
|
Packit Service |
360c39 |
#define MAX_JOURNALS_SAVED 256
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Header for the savemeta output file */
|
|
Packit Service |
360c39 |
struct savemeta_header {
|
|
Packit Service |
360c39 |
#define SAVEMETA_MAGIC (0x01171970)
|
|
Packit Service |
360c39 |
uint32_t sh_magic;
|
|
Packit Service |
360c39 |
#define SAVEMETA_FORMAT (1)
|
|
Packit Service |
360c39 |
uint32_t sh_format; /* In case we want to change the layout */
|
|
Packit Service |
360c39 |
uint64_t sh_time; /* When savemeta was run */
|
|
Packit Service |
360c39 |
uint64_t sh_fs_bytes; /* Size of the fs */
|
|
Packit Service |
360c39 |
uint8_t __reserved[104];
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct saved_metablock {
|
|
Packit Service |
360c39 |
uint64_t blk;
|
|
Packit Service |
360c39 |
uint16_t siglen; /* significant data length */
|
|
Packit Service |
360c39 |
/* This needs to be packed because old versions of gfs2_edit read and write the
|
|
Packit Service |
360c39 |
individual fields separately, so the hole after siglen must be eradicated
|
|
Packit Service |
360c39 |
before the struct reflects what's on disk. */
|
|
Packit Service |
360c39 |
} __attribute__((__packed__));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metafd {
|
|
Packit Service |
360c39 |
int fd;
|
|
Packit Service |
360c39 |
gzFile gzfd;
|
|
Packit Service |
360c39 |
const char *filename;
|
|
Packit Service |
360c39 |
int gziplevel;
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static uint64_t blks_saved;
|
|
Packit Service |
360c39 |
static uint64_t journal_blocks[MAX_JOURNALS_SAVED];
|
|
Packit Service |
360c39 |
static uint64_t gfs1_journal_size = 0; /* in blocks */
|
|
Packit Service |
360c39 |
static int journals_found = 0;
|
|
Packit Service |
360c39 |
int print_level = MSG_NOTICE;
|
|
Packit Service |
360c39 |
extern char *device;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int block_is_a_journal(uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int j;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (j = 0; j < journals_found; j++)
|
|
Packit Service |
360c39 |
if (blk == journal_blocks[j])
|
|
Packit Service |
360c39 |
return TRUE;
|
|
Packit Service |
360c39 |
return FALSE;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct osi_root per_node_tree;
|
|
Packit Service |
360c39 |
struct per_node_node {
|
|
Packit Service |
360c39 |
struct osi_node node;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void destroy_per_node_lookup(void)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node *n;
|
|
Packit Service |
360c39 |
struct per_node_node *pnp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while ((n = osi_first(&per_node_tree))) {
|
|
Packit Service |
360c39 |
pnp = (struct per_node_node *)n;
|
|
Packit Service |
360c39 |
osi_erase(n, &per_node_tree);
|
|
Packit Service |
360c39 |
free(pnp);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int block_is_in_per_node(uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (pnp) {
|
|
Packit Service |
360c39 |
if (blk < pnp->block)
|
|
Packit Service |
360c39 |
pnp = (struct per_node_node *)pnp->node.osi_left;
|
|
Packit Service |
360c39 |
else if (blk > pnp->block)
|
|
Packit Service |
360c39 |
pnp = (struct per_node_node *)pnp->node.osi_right;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int insert_per_node_lookup(uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node **newn = &per_node_tree.osi_node, *parent = NULL;
|
|
Packit Service |
360c39 |
struct per_node_node *pnp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (*newn) {
|
|
Packit Service |
360c39 |
struct per_node_node *cur = (struct per_node_node *)*newn;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
parent = *newn;
|
|
Packit Service |
360c39 |
if (blk < cur->block)
|
|
Packit Service |
360c39 |
newn = &((*newn)->osi_left);
|
|
Packit Service |
360c39 |
else if (blk > cur->block)
|
|
Packit Service |
360c39 |
newn = &((*newn)->osi_right);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
pnp = calloc(1, sizeof(struct per_node_node));
|
|
Packit Service |
360c39 |
if (pnp == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to insert per_node lookup entry");
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
pnp->block = blk;
|
|
Packit Service |
360c39 |
osi_link_node(&pnp->node, parent, newn);
|
|
Packit Service |
360c39 |
osi_insert_color(&pnp->node, &per_node_tree);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int init_per_node_lookup(void)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
struct gfs2_inode *per_node_di;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sbd.gfs1)
|
|
Packit Service |
360c39 |
return FALSE;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node"));
|
|
Packit Service |
360c39 |
if (per_node_di == NULL) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Failed to read per_node: %s\n", strerror(errno));
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do_dinode_extended(&per_node_di->i_di, per_node_di->i_bh);
|
|
Packit Service |
360c39 |
inode_put(&per_node_di);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (i = 0; i < indirect_blocks; i++) {
|
|
Packit Service |
360c39 |
int d;
|
|
Packit Service |
360c39 |
for (d = 0; d < indirect->ii[i].dirents; d++) {
|
|
Packit Service |
360c39 |
int ret = insert_per_node_lookup(indirect->ii[i].dirent[d].block);
|
|
Packit Service |
360c39 |
if (ret != 0)
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int block_is_systemfile(uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return block_is_jindex(blk) || block_is_inum_file(blk) ||
|
|
Packit Service |
360c39 |
block_is_statfs_file(blk) || block_is_quota_file(blk) ||
|
|
Packit Service |
360c39 |
block_is_rindex(blk) || block_is_a_journal(blk) ||
|
|
Packit Service |
360c39 |
block_is_per_node(blk) || block_is_in_per_node(blk);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* anthropomorphize - make a uint64_t number more human
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static const char *anthropomorphize(unsigned long long inhuman_value)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
const char *symbols = " KMGTPE";
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
unsigned long long val = inhuman_value, remainder = 0;
|
|
Packit Service |
360c39 |
static char out_val[32];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(out_val, 0, sizeof(out_val));
|
|
Packit Service |
360c39 |
for (i = 0; i < 6 && val > 1024; i++) {
|
|
Packit Service |
360c39 |
remainder = val % 1024;
|
|
Packit Service |
360c39 |
val /= 1024;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
sprintf(out_val, "%llu.%llu%cB", val, remainder, symbols[i]);
|
|
Packit Service |
360c39 |
return out_val;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static size_t di_save_len(struct gfs2_buffer_head *bh, uint64_t owner)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *inode;
|
|
Packit Service |
360c39 |
struct gfs2_dinode *dn;
|
|
Packit Service |
360c39 |
size_t len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sbd.gfs1)
|
|
Packit Service |
360c39 |
inode = lgfs2_gfs_inode_get(&sbd, bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
inode = lgfs2_inode_get(&sbd, bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode == NULL) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Error reading inode at %"PRIu64": %s\n",
|
|
Packit Service |
360c39 |
bh->b_blocknr, strerror(errno));
|
|
Packit Service |
360c39 |
return 0; /* Skip the block */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
dn = &inode->i_di;
|
|
Packit Service |
360c39 |
len = sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Do not save (user) data from the inode block unless they are
|
|
Packit Service |
360c39 |
indirect pointers, dirents, symlinks or fs internal data */
|
|
Packit Service |
360c39 |
if (dn->di_height != 0 ||
|
|
Packit Service |
360c39 |
S_ISDIR(dn->di_mode) ||
|
|
Packit Service |
360c39 |
S_ISLNK(dn->di_mode) ||
|
|
Packit Service |
360c39 |
(sbd.gfs1 && dn->__pad1 == GFS_FILE_DIR) ||
|
|
Packit Service |
360c39 |
block_is_systemfile(owner))
|
|
Packit Service |
360c39 |
len = sbd.bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
inode_put(&inode;;
|
|
Packit Service |
360c39 |
return len;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* get_gfs_struct_info - get block type and structure length
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* @lbh - The block buffer to examine
|
|
Packit Service |
360c39 |
* @owner - The block address of the parent structure
|
|
Packit Service |
360c39 |
* @block_type - pointer to integer to hold the block type
|
|
Packit Service |
360c39 |
* @gstruct_len - pointer to integer to hold the structure length
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* returns: 0 if successful
|
|
Packit Service |
360c39 |
* -1 if this isn't gfs metadata.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int get_gfs_struct_info(struct gfs2_buffer_head *lbh, uint64_t owner,
|
|
Packit Service |
360c39 |
int *block_type, size_t *gstruct_len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (block_type != NULL)
|
|
Packit Service |
360c39 |
*block_type = 0;
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_meta_header_in(&mh, lbh->b_data);
|
|
Packit Service |
360c39 |
if (mh.mh_magic != GFS2_MAGIC)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (block_type != NULL)
|
|
Packit Service |
360c39 |
*block_type = mh.mh_type;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
switch (mh.mh_type) {
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_SB: /* 1 (superblock) */
|
|
Packit Service |
360c39 |
*gstruct_len = sizeof(struct gfs_sb);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_RG: /* 2 (rsrc grp hdr) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize; /*sizeof(struct gfs_rgrp);*/
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_RB: /* 3 (rsrc grp bitblk) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_DI: /* 4 (disk inode) */
|
|
Packit Service |
360c39 |
*gstruct_len = di_save_len(lbh, owner);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_IN: /* 5 (indir inode blklst) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize; /*sizeof(struct gfs_indirect);*/
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_LF: /* 6 (leaf dinode blklst) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize; /*sizeof(struct gfs_leaf);*/
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_JD: /* 7 (journal data) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_LH: /* 8 (log header) */
|
|
Packit Service |
360c39 |
if (sbd.gfs1)
|
|
Packit Service |
360c39 |
*gstruct_len = 512; /* gfs copies the log header
|
|
Packit Service |
360c39 |
twice and compares the copy,
|
|
Packit Service |
360c39 |
so we need to save all 512
|
|
Packit Service |
360c39 |
bytes of it. */
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
*gstruct_len = sizeof(struct gfs2_log_header);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_LD: /* 9 (log descriptor) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_EA: /* 10 (extended attr hdr) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case GFS2_METATYPE_ED: /* 11 (extended attr data) */
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
default:
|
|
Packit Service |
360c39 |
*gstruct_len = sbd.bsize;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Put out a warm, fuzzy message every second so the user */
|
|
Packit Service |
360c39 |
/* doesn't think we hung. (This may take a long time). */
|
|
Packit Service |
360c39 |
/* We only check whether to report every one percent because */
|
|
Packit Service |
360c39 |
/* checking every block kills performance. We only report */
|
|
Packit Service |
360c39 |
/* every second because we don't need 100 extra messages in */
|
|
Packit Service |
360c39 |
/* logs made from verbose mode. */
|
|
Packit Service |
360c39 |
static void warm_fuzzy_stuff(uint64_t wfsblock, int force)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
static struct timeval tv;
|
|
Packit Service |
360c39 |
static uint32_t seconds = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gettimeofday(&tv, NULL);
|
|
Packit Service |
360c39 |
if (!seconds)
|
|
Packit Service |
360c39 |
seconds = tv.tv_sec;
|
|
Packit Service |
360c39 |
if (force || tv.tv_sec - seconds) {
|
|
Packit Service |
360c39 |
static uint64_t percent;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
seconds = tv.tv_sec;
|
|
Packit Service |
360c39 |
if (sbd.fssize) {
|
|
Packit Service |
360c39 |
printf("\r");
|
|
Packit Service |
360c39 |
percent = (wfsblock * 100) / sbd.fssize;
|
|
Packit Service |
360c39 |
printf("%llu blocks processed, %llu saved (%llu%%)",
|
|
Packit Service |
360c39 |
(unsigned long long)wfsblock,
|
|
Packit Service |
360c39 |
(unsigned long long)blks_saved,
|
|
Packit Service |
360c39 |
(unsigned long long)percent);
|
|
Packit Service |
360c39 |
if (force)
|
|
Packit Service |
360c39 |
printf("\n");
|
|
Packit Service |
360c39 |
fflush(stdout);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Open a file and prepare it for writing by savemeta()
|
|
Packit Service |
360c39 |
* out_fn: the path to the file, which will be truncated if it exists
|
|
Packit Service |
360c39 |
* gziplevel: 0 - do not compress the file,
|
|
Packit Service |
360c39 |
* 1-9 - use gzip compression level 1-9
|
|
Packit Service |
360c39 |
* Returns a struct metafd containing the opened file descriptor
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static struct metafd savemetaopen(char *out_fn, int gziplevel)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct metafd mfd = {-1, NULL, NULL, gziplevel};
|
|
Packit Service |
360c39 |
char gzmode[3] = "w9";
|
|
Packit Service |
360c39 |
char dft_fn[] = DFT_SAVE_FILE;
|
|
Packit Service |
360c39 |
mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!out_fn) {
|
|
Packit Service |
360c39 |
out_fn = dft_fn;
|
|
Packit Service |
360c39 |
mfd.fd = mkstemp(out_fn);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
mfd.fd = open(out_fn, O_RDWR | O_CREAT, 0644);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
umask(mask);
|
|
Packit Service |
360c39 |
mfd.filename = out_fn;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (mfd.fd < 0) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Can't open %s: %s\n", out_fn, strerror(errno));
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ftruncate(mfd.fd, 0)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Can't truncate %s: %s\n", out_fn, strerror(errno));
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gziplevel > 0) {
|
|
Packit Service |
360c39 |
gzmode[1] = '0' + gziplevel;
|
|
Packit Service |
360c39 |
mfd.gzfd = gzdopen(mfd.fd, gzmode);
|
|
Packit Service |
360c39 |
if (!mfd.gzfd) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "gzdopen error: %s\n", strerror(errno));
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return mfd;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Write nbyte bytes from buf to a file opened with savemetaopen()
|
|
Packit Service |
360c39 |
* mfd: the file descriptor opened using savemetaopen()
|
|
Packit Service |
360c39 |
* buf: the buffer to write data from
|
|
Packit Service |
360c39 |
* nbyte: the number of bytes to write
|
|
Packit Service |
360c39 |
* Returns the number of bytes written from buf or -1 on error
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static ssize_t savemetawrite(struct metafd *mfd, const void *buf, size_t nbyte)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
ssize_t ret;
|
|
Packit Service |
360c39 |
int gzerr;
|
|
Packit Service |
360c39 |
const char *gzerrmsg;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (mfd->gziplevel == 0) {
|
|
Packit Service |
360c39 |
return write(mfd->fd, buf, nbyte);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = gzwrite(mfd->gzfd, buf, nbyte);
|
|
Packit Service |
360c39 |
if (ret != nbyte) {
|
|
Packit Service |
360c39 |
gzerrmsg = gzerror(mfd->gzfd, &gzerr);
|
|
Packit Service |
360c39 |
if (gzerr != Z_ERRNO) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Error: zlib: %s\n", gzerrmsg);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Closes a file descriptor previously opened using savemetaopen()
|
|
Packit Service |
360c39 |
* mfd: the file descriptor previously opened using savemetaopen()
|
|
Packit Service |
360c39 |
* Returns 0 on success or -1 on error
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int savemetaclose(struct metafd *mfd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int gzret;
|
|
Packit Service |
360c39 |
if (mfd->gziplevel > 0) {
|
|
Packit Service |
360c39 |
gzret = gzclose(mfd->gzfd);
|
|
Packit Service |
360c39 |
if (gzret == Z_STREAM_ERROR) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "gzclose: file is not valid\n");
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
} else if (gzret == Z_ERRNO) {
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return close(mfd->fd);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t owner, int *blktype)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct saved_metablock *savedata;
|
|
Packit Service |
360c39 |
size_t blklen;
|
|
Packit Service |
360c39 |
size_t outsz;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* If this isn't metadata and isn't a system file, we don't want it.
|
|
Packit Service |
360c39 |
Note that we're checking "owner" here rather than blk. That's
|
|
Packit Service |
360c39 |
because we want to know if the source inode is a system inode
|
|
Packit Service |
360c39 |
not the block within the inode "blk". They may or may not
|
|
Packit Service |
360c39 |
be the same thing. */
|
|
Packit Service |
360c39 |
if (get_gfs_struct_info(savebh, owner, blktype, &blklen) &&
|
|
Packit Service |
360c39 |
!block_is_systemfile(owner) && owner != 0)
|
|
Packit Service |
360c39 |
return 0; /* Not metadata, and not system file, so skip it */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* No need to save trailing zeroes */
|
|
Packit Service |
360c39 |
for (; blklen > 0 && savebh->b_data[blklen - 1] == '\0'; blklen--);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (blklen == 0) /* No significant data; skip. */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
outsz = sizeof(*savedata) + blklen;
|
|
Packit Service |
360c39 |
savedata = calloc(1, outsz);
|
|
Packit Service |
360c39 |
if (savedata == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to save block");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
savedata->blk = cpu_to_be64(savebh->b_blocknr);
|
|
Packit Service |
360c39 |
savedata->siglen = cpu_to_be16(blklen);
|
|
Packit Service |
360c39 |
memcpy(savedata + 1, savebh->b_data, blklen);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (savemetawrite(mfd, savedata, outsz) != outsz) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n",
|
|
Packit Service |
360c39 |
strerror(errno), __FUNCTION__, __LINE__,
|
|
Packit Service |
360c39 |
(unsigned long long)savedata->blk,
|
|
Packit Service |
360c39 |
(unsigned long long)savedata->blk);
|
|
Packit Service |
360c39 |
free(savedata);
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blks_saved++;
|
|
Packit Service |
360c39 |
free(savedata);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner, int *blktype)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *savebh;
|
|
Packit Service |
360c39 |
int err;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs2_check_range(&sbd, blk) && blk != LGFS2_SB_ADDR(&sbd)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "\nWarning: bad block pointer '0x%llx' "
|
|
Packit Service |
360c39 |
"ignored in block (block %llu (0x%llx))",
|
|
Packit Service |
360c39 |
(unsigned long long)blk,
|
|
Packit Service |
360c39 |
(unsigned long long)owner, (unsigned long long)owner);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
savebh = bread(&sbd, blk);
|
|
Packit Service |
360c39 |
if (savebh == NULL)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
err = save_bh(mfd, savebh, owner, blktype);
|
|
Packit Service |
360c39 |
brelse(savebh);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* save_ea_block - save off an extended attribute block
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh, uint64_t owner)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int e;
|
|
Packit Service |
360c39 |
struct gfs2_ea_header ea;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (e = sizeof(struct gfs2_meta_header); e < sbd.bsize; e += ea.ea_rec_len) {
|
|
Packit Service |
360c39 |
uint64_t blk, *b;
|
|
Packit Service |
360c39 |
int charoff, i;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_ea_header_in(&ea, metabh->b_data + e);
|
|
Packit Service |
360c39 |
for (i = 0; i < ea.ea_num_ptrs; i++) {
|
|
Packit Service |
360c39 |
charoff = e + ea.ea_name_len +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_ea_header) +
|
|
Packit Service |
360c39 |
sizeof(uint64_t) - 1;
|
|
Packit Service |
360c39 |
charoff /= sizeof(uint64_t);
|
|
Packit Service |
360c39 |
b = (uint64_t *)(metabh->b_data);
|
|
Packit Service |
360c39 |
b += charoff + i;
|
|
Packit Service |
360c39 |
blk = be64_to_cpu(*b);
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, blk, owner, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!ea.ea_rec_len)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* save_indirect_blocks - save all indirect blocks for the given buffer
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *mybh, uint64_t owner, int height, int hgt)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t old_block = 0, indir_block;
|
|
Packit Service |
360c39 |
uint64_t *ptr;
|
|
Packit Service |
360c39 |
int head_size, blktype;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *nbh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
head_size = (hgt > 1 ?
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header) :
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (ptr = (uint64_t *)(mybh->b_data + head_size);
|
|
Packit Service |
360c39 |
(char *)ptr < (mybh->b_data + sbd.bsize); ptr++) {
|
|
Packit Service |
360c39 |
if (!*ptr)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
indir_block = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
if (indir_block == old_block)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
old_block = indir_block;
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, indir_block, owner, &blktype);
|
|
Packit Service |
360c39 |
if (blktype == GFS2_METATYPE_EA) {
|
|
Packit Service |
360c39 |
nbh = bread(&sbd, indir_block);
|
|
Packit Service |
360c39 |
save_ea_block(mfd, nbh, owner);
|
|
Packit Service |
360c39 |
brelse(nbh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (height != hgt && /* If not at max height and */
|
|
Packit Service |
360c39 |
(!gfs2_check_range(&sbd, indir_block))) {
|
|
Packit Service |
360c39 |
nbh = bread(&sbd, indir_block);
|
|
Packit Service |
360c39 |
osi_list_add_prev(&nbh->b_altlist, cur_list);
|
|
Packit Service |
360c39 |
/* The buffer_head needs to be queued ahead, so
|
|
Packit Service |
360c39 |
don't release it!
|
|
Packit Service |
360c39 |
brelse(nbh);*/
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} /* for all data on the indirect block */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int save_leaf_chain(struct metafd *mfd, struct gfs2_sbd *sdp, uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_leaf leaf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
if (gfs2_check_range(sdp, blk) != 0)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
bh = bread(sdp, blk);
|
|
Packit Service |
360c39 |
if (bh == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to read leaf block");
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(blk, FALSE);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) {
|
|
Packit Service |
360c39 |
int ret = save_bh(mfd, bh, blk, NULL);
|
|
Packit Service |
360c39 |
if (ret != 0) {
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_leaf_in(&leaf, bh->b_data);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
blk = leaf.lf_next;
|
|
Packit Service |
360c39 |
} while (leaf.lf_next != 0);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* save_inode_data - save off important data associated with an inode
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* mfd - destination file descriptor
|
|
Packit Service |
360c39 |
* iblk - block number of the inode to save the data for
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* For user files, we don't want anything except all the indirect block
|
|
Packit Service |
360c39 |
* pointers that reside on blocks on all but the highest height.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* For system files like statfs and inum, we want everything because they
|
|
Packit Service |
360c39 |
* may contain important clues and no user data.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* For file system journals, the "data" is a mixture of metadata and
|
|
Packit Service |
360c39 |
* journaled data. We want all the metadata and none of the user data.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static void save_inode_data(struct metafd *mfd, uint64_t iblk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t height;
|
|
Packit Service |
360c39 |
struct gfs2_inode *inode;
|
|
Packit Service |
360c39 |
osi_list_t metalist[GFS2_MAX_META_HEIGHT];
|
|
Packit Service |
360c39 |
osi_list_t *prev_list, *cur_list, *tmp;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *metabh, *mybh;
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
|
|
Packit Service |
360c39 |
osi_list_init(&metalist[i]);
|
|
Packit Service |
360c39 |
metabh = bread(&sbd, iblk);
|
|
Packit Service |
360c39 |
if (sbd.gfs1) {
|
|
Packit Service |
360c39 |
inode = lgfs2_gfs_inode_get(&sbd, metabh);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
inode = lgfs2_inode_get(&sbd, metabh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (inode == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to read inode");
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
height = inode->i_di.di_height;
|
|
Packit Service |
360c39 |
/* If this is a user inode, we don't follow to the file height.
|
|
Packit Service |
360c39 |
We stop one level less. That way we save off the indirect
|
|
Packit Service |
360c39 |
pointer blocks but not the actual file contents. The exception
|
|
Packit Service |
360c39 |
is directories, where the height represents the level at which
|
|
Packit Service |
360c39 |
the hash table exists, and we have to save the directory data. */
|
|
Packit Service |
360c39 |
if (inode->i_di.di_flags & GFS2_DIF_EXHASH &&
|
|
Packit Service |
360c39 |
(S_ISDIR(inode->i_di.di_mode) ||
|
|
Packit Service |
360c39 |
(sbd.gfs1 && inode->i_di.__pad1 == GFS_FILE_DIR)))
|
|
Packit Service |
360c39 |
height++;
|
|
Packit Service |
360c39 |
else if (height && !(inode->i_di.di_flags & GFS2_DIF_SYSTEM) &&
|
|
Packit Service |
360c39 |
!block_is_systemfile(iblk) && !S_ISDIR(inode->i_di.di_mode))
|
|
Packit Service |
360c39 |
height--;
|
|
Packit Service |
360c39 |
osi_list_add(&metabh->b_altlist, &metalist[0]);
|
|
Packit Service |
360c39 |
for (i = 1; i <= height; i++){
|
|
Packit Service |
360c39 |
prev_list = &metalist[i - 1];
|
|
Packit Service |
360c39 |
cur_list = &metalist[i];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
|
|
Packit Service |
360c39 |
mybh = osi_list_entry(tmp, struct gfs2_buffer_head,
|
|
Packit Service |
360c39 |
b_altlist);
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(iblk, FALSE);
|
|
Packit Service |
360c39 |
save_indirect_blocks(mfd, cur_list, mybh, iblk,
|
|
Packit Service |
360c39 |
height, i);
|
|
Packit Service |
360c39 |
} /* for blocks at that height */
|
|
Packit Service |
360c39 |
} /* for height */
|
|
Packit Service |
360c39 |
/* free metalists */
|
|
Packit Service |
360c39 |
for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
|
|
Packit Service |
360c39 |
cur_list = &metalist[i];
|
|
Packit Service |
360c39 |
while (!osi_list_empty(cur_list)) {
|
|
Packit Service |
360c39 |
mybh = osi_list_entry(cur_list->next,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head,
|
|
Packit Service |
360c39 |
b_altlist);
|
|
Packit Service |
360c39 |
if (mybh == inode->i_bh)
|
|
Packit Service |
360c39 |
osi_list_del(&mybh->b_altlist);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
brelse(mybh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Process directory exhash inodes */
|
|
Packit Service |
360c39 |
if (S_ISDIR(inode->i_di.di_mode) &&
|
|
Packit Service |
360c39 |
inode->i_di.di_flags & GFS2_DIF_EXHASH) {
|
|
Packit Service |
360c39 |
uint64_t leaf_no, old_leaf = -1;
|
|
Packit Service |
360c39 |
int li;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (li = 0; li < (1 << inode->i_di.di_depth); li++) {
|
|
Packit Service |
360c39 |
if (lgfs2_get_leaf_ptr(inode, li, &leaf_no)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Could not read leaf index %d in dinode %"PRIu64"\n", li,
|
|
Packit Service |
360c39 |
(uint64_t)inode->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (leaf_no != old_leaf && save_leaf_chain(mfd, &sbd, leaf_no) != 0)
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
old_leaf = leaf_no;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (inode->i_di.di_eattr) { /* if this inode has extended attributes */
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *lbh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lbh = bread(&sbd, inode->i_di.di_eattr);
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk, NULL);
|
|
Packit Service |
360c39 |
gfs2_meta_header_in(&mh, lbh->b_data);
|
|
Packit Service |
360c39 |
if (mh.mh_magic == GFS2_MAGIC &&
|
|
Packit Service |
360c39 |
mh.mh_type == GFS2_METATYPE_EA)
|
|
Packit Service |
360c39 |
save_ea_block(mfd, lbh, iblk);
|
|
Packit Service |
360c39 |
else if (mh.mh_magic == GFS2_MAGIC &&
|
|
Packit Service |
360c39 |
mh.mh_type == GFS2_METATYPE_IN)
|
|
Packit Service |
360c39 |
save_indirect_blocks(mfd, cur_list, lbh, iblk, 2, 2);
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
if (mh.mh_magic == GFS2_MAGIC) /* if it's metadata */
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, inode->i_di.di_eattr,
|
|
Packit Service |
360c39 |
iblk, NULL);
|
|
Packit Service |
360c39 |
fprintf(stderr,
|
|
Packit Service |
360c39 |
"\nWarning: corrupt extended "
|
|
Packit Service |
360c39 |
"attribute at block %llu (0x%llx) "
|
|
Packit Service |
360c39 |
"detected in inode %lld (0x%llx).\n",
|
|
Packit Service |
360c39 |
(unsigned long long)inode->i_di.di_eattr,
|
|
Packit Service |
360c39 |
(unsigned long long)inode->i_di.di_eattr,
|
|
Packit Service |
360c39 |
(unsigned long long)iblk,
|
|
Packit Service |
360c39 |
(unsigned long long)iblk);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
brelse(lbh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
inode_put(&inode;;
|
|
Packit Service |
360c39 |
brelse(metabh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void get_journal_inode_blocks(void)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int journal;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
journals_found = 0;
|
|
Packit Service |
360c39 |
memset(journal_blocks, 0, sizeof(journal_blocks));
|
|
Packit Service |
360c39 |
/* Save off all the journals--but only the metadata.
|
|
Packit Service |
360c39 |
* This is confusing so I'll explain. The journals contain important
|
|
Packit Service |
360c39 |
* metadata. However, in gfs2 the journals are regular files within
|
|
Packit Service |
360c39 |
* the system directory. Since they're regular files, the blocks
|
|
Packit Service |
360c39 |
* within the journals are considered data, not metadata. Therefore,
|
|
Packit Service |
360c39 |
* they won't have been saved by the code above. We want to dump
|
|
Packit Service |
360c39 |
* these blocks, but we have to be careful. We only care about the
|
|
Packit Service |
360c39 |
* journal blocks that look like metadata, and we need to not save
|
|
Packit Service |
360c39 |
* journaled user data that may exist there as well. */
|
|
Packit Service |
360c39 |
for (journal = 0; ; journal++) { /* while journals exist */
|
|
Packit Service |
360c39 |
uint64_t jblock;
|
|
Packit Service |
360c39 |
int amt;
|
|
Packit Service |
360c39 |
struct gfs2_inode *j_inode = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sbd.gfs1) {
|
|
Packit Service |
360c39 |
struct gfs_jindex ji;
|
|
Packit Service |
360c39 |
char jbuf[sizeof(struct gfs_jindex)];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
j_inode = lgfs2_gfs_inode_read(&sbd,
|
|
Packit Service |
360c39 |
sbd1->sb_jindex_di.no_addr);
|
|
Packit Service |
360c39 |
if (j_inode == NULL) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Error reading journal inode: %s\n", strerror(errno));
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
amt = gfs2_readi(j_inode, (void *)&jbuf,
|
|
Packit Service |
360c39 |
journal * sizeof(struct gfs_jindex),
|
|
Packit Service |
360c39 |
sizeof(struct gfs_jindex));
|
|
Packit Service |
360c39 |
inode_put(&j_inode);
|
|
Packit Service |
360c39 |
if (!amt)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
gfs_jindex_in(&ji, jbuf);
|
|
Packit Service |
360c39 |
jblock = ji.ji_addr;
|
|
Packit Service |
360c39 |
gfs1_journal_size = (uint64_t)ji.ji_nsegment * 16;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
if (journal > indirect->ii[0].dirents - 3)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
jblock = indirect->ii[0].dirent[journal + 2].block;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
journal_blocks[journals_found++] = jblock;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int blktype;
|
|
Packit Service |
360c39 |
uint64_t blk = 0;
|
|
Packit Service |
360c39 |
unsigned i, j, m;
|
|
Packit Service |
360c39 |
uint64_t *ibuf = malloc(sbd.bsize * GFS2_NBBY * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (i = 0; i < rgd->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (j = 0; j < m; j++) {
|
|
Packit Service |
360c39 |
blk = ibuf[j];
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(blk, FALSE);
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, blk, blk, &blktype);
|
|
Packit Service |
360c39 |
if (blktype == GFS2_METATYPE_DI)
|
|
Packit Service |
360c39 |
save_inode_data(mfd, blk);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!sbd.gfs1)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* For gfs1, Save off the free/unlinked meta blocks too.
|
|
Packit Service |
360c39 |
* If we don't, we may run into metadata allocation issues. */
|
|
Packit Service |
360c39 |
m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
for (j = 0; j < m; j++) {
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, mfd, blk, blk, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
free(ibuf);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* We don't use gfs2_rgrp_read() here as it checks for metadata sanity and we
|
|
Packit Service |
360c39 |
want to save rgrp headers even if they're corrupt. */
|
|
Packit Service |
360c39 |
static int rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned x, length = rgd->ri.ri_length;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bhs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
|
|
Packit Service |
360c39 |
if (bhs == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
for (x = 0; x < length; x++)
|
|
Packit Service |
360c39 |
rgd->bits[x].bi_bh = bhs[x];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t addr = rgd->ri.ri_addr;
|
|
Packit Service |
360c39 |
uint32_t i;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rgrp_read(&sbd, rgd))
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n",
|
|
Packit Service |
360c39 |
addr, addr, rgd->ri.ri_length);
|
|
Packit Service |
360c39 |
/* Save the rg and bitmaps */
|
|
Packit Service |
360c39 |
for (i = 0; i < rgd->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE);
|
|
Packit Service |
360c39 |
save_bh(mfd, rgd->bits[i].bi_bh, 0, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Save the other metadata: inodes, etc. if mode is not 'savergs' */
|
|
Packit Service |
360c39 |
if (withcontents)
|
|
Packit Service |
360c39 |
save_allocated(rgd, mfd);
|
|
Packit Service |
360c39 |
gfs2_rgrp_relse(rgd);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int save_header(struct metafd *mfd, uint64_t fsbytes)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct savemeta_header smh = {
|
|
Packit Service |
360c39 |
.sh_magic = cpu_to_be32(SAVEMETA_MAGIC),
|
|
Packit Service |
360c39 |
.sh_format = cpu_to_be32(SAVEMETA_FORMAT),
|
|
Packit Service |
360c39 |
.sh_time = cpu_to_be64(time(NULL)),
|
|
Packit Service |
360c39 |
.sh_fs_bytes = cpu_to_be64(fsbytes)
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (savemetawrite(mfd, (char *)(&smh), sizeof(smh)) != sizeof(smh))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int read_header(gzFile gzin_fd, struct savemeta_header *smh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
size_t rs;
|
|
Packit Service |
360c39 |
struct savemeta_header smh_be = {0};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzseek(gzin_fd, 0, SEEK_SET);
|
|
Packit Service |
360c39 |
rs = gzread(gzin_fd, &smh_be, sizeof(smh_be));
|
|
Packit Service |
360c39 |
if (rs == -1) {
|
|
Packit Service |
360c39 |
perror("Failed to read savemeta file header");
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (rs != sizeof(smh_be))
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
smh->sh_magic = be32_to_cpu(smh_be.sh_magic);
|
|
Packit Service |
360c39 |
smh->sh_format = be32_to_cpu(smh_be.sh_format);
|
|
Packit Service |
360c39 |
smh->sh_time = be64_to_cpu(smh_be.sh_time);
|
|
Packit Service |
360c39 |
smh->sh_fs_bytes = be64_to_cpu(smh_be.sh_fs_bytes);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_header(struct savemeta_header *smh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (smh->sh_magic != SAVEMETA_MAGIC || smh->sh_format > SAVEMETA_FORMAT)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
printf("Metadata saved at %s", ctime((time_t *)&smh->sh_time)); /* ctime() adds \n */
|
|
Packit Service |
360c39 |
printf("File system size %s\n", anthropomorphize(smh->sh_fs_bytes));
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void savemeta(char *out_fn, int saveoption, int gziplevel)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t jindex_block;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *lbh;
|
|
Packit Service |
360c39 |
struct metafd mfd;
|
|
Packit Service |
360c39 |
struct osi_node *n;
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sbd.md.journals = 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
mfd = savemetaopen(out_fn, gziplevel);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blks_saved = 0;
|
|
Packit Service |
360c39 |
if (sbd.gfs1)
|
|
Packit Service |
360c39 |
sbd.bsize = sbd.sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
printf("There are %llu blocks of %u bytes in the filesystem.\n",
|
|
Packit Service |
360c39 |
(unsigned long long)sbd.fssize, sbd.bsize);
|
|
Packit Service |
360c39 |
if (sbd.gfs1)
|
|
Packit Service |
360c39 |
jindex_block = sbd1->sb_jindex_di.no_addr;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
jindex_block = masterblock("jindex");
|
|
Packit Service |
360c39 |
lbh = bread(&sbd, jindex_block);
|
|
Packit Service |
360c39 |
gfs2_dinode_in(&di, lbh->b_data);
|
|
Packit Service |
360c39 |
if (!sbd.gfs1)
|
|
Packit Service |
360c39 |
do_dinode_extended(&di, lbh);
|
|
Packit Service |
360c39 |
brelse(lbh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
printf("Filesystem size: %s\n", anthropomorphize(sbd.fssize * sbd.bsize));
|
|
Packit Service |
360c39 |
get_journal_inode_blocks();
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = init_per_node_lookup();
|
|
Packit Service |
360c39 |
if (err)
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Write the savemeta file header */
|
|
Packit Service |
360c39 |
err = save_header(&mfd, sbd.fssize * sbd.bsize);
|
|
Packit Service |
360c39 |
if (err) {
|
|
Packit Service |
360c39 |
perror("Failed to write metadata file header");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Save off the superblock */
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.bsize, 0, NULL);
|
|
Packit Service |
360c39 |
/* If this is gfs1, save off the rindex because it's not
|
|
Packit Service |
360c39 |
part of the file system as it is in gfs2. */
|
|
Packit Service |
360c39 |
if (sbd.gfs1) {
|
|
Packit Service |
360c39 |
uint64_t blk;
|
|
Packit Service |
360c39 |
int j;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blk = sbd1->sb_rindex_di.no_addr;
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, &mfd, blk, blk, NULL);
|
|
Packit Service |
360c39 |
save_inode_data(&mfd, blk);
|
|
Packit Service |
360c39 |
/* In GFS1, journals aren't part of the RG space */
|
|
Packit Service |
360c39 |
for (j = 0; j < journals_found; j++) {
|
|
Packit Service |
360c39 |
log_debug("Saving journal #%d\n", j + 1);
|
|
Packit Service |
360c39 |
for (blk = journal_blocks[j];
|
|
Packit Service |
360c39 |
blk < journal_blocks[j] + gfs1_journal_size;
|
|
Packit Service |
360c39 |
blk++)
|
|
Packit Service |
360c39 |
save_block(sbd.device_fd, &mfd, blk, blk, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Walk through the resource groups saving everything within */
|
|
Packit Service |
360c39 |
for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rgd = (struct rgrp_tree *)n;
|
|
Packit Service |
360c39 |
save_rgrp(&mfd, rgd, (saveoption != 2));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Clean up */
|
|
Packit Service |
360c39 |
/* There may be a gap between end of file system and end of device */
|
|
Packit Service |
360c39 |
/* so we tell the user that we've processed everything. */
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(sbd.fssize, TRUE);
|
|
Packit Service |
360c39 |
printf("\nMetadata saved to file %s ", mfd.filename);
|
|
Packit Service |
360c39 |
if (mfd.gziplevel) {
|
|
Packit Service |
360c39 |
printf("(gzipped, level %d).\n", mfd.gziplevel);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
printf("(uncompressed).\n");
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
savemetaclose(&mfd;;
|
|
Packit Service |
360c39 |
close(sbd.device_fd);
|
|
Packit Service |
360c39 |
destroy_per_node_lookup();
|
|
Packit Service |
360c39 |
free(indirect);
|
|
Packit Service |
360c39 |
gfs2_rgrp_free(&sbd.rgtree);
|
|
Packit Service |
360c39 |
exit(0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static off_t restore_init(gzFile gzfd, struct savemeta_header *smh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int err;
|
|
Packit Service |
360c39 |
unsigned i;
|
|
Packit Service |
360c39 |
size_t rs;
|
|
Packit Service |
360c39 |
char buf[256];
|
|
Packit Service |
360c39 |
off_t startpos = 0;
|
|
Packit Service |
360c39 |
struct gfs2_meta_header sbmh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = read_header(gzfd, smh);
|
|
Packit Service |
360c39 |
if (err < 0) {
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
} else if (check_header(smh) != 0) {
|
|
Packit Service |
360c39 |
printf("No valid file header found. Falling back to old format...\n");
|
|
Packit Service |
360c39 |
} else if (err == 0) {
|
|
Packit Service |
360c39 |
startpos = sizeof(*smh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzseek(gzfd, startpos, SEEK_SET);
|
|
Packit Service |
360c39 |
rs = gzread(gzfd, buf, sizeof(buf));
|
|
Packit Service |
360c39 |
if (rs != sizeof(buf)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Error: File is too small.\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Scan for the beginning of the file body. Required to support old formats(?). */
|
|
Packit Service |
360c39 |
for (i = 0; i < (256 - sizeof(struct saved_metablock) - sizeof(sbmh)); i++) {
|
|
Packit Service |
360c39 |
off_t off = i + sizeof(struct saved_metablock);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memcpy(&sbmh, &buf[off], sizeof(sbmh));
|
|
Packit Service |
360c39 |
if (sbmh.mh_magic == cpu_to_be32(GFS2_MAGIC) &&
|
|
Packit Service |
360c39 |
sbmh.mh_type == cpu_to_be32(GFS2_METATYPE_SB))
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (i == (sizeof(buf) - sizeof(struct saved_metablock) - sizeof(sbmh)))
|
|
Packit Service |
360c39 |
i = 0;
|
|
Packit Service |
360c39 |
return startpos + i; /* File offset of saved sb */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int restore_block(gzFile gzfd, struct saved_metablock *svb, char *buf, uint16_t maxlen)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int gzerr;
|
|
Packit Service |
360c39 |
int ret;
|
|
Packit Service |
360c39 |
uint16_t checklen;
|
|
Packit Service |
360c39 |
const char *errstr;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = gzread(gzfd, svb, sizeof(*svb));
|
|
Packit Service |
360c39 |
if (ret < sizeof(*svb)) {
|
|
Packit Service |
360c39 |
goto gzread_err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
svb->blk = be64_to_cpu(svb->blk);
|
|
Packit Service |
360c39 |
svb->siglen = be16_to_cpu(svb->siglen);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sbd.fssize && svb->blk >= sbd.fssize) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Error: File system is too small to restore this metadata.\n");
|
|
Packit Service |
360c39 |
fprintf(stderr, "File system is %llu blocks. Restore block = %llu\n",
|
|
Packit Service |
360c39 |
(unsigned long long)sbd.fssize, (unsigned long long)svb->blk);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (maxlen)
|
|
Packit Service |
360c39 |
checklen = maxlen;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
checklen = sbd.bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (checklen && svb->siglen > checklen) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Bad record length: %u for block %"PRIu64" (0x%"PRIx64").\n",
|
|
Packit Service |
360c39 |
svb->siglen, svb->blk, svb->blk);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (buf != NULL && maxlen != 0) {
|
|
Packit Service |
360c39 |
ret = gzread(gzfd, buf, svb->siglen);
|
|
Packit Service |
360c39 |
if (ret < svb->siglen) {
|
|
Packit Service |
360c39 |
goto gzread_err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzread_err:
|
|
Packit Service |
360c39 |
if (gzeof(gzfd))
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errstr = gzerror(gzfd, &gzerr);
|
|
Packit Service |
360c39 |
if (gzerr == Z_ERRNO)
|
|
Packit Service |
360c39 |
errstr = strerror(errno);
|
|
Packit Service |
360c39 |
fprintf(stderr, "Failed to restore block: %s\n", errstr);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int restore_super(gzFile gzfd, off_t pos)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret;
|
|
Packit Service |
360c39 |
struct saved_metablock svb = {0};
|
|
Packit Service |
360c39 |
char *buf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buf = calloc(1, sizeof(struct gfs2_sb));
|
|
Packit Service |
360c39 |
if (buf == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to restore super block");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gzseek(gzfd, pos, SEEK_SET);
|
|
Packit Service |
360c39 |
ret = restore_block(gzfd, &svb, buf, sizeof(struct gfs2_sb));
|
|
Packit Service |
360c39 |
if (ret == 1) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Reached end of file while restoring superblock\n");
|
|
Packit Service |
360c39 |
goto err;
|
|
Packit Service |
360c39 |
} else if (ret != 0) {
|
|
Packit Service |
360c39 |
goto err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_sb_in(&sbd.sd_sb, buf);
|
|
Packit Service |
360c39 |
sbd1 = (struct gfs_sb *)&sbd.sd_sb;
|
|
Packit Service |
360c39 |
ret = check_sb(&sbd.sd_sb);
|
|
Packit Service |
360c39 |
if (ret < 0) {
|
|
Packit Service |
360c39 |
fprintf(stderr,"Error: Invalid superblock data.\n");
|
|
Packit Service |
360c39 |
goto err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (ret == 1)
|
|
Packit Service |
360c39 |
sbd.gfs1 = 1;
|
|
Packit Service |
360c39 |
sbd.bsize = sbd.sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
printf("Block size is %uB\n", sbd.bsize);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
err:
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int find_highest_block(gzFile gzfd, off_t pos, uint64_t fssize)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
uint64_t highest = 0;
|
|
Packit Service |
360c39 |
struct saved_metablock svb = {0};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (1) {
|
|
Packit Service |
360c39 |
gzseek(gzfd, pos, SEEK_SET);
|
|
Packit Service |
360c39 |
err = restore_block(gzfd, &svb, NULL, 0);
|
|
Packit Service |
360c39 |
if (err == 1)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
if (err != 0)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (svb.blk > highest)
|
|
Packit Service |
360c39 |
highest = svb.blk;
|
|
Packit Service |
360c39 |
pos += sizeof(svb) + svb.siglen;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (fssize > 0) {
|
|
Packit Service |
360c39 |
printf("Saved file system size is %"PRIu64" (0x%"PRIx64") blocks, %s\n",
|
|
Packit Service |
360c39 |
fssize, fssize, anthropomorphize(fssize * sbd.bsize));
|
|
Packit Service |
360c39 |
sbd.fssize = fssize;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
sbd.fssize = highest + 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
printf("Highest saved block is %"PRIu64" (0x%"PRIx64")\n", highest, highest);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int restore_data(int fd, gzFile gzin_fd, off_t pos, int printonly)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct saved_metablock savedata = {0};
|
|
Packit Service |
360c39 |
uint64_t writes = 0;
|
|
Packit Service |
360c39 |
char *buf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buf = calloc(1, sbd.bsize);
|
|
Packit Service |
360c39 |
if (buf == NULL) {
|
|
Packit Service |
360c39 |
perror("Failed to restore data");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzseek(gzin_fd, pos, SEEK_SET);
|
|
Packit Service |
360c39 |
blks_saved = 0;
|
|
Packit Service |
360c39 |
while (TRUE) {
|
|
Packit Service |
360c39 |
int err;
|
|
Packit Service |
360c39 |
err = restore_block(gzin_fd, &savedata, buf, sbd.bsize);
|
|
Packit Service |
360c39 |
if (err == 1)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
if (err != 0) {
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (printonly) {
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head dummy_bh = {
|
|
Packit Service |
360c39 |
.b_data = buf,
|
|
Packit Service |
360c39 |
.b_blocknr = savedata.blk,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
if (printonly > 1 && printonly == savedata.blk) {
|
|
Packit Service |
360c39 |
display_block_type(&dummy_bh, TRUE);
|
|
Packit Service |
360c39 |
display_gfs2(&dummy_bh);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
} else if (printonly == 1) {
|
|
Packit Service |
360c39 |
print_gfs2("%"PRId64" (l=0x%x): ", blks_saved, savedata.siglen);
|
|
Packit Service |
360c39 |
display_block_type(&dummy_bh, TRUE);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(savedata.blk, FALSE);
|
|
Packit Service |
360c39 |
memset(buf + savedata.siglen, 0, sbd.bsize - savedata.siglen);
|
|
Packit Service |
360c39 |
if (pwrite(fd, buf, sbd.bsize, savedata.blk * sbd.bsize) != sbd.bsize) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n",
|
|
Packit Service |
360c39 |
strerror(errno), __FUNCTION__, __LINE__,
|
|
Packit Service |
360c39 |
(unsigned long long)savedata.blk,
|
|
Packit Service |
360c39 |
(unsigned long long)savedata.blk);
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
writes++;
|
|
Packit Service |
360c39 |
if (writes % 1000 == 0)
|
|
Packit Service |
360c39 |
fsync(fd);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
blks_saved++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!printonly)
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(sbd.fssize, 1);
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void complain(const char *complaint)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
fprintf(stderr, "%s\n", complaint);
|
|
Packit Service |
360c39 |
die("Format is: \ngfs2_edit restoremeta <file to restore> "
|
|
Packit Service |
360c39 |
"<dest file system>\n");
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
gzFile gzfd;
|
|
Packit Service |
360c39 |
off_t pos = 0;
|
|
Packit Service |
360c39 |
struct savemeta_header smh = {0};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
termlines = 0;
|
|
Packit Service |
360c39 |
if (!in_fn)
|
|
Packit Service |
360c39 |
complain("No source file specified.");
|
|
Packit Service |
360c39 |
if (!printonly && !out_device)
|
|
Packit Service |
360c39 |
complain("No destination file system specified.");
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzfd = gzopen(in_fn, "rb");
|
|
Packit Service |
360c39 |
if (!gzfd)
|
|
Packit Service |
360c39 |
die("Can't open source file %s: %s\n",
|
|
Packit Service |
360c39 |
in_fn, strerror(errno));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!printonly) {
|
|
Packit Service |
360c39 |
sbd.device_fd = open(out_device, O_RDWR);
|
|
Packit Service |
360c39 |
if (sbd.device_fd < 0)
|
|
Packit Service |
360c39 |
die("Can't open destination file system %s: %s\n",
|
|
Packit Service |
360c39 |
out_device, strerror(errno));
|
|
Packit Service |
360c39 |
} else if (out_device) /* for printsavedmeta, the out_device is an
|
|
Packit Service |
360c39 |
optional block no */
|
|
Packit Service |
360c39 |
printonly = check_keywords(out_device);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
pos = restore_init(gzfd, &smh;;
|
|
Packit Service |
360c39 |
error = restore_super(gzfd, pos);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
printf("This is gfs%c metadata.\n", sbd.gfs1 ? '1': '2');
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!printonly) {
|
|
Packit Service |
360c39 |
uint64_t space = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize;
|
|
Packit Service |
360c39 |
printf("There are %"PRIu64" free blocks on the destination device.\n", space);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = find_highest_block(gzfd, pos, sbd.fssize);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = restore_data(sbd.device_fd, gzfd, pos, printonly);
|
|
Packit Service |
360c39 |
printf("File %s %s %s.\n", in_fn,
|
|
Packit Service |
360c39 |
(printonly ? "print" : "restore"),
|
|
Packit Service |
360c39 |
(error ? "error" : "successful"));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gzclose(gzfd);
|
|
Packit Service |
360c39 |
if (!printonly)
|
|
Packit Service |
360c39 |
close(sbd.device_fd);
|
|
Packit Service |
360c39 |
free(indirect);
|
|
Packit Service |
360c39 |
exit(error);
|
|
Packit Service |
360c39 |
}
|