LCOV - code coverage report
Current view: top level - edit - savemeta.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 536 757 70.8 %
Date: 2023-10-25 12:04:14 Functions: 46 52 88.5 %

          Line data    Source code
       1             : #include "clusterautoconfig.h"
       2             : 
       3             : #include <stdio.h>
       4             : #include <stdlib.h>
       5             : #include <ctype.h>
       6             : #include <string.h>
       7             : #include <stdint.h>
       8             : #include <inttypes.h>
       9             : #include <sys/types.h>
      10             : #include <sys/stat.h>
      11             : #include <fcntl.h>
      12             : #include <unistd.h>
      13             : #include <errno.h>
      14             : #include <curses.h>
      15             : #include <term.h>
      16             : #include <sys/ioctl.h>
      17             : #include <limits.h>
      18             : #include <sys/time.h>
      19             : #include <zlib.h>
      20             : #include <bzlib.h>
      21             : #include <time.h>
      22             : 
      23             : #include <logging.h>
      24             : #include "osi_list.h"
      25             : #include "gfs2hex.h"
      26             : #include "hexedit.h"
      27             : #include "libgfs2.h"
      28             : 
      29             : #define DFT_SAVE_FILE "/tmp/gfsmeta.XXXXXX"
      30             : #define MAX_JOURNALS_SAVED 256
      31             : 
      32             : /* Header for the savemeta output file */
      33             : struct savemeta_header {
      34             : #define SAVEMETA_MAGIC (0x01171970)
      35             :         __be32 sh_magic;
      36             : #define SAVEMETA_FORMAT (1)
      37             :         __be32 sh_format; /* In case we want to change the layout */
      38             :         __be64 sh_time; /* When savemeta was run */
      39             :         __be64 sh_fs_bytes; /* Size of the fs */
      40             :         uint8_t __reserved[104];
      41             : };
      42             : 
      43             : struct savemeta {
      44             :         time_t sm_time;
      45             :         unsigned sm_format;
      46             :         uint64_t sm_fs_bytes;
      47             : };
      48             : 
      49             : struct saved_metablock {
      50             :         __be64 blk;
      51             :         __be16 siglen; /* significant data length */
      52             : /* This needs to be packed because old versions of gfs2_edit read and write the
      53             :    individual fields separately, so the hole after siglen must be eradicated
      54             :    before the struct reflects what's on disk. */
      55             : } __attribute__((__packed__));
      56             : 
      57             : struct metafd {
      58             :         int fd;
      59             :         gzFile gzfd;
      60             :         BZFILE *bzfd;
      61             :         const char *filename;
      62             :         int gziplevel;
      63             :         int eof;
      64             :         int (*read)(struct metafd *mfd, void *buf, unsigned len);
      65             :         void (*close)(struct metafd *mfd);
      66             :         const char* (*strerr)(struct metafd *mfd);
      67             : };
      68             : 
      69             : static char *restore_buf;
      70             : static ssize_t restore_left;
      71             : static off_t restore_off;
      72             : #define RESTORE_BUF_SIZE (2 * 1024 * 1024)
      73             : 
      74      393939 : static char *restore_buf_next(struct metafd *mfd, size_t required_len)
      75             : {
      76      393939 :         if (restore_left < required_len) {
      77          10 :                 char *tail = restore_buf + restore_off;
      78             :                 int ret;
      79             : 
      80          10 :                 memmove(restore_buf, tail, restore_left);
      81          10 :                 ret = mfd->read(mfd, restore_buf + restore_left, RESTORE_BUF_SIZE - restore_left);
      82          10 :                 if (ret < (int)required_len - restore_left)
      83           5 :                         return NULL;
      84           5 :                 restore_left += ret;
      85           5 :                 restore_off = 0;
      86             :         }
      87      393934 :         restore_left -= required_len;
      88      393934 :         restore_off += required_len;
      89      393934 :         return &restore_buf[restore_off - required_len];
      90             : }
      91             : 
      92             : /* gzip compression method */
      93             : 
      94           0 : static const char *gz_strerr(struct metafd *mfd)
      95             : {
      96             :         int err;
      97           0 :         const char *errstr = gzerror(mfd->gzfd, &err);
      98             : 
      99           0 :         if (err == Z_ERRNO)
     100           0 :                 return strerror(errno);
     101           0 :         return errstr;
     102             : }
     103             : 
     104          15 : static int gz_read(struct metafd *mfd, void *buf, unsigned len)
     105             : {
     106          15 :         int ret = gzread(mfd->gzfd, buf, len);
     107          15 :         if (ret < len && gzeof(mfd->gzfd))
     108          10 :                 mfd->eof = 1;
     109          15 :         return ret;
     110             : }
     111             : 
     112           5 : static void gz_close(struct metafd *mfd)
     113             : {
     114           5 :         gzclose(mfd->gzfd);
     115           5 : }
     116             : 
     117             : /* This should be tried last because gzip doesn't distinguish between
     118             :    decompressing a gzip file and reading an uncompressed file */
     119           5 : static int restore_try_gzip(struct metafd *mfd)
     120             : {
     121           5 :         mfd->read = gz_read;
     122           5 :         mfd->close = gz_close;
     123           5 :         mfd->strerr = gz_strerr;
     124           5 :         lseek(mfd->fd, 0, SEEK_SET);
     125           5 :         mfd->gzfd = gzdopen(mfd->fd, "rb");
     126           5 :         if (!mfd->gzfd)
     127           0 :                 return 1;
     128           5 :         gzbuffer(mfd->gzfd, (1<<20)); /* Increase zlib's buffers to 1MB */
     129           5 :         restore_left = mfd->read(mfd, restore_buf, RESTORE_BUF_SIZE);
     130           5 :         if (restore_left < 512)
     131           0 :                 return -1;
     132           5 :         return 0;
     133             : }
     134             : 
     135             : /* bzip2 compression method */
     136             : 
     137           0 : static const char *bz_strerr(struct metafd *mfd)
     138             : {
     139             :         int err;
     140           0 :         const char *errstr = BZ2_bzerror(mfd->bzfd, &err);
     141             : 
     142           0 :         if (err == BZ_IO_ERROR)
     143           0 :                 return strerror(errno);
     144           0 :         return errstr;
     145             : }
     146             : 
     147           5 : static int bz_read(struct metafd *mfd, void *buf, unsigned len)
     148             : {
     149           5 :         int bzerr = BZ_OK;
     150             :         int ret;
     151             : 
     152           5 :         ret = BZ2_bzRead(&bzerr, mfd->bzfd, buf, len);
     153           5 :         if (bzerr == BZ_OK)
     154           0 :                 return ret;
     155           5 :         if (bzerr == BZ_STREAM_END) {
     156           0 :                 mfd->eof = 1;
     157           0 :                 return ret;
     158             :         }
     159           5 :         return -1;
     160             : }
     161             : 
     162           0 : static void bz_close(struct metafd *mfd)
     163             : {
     164           0 :         BZ2_bzclose(mfd->bzfd);
     165           0 : }
     166             : 
     167           5 : static int restore_try_bzip(struct metafd *mfd)
     168             : {
     169             :         int bzerr;
     170             :         FILE *f;
     171             : 
     172           5 :         f = fdopen(mfd->fd, "r");
     173           5 :         if (f == NULL)
     174           0 :                 return 1;
     175             : 
     176           5 :         mfd->read = bz_read;
     177           5 :         mfd->close = bz_close;
     178           5 :         mfd->strerr = bz_strerr;
     179           5 :         mfd->bzfd = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0);
     180           5 :         if (!mfd->bzfd)
     181           0 :                 return 1;
     182           5 :         restore_left = mfd->read(mfd, restore_buf, RESTORE_BUF_SIZE);
     183           5 :         if (restore_left < 512)
     184           5 :                 return -1;
     185           0 :         return 0;
     186             : }
     187             : 
     188             : static uint64_t blks_saved;
     189             : static uint64_t journal_blocks[MAX_JOURNALS_SAVED];
     190             : static int journals_found = 0;
     191             : int print_level = MSG_NOTICE;
     192             : 
     193          26 : static int block_is_a_journal(uint64_t blk)
     194             : {
     195             :         int j;
     196             : 
     197         182 :         for (j = 0; j < journals_found; j++)
     198         156 :                 if (blk == journal_blocks[j])
     199           0 :                         return TRUE;
     200          26 :         return FALSE;
     201             : }
     202             : 
     203             : static struct osi_root per_node_tree;
     204             : struct per_node_node {
     205             :         struct osi_node node;
     206             :         uint64_t block;
     207             : };
     208             : 
     209           7 : static void destroy_per_node_lookup(void)
     210             : {
     211             :         struct osi_node *n;
     212             :         struct per_node_node *pnp;
     213             : 
     214          21 :         while ((n = osi_first(&per_node_tree))) {
     215          14 :                 pnp = (struct per_node_node *)n;
     216          14 :                 osi_erase(n, &per_node_tree);
     217          14 :                 free(pnp);
     218             :         }
     219           7 : }
     220             : 
     221          26 : static int block_is_in_per_node(uint64_t blk)
     222             : {
     223          26 :         struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node;
     224             : 
     225          43 :         while (pnp) {
     226          25 :                 if (blk < pnp->block)
     227           6 :                         pnp = (struct per_node_node *)pnp->node.osi_left;
     228          19 :                 else if (blk > pnp->block)
     229          11 :                         pnp = (struct per_node_node *)pnp->node.osi_right;
     230             :                 else
     231           8 :                         return 1;
     232             :         }
     233             : 
     234          18 :         return 0;
     235             : }
     236             : 
     237          14 : static int insert_per_node_lookup(uint64_t blk)
     238             : {
     239          14 :         struct osi_node **newn = &per_node_tree.osi_node, *parent = NULL;
     240             :         struct per_node_node *pnp;
     241             : 
     242          52 :         while (*newn) {
     243          38 :                 struct per_node_node *cur = (struct per_node_node *)*newn;
     244             : 
     245          38 :                 parent = *newn;
     246          38 :                 if (blk < cur->block)
     247           8 :                         newn = &((*newn)->osi_left);
     248          30 :                 else if (blk > cur->block)
     249          30 :                         newn = &((*newn)->osi_right);
     250             :                 else
     251           0 :                         return 0;
     252             :         }
     253             : 
     254          14 :         pnp = calloc(1, sizeof(struct per_node_node));
     255          14 :         if (pnp == NULL) {
     256           0 :                 perror("Failed to insert per_node lookup entry");
     257           0 :                 return 1;
     258             :         }
     259          14 :         pnp->block = blk;
     260          14 :         osi_link_node(&pnp->node, parent, newn);
     261          14 :         osi_insert_color(&pnp->node, &per_node_tree);
     262          14 :         return 0;
     263             : }
     264             : 
     265           7 : static int init_per_node_lookup(void)
     266             : {
     267             :         int i;
     268             :         struct lgfs2_inode *per_node_di;
     269             : 
     270           7 :         per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node"));
     271           7 :         if (per_node_di == NULL) {
     272           0 :                 fprintf(stderr, "Failed to read per_node: %s\n", strerror(errno));
     273           0 :                 return 1;
     274             :         }
     275             : 
     276           7 :         do_dinode_extended(per_node_di->i_bh->b_data);
     277           7 :         lgfs2_inode_put(&per_node_di);
     278             : 
     279          10 :         for (i = 0; i < indirect_blocks; i++) {
     280             :                 int d;
     281          17 :                 for (d = 0; d < indirect->ii[i].dirents; d++) {
     282          14 :                         int ret = insert_per_node_lookup(indirect->ii[i].dirent[d].inum.in_addr);
     283          14 :                         if (ret != 0)
     284           0 :                                 return ret;
     285             :                 }
     286             :         }
     287           7 :         return 0;
     288             : }
     289             : 
     290          87 : static int block_is_systemfile(uint64_t blk)
     291             : {
     292         167 :         return block_is_inum_file(blk) ||
     293         153 :                block_is_statfs_file(blk) ||
     294         139 :                block_is_quota_file(blk) ||
     295          92 :                block_is_rindex(blk) ||
     296          52 :                block_is_a_journal(blk) ||
     297         193 :                block_is_per_node(blk) ||
     298          26 :                block_is_in_per_node(blk);
     299             : }
     300             : 
     301         108 : static size_t di_save_len(const char *buf, uint64_t owner)
     302             : {
     303             :         const struct gfs2_dinode *dn;
     304             :         uint16_t di_height;
     305             :         uint32_t di_mode;
     306             : 
     307         108 :         dn = (void *)buf;
     308         108 :         di_mode = be32_to_cpu(dn->di_mode);
     309         108 :         di_height = be16_to_cpu(dn->di_height);
     310             : 
     311             :         /* Do not save (user) data from the inode block unless they are
     312             :            indirect pointers, dirents, symlinks or fs internal data */
     313         155 :         if (di_height > 0 || S_ISDIR(di_mode) || S_ISLNK(di_mode) ||
     314          47 :             block_is_systemfile(owner))
     315          90 :                 return sbd.sd_bsize;
     316          18 :         return sizeof(struct gfs2_dinode);
     317             : }
     318             : 
     319             : /*
     320             :  * get_struct_info - get block type and structure length
     321             :  *
     322             :  * @buf - The block buffer to examine
     323             :  * @owner - The block address of the parent structure
     324             :  * @block_type - pointer to integer to hold the block type
     325             :  * @gstruct_len - pointer to integer to hold the structure length
     326             :  *
     327             :  * returns: 0 if successful
     328             :  *          -1 if this isn't gfs2 metadata.
     329             :  */
     330      219278 : static int get_struct_info(const char *buf, uint64_t owner, unsigned *block_type,
     331             :                                unsigned *gstruct_len)
     332             : {
     333      219278 :         struct gfs2_meta_header *mh = (struct gfs2_meta_header *)buf;
     334             : 
     335      219278 :         if (block_type != NULL)
     336      219278 :                 *block_type = 0;
     337             : 
     338      219278 :         if (gstruct_len != NULL)
     339      219278 :                 *gstruct_len = sbd.sd_bsize;
     340             : 
     341      219278 :         if (be32_to_cpu(mh->mh_magic) != GFS2_MAGIC)
     342          40 :                 return -1;
     343             : 
     344      219238 :         if (block_type != NULL)
     345      219238 :                 *block_type = be32_to_cpu(mh->mh_type);
     346             : 
     347      219238 :         if (gstruct_len == NULL)
     348           0 :                 return 0;
     349             : 
     350      219238 :         switch (be32_to_cpu(mh->mh_type)) {
     351           7 :         case GFS2_METATYPE_SB:   /* 1 (superblock) */
     352           7 :                 *gstruct_len = sizeof(struct gfs2_sb);
     353           7 :                 break;
     354           0 :         case GFS2_METATYPE_RG:   /* 2 (rsrc grp hdr) */
     355           0 :                 *gstruct_len = sbd.sd_bsize; /*sizeof(struct gfs_rgrp);*/
     356           0 :                 break;
     357           0 :         case GFS2_METATYPE_RB:   /* 3 (rsrc grp bitblk) */
     358           0 :                 *gstruct_len = sbd.sd_bsize;
     359           0 :                 break;
     360         108 :         case GFS2_METATYPE_DI:   /* 4 (disk inode) */
     361         108 :                 *gstruct_len = di_save_len(buf, owner);
     362         108 :                 break;
     363        2029 :         case GFS2_METATYPE_IN:   /* 5 (indir inode blklst) */
     364        2029 :                 *gstruct_len = sbd.sd_bsize; /*sizeof(struct gfs_indirect);*/
     365        2029 :                 break;
     366           6 :         case GFS2_METATYPE_LF:   /* 6 (leaf dinode blklst) */
     367           6 :                 *gstruct_len = sbd.sd_bsize; /*sizeof(struct gfs_leaf);*/
     368           6 :                 break;
     369           0 :         case GFS2_METATYPE_JD:   /* 7 (journal data) */
     370           0 :                 *gstruct_len = sbd.sd_bsize;
     371           0 :                 break;
     372      204800 :         case GFS2_METATYPE_LH:   /* 8 (log header) */
     373      204800 :                 *gstruct_len = sizeof(struct gfs2_log_header);
     374      204800 :                 break;
     375           0 :         case GFS2_METATYPE_LD:   /* 9 (log descriptor) */
     376           0 :                 *gstruct_len = sbd.sd_bsize;
     377           0 :                 break;
     378           0 :         case GFS2_METATYPE_EA:   /* 10 (extended attr hdr) */
     379           0 :                 *gstruct_len = sbd.sd_bsize;
     380           0 :                 break;
     381           0 :         case GFS2_METATYPE_ED:   /* 11 (extended attr data) */
     382           0 :                 *gstruct_len = sbd.sd_bsize;
     383           0 :                 break;
     384       12288 :         default:
     385       12288 :                 *gstruct_len = sbd.sd_bsize;
     386       12288 :                 break;
     387             :         }
     388      219238 :         return 0;
     389             : }
     390             : 
     391             : /**
     392             :  * Print a progress message if one second has elapsed since the last time.
     393             :  * pblock: The latest block number processed
     394             :  * force:  If this is non-zero, print immediately and add a newline after the
     395             :  *         progress message.
     396             :  */
     397      242007 : static void report_progress(uint64_t pblock, int force)
     398             : {
     399             :         static struct timeval tv;
     400             :         static uint32_t seconds = 0;
     401             : 
     402      242007 :         gettimeofday(&tv, NULL);
     403      242007 :         if (!seconds)
     404          12 :                 seconds = tv.tv_sec;
     405      242007 :         if (force || tv.tv_sec - seconds) {
     406             :                 static uint64_t percent;
     407             : 
     408          14 :                 seconds = tv.tv_sec;
     409          14 :                 if (sbd.fssize) {
     410          14 :                         printf("\r");
     411          14 :                         percent = (pblock * 100) / sbd.fssize;
     412          14 :                         printf("%"PRIu64" blocks saved (%"PRIu64"%% complete)",
     413             :                                blks_saved, percent);
     414          14 :                         if (force)
     415          12 :                                 printf("\n");
     416          14 :                         fflush(stdout);
     417             :                 }
     418             :         }
     419      242007 : }
     420             : 
     421             : /**
     422             :  * Open a file and prepare it for writing by savemeta()
     423             :  * out_fn: the path to the file, which will be truncated if it exists
     424             :  * gziplevel: 0   - do not compress the file,
     425             :  *            1-9 - use gzip compression level 1-9
     426             :  * Returns a struct metafd containing the opened file descriptor
     427             :  */
     428           7 : static struct metafd savemetaopen(char *out_fn, int gziplevel)
     429             : {
     430           7 :         struct metafd mfd = {0};
     431           7 :         char gzmode[3] = "w9";
     432           7 :         char dft_fn[] = DFT_SAVE_FILE;
     433           7 :         mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
     434             :         struct stat st;
     435             : 
     436           7 :         mfd.gziplevel = gziplevel;
     437             : 
     438           7 :         if (!out_fn) {
     439           0 :                 out_fn = dft_fn;
     440           0 :                 mfd.fd = mkstemp(out_fn);
     441             :         } else {
     442           7 :                 mfd.fd = open(out_fn, O_RDWR | O_CREAT, 0644);
     443             :         }
     444           7 :         umask(mask);
     445           7 :         mfd.filename = out_fn;
     446             : 
     447           7 :         if (mfd.fd < 0) {
     448           0 :                 fprintf(stderr, "Can't open %s: %s\n", out_fn, strerror(errno));
     449           0 :                 exit(1);
     450             :         }
     451           7 :         if (fstat(mfd.fd, &st) == -1) {
     452           0 :                 fprintf(stderr, "Failed to stat %s: %s\n", out_fn, strerror(errno));
     453           0 :                 exit(1);
     454             :         }
     455           7 :         if (S_ISREG(st.st_mode) && ftruncate(mfd.fd, 0)) {
     456           0 :                 fprintf(stderr, "Can't truncate %s: %s\n", out_fn, strerror(errno));
     457           0 :                 exit(1);
     458             :         }
     459             : 
     460           7 :         if (gziplevel > 0) {
     461           2 :                 gzmode[1] = '0' + gziplevel;
     462           2 :                 mfd.gzfd = gzdopen(mfd.fd, gzmode);
     463           2 :                 if (!mfd.gzfd) {
     464           0 :                         fprintf(stderr, "gzdopen error: %s\n", strerror(errno));
     465           0 :                         exit(1);
     466             :                 }
     467           2 :                 gzbuffer(mfd.gzfd, (1<<20)); /* Increase zlib's buffers to 1MB */
     468             :         }
     469             : 
     470           7 :         return mfd;
     471             : }
     472             : 
     473             : /**
     474             :  * Write nbyte bytes from buf to a file opened with savemetaopen()
     475             :  * mfd: the file descriptor opened using savemetaopen()
     476             :  * buf: the buffer to write data from
     477             :  * nbyte: the number of bytes to write
     478             :  * Returns the number of bytes written from buf or -1 on error
     479             :  */
     480      263993 : static ssize_t savemetawrite(struct metafd *mfd, const void *buf, size_t nbyte)
     481             : {
     482             :         ssize_t ret;
     483             :         int gzerr;
     484             :         const char *gzerrmsg;
     485             : 
     486      263993 :         if (mfd->gziplevel == 0) {
     487      213595 :                 return write(mfd->fd, buf, nbyte);
     488             :         }
     489             : 
     490       50398 :         ret = gzwrite(mfd->gzfd, buf, nbyte);
     491       50398 :         if (ret != nbyte) {
     492           0 :                 gzerrmsg = gzerror(mfd->gzfd, &gzerr);
     493           0 :                 if (gzerr != Z_ERRNO) {
     494           0 :                         fprintf(stderr, "Error: zlib: %s\n", gzerrmsg);
     495             :                 }
     496             :         }
     497       50398 :         return ret;
     498             : }
     499             : 
     500             : /**
     501             :  * Closes a file descriptor previously opened using savemetaopen()
     502             :  * mfd: the file descriptor previously opened using savemetaopen()
     503             :  * Returns 0 on success or -1 on error
     504             :  */
     505           7 : static int savemetaclose(struct metafd *mfd)
     506             : {
     507             :         int gzret;
     508           7 :         if (mfd->gziplevel > 0) {
     509           2 :                 gzret = gzclose(mfd->gzfd);
     510           2 :                 if (gzret == Z_STREAM_ERROR) {
     511           0 :                         fprintf(stderr, "gzclose: file is not valid\n");
     512           0 :                         return -1;
     513           2 :                 } else if (gzret == Z_ERRNO) {
     514           0 :                         return -1;
     515             :                 }
     516             :         }
     517           7 :         return close(mfd->fd);
     518             : }
     519             : 
     520      263986 : static int save_buf(struct metafd *mfd, const char *buf, uint64_t addr, unsigned blklen)
     521             : {
     522             :         struct saved_metablock *savedata;
     523             :         size_t outsz;
     524             : 
     525             :         /* No need to save trailing zeroes, but leave that for compression to
     526             :            deal with when enabled as this adds a significant overhead */
     527      263986 :         if (mfd->gziplevel == 0)
     528    43150243 :                 for (; blklen > 0 && buf[blklen - 1] == '\0'; blklen--);
     529             : 
     530      263986 :         if (blklen == 0) /* No significant data; skip. */
     531           0 :                 return 0;
     532             : 
     533      263986 :         outsz = sizeof(*savedata) + blklen;
     534      263986 :         savedata = calloc(1, outsz);
     535      263986 :         if (savedata == NULL) {
     536           0 :                 perror("Failed to save block");
     537           0 :                 exit(1);
     538             :         }
     539      263986 :         savedata->blk = cpu_to_be64(addr);
     540      263986 :         savedata->siglen = cpu_to_be16(blklen);
     541      263986 :         memcpy(savedata + 1, buf, blklen);
     542             : 
     543      263986 :         if (savemetawrite(mfd, savedata, outsz) != outsz) {
     544           0 :                 fprintf(stderr, "write error: %s from %s:%d: block %"PRIu64"\n",
     545           0 :                         strerror(errno), __FUNCTION__, __LINE__, addr);
     546           0 :                 free(savedata);
     547           0 :                 exit(-1);
     548             :         }
     549      263986 :         blks_saved++;
     550      263986 :         free(savedata);
     551      263986 :         return 0;
     552             : }
     553             : 
     554             : struct block_range {
     555             :         struct block_range *next;
     556             :         uint64_t start;
     557             :         unsigned len;
     558             :         unsigned *blktype;
     559             :         unsigned *blklen;
     560             :         char *buf;
     561             : };
     562             : 
     563        2293 : static int block_range_prepare(struct block_range *br)
     564             : {
     565        2293 :         br->buf = calloc(br->len, sbd.sd_bsize + sizeof(*br->blktype) + sizeof(*br->blklen));
     566        2293 :         if (br->buf == NULL) {
     567           0 :                 perror("Failed to allocate block range buffer");
     568           0 :                 return 1;
     569             :         }
     570        2293 :         br->blktype = (unsigned *)(br->buf + (br->len * sbd.sd_bsize));
     571        2293 :         br->blklen = br->blktype + br->len;
     572        2293 :         return 0;
     573             : }
     574             : 
     575        2293 : static int block_range_check(struct block_range *br)
     576             : {
     577        2293 :         if (br->start >= LGFS2_SB_ADDR(&sbd) && br->start + br->len <= sbd.fssize)
     578        2293 :                 return 0;
     579             : 
     580           0 :         fprintf(stderr, "Warning: bad range 0x%"PRIx64" (%u blocks) ignored.\n",
     581             :                 br->start, br->len);
     582           0 :         free(br->buf);
     583           0 :         br->buf = NULL;
     584           0 :         return 1;
     585             : }
     586             : 
     587        2293 : static void block_range_setinfo(struct block_range *br, uint64_t owner)
     588             : {
     589      221571 :         for (unsigned i = 0; i < br->len; i++) {
     590      219278 :                 char *buf = br->buf + (i * sbd.sd_bsize);
     591      219278 :                 uint64_t addr = br->start + i;
     592      219278 :                 uint64_t _owner = (owner == 0) ? addr : owner;
     593             : 
     594      219318 :                 if (get_struct_info(buf, _owner, br->blktype + i, br->blklen + i) &&
     595          40 :                     !block_is_systemfile(_owner)) {
     596           0 :                         br->blklen[i] = 0;
     597             :                 }
     598             :         }
     599        2293 : }
     600             : 
     601         212 : static void block_range_free(struct block_range **brp)
     602             : {
     603         212 :         free((*brp)->buf);
     604         212 :         free(*brp);
     605         212 :         *brp = NULL;
     606         212 : }
     607             : 
     608             : struct block_range_queue {
     609             :         struct block_range *tail;
     610             :         struct block_range **head;
     611             : };
     612             : 
     613        1080 : static void block_range_queue_init(struct block_range_queue *q)
     614             : {
     615        1080 :         q->head = &q->tail;
     616        1080 : }
     617             : 
     618         212 : static void block_range_queue_insert(struct block_range_queue *q, struct block_range *br)
     619             : {
     620         212 :         *q->head = br;
     621         212 :         q->head = &br->next;
     622         212 : }
     623             : 
     624         212 : static struct block_range *block_range_queue_pop(struct block_range_queue *q)
     625             : {
     626         212 :         struct block_range *br = q->tail;
     627             : 
     628         212 :         q->tail = br->next;
     629         212 :         br->next = NULL;
     630         212 :         return br;
     631             : }
     632             : 
     633        2286 : static int save_range(struct metafd *mfd, struct block_range *br)
     634             : {
     635      221557 :         for (unsigned i = 0; i < br->len; i++) {
     636             :                 int err;
     637             : 
     638      219271 :                 err = save_buf(mfd, br->buf + (i * sbd.sd_bsize), br->start + i, br->blklen[i]);
     639      219271 :                 if (err != 0)
     640           0 :                         return err;
     641             :         }
     642        2286 :         return 0;
     643             : }
     644             : 
     645        2293 : static int check_read_range(int fd, struct block_range *br, uint64_t owner)
     646             : {
     647             :         size_t size;
     648             : 
     649        2293 :         if (block_range_prepare(br) != 0)
     650           0 :                 return 1;
     651             : 
     652        2293 :         if (block_range_check(br) != 0)
     653           0 :                 return 1;
     654             : 
     655        2293 :         size = br->len * sbd.sd_bsize;
     656        2293 :         if (pread(sbd.device_fd, br->buf, size, sbd.sd_bsize * br->start) != size) {
     657           0 :                 fprintf(stderr, "Failed to read block range 0x%"PRIx64" (%u blocks): %s\n",
     658           0 :                         br->start, br->len, strerror(errno));
     659           0 :                 free(br->buf);
     660           0 :                 br->buf = NULL;
     661           0 :                 return 1;
     662             :         }
     663        2293 :         block_range_setinfo(br, owner);
     664        2293 :         return 0;
     665             : }
     666             : 
     667           7 : static char *check_read_block(int fd, uint64_t blk, uint64_t owner, int *blktype, size_t *blklen)
     668             : {
     669           7 :         struct block_range br = {
     670             :                 .start = blk,
     671             :                 .len = 1
     672             :         };
     673             : 
     674           7 :         if (check_read_range(fd, &br, owner) != 0)
     675           0 :                 return NULL;
     676           7 :         if (blklen != NULL)
     677           0 :                 *blklen = *br.blklen;
     678           7 :         if (blktype != NULL)
     679           0 :                 *blktype = *br.blktype;
     680           7 :         return br.buf;
     681             : }
     682             : 
     683             : /*
     684             :  * save_ea_block - save off an extended attribute block
     685             :  */
     686           0 : static void save_ea_block(struct metafd *mfd, char *buf, uint64_t owner)
     687             : {
     688             :         struct gfs2_ea_header *ea;
     689           0 :         uint32_t rec_len = 0;
     690             :         int e;
     691             : 
     692           0 :         for (e = sizeof(struct gfs2_meta_header); e < sbd.sd_bsize; e += rec_len) {
     693             :                 uint64_t blk;
     694             :                 int charoff, i;
     695             :                 __be64 *b;
     696             : 
     697           0 :                 ea = (void *)(buf + e);
     698             :                 /* ea_num_ptrs and ea_name_len are u8 so no endianness worries */
     699           0 :                 for (i = 0; i < ea->ea_num_ptrs; i++) {
     700             :                         char *_buf;
     701             : 
     702           0 :                         charoff = e + ea->ea_name_len +
     703             :                                 sizeof(struct gfs2_ea_header) +
     704           0 :                                 sizeof(uint64_t) - 1;
     705           0 :                         charoff /= sizeof(uint64_t);
     706           0 :                         b = (__be64 *)buf;
     707           0 :                         b += charoff + i;
     708           0 :                         blk = be64_to_cpu(*b);
     709           0 :                         _buf = check_read_block(sbd.device_fd, blk, owner, NULL, NULL);
     710           0 :                         if (_buf != NULL) {
     711           0 :                                 save_buf(mfd, _buf, blk, sbd.sd_bsize);
     712           0 :                                 free(_buf);
     713             :                         }
     714             :                 }
     715           0 :                 rec_len = be32_to_cpu(ea->ea_rec_len);
     716           0 :                 if (rec_len == 0)
     717           0 :                         break;
     718             :         }
     719           0 : }
     720             : 
     721        2234 : static void save_indirect_range(struct metafd *mfd, struct block_range **brp, uint64_t owner,
     722             :                                 struct block_range_queue *q)
     723             : {
     724        2234 :         struct block_range *br = *brp;
     725             : 
     726        2234 :         if (check_read_range(sbd.device_fd, br, owner) != 0)
     727           0 :                 return;
     728             : 
     729        2234 :         save_range(mfd, br);
     730      221397 :         for (unsigned i = 0; i < br->len; i++) {
     731      219163 :                 if (br->blktype[i] == GFS2_METATYPE_EA)
     732           0 :                         save_ea_block(mfd, br->buf + (i * sbd.sd_bsize), owner);
     733             :         }
     734        2234 :         if (q) {
     735         212 :                 block_range_queue_insert(q, br);
     736         212 :                 *brp = NULL; /* The list now has ownership of it */
     737             :         } else {
     738        2022 :                 free(br->buf);
     739        2022 :                 br->buf = NULL;
     740             :         }
     741             : }
     742             : 
     743        2066 : static void save_indirect_blocks(struct metafd *mfd, char *buf, uint64_t owner,
     744             :                                  struct block_range_queue *q, unsigned headsize)
     745             : {
     746        2066 :         uint64_t old_block = 0, indir_block;
     747        2066 :         struct block_range *br = NULL;
     748             :         __be64 *ptr;
     749             : 
     750        2066 :         for (ptr = (__be64 *)(buf + headsize);
     751      233306 :              (char *)ptr < (buf + sbd.sd_bsize); ptr++) {
     752      231240 :                 if (!*ptr)
     753       11955 :                         continue;
     754             : 
     755      219285 :                 indir_block = be64_to_cpu(*ptr);
     756      219285 :                 if (indir_block == old_block)
     757         122 :                         continue;
     758      219163 :                 old_block = indir_block;
     759             : 
     760      219163 :                 if (br == NULL) {
     761        2066 : new_range:
     762        2231 :                         br = calloc(1, sizeof(*br));
     763        2231 :                         if (br == NULL) {
     764           0 :                                 perror("Failed to save indirect blocks");
     765           0 :                                 return;
     766             :                         }
     767        2231 :                         br->start = indir_block;
     768        2231 :                         br->len = 1;
     769      217097 :                 } else if (indir_block == br->start + br->len) {
     770      216929 :                         br->len++;
     771             :                 } else {
     772         168 :                         save_indirect_range(mfd, &br, owner, q);
     773         168 :                         if (br == NULL) /* This one was queued up for later */
     774         165 :                                 goto new_range;
     775           3 :                         br->start = indir_block;
     776           3 :                         br->len = 1;
     777             :                 }
     778             :         }
     779        2066 :         if (br != NULL && br->start != 0)
     780        2066 :                 save_indirect_range(mfd, &br, owner, q);
     781        2066 :         free(br);
     782             : }
     783             : 
     784           0 : static int save_leaf_chain(struct metafd *mfd, struct lgfs2_sbd *sdp, char *buf)
     785             : {
     786           0 :         struct gfs2_leaf *leaf = (struct gfs2_leaf *)buf;
     787             : 
     788           0 :         while (leaf->lf_next != 0) {
     789           0 :                 uint64_t blk = be64_to_cpu(leaf->lf_next);
     790             :                 ssize_t r;
     791             : 
     792           0 :                 if (lgfs2_check_range(sdp, blk) != 0)
     793           0 :                         return 0;
     794             : 
     795           0 :                 r = pread(sdp->device_fd, buf, sdp->sd_bsize, sdp->sd_bsize * blk);
     796           0 :                 if (r != sdp->sd_bsize) {
     797           0 :                         fprintf(stderr, "Failed to read leaf block %"PRIx64": %s\n",
     798           0 :                                 blk, strerror(errno));
     799           0 :                         return 1;
     800             :                 }
     801           0 :                 report_progress(blk, 0);
     802           0 :                 if (lgfs2_check_meta(buf, GFS2_METATYPE_LF) == 0) {
     803           0 :                         int ret = save_buf(mfd, buf, blk, sdp->sd_bsize);
     804           0 :                         if (ret != 0)
     805           0 :                                 return ret;
     806             :                 }
     807           0 :                 leaf = (struct gfs2_leaf *)buf;
     808             :         }
     809           0 :         return 0;
     810             : }
     811             : 
     812           4 : static void save_leaf_blocks(struct metafd *mfd, struct block_range_queue *q)
     813             : {
     814           4 :         while (q->tail != NULL) {
     815           0 :                 struct block_range *br = q->tail;
     816             : 
     817           0 :                 for (unsigned i = 0; i < br->len; i++) {
     818           0 :                         char *buf = br->buf + (i * sbd.sd_bsize);
     819             : 
     820           0 :                         save_leaf_chain(mfd, &sbd, buf);
     821             :                 }
     822           0 :                 q->tail = br->next;
     823           0 :                 block_range_free(&br);
     824             :         }
     825           4 : }
     826             : 
     827             : /*
     828             :  * save_inode_data - save off important data associated with an inode
     829             :  *
     830             :  * mfd - destination file descriptor
     831             :  * buf - buffer containing the inode block
     832             :  * iblk - block number of the inode to save the data for
     833             :  *
     834             :  * For user files, we don't want anything except all the indirect block
     835             :  * pointers that reside on blocks on all but the highest height.
     836             :  *
     837             :  * For system files like statfs and inum, we want everything because they
     838             :  * may contain important clues and no user data.
     839             :  *
     840             :  * For file system journals, the "data" is a mixture of metadata and
     841             :  * journaled data.  We want all the metadata and none of the user data.
     842             :  */
     843         108 : static void save_inode_data(struct metafd *mfd, char *ibuf, uint64_t iblk)
     844             : {
     845         108 :         struct block_range_queue indq[GFS2_MAX_META_HEIGHT] = {{NULL}};
     846         108 :         struct gfs2_dinode *dip = (struct gfs2_dinode *)ibuf;
     847             :         uint16_t height;
     848             :         int is_exhash;
     849             : 
     850        1188 :         for (unsigned i = 0; i < GFS2_MAX_META_HEIGHT; i++)
     851        1080 :                 block_range_queue_init(&indq[i]);
     852             : 
     853         108 :         height = be16_to_cpu(dip->di_height);
     854             : 
     855             :         /* If this is a user inode, we don't follow to the file height.
     856             :            We stop one level less.  That way we save off the indirect
     857             :            pointer blocks but not the actual file contents. The exception
     858             :            is directories, where the height represents the level at which
     859             :            the hash table exists, and we have to save the directory data. */
     860             : 
     861         136 :         is_exhash = S_ISDIR(be32_to_cpu(dip->di_mode)) &&
     862          28 :                     be32_to_cpu(dip->di_flags) & GFS2_DIF_EXHASH;
     863         108 :         if (is_exhash)
     864           4 :                 height++;
     865         104 :         else if (height > 0 && !(be32_to_cpu(dip->di_flags) & GFS2_DIF_SYSTEM) &&
     866           0 :                  !block_is_systemfile(iblk) && !S_ISDIR(be32_to_cpu(dip->di_mode)))
     867           0 :                 height--;
     868             : 
     869         108 :         if (height == 1)
     870          19 :                 save_indirect_blocks(mfd, ibuf, iblk, NULL, sizeof(*dip));
     871          89 :         else if (height > 1)
     872          18 :                 save_indirect_blocks(mfd, ibuf, iblk, &indq[0], sizeof(*dip));
     873             : 
     874         131 :         for (unsigned i = 1; i < height; i++) {
     875          23 :                 struct block_range_queue *nextq = &indq[i];
     876             : 
     877          23 :                 if (!is_exhash && i == height - 1)
     878          18 :                         nextq = NULL;
     879             : 
     880             :                 /* Coverity can't figure out that the tail becomes NULL eventually. */
     881             :                 /* coverity[loop_top:SUPPRESS] */
     882         235 :                 while (indq[i - 1].tail != NULL) {
     883         212 :                         struct block_range *q = block_range_queue_pop(&indq[i - 1]);
     884             : 
     885        2241 :                         for (unsigned j = 0; j < q->len; j++) {
     886        2029 :                                 char *_buf = q->buf + (j * sbd.sd_bsize);
     887             : 
     888        2029 :                                 save_indirect_blocks(mfd, _buf, iblk, nextq, sizeof(dip->di_header));
     889             :                         }
     890         212 :                         report_progress(q->start + q->len, 0);
     891         212 :                         block_range_free(&q);
     892             :                 }
     893             :         }
     894         108 :         if (is_exhash)
     895           4 :                 save_leaf_blocks(mfd, &indq[height - 1]);
     896         108 :         if (dip->di_eattr) { /* if this inode has extended attributes */
     897             :                 size_t blklen;
     898             :                 uint64_t blk;
     899             :                 int mhtype;
     900             :                 char *buf;
     901             : 
     902           0 :                 blk = be64_to_cpu(dip->di_eattr);
     903           0 :                 buf = check_read_block(sbd.device_fd, blk, iblk, &mhtype, &blklen);
     904           0 :                 if (buf != NULL) {
     905           0 :                         save_buf(mfd, buf, blk, blklen);
     906           0 :                         if (mhtype == GFS2_METATYPE_EA)
     907           0 :                                 save_ea_block(mfd, buf, iblk);
     908           0 :                         else if (mhtype == GFS2_METATYPE_IN)
     909           0 :                                 save_indirect_blocks(mfd, buf, iblk, NULL, sizeof(dip->di_header));
     910           0 :                         free(buf);
     911             :                 }
     912             :         }
     913         108 : }
     914             : 
     915           7 : static void get_journal_inode_blocks(void)
     916             : {
     917             :         int journal;
     918             : 
     919           7 :         journals_found = 0;
     920           7 :         memset(journal_blocks, 0, sizeof(journal_blocks));
     921             :         /* Save off all the journals--but only the metadata.
     922             :          * This is confusing so I'll explain.  The journals contain important 
     923             :          * metadata.  However, in gfs2 the journals are regular files within
     924             :          * the system directory.  Since they're regular files, the blocks
     925             :          * within the journals are considered data, not metadata.  Therefore,
     926             :          * they won't have been saved by the code above.  We want to dump
     927             :          * these blocks, but we have to be careful.  We only care about the
     928             :          * journal blocks that look like metadata, and we need to not save
     929             :          * journaled user data that may exist there as well. */
     930           7 :         for (journal = 0; ; journal++) { /* while journals exist */
     931             :                 uint64_t jblock;
     932             : 
     933          49 :                 if (journal + 3 > indirect->ii[0].dirents)
     934           7 :                         break;
     935          42 :                 jblock = indirect->ii[0].dirent[journal + 2].inum.in_addr;
     936          42 :                 journal_blocks[journals_found++] = jblock;
     937             :         }
     938           7 : }
     939             : 
     940          52 : static void save_allocated_range(struct metafd *mfd, struct block_range *br)
     941             : {
     942          52 :         if (check_read_range(sbd.device_fd, br, 0) != 0)
     943           0 :                 return;
     944             : 
     945          52 :         save_range(mfd, br);
     946         160 :         for (unsigned i = 0; i < br->len; i++) {
     947         108 :                 char *buf = br->buf + (i * sbd.sd_bsize);
     948             : 
     949         108 :                 if (br->blktype[i] == GFS2_METATYPE_DI)
     950         108 :                         save_inode_data(mfd, buf, br->start + i);
     951             :         }
     952          52 :         free(br->buf);
     953             : }
     954             : 
     955         493 : static void save_allocated(struct lgfs2_rgrp_tree *rgd, struct metafd *mfd)
     956             : {
     957         493 :         uint64_t blk = 0;
     958             :         unsigned i, j, m;
     959         493 :         uint64_t *ibuf = malloc(sbd.sd_bsize * GFS2_NBBY * sizeof(uint64_t));
     960             : 
     961       45201 :         for (i = 0; i < rgd->rt_length; i++) {
     962       44708 :                 struct block_range br = {0};
     963             : 
     964       44708 :                 m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE);
     965             : 
     966       44816 :                 for (j = 0; j < m; j++) {
     967         108 :                         blk = ibuf[j];
     968         108 :                         if (br.start == 0) {
     969          32 :                                 br.start = blk;
     970          32 :                                 br.len = 1;
     971          76 :                         } else if (blk == br.start + br.len) {
     972          56 :                                 br.len++;
     973             :                         } else {
     974          20 :                                 save_allocated_range(mfd, &br);
     975          20 :                                 br.start = blk;
     976          20 :                                 br.len = 1;
     977             :                         }
     978         108 :                         report_progress(blk, 0);
     979             :                 }
     980       44708 :                 if (br.start != 0)
     981          32 :                         save_allocated_range(mfd, &br);
     982             :         }
     983         493 :         free(ibuf);
     984         493 : }
     985             : 
     986         493 : static char *rgrp_read(struct lgfs2_sbd *sdp, uint64_t addr, unsigned blocks)
     987             : {
     988         493 :         size_t len = blocks * sdp->sd_bsize;
     989         493 :         off_t off = addr * sdp->sd_bsize;
     990             :         char *buf;
     991             : 
     992         493 :         if (blocks == 0 || lgfs2_check_range(sdp, addr))
     993           0 :                 return NULL;
     994             : 
     995         493 :         buf = calloc(1, len);
     996         493 :         if (buf == NULL)
     997           0 :                 return NULL;
     998             : 
     999         493 :         if (pread(sdp->device_fd, buf, len, off) != len) {
    1000           0 :                 free(buf);
    1001           0 :                 return NULL;
    1002             :         }
    1003         493 :         return buf;
    1004             : }
    1005             : 
    1006         493 : static void save_rgrp(struct lgfs2_sbd *sdp, struct metafd *mfd, struct lgfs2_rgrp_tree *rgd, int withcontents)
    1007             : {
    1008         493 :         uint64_t addr = rgd->rt_addr;
    1009             :         char *buf;
    1010             : 
    1011         493 :         buf = rgrp_read(sdp, rgd->rt_addr, rgd->rt_length);
    1012         493 :         if (buf == NULL)
    1013           0 :                 return;
    1014             : 
    1015       45201 :         for (unsigned i = 0; i < rgd->rt_length; i++)
    1016       44708 :                 rgd->rt_bits[i].bi_data = buf + (i * sdp->sd_bsize);
    1017             : 
    1018         493 :         log_debug("RG at %"PRIu64" is %"PRIu32" long\n", addr, rgd->rt_length);
    1019             :         /* Save the rg and bitmaps */
    1020       45201 :         for (unsigned i = 0; i < rgd->rt_length; i++) {
    1021       44708 :                 report_progress(rgd->rt_addr + i, 0);
    1022       44708 :                 save_buf(mfd, buf + (i * sdp->sd_bsize), rgd->rt_addr + i, sdp->sd_bsize);
    1023             :         }
    1024             :         /* Save the other metadata: inodes, etc. if mode is not 'savergs' */
    1025         493 :         if (withcontents)
    1026         493 :                 save_allocated(rgd, mfd);
    1027             : 
    1028         493 :         free(buf);
    1029       45201 :         for (unsigned i = 0; i < rgd->rt_length; i++)
    1030       44708 :                 rgd->rt_bits[i].bi_data = NULL;
    1031             : }
    1032             : 
    1033           7 : static int save_header(struct metafd *mfd, uint64_t fsbytes)
    1034             : {
    1035          35 :         struct savemeta_header smh = {
    1036           7 :                 .sh_magic = cpu_to_be32(SAVEMETA_MAGIC),
    1037           7 :                 .sh_format = cpu_to_be32(SAVEMETA_FORMAT),
    1038           7 :                 .sh_time = cpu_to_be64(time(NULL)),
    1039           7 :                 .sh_fs_bytes = cpu_to_be64(fsbytes)
    1040             :         };
    1041             : 
    1042           7 :         if (savemetawrite(mfd, (char *)(&smh), sizeof(smh)) != sizeof(smh))
    1043           0 :                 return -1;
    1044           7 :         return 0;
    1045             : }
    1046             : 
    1047           5 : static int parse_header(char *buf, struct savemeta *sm)
    1048             : {
    1049           5 :         struct savemeta_header *smh = (void *)buf;
    1050             : 
    1051           5 :         if (be32_to_cpu(smh->sh_magic) != SAVEMETA_MAGIC) {
    1052           0 :                 printf("No valid file header found. Falling back to old format...\n");
    1053           0 :                 return 1;
    1054             :         }
    1055           5 :         if (be32_to_cpu(smh->sh_format) > SAVEMETA_FORMAT) {
    1056           0 :                 printf("This version of gfs2_edit is too old to restore this metadata format.\n");
    1057           0 :                 return -1;
    1058             :         }
    1059           5 :         sm->sm_format = be32_to_cpu(smh->sh_format);
    1060           5 :         sm->sm_time = be64_to_cpu(smh->sh_time);
    1061           5 :         sm->sm_fs_bytes = be64_to_cpu(smh->sh_fs_bytes);
    1062           5 :         printf("Metadata saved at %s", ctime(&sm->sm_time)); /* ctime() adds \n */
    1063           5 :         printf("File system size %.2fGB\n", sm->sm_fs_bytes / ((float)(1 << 30)));
    1064           5 :         return 0;
    1065             : }
    1066             : 
    1067           7 : void savemeta(char *out_fn, int saveoption, int gziplevel)
    1068             : {
    1069             :         struct metafd mfd;
    1070             :         struct osi_node *n;
    1071             :         uint64_t sb_addr;
    1072           7 :         int err = 0;
    1073             :         char *buf;
    1074             : 
    1075           7 :         sbd.md.journals = 1;
    1076             : 
    1077           7 :         mfd = savemetaopen(out_fn, gziplevel);
    1078             : 
    1079           7 :         blks_saved = 0;
    1080           7 :         printf("There are %"PRIu64" blocks of %u bytes in the filesystem.\n",
    1081             :                sbd.fssize, sbd.sd_bsize);
    1082             : 
    1083           7 :         printf("Filesystem size: %.2fGB\n", (sbd.fssize * sbd.sd_bsize) / ((float)(1 << 30)));
    1084           7 :         get_journal_inode_blocks();
    1085             : 
    1086           7 :         err = init_per_node_lookup();
    1087           7 :         if (err)
    1088           0 :                 exit(1);
    1089             : 
    1090             :         /* Write the savemeta file header */
    1091           7 :         err = save_header(&mfd, sbd.fssize * sbd.sd_bsize);
    1092           7 :         if (err) {
    1093           0 :                 perror("Failed to write metadata file header");
    1094           0 :                 exit(1);
    1095             :         }
    1096             :         /* Save off the superblock */
    1097           7 :         sb_addr = GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.sd_bsize;
    1098           7 :         buf = check_read_block(sbd.device_fd, sb_addr, 0, NULL, NULL);
    1099           7 :         if (buf != NULL) {
    1100           7 :                 save_buf(&mfd, buf, sb_addr, sizeof(struct gfs2_sb));
    1101           7 :                 free(buf);
    1102             :         }
    1103             :         /* Walk through the resource groups saving everything within */
    1104         500 :         for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
    1105             :                 struct lgfs2_rgrp_tree *rgd;
    1106             : 
    1107         493 :                 rgd = (struct lgfs2_rgrp_tree *)n;
    1108         493 :                 save_rgrp(&sbd, &mfd, rgd, (saveoption != 2));
    1109             :         }
    1110             :         /* Clean up */
    1111             :         /* There may be a gap between end of file system and end of device */
    1112             :         /* so we tell the user that we've processed everything. */
    1113           7 :         report_progress(sbd.fssize, 1);
    1114           7 :         printf("\nMetadata saved to file %s ", mfd.filename);
    1115           7 :         if (mfd.gziplevel) {
    1116           2 :                 printf("(gzipped, level %d).\n", mfd.gziplevel);
    1117             :         } else {
    1118           5 :                 printf("(uncompressed).\n");
    1119             :         }
    1120           7 :         savemetaclose(&mfd);
    1121           7 :         close(sbd.device_fd);
    1122           7 :         destroy_per_node_lookup();
    1123           7 :         free(indirect);
    1124           7 :         lgfs2_rgrp_free(&sbd, &sbd.rgtree);
    1125           7 :         exit(0);
    1126             : }
    1127             : 
    1128      196972 : static char *restore_block(struct metafd *mfd, uint64_t *blk, uint16_t *siglen)
    1129             : {
    1130             :         struct saved_metablock *svb;
    1131             :         const char *errstr;
    1132      196972 :         char *buf = NULL;
    1133             : 
    1134      196972 :         svb = (struct saved_metablock *)(restore_buf_next(mfd, sizeof(*svb)));
    1135      196972 :         if (svb == NULL)
    1136           5 :                 goto nobuffer;
    1137      196967 :         *blk = be64_to_cpu(svb->blk);
    1138      196967 :         *siglen = be16_to_cpu(svb->siglen);
    1139             : 
    1140      196967 :         if (sbd.fssize && *blk >= sbd.fssize) {
    1141           0 :                 fprintf(stderr, "Error: File system is too small to restore this metadata.\n");
    1142           0 :                 fprintf(stderr, "File system is %"PRIu64" blocks. Restore block = %"PRIu64"\n",
    1143             :                         sbd.fssize, *blk);
    1144           0 :                 return NULL;
    1145             :         }
    1146             : 
    1147      196967 :         if (*siglen > sbd.sd_bsize) {
    1148           0 :                 fprintf(stderr, "Bad record length: %u for block %"PRIu64" (0x%"PRIx64").\n",
    1149           0 :                         *siglen, *blk, *blk);
    1150           0 :                 return NULL;
    1151             :         }
    1152             : 
    1153      196967 :         buf = restore_buf_next(mfd, *siglen);
    1154      196967 :         if (buf != NULL) {
    1155      196967 :                 return buf;
    1156             :         }
    1157           0 : nobuffer:
    1158           5 :         if (mfd->eof)
    1159           5 :                 return NULL;
    1160             : 
    1161           0 :         errstr = mfd->strerr(mfd);
    1162           0 :         fprintf(stderr, "Failed to restore block: %s\n", errstr);
    1163           0 :         return NULL;
    1164             : }
    1165             : 
    1166           5 : static int restore_super(struct metafd *mfd, void *buf, int printonly)
    1167             : {
    1168             :         int ret;
    1169             : 
    1170           5 :         lgfs2_sb_in(&sbd, buf);
    1171           5 :         ret = lgfs2_check_sb(buf);
    1172           5 :         if (ret < 0) {
    1173           0 :                 fprintf(stderr, "Error: Invalid superblock in metadata file.\n");
    1174           0 :                 return -1;
    1175             :         }
    1176           5 :         if ((!printonly) && lgfs2_sb_write(&sbd, sbd.device_fd)) {
    1177           0 :                 fprintf(stderr, "Failed to write superblock\n");
    1178           0 :                 return -1;
    1179             :         }
    1180           5 :         blks_saved++;
    1181           5 :         return 0;
    1182             : }
    1183             : 
    1184           5 : static int restore_data(int fd, struct metafd *mfd, int printonly)
    1185             : {
    1186           5 :         uint64_t writes = 0;
    1187             :         char *buf;
    1188             : 
    1189           5 :         buf = calloc(1, sbd.sd_bsize);
    1190           5 :         if (buf == NULL) {
    1191           0 :                 perror("Failed to restore data");
    1192           0 :                 exit(1);
    1193             :         }
    1194             : 
    1195      196967 :         while (TRUE) {
    1196      196972 :                 uint16_t siglen = 0;
    1197      196972 :                 uint64_t blk = 0;
    1198             :                 char *bp;
    1199             : 
    1200      196972 :                 bp = restore_block(mfd, &blk, &siglen);
    1201      196972 :                 if (bp == NULL && mfd->eof)
    1202           5 :                         break;
    1203      196967 :                 if (bp == NULL) {
    1204           0 :                         free(buf);
    1205           0 :                         return -1;
    1206             :                 }
    1207      196967 :                 if (printonly) {
    1208           0 :                         if (printonly > 1 && printonly == blk) {
    1209           0 :                                 display_block_type(bp, blk, TRUE);
    1210           0 :                                 display_gfs2(bp);
    1211           0 :                                 break;
    1212           0 :                         } else if (printonly == 1) {
    1213           0 :                                 print_gfs2("%"PRId64" (l=0x%x): ", blks_saved, siglen);
    1214           0 :                                 display_block_type(bp, blk, TRUE);
    1215             :                         }
    1216             :                 } else {
    1217      196967 :                         report_progress(blk, 0);
    1218      196967 :                         memcpy(buf, bp, siglen);
    1219      196967 :                         memset(buf + siglen, 0, sbd.sd_bsize - siglen);
    1220      196967 :                         if (pwrite(fd, buf, sbd.sd_bsize, blk * sbd.sd_bsize) != sbd.sd_bsize) {
    1221           0 :                                 fprintf(stderr, "write error: %s from %s:%d: block %"PRIu64" (0x%"PRIx64")\n",
    1222           0 :                                         strerror(errno), __FUNCTION__, __LINE__, blk, blk);
    1223           0 :                                 free(buf);
    1224           0 :                                 return -1;
    1225             :                         }
    1226      196967 :                         writes++;
    1227      196967 :                         if (writes % 1000 == 0)
    1228         193 :                                 fsync(fd);
    1229             :                 }
    1230      196967 :                 blks_saved++;
    1231             :         }
    1232           5 :         if (!printonly)
    1233           5 :                 report_progress(sbd.fssize, 1);
    1234           5 :         free(buf);
    1235           5 :         return 0;
    1236             : }
    1237             : 
    1238           0 : static void restoremeta_usage(void)
    1239             : {
    1240           0 :         fprintf(stderr, "Usage:\n");
    1241           0 :         fprintf(stderr, "gfs2_edit restoremeta <metadata_file> <block_device>\n");
    1242           0 : }
    1243             : 
    1244           5 : static int restore_init(const char *path, struct metafd *mfd, int printonly)
    1245             : {
    1246           5 :         struct savemeta sm = {0};
    1247             :         struct gfs2_sb rsb;
    1248             :         uint16_t sb_siglen;
    1249             :         char *end;
    1250             :         char *bp;
    1251             :         int ret;
    1252             : 
    1253           5 :         blks_saved = 0;
    1254           5 :         restore_buf = malloc(RESTORE_BUF_SIZE);
    1255           5 :         if (restore_buf == NULL) {
    1256           0 :                 perror("Restore failed");
    1257           0 :                 return -1;
    1258             :         }
    1259           5 :         restore_off = 0;
    1260           5 :         restore_left = 0;
    1261             : 
    1262           5 :         mfd->filename = path;
    1263           5 :         mfd->fd = open(path, O_RDONLY|O_CLOEXEC);
    1264           5 :         if (mfd->fd < 0) {
    1265           0 :                 perror("Could not open metadata file");
    1266           0 :                 return 1;
    1267             :         }
    1268          10 :         if (restore_try_bzip(mfd) != 0 &&
    1269           5 :             restore_try_gzip(mfd) != 0) {
    1270           0 :                 fprintf(stderr, "Failed to read metadata file header and superblock\n");
    1271           0 :                 return -1;
    1272             :         }
    1273           5 :         bp = restore_buf;
    1274           5 :         ret = parse_header(bp, &sm);
    1275           5 :         if (ret == 0) {
    1276           5 :                 bp = restore_buf + sizeof(struct savemeta_header);
    1277           5 :                 restore_off = sizeof(struct savemeta_header);
    1278           0 :         } else if (ret == -1) {
    1279           0 :                 return -1;
    1280             :         }
    1281             :         /* Scan for the position of the superblock. Required to support old formats(?). */
    1282           5 :         end = &restore_buf[256 + sizeof(struct saved_metablock) + sizeof(struct gfs2_meta_header)];
    1283           5 :         while (bp <= end) {
    1284           5 :                 memcpy(&rsb, bp + sizeof(struct saved_metablock), sizeof(rsb));
    1285           5 :                 sb_siglen = be16_to_cpu(((struct saved_metablock *)bp)->siglen);
    1286          10 :                 if (be32_to_cpu(rsb.sb_header.mh_magic) == GFS2_MAGIC &&
    1287           5 :                     be32_to_cpu(rsb.sb_header.mh_type) == GFS2_METATYPE_SB)
    1288           5 :                         break;
    1289           0 :                 bp++;
    1290             :         }
    1291           5 :         if (bp > end) {
    1292           0 :                 fprintf(stderr, "No superblock found in metadata file\n");
    1293           0 :                 return -1;
    1294             :         }
    1295           5 :         bp += sizeof(struct saved_metablock);
    1296           5 :         ret = restore_super(mfd, &rsb, printonly);
    1297           5 :         if (ret != 0)
    1298           0 :                 return ret;
    1299             : 
    1300           5 :         if (sm.sm_fs_bytes > 0) {
    1301           5 :                 sbd.fssize = sm.sm_fs_bytes / sbd.sd_bsize;
    1302           5 :                 printf("Saved file system size is %"PRIu64" blocks, %.2fGB\n",
    1303           5 :                        sbd.fssize, sm.sm_fs_bytes / ((float)(1 << 30)));
    1304             :         }
    1305           5 :         printf("Block size is %uB\n", sbd.sd_bsize);
    1306           5 :         printf("This is gfs2 metadata.\n");
    1307           5 :         if (printonly > 1 && printonly == LGFS2_SB_ADDR(&sbd)) {
    1308           0 :                 display_block_type(bp, LGFS2_SB_ADDR(&sbd), TRUE);
    1309           0 :                 display_gfs2(bp);
    1310           5 :         } else if (printonly == 1) {
    1311           0 :                 print_gfs2("0 (l=0x%x): ", sb_siglen);
    1312           0 :                 display_block_type(bp, LGFS2_SB_ADDR(&sbd), TRUE);
    1313             :         }
    1314           5 :         bp += sb_siglen;
    1315           5 :         restore_off = bp - restore_buf;
    1316           5 :         restore_left -= restore_off;
    1317           5 :         return 0;
    1318             : }
    1319             : 
    1320           5 : void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly)
    1321             : {
    1322           5 :         struct metafd mfd = {0};
    1323             :         int error;
    1324             : 
    1325           5 :         termlines = 0;
    1326           5 :         if (in_fn == NULL || in_fn[0] == '\0') {
    1327           0 :                 fprintf(stderr, "No source file specified.");
    1328           0 :                 restoremeta_usage();
    1329           0 :                 exit(1);
    1330             :         }
    1331           5 :         if (!printonly && (out_device == NULL || out_device[0] == '\0')) {
    1332           0 :                 fprintf(stderr, "No destination file system specified.");
    1333           0 :                 restoremeta_usage();
    1334           0 :                 exit(1);
    1335             :         }
    1336           5 :         if (!printonly) {
    1337           5 :                 sbd.device_fd = open(out_device, O_RDWR);
    1338           5 :                 if (sbd.device_fd < 0) {
    1339           0 :                         fprintf(stderr, "Failed to open target '%s': %s\n",
    1340           0 :                             out_device, strerror(errno));
    1341           0 :                         exit(1);
    1342             :                 }
    1343           0 :         } else if (out_device) /* for printsavedmeta, the out_device is an
    1344             :                                   optional block no */
    1345           0 :                 printonly = check_keywords(out_device);
    1346             : 
    1347           5 :         error = restore_init(in_fn, &mfd, printonly);
    1348           5 :         if (error != 0)
    1349           0 :                 exit(error);
    1350             : 
    1351           5 :         if (!printonly) {
    1352           5 :                 uint64_t space = lseek(sbd.device_fd, 0, SEEK_END) / sbd.sd_bsize;
    1353           5 :                 printf("There are %"PRIu64" free blocks on the destination device.\n", space);
    1354             :         }
    1355             : 
    1356           5 :         error = restore_data(sbd.device_fd, &mfd, printonly);
    1357           5 :         printf("File %s %s %s.\n", in_fn,
    1358             :                (printonly ? "print" : "restore"),
    1359             :                (error ? "error" : "successful"));
    1360             : 
    1361           5 :         mfd.close(&mfd);
    1362           5 :         if (!printonly)
    1363           5 :                 close(sbd.device_fd);
    1364           5 :         free(indirect);
    1365           5 :         exit(error);
    1366             : }

Generated by: LCOV version 1.14