]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/metadump.c
metadump: Introduce metadump v1 operations
[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,
b09e839e 41 N_("[-a] [-e] [-g] [-m max_extent] [-w] [-o] 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;
78 bool stdout_metadump;
79 xfs_ino_t cur_ino;
80 /* Metadump file */
81 FILE *outf;
be75f7d7 82 struct metadump_ops *mdops;
fb4697dd
CB
83 /* header + index + buffers */
84 struct xfs_metablock *metablock;
85 __be64 *block_index;
86 char *block_buffer;
87 int num_indices;
88 int cur_index;
89} metadump;
61983f67
BN
90
91void
92metadump_init(void)
93{
94 add_command(&metadump_cmd);
95}
96
97static void
98metadump_help(void)
99{
9ee7055c 100 dbprintf(_(
61983f67
BN
101"\n"
102" The 'metadump' command dumps the known metadata to a compact file suitable\n"
103" for compressing and sending to an XFS maintainer for corruption analysis \n"
104" or xfs_repair failures.\n\n"
88b8e1d6 105" Options:\n"
b09e839e 106" -a -- Copy full metadata blocks without zeroing unused space\n"
61983f67
BN
107" -e -- Ignore read errors and keep going\n"
108" -g -- Display dump progress\n"
7431d134 109" -m -- Specify max extent size in blocks to copy (default = %d blocks)\n"
61983f67
BN
110" -o -- Don't obfuscate names and extended attributes\n"
111" -w -- Show warnings of bad metadata information\n"
9ee7055c 112"\n"), DEFAULT_MAX_EXT_SIZE);
61983f67
BN
113}
114
115static void
116print_warning(const char *fmt, ...)
117{
118 char buf[200];
119 va_list ap;
120
121 if (seenint())
122 return;
123
124 va_start(ap, fmt);
125 vsnprintf(buf, sizeof(buf), fmt, ap);
126 va_end(ap);
127 buf[sizeof(buf)-1] = '\0';
128
fb4697dd
CB
129 fprintf(stderr, "%s%s: %s\n",
130 metadump.progress_since_warning ? "\n" : "",
61983f67 131 progname, buf);
fb4697dd 132 metadump.progress_since_warning = false;
61983f67
BN
133}
134
135static void
136print_progress(const char *fmt, ...)
137{
138 char buf[60];
139 va_list ap;
140 FILE *f;
141
142 if (seenint())
143 return;
144
145 va_start(ap, fmt);
146 vsnprintf(buf, sizeof(buf), fmt, ap);
147 va_end(ap);
148 buf[sizeof(buf)-1] = '\0';
149
fb4697dd 150 f = metadump.stdout_metadump ? stderr : stdout;
61983f67
BN
151 fprintf(f, "\r%-59s", buf);
152 fflush(f);
fb4697dd 153 metadump.progress_since_warning = true;
61983f67
BN
154}
155
fd491857
DC
156/*
157 * we want to preserve the state of the metadata in the dump - whether it is
158 * intact or corrupt, so even if the buffer has a verifier attached to it we
159 * don't want to run it prior to writing the buffer to the metadump image.
160 *
161 * The only reason for running the verifier is to recalculate the CRCs on a
162 * buffer that has been obfuscated. i.e. a buffer than metadump modified itself.
163 * In this case, we only run the verifier if the buffer was not corrupt to begin
164 * with so that we don't accidentally correct buffers with CRC or errors in them
165 * when we are obfuscating them.
166 */
61983f67
BN
167static int
168write_buf(
169 iocur_t *buf)
170{
fd491857 171 struct xfs_buf *bp = buf->bp;
61983f67 172 int i;
878afc65 173 int ret;
61983f67 174
8ab75c4d
DC
175 /*
176 * Run the write verifier to recalculate the buffer CRCs and check
fd491857
DC
177 * metadump didn't introduce a new corruption. Warn if the verifier
178 * failed, but still continue to dump it into the output file.
8ab75c4d 179 */
fd491857
DC
180 if (buf->need_crc && bp && bp->b_ops && !bp->b_error) {
181 bp->b_ops->verify_write(bp);
182 if (bp->b_error) {
183 print_warning(
a3fac935
ES
184 "obfuscation corrupted block at %s bno 0x%llx/0x%x",
185 bp->b_ops->name,
f1208396 186 (long long)xfs_buf_daddr(bp), BBTOB(bp->b_length));
8ab75c4d
DC
187 }
188 }
189
1516a5b5
DC
190 /* handle discontiguous buffers */
191 if (!buf->bbmap) {
1a5a88ec
CB
192 ret = metadump.mdops->write(buf->typ->typnm, buf->data, buf->bb,
193 buf->blen);
1516a5b5
DC
194 if (ret)
195 return ret;
196 } else {
197 int len = 0;
198 for (i = 0; i < buf->bbmap->nmaps; i++) {
1a5a88ec
CB
199 ret = metadump.mdops->write(buf->typ->typnm,
200 buf->data + BBTOB(len),
201 buf->bbmap->b[i].bm_bn,
202 buf->bbmap->b[i].bm_len);
878afc65
DC
203 if (ret)
204 return ret;
1516a5b5 205 len += buf->bbmap->b[i].bm_len;
61983f67
BN
206 }
207 }
878afc65 208 return seenint() ? -EINTR : 0;
61983f67
BN
209}
210
6058426f
DC
211/*
212 * We could be processing a corrupt block, so we can't trust any of
213 * the offsets or lengths to be within the buffer range. Hence check
214 * carefully!
215 */
20f35ef4
ES
216static void
217zero_btree_node(
218 struct xfs_btree_block *block,
219 typnm_t btype)
220{
221 int nrecs;
222 xfs_bmbt_ptr_t *bpp;
223 xfs_bmbt_key_t *bkp;
224 xfs_inobt_ptr_t *ipp;
225 xfs_inobt_key_t *ikp;
226 xfs_alloc_ptr_t *app;
227 xfs_alloc_key_t *akp;
a7302f83
DC
228 char *zp1, *zp2;
229 char *key_end;
e7fd2b6f 230 struct xfs_ino_geometry *igeo = M_IGEO(mp);
20f35ef4
ES
231
232 nrecs = be16_to_cpu(block->bb_numrecs);
6058426f
DC
233 if (nrecs < 0)
234 return;
20f35ef4
ES
235
236 switch (btype) {
237 case TYP_BMAPBTA:
238 case TYP_BMAPBTD:
6058426f
DC
239 if (nrecs > mp->m_bmap_dmxr[1])
240 return;
241
20f35ef4
ES
242 bkp = XFS_BMBT_KEY_ADDR(mp, block, 1);
243 bpp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
a7302f83
DC
244 zp1 = (char *)&bkp[nrecs];
245 zp2 = (char *)&bpp[nrecs];
246 key_end = (char *)bpp;
20f35ef4
ES
247 break;
248 case TYP_INOBT:
249 case TYP_FINOBT:
e7fd2b6f 250 if (nrecs > igeo->inobt_mxr[1])
6058426f
DC
251 return;
252
20f35ef4 253 ikp = XFS_INOBT_KEY_ADDR(mp, block, 1);
e7fd2b6f 254 ipp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
a7302f83
DC
255 zp1 = (char *)&ikp[nrecs];
256 zp2 = (char *)&ipp[nrecs];
257 key_end = (char *)ipp;
20f35ef4
ES
258 break;
259 case TYP_BNOBT:
260 case TYP_CNTBT:
6058426f
DC
261 if (nrecs > mp->m_alloc_mxr[1])
262 return;
263
20f35ef4
ES
264 akp = XFS_ALLOC_KEY_ADDR(mp, block, 1);
265 app = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
a7302f83
DC
266 zp1 = (char *)&akp[nrecs];
267 zp2 = (char *)&app[nrecs];
268 key_end = (char *)app;
20f35ef4
ES
269 break;
270 default:
a7302f83 271 return;
20f35ef4
ES
272 }
273
a7302f83
DC
274
275 /* Zero from end of keys to beginning of pointers */
276 memset(zp1, 0, key_end - zp1);
277
278 /* Zero from end of pointers to end of block */
279 memset(zp2, 0, (char *)block + mp->m_sb.sb_blocksize - zp2);
20f35ef4
ES
280}
281
6058426f
DC
282/*
283 * We could be processing a corrupt block, so we can't trust any of
284 * the offsets or lengths to be within the buffer range. Hence check
285 * carefully!
286 */
20f35ef4
ES
287static void
288zero_btree_leaf(
289 struct xfs_btree_block *block,
290 typnm_t btype)
291{
292 int nrecs;
293 struct xfs_bmbt_rec *brp;
294 struct xfs_inobt_rec *irp;
295 struct xfs_alloc_rec *arp;
a7302f83 296 char *zp;
20f35ef4
ES
297
298 nrecs = be16_to_cpu(block->bb_numrecs);
6058426f
DC
299 if (nrecs < 0)
300 return;
20f35ef4
ES
301
302 switch (btype) {
303 case TYP_BMAPBTA:
304 case TYP_BMAPBTD:
6058426f
DC
305 if (nrecs > mp->m_bmap_dmxr[0])
306 return;
307
20f35ef4 308 brp = XFS_BMBT_REC_ADDR(mp, block, 1);
a7302f83 309 zp = (char *)&brp[nrecs];
20f35ef4
ES
310 break;
311 case TYP_INOBT:
312 case TYP_FINOBT:
e7fd2b6f 313 if (nrecs > M_IGEO(mp)->inobt_mxr[0])
6058426f
DC
314 return;
315
20f35ef4 316 irp = XFS_INOBT_REC_ADDR(mp, block, 1);
a7302f83 317 zp = (char *)&irp[nrecs];
20f35ef4
ES
318 break;
319 case TYP_BNOBT:
320 case TYP_CNTBT:
6058426f
DC
321 if (nrecs > mp->m_alloc_mxr[0])
322 return;
323
20f35ef4 324 arp = XFS_ALLOC_REC_ADDR(mp, block, 1);
a7302f83 325 zp = (char *)&arp[nrecs];
20f35ef4
ES
326 break;
327 default:
a7302f83 328 return;
20f35ef4
ES
329 }
330
331 /* Zero from end of records to end of block */
a7302f83 332 memset(zp, 0, (char *)block + mp->m_sb.sb_blocksize - zp);
20f35ef4
ES
333}
334
335static void
336zero_btree_block(
337 struct xfs_btree_block *block,
338 typnm_t btype)
339{
340 int level;
341
342 level = be16_to_cpu(block->bb_level);
343
344 if (level > 0)
345 zero_btree_node(block, btype);
346 else
347 zero_btree_leaf(block, btype);
348}
61983f67
BN
349
350static int
351scan_btree(
352 xfs_agnumber_t agno,
353 xfs_agblock_t agbno,
354 int level,
355 typnm_t btype,
356 void *arg,
b194c7d8 357 int (*func)(struct xfs_btree_block *block,
61983f67
BN
358 xfs_agnumber_t agno,
359 xfs_agblock_t agbno,
360 int level,
361 typnm_t btype,
362 void *arg))
363{
d24c0a90
BN
364 int rval = 0;
365
61983f67
BN
366 push_cur();
367 set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb,
368 DB_RING_IGN, NULL);
369 if (iocur_top->data == NULL) {
370 print_warning("cannot read %s block %u/%u", typtab[btype].name,
371 agno, agbno);
fb4697dd 372 rval = !metadump.stop_on_read_error;
d24c0a90 373 goto pop_out;
61983f67 374 }
20f35ef4 375
fb4697dd 376 if (metadump.zero_stale_data) {
20f35ef4
ES
377 zero_btree_block(iocur_top->data, btype);
378 iocur_top->need_crc = 1;
379 }
380
878afc65 381 if (write_buf(iocur_top))
d24c0a90 382 goto pop_out;
61983f67
BN
383
384 if (!(*func)(iocur_top->data, agno, agbno, level - 1, btype, arg))
d24c0a90
BN
385 goto pop_out;
386 rval = 1;
387pop_out:
61983f67 388 pop_cur();
d24c0a90 389 return rval;
61983f67
BN
390}
391
392/* free space tree copy routines */
393
394static int
395valid_bno(
61983f67 396 xfs_agnumber_t agno,
88b8e1d6 397 xfs_agblock_t agbno)
61983f67 398{
88b8e1d6
BN
399 if (agno < (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
400 agbno <= mp->m_sb.sb_agblocks)
401 return 1;
402 if (agno == (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
403 agbno <= (mp->m_sb.sb_dblocks -
5a35bf2c 404 (xfs_rfsblock_t)(mp->m_sb.sb_agcount - 1) *
66be354e 405 mp->m_sb.sb_agblocks))
61983f67
BN
406 return 1;
407
61983f67
BN
408 return 0;
409}
410
88b8e1d6 411
61983f67
BN
412static int
413scanfunc_freesp(
b194c7d8 414 struct xfs_btree_block *block,
61983f67
BN
415 xfs_agnumber_t agno,
416 xfs_agblock_t agbno,
417 int level,
418 typnm_t btype,
419 void *arg)
420{
421 xfs_alloc_ptr_t *pp;
422 int i;
88b8e1d6 423 int numrecs;
61983f67
BN
424
425 if (level == 0)
426 return 1;
427
b194c7d8 428 numrecs = be16_to_cpu(block->bb_numrecs);
88b8e1d6 429 if (numrecs > mp->m_alloc_mxr[1]) {
fb4697dd 430 if (metadump.show_warnings)
88b8e1d6
BN
431 print_warning("invalid numrecs (%u) in %s block %u/%u",
432 numrecs, typtab[btype].name, agno, agbno);
61983f67
BN
433 return 1;
434 }
435
b3563c19 436 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
88b8e1d6
BN
437 for (i = 0; i < numrecs; i++) {
438 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 439 if (metadump.show_warnings)
88b8e1d6
BN
440 print_warning("invalid block number (%u/%u) "
441 "in %s block %u/%u",
442 agno, be32_to_cpu(pp[i]),
443 typtab[btype].name, agno, agbno);
61983f67 444 continue;
88b8e1d6 445 }
61983f67
BN
446 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
447 scanfunc_freesp))
448 return 0;
449 }
450 return 1;
451}
452
453static int
454copy_free_bno_btree(
455 xfs_agnumber_t agno,
456 xfs_agf_t *agf)
457{
458 xfs_agblock_t root;
459 int levels;
460
461 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
462 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
463
464 /* validate root and levels before processing the tree */
465 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 466 if (metadump.show_warnings)
61983f67
BN
467 print_warning("invalid block number (%u) in bnobt "
468 "root in agf %u", root, agno);
469 return 1;
470 }
716b497a 471 if (levels > mp->m_alloc_maxlevels) {
fb4697dd 472 if (metadump.show_warnings)
61983f67
BN
473 print_warning("invalid level (%u) in bnobt root "
474 "in agf %u", levels, agno);
475 return 1;
476 }
477
478 return scan_btree(agno, root, levels, TYP_BNOBT, agf, scanfunc_freesp);
479}
480
481static int
482copy_free_cnt_btree(
483 xfs_agnumber_t agno,
484 xfs_agf_t *agf)
485{
486 xfs_agblock_t root;
487 int levels;
488
489 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
490 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
491
492 /* validate root and levels before processing the tree */
493 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 494 if (metadump.show_warnings)
61983f67
BN
495 print_warning("invalid block number (%u) in cntbt "
496 "root in agf %u", root, agno);
497 return 1;
498 }
716b497a 499 if (levels > mp->m_alloc_maxlevels) {
fb4697dd 500 if (metadump.show_warnings)
61983f67
BN
501 print_warning("invalid level (%u) in cntbt root "
502 "in agf %u", levels, agno);
503 return 1;
504 }
505
506 return scan_btree(agno, root, levels, TYP_CNTBT, agf, scanfunc_freesp);
507}
508
e434854e
DW
509static int
510scanfunc_rmapbt(
511 struct xfs_btree_block *block,
512 xfs_agnumber_t agno,
513 xfs_agblock_t agbno,
514 int level,
515 typnm_t btype,
516 void *arg)
517{
518 xfs_rmap_ptr_t *pp;
519 int i;
520 int numrecs;
521
522 if (level == 0)
523 return 1;
524
525 numrecs = be16_to_cpu(block->bb_numrecs);
526 if (numrecs > mp->m_rmap_mxr[1]) {
fb4697dd 527 if (metadump.show_warnings)
e434854e
DW
528 print_warning("invalid numrecs (%u) in %s block %u/%u",
529 numrecs, typtab[btype].name, agno, agbno);
530 return 1;
531 }
532
533 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
534 for (i = 0; i < numrecs; i++) {
535 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 536 if (metadump.show_warnings)
e434854e
DW
537 print_warning("invalid block number (%u/%u) "
538 "in %s block %u/%u",
539 agno, be32_to_cpu(pp[i]),
540 typtab[btype].name, agno, agbno);
541 continue;
542 }
543 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
544 scanfunc_rmapbt))
545 return 0;
546 }
547 return 1;
548}
549
550static int
551copy_rmap_btree(
552 xfs_agnumber_t agno,
553 struct xfs_agf *agf)
554{
555 xfs_agblock_t root;
556 int levels;
557
2660e653 558 if (!xfs_has_rmapbt(mp))
e434854e
DW
559 return 1;
560
561 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
562 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
563
564 /* validate root and levels before processing the tree */
565 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 566 if (metadump.show_warnings)
e434854e
DW
567 print_warning("invalid block number (%u) in rmapbt "
568 "root in agf %u", root, agno);
569 return 1;
570 }
716b497a 571 if (levels > mp->m_rmap_maxlevels) {
fb4697dd 572 if (metadump.show_warnings)
e434854e
DW
573 print_warning("invalid level (%u) in rmapbt root "
574 "in agf %u", levels, agno);
575 return 1;
576 }
577
578 return scan_btree(agno, root, levels, TYP_RMAPBT, agf, scanfunc_rmapbt);
579}
580
e2756db3
DW
581static int
582scanfunc_refcntbt(
583 struct xfs_btree_block *block,
584 xfs_agnumber_t agno,
585 xfs_agblock_t agbno,
586 int level,
587 typnm_t btype,
588 void *arg)
589{
590 xfs_refcount_ptr_t *pp;
591 int i;
592 int numrecs;
593
594 if (level == 0)
595 return 1;
596
597 numrecs = be16_to_cpu(block->bb_numrecs);
598 if (numrecs > mp->m_refc_mxr[1]) {
fb4697dd 599 if (metadump.show_warnings)
e2756db3
DW
600 print_warning("invalid numrecs (%u) in %s block %u/%u",
601 numrecs, typtab[btype].name, agno, agbno);
602 return 1;
603 }
604
605 pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
606 for (i = 0; i < numrecs; i++) {
607 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
fb4697dd 608 if (metadump.show_warnings)
e2756db3
DW
609 print_warning("invalid block number (%u/%u) "
610 "in %s block %u/%u",
611 agno, be32_to_cpu(pp[i]),
612 typtab[btype].name, agno, agbno);
613 continue;
614 }
615 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
616 scanfunc_refcntbt))
617 return 0;
618 }
619 return 1;
620}
621
622static int
623copy_refcount_btree(
624 xfs_agnumber_t agno,
625 struct xfs_agf *agf)
626{
627 xfs_agblock_t root;
628 int levels;
629
2660e653 630 if (!xfs_has_reflink(mp))
e2756db3
DW
631 return 1;
632
633 root = be32_to_cpu(agf->agf_refcount_root);
634 levels = be32_to_cpu(agf->agf_refcount_level);
635
636 /* validate root and levels before processing the tree */
637 if (root == 0 || root > mp->m_sb.sb_agblocks) {
fb4697dd 638 if (metadump.show_warnings)
e2756db3
DW
639 print_warning("invalid block number (%u) in refcntbt "
640 "root in agf %u", root, agno);
641 return 1;
642 }
716b497a 643 if (levels > mp->m_refc_maxlevels) {
fb4697dd 644 if (metadump.show_warnings)
e2756db3
DW
645 print_warning("invalid level (%u) in refcntbt root "
646 "in agf %u", levels, agno);
647 return 1;
648 }
649
650 return scan_btree(agno, root, levels, TYP_REFCBT, agf, scanfunc_refcntbt);
651}
652
61983f67
BN
653/* filename and extended attribute obfuscation routines */
654
78027d48 655struct name_ent {
61983f67
BN
656 struct name_ent *next;
657 xfs_dahash_t hash;
78027d48 658 int namelen;
02211695 659 unsigned char name[1];
78027d48 660};
61983f67
BN
661
662#define NAME_TABLE_SIZE 4096
663
a85f8b0a 664static struct name_ent *nametable[NAME_TABLE_SIZE];
61983f67
BN
665
666static void
a85f8b0a 667nametable_clear(void)
61983f67 668{
a85f8b0a 669 int i;
78027d48 670 struct name_ent *ent;
61983f67
BN
671
672 for (i = 0; i < NAME_TABLE_SIZE; i++) {
a85f8b0a
AE
673 while ((ent = nametable[i])) {
674 nametable[i] = ent->next;
675 free(ent);
61983f67
BN
676 }
677 }
678}
679
a85f8b0a
AE
680/*
681 * See if the given name is already in the name table. If so,
682 * return a pointer to its entry, otherwise return a null pointer.
683 */
684static struct name_ent *
02211695 685nametable_find(xfs_dahash_t hash, int namelen, unsigned char *name)
a85f8b0a
AE
686{
687 struct name_ent *ent;
688
689 for (ent = nametable[hash % NAME_TABLE_SIZE]; ent; ent = ent->next) {
690 if (ent->hash == hash && ent->namelen == namelen &&
691 !memcmp(ent->name, name, namelen))
692 return ent;
693 }
694 return NULL;
695}
696
697/*
698 * Add the given name to the name table. Returns a pointer to the
699 * name's new entry, or a null pointer if an error occurs.
700 */
701static struct name_ent *
02211695 702nametable_add(xfs_dahash_t hash, int namelen, unsigned char *name)
a85f8b0a
AE
703{
704 struct name_ent *ent;
705
706 ent = malloc(sizeof *ent + namelen);
707 if (!ent)
708 return NULL;
709
710 ent->namelen = namelen;
711 memcpy(ent->name, name, namelen);
712 ent->hash = hash;
713 ent->next = nametable[hash % NAME_TABLE_SIZE];
714
715 nametable[hash % NAME_TABLE_SIZE] = ent;
716
717 return ent;
718}
61983f67 719
56281ed4
AE
720#define ORPHANAGE "lost+found"
721#define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1)
722
723static inline int
724is_orphanage_dir(
725 struct xfs_mount *mp,
726 xfs_ino_t dir_ino,
727 size_t name_len,
02211695 728 unsigned char *name)
56281ed4
AE
729{
730 return dir_ino == mp->m_sb.sb_rootino &&
731 name_len == ORPHANAGE_LEN &&
732 !memcmp(name, ORPHANAGE, ORPHANAGE_LEN);
733}
734
735/*
736 * Determine whether a name is one we shouldn't obfuscate because
737 * it's an orphan (or the "lost+found" directory itself). Note
738 * "cur_ino" is the inode for the directory currently being
739 * processed.
740 *
741 * Returns 1 if the name should NOT be obfuscated or 0 otherwise.
742 */
61983f67 743static int
56281ed4 744in_lost_found(
61983f67
BN
745 xfs_ino_t ino,
746 int namelen,
02211695 747 unsigned char *name)
61983f67
BN
748{
749 static xfs_ino_t orphanage_ino = 0;
56281ed4 750 char s[24]; /* 21 is enough (64 bits in decimal) */
61983f67
BN
751 int slen;
752
56281ed4
AE
753 /* Record the "lost+found" inode if we haven't done so already */
754
755 ASSERT(ino != 0);
fb4697dd
CB
756 if (!orphanage_ino && is_orphanage_dir(mp, metadump.cur_ino, namelen,
757 name))
56281ed4
AE
758 orphanage_ino = ino;
759
760 /* We don't obfuscate the "lost+found" directory itself */
761
762 if (ino == orphanage_ino)
61983f67
BN
763 return 1;
764
56281ed4
AE
765 /* Most files aren't in "lost+found" at all */
766
fb4697dd 767 if (metadump.cur_ino != orphanage_ino)
61983f67
BN
768 return 0;
769
770 /*
56281ed4
AE
771 * Within "lost+found", we don't obfuscate any file whose
772 * name is the same as its inode number. Any others are
773 * stray files and can be obfuscated.
61983f67 774 */
56281ed4 775 slen = snprintf(s, sizeof (s), "%llu", (unsigned long long) ino);
61983f67 776
56281ed4 777 return slen == namelen && !memcmp(name, s, namelen);
61983f67
BN
778}
779
fcb63670
AE
780/*
781 * Look up the given name in the name table. If it is already
1167ddc4
AE
782 * present, iterate through a well-defined sequence of alternate
783 * names and attempt to use an alternate name instead.
fcb63670
AE
784 *
785 * Returns 1 if the (possibly modified) name is not present in the
1167ddc4
AE
786 * name table. Returns 0 if the name and all possible alternates
787 * are already in the table.
fcb63670
AE
788 */
789static int
02211695 790handle_duplicate_name(xfs_dahash_t hash, size_t name_len, unsigned char *name)
fcb63670 791{
02211695 792 unsigned char new_name[name_len + 1];
1167ddc4 793 uint32_t seq = 1;
fcb63670
AE
794
795 if (!nametable_find(hash, name_len, name))
1167ddc4 796 return 1; /* No duplicate */
fcb63670
AE
797
798 /* Name is already in use. Need to find an alternate. */
799
800 do {
1167ddc4 801 int found;
fcb63670 802
1167ddc4
AE
803 /* Only change incoming name if we find an alternate */
804 do {
805 memcpy(new_name, name, name_len);
806 found = find_alternate(name_len, new_name, seq++);
807 if (found < 0)
808 return 0; /* No more to check */
809 } while (!found);
810 } while (nametable_find(hash, name_len, new_name));
fcb63670 811
1167ddc4
AE
812 /*
813 * The alternate wasn't in the table already. Pass it back
814 * to the caller.
815 */
816 memcpy(name, new_name, name_len);
817
818 return 1;
fcb63670
AE
819}
820
10a01bcd
DW
821static inline xfs_dahash_t
822dirattr_hashname(
823 bool is_dirent,
824 const uint8_t *name,
825 int namelen)
826{
827 if (is_dirent) {
828 struct xfs_name xname = {
829 .name = name,
830 .len = namelen,
831 };
832
833 return libxfs_dir2_hashname(mp, &xname);
834 }
835
836 return libxfs_da_hashname(name, namelen);
837}
838
da7daaf2
AE
839static void
840generate_obfuscated_name(
841 xfs_ino_t ino,
842 int namelen,
02211695 843 unsigned char *name)
da7daaf2
AE
844{
845 xfs_dahash_t hash;
da7daaf2 846
56281ed4
AE
847 /*
848 * We don't obfuscate "lost+found" or any orphan files
849 * therein. When the name table is used for extended
850 * attributes, the inode number provided is 0, in which
851 * case we don't need to make this check.
852 */
853 if (ino && in_lost_found(ino, namelen, name))
854 return;
61983f67 855
ad6bb839 856 /*
fcb63670
AE
857 * If the name starts with a slash, just skip over it. It
858 * isn't included in the hash and we don't record it in the
859 * name table. Note that the namelen value passed in does
860 * not count the leading slash (if one is present).
ad6bb839
AE
861 */
862 if (*name == '/')
863 name++;
61983f67 864
fcb63670 865 /* Obfuscate the name (if possible) */
61983f67 866
10a01bcd
DW
867 hash = dirattr_hashname(ino != 0, name, namelen);
868 obfuscate_name(hash, namelen, name, ino != 0);
869 ASSERT(hash == dirattr_hashname(ino != 0, name, namelen));
88b1fe2a
AE
870
871 /*
fcb63670
AE
872 * Make sure the name is not something already seen. If we
873 * fail to find a suitable alternate, we're dealing with a
874 * very pathological situation, and we may end up creating
875 * a duplicate name in the metadump, so issue a warning.
88b1fe2a 876 */
fcb63670 877 if (!handle_duplicate_name(hash, namelen, name)) {
88b1fe2a
AE
878 print_warning("duplicate name for inode %llu "
879 "in dir inode %llu\n",
880 (unsigned long long) ino,
fb4697dd 881 (unsigned long long) metadump.cur_ino);
fcb63670
AE
882 return;
883 }
884
885 /* Create an entry for the new name in the name table. */
61983f67 886
a85f8b0a
AE
887 if (!nametable_add(hash, namelen, name))
888 print_warning("unable to record name for inode %llu "
889 "in dir inode %llu\n",
890 (unsigned long long) ino,
fb4697dd 891 (unsigned long long) metadump.cur_ino);
61983f67
BN
892}
893
894static void
87c955c3 895process_sf_dir(
7328ea6e 896 struct xfs_dinode *dip)
61983f67 897{
eb0cb950 898 struct xfs_dir2_sf_hdr *sfp;
61983f67 899 xfs_dir2_sf_entry_t *sfep;
14f8b681 900 uint64_t ino_dir_size;
61983f67
BN
901 int i;
902
eb0cb950 903 sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
56b2de80 904 ino_dir_size = be64_to_cpu(dip->di_size);
61983f67
BN
905 if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) {
906 ino_dir_size = XFS_DFORK_DSIZE(dip, mp);
fb4697dd 907 if (metadump.show_warnings)
88b8e1d6 908 print_warning("invalid size in dir inode %llu",
fb4697dd 909 (long long)metadump.cur_ino);
61983f67
BN
910 }
911
eb0cb950
DC
912 sfep = xfs_dir2_sf_firstentry(sfp);
913 for (i = 0; (i < sfp->count) &&
61983f67
BN
914 ((char *)sfep - (char *)sfp < ino_dir_size); i++) {
915
916 /*
917 * first check for bad name lengths. If they are bad, we
918 * have limitations to how much can be obfuscated.
919 */
920 int namelen = sfep->namelen;
921
922 if (namelen == 0) {
fb4697dd 923 if (metadump.show_warnings)
61983f67 924 print_warning("zero length entry in dir inode "
fb4697dd 925 "%llu", (long long)metadump.cur_ino);
eb0cb950 926 if (i != sfp->count - 1)
61983f67
BN
927 break;
928 namelen = ino_dir_size - ((char *)&sfep->name[0] -
929 (char *)sfp);
930 } else if ((char *)sfep - (char *)sfp +
660836c9 931 libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen) >
61983f67 932 ino_dir_size) {
fb4697dd 933 if (metadump.show_warnings)
61983f67 934 print_warning("entry length in dir inode %llu "
fb4697dd
CB
935 "overflows space",
936 (long long)metadump.cur_ino);
eb0cb950 937 if (i != sfp->count - 1)
61983f67
BN
938 break;
939 namelen = ino_dir_size - ((char *)&sfep->name[0] -
940 (char *)sfp);
941 }
942
fb4697dd 943 if (metadump.obfuscate)
87c955c3 944 generate_obfuscated_name(
e96bd2d3 945 libxfs_dir2_sf_get_ino(mp, sfp, sfep),
a2ceac1f 946 namelen, &sfep->name[0]);
61983f67
BN
947
948 sfep = (xfs_dir2_sf_entry_t *)((char *)sfep +
660836c9 949 libxfs_dir2_sf_entsize(mp, sfp, namelen));
61983f67 950 }
87c955c3
ES
951
952 /* zero stale data in rest of space in data fork, if any */
fb4697dd
CB
953 if (metadump.zero_stale_data &&
954 (ino_dir_size < XFS_DFORK_DSIZE(dip, mp)))
87c955c3 955 memset(sfep, 0, XFS_DFORK_DSIZE(dip, mp) - ino_dir_size);
61983f67
BN
956}
957
f63c7540
DC
958/*
959 * The pathname may not be null terminated. It may be terminated by the end of
960 * a buffer or inode literal area, and the start of the next region contains
961 * unknown data. Therefore, when we get to the last component of the symlink, we
962 * cannot assume that strlen() will give us the right result. Hence we need to
963 * track the remaining pathname length and use that instead.
964 */
b249a9f0
ES
965static void
966obfuscate_path_components(
967 char *buf,
14f8b681 968 uint64_t len)
b249a9f0 969{
02211695
CH
970 unsigned char *comp = (unsigned char *)buf;
971 unsigned char *end = comp + len;
b249a9f0
ES
972 xfs_dahash_t hash;
973
f63c7540 974 while (comp < end) {
b249a9f0
ES
975 char *slash;
976 int namelen;
977
978 /* find slash at end of this component */
979 slash = strchr((char *)comp, '/');
980 if (!slash) {
981 /* last (or single) component */
f63c7540 982 namelen = strnlen((char *)comp, len);
b249a9f0 983 hash = libxfs_da_hashname(comp, namelen);
10a01bcd 984 obfuscate_name(hash, namelen, comp, false);
cb8c70b0 985 ASSERT(hash == libxfs_da_hashname(comp, namelen));
b249a9f0
ES
986 break;
987 }
988 namelen = slash - (char *)comp;
989 /* handle leading or consecutive slashes */
990 if (!namelen) {
991 comp++;
f63c7540 992 len--;
b249a9f0
ES
993 continue;
994 }
995 hash = libxfs_da_hashname(comp, namelen);
10a01bcd 996 obfuscate_name(hash, namelen, comp, false);
cb8c70b0 997 ASSERT(hash == libxfs_da_hashname(comp, namelen));
b249a9f0 998 comp += namelen + 1;
f63c7540 999 len -= namelen + 1;
b249a9f0
ES
1000 }
1001}
1002
61983f67 1003static void
87c955c3 1004process_sf_symlink(
7328ea6e 1005 struct xfs_dinode *dip)
61983f67 1006{
14f8b681 1007 uint64_t len;
56b2de80 1008 char *buf;
88b8e1d6 1009
56b2de80 1010 len = be64_to_cpu(dip->di_size);
88b8e1d6 1011 if (len > XFS_DFORK_DSIZE(dip, mp)) {
fb4697dd 1012 if (metadump.show_warnings)
88b8e1d6 1013 print_warning("invalid size (%d) in symlink inode %llu",
fb4697dd 1014 len, (long long)metadump.cur_ino);
88b8e1d6
BN
1015 len = XFS_DFORK_DSIZE(dip, mp);
1016 }
61983f67 1017
56b2de80 1018 buf = (char *)XFS_DFORK_DPTR(dip);
fb4697dd 1019 if (metadump.obfuscate)
87c955c3
ES
1020 obfuscate_path_components(buf, len);
1021
1022 /* zero stale data in rest of space in data fork, if any */
fb4697dd 1023 if (metadump.zero_stale_data && len < XFS_DFORK_DSIZE(dip, mp))
87c955c3 1024 memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len);
61983f67
BN
1025}
1026
1027static void
87c955c3 1028process_sf_attr(
7328ea6e 1029 struct xfs_dinode *dip)
61983f67
BN
1030{
1031 /*
1941482c
ES
1032 * with extended attributes, obfuscate the names and fill the actual
1033 * values with 'v' (to see a valid string length, as opposed to NULLs)
61983f67
BN
1034 */
1035
2fd09353 1036 struct xfs_attr_shortform *asfp;
cc3650f7
CM
1037 struct xfs_attr_sf_entry *asfep;
1038 int ino_attr_size;
1039 int i;
61983f67 1040
2fd09353 1041 asfp = (struct xfs_attr_shortform *)XFS_DFORK_APTR(dip);
61983f67
BN
1042 if (asfp->hdr.count == 0)
1043 return;
1044
1045 ino_attr_size = be16_to_cpu(asfp->hdr.totsize);
1046 if (ino_attr_size > XFS_DFORK_ASIZE(dip, mp)) {
1047 ino_attr_size = XFS_DFORK_ASIZE(dip, mp);
fb4697dd 1048 if (metadump.show_warnings)
61983f67 1049 print_warning("invalid attr size in inode %llu",
fb4697dd 1050 (long long)metadump.cur_ino);
61983f67
BN
1051 }
1052
1053 asfep = &asfp->list[0];
1054 for (i = 0; (i < asfp->hdr.count) &&
1055 ((char *)asfep - (char *)asfp < ino_attr_size); i++) {
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
BN
1063 break;
1064 } else if ((char *)asfep - (char *)asfp +
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();
2592 set_cur(&typtab[TYP_LOG], XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
2593 mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL);
2594 if (iocur_top->data == NULL) {
d24c0a90 2595 pop_cur();
61983f67 2596 print_warning("cannot read log");
fb4697dd 2597 return !metadump.stop_on_read_error;
61983f67 2598 }
190df617 2599
75333d29 2600 /* If not obfuscating or zeroing, just copy the log as it is */
fb4697dd 2601 if (!metadump.obfuscate && !metadump.zero_stale_data)
37a78181
ES
2602 goto done;
2603
0ab627db 2604 dirty = xlog_is_dirty(mp, &log, &x, 0);
190df617
ES
2605
2606 switch (dirty) {
2607 case 0:
2608 /* clear out a clean log */
fb4697dd 2609 if (metadump.show_progress)
190df617 2610 print_progress("Zeroing clean log");
1c12a814
BF
2611
2612 logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
2613 logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
2660e653
DW
2614 logversion = xfs_has_logv2(mp) ? 2 : 1;
2615 if (xfs_has_crc(mp))
1c12a814
BF
2616 cycle = log.l_curr_cycle + 1;
2617
2618 libxfs_log_clear(NULL, iocur_top->data, logstart, logblocks,
2619 &mp->m_sb.sb_uuid, logversion,
571a78a7 2620 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
190df617
ES
2621 break;
2622 case 1:
2623 /* keep the dirty log */
fb4697dd 2624 if (metadump.obfuscate)
74642d8e 2625 print_warning(
3b3751ab
JT
2626_("Warning: log recovery of an obfuscated metadata image can leak "
2627"unobfuscated metadata and/or cause image corruption. If possible, "
2628"please mount the filesystem to clean the log, or disable obfuscation."));
190df617
ES
2629 break;
2630 case -1:
2631 /* log detection error */
fb4697dd 2632 if (metadump.obfuscate)
74642d8e 2633 print_warning(
190df617
ES
2634_("Could not discern log; image will contain unobfuscated metadata in log."));
2635 break;
2636 }
2637
37a78181 2638done:
878afc65 2639 return !write_buf(iocur_top);
61983f67
BN
2640}
2641
eba3f43e 2642static int
1a5a88ec 2643init_metadump_v1(void)
eba3f43e
CB
2644{
2645 metadump.metablock = (xfs_metablock_t *)calloc(BBSIZE + 1, BBSIZE);
2646 if (metadump.metablock == NULL) {
2647 print_warning("memory allocation failure");
2648 return -1;
2649 }
2650 metadump.metablock->mb_blocklog = BBSHIFT;
2651 metadump.metablock->mb_magic = cpu_to_be32(XFS_MD_MAGIC);
2652
2653 /* Set flags about state of metadump */
2654 metadump.metablock->mb_info = XFS_METADUMP_INFO_FLAGS;
2655 if (metadump.obfuscate)
2656 metadump.metablock->mb_info |= XFS_METADUMP_OBFUSCATED;
2657 if (!metadump.zero_stale_data)
2658 metadump.metablock->mb_info |= XFS_METADUMP_FULLBLOCKS;
2659 if (metadump.dirty_log)
2660 metadump.metablock->mb_info |= XFS_METADUMP_DIRTYLOG;
2661
2662 metadump.block_index = (__be64 *)((char *)metadump.metablock +
2663 sizeof(xfs_metablock_t));
2664 metadump.block_buffer = (char *)(metadump.metablock) + BBSIZE;
2665 metadump.num_indices = (BBSIZE - sizeof(xfs_metablock_t)) / sizeof(__be64);
2666
2667 /*
2668 * A metadump block can hold at most num_indices of BBSIZE sectors;
2669 * do not try to dump a filesystem with a sector size which does not
2670 * fit within num_indices (i.e. within a single metablock).
2671 */
2672 if (mp->m_sb.sb_sectsize > metadump.num_indices * BBSIZE) {
2673 print_warning("Cannot dump filesystem with sector size %u",
2674 mp->m_sb.sb_sectsize);
2675 free(metadump.metablock);
2676 return -1;
2677 }
2678
2679 metadump.cur_index = 0;
2680
2681 return 0;
2682}
2683
1a5a88ec
CB
2684static int
2685finish_dump_metadump_v1(void)
2686{
2687 /*
2688 * write index block and following data blocks (streaming)
2689 */
2690 metadump.metablock->mb_count = cpu_to_be16(metadump.cur_index);
2691 if (fwrite(metadump.metablock, (metadump.cur_index + 1) << BBSHIFT, 1,
2692 metadump.outf) != 1) {
2693 print_warning("error writing to target file");
2694 return -1;
2695 }
2696
2697 memset(metadump.block_index, 0, metadump.num_indices * sizeof(__be64));
2698 metadump.cur_index = 0;
2699 return 0;
2700}
2701
2702static int
2703write_metadump_v1(
2704 enum typnm type,
2705 const char *data,
2706 xfs_daddr_t off,
2707 int len)
2708{
2709 int i;
2710 int ret;
2711
2712 for (i = 0; i < len; i++, off++, data += BBSIZE) {
2713 metadump.block_index[metadump.cur_index] = cpu_to_be64(off);
2714 memcpy(&metadump.block_buffer[metadump.cur_index << BBSHIFT],
2715 data, BBSIZE);
2716 if (++metadump.cur_index == metadump.num_indices) {
2717 ret = finish_dump_metadump_v1();
2718 if (ret)
2719 return -EIO;
2720 }
2721 }
2722
2723 return 0;
2724}
2725
eba3f43e 2726static void
1a5a88ec 2727release_metadump_v1(void)
eba3f43e
CB
2728{
2729 free(metadump.metablock);
2730}
2731
1a5a88ec
CB
2732static struct metadump_ops metadump1_ops = {
2733 .init = init_metadump_v1,
2734 .write = write_metadump_v1,
2735 .finish_dump = finish_dump_metadump_v1,
2736 .release = release_metadump_v1,
2737};
2738
61983f67
BN
2739static int
2740metadump_f(
2741 int argc,
2742 char **argv)
2743{
2744 xfs_agnumber_t agno;
2745 int c;
2746 int start_iocur_sp;
449df236
DW
2747 int outfd = -1;
2748 int ret;
88b8e1d6 2749 char *p;
61983f67
BN
2750
2751 exitcode = 1;
fb4697dd
CB
2752
2753 metadump.version = 1;
2754 metadump.show_progress = false;
2755 metadump.stop_on_read_error = false;
2756 metadump.max_extent_size = DEFAULT_MAX_EXT_SIZE;
2757 metadump.show_warnings = false;
2758 metadump.obfuscate = true;
2759 metadump.zero_stale_data = true;
2760 metadump.dirty_log = false;
61983f67
BN
2761
2762 if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
2763 print_warning("bad superblock magic number %x, giving up",
2764 mp->m_sb.sb_magicnum);
2765 return 0;
2766 }
2767
a547152d
ES
2768 /*
2769 * on load, we sanity-checked agcount and possibly set to 1
2770 * if it was corrupted and large.
2771 */
2772 if (mp->m_sb.sb_agcount == 1 &&
2773 XFS_MAX_DBLOCKS(&mp->m_sb) < mp->m_sb.sb_dblocks) {
2774 print_warning("truncated agcount, giving up");
2775 return 0;
2776 }
2777
b09e839e 2778 while ((c = getopt(argc, argv, "aegm:ow")) != EOF) {
61983f67 2779 switch (c) {
b09e839e 2780 case 'a':
fb4697dd 2781 metadump.zero_stale_data = false;
b09e839e 2782 break;
61983f67 2783 case 'e':
fb4697dd 2784 metadump.stop_on_read_error = true;
61983f67
BN
2785 break;
2786 case 'g':
fb4697dd 2787 metadump.show_progress = true;
61983f67 2788 break;
88b8e1d6 2789 case 'm':
fb4697dd
CB
2790 metadump.max_extent_size =
2791 (int)strtol(optarg, &p, 0);
2792 if (*p != '\0' ||
2793 metadump.max_extent_size <= 0) {
88b8e1d6
BN
2794 print_warning("bad max extent size %s",
2795 optarg);
2796 return 0;
2797 }
2798 break;
61983f67 2799 case 'o':
fb4697dd 2800 metadump.obfuscate = false;
61983f67
BN
2801 break;
2802 case 'w':
fb4697dd 2803 metadump.show_warnings = true;
61983f67
BN
2804 break;
2805 default:
2806 print_warning("bad option for metadump command");
2807 return 0;
2808 }
2809 }
2810
2811 if (optind != argc - 1) {
2812 print_warning("too few options for metadump (no filename given)");
2813 return 0;
2814 }
2815
2291c68b
ES
2816 /* If we'll copy the log, see if the log is dirty */
2817 if (mp->m_sb.sb_logstart) {
2818 push_cur();
2819 set_cur(&typtab[TYP_LOG],
2820 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
2821 mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL);
2822 if (iocur_top->data) { /* best effort */
2823 struct xlog log;
2824
2825 if (xlog_is_dirty(mp, &log, &x, 0))
fb4697dd 2826 metadump.dirty_log = true;
2291c68b
ES
2827 }
2828 pop_cur();
2829 }
2830
61983f67
BN
2831 start_iocur_sp = iocur_sp;
2832
2833 if (strcmp(argv[optind], "-") == 0) {
2834 if (isatty(fileno(stdout))) {
2835 print_warning("cannot write to a terminal");
eba3f43e 2836 goto out;
61983f67 2837 }
4944defa
DW
2838 /*
2839 * Redirect stdout to stderr for the duration of the
2840 * metadump operation so that dbprintf and other messages
2841 * are sent to the console instead of polluting the
2842 * metadump stream.
449df236
DW
2843 *
2844 * We get to do this the hard way because musl doesn't
2845 * allow reassignment of stdout.
4944defa 2846 */
449df236
DW
2847 fflush(stdout);
2848 outfd = dup(STDOUT_FILENO);
2849 if (outfd < 0) {
2850 perror("opening dump stream");
2851 goto out;
2852 }
2853 ret = dup2(STDERR_FILENO, STDOUT_FILENO);
2854 if (ret < 0) {
2855 perror("redirecting stdout");
2856 close(outfd);
2857 goto out;
2858 }
fb4697dd
CB
2859 metadump.outf = fdopen(outfd, "a");
2860 if (metadump.outf == NULL) {
449df236
DW
2861 fprintf(stderr, "cannot create dump stream\n");
2862 dup2(outfd, STDOUT_FILENO);
2863 close(outfd);
2864 goto out;
2865 }
fb4697dd 2866 metadump.stdout_metadump = true;
61983f67 2867 } else {
fb4697dd
CB
2868 metadump.outf = fopen(argv[optind], "wb");
2869 if (metadump.outf == NULL) {
61983f67 2870 print_warning("cannot create dump file");
449df236 2871 goto out;
61983f67
BN
2872 }
2873 }
2874
1a5a88ec
CB
2875 metadump.mdops = &metadump1_ops;
2876
2877 ret = metadump.mdops->init();
1e470277
CB
2878 if (ret)
2879 goto out;
2880
61983f67
BN
2881 exitcode = 0;
2882
2883 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
2884 if (!scan_ag(agno)) {
2885 exitcode = 1;
2886 break;
2887 }
2888 }
2889
2890 /* copy realtime and quota inode contents */
2891 if (!exitcode)
2892 exitcode = !copy_sb_inodes();
2893
2894 /* copy log if it's internal */
2895 if ((mp->m_sb.sb_logstart != 0) && !exitcode)
2896 exitcode = !copy_log();
2897
2898 /* write the remaining index */
2899 if (!exitcode)
1a5a88ec 2900 exitcode = metadump.mdops->finish_dump() < 0;
61983f67 2901
fb4697dd
CB
2902 if (metadump.progress_since_warning)
2903 fputc('\n', metadump.stdout_metadump ? stderr : stdout);
61983f67 2904
fb4697dd
CB
2905 if (metadump.stdout_metadump) {
2906 fflush(metadump.outf);
449df236
DW
2907 fflush(stdout);
2908 ret = dup2(outfd, STDOUT_FILENO);
2909 if (ret < 0)
2910 perror("un-redirecting stdout");
fb4697dd 2911 metadump.stdout_metadump = false;
449df236 2912 }
fb4697dd 2913 fclose(metadump.outf);
61983f67
BN
2914
2915 /* cleanup iocur stack */
2916 while (iocur_sp > start_iocur_sp)
2917 pop_cur();
1e470277 2918
1a5a88ec 2919 metadump.mdops->release();
61983f67 2920
1e470277 2921out:
61983f67
BN
2922 return 0;
2923}