]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/metadump.c
xfsprogs: Release v6.8.0
[thirdparty/xfsprogs-dev.git] / db / metadump.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
61983f67 2/*
56281ed4 3 * Copyright (c) 2007, 2011 SGI
61983f67 4 * All Rights Reserved.
61983f67
BN
5 */
6
6b803e5a
CH
7#include "libxfs.h"
8#include "libxlog.h"
61983f67
BN
9#include "bmap.h"
10#include "command.h"
11#include "metadump.h"
12#include "io.h"
13#include "output.h"
14#include "type.h"
15#include "init.h"
16#include "sig.h"
17#include "xfs_metadump.h"
a2ceac1f
DC
18#include "fprint.h"
19#include "faddr.h"
20#include "field.h"
21#include "dir2.h"
2b686ab3 22#include "obfuscate.h"
61983f67 23
d3e0c71f 24#define DEFAULT_MAX_EXT_SIZE XFS_MAX_BMBT_EXTLEN
7431d134 25
61983f67
BN
26/* copy all metadata structures to/from a file */
27
28static int metadump_f(int argc, char **argv);
29static void metadump_help(void);
30
31/*
32 * metadump commands issue info/wornings/errors to standard error as
33 * metadump supports stdout as a destination.
34 *
35 * All static functions return zero on failure, while the public functions
36 * return zero on success.
37 */
38
39static const cmdinfo_t metadump_cmd =
40 { "metadump", NULL, metadump_f, 0, -1, 0,
0323bbf6 41 N_("[-a] [-e] [-g] [-m max_extent] [-w] [-o] [-v 1|2] filename"),
9ee7055c 42 N_("dump metadata to a file"), metadump_help };
61983f67 43
be75f7d7
CB
44struct metadump_ops {
45 /*
46 * Initialize Metadump. This may perform actions such as
47 * 1. Allocating memory for structures required for dumping the
48 * metadata.
49 * 2. Writing a header to the beginning of the metadump file.
50 */
51 int (*init)(void);
52 /*
53 * Write metadata to the metadump file along with the required ancillary
54 * data. @off and @len are in units of 512 byte blocks.
55 */
56 int (*write)(enum typnm type, const char *data, xfs_daddr_t off,
57 int len);
58 /*
59 * Flush any in-memory remanents of metadata to the metadump file.
60 */
61 int (*finish_dump)(void);
62 /*
63 * Free resources allocated during metadump process.
64 */
65 void (*release)(void);
66};
67
fb4697dd
CB
68static struct metadump {
69 int version;
70 bool show_progress;
71 bool stop_on_read_error;
72 int max_extent_size;
73 bool show_warnings;
74 bool obfuscate;
75 bool zero_stale_data;
76 bool progress_since_warning;
77 bool dirty_log;
0323bbf6 78 bool external_log;
fb4697dd
CB
79 bool stdout_metadump;
80 xfs_ino_t cur_ino;
81 /* Metadump file */
82 FILE *outf;
be75f7d7 83 struct metadump_ops *mdops;
fb4697dd
CB
84 /* header + index + buffers */
85 struct xfs_metablock *metablock;
86 __be64 *block_index;
87 char *block_buffer;
88 int num_indices;
89 int cur_index;
90} metadump;
61983f67
BN
91
92void
93metadump_init(void)
94{
95 add_command(&metadump_cmd);
96}
97
98static void
99metadump_help(void)
100{
9ee7055c 101 dbprintf(_(
61983f67
BN
102"\n"
103" The 'metadump' command dumps the known metadata to a compact file suitable\n"
104" for compressing and sending to an XFS maintainer for corruption analysis \n"
105" or xfs_repair failures.\n\n"
88b8e1d6 106" Options:\n"
b09e839e 107" -a -- Copy full metadata blocks without zeroing unused space\n"
61983f67
BN
108" -e -- Ignore read errors and keep going\n"
109" -g -- Display dump progress\n"
7431d134 110" -m -- Specify max extent size in blocks to copy (default = %d blocks)\n"
61983f67 111" -o -- Don't obfuscate names and extended attributes\n"
0323bbf6 112" -v -- Metadump version to be used\n"
61983f67 113" -w -- Show warnings of bad metadata information\n"
9ee7055c 114"\n"), DEFAULT_MAX_EXT_SIZE);
61983f67
BN
115}
116
117static void
118print_warning(const char *fmt, ...)
119{
120 char buf[200];
121 va_list ap;
122
123 if (seenint())
124 return;
125
126 va_start(ap, fmt);
127 vsnprintf(buf, sizeof(buf), fmt, ap);
128 va_end(ap);
129 buf[sizeof(buf)-1] = '\0';
130
fb4697dd
CB
131 fprintf(stderr, "%s%s: %s\n",
132 metadump.progress_since_warning ? "\n" : "",
61983f67 133 progname, buf);
fb4697dd 134 metadump.progress_since_warning = false;
61983f67
BN
135}
136
137static void
138print_progress(const char *fmt, ...)
139{
140 char buf[60];
141 va_list ap;
142 FILE *f;
143
144 if (seenint())
145 return;
146
147 va_start(ap, fmt);
148 vsnprintf(buf, sizeof(buf), fmt, ap);
149 va_end(ap);
150 buf[sizeof(buf)-1] = '\0';
151
fb4697dd 152 f = metadump.stdout_metadump ? stderr : stdout;
61983f67
BN
153 fprintf(f, "\r%-59s", buf);
154 fflush(f);
fb4697dd 155 metadump.progress_since_warning = true;
61983f67
BN
156}
157
fd491857
DC
158/*
159 * we want to preserve the state of the metadata in the dump - whether it is
160 * intact or corrupt, so even if the buffer has a verifier attached to it we
161 * don't want to run it prior to writing the buffer to the metadump image.
162 *
163 * The only reason for running the verifier is to recalculate the CRCs on a
164 * buffer that has been obfuscated. i.e. a buffer than metadump modified itself.
165 * In this case, we only run the verifier if the buffer was not corrupt to begin
166 * with so that we don't accidentally correct buffers with CRC or errors in them
167 * when we are obfuscating them.
168 */
61983f67
BN
169static int
170write_buf(
171 iocur_t *buf)
172{
fd491857 173 struct xfs_buf *bp = buf->bp;
61983f67 174 int i;
878afc65 175 int ret;
61983f67 176
8ab75c4d
DC
177 /*
178 * Run the write verifier to recalculate the buffer CRCs and check
fd491857
DC
179 * metadump didn't introduce a new corruption. Warn if the verifier
180 * failed, but still continue to dump it into the output file.
8ab75c4d 181 */
fd491857
DC
182 if (buf->need_crc && bp && bp->b_ops && !bp->b_error) {
183 bp->b_ops->verify_write(bp);
184 if (bp->b_error) {
185 print_warning(
a3fac935
ES
186 "obfuscation corrupted block at %s bno 0x%llx/0x%x",
187 bp->b_ops->name,
f1208396 188 (long long)xfs_buf_daddr(bp), BBTOB(bp->b_length));
8ab75c4d
DC
189 }
190 }
191
1516a5b5
DC
192 /* handle discontiguous buffers */
193 if (!buf->bbmap) {
1a5a88ec
CB
194 ret = metadump.mdops->write(buf->typ->typnm, buf->data, buf->bb,
195 buf->blen);
1516a5b5
DC
196 if (ret)
197 return ret;
198 } else {
199 int len = 0;
200 for (i = 0; i < buf->bbmap->nmaps; i++) {
1a5a88ec
CB
201 ret = metadump.mdops->write(buf->typ->typnm,
202 buf->data + BBTOB(len),
203 buf->bbmap->b[i].bm_bn,
204 buf->bbmap->b[i].bm_len);
878afc65
DC
205 if (ret)
206 return ret;
1516a5b5 207 len += buf->bbmap->b[i].bm_len;
61983f67
BN
208 }
209 }
878afc65 210 return seenint() ? -EINTR : 0;
61983f67
BN
211}
212
6058426f
DC
213/*
214 * We could be processing a corrupt block, so we can't trust any of
215 * the offsets or lengths to be within the buffer range. Hence check
216 * carefully!
217 */
20f35ef4
ES
218static void
219zero_btree_node(
220 struct xfs_btree_block *block,
221 typnm_t btype)
222{
223 int nrecs;
224 xfs_bmbt_ptr_t *bpp;
225 xfs_bmbt_key_t *bkp;
226 xfs_inobt_ptr_t *ipp;
227 xfs_inobt_key_t *ikp;
228 xfs_alloc_ptr_t *app;
229 xfs_alloc_key_t *akp;
a7302f83
DC
230 char *zp1, *zp2;
231 char *key_end;
e7fd2b6f 232 struct xfs_ino_geometry *igeo = M_IGEO(mp);
20f35ef4
ES
233
234 nrecs = be16_to_cpu(block->bb_numrecs);
6058426f
DC
235 if (nrecs < 0)
236 return;
20f35ef4
ES
237
238 switch (btype) {
239 case TYP_BMAPBTA:
240 case TYP_BMAPBTD:
6058426f
DC
241 if (nrecs > mp->m_bmap_dmxr[1])
242 return;
243
20f35ef4
ES
244 bkp = XFS_BMBT_KEY_ADDR(mp, block, 1);
245 bpp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
a7302f83
DC
246 zp1 = (char *)&bkp[nrecs];
247 zp2 = (char *)&bpp[nrecs];
248 key_end = (char *)bpp;
20f35ef4
ES
249 break;
250 case TYP_INOBT:
251 case TYP_FINOBT:
e7fd2b6f 252 if (nrecs > igeo->inobt_mxr[1])
6058426f
DC
253 return;
254
20f35ef4 255 ikp = XFS_INOBT_KEY_ADDR(mp, block, 1);
e7fd2b6f 256 ipp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
a7302f83
DC
257 zp1 = (char *)&ikp[nrecs];
258 zp2 = (char *)&ipp[nrecs];
259 key_end = (char *)ipp;
20f35ef4
ES
260 break;
261 case TYP_BNOBT:
262 case TYP_CNTBT:
6058426f
DC
263 if (nrecs > mp->m_alloc_mxr[1])
264 return;
265
20f35ef4
ES
266 akp = XFS_ALLOC_KEY_ADDR(mp, block, 1);
267 app = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
a7302f83
DC
268 zp1 = (char *)&akp[nrecs];
269 zp2 = (char *)&app[nrecs];
270 key_end = (char *)app;
20f35ef4
ES
271 break;
272 default:
a7302f83 273 return;
20f35ef4
ES
274 }
275
a7302f83
DC
276
277 /* Zero from end of keys to beginning of pointers */
278 memset(zp1, 0, key_end - zp1);
279
280 /* Zero from end of pointers to end of block */
281 memset(zp2, 0, (char *)block + mp->m_sb.sb_blocksize - zp2);
20f35ef4
ES
282}
283
6058426f
DC
284/*
285 * We could be processing a corrupt block, so we can't trust any of
286 * the offsets or lengths to be within the buffer range. Hence check
287 * carefully!
288 */
20f35ef4
ES
289static void
290zero_btree_leaf(
291 struct xfs_btree_block *block,
292 typnm_t btype)
293{
294 int nrecs;
295 struct xfs_bmbt_rec *brp;
296 struct xfs_inobt_rec *irp;
297 struct xfs_alloc_rec *arp;
a7302f83 298 char *zp;
20f35ef4
ES
299
300 nrecs = be16_to_cpu(block->bb_numrecs);
6058426f
DC
301 if (nrecs < 0)
302 return;
20f35ef4
ES
303
304 switch (btype) {
305 case TYP_BMAPBTA:
306 case TYP_BMAPBTD:
6058426f
DC
307 if (nrecs > mp->m_bmap_dmxr[0])
308 return;
309
20f35ef4 310 brp = XFS_BMBT_REC_ADDR(mp, block, 1);
a7302f83 311 zp = (char *)&brp[nrecs];
20f35ef4
ES
312 break;
313 case TYP_INOBT:
314 case TYP_FINOBT:
e7fd2b6f 315 if (nrecs > M_IGEO(mp)->inobt_mxr[0])
6058426f
DC
316 return;
317
20f35ef4 318 irp = XFS_INOBT_REC_ADDR(mp, block, 1);
a7302f83 319 zp = (char *)&irp[nrecs];
20f35ef4
ES
320 break;
321 case TYP_BNOBT:
322 case TYP_CNTBT:
6058426f
DC
323 if (nrecs > mp->m_alloc_mxr[0])
324 return;
325
20f35ef4 326 arp = XFS_ALLOC_REC_ADDR(mp, block, 1);
a7302f83 327 zp = (char *)&arp[nrecs];
20f35ef4
ES
328 break;
329 default:
a7302f83 330 return;
20f35ef4
ES
331 }
332
333 /* Zero from end of records to end of block */
a7302f83 334 memset(zp, 0, (char *)block + mp->m_sb.sb_blocksize - zp);
20f35ef4
ES
335}
336
337static void
338zero_btree_block(
339 struct xfs_btree_block *block,
340 typnm_t btype)
341{
342 int level;
343
344 level = be16_to_cpu(block->bb_level);
345
346 if (level > 0)
347 zero_btree_node(block, btype);
348 else
349 zero_btree_leaf(block, btype);
350}
61983f67
BN
351
352static int
353scan_btree(
354 xfs_agnumber_t agno,
355 xfs_agblock_t agbno,
356 int level,
357 typnm_t btype,
358 void *arg,
b194c7d8 359 int (*func)(struct xfs_btree_block *block,
61983f67
BN
360 xfs_agnumber_t agno,
361 xfs_agblock_t agbno,
362 int level,
363 typnm_t btype,
364 void *arg))
365{
d24c0a90
BN
366 int rval = 0;
367
61983f67
BN
368 push_cur();
369 set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb,
370 DB_RING_IGN, NULL);
371 if (iocur_top->data == NULL) {
372 print_warning("cannot read %s block %u/%u", typtab[btype].name,
373 agno, agbno);
fb4697dd 374 rval = !metadump.stop_on_read_error;
d24c0a90 375 goto pop_out;
61983f67 376 }
20f35ef4 377
fb4697dd 378 if (metadump.zero_stale_data) {
20f35ef4
ES
379 zero_btree_block(iocur_top->data, btype);
380 iocur_top->need_crc = 1;
381 }
382
878afc65 383 if (write_buf(iocur_top))
d24c0a90 384 goto pop_out;
61983f67
BN
385
386 if (!(*func)(iocur_top->data, agno, agbno, level - 1, btype, arg))
d24c0a90
BN
387 goto pop_out;
388 rval = 1;
389pop_out:
61983f67 390 pop_cur();
d24c0a90 391 return rval;
61983f67
BN
392}
393
394/* free space tree copy routines */
395
396static int
397valid_bno(
61983f67 398 xfs_agnumber_t agno,
88b8e1d6 399 xfs_agblock_t agbno)
61983f67 400{
88b8e1d6
BN
401 if (agno < (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
402 agbno <= mp->m_sb.sb_agblocks)
403 return 1;
404 if (agno == (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
405 agbno <= (mp->m_sb.sb_dblocks -
5a35bf2c 406 (xfs_rfsblock_t)(mp->m_sb.sb_agcount - 1) *
66be354e 407 mp->m_sb.sb_agblocks))
61983f67
BN
408 return 1;
409
61983f67
BN
410 return 0;
411}
412
88b8e1d6 413
61983f67
BN
414static int
415scanfunc_freesp(
b194c7d8 416 struct xfs_btree_block *block,
61983f67
BN
417 xfs_agnumber_t agno,
418 xfs_agblock_t agbno,
419 int level,
420 typnm_t btype,
421 void *arg)
422{
423 xfs_alloc_ptr_t *pp;
424 int i;
88b8e1d6 425 int numrecs;
61983f67
BN
426
427 if (level == 0)
428 return 1;
429
b194c7d8 430 numrecs = be16_to_cpu(block->bb_numrecs);
88b8e1d6 431 if (numrecs > mp->m_alloc_mxr[1]) {
fb4697dd 432 if (metadump.show_warnings)
88b8e1d6
BN
433 print_warning("invalid numrecs (%u) in %s block %u/%u",
434 numrecs, typtab[btype].name, agno, agbno);
61983f67
BN
435 return 1;
436 }
437
b3563c19 438 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
88b8e1d6
BN
439 for (i = 0; i < numrecs; i++) {
440 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 441 if (metadump.show_warnings)
88b8e1d6
BN
442 print_warning("invalid block number (%u/%u) "
443 "in %s block %u/%u",
444 agno, be32_to_cpu(pp[i]),
445 typtab[btype].name, agno, agbno);
61983f67 446 continue;
88b8e1d6 447 }
61983f67
BN
448 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
449 scanfunc_freesp))
450 return 0;
451 }
452 return 1;
453}
454
455static int
456copy_free_bno_btree(
457 xfs_agnumber_t agno,
458 xfs_agf_t *agf)
459{
460 xfs_agblock_t root;
461 int levels;
462
463 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
464 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
465
466 /* validate root and levels before processing the tree */
467 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 468 if (metadump.show_warnings)
61983f67
BN
469 print_warning("invalid block number (%u) in bnobt "
470 "root in agf %u", root, agno);
471 return 1;
472 }
716b497a 473 if (levels > mp->m_alloc_maxlevels) {
fb4697dd 474 if (metadump.show_warnings)
61983f67
BN
475 print_warning("invalid level (%u) in bnobt root "
476 "in agf %u", levels, agno);
477 return 1;
478 }
479
480 return scan_btree(agno, root, levels, TYP_BNOBT, agf, scanfunc_freesp);
481}
482
483static int
484copy_free_cnt_btree(
485 xfs_agnumber_t agno,
486 xfs_agf_t *agf)
487{
488 xfs_agblock_t root;
489 int levels;
490
491 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
492 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
493
494 /* validate root and levels before processing the tree */
495 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 496 if (metadump.show_warnings)
61983f67
BN
497 print_warning("invalid block number (%u) in cntbt "
498 "root in agf %u", root, agno);
499 return 1;
500 }
716b497a 501 if (levels > mp->m_alloc_maxlevels) {
fb4697dd 502 if (metadump.show_warnings)
61983f67
BN
503 print_warning("invalid level (%u) in cntbt root "
504 "in agf %u", levels, agno);
505 return 1;
506 }
507
508 return scan_btree(agno, root, levels, TYP_CNTBT, agf, scanfunc_freesp);
509}
510
e434854e
DW
511static int
512scanfunc_rmapbt(
513 struct xfs_btree_block *block,
514 xfs_agnumber_t agno,
515 xfs_agblock_t agbno,
516 int level,
517 typnm_t btype,
518 void *arg)
519{
520 xfs_rmap_ptr_t *pp;
521 int i;
522 int numrecs;
523
524 if (level == 0)
525 return 1;
526
527 numrecs = be16_to_cpu(block->bb_numrecs);
528 if (numrecs > mp->m_rmap_mxr[1]) {
fb4697dd 529 if (metadump.show_warnings)
e434854e
DW
530 print_warning("invalid numrecs (%u) in %s block %u/%u",
531 numrecs, typtab[btype].name, agno, agbno);
532 return 1;
533 }
534
535 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
536 for (i = 0; i < numrecs; i++) {
537 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 538 if (metadump.show_warnings)
e434854e
DW
539 print_warning("invalid block number (%u/%u) "
540 "in %s block %u/%u",
541 agno, be32_to_cpu(pp[i]),
542 typtab[btype].name, agno, agbno);
543 continue;
544 }
545 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
546 scanfunc_rmapbt))
547 return 0;
548 }
549 return 1;
550}
551
552static int
553copy_rmap_btree(
554 xfs_agnumber_t agno,
555 struct xfs_agf *agf)
556{
557 xfs_agblock_t root;
558 int levels;
559
2660e653 560 if (!xfs_has_rmapbt(mp))
e434854e
DW
561 return 1;
562
563 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
564 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
565
566 /* validate root and levels before processing the tree */
567 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 568 if (metadump.show_warnings)
e434854e
DW
569 print_warning("invalid block number (%u) in rmapbt "
570 "root in agf %u", root, agno);
571 return 1;
572 }
716b497a 573 if (levels > mp->m_rmap_maxlevels) {
fb4697dd 574 if (metadump.show_warnings)
e434854e
DW
575 print_warning("invalid level (%u) in rmapbt root "
576 "in agf %u", levels, agno);
577 return 1;
578 }
579
580 return scan_btree(agno, root, levels, TYP_RMAPBT, agf, scanfunc_rmapbt);
581}
582
e2756db3
DW
583static int
584scanfunc_refcntbt(
585 struct xfs_btree_block *block,
586 xfs_agnumber_t agno,
587 xfs_agblock_t agbno,
588 int level,
589 typnm_t btype,
590 void *arg)
591{
592 xfs_refcount_ptr_t *pp;
593 int i;
594 int numrecs;
595
596 if (level == 0)
597 return 1;
598
599 numrecs = be16_to_cpu(block->bb_numrecs);
600 if (numrecs > mp->m_refc_mxr[1]) {
fb4697dd 601 if (metadump.show_warnings)
e2756db3
DW
602 print_warning("invalid numrecs (%u) in %s block %u/%u",
603 numrecs, typtab[btype].name, agno, agbno);
604 return 1;
605 }
606
607 pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
608 for (i = 0; i < numrecs; i++) {
609 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 610 if (metadump.show_warnings)
e2756db3
DW
611 print_warning("invalid block number (%u/%u) "
612 "in %s block %u/%u",
613 agno, be32_to_cpu(pp[i]),
614 typtab[btype].name, agno, agbno);
615 continue;
616 }
617 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
618 scanfunc_refcntbt))
619 return 0;
620 }
621 return 1;
622}
623
624static int
625copy_refcount_btree(
626 xfs_agnumber_t agno,
627 struct xfs_agf *agf)
628{
629 xfs_agblock_t root;
630 int levels;
631
2660e653 632 if (!xfs_has_reflink(mp))
e2756db3
DW
633 return 1;
634
635 root = be32_to_cpu(agf->agf_refcount_root);
636 levels = be32_to_cpu(agf->agf_refcount_level);
637
638 /* validate root and levels before processing the tree */
639 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 640 if (metadump.show_warnings)
e2756db3
DW
641 print_warning("invalid block number (%u) in refcntbt "
642 "root in agf %u", root, agno);
643 return 1;
644 }
716b497a 645 if (levels > mp->m_refc_maxlevels) {
fb4697dd 646 if (metadump.show_warnings)
e2756db3
DW
647 print_warning("invalid level (%u) in refcntbt root "
648 "in agf %u", levels, agno);
649 return 1;
650 }
651
652 return scan_btree(agno, root, levels, TYP_REFCBT, agf, scanfunc_refcntbt);
653}
654
61983f67
BN
655/* filename and extended attribute obfuscation routines */
656
78027d48 657struct name_ent {
61983f67
BN
658 struct name_ent *next;
659 xfs_dahash_t hash;
78027d48 660 int namelen;
02211695 661 unsigned char name[1];
78027d48 662};
61983f67
BN
663
664#define NAME_TABLE_SIZE 4096
665
a85f8b0a 666static struct name_ent *nametable[NAME_TABLE_SIZE];
61983f67
BN
667
668static void
a85f8b0a 669nametable_clear(void)
61983f67 670{
a85f8b0a 671 int i;
78027d48 672 struct name_ent *ent;
61983f67
BN
673
674 for (i = 0; i < NAME_TABLE_SIZE; i++) {
a85f8b0a
AE
675 while ((ent = nametable[i])) {
676 nametable[i] = ent->next;
677 free(ent);
61983f67
BN
678 }
679 }
680}
681
a85f8b0a
AE
682/*
683 * See if the given name is already in the name table. If so,
684 * return a pointer to its entry, otherwise return a null pointer.
685 */
686static struct name_ent *
02211695 687nametable_find(xfs_dahash_t hash, int namelen, unsigned char *name)
a85f8b0a
AE
688{
689 struct name_ent *ent;
690
691 for (ent = nametable[hash % NAME_TABLE_SIZE]; ent; ent = ent->next) {
692 if (ent->hash == hash && ent->namelen == namelen &&
693 !memcmp(ent->name, name, namelen))
694 return ent;
695 }
696 return NULL;
697}
698
699/*
700 * Add the given name to the name table. Returns a pointer to the
701 * name's new entry, or a null pointer if an error occurs.
702 */
703static struct name_ent *
02211695 704nametable_add(xfs_dahash_t hash, int namelen, unsigned char *name)
a85f8b0a
AE
705{
706 struct name_ent *ent;
707
708 ent = malloc(sizeof *ent + namelen);
709 if (!ent)
710 return NULL;
711
712 ent->namelen = namelen;
713 memcpy(ent->name, name, namelen);
714 ent->hash = hash;
715 ent->next = nametable[hash % NAME_TABLE_SIZE];
716
717 nametable[hash % NAME_TABLE_SIZE] = ent;
718
719 return ent;
720}
61983f67 721
56281ed4
AE
722#define ORPHANAGE "lost+found"
723#define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1)
724
725static inline int
726is_orphanage_dir(
727 struct xfs_mount *mp,
728 xfs_ino_t dir_ino,
729 size_t name_len,
02211695 730 unsigned char *name)
56281ed4
AE
731{
732 return dir_ino == mp->m_sb.sb_rootino &&
733 name_len == ORPHANAGE_LEN &&
734 !memcmp(name, ORPHANAGE, ORPHANAGE_LEN);
735}
736
737/*
738 * Determine whether a name is one we shouldn't obfuscate because
739 * it's an orphan (or the "lost+found" directory itself). Note
740 * "cur_ino" is the inode for the directory currently being
741 * processed.
742 *
743 * Returns 1 if the name should NOT be obfuscated or 0 otherwise.
744 */
61983f67 745static int
56281ed4 746in_lost_found(
61983f67
BN
747 xfs_ino_t ino,
748 int namelen,
02211695 749 unsigned char *name)
61983f67
BN
750{
751 static xfs_ino_t orphanage_ino = 0;
56281ed4 752 char s[24]; /* 21 is enough (64 bits in decimal) */
61983f67
BN
753 int slen;
754
56281ed4
AE
755 /* Record the "lost+found" inode if we haven't done so already */
756
757 ASSERT(ino != 0);
fb4697dd
CB
758 if (!orphanage_ino && is_orphanage_dir(mp, metadump.cur_ino, namelen,
759 name))
56281ed4
AE
760 orphanage_ino = ino;
761
762 /* We don't obfuscate the "lost+found" directory itself */
763
764 if (ino == orphanage_ino)
61983f67
BN
765 return 1;
766
56281ed4
AE
767 /* Most files aren't in "lost+found" at all */
768
fb4697dd 769 if (metadump.cur_ino != orphanage_ino)
61983f67
BN
770 return 0;
771
772 /*
56281ed4
AE
773 * Within "lost+found", we don't obfuscate any file whose
774 * name is the same as its inode number. Any others are
775 * stray files and can be obfuscated.
61983f67 776 */
56281ed4 777 slen = snprintf(s, sizeof (s), "%llu", (unsigned long long) ino);
61983f67 778
56281ed4 779 return slen == namelen && !memcmp(name, s, namelen);
61983f67
BN
780}
781
fcb63670
AE
782/*
783 * Look up the given name in the name table. If it is already
1167ddc4
AE
784 * present, iterate through a well-defined sequence of alternate
785 * names and attempt to use an alternate name instead.
fcb63670
AE
786 *
787 * Returns 1 if the (possibly modified) name is not present in the
1167ddc4
AE
788 * name table. Returns 0 if the name and all possible alternates
789 * are already in the table.
fcb63670
AE
790 */
791static int
02211695 792handle_duplicate_name(xfs_dahash_t hash, size_t name_len, unsigned char *name)
fcb63670 793{
02211695 794 unsigned char new_name[name_len + 1];
1167ddc4 795 uint32_t seq = 1;
fcb63670
AE
796
797 if (!nametable_find(hash, name_len, name))
1167ddc4 798 return 1; /* No duplicate */
fcb63670
AE
799
800 /* Name is already in use. Need to find an alternate. */
801
802 do {
1167ddc4 803 int found;
fcb63670 804
1167ddc4
AE
805 /* Only change incoming name if we find an alternate */
806 do {
807 memcpy(new_name, name, name_len);
808 found = find_alternate(name_len, new_name, seq++);
809 if (found < 0)
810 return 0; /* No more to check */
811 } while (!found);
812 } while (nametable_find(hash, name_len, new_name));
fcb63670 813
1167ddc4
AE
814 /*
815 * The alternate wasn't in the table already. Pass it back
816 * to the caller.
817 */
818 memcpy(name, new_name, name_len);
819
820 return 1;
fcb63670
AE
821}
822
10a01bcd
DW
823static inline xfs_dahash_t
824dirattr_hashname(
825 bool is_dirent,
826 const uint8_t *name,
827 int namelen)
828{
829 if (is_dirent) {
830 struct xfs_name xname = {
831 .name = name,
832 .len = namelen,
833 };
834
835 return libxfs_dir2_hashname(mp, &xname);
836 }
837
838 return libxfs_da_hashname(name, namelen);
839}
840
da7daaf2
AE
841static void
842generate_obfuscated_name(
843 xfs_ino_t ino,
844 int namelen,
02211695 845 unsigned char *name)
da7daaf2
AE
846{
847 xfs_dahash_t hash;
da7daaf2 848
56281ed4
AE
849 /*
850 * We don't obfuscate "lost+found" or any orphan files
851 * therein. When the name table is used for extended
852 * attributes, the inode number provided is 0, in which
853 * case we don't need to make this check.
854 */
855 if (ino && in_lost_found(ino, namelen, name))
856 return;
61983f67 857
ad6bb839 858 /*
fcb63670
AE
859 * If the name starts with a slash, just skip over it. It
860 * isn't included in the hash and we don't record it in the
861 * name table. Note that the namelen value passed in does
862 * not count the leading slash (if one is present).
ad6bb839
AE
863 */
864 if (*name == '/')
865 name++;
61983f67 866
fcb63670 867 /* Obfuscate the name (if possible) */
61983f67 868
10a01bcd
DW
869 hash = dirattr_hashname(ino != 0, name, namelen);
870 obfuscate_name(hash, namelen, name, ino != 0);
871 ASSERT(hash == dirattr_hashname(ino != 0, name, namelen));
88b1fe2a
AE
872
873 /*
fcb63670
AE
874 * Make sure the name is not something already seen. If we
875 * fail to find a suitable alternate, we're dealing with a
876 * very pathological situation, and we may end up creating
877 * a duplicate name in the metadump, so issue a warning.
88b1fe2a 878 */
fcb63670 879 if (!handle_duplicate_name(hash, namelen, name)) {
88b1fe2a
AE
880 print_warning("duplicate name for inode %llu "
881 "in dir inode %llu\n",
882 (unsigned long long) ino,
fb4697dd 883 (unsigned long long) metadump.cur_ino);
fcb63670
AE
884 return;
885 }
886
887 /* Create an entry for the new name in the name table. */
61983f67 888
a85f8b0a
AE
889 if (!nametable_add(hash, namelen, name))
890 print_warning("unable to record name for inode %llu "
891 "in dir inode %llu\n",
892 (unsigned long long) ino,
fb4697dd 893 (unsigned long long) metadump.cur_ino);
61983f67
BN
894}
895
896static void
87c955c3 897process_sf_dir(
7328ea6e 898 struct xfs_dinode *dip)
61983f67 899{
eb0cb950 900 struct xfs_dir2_sf_hdr *sfp;
61983f67 901 xfs_dir2_sf_entry_t *sfep;
14f8b681 902 uint64_t ino_dir_size;
61983f67
BN
903 int i;
904
eb0cb950 905 sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
56b2de80 906 ino_dir_size = be64_to_cpu(dip->di_size);
61983f67
BN
907 if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) {
908 ino_dir_size = XFS_DFORK_DSIZE(dip, mp);
fb4697dd 909 if (metadump.show_warnings)
88b8e1d6 910 print_warning("invalid size in dir inode %llu",
fb4697dd 911 (long long)metadump.cur_ino);
61983f67
BN
912 }
913
eb0cb950
DC
914 sfep = xfs_dir2_sf_firstentry(sfp);
915 for (i = 0; (i < sfp->count) &&
61983f67
BN
916 ((char *)sfep - (char *)sfp < ino_dir_size); i++) {
917
918 /*
919 * first check for bad name lengths. If they are bad, we
920 * have limitations to how much can be obfuscated.
921 */
922 int namelen = sfep->namelen;
923
924 if (namelen == 0) {
fb4697dd 925 if (metadump.show_warnings)
61983f67 926 print_warning("zero length entry in dir inode "
fb4697dd 927 "%llu", (long long)metadump.cur_ino);
eb0cb950 928 if (i != sfp->count - 1)
61983f67
BN
929 break;
930 namelen = ino_dir_size - ((char *)&sfep->name[0] -
931 (char *)sfp);
932 } else if ((char *)sfep - (char *)sfp +
660836c9 933 libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen) >
61983f67 934 ino_dir_size) {
fb4697dd 935 if (metadump.show_warnings)
61983f67 936 print_warning("entry length in dir inode %llu "
fb4697dd
CB
937 "overflows space",
938 (long long)metadump.cur_ino);
eb0cb950 939 if (i != sfp->count - 1)
61983f67
BN
940 break;
941 namelen = ino_dir_size - ((char *)&sfep->name[0] -
942 (char *)sfp);
943 }
944
fb4697dd 945 if (metadump.obfuscate)
87c955c3 946 generate_obfuscated_name(
e96bd2d3 947 libxfs_dir2_sf_get_ino(mp, sfp, sfep),
a2ceac1f 948 namelen, &sfep->name[0]);
61983f67
BN
949
950 sfep = (xfs_dir2_sf_entry_t *)((char *)sfep +
660836c9 951 libxfs_dir2_sf_entsize(mp, sfp, namelen));
61983f67 952 }
87c955c3
ES
953
954 /* zero stale data in rest of space in data fork, if any */
fb4697dd
CB
955 if (metadump.zero_stale_data &&
956 (ino_dir_size < XFS_DFORK_DSIZE(dip, mp)))
87c955c3 957 memset(sfep, 0, XFS_DFORK_DSIZE(dip, mp) - ino_dir_size);
61983f67
BN
958}
959
f63c7540
DC
960/*
961 * The pathname may not be null terminated. It may be terminated by the end of
962 * a buffer or inode literal area, and the start of the next region contains
963 * unknown data. Therefore, when we get to the last component of the symlink, we
964 * cannot assume that strlen() will give us the right result. Hence we need to
965 * track the remaining pathname length and use that instead.
966 */
b249a9f0
ES
967static void
968obfuscate_path_components(
969 char *buf,
14f8b681 970 uint64_t len)
b249a9f0 971{
02211695
CH
972 unsigned char *comp = (unsigned char *)buf;
973 unsigned char *end = comp + len;
b249a9f0
ES
974 xfs_dahash_t hash;
975
f63c7540 976 while (comp < end) {
b249a9f0
ES
977 char *slash;
978 int namelen;
979
980 /* find slash at end of this component */
981 slash = strchr((char *)comp, '/');
982 if (!slash) {
983 /* last (or single) component */
f63c7540 984 namelen = strnlen((char *)comp, len);
b249a9f0 985 hash = libxfs_da_hashname(comp, namelen);
10a01bcd 986 obfuscate_name(hash, namelen, comp, false);
cb8c70b0 987 ASSERT(hash == libxfs_da_hashname(comp, namelen));
b249a9f0
ES
988 break;
989 }
990 namelen = slash - (char *)comp;
991 /* handle leading or consecutive slashes */
992 if (!namelen) {
993 comp++;
f63c7540 994 len--;
b249a9f0
ES
995 continue;
996 }
997 hash = libxfs_da_hashname(comp, namelen);
10a01bcd 998 obfuscate_name(hash, namelen, comp, false);
cb8c70b0 999 ASSERT(hash == libxfs_da_hashname(comp, namelen));
b249a9f0 1000 comp += namelen + 1;
f63c7540 1001 len -= namelen + 1;
b249a9f0
ES
1002 }
1003}
1004
61983f67 1005static void
87c955c3 1006process_sf_symlink(
7328ea6e 1007 struct xfs_dinode *dip)
61983f67 1008{
14f8b681 1009 uint64_t len;
56b2de80 1010 char *buf;
88b8e1d6 1011
56b2de80 1012 len = be64_to_cpu(dip->di_size);
88b8e1d6 1013 if (len > XFS_DFORK_DSIZE(dip, mp)) {
fb4697dd 1014 if (metadump.show_warnings)
88b8e1d6 1015 print_warning("invalid size (%d) in symlink inode %llu",
fb4697dd 1016 len, (long long)metadump.cur_ino);
88b8e1d6
BN
1017 len = XFS_DFORK_DSIZE(dip, mp);
1018 }
61983f67 1019
56b2de80 1020 buf = (char *)XFS_DFORK_DPTR(dip);
fb4697dd 1021 if (metadump.obfuscate)
87c955c3
ES
1022 obfuscate_path_components(buf, len);
1023
1024 /* zero stale data in rest of space in data fork, if any */
fb4697dd 1025 if (metadump.zero_stale_data && len < XFS_DFORK_DSIZE(dip, mp))
87c955c3 1026 memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len);
61983f67
BN
1027}
1028
1029static void
87c955c3 1030process_sf_attr(
7328ea6e 1031 struct xfs_dinode *dip)
61983f67
BN
1032{
1033 /*
1941482c
ES
1034 * with extended attributes, obfuscate the names and fill the actual
1035 * values with 'v' (to see a valid string length, as opposed to NULLs)
61983f67
BN
1036 */
1037
5e2372c4
CH
1038 struct xfs_attr_sf_hdr *hdr = XFS_DFORK_APTR(dip);
1039 struct xfs_attr_sf_entry *asfep = libxfs_attr_sf_firstentry(hdr);
cc3650f7
CM
1040 int ino_attr_size;
1041 int i;
61983f67 1042
5e2372c4 1043 if (hdr->count == 0)
61983f67
BN
1044 return;
1045
5e2372c4 1046 ino_attr_size = be16_to_cpu(hdr->totsize);
61983f67
BN
1047 if (ino_attr_size > XFS_DFORK_ASIZE(dip, mp)) {
1048 ino_attr_size = XFS_DFORK_ASIZE(dip, mp);
fb4697dd 1049 if (metadump.show_warnings)
61983f67 1050 print_warning("invalid attr size in inode %llu",
fb4697dd 1051 (long long)metadump.cur_ino);
61983f67
BN
1052 }
1053
5e2372c4
CH
1054 for (i = 0; (i < hdr->count) &&
1055 ((char *)asfep - (char *)hdr < ino_attr_size); i++) {
61983f67
BN
1056
1057 int namelen = asfep->namelen;
1058
1059 if (namelen == 0) {
fb4697dd 1060 if (metadump.show_warnings)
61983f67 1061 print_warning("zero length attr entry in inode "
fb4697dd 1062 "%llu", (long long)metadump.cur_ino);
61983f67 1063 break;
5e2372c4 1064 } else if ((char *)asfep - (char *)hdr +
24b24fad 1065 xfs_attr_sf_entsize(asfep) > ino_attr_size) {
fb4697dd 1066 if (metadump.show_warnings)
61983f67 1067 print_warning("attr entry length in inode %llu "
fb4697dd
CB
1068 "overflows space",
1069 (long long)metadump.cur_ino);
61983f67
BN
1070 break;
1071 }
1072
fb4697dd 1073 if (metadump.obfuscate) {
87c955c3
ES
1074 generate_obfuscated_name(0, asfep->namelen,
1075 &asfep->nameval[0]);
1076 memset(&asfep->nameval[asfep->namelen], 'v',
1077 asfep->valuelen);
1078 }
61983f67 1079
cc3650f7 1080 asfep = (struct xfs_attr_sf_entry *)((char *)asfep +
24b24fad 1081 xfs_attr_sf_entsize(asfep));
61983f67 1082 }
87c955c3
ES
1083
1084 /* zero stale data in rest of space in attr fork, if any */
fb4697dd
CB
1085 if (metadump.zero_stale_data &&
1086 (ino_attr_size < XFS_DFORK_ASIZE(dip, mp)))
87c955c3 1087 memset(asfep, 0, XFS_DFORK_ASIZE(dip, mp) - ino_attr_size);
61983f67
BN
1088}
1089
c3387ef7
SR
1090static void
1091process_dir_free_block(
1092 char *block)
1093{
1094 struct xfs_dir2_free *free;
1095 struct xfs_dir3_icfree_hdr freehdr;
1096
fb4697dd 1097 if (!metadump.zero_stale_data)
c3387ef7
SR
1098 return;
1099
1100 free = (struct xfs_dir2_free *)block;
61e2142e 1101 libxfs_dir2_free_hdr_from_disk(mp, &freehdr, free);
c3387ef7
SR
1102
1103 switch (freehdr.magic) {
1104 case XFS_DIR2_FREE_MAGIC:
1105 case XFS_DIR3_FREE_MAGIC: {
1106 __be16 *bests;
1107 char *high;
1108 int used;
1109
1110 /* Zero out space from end of bests[] to end of block */
cb5d1930 1111 bests = freehdr.bests;
c3387ef7
SR
1112 high = (char *)&bests[freehdr.nvalid];
1113 used = high - (char*)free;
1114 memset(high, 0, mp->m_dir_geo->blksize - used);
1115 iocur_top->need_crc = 1;
1116 break;
1117 }
1118 default:
fb4697dd 1119 if (metadump.show_warnings)
c3387ef7
SR
1120 print_warning("invalid magic in dir inode %llu "
1121 "free block",
fb4697dd 1122 (unsigned long long)metadump.cur_ino);
c3387ef7
SR
1123 break;
1124 }
1125}
1126
a56173b5
ES
1127static void
1128process_dir_leaf_block(
1129 char *block)
1130{
1131 struct xfs_dir2_leaf *leaf;
11f3d9ff 1132 struct xfs_dir3_icleaf_hdr leafhdr;
a56173b5 1133
fb4697dd 1134 if (!metadump.zero_stale_data)
a56173b5
ES
1135 return;
1136
1137 /* Yes, this works for dir2 & dir3. Difference is padding. */
1138 leaf = (struct xfs_dir2_leaf *)block;
9db68faf 1139 libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
a56173b5 1140
11f3d9ff
SR
1141 switch (leafhdr.magic) {
1142 case XFS_DIR2_LEAF1_MAGIC:
1143 case XFS_DIR3_LEAF1_MAGIC: {
a56173b5
ES
1144 struct xfs_dir2_leaf_tail *ltp;
1145 __be16 *lbp;
a56173b5
ES
1146 char *free; /* end of ents */
1147
11f3d9ff 1148 /* Zero out space from end of ents[] to bests */
a2279497 1149 free = (char *)&leafhdr.ents[leafhdr.count];
a56173b5
ES
1150 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
1151 lbp = xfs_dir2_leaf_bests_p(ltp);
1152 memset(free, 0, (char *)lbp - free);
1153 iocur_top->need_crc = 1;
11f3d9ff
SR
1154 break;
1155 }
1156 case XFS_DIR2_LEAFN_MAGIC:
1157 case XFS_DIR3_LEAFN_MAGIC: {
11f3d9ff
SR
1158 char *free;
1159 int used;
1160
1161 /* Zero out space from end of ents[] to end of block */
a2279497 1162 free = (char *)&leafhdr.ents[leafhdr.count];
11f3d9ff
SR
1163 used = free - (char*)leaf;
1164 memset(free, 0, mp->m_dir_geo->blksize - used);
1165 iocur_top->need_crc = 1;
1166 break;
1167 }
1168 default:
1169 break;
a56173b5
ES
1170 }
1171}
1172
61983f67 1173static void
6d34e8b3 1174process_dir_data_block(
6e79202b 1175 char *block,
5a35bf2c 1176 xfs_fileoff_t offset,
6e79202b 1177 int is_block_format)
61983f67
BN
1178{
1179 /*
1180 * we have to rely on the fileoffset and signature of the block to
1181 * handle it's contents. If it's invalid, leave it alone.
1182 * for multi-fsblock dir blocks, if a name crosses an extent boundary,
1183 * ignore it and continue.
1184 */
6e79202b
DC
1185 int dir_offset;
1186 char *ptr;
1187 char *endptr;
1188 int end_of_data;
1189 int wantmagic;
1190 struct xfs_dir2_data_hdr *datahdr;
1191
1192 datahdr = (struct xfs_dir2_data_hdr *)block;
1193
6e79202b
DC
1194 if (is_block_format) {
1195 xfs_dir2_leaf_entry_t *blp;
1196 xfs_dir2_block_tail_t *btp;
1197
ff105f75 1198 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, datahdr);
6e79202b
DC
1199 blp = xfs_dir2_block_leaf_p(btp);
1200 if ((char *)blp > (char *)btp)
1201 blp = (xfs_dir2_leaf_entry_t *)btp;
1202
1203 end_of_data = (char *)blp - block;
2660e653 1204 if (xfs_has_crc(mp))
6e79202b
DC
1205 wantmagic = XFS_DIR3_BLOCK_MAGIC;
1206 else
1207 wantmagic = XFS_DIR2_BLOCK_MAGIC;
1208 } else { /* leaf/node format */
ff105f75 1209 end_of_data = mp->m_dir_geo->fsbcount << mp->m_sb.sb_blocklog;
2660e653 1210 if (xfs_has_crc(mp))
6e79202b
DC
1211 wantmagic = XFS_DIR3_DATA_MAGIC;
1212 else
1213 wantmagic = XFS_DIR2_DATA_MAGIC;
1214 }
61983f67 1215
6e79202b 1216 if (be32_to_cpu(datahdr->magic) != wantmagic) {
fb4697dd 1217 if (metadump.show_warnings)
6e79202b
DC
1218 print_warning(
1219 "invalid magic in dir inode %llu block %ld",
fb4697dd 1220 (unsigned long long)metadump.cur_ino, (long)offset);
6e79202b
DC
1221 return;
1222 }
61983f67 1223
58a1d356 1224 dir_offset = mp->m_dir_geo->data_entry_offset;
6e79202b 1225 ptr = block + dir_offset;
ff105f75 1226 endptr = block + mp->m_dir_geo->blksize;
61983f67 1227
6e79202b
DC
1228 while (ptr < endptr && dir_offset < end_of_data) {
1229 xfs_dir2_data_entry_t *dep;
1230 xfs_dir2_data_unused_t *dup;
1231 int length;
61983f67 1232
6e79202b 1233 dup = (xfs_dir2_data_unused_t *)ptr;
61983f67 1234
6e79202b 1235 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
8ab6f7e0
ES
1236 int free_length = be16_to_cpu(dup->length);
1237 if (dir_offset + free_length > end_of_data ||
1238 !free_length ||
1239 (free_length & (XFS_DIR2_DATA_ALIGN - 1))) {
fb4697dd 1240 if (metadump.show_warnings)
6e79202b
DC
1241 print_warning(
1242 "invalid length for dir free space in inode %llu",
fb4697dd 1243 (long long)metadump.cur_ino);
6e79202b 1244 return;
61983f67 1245 }
6e79202b
DC
1246 if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
1247 dir_offset)
1248 return;
8ab6f7e0
ES
1249 dir_offset += free_length;
1250 ptr += free_length;
6d34e8b3
ES
1251 /*
1252 * Zero the unused space up to the tag - the tag is
1253 * actually at a variable offset, so zeroing &dup->tag
1254 * is zeroing the free space in between
1255 */
fb4697dd 1256 if (metadump.zero_stale_data) {
8ab6f7e0 1257 int zlen = free_length -
6d34e8b3
ES
1258 sizeof(xfs_dir2_data_unused_t);
1259
1260 if (zlen > 0) {
1261 memset(&dup->tag, 0, zlen);
1262 iocur_top->need_crc = 1;
1263 }
1264 }
6e79202b
DC
1265 if (dir_offset >= end_of_data || ptr >= endptr)
1266 return;
1267 }
1268
1269 dep = (xfs_dir2_data_entry_t *)ptr;
271a654f 1270 length = libxfs_dir2_data_entsize(mp, dep->namelen);
6e79202b
DC
1271
1272 if (dir_offset + length > end_of_data ||
1273 ptr + length > endptr) {
fb4697dd 1274 if (metadump.show_warnings)
6e79202b
DC
1275 print_warning(
1276 "invalid length for dir entry name in inode %llu",
fb4697dd 1277 (long long)metadump.cur_ino);
6e79202b 1278 return;
61983f67 1279 }
823711f2 1280 if (be16_to_cpu(*libxfs_dir2_data_entry_tag_p(mp, dep)) !=
6e79202b
DC
1281 dir_offset)
1282 return;
6d34e8b3 1283
fb4697dd 1284 if (metadump.obfuscate)
6d34e8b3 1285 generate_obfuscated_name(be64_to_cpu(dep->inumber),
6e79202b
DC
1286 dep->namelen, &dep->name[0]);
1287 dir_offset += length;
1288 ptr += length;
6d34e8b3 1289 /* Zero the unused space after name, up to the tag */
fb4697dd 1290 if (metadump.zero_stale_data) {
6d34e8b3
ES
1291 /* 1 byte for ftype; don't bother with conditional */
1292 int zlen =
823711f2 1293 (char *)libxfs_dir2_data_entry_tag_p(mp, dep) -
6d34e8b3
ES
1294 (char *)&dep->name[dep->namelen] - 1;
1295 if (zlen > 0) {
1296 memset(&dep->name[dep->namelen] + 1, 0, zlen);
1297 iocur_top->need_crc = 1;
1298 }
1299 }
61983f67
BN
1300 }
1301}
1302
0e81250e 1303static int
23b2ae23 1304process_symlink_block(
0e81250e
DW
1305 xfs_fileoff_t o,
1306 xfs_fsblock_t s,
1307 xfs_filblks_t c,
1308 typnm_t btype,
1309 xfs_fileoff_t last)
61983f67 1310{
0e81250e
DW
1311 struct bbmap map;
1312 char *link;
a196ca65 1313 int rval = 1;
0e81250e
DW
1314
1315 push_cur();
1316 map.nmaps = 1;
1317 map.b[0].bm_bn = XFS_FSB_TO_DADDR(mp, s);
1318 map.b[0].bm_len = XFS_FSB_TO_BB(mp, c);
1319 set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &map);
1320 if (!iocur_top->data) {
1321 xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s);
1322 xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s);
1323
1324 print_warning("cannot read %s block %u/%u (%llu)",
1325 typtab[btype].name, agno, agbno, s);
fb4697dd 1326 rval = !metadump.stop_on_read_error;
0e81250e
DW
1327 goto out_pop;
1328 }
1329 link = iocur_top->data;
23b2ae23 1330
2660e653 1331 if (xfs_has_crc((mp)))
23b2ae23
ES
1332 link += sizeof(struct xfs_dsymlink_hdr);
1333
fb4697dd 1334 if (metadump.obfuscate)
23b2ae23
ES
1335 obfuscate_path_components(link, XFS_SYMLINK_BUF_SPACE(mp,
1336 mp->m_sb.sb_blocksize));
fb4697dd 1337 if (metadump.zero_stale_data) {
23b2ae23 1338 size_t linklen, zlen;
80917c1a 1339
23b2ae23
ES
1340 linklen = strlen(link);
1341 zlen = mp->m_sb.sb_blocksize - linklen;
2660e653 1342 if (xfs_has_crc(mp))
23b2ae23
ES
1343 zlen -= sizeof(struct xfs_dsymlink_hdr);
1344 if (zlen < mp->m_sb.sb_blocksize)
1345 memset(link + linklen, 0, zlen);
1346 }
0e81250e
DW
1347
1348 iocur_top->need_crc = 1;
a196ca65
DC
1349 if (write_buf(iocur_top))
1350 rval = 0;
0e81250e
DW
1351out_pop:
1352 pop_cur();
a196ca65 1353 return rval;
61983f67
BN
1354}
1355
1356#define MAX_REMOTE_VALS 4095
1357
1358static struct attr_data_s {
1359 int remote_val_count;
1360 xfs_dablk_t remote_vals[MAX_REMOTE_VALS];
1361} attr_data;
1362
1363static inline void
1364add_remote_vals(
1365 xfs_dablk_t blockidx,
1366 int length)
1367{
1368 while (length > 0 && attr_data.remote_val_count < MAX_REMOTE_VALS) {
1369 attr_data.remote_vals[attr_data.remote_val_count] = blockidx;
1370 attr_data.remote_val_count++;
1371 blockidx++;
e66eae01 1372 length -= XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
61983f67 1373 }
ed737480
DC
1374
1375 if (attr_data.remote_val_count >= MAX_REMOTE_VALS) {
1376 print_warning(
1377"Overflowed attr obfuscation array. No longer obfuscating remote attrs.");
1378 }
61983f67
BN
1379}
1380
80853366 1381/* Handle remote and leaf attributes */
61983f67 1382static void
70099c89 1383process_attr_block(
80853366
ES
1384 char *block,
1385 xfs_fileoff_t offset)
61983f67 1386{
80853366
ES
1387 struct xfs_attr_leafblock *leaf;
1388 struct xfs_attr3_icleaf_hdr hdr;
1389 int i;
1390 int nentries;
1391 xfs_attr_leaf_entry_t *entry;
1392 xfs_attr_leaf_name_local_t *local;
1393 xfs_attr_leaf_name_remote_t *remote;
14f8b681 1394 uint32_t bs = mp->m_sb.sb_blocksize;
70099c89 1395 char *first_name;
80853366 1396
61983f67 1397
ed737480 1398 leaf = (xfs_attr_leafblock_t *)block;
61983f67 1399
80853366
ES
1400 /* Remote attributes - attr3 has XFS_ATTR3_RMT_MAGIC, attr has none */
1401 if ((be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) &&
1402 (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR3_LEAF_MAGIC)) {
ed737480 1403 for (i = 0; i < attr_data.remote_val_count; i++) {
fb4697dd
CB
1404 if (metadump.obfuscate &&
1405 attr_data.remote_vals[i] == offset)
80853366
ES
1406 /* Macros to handle both attr and attr3 */
1407 memset(block +
1408 (bs - XFS_ATTR3_RMT_BUF_SPACE(mp, bs)),
1941482c 1409 'v', XFS_ATTR3_RMT_BUF_SPACE(mp, bs));
61983f67 1410 }
ed737480
DC
1411 return;
1412 }
61983f67 1413
80853366 1414 /* Ok, it's a leaf - get header; accounts for crc & non-crc */
19ebedcf 1415 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &hdr, leaf);
80853366
ES
1416
1417 nentries = hdr.count;
59562913
ES
1418 if (nentries == 0 ||
1419 nentries * sizeof(xfs_attr_leaf_entry_t) +
80853366
ES
1420 xfs_attr3_leaf_hdr_size(leaf) >
1421 XFS_ATTR3_RMT_BUF_SPACE(mp, bs)) {
fb4697dd 1422 if (metadump.show_warnings)
ed737480 1423 print_warning("invalid attr count in inode %llu",
fb4697dd 1424 (long long)metadump.cur_ino);
ed737480
DC
1425 return;
1426 }
1427
80853366 1428 entry = xfs_attr3_leaf_entryp(leaf);
70099c89
ES
1429 /* We will move this as we parse */
1430 first_name = NULL;
80853366 1431 for (i = 0; i < nentries; i++, entry++) {
70099c89
ES
1432 int nlen, vlen, zlen;
1433
1434 /* Grows up; if this name is topmost, move first_name */
1435 if (!first_name || xfs_attr3_leaf_name(leaf, i) < first_name)
1436 first_name = xfs_attr3_leaf_name(leaf, i);
1437
ff105f75 1438 if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) {
fb4697dd 1439 if (metadump.show_warnings)
ed737480
DC
1440 print_warning(
1441 "invalid attr nameidx in inode %llu",
fb4697dd 1442 (long long)metadump.cur_ino);
ed737480 1443 break;
61983f67 1444 }
ed737480
DC
1445 if (entry->flags & XFS_ATTR_LOCAL) {
1446 local = xfs_attr3_leaf_name_local(leaf, i);
1447 if (local->namelen == 0) {
fb4697dd 1448 if (metadump.show_warnings)
ed737480
DC
1449 print_warning(
1450 "zero length for attr name in inode %llu",
fb4697dd 1451 (long long)metadump.cur_ino);
61983f67
BN
1452 break;
1453 }
fb4697dd 1454 if (metadump.obfuscate) {
70099c89
ES
1455 generate_obfuscated_name(0, local->namelen,
1456 &local->nameval[0]);
1457 memset(&local->nameval[local->namelen], 'v',
1458 be16_to_cpu(local->valuelen));
1459 }
1460 /* zero from end of nameval[] to next name start */
1461 nlen = local->namelen;
1462 vlen = be16_to_cpu(local->valuelen);
1463 zlen = xfs_attr_leaf_entsize_local(nlen, vlen) -
39e9f4c2 1464 (offsetof(struct xfs_attr_leaf_name_local, nameval) +
70099c89 1465 nlen + vlen);
fb4697dd 1466 if (metadump.zero_stale_data)
70099c89 1467 memset(&local->nameval[nlen + vlen], 0, zlen);
ed737480
DC
1468 } else {
1469 remote = xfs_attr3_leaf_name_remote(leaf, i);
1470 if (remote->namelen == 0 || remote->valueblk == 0) {
fb4697dd 1471 if (metadump.show_warnings)
ed737480
DC
1472 print_warning(
1473 "invalid attr entry in inode %llu",
fb4697dd 1474 (long long)metadump.cur_ino);
ed737480 1475 break;
61983f67 1476 }
fb4697dd 1477 if (metadump.obfuscate) {
70099c89
ES
1478 generate_obfuscated_name(0, remote->namelen,
1479 &remote->name[0]);
1480 add_remote_vals(be32_to_cpu(remote->valueblk),
1481 be32_to_cpu(remote->valuelen));
1482 }
1483 /* zero from end of name[] to next name start */
1484 nlen = remote->namelen;
1485 zlen = xfs_attr_leaf_entsize_remote(nlen) -
39e9f4c2 1486 (offsetof(struct xfs_attr_leaf_name_remote, name) +
70099c89 1487 nlen);
fb4697dd 1488 if (metadump.zero_stale_data)
70099c89 1489 memset(&remote->name[nlen], 0, zlen);
61983f67
BN
1490 }
1491 }
70099c89
ES
1492
1493 /* Zero from end of entries array to the first name/val */
fb4697dd 1494 if (metadump.zero_stale_data) {
70099c89
ES
1495 struct xfs_attr_leaf_entry *entries;
1496
1497 entries = xfs_attr3_leaf_entryp(leaf);
1498 memset(&entries[nentries], 0,
1499 first_name - (char *)&entries[nentries]);
1500 }
61983f67
BN
1501}
1502
70099c89 1503/* Processes symlinks, attrs, directories ... */
d452ae4d
DC
1504static int
1505process_single_fsb_objects(
5a35bf2c
DC
1506 xfs_fileoff_t o,
1507 xfs_fsblock_t s,
1508 xfs_filblks_t c,
d452ae4d 1509 typnm_t btype,
5a35bf2c 1510 xfs_fileoff_t last)
d452ae4d 1511{
a196ca65 1512 int rval = 1;
ed737480 1513 char *dp;
ed737480 1514 int i;
d452ae4d 1515
0c6b1caf
DC
1516 for (i = 0; i < c; i++) {
1517 push_cur();
1518 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), blkbb,
1519 DB_RING_IGN, NULL);
d452ae4d 1520
0c6b1caf
DC
1521 if (!iocur_top->data) {
1522 xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s);
1523 xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s);
61983f67 1524
0c6b1caf
DC
1525 print_warning("cannot read %s block %u/%u (%llu)",
1526 typtab[btype].name, agno, agbno, s);
fb4697dd 1527 rval = !metadump.stop_on_read_error;
0c6b1caf 1528 goto out_pop;
d452ae4d 1529
0c6b1caf 1530 }
d452ae4d 1531
fb4697dd 1532 if (!metadump.obfuscate && !metadump.zero_stale_data)
0c6b1caf 1533 goto write;
d452ae4d 1534
c83c169e 1535 /* Zero unused part of interior nodes */
fb4697dd 1536 if (metadump.zero_stale_data) {
c83c169e
ES
1537 xfs_da_intnode_t *node = iocur_top->data;
1538 int magic = be16_to_cpu(node->hdr.info.magic);
1539
1540 if (magic == XFS_DA_NODE_MAGIC ||
1541 magic == XFS_DA3_NODE_MAGIC) {
1542 struct xfs_da3_icnode_hdr hdr;
1543 int used;
1544
08c16786 1545 libxfs_da3_node_hdr_from_disk(mp, &hdr, node);
52be9b6a
CH
1546 switch (btype) {
1547 case TYP_DIR2:
1548 used = mp->m_dir_geo->node_hdr_size;
1549 break;
1550 case TYP_ATTR:
1551 used = mp->m_attr_geo->node_hdr_size;
1552 break;
1553 default:
1554 /* unknown type, don't zero anything */
1555 used = mp->m_sb.sb_blocksize;
1556 break;
1557 }
c83c169e
ES
1558
1559 used += hdr.count
1560 * sizeof(struct xfs_da_node_entry);
1561
1562 if (used < mp->m_sb.sb_blocksize) {
1563 memset((char *)node + used, 0,
1564 mp->m_sb.sb_blocksize - used);
1565 iocur_top->need_crc = 1;
1566 }
1567 }
1568 }
1569
1570 /* Handle leaf nodes */
0c6b1caf 1571 dp = iocur_top->data;
ed737480
DC
1572 switch (btype) {
1573 case TYP_DIR2:
a56173b5 1574 if (o >= mp->m_dir_geo->freeblk) {
c3387ef7 1575 process_dir_free_block(dp);
a56173b5
ES
1576 } else if (o >= mp->m_dir_geo->leafblk) {
1577 process_dir_leaf_block(dp);
1578 } else {
1579 process_dir_data_block(dp, o,
ff105f75 1580 last == mp->m_dir_geo->fsbcount);
a56173b5 1581 }
fd491857 1582 iocur_top->need_crc = 1;
ed737480 1583 break;
ed737480 1584 case TYP_ATTR:
70099c89
ES
1585 process_attr_block(dp, o);
1586 iocur_top->need_crc = 1;
ed737480
DC
1587 break;
1588 default:
1589 break;
1590 }
0c6b1caf
DC
1591
1592write:
a196ca65
DC
1593 if (write_buf(iocur_top))
1594 rval = 0;
0c6b1caf
DC
1595out_pop:
1596 pop_cur();
a196ca65 1597 if (!rval)
0c6b1caf 1598 break;
ed737480 1599 o++;
0c6b1caf 1600 s++;
d452ae4d 1601 }
d452ae4d 1602
a196ca65 1603 return rval;
d452ae4d
DC
1604}
1605
6e79202b
DC
1606/*
1607 * Static map to aggregate multiple extents into a single directory block.
1608 */
1609static struct bbmap mfsb_map;
1610static int mfsb_length;
1611
d452ae4d 1612static int
9e43c345 1613process_multi_fsb_dir(
5a35bf2c
DC
1614 xfs_fileoff_t o,
1615 xfs_fsblock_t s,
1616 xfs_filblks_t c,
d452ae4d 1617 typnm_t btype,
5a35bf2c 1618 xfs_fileoff_t last)
d452ae4d 1619{
b04e7e92 1620 char *dp;
a196ca65 1621 int rval = 1;
ed737480 1622
6e79202b
DC
1623 while (c > 0) {
1624 unsigned int bm_len;
ed737480 1625
ff105f75
DC
1626 if (mfsb_length + c >= mp->m_dir_geo->fsbcount) {
1627 bm_len = mp->m_dir_geo->fsbcount - mfsb_length;
6e79202b
DC
1628 mfsb_length = 0;
1629 } else {
1630 mfsb_length += c;
1631 bm_len = c;
1632 }
ed737480 1633
6e79202b
DC
1634 mfsb_map.b[mfsb_map.nmaps].bm_bn = XFS_FSB_TO_DADDR(mp, s);
1635 mfsb_map.b[mfsb_map.nmaps].bm_len = XFS_FSB_TO_BB(mp, bm_len);
1636 mfsb_map.nmaps++;
ed737480 1637
6e79202b
DC
1638 if (mfsb_length == 0) {
1639 push_cur();
1640 set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &mfsb_map);
1641 if (!iocur_top->data) {
1642 xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, s);
1643 xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, s);
ed737480 1644
6e79202b
DC
1645 print_warning("cannot read %s block %u/%u (%llu)",
1646 typtab[btype].name, agno, agbno, s);
fb4697dd 1647 rval = !metadump.stop_on_read_error;
6e79202b 1648 goto out_pop;
ed737480 1649
6e79202b 1650 }
ed737480 1651
fb4697dd 1652 if (!metadump.obfuscate && !metadump.zero_stale_data)
b04e7e92 1653 goto write;
6e79202b 1654
b04e7e92
SR
1655 dp = iocur_top->data;
1656 if (o >= mp->m_dir_geo->freeblk) {
c3387ef7 1657 process_dir_free_block(dp);
b04e7e92
SR
1658 } else if (o >= mp->m_dir_geo->leafblk) {
1659 process_dir_leaf_block(dp);
1660 } else {
1661 process_dir_data_block(dp, o,
1662 last == mp->m_dir_geo->fsbcount);
1663 }
fd491857 1664 iocur_top->need_crc = 1;
b04e7e92 1665write:
a196ca65
DC
1666 if (write_buf(iocur_top))
1667 rval = 0;
ed737480 1668out_pop:
6e79202b
DC
1669 pop_cur();
1670 mfsb_map.nmaps = 0;
a196ca65 1671 if (!rval)
6e79202b
DC
1672 break;
1673 }
1674 c -= bm_len;
1675 s += bm_len;
1676 }
1677
a196ca65 1678 return rval;
d452ae4d
DC
1679}
1680
001df390
DW
1681static bool
1682is_multi_fsb_object(
1683 struct xfs_mount *mp,
1684 typnm_t btype)
1685{
1686 if (btype == TYP_DIR2 && mp->m_dir_geo->fsbcount > 1)
1687 return true;
0e81250e
DW
1688 if (btype == TYP_SYMLINK)
1689 return true;
001df390
DW
1690 return false;
1691}
1692
9e43c345
DW
1693static int
1694process_multi_fsb_objects(
1695 xfs_fileoff_t o,
1696 xfs_fsblock_t s,
1697 xfs_filblks_t c,
1698 typnm_t btype,
1699 xfs_fileoff_t last)
1700{
1701 switch (btype) {
1702 case TYP_DIR2:
1703 return process_multi_fsb_dir(o, s, c, btype, last);
0e81250e
DW
1704 case TYP_SYMLINK:
1705 return process_symlink_block(o, s, c, btype, last);
9e43c345
DW
1706 default:
1707 print_warning("bad type for multi-fsb object %d", btype);
a196ca65 1708 return 1;
9e43c345
DW
1709 }
1710}
1711
d452ae4d 1712/* inode copy routines */
61983f67
BN
1713static int
1714process_bmbt_reclist(
a196ca65
DC
1715 xfs_bmbt_rec_t *rp,
1716 int numrecs,
61983f67
BN
1717 typnm_t btype)
1718{
1719 int i;
5a35bf2c
DC
1720 xfs_fileoff_t o, op = NULLFILEOFF;
1721 xfs_fsblock_t s;
1722 xfs_filblks_t c, cp = NULLFILEOFF;
61983f67 1723 int f;
5a35bf2c 1724 xfs_fileoff_t last;
88b8e1d6
BN
1725 xfs_agnumber_t agno;
1726 xfs_agblock_t agbno;
001df390 1727 bool is_multi_fsb = is_multi_fsb_object(mp, btype);
a196ca65 1728 int rval = 1;
61983f67
BN
1729
1730 if (btype == TYP_DATA)
1731 return 1;
1732
1733 convert_extent(&rp[numrecs - 1], &o, &s, &c, &f);
1734 last = o + c;
1735
1736 for (i = 0; i < numrecs; i++, rp++) {
1737 convert_extent(rp, &o, &s, &c, &f);
1738
88b8e1d6
BN
1739 /*
1740 * ignore extents that are clearly bogus, and if a bogus
1741 * one is found, stop processing remaining extents
1742 */
1743 if (i > 0 && op + cp > o) {
fb4697dd 1744 if (metadump.show_warnings)
88b8e1d6
BN
1745 print_warning("bmap extent %d in %s ino %llu "
1746 "starts at %llu, previous extent "
1747 "ended at %llu", i,
fb4697dd
CB
1748 typtab[btype].name,
1749 (long long)metadump.cur_ino,
88b8e1d6
BN
1750 o, op + cp - 1);
1751 break;
1752 }
1753
fb4697dd 1754 if (c > metadump.max_extent_size) {
88b8e1d6
BN
1755 /*
1756 * since we are only processing non-data extents,
1757 * large numbers of blocks in a metadata extent is
1758 * extremely rare and more than likely to be corrupt.
1759 */
fb4697dd 1760 if (metadump.show_warnings)
88b8e1d6
BN
1761 print_warning("suspicious count %u in bmap "
1762 "extent %d in %s ino %llu", c, i,
fb4697dd
CB
1763 typtab[btype].name,
1764 (long long)metadump.cur_ino);
88b8e1d6
BN
1765 break;
1766 }
1767
1768 op = o;
1769 cp = c;
1770
1771 agno = XFS_FSB_TO_AGNO(mp, s);
1772 agbno = XFS_FSB_TO_AGBNO(mp, s);
1773
1774 if (!valid_bno(agno, agbno)) {
fb4697dd 1775 if (metadump.show_warnings)
88b8e1d6
BN
1776 print_warning("invalid block number %u/%u "
1777 "(%llu) in bmap extent %d in %s ino "
1778 "%llu", agno, agbno, s, i,
fb4697dd
CB
1779 typtab[btype].name,
1780 (long long)metadump.cur_ino);
88b8e1d6
BN
1781 break;
1782 }
1783
1784 if (!valid_bno(agno, agbno + c - 1)) {
fb4697dd 1785 if (metadump.show_warnings)
88b8e1d6
BN
1786 print_warning("bmap extent %i in %s inode %llu "
1787 "overflows AG (end is %u/%u)", i,
fb4697dd
CB
1788 typtab[btype].name,
1789 (long long)metadump.cur_ino,
88b8e1d6
BN
1790 agno, agbno + c - 1);
1791 break;
1792 }
1793
d452ae4d 1794 /* multi-extent blocks require special handling */
001df390 1795 if (is_multi_fsb)
a196ca65 1796 rval = process_multi_fsb_objects(o, s, c, btype,
001df390
DW
1797 last);
1798 else
a196ca65 1799 rval = process_single_fsb_objects(o, s, c, btype,
001df390 1800 last);
a196ca65
DC
1801 if (!rval)
1802 break;
61983f67
BN
1803 }
1804
a196ca65 1805 return rval;
61983f67
BN
1806}
1807
1808static int
1809scanfunc_bmap(
b194c7d8 1810 struct xfs_btree_block *block,
61983f67
BN
1811 xfs_agnumber_t agno,
1812 xfs_agblock_t agbno,
1813 int level,
1814 typnm_t btype,
1815 void *arg) /* ptr to itype */
1816{
1817 int i;
1818 xfs_bmbt_ptr_t *pp;
61983f67
BN
1819 int nrecs;
1820
b194c7d8 1821 nrecs = be16_to_cpu(block->bb_numrecs);
61983f67
BN
1822
1823 if (level == 0) {
1824 if (nrecs > mp->m_bmap_dmxr[0]) {
fb4697dd 1825 if (metadump.show_warnings)
61983f67
BN
1826 print_warning("invalid numrecs (%u) in %s "
1827 "block %u/%u", nrecs,
1828 typtab[btype].name, agno, agbno);
1829 return 1;
1830 }
b3563c19
BN
1831 return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1),
1832 nrecs, *(typnm_t*)arg);
61983f67
BN
1833 }
1834
1835 if (nrecs > mp->m_bmap_dmxr[1]) {
fb4697dd 1836 if (metadump.show_warnings)
61983f67
BN
1837 print_warning("invalid numrecs (%u) in %s block %u/%u",
1838 nrecs, typtab[btype].name, agno, agbno);
1839 return 1;
1840 }
b3563c19 1841 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
61983f67
BN
1842 for (i = 0; i < nrecs; i++) {
1843 xfs_agnumber_t ag;
1844 xfs_agblock_t bno;
1845
1bec3a62
ES
1846 ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
1847 bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
61983f67
BN
1848
1849 if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
1850 ag > mp->m_sb.sb_agcount) {
fb4697dd 1851 if (metadump.show_warnings)
61983f67
BN
1852 print_warning("invalid block number (%u/%u) "
1853 "in %s block %u/%u", ag, bno,
1854 typtab[btype].name, agno, agbno);
1855 continue;
1856 }
1857
1858 if (!scan_btree(ag, bno, level, btype, arg, scanfunc_bmap))
1859 return 0;
1860 }
1861 return 1;
1862}
1863
1864static int
1865process_btinode(
7328ea6e 1866 struct xfs_dinode *dip,
61983f67
BN
1867 typnm_t itype)
1868{
1869 xfs_bmdr_block_t *dib;
1870 int i;
1871 xfs_bmbt_ptr_t *pp;
61983f67
BN
1872 int level;
1873 int nrecs;
1874 int maxrecs;
1875 int whichfork;
1876 typnm_t btype;
1877
1878 whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
1879 btype = (itype == TYP_ATTR) ? TYP_BMAPBTA : TYP_BMAPBTD;
1880
1881 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
1882 level = be16_to_cpu(dib->bb_level);
1883 nrecs = be16_to_cpu(dib->bb_numrecs);
1884
1885 if (level > XFS_BM_MAXLEVELS(mp, whichfork)) {
fb4697dd 1886 if (metadump.show_warnings)
61983f67 1887 print_warning("invalid level (%u) in inode %lld %s "
fb4697dd
CB
1888 "root", level, (long long)metadump.cur_ino,
1889 typtab[btype].name);
61983f67
BN
1890 return 1;
1891 }
1892
b3563c19
BN
1893 if (level == 0) {
1894 return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1),
1895 nrecs, itype);
1896 }
61983f67 1897
e2f60652 1898 maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0);
61983f67 1899 if (nrecs > maxrecs) {
fb4697dd 1900 if (metadump.show_warnings)
61983f67 1901 print_warning("invalid numrecs (%u) in inode %lld %s "
fb4697dd
CB
1902 "root", nrecs, (long long)metadump.cur_ino,
1903 typtab[btype].name);
61983f67
BN
1904 return 1;
1905 }
1906
b3563c19 1907 pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
07b75e31 1908
fb4697dd 1909 if (metadump.zero_stale_data) {
07b75e31
SR
1910 char *top;
1911
1912 /* Unused btree key space */
1913 top = (char*)XFS_BMDR_KEY_ADDR(dib, nrecs + 1);
1914 memset(top, 0, (char*)pp - top);
1915
1916 /* Unused btree ptr space */
1917 top = (char*)&pp[nrecs];
1918 memset(top, 0, (char*)dib + XFS_DFORK_SIZE(dip, mp, whichfork) - top);
1919 }
1920
61983f67
BN
1921 for (i = 0; i < nrecs; i++) {
1922 xfs_agnumber_t ag;
1923 xfs_agblock_t bno;
1924
1bec3a62
ES
1925 ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
1926 bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
61983f67
BN
1927
1928 if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
1929 ag > mp->m_sb.sb_agcount) {
fb4697dd 1930 if (metadump.show_warnings)
61983f67 1931 print_warning("invalid block number (%u/%u) "
fb4697dd
CB
1932 "in inode %llu %s root", ag, bno,
1933 (long long)metadump.cur_ino,
1934 typtab[btype].name);
61983f67
BN
1935 continue;
1936 }
1937
1938 if (!scan_btree(ag, bno, level, btype, &itype, scanfunc_bmap))
1939 return 0;
1940 }
1941 return 1;
1942}
1943
1944static int
1945process_exinode(
7328ea6e 1946 struct xfs_dinode *dip,
61983f67
BN
1947 typnm_t itype)
1948{
1949 int whichfork;
87c955c3 1950 int used;
95e3fc7f 1951 xfs_extnum_t nex, max_nex;
61983f67
BN
1952
1953 whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
1954
5f70c91b 1955 nex = xfs_dfork_nextents(dip, whichfork);
95e3fc7f
DW
1956 max_nex = xfs_iext_max_nextents(
1957 xfs_dinode_has_large_extent_counts(dip),
1958 whichfork);
87c955c3 1959 used = nex * sizeof(xfs_bmbt_rec_t);
95e3fc7f 1960 if (nex > max_nex || used > XFS_DFORK_SIZE(dip, mp, whichfork)) {
fb4697dd 1961 if (metadump.show_warnings)
95e3fc7f 1962 print_warning("bad number of extents %llu in inode %lld",
fb4697dd
CB
1963 (unsigned long long)nex,
1964 (long long)metadump.cur_ino);
88b8e1d6
BN
1965 return 1;
1966 }
1967
87c955c3 1968 /* Zero unused data fork past used extents */
fb4697dd
CB
1969 if (metadump.zero_stale_data &&
1970 (used < XFS_DFORK_SIZE(dip, mp, whichfork)))
87c955c3
ES
1971 memset(XFS_DFORK_PTR(dip, whichfork) + used, 0,
1972 XFS_DFORK_SIZE(dip, mp, whichfork) - used);
1973
1974
88b8e1d6
BN
1975 return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip,
1976 whichfork), nex, itype);
61983f67
BN
1977}
1978
1979static int
1980process_inode_data(
7328ea6e 1981 struct xfs_dinode *dip,
61983f67
BN
1982 typnm_t itype)
1983{
56b2de80 1984 switch (dip->di_format) {
61983f67 1985 case XFS_DINODE_FMT_LOCAL:
fb4697dd 1986 if (!(metadump.obfuscate || metadump.zero_stale_data))
38feb6e5
DC
1987 break;
1988
1989 /*
1990 * If the fork size is invalid, we can't safely do
1991 * anything with this fork. Leave it alone to preserve
1992 * the information for diagnostic purposes.
1993 */
1994 if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
1995 print_warning(
1996"Invalid data fork size (%d) in inode %llu, preserving contents!",
1997 XFS_DFORK_DSIZE(dip, mp),
fb4697dd 1998 (long long)metadump.cur_ino);
38feb6e5
DC
1999 break;
2000 }
61983f67 2001
38feb6e5
DC
2002 switch (itype) {
2003 case TYP_DIR2:
2004 process_sf_dir(dip);
2005 break;
61983f67 2006
38feb6e5
DC
2007 case TYP_SYMLINK:
2008 process_sf_symlink(dip);
2009 break;
2010
2011 default:
2012 break;
2013 }
61983f67
BN
2014 break;
2015
2016 case XFS_DINODE_FMT_EXTENTS:
2017 return process_exinode(dip, itype);
2018
2019 case XFS_DINODE_FMT_BTREE:
2020 return process_btinode(dip, itype);
2021 }
2022 return 1;
2023}
2024
a196ca65 2025static void
b32d0eb6 2026process_dev_inode(
7328ea6e 2027 struct xfs_dinode *dip)
b32d0eb6 2028{
5f70c91b 2029 if (xfs_dfork_data_extents(dip)) {
fb4697dd 2030 if (metadump.show_warnings)
b32d0eb6 2031 print_warning("inode %llu has unexpected extents",
fb4697dd 2032 (unsigned long long)metadump.cur_ino);
a196ca65
DC
2033 return;
2034 }
38feb6e5
DC
2035
2036 /*
2037 * If the fork size is invalid, we can't safely do anything with
2038 * this fork. Leave it alone to preserve the information for diagnostic
2039 * purposes.
2040 */
2041 if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
2042 print_warning(
2043"Invalid data fork size (%d) in inode %llu, preserving contents!",
fb4697dd 2044 XFS_DFORK_DSIZE(dip, mp), (long long)metadump.cur_ino);
38feb6e5
DC
2045 return;
2046 }
2047
fb4697dd 2048 if (metadump.zero_stale_data) {
a196ca65 2049 unsigned int size = sizeof(xfs_dev_t);
b32d0eb6 2050
a196ca65
DC
2051 memset(XFS_DFORK_DPTR(dip) + size, 0,
2052 XFS_DFORK_DSIZE(dip, mp) - size);
b32d0eb6
SR
2053 }
2054}
2055
fd491857
DC
2056/*
2057 * when we process the inode, we may change the data in the data and/or
2058 * attribute fork if they are in short form and we are obfuscating names.
2059 * In this case we need to recalculate the CRC of the inode, but we should
2060 * only do that if the CRC in the inode is good to begin with. If the crc
2061 * is not ok, we just leave it alone.
2062 */
61983f67
BN
2063static int
2064process_inode(
2065 xfs_agnumber_t agno,
2066 xfs_agino_t agino,
7328ea6e 2067 struct xfs_dinode *dip,
27499a0a 2068 bool free_inode)
61983f67 2069{
a196ca65 2070 int rval = 1;
fd491857
DC
2071 bool crc_was_ok = false; /* no recalc by default */
2072 bool need_new_crc = false;
61983f67 2073
fb4697dd 2074 metadump.cur_ino = XFS_AGINO_TO_INO(mp, agno, agino);
61983f67 2075
27499a0a 2076 /* we only care about crc recalculation if we will modify the inode. */
fb4697dd 2077 if (metadump.obfuscate || metadump.zero_stale_data) {
e2f60652 2078 crc_was_ok = libxfs_verify_cksum((char *)dip,
fd491857
DC
2079 mp->m_sb.sb_inodesize,
2080 offsetof(struct xfs_dinode, di_crc));
2081 }
2082
27499a0a 2083 if (free_inode) {
fb4697dd 2084 if (metadump.zero_stale_data) {
27499a0a 2085 /* Zero all of the inode literal area */
4de63245 2086 memset(XFS_DFORK_DPTR(dip), 0, XFS_LITINO(mp));
27499a0a
ES
2087 }
2088 goto done;
2089 }
2090
61983f67 2091 /* copy appropriate data fork metadata */
56b2de80 2092 switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
61983f67 2093 case S_IFDIR:
a196ca65 2094 rval = process_inode_data(dip, TYP_DIR2);
fd491857 2095 if (dip->di_format == XFS_DINODE_FMT_LOCAL)
3ea31010 2096 need_new_crc = true;
61983f67
BN
2097 break;
2098 case S_IFLNK:
a196ca65 2099 rval = process_inode_data(dip, TYP_SYMLINK);
fd491857 2100 if (dip->di_format == XFS_DINODE_FMT_LOCAL)
3ea31010 2101 need_new_crc = true;
61983f67 2102 break;
88b8e1d6 2103 case S_IFREG:
a196ca65 2104 rval = process_inode_data(dip, TYP_DATA);
88b8e1d6 2105 break;
b32d0eb6
SR
2106 case S_IFIFO:
2107 case S_IFCHR:
2108 case S_IFBLK:
2109 case S_IFSOCK:
a196ca65 2110 process_dev_inode(dip);
3ea31010 2111 need_new_crc = true;
b32d0eb6
SR
2112 break;
2113 default:
2114 break;
61983f67 2115 }
a85f8b0a 2116 nametable_clear();
a196ca65
DC
2117 if (!rval)
2118 goto done;
61983f67 2119
88b8e1d6 2120 /* copy extended attributes if they exist and forkoff is valid */
a196ca65 2121 if (XFS_DFORK_DSIZE(dip, mp) < XFS_LITINO(mp)) {
61983f67 2122 attr_data.remote_val_count = 0;
56b2de80 2123 switch (dip->di_aformat) {
61983f67 2124 case XFS_DINODE_FMT_LOCAL:
3ea31010 2125 need_new_crc = true;
fb4697dd
CB
2126 if (metadump.obfuscate ||
2127 metadump.zero_stale_data)
87c955c3 2128 process_sf_attr(dip);
61983f67
BN
2129 break;
2130
2131 case XFS_DINODE_FMT_EXTENTS:
a196ca65 2132 rval = process_exinode(dip, TYP_ATTR);
61983f67
BN
2133 break;
2134
2135 case XFS_DINODE_FMT_BTREE:
a196ca65 2136 rval = process_btinode(dip, TYP_ATTR);
61983f67
BN
2137 break;
2138 }
a85f8b0a 2139 nametable_clear();
61983f67 2140 }
fd491857 2141
27499a0a
ES
2142done:
2143 /* Heavy handed but low cost; just do it as a catch-all. */
fb4697dd 2144 if (metadump.zero_stale_data)
3ea31010 2145 need_new_crc = true;
27499a0a 2146
fd491857 2147 if (crc_was_ok && need_new_crc)
f616e2bf 2148 libxfs_dinode_calc_crc(mp, dip);
a196ca65
DC
2149
2150 return rval;
61983f67
BN
2151}
2152
14f8b681 2153static uint32_t inodes_copied;
61983f67
BN
2154
2155static int
2156copy_inode_chunk(
2157 xfs_agnumber_t agno,
2158 xfs_inobt_rec_t *rp)
2159{
2160 xfs_agino_t agino;
2161 int off;
2162 xfs_agblock_t agbno;
04b21e41 2163 xfs_agblock_t end_agbno;
61983f67 2164 int i;
d24c0a90 2165 int rval = 0;
04b21e41
BF
2166 int blks_per_buf;
2167 int inodes_per_buf;
2168 int ioff;
e7fd2b6f 2169 struct xfs_ino_geometry *igeo = M_IGEO(mp);
61983f67
BN
2170
2171 agino = be32_to_cpu(rp->ir_startino);
2172 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
e7fd2b6f 2173 end_agbno = agbno + igeo->ialloc_blks;
61983f67
BN
2174 off = XFS_INO_TO_OFFSET(mp, agino);
2175
04b21e41
BF
2176 /*
2177 * If the fs supports sparse inode records, we must process inodes a
2178 * cluster at a time because that is the sparse allocation granularity.
2179 * Otherwise, we risk CRC corruption errors on reads of inode chunks.
2180 *
2181 * Also make sure that that we don't process more than the single record
2182 * we've been passed (large block sizes can hold multiple inode chunks).
2183 */
2660e653 2184 if (xfs_has_sparseinodes(mp))
e7fd2b6f 2185 blks_per_buf = igeo->blocks_per_cluster;
04b21e41 2186 else
e7fd2b6f 2187 blks_per_buf = igeo->ialloc_blks;
7516da71 2188 inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf),
04b21e41
BF
2189 XFS_INODES_PER_CHUNK);
2190
2191 /*
2192 * Sanity check that we only process a single buffer if ir_startino has
2193 * a buffer offset. A non-zero offset implies that the entire chunk lies
2194 * within a block.
2195 */
2196 if (off && inodes_per_buf != XFS_INODES_PER_CHUNK) {
2197 print_warning("bad starting inode offset %d", off);
2198 return 0;
2199 }
2200
88b8e1d6
BN
2201 if (agino == 0 || agino == NULLAGINO || !valid_bno(agno, agbno) ||
2202 !valid_bno(agno, XFS_AGINO_TO_AGBNO(mp,
2203 agino + XFS_INODES_PER_CHUNK - 1))) {
fb4697dd 2204 if (metadump.show_warnings)
88b8e1d6
BN
2205 print_warning("bad inode number %llu (%u/%u)",
2206 XFS_AGINO_TO_INO(mp, agno, agino), agno, agino);
2207 return 1;
2208 }
2209
88b8e1d6
BN
2210 /*
2211 * check for basic assumptions about inode chunks, and if any
2212 * assumptions fail, don't process the inode chunk.
2213 */
88b8e1d6
BN
2214 if ((mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && off != 0) ||
2215 (mp->m_sb.sb_inopblock > XFS_INODES_PER_CHUNK &&
2216 off % XFS_INODES_PER_CHUNK != 0) ||
2660e653 2217 (xfs_has_align(mp) &&
0ab7cbc8 2218 mp->m_sb.sb_inoalignmt != 0 &&
88b8e1d6 2219 agbno % mp->m_sb.sb_inoalignmt != 0)) {
fb4697dd 2220 if (metadump.show_warnings)
88b8e1d6
BN
2221 print_warning("badly aligned inode (start = %llu)",
2222 XFS_AGINO_TO_INO(mp, agno, agino));
9180183e
BF
2223 return 1;
2224 }
2225
2226 push_cur();
04b21e41
BF
2227 ioff = 0;
2228 while (agbno < end_agbno && ioff < XFS_INODES_PER_CHUNK) {
2229 if (xfs_inobt_is_sparse_disk(rp, ioff))
2230 goto next_bp;
2231
2232 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
2233 XFS_FSB_TO_BB(mp, blks_per_buf), DB_RING_IGN, NULL);
2234 if (iocur_top->data == NULL) {
2235 print_warning("cannot read inode block %u/%u",
2236 agno, agbno);
fb4697dd 2237 rval = !metadump.stop_on_read_error;
04b21e41
BF
2238 goto pop_out;
2239 }
88b8e1d6 2240
04b21e41 2241 for (i = 0; i < inodes_per_buf; i++) {
7328ea6e 2242 struct xfs_dinode *dip;
61983f67 2243
7328ea6e 2244 dip = (struct xfs_dinode *)((char *)iocur_top->data +
04b21e41 2245 ((off + i) << mp->m_sb.sb_inodelog));
61983f67 2246
04b21e41
BF
2247 /* process_inode handles free inodes, too */
2248 if (!process_inode(agno, agino + ioff + i, dip,
a196ca65 2249 XFS_INOBT_IS_FREE_DISK(rp, ioff + i)))
04b21e41 2250 goto pop_out;
9180183e 2251
04b21e41
BF
2252 inodes_copied++;
2253 }
61983f67 2254
04b21e41
BF
2255 if (write_buf(iocur_top))
2256 goto pop_out;
2257
2258next_bp:
2259 agbno += blks_per_buf;
2260 ioff += inodes_per_buf;
2261 }
61983f67 2262
fb4697dd 2263 if (metadump.show_progress)
61983f67
BN
2264 print_progress("Copied %u of %u inodes (%u of %u AGs)",
2265 inodes_copied, mp->m_sb.sb_icount, agno,
2266 mp->m_sb.sb_agcount);
d24c0a90
BN
2267 rval = 1;
2268pop_out:
61983f67 2269 pop_cur();
d24c0a90 2270 return rval;
61983f67
BN
2271}
2272
2273static int
2274scanfunc_ino(
b194c7d8 2275 struct xfs_btree_block *block,
61983f67
BN
2276 xfs_agnumber_t agno,
2277 xfs_agblock_t agbno,
2278 int level,
2279 typnm_t btype,
2280 void *arg)
2281{
2282 xfs_inobt_rec_t *rp;
2283 xfs_inobt_ptr_t *pp;
2284 int i;
88b8e1d6 2285 int numrecs;
03e956b2 2286 int finobt = *(int *) arg;
e7fd2b6f 2287 struct xfs_ino_geometry *igeo = M_IGEO(mp);
88b8e1d6 2288
b194c7d8 2289 numrecs = be16_to_cpu(block->bb_numrecs);
61983f67
BN
2290
2291 if (level == 0) {
e7fd2b6f 2292 if (numrecs > igeo->inobt_mxr[0]) {
fb4697dd 2293 if (metadump.show_warnings)
88b8e1d6
BN
2294 print_warning("invalid numrecs %d in %s "
2295 "block %u/%u", numrecs,
2296 typtab[btype].name, agno, agbno);
e7fd2b6f 2297 numrecs = igeo->inobt_mxr[0];
88b8e1d6 2298 }
03e956b2
BF
2299
2300 /*
2301 * Only copy the btree blocks for the finobt. The inobt scan
2302 * copies the inode chunks.
2303 */
2304 if (finobt)
2305 return 1;
2306
b3563c19 2307 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
88b8e1d6 2308 for (i = 0; i < numrecs; i++, rp++) {
61983f67
BN
2309 if (!copy_inode_chunk(agno, rp))
2310 return 0;
2311 }
88b8e1d6
BN
2312 return 1;
2313 }
2314
e7fd2b6f 2315 if (numrecs > igeo->inobt_mxr[1]) {
fb4697dd 2316 if (metadump.show_warnings)
88b8e1d6
BN
2317 print_warning("invalid numrecs %d in %s block %u/%u",
2318 numrecs, typtab[btype].name, agno, agbno);
e7fd2b6f 2319 numrecs = igeo->inobt_mxr[1];
88b8e1d6
BN
2320 }
2321
e7fd2b6f 2322 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
88b8e1d6
BN
2323 for (i = 0; i < numrecs; i++) {
2324 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 2325 if (metadump.show_warnings)
88b8e1d6
BN
2326 print_warning("invalid block number (%u/%u) "
2327 "in %s block %u/%u",
2328 agno, be32_to_cpu(pp[i]),
2329 typtab[btype].name, agno, agbno);
2330 continue;
61983f67 2331 }
88b8e1d6
BN
2332 if (!scan_btree(agno, be32_to_cpu(pp[i]), level,
2333 btype, arg, scanfunc_ino))
2334 return 0;
61983f67
BN
2335 }
2336 return 1;
2337}
2338
2339static int
2340copy_inodes(
2341 xfs_agnumber_t agno,
2342 xfs_agi_t *agi)
2343{
2344 xfs_agblock_t root;
2345 int levels;
03e956b2 2346 int finobt = 0;
61983f67
BN
2347
2348 root = be32_to_cpu(agi->agi_root);
2349 levels = be32_to_cpu(agi->agi_level);
2350
2351 /* validate root and levels before processing the tree */
2352 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 2353 if (metadump.show_warnings)
61983f67
BN
2354 print_warning("invalid block number (%u) in inobt "
2355 "root in agi %u", root, agno);
2356 return 1;
2357 }
716b497a 2358 if (levels > M_IGEO(mp)->inobt_maxlevels) {
fb4697dd 2359 if (metadump.show_warnings)
61983f67
BN
2360 print_warning("invalid level (%u) in inobt root "
2361 "in agi %u", levels, agno);
2362 return 1;
2363 }
2364
03e956b2
BF
2365 if (!scan_btree(agno, root, levels, TYP_INOBT, &finobt, scanfunc_ino))
2366 return 0;
2367
2660e653 2368 if (xfs_has_finobt(mp)) {
03e956b2
BF
2369 root = be32_to_cpu(agi->agi_free_root);
2370 levels = be32_to_cpu(agi->agi_free_level);
2371
9b9c121a 2372 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 2373 if (metadump.show_warnings)
9b9c121a
DW
2374 print_warning("invalid block number (%u) in "
2375 "finobt root in agi %u", root,
2376 agno);
2377 return 1;
2378 }
2379
2380 if (levels > M_IGEO(mp)->inobt_maxlevels) {
fb4697dd 2381 if (metadump.show_warnings)
9b9c121a
DW
2382 print_warning("invalid level (%u) in finobt "
2383 "root in agi %u", levels, agno);
2384 return 1;
2385 }
2386
03e956b2 2387 finobt = 1;
28bbc15a 2388 if (!scan_btree(agno, root, levels, TYP_FINOBT, &finobt,
03e956b2
BF
2389 scanfunc_ino))
2390 return 0;
2391 }
2392
2393 return 1;
61983f67
BN
2394}
2395
2396static int
2397scan_ag(
2398 xfs_agnumber_t agno)
2399{
2400 xfs_agf_t *agf;
2401 xfs_agi_t *agi;
d24c0a90
BN
2402 int stack_count = 0;
2403 int rval = 0;
61983f67
BN
2404
2405 /* copy the superblock of the AG */
2406 push_cur();
d24c0a90 2407 stack_count++;
61983f67
BN
2408 set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
2409 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2410 if (!iocur_top->data) {
2411 print_warning("cannot read superblock for ag %u", agno);
fb4697dd 2412 if (metadump.stop_on_read_error)
d24c0a90 2413 goto pop_out;
61983f67 2414 } else {
8927d44b 2415 /* Replace any filesystem label with "L's" */
fb4697dd 2416 if (metadump.obfuscate) {
8927d44b
ES
2417 struct xfs_sb *sb = iocur_top->data;
2418 memset(sb->sb_fname, 'L',
2419 min(strlen(sb->sb_fname), sizeof(sb->sb_fname)));
2420 iocur_top->need_crc = 1;
2421 }
878afc65 2422 if (write_buf(iocur_top))
d24c0a90 2423 goto pop_out;
61983f67
BN
2424 }
2425
2426 /* copy the AG free space btree root */
2427 push_cur();
d24c0a90 2428 stack_count++;
61983f67
BN
2429 set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
2430 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2431 agf = iocur_top->data;
2432 if (iocur_top->data == NULL) {
2433 print_warning("cannot read agf block for ag %u", agno);
fb4697dd 2434 if (metadump.stop_on_read_error)
d24c0a90 2435 goto pop_out;
61983f67 2436 } else {
878afc65 2437 if (write_buf(iocur_top))
d24c0a90 2438 goto pop_out;
61983f67
BN
2439 }
2440
2441 /* copy the AG inode btree root */
2442 push_cur();
d24c0a90 2443 stack_count++;
61983f67
BN
2444 set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
2445 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2446 agi = iocur_top->data;
2447 if (iocur_top->data == NULL) {
2448 print_warning("cannot read agi block for ag %u", agno);
fb4697dd 2449 if (metadump.stop_on_read_error)
d24c0a90 2450 goto pop_out;
61983f67 2451 } else {
878afc65 2452 if (write_buf(iocur_top))
d24c0a90 2453 goto pop_out;
61983f67
BN
2454 }
2455
2456 /* copy the AG free list header */
2457 push_cur();
d24c0a90 2458 stack_count++;
61983f67
BN
2459 set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
2460 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2461 if (iocur_top->data == NULL) {
2462 print_warning("cannot read agfl block for ag %u", agno);
fb4697dd 2463 if (metadump.stop_on_read_error)
d24c0a90 2464 goto pop_out;
61983f67 2465 } else {
fb4697dd 2466 if (agf && metadump.zero_stale_data) {
18cdb614
ES
2467 /* Zero out unused bits of agfl */
2468 int i;
2469 __be32 *agfl_bno;
2470
b134e771 2471 agfl_bno = xfs_buf_to_agfl_bno(iocur_top->bp);
18cdb614
ES
2472 i = be32_to_cpu(agf->agf_fllast);
2473
2474 for (;;) {
b8165508 2475 if (++i == libxfs_agfl_size(mp))
18cdb614
ES
2476 i = 0;
2477 if (i == be32_to_cpu(agf->agf_flfirst))
2478 break;
2479 agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
2480 }
2481 iocur_top->need_crc = 1;
2482 }
878afc65 2483 if (write_buf(iocur_top))
d24c0a90 2484 goto pop_out;
61983f67 2485 }
61983f67
BN
2486
2487 /* copy AG free space btrees */
2488 if (agf) {
fb4697dd 2489 if (metadump.show_progress)
61983f67
BN
2490 print_progress("Copying free space trees of AG %u",
2491 agno);
2492 if (!copy_free_bno_btree(agno, agf))
d24c0a90 2493 goto pop_out;
61983f67 2494 if (!copy_free_cnt_btree(agno, agf))
d24c0a90 2495 goto pop_out;
e434854e
DW
2496 if (!copy_rmap_btree(agno, agf))
2497 goto pop_out;
e2756db3
DW
2498 if (!copy_refcount_btree(agno, agf))
2499 goto pop_out;
61983f67
BN
2500 }
2501
2502 /* copy inode btrees and the inodes and their associated metadata */
2503 if (agi) {
2504 if (!copy_inodes(agno, agi))
d24c0a90 2505 goto pop_out;
61983f67 2506 }
d24c0a90
BN
2507 rval = 1;
2508pop_out:
2509 while (stack_count--)
2510 pop_cur();
2511 return rval;
61983f67
BN
2512}
2513
2514static int
2515copy_ino(
2516 xfs_ino_t ino,
2517 typnm_t itype)
2518{
2519 xfs_agnumber_t agno;
2520 xfs_agblock_t agbno;
2521 xfs_agino_t agino;
61983f67 2522 int offset;
a196ca65 2523 int rval = 1;
61983f67 2524
39fe84af 2525 if (ino == 0 || ino == NULLFSINO)
61983f67
BN
2526 return 1;
2527
2528 agno = XFS_INO_TO_AGNO(mp, ino);
2529 agino = XFS_INO_TO_AGINO(mp, ino);
2530 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
2531 offset = XFS_AGINO_TO_OFFSET(mp, agino);
2532
2533 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
2534 offset >= mp->m_sb.sb_inopblock) {
fb4697dd 2535 if (metadump.show_warnings)
61983f67
BN
2536 print_warning("invalid %s inode number (%lld)",
2537 typtab[itype].name, (long long)ino);
2538 return 1;
2539 }
2540
2541 push_cur();
2542 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
2543 blkbb, DB_RING_IGN, NULL);
2544 if (iocur_top->data == NULL) {
2545 print_warning("cannot read %s inode %lld",
2546 typtab[itype].name, (long long)ino);
fb4697dd 2547 rval = !metadump.stop_on_read_error;
d24c0a90 2548 goto pop_out;
61983f67
BN
2549 }
2550 off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
2551
fb4697dd 2552 metadump.cur_ino = ino;
5e656dbb 2553 rval = process_inode_data(iocur_top->data, itype);
d24c0a90
BN
2554pop_out:
2555 pop_cur();
2556 return rval;
61983f67
BN
2557}
2558
2559
2560static int
2561copy_sb_inodes(void)
2562{
2563 if (!copy_ino(mp->m_sb.sb_rbmino, TYP_RTBITMAP))
2564 return 0;
2565
2566 if (!copy_ino(mp->m_sb.sb_rsumino, TYP_RTSUMMARY))
2567 return 0;
2568
2569 if (!copy_ino(mp->m_sb.sb_uquotino, TYP_DQBLK))
2570 return 0;
2571
0340d706
CS
2572 if (!copy_ino(mp->m_sb.sb_gquotino, TYP_DQBLK))
2573 return 0;
2574
2575 return copy_ino(mp->m_sb.sb_pquotino, TYP_DQBLK);
61983f67
BN
2576}
2577
2578static int
2579copy_log(void)
2580{
0ab627db
BF
2581 struct xlog log;
2582 int dirty;
1c12a814
BF
2583 xfs_daddr_t logstart;
2584 int logblocks;
2585 int logversion;
2586 int cycle = XLOG_INIT_CYCLE;
190df617 2587
fb4697dd 2588 if (metadump.show_progress)
61983f67
BN
2589 print_progress("Copying log");
2590
2591 push_cur();
0323bbf6
CB
2592 if (metadump.external_log) {
2593 ASSERT(mp->m_sb.sb_logstart == 0);
2594 set_log_cur(&typtab[TYP_LOG],
2595 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
2596 mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN,
2597 NULL);
2598 } else {
2599 ASSERT(mp->m_sb.sb_logstart != 0);
2600 set_cur(&typtab[TYP_LOG],
2601 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
2602 mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN,
2603 NULL);
2604 }
2605
61983f67 2606 if (iocur_top->data == NULL) {
d24c0a90 2607 pop_cur();
61983f67 2608 print_warning("cannot read log");
fb4697dd 2609 return !metadump.stop_on_read_error;
61983f67 2610 }
190df617 2611
75333d29 2612 /* If not obfuscating or zeroing, just copy the log as it is */
fb4697dd 2613 if (!metadump.obfuscate && !metadump.zero_stale_data)
37a78181
ES
2614 goto done;
2615
c42edb2e 2616 dirty = xlog_is_dirty(mp, &log);
190df617
ES
2617
2618 switch (dirty) {
2619 case 0:
2620 /* clear out a clean log */
fb4697dd 2621 if (metadump.show_progress)
190df617 2622 print_progress("Zeroing clean log");
1c12a814
BF
2623
2624 logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
2625 logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
2660e653
DW
2626 logversion = xfs_has_logv2(mp) ? 2 : 1;
2627 if (xfs_has_crc(mp))
1c12a814
BF
2628 cycle = log.l_curr_cycle + 1;
2629
2630 libxfs_log_clear(NULL, iocur_top->data, logstart, logblocks,
2631 &mp->m_sb.sb_uuid, logversion,
571a78a7 2632 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
190df617
ES
2633 break;
2634 case 1:
2635 /* keep the dirty log */
fb4697dd 2636 if (metadump.obfuscate)
74642d8e 2637 print_warning(
3b3751ab
JT
2638_("Warning: log recovery of an obfuscated metadata image can leak "
2639"unobfuscated metadata and/or cause image corruption. If possible, "
2640"please mount the filesystem to clean the log, or disable obfuscation."));
190df617
ES
2641 break;
2642 case -1:
2643 /* log detection error */
fb4697dd 2644 if (metadump.obfuscate)
74642d8e 2645 print_warning(
190df617
ES
2646_("Could not discern log; image will contain unobfuscated metadata in log."));
2647 break;
2648 }
2649
37a78181 2650done:
878afc65 2651 return !write_buf(iocur_top);
61983f67
BN
2652}
2653
eba3f43e 2654static int
1a5a88ec 2655init_metadump_v1(void)
eba3f43e
CB
2656{
2657 metadump.metablock = (xfs_metablock_t *)calloc(BBSIZE + 1, BBSIZE);
2658 if (metadump.metablock == NULL) {
2659 print_warning("memory allocation failure");
2660 return -1;
2661 }
2662 metadump.metablock->mb_blocklog = BBSHIFT;
46944d20 2663 metadump.metablock->mb_magic = cpu_to_be32(XFS_MD_MAGIC_V1);
eba3f43e
CB
2664
2665 /* Set flags about state of metadump */
2666 metadump.metablock->mb_info = XFS_METADUMP_INFO_FLAGS;
2667 if (metadump.obfuscate)
2668 metadump.metablock->mb_info |= XFS_METADUMP_OBFUSCATED;
2669 if (!metadump.zero_stale_data)
2670 metadump.metablock->mb_info |= XFS_METADUMP_FULLBLOCKS;
2671 if (metadump.dirty_log)
2672 metadump.metablock->mb_info |= XFS_METADUMP_DIRTYLOG;
2673
2674 metadump.block_index = (__be64 *)((char *)metadump.metablock +
2675 sizeof(xfs_metablock_t));
2676 metadump.block_buffer = (char *)(metadump.metablock) + BBSIZE;
2677 metadump.num_indices = (BBSIZE - sizeof(xfs_metablock_t)) / sizeof(__be64);
2678
2679 /*
2680 * A metadump block can hold at most num_indices of BBSIZE sectors;
2681 * do not try to dump a filesystem with a sector size which does not
2682 * fit within num_indices (i.e. within a single metablock).
2683 */
2684 if (mp->m_sb.sb_sectsize > metadump.num_indices * BBSIZE) {
2685 print_warning("Cannot dump filesystem with sector size %u",
2686 mp->m_sb.sb_sectsize);
2687 free(metadump.metablock);
2688 return -1;
2689 }
2690
2691 metadump.cur_index = 0;
2692
2693 return 0;
2694}
2695
1a5a88ec
CB
2696static int
2697finish_dump_metadump_v1(void)
2698{
2699 /*
2700 * write index block and following data blocks (streaming)
2701 */
2702 metadump.metablock->mb_count = cpu_to_be16(metadump.cur_index);
2703 if (fwrite(metadump.metablock, (metadump.cur_index + 1) << BBSHIFT, 1,
2704 metadump.outf) != 1) {
2705 print_warning("error writing to target file");
2706 return -1;
2707 }
2708
2709 memset(metadump.block_index, 0, metadump.num_indices * sizeof(__be64));
2710 metadump.cur_index = 0;
2711 return 0;
2712}
2713
2714static int
2715write_metadump_v1(
2716 enum typnm type,
2717 const char *data,
2718 xfs_daddr_t off,
2719 int len)
2720{
2721 int i;
2722 int ret;
2723
2724 for (i = 0; i < len; i++, off++, data += BBSIZE) {
2725 metadump.block_index[metadump.cur_index] = cpu_to_be64(off);
2726 memcpy(&metadump.block_buffer[metadump.cur_index << BBSHIFT],
2727 data, BBSIZE);
2728 if (++metadump.cur_index == metadump.num_indices) {
2729 ret = finish_dump_metadump_v1();
2730 if (ret)
2731 return -EIO;
2732 }
2733 }
2734
2735 return 0;
2736}
2737
eba3f43e 2738static void
1a5a88ec 2739release_metadump_v1(void)
eba3f43e
CB
2740{
2741 free(metadump.metablock);
2742}
2743
1a5a88ec
CB
2744static struct metadump_ops metadump1_ops = {
2745 .init = init_metadump_v1,
2746 .write = write_metadump_v1,
2747 .finish_dump = finish_dump_metadump_v1,
2748 .release = release_metadump_v1,
2749};
2750
11926582
CB
2751static int
2752init_metadump_v2(void)
2753{
2754 struct xfs_metadump_header xmh = {0};
2755 uint32_t compat_flags = 0;
2756
2757 xmh.xmh_magic = cpu_to_be32(XFS_MD_MAGIC_V2);
2758 xmh.xmh_version = cpu_to_be32(2);
2759
2760 if (metadump.obfuscate)
2761 compat_flags |= XFS_MD2_COMPAT_OBFUSCATED;
2762 if (!metadump.zero_stale_data)
2763 compat_flags |= XFS_MD2_COMPAT_FULLBLOCKS;
2764 if (metadump.dirty_log)
2765 compat_flags |= XFS_MD2_COMPAT_DIRTYLOG;
0323bbf6
CB
2766 if (metadump.external_log)
2767 compat_flags |= XFS_MD2_COMPAT_EXTERNALLOG;
11926582
CB
2768
2769 xmh.xmh_compat_flags = cpu_to_be32(compat_flags);
2770
2771 if (fwrite(&xmh, sizeof(xmh), 1, metadump.outf) != 1) {
2772 print_warning("error writing to target file");
2773 return -1;
2774 }
2775
2776 return 0;
2777}
2778
2779static int
2780write_metadump_v2(
2781 enum typnm type,
2782 const char *data,
2783 xfs_daddr_t off,
2784 int len)
2785{
2786 struct xfs_meta_extent xme;
2787 uint64_t addr;
2788
2789 addr = off;
2790 if (type == TYP_LOG &&
2791 mp->m_logdev_targp->bt_bdev != mp->m_ddev_targp->bt_bdev)
2792 addr |= XME_ADDR_LOG_DEVICE;
2793 else
2794 addr |= XME_ADDR_DATA_DEVICE;
2795
2796 xme.xme_addr = cpu_to_be64(addr);
2797 xme.xme_len = cpu_to_be32(len);
2798
2799 if (fwrite(&xme, sizeof(xme), 1, metadump.outf) != 1) {
2800 print_warning("error writing to target file");
2801 return -EIO;
2802 }
2803
2804 if (fwrite(data, len << BBSHIFT, 1, metadump.outf) != 1) {
2805 print_warning("error writing to target file");
2806 return -EIO;
2807 }
2808
2809 return 0;
2810}
2811
2812static struct metadump_ops metadump2_ops = {
2813 .init = init_metadump_v2,
2814 .write = write_metadump_v2,
2815};
2816
61983f67
BN
2817static int
2818metadump_f(
2819 int argc,
2820 char **argv)
2821{
2822 xfs_agnumber_t agno;
2823 int c;
2824 int start_iocur_sp;
449df236
DW
2825 int outfd = -1;
2826 int ret;
88b8e1d6 2827 char *p;
0323bbf6 2828 bool version_opt_set = false;
61983f67
BN
2829
2830 exitcode = 1;
fb4697dd
CB
2831
2832 metadump.version = 1;
2833 metadump.show_progress = false;
2834 metadump.stop_on_read_error = false;
2835 metadump.max_extent_size = DEFAULT_MAX_EXT_SIZE;
2836 metadump.show_warnings = false;
2837 metadump.obfuscate = true;
2838 metadump.zero_stale_data = true;
2839 metadump.dirty_log = false;
0323bbf6 2840 metadump.external_log = false;
61983f67
BN
2841
2842 if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
2843 print_warning("bad superblock magic number %x, giving up",
2844 mp->m_sb.sb_magicnum);
2845 return 0;
2846 }
2847
a547152d
ES
2848 /*
2849 * on load, we sanity-checked agcount and possibly set to 1
2850 * if it was corrupted and large.
2851 */
2852 if (mp->m_sb.sb_agcount == 1 &&
2853 XFS_MAX_DBLOCKS(&mp->m_sb) < mp->m_sb.sb_dblocks) {
2854 print_warning("truncated agcount, giving up");
2855 return 0;
2856 }
2857
0323bbf6 2858 while ((c = getopt(argc, argv, "aegm:ov:w")) != EOF) {
61983f67 2859 switch (c) {
b09e839e 2860 case 'a':
fb4697dd 2861 metadump.zero_stale_data = false;
b09e839e 2862 break;
61983f67 2863 case 'e':
fb4697dd 2864 metadump.stop_on_read_error = true;
61983f67
BN
2865 break;
2866 case 'g':
fb4697dd 2867 metadump.show_progress = true;
61983f67 2868 break;
88b8e1d6 2869 case 'm':
fb4697dd
CB
2870 metadump.max_extent_size =
2871 (int)strtol(optarg, &p, 0);
2872 if (*p != '\0' ||
2873 metadump.max_extent_size <= 0) {
88b8e1d6
BN
2874 print_warning("bad max extent size %s",
2875 optarg);
2876 return 0;
2877 }
2878 break;
61983f67 2879 case 'o':
fb4697dd 2880 metadump.obfuscate = false;
61983f67 2881 break;
0323bbf6
CB
2882 case 'v':
2883 metadump.version = (int)strtol(optarg, &p, 0);
2884 if (*p != '\0' ||
2885 (metadump.version != 1 &&
2886 metadump.version != 2)) {
2887 print_warning("bad metadump version: %s",
2888 optarg);
2889 return 0;
2890 }
2891 version_opt_set = true;
2892 break;
61983f67 2893 case 'w':
fb4697dd 2894 metadump.show_warnings = true;
61983f67
BN
2895 break;
2896 default:
2897 print_warning("bad option for metadump command");
2898 return 0;
2899 }
2900 }
2901
2902 if (optind != argc - 1) {
2903 print_warning("too few options for metadump (no filename given)");
2904 return 0;
2905 }
2906
0323bbf6
CB
2907 if (mp->m_logdev_targp->bt_bdev != mp->m_ddev_targp->bt_bdev)
2908 metadump.external_log = true;
2909
2910 if (metadump.external_log && !version_opt_set)
2911 metadump.version = 2;
2912
2913 if (metadump.version == 2 && mp->m_sb.sb_logstart == 0 &&
2914 !metadump.external_log) {
2915 print_warning("external log device not loaded, use -l");
2916 return 1;
2917 }
2918
2919 /*
2920 * If we'll copy the log, see if the log is dirty.
2921 *
2922 * Metadump v1 does not support dumping the contents of an external
2923 * log. Hence we skip the dirty log check.
2924 */
2925 if (!(metadump.version == 1 && metadump.external_log)) {
2291c68b 2926 push_cur();
0323bbf6
CB
2927 if (metadump.external_log) {
2928 ASSERT(mp->m_sb.sb_logstart == 0);
2929 set_log_cur(&typtab[TYP_LOG],
2930 XFS_FSB_TO_DADDR(mp,
2931 mp->m_sb.sb_logstart),
2932 mp->m_sb.sb_logblocks * blkbb,
2933 DB_RING_IGN, NULL);
2934 } else {
2935 ASSERT(mp->m_sb.sb_logstart != 0);
2936 set_cur(&typtab[TYP_LOG],
2937 XFS_FSB_TO_DADDR(mp,
2938 mp->m_sb.sb_logstart),
2939 mp->m_sb.sb_logblocks * blkbb,
2940 DB_RING_IGN, NULL);
2941 }
2942
2291c68b
ES
2943 if (iocur_top->data) { /* best effort */
2944 struct xlog log;
2945
c42edb2e 2946 if (xlog_is_dirty(mp, &log))
fb4697dd 2947 metadump.dirty_log = true;
2291c68b
ES
2948 }
2949 pop_cur();
2950 }
2951
61983f67
BN
2952 start_iocur_sp = iocur_sp;
2953
2954 if (strcmp(argv[optind], "-") == 0) {
2955 if (isatty(fileno(stdout))) {
2956 print_warning("cannot write to a terminal");
eba3f43e 2957 goto out;
61983f67 2958 }
4944defa
DW
2959 /*
2960 * Redirect stdout to stderr for the duration of the
2961 * metadump operation so that dbprintf and other messages
2962 * are sent to the console instead of polluting the
2963 * metadump stream.
449df236
DW
2964 *
2965 * We get to do this the hard way because musl doesn't
2966 * allow reassignment of stdout.
4944defa 2967 */
449df236
DW
2968 fflush(stdout);
2969 outfd = dup(STDOUT_FILENO);
2970 if (outfd < 0) {
2971 perror("opening dump stream");
2972 goto out;
2973 }
2974 ret = dup2(STDERR_FILENO, STDOUT_FILENO);
2975 if (ret < 0) {
2976 perror("redirecting stdout");
2977 close(outfd);
2978 goto out;
2979 }
fb4697dd
CB
2980 metadump.outf = fdopen(outfd, "a");
2981 if (metadump.outf == NULL) {
449df236
DW
2982 fprintf(stderr, "cannot create dump stream\n");
2983 dup2(outfd, STDOUT_FILENO);
2984 close(outfd);
2985 goto out;
2986 }
fb4697dd 2987 metadump.stdout_metadump = true;
61983f67 2988 } else {
fb4697dd
CB
2989 metadump.outf = fopen(argv[optind], "wb");
2990 if (metadump.outf == NULL) {
61983f67 2991 print_warning("cannot create dump file");
449df236 2992 goto out;
61983f67
BN
2993 }
2994 }
2995
11926582
CB
2996 if (metadump.version == 1)
2997 metadump.mdops = &metadump1_ops;
2998 else
2999 metadump.mdops = &metadump2_ops;
1a5a88ec
CB
3000
3001 ret = metadump.mdops->init();
1e470277
CB
3002 if (ret)
3003 goto out;
3004
61983f67
BN
3005 exitcode = 0;
3006
3007 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
3008 if (!scan_ag(agno)) {
3009 exitcode = 1;
3010 break;
3011 }
3012 }
3013
3014 /* copy realtime and quota inode contents */
3015 if (!exitcode)
3016 exitcode = !copy_sb_inodes();
3017
0323bbf6
CB
3018 /* copy log */
3019 if (!exitcode && !(metadump.version == 1 && metadump.external_log))
61983f67
BN
3020 exitcode = !copy_log();
3021
3022 /* write the remaining index */
11926582 3023 if (!exitcode && metadump.mdops->finish_dump)
1a5a88ec 3024 exitcode = metadump.mdops->finish_dump() < 0;
61983f67 3025
fb4697dd
CB
3026 if (metadump.progress_since_warning)
3027 fputc('\n', metadump.stdout_metadump ? stderr : stdout);
61983f67 3028
fb4697dd
CB
3029 if (metadump.stdout_metadump) {
3030 fflush(metadump.outf);
449df236
DW
3031 fflush(stdout);
3032 ret = dup2(outfd, STDOUT_FILENO);
3033 if (ret < 0)
3034 perror("un-redirecting stdout");
fb4697dd 3035 metadump.stdout_metadump = false;
449df236 3036 }
fb4697dd 3037 fclose(metadump.outf);
61983f67
BN
3038
3039 /* cleanup iocur stack */
3040 while (iocur_sp > start_iocur_sp)
3041 pop_cur();
1e470277 3042
11926582
CB
3043 if (metadump.mdops->release)
3044 metadump.mdops->release();
61983f67 3045
1e470277 3046out:
61983f67
BN
3047 return 0;
3048}