LCOV - code coverage report
Current view: top level - edit - savemeta.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 70.6 % 765 540
Test Date: 2024-03-07 16:24:06 Functions: 88.5 % 52 46

            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       460952 : static char *restore_buf_next(struct metafd *mfd, size_t required_len)
      75              : {
      76       460952 :         if (restore_left < required_len) {
      77           14 :                 char *tail = restore_buf + restore_off;
      78              :                 int ret;
      79              : 
      80           14 :                 memmove(restore_buf, tail, restore_left);
      81           14 :                 ret = mfd->read(mfd, restore_buf + restore_left, RESTORE_BUF_SIZE - restore_left);
      82           14 :                 if (ret < (int)required_len - restore_left)
      83            6 :                         return NULL;
      84            8 :                 restore_left += ret;
      85            8 :                 restore_off = 0;
      86              :         }
      87       460946 :         restore_left -= required_len;
      88       460946 :         restore_off += required_len;
      89       460946 :         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           20 : static int gz_read(struct metafd *mfd, void *buf, unsigned len)
     105              : {
     106           20 :         int ret = gzread(mfd->gzfd, buf, len);
     107           20 :         if (ret < len && gzeof(mfd->gzfd))
     108           12 :                 mfd->eof = 1;
     109           20 :         return ret;
     110              : }
     111              : 
     112            6 : static void gz_close(struct metafd *mfd)
     113              : {
     114            6 :         gzclose(mfd->gzfd);
     115            6 : }
     116              : 
     117              : /* This should be tried last because gzip doesn't distinguish between
     118              :    decompressing a gzip file and reading an uncompressed file */
     119            6 : static int restore_try_gzip(struct metafd *mfd)
     120              : {
     121            6 :         mfd->read = gz_read;
     122            6 :         mfd->close = gz_close;
     123            6 :         mfd->strerr = gz_strerr;
     124            6 :         lseek(mfd->fd, 0, SEEK_SET);
     125            6 :         mfd->gzfd = gzdopen(mfd->fd, "rb");
     126            6 :         if (!mfd->gzfd)
     127            0 :                 return 1;
     128            6 :         gzbuffer(mfd->gzfd, (1<<20)); /* Increase zlib's buffers to 1MB */
     129            6 :         restore_left = mfd->read(mfd, restore_buf, RESTORE_BUF_SIZE);
     130            6 :         if (restore_left < 512)
     131            0 :                 return -1;
     132            6 :         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            6 : static int bz_read(struct metafd *mfd, void *buf, unsigned len)
     148              : {
     149            6 :         int bzerr = BZ_OK;
     150              :         int ret;
     151              : 
     152            6 :         ret = BZ2_bzRead(&bzerr, mfd->bzfd, buf, len);
     153            6 :         if (bzerr == BZ_OK)
     154            0 :                 return ret;
     155            6 :         if (bzerr == BZ_STREAM_END) {
     156            0 :                 mfd->eof = 1;
     157            0 :                 return ret;
     158              :         }
     159            6 :         return -1;
     160              : }
     161              : 
     162            0 : static void bz_close(struct metafd *mfd)
     163              : {
     164            0 :         BZ2_bzclose(mfd->bzfd);
     165            0 : }
     166              : 
     167            6 : static int restore_try_bzip(struct metafd *mfd)
     168              : {
     169              :         int bzerr;
     170              :         FILE *f;
     171              : 
     172            6 :         f = fdopen(mfd->fd, "r");
     173            6 :         if (f == NULL)
     174            0 :                 return 1;
     175              : 
     176            6 :         mfd->read = bz_read;
     177            6 :         mfd->close = bz_close;
     178            6 :         mfd->strerr = bz_strerr;
     179            6 :         mfd->bzfd = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0);
     180            6 :         if (!mfd->bzfd)
     181            0 :                 return 1;
     182            6 :         restore_left = mfd->read(mfd, restore_buf, RESTORE_BUF_SIZE);
     183            6 :         if (restore_left < 512)
     184            6 :                 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           28 : static int block_is_a_journal(uint64_t blk)
     194              : {
     195              :         int j;
     196              : 
     197          196 :         for (j = 0; j < journals_found; j++)
     198          168 :                 if (blk == journal_blocks[j])
     199            0 :                         return TRUE;
     200           28 :         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            8 : static void destroy_per_node_lookup(void)
     210              : {
     211              :         struct osi_node *n;
     212              :         struct per_node_node *pnp;
     213              : 
     214           22 :         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            8 : }
     220              : 
     221           28 : static int block_is_in_per_node(uint64_t blk)
     222              : {
     223           28 :         struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node;
     224              : 
     225           45 :         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           20 :         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            8 : static int init_per_node_lookup(void)
     266              : {
     267              :         int i;
     268              :         struct lgfs2_inode *per_node_di;
     269              : 
     270            8 :         per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node"));
     271            8 :         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            8 :         do_dinode_extended(per_node_di->i_bh->b_data);
     277            8 :         lgfs2_inode_put(&per_node_di);
     278              : 
     279           11 :         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            8 :         return 0;
     288              : }
     289              : 
     290           94 : static int block_is_systemfile(uint64_t blk)
     291              : {
     292          180 :         return block_is_inum_file(blk) ||
     293          164 :                block_is_statfs_file(blk) ||
     294          148 :                block_is_quota_file(blk) ||
     295           98 :                block_is_rindex(blk) ||
     296           56 :                block_is_a_journal(blk) ||
     297          208 :                block_is_per_node(blk) ||
     298           28 :                block_is_in_per_node(blk);
     299              : }
     300              : 
     301          120 : 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          120 :         dn = (void *)buf;
     308          120 :         di_mode = be32_to_cpu(dn->di_mode);
     309          120 :         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          172 :         if (di_height > 0 || S_ISDIR(di_mode) || S_ISLNK(di_mode) ||
     314           52 :             block_is_systemfile(owner))
     315          100 :                 return sbd.sd_bsize;
     316           20 :         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       252382 : static int get_struct_info(const char *buf, uint64_t owner, unsigned *block_type,
     331              :                                unsigned *gstruct_len)
     332              : {
     333       252382 :         struct gfs2_meta_header *mh = (struct gfs2_meta_header *)buf;
     334              : 
     335       252382 :         if (block_type != NULL)
     336       252382 :                 *block_type = 0;
     337              : 
     338       252382 :         if (gstruct_len != NULL)
     339       252382 :                 *gstruct_len = sbd.sd_bsize;
     340              : 
     341       252382 :         if (be32_to_cpu(mh->mh_magic) != GFS2_MAGIC)
     342           42 :                 return -1;
     343              : 
     344       252340 :         if (block_type != NULL)
     345       252340 :                 *block_type = be32_to_cpu(mh->mh_type);
     346              : 
     347       252340 :         if (gstruct_len == NULL)
     348            0 :                 return 0;
     349              : 
     350       252340 :         switch (be32_to_cpu(mh->mh_type)) {
     351            8 :         case GFS2_METATYPE_SB:   /* 1 (superblock) */
     352            8 :                 *gstruct_len = sizeof(struct gfs2_sb);
     353            8 :                 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          120 :         case GFS2_METATYPE_DI:   /* 4 (disk inode) */
     361          120 :                 *gstruct_len = di_save_len(buf, owner);
     362          120 :                 break;
     363         2094 :         case GFS2_METATYPE_IN:   /* 5 (indir inode blklst) */
     364         2094 :                 *gstruct_len = sbd.sd_bsize; /*sizeof(struct gfs_indirect);*/
     365         2094 :                 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       237568 :         case GFS2_METATYPE_LH:   /* 8 (log header) */
     373       237568 :                 *gstruct_len = sizeof(struct gfs2_log_header);
     374       237568 :                 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        12544 :         default:
     385        12544 :                 *gstruct_len = sbd.sd_bsize;
     386        12544 :                 break;
     387              :         }
     388       252340 :         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       275931 : static void report_progress(uint64_t pblock, int force)
     398              : {
     399              :         static struct timeval tv;
     400              :         static uint32_t seconds = 0;
     401              : 
     402       275931 :         gettimeofday(&tv, NULL);
     403       275931 :         if (!seconds)
     404           14 :                 seconds = tv.tv_sec;
     405       275931 :         if (force || tv.tv_sec - seconds) {
     406              :                 static uint64_t percent;
     407              : 
     408           18 :                 seconds = tv.tv_sec;
     409           18 :                 if (sbd.fssize) {
     410           18 :                         printf("\r");
     411           18 :                         percent = (pblock * 100) / sbd.fssize;
     412           18 :                         printf("%"PRIu64" blocks saved (%"PRIu64"%% complete)",
     413              :                                blks_saved, percent);
     414           18 :                         if (force)
     415           14 :                                 printf("\n");
     416           18 :                         fflush(stdout);
     417              :                 }
     418              :         }
     419       275931 : }
     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            8 : static struct metafd savemetaopen(char *out_fn, int gziplevel)
     429              : {
     430            8 :         struct metafd mfd = {0};
     431            8 :         char gzmode[3] = "w9";
     432            8 :         char dft_fn[] = DFT_SAVE_FILE;
     433            8 :         mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
     434              :         struct stat st;
     435              : 
     436            8 :         mfd.gziplevel = gziplevel;
     437              : 
     438            8 :         if (!out_fn) {
     439            0 :                 out_fn = dft_fn;
     440            0 :                 mfd.fd = mkstemp(out_fn);
     441              :         } else {
     442            8 :                 mfd.fd = open(out_fn, O_RDWR | O_CREAT, 0644);
     443              :         }
     444            8 :         umask(mask);
     445            8 :         mfd.filename = out_fn;
     446              : 
     447            8 :         if (mfd.fd < 0) {
     448            0 :                 fprintf(stderr, "Can't open %s: %s\n", out_fn, strerror(errno));
     449            0 :                 exit(1);
     450              :         }
     451            8 :         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            8 :         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            8 :         if (gziplevel > 0) {
     461            3 :                 gzmode[1] = '0' + gziplevel;
     462            3 :                 mfd.gzfd = gzdopen(mfd.fd, gzmode);
     463            3 :                 if (!mfd.gzfd) {
     464            0 :                         fprintf(stderr, "gzdopen error: %s\n", strerror(errno));
     465            0 :                         exit(1);
     466              :                 }
     467            3 :                 gzbuffer(mfd.gzfd, (1<<20)); /* Increase zlib's buffers to 1MB */
     468              :         }
     469              : 
     470            8 :         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       297501 : 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       297501 :         if (mfd->gziplevel == 0) {
     487       213595 :                 return write(mfd->fd, buf, nbyte);
     488              :         }
     489              : 
     490        83906 :         ret = gzwrite(mfd->gzfd, buf, nbyte);
     491        83906 :         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        83906 :         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            8 : static int savemetaclose(struct metafd *mfd)
     506              : {
     507              :         int gzret;
     508            8 :         if (mfd->gziplevel > 0) {
     509            3 :                 gzret = gzclose(mfd->gzfd);
     510            3 :                 if (gzret == Z_STREAM_ERROR) {
     511            0 :                         fprintf(stderr, "gzclose: file is not valid\n");
     512            0 :                         return -1;
     513            3 :                 } else if (gzret == Z_ERRNO) {
     514            0 :                         return -1;
     515              :                 }
     516              :         }
     517            8 :         return close(mfd->fd);
     518              : }
     519              : 
     520       297493 : 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       297493 :         if (mfd->gziplevel == 0)
     528     43150243 :                 for (; blklen > 0 && buf[blklen - 1] == '\0'; blklen--);
     529              : 
     530       297493 :         if (blklen == 0) /* No significant data; skip. */
     531            0 :                 return 0;
     532              : 
     533       297493 :         outsz = sizeof(*savedata) + blklen;
     534       297493 :         savedata = calloc(1, outsz);
     535       297493 :         if (savedata == NULL) {
     536            0 :                 perror("Failed to save block");
     537            0 :                 exit(1);
     538              :         }
     539       297493 :         savedata->blk = cpu_to_be64(addr);
     540       297493 :         savedata->siglen = cpu_to_be16(blklen);
     541       297493 :         memcpy(savedata + 1, buf, blklen);
     542              : 
     543       297493 :         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       297493 :         blks_saved++;
     550       297493 :         free(savedata);
     551       297493 :         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         2367 : static int block_range_prepare(struct block_range *br)
     564              : {
     565         2367 :         br->buf = calloc(br->len, sbd.sd_bsize + sizeof(*br->blktype) + sizeof(*br->blklen));
     566         2367 :         if (br->buf == NULL) {
     567            0 :                 perror("Failed to allocate block range buffer");
     568            0 :                 return 1;
     569              :         }
     570         2367 :         br->blktype = (unsigned *)(br->buf + (br->len * sbd.sd_bsize));
     571         2367 :         br->blklen = br->blktype + br->len;
     572         2367 :         return 0;
     573              : }
     574              : 
     575         2367 : static int block_range_check(struct block_range *br)
     576              : {
     577         2367 :         if (br->start >= LGFS2_SB_ADDR(&sbd) && br->start + br->len <= sbd.fssize)
     578         2367 :                 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         2367 : static void block_range_setinfo(struct block_range *br, uint64_t owner)
     588              : {
     589       254749 :         for (unsigned i = 0; i < br->len; i++) {
     590       252382 :                 char *buf = br->buf + (i * sbd.sd_bsize);
     591       252382 :                 uint64_t addr = br->start + i;
     592       252382 :                 uint64_t _owner = (owner == 0) ? addr : owner;
     593              : 
     594       252424 :                 if (get_struct_info(buf, _owner, br->blktype + i, br->blklen + i) &&
     595           42 :                     !block_is_systemfile(_owner)) {
     596            0 :                         br->blklen[i] = 0;
     597              :                 }
     598              :         }
     599         2367 : }
     600              : 
     601          213 : static void block_range_free(struct block_range **brp)
     602              : {
     603          213 :         free((*brp)->buf);
     604          213 :         free(*brp);
     605          213 :         *brp = NULL;
     606          213 : }
     607              : 
     608              : struct block_range_queue {
     609              :         struct block_range *tail;
     610              :         struct block_range **head;
     611              : };
     612              : 
     613         1200 : static void block_range_queue_init(struct block_range_queue *q)
     614              : {
     615         1200 :         q->head = &q->tail;
     616         1200 : }
     617              : 
     618          213 : static void block_range_queue_insert(struct block_range_queue *q, struct block_range *br)
     619              : {
     620          213 :         *q->head = br;
     621          213 :         q->head = &br->next;
     622          213 : }
     623              : 
     624          213 : static struct block_range *block_range_queue_pop(struct block_range_queue *q)
     625              : {
     626          213 :         struct block_range *br = q->tail;
     627              : 
     628          213 :         q->tail = br->next;
     629          213 :         br->next = NULL;
     630          213 :         return br;
     631              : }
     632              : 
     633         2359 : static int save_range(struct metafd *mfd, struct block_range *br)
     634              : {
     635       254733 :         for (unsigned i = 0; i < br->len; i++) {
     636              :                 int err;
     637              : 
     638       252374 :                 err = save_buf(mfd, br->buf + (i * sbd.sd_bsize), br->start + i, br->blklen[i]);
     639       252374 :                 if (err != 0)
     640            0 :                         return err;
     641              :         }
     642         2359 :         return 0;
     643              : }
     644              : 
     645         2367 : static int check_read_range(int fd, struct block_range *br, uint64_t owner)
     646              : {
     647              :         size_t size;
     648              : 
     649         2367 :         if (block_range_prepare(br) != 0)
     650            0 :                 return 1;
     651              : 
     652         2367 :         if (block_range_check(br) != 0)
     653            0 :                 return 1;
     654              : 
     655         2367 :         size = br->len * sbd.sd_bsize;
     656         2367 :         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         2367 :         block_range_setinfo(br, owner);
     664         2367 :         return 0;
     665              : }
     666              : 
     667            8 : static char *check_read_block(int fd, uint64_t blk, uint64_t owner, int *blktype, size_t *blklen)
     668              : {
     669            8 :         struct block_range br = {
     670              :                 .start = blk,
     671              :                 .len = 1
     672              :         };
     673              : 
     674            8 :         if (check_read_range(fd, &br, owner) != 0)
     675            0 :                 return NULL;
     676            8 :         if (blklen != NULL)
     677            0 :                 *blklen = *br.blklen;
     678            8 :         if (blktype != NULL)
     679            0 :                 *blktype = *br.blktype;
     680            8 :         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         2302 : static void save_indirect_range(struct metafd *mfd, struct block_range **brp, uint64_t owner,
     722              :                                 struct block_range_queue *q)
     723              : {
     724         2302 :         struct block_range *br = *brp;
     725              : 
     726         2302 :         if (check_read_range(sbd.device_fd, br, owner) != 0)
     727            0 :                 return;
     728              : 
     729         2302 :         save_range(mfd, br);
     730       254556 :         for (unsigned i = 0; i < br->len; i++) {
     731       252254 :                 if (br->blktype[i] == GFS2_METATYPE_EA)
     732            0 :                         save_ea_block(mfd, br->buf + (i * sbd.sd_bsize), owner);
     733              :         }
     734         2302 :         if (q) {
     735          213 :                 block_range_queue_insert(q, br);
     736          213 :                 *brp = NULL; /* The list now has ownership of it */
     737              :         } else {
     738         2089 :                 free(br->buf);
     739         2089 :                 br->buf = NULL;
     740              :         }
     741              : }
     742              : 
     743         2134 : static void save_indirect_blocks(struct metafd *mfd, char *buf, uint64_t owner,
     744              :                                  struct block_range_queue *q, unsigned headsize)
     745              : {
     746         2134 :         uint64_t old_block = 0, indir_block;
     747         2134 :         struct block_range *br = NULL;
     748              :         __be64 *ptr;
     749              : 
     750         2134 :         for (ptr = (__be64 *)(buf + headsize);
     751       267908 :              (char *)ptr < (buf + sbd.sd_bsize); ptr++) {
     752       265774 :                 if (!*ptr)
     753        13398 :                         continue;
     754              : 
     755       252376 :                 indir_block = be64_to_cpu(*ptr);
     756       252376 :                 if (indir_block == old_block)
     757          122 :                         continue;
     758       252254 :                 old_block = indir_block;
     759              : 
     760       252254 :                 if (br == NULL) {
     761         2134 : new_range:
     762         2299 :                         br = calloc(1, sizeof(*br));
     763         2299 :                         if (br == NULL) {
     764            0 :                                 perror("Failed to save indirect blocks");
     765            0 :                                 return;
     766              :                         }
     767         2299 :                         br->start = indir_block;
     768         2299 :                         br->len = 1;
     769       250120 :                 } else if (indir_block == br->start + br->len) {
     770       249952 :                         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         2134 :         if (br != NULL && br->start != 0)
     780         2134 :                 save_indirect_range(mfd, &br, owner, q);
     781         2134 :         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          120 : static void save_inode_data(struct metafd *mfd, char *ibuf, uint64_t iblk)
     844              : {
     845          120 :         struct block_range_queue indq[GFS2_MAX_META_HEIGHT] = {{NULL}};
     846          120 :         struct gfs2_dinode *dip = (struct gfs2_dinode *)ibuf;
     847              :         uint16_t height;
     848              :         int is_exhash;
     849              : 
     850         1320 :         for (unsigned i = 0; i < GFS2_MAX_META_HEIGHT; i++)
     851         1200 :                 block_range_queue_init(&indq[i]);
     852              : 
     853          120 :         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          152 :         is_exhash = S_ISDIR(be32_to_cpu(dip->di_mode)) &&
     862           32 :                     be32_to_cpu(dip->di_flags) & GFS2_DIF_EXHASH;
     863          120 :         if (is_exhash)
     864            4 :                 height++;
     865          116 :         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          120 :         if (height == 1)
     870           21 :                 save_indirect_blocks(mfd, ibuf, iblk, NULL, sizeof(*dip));
     871           99 :         else if (height > 1)
     872           19 :                 save_indirect_blocks(mfd, ibuf, iblk, &indq[0], sizeof(*dip));
     873              : 
     874          144 :         for (unsigned i = 1; i < height; i++) {
     875           24 :                 struct block_range_queue *nextq = &indq[i];
     876              : 
     877           24 :                 if (!is_exhash && i == height - 1)
     878           19 :                         nextq = NULL;
     879              : 
     880              :                 /* Coverity can't figure out that the tail becomes NULL eventually. */
     881              :                 /* coverity[loop_top:SUPPRESS] */
     882          237 :                 while (indq[i - 1].tail != NULL) {
     883          213 :                         struct block_range *q = block_range_queue_pop(&indq[i - 1]);
     884              : 
     885         2307 :                         for (unsigned j = 0; j < q->len; j++) {
     886         2094 :                                 char *_buf = q->buf + (j * sbd.sd_bsize);
     887              : 
     888         2094 :                                 save_indirect_blocks(mfd, _buf, iblk, nextq, sizeof(dip->di_header));
     889              :                         }
     890          213 :                         report_progress(q->start + q->len, 0);
     891          213 :                         block_range_free(&q);
     892              :                 }
     893              :         }
     894          120 :         if (is_exhash)
     895            4 :                 save_leaf_blocks(mfd, &indq[height - 1]);
     896          120 :         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          120 : }
     914              : 
     915            8 : static void get_journal_inode_blocks(void)
     916              : {
     917              :         int journal;
     918              : 
     919            8 :         journals_found = 0;
     920            8 :         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            8 :         for (journal = 0; ; journal++) { /* while journals exist */
     931              :                 uint64_t jblock;
     932              : 
     933           56 :                 if (journal + 3 > indirect->ii[0].dirents)
     934            8 :                         break;
     935           48 :                 jblock = indirect->ii[0].dirent[journal + 2].inum.in_addr;
     936           48 :                 journal_blocks[journals_found++] = jblock;
     937              :         }
     938            8 : }
     939              : 
     940           57 : static void save_allocated_range(struct metafd *mfd, struct block_range *br)
     941              : {
     942           57 :         if (check_read_range(sbd.device_fd, br, 0) != 0)
     943            0 :                 return;
     944              : 
     945           57 :         save_range(mfd, br);
     946          177 :         for (unsigned i = 0; i < br->len; i++) {
     947          120 :                 char *buf = br->buf + (i * sbd.sd_bsize);
     948              : 
     949          120 :                 if (br->blktype[i] == GFS2_METATYPE_DI)
     950          120 :                         save_inode_data(mfd, buf, br->start + i);
     951              :         }
     952           57 :         free(br->buf);
     953              : }
     954              : 
     955          574 : static void save_allocated(struct lgfs2_rgrp_tree *rgd, struct metafd *mfd)
     956              : {
     957          574 :         uint64_t blk = 0;
     958              :         unsigned i, j, m;
     959          574 :         uint64_t *ibuf = malloc(sbd.sd_bsize * GFS2_NBBY * sizeof(uint64_t));
     960              : 
     961        45685 :         for (i = 0; i < rgd->rt_length; i++) {
     962        45111 :                 struct block_range br = {0};
     963              : 
     964        45111 :                 m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE);
     965              : 
     966        45231 :                 for (j = 0; j < m; j++) {
     967          120 :                         blk = ibuf[j];
     968          120 :                         if (br.start == 0) {
     969           35 :                                 br.start = blk;
     970           35 :                                 br.len = 1;
     971           85 :                         } else if (blk == br.start + br.len) {
     972           63 :                                 br.len++;
     973              :                         } else {
     974           22 :                                 save_allocated_range(mfd, &br);
     975           22 :                                 br.start = blk;
     976           22 :                                 br.len = 1;
     977              :                         }
     978          120 :                         report_progress(blk, 0);
     979              :                 }
     980        45111 :                 if (br.start != 0)
     981           35 :                         save_allocated_range(mfd, &br);
     982              :         }
     983          574 :         free(ibuf);
     984          574 : }
     985              : 
     986          574 : static char *rgrp_read(struct lgfs2_sbd *sdp, uint64_t addr, unsigned blocks)
     987              : {
     988          574 :         size_t len = blocks * sdp->sd_bsize;
     989          574 :         off_t off = addr * sdp->sd_bsize;
     990              :         char *buf;
     991              : 
     992          574 :         if (blocks == 0 || lgfs2_check_range(sdp, addr))
     993            0 :                 return NULL;
     994              : 
     995          574 :         buf = calloc(1, len);
     996          574 :         if (buf == NULL)
     997            0 :                 return NULL;
     998              : 
     999          574 :         if (pread(sdp->device_fd, buf, len, off) != len) {
    1000            0 :                 free(buf);
    1001            0 :                 return NULL;
    1002              :         }
    1003          574 :         return buf;
    1004              : }
    1005              : 
    1006          574 : static void save_rgrp(struct lgfs2_sbd *sdp, struct metafd *mfd, struct lgfs2_rgrp_tree *rgd, int withcontents)
    1007              : {
    1008          574 :         uint64_t addr = rgd->rt_addr;
    1009              :         char *buf;
    1010              : 
    1011          574 :         buf = rgrp_read(sdp, rgd->rt_addr, rgd->rt_length);
    1012          574 :         if (buf == NULL)
    1013            0 :                 return;
    1014              : 
    1015        45685 :         for (unsigned i = 0; i < rgd->rt_length; i++)
    1016        45111 :                 rgd->rt_bits[i].bi_data = buf + (i * sdp->sd_bsize);
    1017              : 
    1018          574 :         log_debug("RG at %"PRIu64" is %"PRIu32" long\n", addr, rgd->rt_length);
    1019              :         /* Save the rg and bitmaps */
    1020        45685 :         for (unsigned i = 0; i < rgd->rt_length; i++) {
    1021        45111 :                 report_progress(rgd->rt_addr + i, 0);
    1022        45111 :                 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          574 :         if (withcontents)
    1026          574 :                 save_allocated(rgd, mfd);
    1027              : 
    1028          574 :         free(buf);
    1029        45685 :         for (unsigned i = 0; i < rgd->rt_length; i++)
    1030        45111 :                 rgd->rt_bits[i].bi_data = NULL;
    1031              : }
    1032              : 
    1033            8 : static int save_header(struct metafd *mfd, uint64_t fsbytes)
    1034              : {
    1035           40 :         struct savemeta_header smh = {
    1036            8 :                 .sh_magic = cpu_to_be32(SAVEMETA_MAGIC),
    1037            8 :                 .sh_format = cpu_to_be32(SAVEMETA_FORMAT),
    1038            8 :                 .sh_time = cpu_to_be64(time(NULL)),
    1039            8 :                 .sh_fs_bytes = cpu_to_be64(fsbytes)
    1040              :         };
    1041              : 
    1042            8 :         if (savemetawrite(mfd, (char *)(&smh), sizeof(smh)) != sizeof(smh))
    1043            0 :                 return -1;
    1044            8 :         return 0;
    1045              : }
    1046              : 
    1047            6 : static int parse_header(char *buf, struct savemeta *sm)
    1048              : {
    1049            6 :         struct savemeta_header *smh = (void *)buf;
    1050              : 
    1051            6 :         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            6 :         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            6 :         sm->sm_format = be32_to_cpu(smh->sh_format);
    1060            6 :         sm->sm_time = be64_to_cpu(smh->sh_time);
    1061            6 :         sm->sm_fs_bytes = be64_to_cpu(smh->sh_fs_bytes);
    1062            6 :         printf("Metadata saved at %s", ctime(&sm->sm_time)); /* ctime() adds \n */
    1063            6 :         printf("File system size %.2fGB\n", sm->sm_fs_bytes / ((float)(1 << 30)));
    1064            6 :         return 0;
    1065              : }
    1066              : 
    1067            8 : 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            8 :         int err = 0;
    1073              :         char *buf;
    1074              : 
    1075            8 :         sbd.md.journals = 1;
    1076              : 
    1077            8 :         mfd = savemetaopen(out_fn, gziplevel);
    1078              : 
    1079            8 :         blks_saved = 0;
    1080            8 :         printf("There are %"PRIu64" blocks of %u bytes in the filesystem.\n",
    1081              :                sbd.fssize, sbd.sd_bsize);
    1082              : 
    1083            8 :         printf("Filesystem size: %.2fGB\n", (sbd.fssize * sbd.sd_bsize) / ((float)(1 << 30)));
    1084            8 :         get_journal_inode_blocks();
    1085              : 
    1086            8 :         err = init_per_node_lookup();
    1087            8 :         if (err)
    1088            0 :                 exit(1);
    1089              : 
    1090              :         /* Write the savemeta file header */
    1091            8 :         err = save_header(&mfd, sbd.fssize * sbd.sd_bsize);
    1092            8 :         if (err) {
    1093            0 :                 perror("Failed to write metadata file header");
    1094            0 :                 exit(1);
    1095              :         }
    1096              :         /* Save off the superblock */
    1097            8 :         sb_addr = GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.sd_bsize;
    1098            8 :         buf = check_read_block(sbd.device_fd, sb_addr, 0, NULL, NULL);
    1099            8 :         if (buf != NULL) {
    1100            8 :                 save_buf(&mfd, buf, sb_addr, sizeof(struct gfs2_sb));
    1101            8 :                 free(buf);
    1102              :         }
    1103              :         /* Walk through the resource groups saving everything within */
    1104          582 :         for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
    1105              :                 struct lgfs2_rgrp_tree *rgd;
    1106              : 
    1107          574 :                 rgd = (struct lgfs2_rgrp_tree *)n;
    1108          574 :                 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            8 :         report_progress(sbd.fssize, 1);
    1114            8 :         printf("\nMetadata saved to file %s ", mfd.filename);
    1115            8 :         if (mfd.gziplevel) {
    1116            3 :                 printf("(gzipped, level %d).\n", mfd.gziplevel);
    1117              :         } else {
    1118            5 :                 printf("(uncompressed).\n");
    1119              :         }
    1120            8 :         savemetaclose(&mfd);
    1121            8 :         close(sbd.device_fd);
    1122            8 :         destroy_per_node_lookup();
    1123            8 :         free(indirect);
    1124            8 :         lgfs2_rgrp_free(&sbd, &sbd.rgtree);
    1125            8 :         exit(0);
    1126              : }
    1127              : 
    1128       230479 : static char *restore_block(struct metafd *mfd, uint64_t *blk, uint16_t *siglen)
    1129              : {
    1130              :         struct saved_metablock *svb;
    1131              :         const char *errstr;
    1132       230479 :         char *buf = NULL;
    1133              : 
    1134       230479 :         svb = (struct saved_metablock *)(restore_buf_next(mfd, sizeof(*svb)));
    1135       230479 :         if (svb == NULL)
    1136            6 :                 goto nobuffer;
    1137       230473 :         *blk = be64_to_cpu(svb->blk);
    1138       230473 :         *siglen = be16_to_cpu(svb->siglen);
    1139              : 
    1140       230473 :         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       230473 :         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       230473 :         buf = restore_buf_next(mfd, *siglen);
    1154       230473 :         if (buf != NULL) {
    1155       230473 :                 return buf;
    1156              :         }
    1157            0 : nobuffer:
    1158            6 :         if (mfd->eof)
    1159            6 :                 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            6 : static int restore_super(struct metafd *mfd, void *buf, int printonly)
    1167              : {
    1168              :         int ret;
    1169              : 
    1170            6 :         lgfs2_sb_in(&sbd, buf);
    1171            6 :         ret = lgfs2_check_sb(buf);
    1172            6 :         if (ret < 0) {
    1173            0 :                 fprintf(stderr, "Error: Invalid superblock in metadata file.\n");
    1174            0 :                 return -1;
    1175              :         }
    1176            6 :         if ((!printonly) && lgfs2_sb_write(&sbd, sbd.device_fd)) {
    1177            0 :                 fprintf(stderr, "Failed to write superblock\n");
    1178            0 :                 return -1;
    1179              :         }
    1180            6 :         blks_saved++;
    1181            6 :         return 0;
    1182              : }
    1183              : 
    1184            6 : static int restore_data(int fd, struct metafd *mfd, int printonly)
    1185              : {
    1186            6 :         uint64_t writes = 0;
    1187              :         char *buf;
    1188              : 
    1189            6 :         buf = calloc(1, sbd.sd_bsize);
    1190            6 :         if (buf == NULL) {
    1191            0 :                 perror("Failed to restore data");
    1192            0 :                 exit(1);
    1193              :         }
    1194              : 
    1195       230473 :         while (TRUE) {
    1196       230479 :                 uint16_t siglen = 0;
    1197       230479 :                 uint64_t blk = 0;
    1198              :                 char *bp;
    1199              : 
    1200       230479 :                 bp = restore_block(mfd, &blk, &siglen);
    1201       230479 :                 if (bp == NULL && mfd->eof)
    1202            6 :                         break;
    1203       230473 :                 if (bp == NULL) {
    1204            0 :                         free(buf);
    1205            0 :                         return -1;
    1206              :                 }
    1207       230473 :                 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       230473 :                         report_progress(blk, 0);
    1218       230473 :                         memcpy(buf, bp, siglen);
    1219       230473 :                         memset(buf + siglen, 0, sbd.sd_bsize - siglen);
    1220       230473 :                         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       230473 :                         writes++;
    1227       230473 :                         if (writes % 1000 == 0)
    1228          226 :                                 fsync(fd);
    1229              :                 }
    1230       230473 :                 blks_saved++;
    1231              :         }
    1232            6 :         if (!printonly)
    1233            6 :                 report_progress(sbd.fssize, 1);
    1234            6 :         free(buf);
    1235            6 :         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            6 : static int restore_init(const char *path, struct metafd *mfd, struct savemeta *sm, int printonly)
    1245              : {
    1246              :         struct gfs2_sb rsb;
    1247              :         uint16_t sb_siglen;
    1248              :         char *end;
    1249              :         char *bp;
    1250              :         int ret;
    1251              : 
    1252            6 :         blks_saved = 0;
    1253            6 :         restore_buf = malloc(RESTORE_BUF_SIZE);
    1254            6 :         if (restore_buf == NULL) {
    1255            0 :                 perror("Restore failed");
    1256            0 :                 return -1;
    1257              :         }
    1258            6 :         restore_off = 0;
    1259            6 :         restore_left = 0;
    1260              : 
    1261            6 :         mfd->filename = path;
    1262            6 :         mfd->fd = open(path, O_RDONLY|O_CLOEXEC);
    1263            6 :         if (mfd->fd < 0) {
    1264            0 :                 perror("Could not open metadata file");
    1265            0 :                 return 1;
    1266              :         }
    1267           12 :         if (restore_try_bzip(mfd) != 0 &&
    1268            6 :             restore_try_gzip(mfd) != 0) {
    1269            0 :                 fprintf(stderr, "Failed to read metadata file header and superblock\n");
    1270            0 :                 return -1;
    1271              :         }
    1272            6 :         bp = restore_buf;
    1273            6 :         ret = parse_header(bp, sm);
    1274            6 :         if (ret == 0) {
    1275            6 :                 bp = restore_buf + sizeof(struct savemeta_header);
    1276            6 :                 restore_off = sizeof(struct savemeta_header);
    1277            0 :         } else if (ret == -1) {
    1278            0 :                 return -1;
    1279              :         }
    1280              :         /* Scan for the position of the superblock. Required to support old formats(?). */
    1281            6 :         end = &restore_buf[256 + sizeof(struct saved_metablock) + sizeof(struct gfs2_meta_header)];
    1282            6 :         while (bp <= end) {
    1283            6 :                 memcpy(&rsb, bp + sizeof(struct saved_metablock), sizeof(rsb));
    1284            6 :                 sb_siglen = be16_to_cpu(((struct saved_metablock *)bp)->siglen);
    1285           12 :                 if (be32_to_cpu(rsb.sb_header.mh_magic) == GFS2_MAGIC &&
    1286            6 :                     be32_to_cpu(rsb.sb_header.mh_type) == GFS2_METATYPE_SB)
    1287            6 :                         break;
    1288            0 :                 bp++;
    1289              :         }
    1290            6 :         if (bp > end) {
    1291            0 :                 fprintf(stderr, "No superblock found in metadata file\n");
    1292            0 :                 return -1;
    1293              :         }
    1294            6 :         bp += sizeof(struct saved_metablock);
    1295            6 :         ret = restore_super(mfd, &rsb, printonly);
    1296            6 :         if (ret != 0)
    1297            0 :                 return ret;
    1298              : 
    1299            6 :         if (sm->sm_fs_bytes > 0) {
    1300            6 :                 sbd.fssize = sm->sm_fs_bytes / sbd.sd_bsize;
    1301            6 :                 printf("Saved file system size is %"PRIu64" blocks, %.2fGB\n",
    1302            6 :                        sbd.fssize, sm->sm_fs_bytes / ((float)(1 << 30)));
    1303              :         }
    1304            6 :         printf("Block size is %uB\n", sbd.sd_bsize);
    1305            6 :         printf("This is gfs2 metadata.\n");
    1306            6 :         if (printonly > 1 && printonly == LGFS2_SB_ADDR(&sbd)) {
    1307            0 :                 display_block_type(bp, LGFS2_SB_ADDR(&sbd), TRUE);
    1308            0 :                 display_gfs2(bp);
    1309            6 :         } else if (printonly == 1) {
    1310            0 :                 print_gfs2("0 (l=0x%x): ", sb_siglen);
    1311            0 :                 display_block_type(bp, LGFS2_SB_ADDR(&sbd), TRUE);
    1312              :         }
    1313            6 :         bp += sb_siglen;
    1314            6 :         restore_off = bp - restore_buf;
    1315            6 :         restore_left -= restore_off;
    1316            6 :         return 0;
    1317              : }
    1318              : 
    1319            6 : void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly)
    1320              : {
    1321            6 :         struct metafd mfd = {0};
    1322            6 :         struct savemeta sm = {0};
    1323              :         struct stat st;
    1324              :         int error;
    1325              : 
    1326            6 :         termlines = 0;
    1327            6 :         if (in_fn == NULL || in_fn[0] == '\0') {
    1328            0 :                 fprintf(stderr, "No source file specified.");
    1329            0 :                 restoremeta_usage();
    1330            0 :                 exit(1);
    1331              :         }
    1332            6 :         if (!printonly && (out_device == NULL || out_device[0] == '\0')) {
    1333            0 :                 fprintf(stderr, "No destination file system specified.");
    1334            0 :                 restoremeta_usage();
    1335            0 :                 exit(1);
    1336              :         }
    1337            6 :         if (!printonly) {
    1338            6 :                 sbd.device_fd = open(out_device, O_RDWR);
    1339            6 :                 if (sbd.device_fd < 0) {
    1340            0 :                         fprintf(stderr, "Failed to open target '%s': %s\n",
    1341            0 :                             out_device, strerror(errno));
    1342            0 :                         exit(1);
    1343              :                 }
    1344            0 :         } else if (out_device) /* for printsavedmeta, the out_device is an
    1345              :                                   optional block no */
    1346            0 :                 printonly = check_keywords(out_device);
    1347              : 
    1348            6 :         error = restore_init(in_fn, &mfd, &sm, printonly);
    1349            6 :         if (error != 0)
    1350            0 :                 exit(error);
    1351              : 
    1352            6 :         if (!printonly) {
    1353            6 :                 uint64_t space = lseek(sbd.device_fd, 0, SEEK_END) / sbd.sd_bsize;
    1354            6 :                 printf("There are %"PRIu64" free blocks on the destination device.\n", space);
    1355              :         }
    1356              : 
    1357            6 :         error = restore_data(sbd.device_fd, &mfd, printonly);
    1358              : 
    1359              :         /* When there is a metadata header available, truncate to filesystem 
    1360              :            size if our device_fd is a regular file */   
    1361            6 :         if (!printonly) {
    1362            6 :                 if (fstat(sbd.device_fd, &st) == -1) {
    1363            0 :                         fprintf(stderr, "Failed to stat %s: %s\n", out_device, strerror(errno));
    1364            0 :                         error = errno;
    1365              :                 }
    1366              :         
    1367            6 :                 if (sm.sm_fs_bytes > 0 && S_ISREG(st.st_mode)) {
    1368            6 :                         if (ftruncate(sbd.device_fd, sm.sm_fs_bytes) != 0) {
    1369            0 :                                 fprintf(stderr, "Failed to truncate: %s, %s\n", out_device, strerror(errno));
    1370            0 :                                 error = errno;
    1371              :                         }
    1372              :                 }
    1373              :         }
    1374              : 
    1375            6 :         printf("File %s %s %s.\n", in_fn,
    1376              :                (printonly ? "print" : "restore"),
    1377              :                (error ? "error" : "successful"));
    1378              : 
    1379            6 :         mfd.close(&mfd);
    1380            6 :         if (!printonly)
    1381            6 :                 close(sbd.device_fd);
    1382            6 :         free(indirect);
    1383            6 :         exit(error);
    1384              : }
        

Generated by: LCOV version 2.0-1