]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/metadump.c
xfsprogs: metadump: move duplicate name handling into its own function
[thirdparty/xfsprogs-dev.git] / db / metadump.c
CommitLineData
61983f67 1/*
56281ed4 2 * Copyright (c) 2007, 2011 SGI
61983f67
BN
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <libxfs.h>
20#include "bmap.h"
21#include "command.h"
22#include "metadump.h"
23#include "io.h"
24#include "output.h"
25#include "type.h"
26#include "init.h"
27#include "sig.h"
28#include "xfs_metadump.h"
29
7431d134
BN
30#define DEFAULT_MAX_EXT_SIZE 1000
31
88b1fe2a
AE
32/*
33 * It's possible that multiple files in a directory (or attributes
34 * in a file) produce the same obfuscated name. If that happens, we
35 * try to create another one. After several rounds of this though,
36 * we just give up and leave the original name as-is.
37 */
38#define DUP_MAX 5 /* Max duplicates before we give up */
39
61983f67
BN
40/* copy all metadata structures to/from a file */
41
42static int metadump_f(int argc, char **argv);
43static void metadump_help(void);
44
45/*
46 * metadump commands issue info/wornings/errors to standard error as
47 * metadump supports stdout as a destination.
48 *
49 * All static functions return zero on failure, while the public functions
50 * return zero on success.
51 */
52
53static const cmdinfo_t metadump_cmd =
54 { "metadump", NULL, metadump_f, 0, -1, 0,
9ee7055c
AM
55 N_("[-e] [-g] [-m max_extent] [-w] [-o] filename"),
56 N_("dump metadata to a file"), metadump_help };
61983f67
BN
57
58static FILE *outf; /* metadump file */
59
60static xfs_metablock_t *metablock; /* header + index + buffers */
61static __be64 *block_index;
62static char *block_buffer;
63
64static int num_indicies;
65static int cur_index;
66
67static xfs_ino_t cur_ino;
68
69static int show_progress = 0;
70static int stop_on_read_error = 0;
7431d134 71static int max_extent_size = DEFAULT_MAX_EXT_SIZE;
61983f67
BN
72static int dont_obfuscate = 0;
73static int show_warnings = 0;
74static int progress_since_warning = 0;
75
76void
77metadump_init(void)
78{
79 add_command(&metadump_cmd);
80}
81
82static void
83metadump_help(void)
84{
9ee7055c 85 dbprintf(_(
61983f67
BN
86"\n"
87" The 'metadump' command dumps the known metadata to a compact file suitable\n"
88" for compressing and sending to an XFS maintainer for corruption analysis \n"
89" or xfs_repair failures.\n\n"
88b8e1d6 90" Options:\n"
61983f67
BN
91" -e -- Ignore read errors and keep going\n"
92" -g -- Display dump progress\n"
7431d134 93" -m -- Specify max extent size in blocks to copy (default = %d blocks)\n"
61983f67
BN
94" -o -- Don't obfuscate names and extended attributes\n"
95" -w -- Show warnings of bad metadata information\n"
9ee7055c 96"\n"), DEFAULT_MAX_EXT_SIZE);
61983f67
BN
97}
98
99static void
100print_warning(const char *fmt, ...)
101{
102 char buf[200];
103 va_list ap;
104
105 if (seenint())
106 return;
107
108 va_start(ap, fmt);
109 vsnprintf(buf, sizeof(buf), fmt, ap);
110 va_end(ap);
111 buf[sizeof(buf)-1] = '\0';
112
113 fprintf(stderr, "%s%s: %s\n", progress_since_warning ? "\n" : "",
114 progname, buf);
115 progress_since_warning = 0;
116}
117
118static void
119print_progress(const char *fmt, ...)
120{
121 char buf[60];
122 va_list ap;
123 FILE *f;
124
125 if (seenint())
126 return;
127
128 va_start(ap, fmt);
129 vsnprintf(buf, sizeof(buf), fmt, ap);
130 va_end(ap);
131 buf[sizeof(buf)-1] = '\0';
132
133 f = (outf == stdout) ? stderr : stdout;
134 fprintf(f, "\r%-59s", buf);
135 fflush(f);
136 progress_since_warning = 1;
137}
138
139/*
140 * A complete dump file will have a "zero" entry in the last index block,
141 * even if the dump is exactly aligned, the last index will be full of
142 * zeros. If the last index entry is non-zero, the dump is incomplete.
143 * Correspondingly, the last chunk will have a count < num_indicies.
144 */
145
146static int
147write_index(void)
148{
149 /*
150 * write index block and following data blocks (streaming)
151 */
152 metablock->mb_count = cpu_to_be16(cur_index);
153 if (fwrite(metablock, (cur_index + 1) << BBSHIFT, 1, outf) != 1) {
154 print_warning("error writing to file: %s", strerror(errno));
155 return 0;
156 }
157
158 memset(block_index, 0, num_indicies * sizeof(__be64));
159 cur_index = 0;
160 return 1;
161}
162
163static int
164write_buf(
165 iocur_t *buf)
166{
167 char *data;
168 __int64_t off;
169 int i;
170
171 for (i = 0, off = buf->bb, data = buf->data;
172 i < buf->blen;
173 i++, off++, data += BBSIZE) {
174 block_index[cur_index] = cpu_to_be64(off);
175 memcpy(&block_buffer[cur_index << BBSHIFT], data, BBSIZE);
176 if (++cur_index == num_indicies) {
177 if (!write_index())
178 return 0;
179 }
180 }
181 return !seenint();
182}
183
184
185static int
186scan_btree(
187 xfs_agnumber_t agno,
188 xfs_agblock_t agbno,
189 int level,
190 typnm_t btype,
191 void *arg,
b194c7d8 192 int (*func)(struct xfs_btree_block *block,
61983f67
BN
193 xfs_agnumber_t agno,
194 xfs_agblock_t agbno,
195 int level,
196 typnm_t btype,
197 void *arg))
198{
d24c0a90
BN
199 int rval = 0;
200
61983f67
BN
201 push_cur();
202 set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb,
203 DB_RING_IGN, NULL);
204 if (iocur_top->data == NULL) {
205 print_warning("cannot read %s block %u/%u", typtab[btype].name,
206 agno, agbno);
d24c0a90
BN
207 rval = !stop_on_read_error;
208 goto pop_out;
61983f67
BN
209 }
210 if (!write_buf(iocur_top))
d24c0a90 211 goto pop_out;
61983f67
BN
212
213 if (!(*func)(iocur_top->data, agno, agbno, level - 1, btype, arg))
d24c0a90
BN
214 goto pop_out;
215 rval = 1;
216pop_out:
61983f67 217 pop_cur();
d24c0a90 218 return rval;
61983f67
BN
219}
220
221/* free space tree copy routines */
222
223static int
224valid_bno(
61983f67 225 xfs_agnumber_t agno,
88b8e1d6 226 xfs_agblock_t agbno)
61983f67 227{
88b8e1d6
BN
228 if (agno < (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
229 agbno <= mp->m_sb.sb_agblocks)
230 return 1;
231 if (agno == (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
232 agbno <= (mp->m_sb.sb_dblocks -
66be354e
ES
233 (xfs_drfsbno_t)(mp->m_sb.sb_agcount - 1) *
234 mp->m_sb.sb_agblocks))
61983f67
BN
235 return 1;
236
61983f67
BN
237 return 0;
238}
239
88b8e1d6 240
61983f67
BN
241static int
242scanfunc_freesp(
b194c7d8 243 struct xfs_btree_block *block,
61983f67
BN
244 xfs_agnumber_t agno,
245 xfs_agblock_t agbno,
246 int level,
247 typnm_t btype,
248 void *arg)
249{
250 xfs_alloc_ptr_t *pp;
251 int i;
88b8e1d6 252 int numrecs;
61983f67
BN
253
254 if (level == 0)
255 return 1;
256
b194c7d8 257 numrecs = be16_to_cpu(block->bb_numrecs);
88b8e1d6 258 if (numrecs > mp->m_alloc_mxr[1]) {
61983f67 259 if (show_warnings)
88b8e1d6
BN
260 print_warning("invalid numrecs (%u) in %s block %u/%u",
261 numrecs, typtab[btype].name, agno, agbno);
61983f67
BN
262 return 1;
263 }
264
b3563c19 265 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
88b8e1d6
BN
266 for (i = 0; i < numrecs; i++) {
267 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
268 if (show_warnings)
269 print_warning("invalid block number (%u/%u) "
270 "in %s block %u/%u",
271 agno, be32_to_cpu(pp[i]),
272 typtab[btype].name, agno, agbno);
61983f67 273 continue;
88b8e1d6 274 }
61983f67
BN
275 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
276 scanfunc_freesp))
277 return 0;
278 }
279 return 1;
280}
281
282static int
283copy_free_bno_btree(
284 xfs_agnumber_t agno,
285 xfs_agf_t *agf)
286{
287 xfs_agblock_t root;
288 int levels;
289
290 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
291 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
292
293 /* validate root and levels before processing the tree */
294 if (root == 0 || root > mp->m_sb.sb_agblocks) {
295 if (show_warnings)
296 print_warning("invalid block number (%u) in bnobt "
297 "root in agf %u", root, agno);
298 return 1;
299 }
300 if (levels >= XFS_BTREE_MAXLEVELS) {
301 if (show_warnings)
302 print_warning("invalid level (%u) in bnobt root "
303 "in agf %u", levels, agno);
304 return 1;
305 }
306
307 return scan_btree(agno, root, levels, TYP_BNOBT, agf, scanfunc_freesp);
308}
309
310static int
311copy_free_cnt_btree(
312 xfs_agnumber_t agno,
313 xfs_agf_t *agf)
314{
315 xfs_agblock_t root;
316 int levels;
317
318 root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
319 levels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
320
321 /* validate root and levels before processing the tree */
322 if (root == 0 || root > mp->m_sb.sb_agblocks) {
323 if (show_warnings)
324 print_warning("invalid block number (%u) in cntbt "
325 "root in agf %u", root, agno);
326 return 1;
327 }
328 if (levels >= XFS_BTREE_MAXLEVELS) {
329 if (show_warnings)
330 print_warning("invalid level (%u) in cntbt root "
331 "in agf %u", levels, agno);
332 return 1;
333 }
334
335 return scan_btree(agno, root, levels, TYP_CNTBT, agf, scanfunc_freesp);
336}
337
338/* filename and extended attribute obfuscation routines */
339
340typedef struct name_ent {
341 struct name_ent *next;
342 xfs_dahash_t hash;
343 int namelen;
344 uchar_t name[1];
345} name_ent_t;
346
347#define NAME_TABLE_SIZE 4096
348
a85f8b0a 349static struct name_ent *nametable[NAME_TABLE_SIZE];
61983f67
BN
350
351static void
a85f8b0a 352nametable_clear(void)
61983f67 353{
a85f8b0a
AE
354 int i;
355 name_ent_t *ent;
61983f67
BN
356
357 for (i = 0; i < NAME_TABLE_SIZE; i++) {
a85f8b0a
AE
358 while ((ent = nametable[i])) {
359 nametable[i] = ent->next;
360 free(ent);
61983f67
BN
361 }
362 }
363}
364
a85f8b0a
AE
365/*
366 * See if the given name is already in the name table. If so,
367 * return a pointer to its entry, otherwise return a null pointer.
368 */
369static struct name_ent *
370nametable_find(xfs_dahash_t hash, int namelen, uchar_t *name)
371{
372 struct name_ent *ent;
373
374 for (ent = nametable[hash % NAME_TABLE_SIZE]; ent; ent = ent->next) {
375 if (ent->hash == hash && ent->namelen == namelen &&
376 !memcmp(ent->name, name, namelen))
377 return ent;
378 }
379 return NULL;
380}
381
382/*
383 * Add the given name to the name table. Returns a pointer to the
384 * name's new entry, or a null pointer if an error occurs.
385 */
386static struct name_ent *
387nametable_add(xfs_dahash_t hash, int namelen, uchar_t *name)
388{
389 struct name_ent *ent;
390
391 ent = malloc(sizeof *ent + namelen);
392 if (!ent)
393 return NULL;
394
395 ent->namelen = namelen;
396 memcpy(ent->name, name, namelen);
397 ent->hash = hash;
398 ent->next = nametable[hash % NAME_TABLE_SIZE];
399
400 nametable[hash % NAME_TABLE_SIZE] = ent;
401
402 return ent;
403}
61983f67
BN
404
405#define is_invalid_char(c) ((c) == '/' || (c) == '\0')
406#define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
407
408static inline uchar_t
409random_filename_char(void)
410{
411 uchar_t c;
412
413 do {
414 c = random() % 127 + 1;
415 } while (c == '/');
416 return c;
417}
418
56281ed4
AE
419#define ORPHANAGE "lost+found"
420#define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1)
421
422static inline int
423is_orphanage_dir(
424 struct xfs_mount *mp,
425 xfs_ino_t dir_ino,
426 size_t name_len,
427 uchar_t *name)
428{
429 return dir_ino == mp->m_sb.sb_rootino &&
430 name_len == ORPHANAGE_LEN &&
431 !memcmp(name, ORPHANAGE, ORPHANAGE_LEN);
432}
433
434/*
435 * Determine whether a name is one we shouldn't obfuscate because
436 * it's an orphan (or the "lost+found" directory itself). Note
437 * "cur_ino" is the inode for the directory currently being
438 * processed.
439 *
440 * Returns 1 if the name should NOT be obfuscated or 0 otherwise.
441 */
61983f67 442static int
56281ed4 443in_lost_found(
61983f67
BN
444 xfs_ino_t ino,
445 int namelen,
446 uchar_t *name)
447{
448 static xfs_ino_t orphanage_ino = 0;
56281ed4 449 char s[24]; /* 21 is enough (64 bits in decimal) */
61983f67
BN
450 int slen;
451
56281ed4
AE
452 /* Record the "lost+found" inode if we haven't done so already */
453
454 ASSERT(ino != 0);
455 if (!orphanage_ino && is_orphanage_dir(mp, cur_ino, namelen, name))
456 orphanage_ino = ino;
457
458 /* We don't obfuscate the "lost+found" directory itself */
459
460 if (ino == orphanage_ino)
61983f67
BN
461 return 1;
462
56281ed4
AE
463 /* Most files aren't in "lost+found" at all */
464
465 if (cur_ino != orphanage_ino)
61983f67
BN
466 return 0;
467
468 /*
56281ed4
AE
469 * Within "lost+found", we don't obfuscate any file whose
470 * name is the same as its inode number. Any others are
471 * stray files and can be obfuscated.
61983f67 472 */
56281ed4 473 slen = snprintf(s, sizeof (s), "%llu", (unsigned long long) ino);
61983f67 474
56281ed4 475 return slen == namelen && !memcmp(name, s, namelen);
61983f67
BN
476}
477
da7daaf2
AE
478/*
479 * Given a name and its hash value, massage the name in such a way
480 * that the result is another name of equal length which shares the
481 * same hash value.
482 */
61983f67 483static void
da7daaf2
AE
484obfuscate_name(
485 xfs_dahash_t hash,
486 size_t name_len,
487 uchar_t *name)
61983f67 488{
002c6e02 489 uchar_t *newp = name;
da7daaf2
AE
490 int i;
491 xfs_dahash_t new_hash = 0;
492 uchar_t *first;
493 uchar_t high_bit;
494 int shift;
61983f67 495
56281ed4
AE
496 /*
497 * Our obfuscation algorithm requires at least 5-character
498 * names, so don't bother if the name is too short. We
499 * work backward from a hash value to determine the last
500 * five bytes in a name required to produce a new name
501 * with the same hash.
502 */
da7daaf2 503 if (name_len < 5)
61983f67
BN
504 return;
505
da7daaf2
AE
506 /*
507 * The beginning of the obfuscated name can be pretty much
508 * anything, so fill it in with random characters.
509 * Accumulate its new hash value as we go.
510 */
511 for (i = 0; i < name_len - 5; i++) {
512 *newp = random_filename_char();
513 new_hash = *newp ^ rol32(new_hash, 7);
514 newp++;
515 }
516
517 /*
518 * Compute which five bytes need to be used at the end of
519 * the name so the hash of the obfuscated name is the same
520 * as the hash of the original. If any result in an invalid
521 * character, flip a bit and arrange for a corresponding bit
522 * in a neighboring byte to be flipped as well. For the
523 * last byte, the "neighbor" to change is the first byte
524 * we're computing here.
525 */
526 new_hash = rol32(new_hash, 3) ^ hash;
527
528 first = newp;
529 high_bit = 0;
530 for (shift = 28; shift >= 0; shift -= 7) {
531 *newp = (new_hash >> shift & 0x7f) ^ high_bit;
532 if (is_invalid_char(*newp)) {
533 *newp ^= 1;
534 high_bit = 0x80;
535 } else
536 high_bit = 0;
537 ASSERT(!is_invalid_char(*newp));
538 newp++;
539 }
540
541 /*
542 * If we flipped a bit on the last byte, we need to fix up
543 * the matching bit in the first byte. The result will
544 * be a valid character, because we know that first byte
545 * has 0's in its upper four bits (it was produced by a
546 * 28-bit right-shift of a 32-bit unsigned value).
547 */
548 if (high_bit) {
549 *first ^= 0x10;
550 ASSERT(!is_invalid_char(*first));
551 }
002c6e02 552 ASSERT(libxfs_da_hashname(name, name_len) == hash);
da7daaf2
AE
553}
554
fcb63670
AE
555/*
556 * Look up the given name in the name table. If it is already
557 * present, find an alternate and attempt to use that name instead.
558 *
559 * Returns 1 if the (possibly modified) name is not present in the
560 * name table. Returns 0 otherwise.
561 */
562static int
563handle_duplicate_name(xfs_dahash_t hash, size_t name_len, uchar_t *name)
564{
565 int dup = 0;
566
567 if (!nametable_find(hash, name_len, name))
568 return 1; /* Not already in table */
569
570 /* Name is already in use. Need to find an alternate. */
571
572 do {
573 obfuscate_name(hash, name_len, name);
574
575 /*
576 * Search the name table to be sure we don't produce
577 * a name that's already been used.
578 */
579 if (!nametable_find(hash, name_len, name))
580 break;
581 } while (++dup < DUP_MAX);
582
583 return dup < DUP_MAX ? 1 : 0;
584}
585
da7daaf2
AE
586static void
587generate_obfuscated_name(
588 xfs_ino_t ino,
589 int namelen,
590 uchar_t *name)
591{
592 xfs_dahash_t hash;
da7daaf2 593
56281ed4
AE
594 /*
595 * We don't obfuscate "lost+found" or any orphan files
596 * therein. When the name table is used for extended
597 * attributes, the inode number provided is 0, in which
598 * case we don't need to make this check.
599 */
600 if (ino && in_lost_found(ino, namelen, name))
601 return;
61983f67 602
ad6bb839 603 /*
fcb63670
AE
604 * If the name starts with a slash, just skip over it. It
605 * isn't included in the hash and we don't record it in the
606 * name table. Note that the namelen value passed in does
607 * not count the leading slash (if one is present).
ad6bb839
AE
608 */
609 if (*name == '/')
610 name++;
61983f67 611
fcb63670 612 /* Obfuscate the name (if possible) */
61983f67 613
fcb63670
AE
614 hash = libxfs_da_hashname(name, namelen);
615 obfuscate_name(hash, namelen, name);
88b1fe2a
AE
616
617 /*
fcb63670
AE
618 * Make sure the name is not something already seen. If we
619 * fail to find a suitable alternate, we're dealing with a
620 * very pathological situation, and we may end up creating
621 * a duplicate name in the metadump, so issue a warning.
88b1fe2a 622 */
fcb63670 623 if (!handle_duplicate_name(hash, namelen, name)) {
88b1fe2a
AE
624 print_warning("duplicate name for inode %llu "
625 "in dir inode %llu\n",
626 (unsigned long long) ino,
627 (unsigned long long) cur_ino);
fcb63670
AE
628 return;
629 }
630
631 /* Create an entry for the new name in the name table. */
61983f67 632
a85f8b0a
AE
633 if (!nametable_add(hash, namelen, name))
634 print_warning("unable to record name for inode %llu "
635 "in dir inode %llu\n",
636 (unsigned long long) ino,
637 (unsigned long long) cur_ino);
61983f67
BN
638}
639
640static void
641obfuscate_sf_dir(
642 xfs_dinode_t *dip)
643{
644 xfs_dir2_sf_t *sfp;
645 xfs_dir2_sf_entry_t *sfep;
5e656dbb 646 __uint64_t ino_dir_size;
61983f67
BN
647 int i;
648
649 sfp = &dip->di_u.di_dir2sf;
5e656dbb 650 ino_dir_size = be64_to_cpu(dip->di_core.di_size);
61983f67
BN
651 if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) {
652 ino_dir_size = XFS_DFORK_DSIZE(dip, mp);
653 if (show_warnings)
88b8e1d6 654 print_warning("invalid size in dir inode %llu",
61983f67
BN
655 (long long)cur_ino);
656 }
657
5e656dbb 658 sfep = xfs_dir2_sf_firstentry(sfp);
61983f67
BN
659 for (i = 0; (i < sfp->hdr.count) &&
660 ((char *)sfep - (char *)sfp < ino_dir_size); i++) {
661
662 /*
663 * first check for bad name lengths. If they are bad, we
664 * have limitations to how much can be obfuscated.
665 */
666 int namelen = sfep->namelen;
667
668 if (namelen == 0) {
669 if (show_warnings)
670 print_warning("zero length entry in dir inode "
671 "%llu", (long long)cur_ino);
672 if (i != sfp->hdr.count - 1)
673 break;
674 namelen = ino_dir_size - ((char *)&sfep->name[0] -
675 (char *)sfp);
676 } else if ((char *)sfep - (char *)sfp +
5e656dbb 677 xfs_dir2_sf_entsize_byentry(sfp, sfep) >
61983f67
BN
678 ino_dir_size) {
679 if (show_warnings)
680 print_warning("entry length in dir inode %llu "
681 "overflows space", (long long)cur_ino);
682 if (i != sfp->hdr.count - 1)
683 break;
684 namelen = ino_dir_size - ((char *)&sfep->name[0] -
685 (char *)sfp);
686 }
687
5e656dbb
BN
688 generate_obfuscated_name(xfs_dir2_sf_get_inumber(sfp,
689 xfs_dir2_sf_inumberp(sfep)), namelen,
61983f67
BN
690 &sfep->name[0]);
691
692 sfep = (xfs_dir2_sf_entry_t *)((char *)sfep +
5e656dbb 693 xfs_dir2_sf_entsize_byname(sfp, namelen));
61983f67
BN
694 }
695}
696
697static void
698obfuscate_sf_symlink(
699 xfs_dinode_t *dip)
700{
5e656dbb 701 __uint64_t len;
88b8e1d6 702
5e656dbb 703 len = be64_to_cpu(dip->di_core.di_size);
88b8e1d6
BN
704 if (len > XFS_DFORK_DSIZE(dip, mp)) {
705 if (show_warnings)
706 print_warning("invalid size (%d) in symlink inode %llu",
707 len, (long long)cur_ino);
708 len = XFS_DFORK_DSIZE(dip, mp);
709 }
61983f67 710
88b8e1d6
BN
711 while (len > 0)
712 dip->di_u.di_symlink[--len] = random() % 127 + 1;
61983f67
BN
713}
714
715static void
716obfuscate_sf_attr(
717 xfs_dinode_t *dip)
718{
719 /*
720 * with extended attributes, obfuscate the names and zero the actual
721 * values.
722 */
723
724 xfs_attr_shortform_t *asfp;
725 xfs_attr_sf_entry_t *asfep;
726 int ino_attr_size;
727 int i;
728
729 asfp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
730 if (asfp->hdr.count == 0)
731 return;
732
733 ino_attr_size = be16_to_cpu(asfp->hdr.totsize);
734 if (ino_attr_size > XFS_DFORK_ASIZE(dip, mp)) {
735 ino_attr_size = XFS_DFORK_ASIZE(dip, mp);
736 if (show_warnings)
737 print_warning("invalid attr size in inode %llu",
738 (long long)cur_ino);
739 }
740
741 asfep = &asfp->list[0];
742 for (i = 0; (i < asfp->hdr.count) &&
743 ((char *)asfep - (char *)asfp < ino_attr_size); i++) {
744
745 int namelen = asfep->namelen;
746
747 if (namelen == 0) {
748 if (show_warnings)
749 print_warning("zero length attr entry in inode "
750 "%llu", (long long)cur_ino);
751 break;
752 } else if ((char *)asfep - (char *)asfp +
753 XFS_ATTR_SF_ENTSIZE(asfep) > ino_attr_size) {
754 if (show_warnings)
755 print_warning("attr entry length in inode %llu "
756 "overflows space", (long long)cur_ino);
757 break;
758 }
759
760 generate_obfuscated_name(0, asfep->namelen, &asfep->nameval[0]);
761 memset(&asfep->nameval[asfep->namelen], 0, asfep->valuelen);
762
763 asfep = (xfs_attr_sf_entry_t *)((char *)asfep +
764 XFS_ATTR_SF_ENTSIZE(asfep));
765 }
766}
767
768/*
769 * dir_data structure is used to track multi-fsblock dir2 blocks between extent
770 * processing calls.
771 */
772
773static struct dir_data_s {
774 int end_of_data;
775 int block_index;
776 int offset_to_entry;
777 int bad_block;
778} dir_data;
779
780static void
781obfuscate_dir_data_blocks(
782 char *block,
783 xfs_dfiloff_t offset,
784 xfs_dfilblks_t count,
785 int is_block_format)
786{
787 /*
788 * we have to rely on the fileoffset and signature of the block to
789 * handle it's contents. If it's invalid, leave it alone.
790 * for multi-fsblock dir blocks, if a name crosses an extent boundary,
791 * ignore it and continue.
792 */
793 int c;
794 int dir_offset;
795 char *ptr;
796 char *endptr;
797
798 if (is_block_format && count != mp->m_dirblkfsbs)
799 return; /* too complex to handle this rare case */
800
801 for (c = 0, endptr = block; c < count; c++) {
802
803 if (dir_data.block_index == 0) {
804 int wantmagic;
805
806 if (offset % mp->m_dirblkfsbs != 0)
807 return; /* corrupted, leave it alone */
808
809 dir_data.bad_block = 0;
810
811 if (is_block_format) {
812 xfs_dir2_leaf_entry_t *blp;
813 xfs_dir2_block_tail_t *btp;
814
5e656dbb 815 btp = xfs_dir2_block_tail_p(mp,
61983f67 816 (xfs_dir2_block_t *)block);
5e656dbb 817 blp = xfs_dir2_block_leaf_p(btp);
61983f67
BN
818 if ((char *)blp > (char *)btp)
819 blp = (xfs_dir2_leaf_entry_t *)btp;
820
821 dir_data.end_of_data = (char *)blp - block;
822 wantmagic = XFS_DIR2_BLOCK_MAGIC;
823 } else { /* leaf/node format */
824 dir_data.end_of_data = mp->m_dirblkfsbs <<
825 mp->m_sb.sb_blocklog;
826 wantmagic = XFS_DIR2_DATA_MAGIC;
827 }
828 dir_data.offset_to_entry = offsetof(xfs_dir2_data_t, u);
829
830 if (be32_to_cpu(((xfs_dir2_data_hdr_t*)block)->magic) !=
831 wantmagic) {
832 if (show_warnings)
833 print_warning("invalid magic in dir "
834 "inode %llu block %ld",
835 (long long)cur_ino,
836 (long)offset);
837 dir_data.bad_block = 1;
838 }
839 }
840 dir_data.block_index++;
841 if (dir_data.block_index == mp->m_dirblkfsbs)
842 dir_data.block_index = 0;
843
844 if (dir_data.bad_block)
845 continue;
846
847 dir_offset = (dir_data.block_index << mp->m_sb.sb_blocklog) +
848 dir_data.offset_to_entry;
849
850 ptr = endptr + dir_data.offset_to_entry;
851 endptr += mp->m_sb.sb_blocksize;
852
853 while (ptr < endptr && dir_offset < dir_data.end_of_data) {
854 xfs_dir2_data_entry_t *dep;
855 xfs_dir2_data_unused_t *dup;
856 int length;
857
858 dup = (xfs_dir2_data_unused_t *)ptr;
859
860 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
861 int length = be16_to_cpu(dup->length);
862 if (dir_offset + length > dir_data.end_of_data ||
863 length == 0 || (length &
864 (XFS_DIR2_DATA_ALIGN - 1))) {
865 if (show_warnings)
866 print_warning("invalid length "
867 "for dir free space in "
868 "inode %llu",
869 (long long)cur_ino);
870 dir_data.bad_block = 1;
871 break;
872 }
5e656dbb 873 if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
61983f67
BN
874 dir_offset) {
875 dir_data.bad_block = 1;
876 break;
877 }
878 dir_offset += length;
879 ptr += length;
880 if (dir_offset >= dir_data.end_of_data ||
881 ptr >= endptr)
882 break;
883 }
884
885 dep = (xfs_dir2_data_entry_t *)ptr;
5e656dbb 886 length = xfs_dir2_data_entsize(dep->namelen);
61983f67
BN
887
888 if (dir_offset + length > dir_data.end_of_data ||
889 ptr + length > endptr) {
890 if (show_warnings)
891 print_warning("invalid length for "
892 "dir entry name in inode %llu",
893 (long long)cur_ino);
894 break;
895 }
5e656dbb 896 if (be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) !=
61983f67
BN
897 dir_offset) {
898 dir_data.bad_block = 1;
899 break;
900 }
901 generate_obfuscated_name(be64_to_cpu(dep->inumber),
902 dep->namelen, &dep->name[0]);
903 dir_offset += length;
904 ptr += length;
905 }
906 dir_data.offset_to_entry = dir_offset &
907 (mp->m_sb.sb_blocksize - 1);
908 }
909}
910
911static void
912obfuscate_symlink_blocks(
913 char *block,
914 xfs_dfilblks_t count)
915{
916 int i;
917
918 count <<= mp->m_sb.sb_blocklog;
919 for (i = 0; i < count; i++)
920 block[i] = random() % 127 + 1;
921}
922
923#define MAX_REMOTE_VALS 4095
924
925static struct attr_data_s {
926 int remote_val_count;
927 xfs_dablk_t remote_vals[MAX_REMOTE_VALS];
928} attr_data;
929
930static inline void
931add_remote_vals(
932 xfs_dablk_t blockidx,
933 int length)
934{
935 while (length > 0 && attr_data.remote_val_count < MAX_REMOTE_VALS) {
936 attr_data.remote_vals[attr_data.remote_val_count] = blockidx;
937 attr_data.remote_val_count++;
938 blockidx++;
939 length -= XFS_LBSIZE(mp);
940 }
941}
942
943static void
944obfuscate_attr_blocks(
945 char *block,
946 xfs_dfiloff_t offset,
947 xfs_dfilblks_t count)
948{
949 xfs_attr_leafblock_t *leaf;
950 int c;
951 int i;
952 int nentries;
953 xfs_attr_leaf_entry_t *entry;
954 xfs_attr_leaf_name_local_t *local;
955 xfs_attr_leaf_name_remote_t *remote;
956
957 for (c = 0; c < count; c++, offset++, block += XFS_LBSIZE(mp)) {
958
959 leaf = (xfs_attr_leafblock_t *)block;
960
961 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) {
962 for (i = 0; i < attr_data.remote_val_count; i++) {
963 if (attr_data.remote_vals[i] == offset)
964 memset(block, 0, XFS_LBSIZE(mp));
965 }
966 continue;
967 }
968
969 nentries = be16_to_cpu(leaf->hdr.count);
970 if (nentries * sizeof(xfs_attr_leaf_entry_t) +
971 sizeof(xfs_attr_leaf_hdr_t) > XFS_LBSIZE(mp)) {
972 if (show_warnings)
973 print_warning("invalid attr count in inode %llu",
974 (long long)cur_ino);
975 continue;
976 }
977
978 for (i = 0, entry = &leaf->entries[0]; i < nentries;
979 i++, entry++) {
980 if (be16_to_cpu(entry->nameidx) > XFS_LBSIZE(mp)) {
981 if (show_warnings)
982 print_warning("invalid attr nameidx "
983 "in inode %llu",
984 (long long)cur_ino);
985 break;
986 }
987 if (entry->flags & XFS_ATTR_LOCAL) {
988 local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
989 if (local->namelen == 0) {
990 if (show_warnings)
991 print_warning("zero length for "
992 "attr name in inode %llu",
993 (long long)cur_ino);
994 break;
995 }
996 generate_obfuscated_name(0, local->namelen,
997 &local->nameval[0]);
998 memset(&local->nameval[local->namelen], 0,
999 be16_to_cpu(local->valuelen));
1000 } else {
1001 remote = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
1002 if (remote->namelen == 0 ||
1003 remote->valueblk == 0) {
1004 if (show_warnings)
1005 print_warning("invalid attr "
1006 "entry in inode %llu",
1007 (long long)cur_ino);
1008 break;
1009 }
1010 generate_obfuscated_name(0, remote->namelen,
1011 &remote->name[0]);
1012 add_remote_vals(be32_to_cpu(remote->valueblk),
1013 be32_to_cpu(remote->valuelen));
1014 }
1015 }
1016 }
1017}
1018
1019/* inode copy routines */
1020
1021static int
1022process_bmbt_reclist(
1023 xfs_bmbt_rec_t *rp,
1024 int numrecs,
1025 typnm_t btype)
1026{
1027 int i;
95c20099 1028 xfs_dfiloff_t o, op = NULLDFILOFF;
61983f67 1029 xfs_dfsbno_t s;
95c20099 1030 xfs_dfilblks_t c, cp = NULLDFILOFF;
61983f67
BN
1031 int f;
1032 xfs_dfiloff_t last;
88b8e1d6
BN
1033 xfs_agnumber_t agno;
1034 xfs_agblock_t agbno;
61983f67
BN
1035
1036 if (btype == TYP_DATA)
1037 return 1;
1038
1039 convert_extent(&rp[numrecs - 1], &o, &s, &c, &f);
1040 last = o + c;
1041
1042 for (i = 0; i < numrecs; i++, rp++) {
1043 convert_extent(rp, &o, &s, &c, &f);
1044
88b8e1d6
BN
1045 /*
1046 * ignore extents that are clearly bogus, and if a bogus
1047 * one is found, stop processing remaining extents
1048 */
1049 if (i > 0 && op + cp > o) {
1050 if (show_warnings)
1051 print_warning("bmap extent %d in %s ino %llu "
1052 "starts at %llu, previous extent "
1053 "ended at %llu", i,
1054 typtab[btype].name, (long long)cur_ino,
1055 o, op + cp - 1);
1056 break;
1057 }
1058
1059 if (c > max_extent_size) {
1060 /*
1061 * since we are only processing non-data extents,
1062 * large numbers of blocks in a metadata extent is
1063 * extremely rare and more than likely to be corrupt.
1064 */
1065 if (show_warnings)
1066 print_warning("suspicious count %u in bmap "
1067 "extent %d in %s ino %llu", c, i,
1068 typtab[btype].name, (long long)cur_ino);
1069 break;
1070 }
1071
1072 op = o;
1073 cp = c;
1074
1075 agno = XFS_FSB_TO_AGNO(mp, s);
1076 agbno = XFS_FSB_TO_AGBNO(mp, s);
1077
1078 if (!valid_bno(agno, agbno)) {
1079 if (show_warnings)
1080 print_warning("invalid block number %u/%u "
1081 "(%llu) in bmap extent %d in %s ino "
1082 "%llu", agno, agbno, s, i,
1083 typtab[btype].name, (long long)cur_ino);
1084 break;
1085 }
1086
1087 if (!valid_bno(agno, agbno + c - 1)) {
1088 if (show_warnings)
1089 print_warning("bmap extent %i in %s inode %llu "
1090 "overflows AG (end is %u/%u)", i,
1091 typtab[btype].name, (long long)cur_ino,
1092 agno, agbno + c - 1);
1093 break;
1094 }
1095
61983f67
BN
1096 push_cur();
1097 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), c * blkbb,
1098 DB_RING_IGN, NULL);
1099 if (iocur_top->data == NULL) {
88b8e1d6
BN
1100 print_warning("cannot read %s block %u/%u (%llu)",
1101 typtab[btype].name, agno, agbno, s);
d24c0a90
BN
1102 if (stop_on_read_error) {
1103 pop_cur();
61983f67 1104 return 0;
d24c0a90 1105 }
61983f67
BN
1106 } else {
1107 if (!dont_obfuscate)
1108 switch (btype) {
1109 case TYP_DIR2:
1110 if (o < mp->m_dirleafblk)
1111 obfuscate_dir_data_blocks(
1112 iocur_top->data, o, c,
1113 last == mp->m_dirblkfsbs);
1114 break;
1115
1116 case TYP_SYMLINK:
1117 obfuscate_symlink_blocks(
1118 iocur_top->data, c);
1119 break;
1120
1121 case TYP_ATTR:
1122 obfuscate_attr_blocks(iocur_top->data,
1123 o, c);
1124 break;
1125
1126 default: ;
1127 }
d24c0a90
BN
1128 if (!write_buf(iocur_top)) {
1129 pop_cur();
61983f67 1130 return 0;
d24c0a90 1131 }
61983f67
BN
1132 }
1133 pop_cur();
1134 }
1135
1136 return 1;
1137}
1138
1139static int
1140scanfunc_bmap(
b194c7d8 1141 struct xfs_btree_block *block,
61983f67
BN
1142 xfs_agnumber_t agno,
1143 xfs_agblock_t agbno,
1144 int level,
1145 typnm_t btype,
1146 void *arg) /* ptr to itype */
1147{
1148 int i;
1149 xfs_bmbt_ptr_t *pp;
61983f67
BN
1150 int nrecs;
1151
b194c7d8 1152 nrecs = be16_to_cpu(block->bb_numrecs);
61983f67
BN
1153
1154 if (level == 0) {
1155 if (nrecs > mp->m_bmap_dmxr[0]) {
1156 if (show_warnings)
1157 print_warning("invalid numrecs (%u) in %s "
1158 "block %u/%u", nrecs,
1159 typtab[btype].name, agno, agbno);
1160 return 1;
1161 }
b3563c19
BN
1162 return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1),
1163 nrecs, *(typnm_t*)arg);
61983f67
BN
1164 }
1165
1166 if (nrecs > mp->m_bmap_dmxr[1]) {
1167 if (show_warnings)
1168 print_warning("invalid numrecs (%u) in %s block %u/%u",
1169 nrecs, typtab[btype].name, agno, agbno);
1170 return 1;
1171 }
b3563c19 1172 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
61983f67
BN
1173 for (i = 0; i < nrecs; i++) {
1174 xfs_agnumber_t ag;
1175 xfs_agblock_t bno;
1176
1177 ag = XFS_FSB_TO_AGNO(mp, be64_to_cpu(pp[i]));
1178 bno = XFS_FSB_TO_AGBNO(mp, be64_to_cpu(pp[i]));
1179
1180 if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
1181 ag > mp->m_sb.sb_agcount) {
1182 if (show_warnings)
1183 print_warning("invalid block number (%u/%u) "
1184 "in %s block %u/%u", ag, bno,
1185 typtab[btype].name, agno, agbno);
1186 continue;
1187 }
1188
1189 if (!scan_btree(ag, bno, level, btype, arg, scanfunc_bmap))
1190 return 0;
1191 }
1192 return 1;
1193}
1194
1195static int
1196process_btinode(
1197 xfs_dinode_t *dip,
1198 typnm_t itype)
1199{
1200 xfs_bmdr_block_t *dib;
1201 int i;
1202 xfs_bmbt_ptr_t *pp;
61983f67
BN
1203 int level;
1204 int nrecs;
1205 int maxrecs;
1206 int whichfork;
1207 typnm_t btype;
1208
1209 whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
1210 btype = (itype == TYP_ATTR) ? TYP_BMAPBTA : TYP_BMAPBTD;
1211
1212 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
1213 level = be16_to_cpu(dib->bb_level);
1214 nrecs = be16_to_cpu(dib->bb_numrecs);
1215
1216 if (level > XFS_BM_MAXLEVELS(mp, whichfork)) {
1217 if (show_warnings)
1218 print_warning("invalid level (%u) in inode %lld %s "
1219 "root", level, (long long)cur_ino,
1220 typtab[btype].name);
1221 return 1;
1222 }
1223
b3563c19
BN
1224 if (level == 0) {
1225 return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1),
1226 nrecs, itype);
1227 }
61983f67 1228
b3563c19 1229 maxrecs = xfs_bmdr_maxrecs(mp, XFS_DFORK_SIZE(dip, mp, whichfork), 0);
61983f67
BN
1230 if (nrecs > maxrecs) {
1231 if (show_warnings)
1232 print_warning("invalid numrecs (%u) in inode %lld %s "
1233 "root", nrecs, (long long)cur_ino,
1234 typtab[btype].name);
1235 return 1;
1236 }
1237
b3563c19 1238 pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
61983f67
BN
1239 for (i = 0; i < nrecs; i++) {
1240 xfs_agnumber_t ag;
1241 xfs_agblock_t bno;
1242
1243 ag = XFS_FSB_TO_AGNO(mp, be64_to_cpu(pp[i]));
1244 bno = XFS_FSB_TO_AGBNO(mp, be64_to_cpu(pp[i]));
1245
1246 if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
1247 ag > mp->m_sb.sb_agcount) {
1248 if (show_warnings)
1249 print_warning("invalid block number (%u/%u) "
1250 "in inode %llu %s root", ag,
1251 bno, (long long)cur_ino,
1252 typtab[btype].name);
1253 continue;
1254 }
1255
1256 if (!scan_btree(ag, bno, level, btype, &itype, scanfunc_bmap))
1257 return 0;
1258 }
1259 return 1;
1260}
1261
1262static int
1263process_exinode(
1264 xfs_dinode_t *dip,
1265 typnm_t itype)
1266{
1267 int whichfork;
88b8e1d6 1268 xfs_extnum_t nex;
61983f67
BN
1269
1270 whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
1271
5e656dbb
BN
1272 nex = XFS_DFORK_NEXTENTS(dip, whichfork);
1273 if (nex < 0 || nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
1274 sizeof(xfs_bmbt_rec_t)) {
88b8e1d6
BN
1275 if (show_warnings)
1276 print_warning("bad number of extents %d in inode %lld",
1277 nex, (long long)cur_ino);
1278 return 1;
1279 }
1280
1281 return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip,
1282 whichfork), nex, itype);
61983f67
BN
1283}
1284
1285static int
1286process_inode_data(
1287 xfs_dinode_t *dip,
1288 typnm_t itype)
1289{
1290 switch (dip->di_core.di_format) {
1291 case XFS_DINODE_FMT_LOCAL:
1292 if (!dont_obfuscate)
1293 switch (itype) {
1294 case TYP_DIR2:
1295 obfuscate_sf_dir(dip);
1296 break;
1297
1298 case TYP_SYMLINK:
1299 obfuscate_sf_symlink(dip);
1300 break;
1301
1302 default: ;
1303 }
1304 break;
1305
1306 case XFS_DINODE_FMT_EXTENTS:
1307 return process_exinode(dip, itype);
1308
1309 case XFS_DINODE_FMT_BTREE:
1310 return process_btinode(dip, itype);
1311 }
1312 return 1;
1313}
1314
1315static int
1316process_inode(
1317 xfs_agnumber_t agno,
1318 xfs_agino_t agino,
1319 xfs_dinode_t *dip)
1320{
61983f67
BN
1321 int success;
1322
61983f67
BN
1323 success = 1;
1324 cur_ino = XFS_AGINO_TO_INO(mp, agno, agino);
1325
61983f67 1326 /* copy appropriate data fork metadata */
5e656dbb 1327 switch (be16_to_cpu(dip->di_core.di_mode) & S_IFMT) {
61983f67
BN
1328 case S_IFDIR:
1329 memset(&dir_data, 0, sizeof(dir_data));
1330 success = process_inode_data(dip, TYP_DIR2);
1331 break;
1332 case S_IFLNK:
1333 success = process_inode_data(dip, TYP_SYMLINK);
1334 break;
88b8e1d6 1335 case S_IFREG:
61983f67 1336 success = process_inode_data(dip, TYP_DATA);
88b8e1d6
BN
1337 break;
1338 default: ;
61983f67 1339 }
a85f8b0a 1340 nametable_clear();
61983f67 1341
88b8e1d6 1342 /* copy extended attributes if they exist and forkoff is valid */
5e656dbb 1343 if (success && XFS_DFORK_DSIZE(dip, mp) < XFS_LITINO(mp)) {
61983f67
BN
1344 attr_data.remote_val_count = 0;
1345 switch (dip->di_core.di_aformat) {
1346 case XFS_DINODE_FMT_LOCAL:
1347 if (!dont_obfuscate)
1348 obfuscate_sf_attr(dip);
1349 break;
1350
1351 case XFS_DINODE_FMT_EXTENTS:
1352 success = process_exinode(dip, TYP_ATTR);
1353 break;
1354
1355 case XFS_DINODE_FMT_BTREE:
1356 success = process_btinode(dip, TYP_ATTR);
1357 break;
1358 }
a85f8b0a 1359 nametable_clear();
61983f67 1360 }
61983f67
BN
1361 return success;
1362}
1363
1364static __uint32_t inodes_copied = 0;
1365
1366static int
1367copy_inode_chunk(
1368 xfs_agnumber_t agno,
1369 xfs_inobt_rec_t *rp)
1370{
1371 xfs_agino_t agino;
1372 int off;
1373 xfs_agblock_t agbno;
1374 int i;
d24c0a90 1375 int rval = 0;
61983f67
BN
1376
1377 agino = be32_to_cpu(rp->ir_startino);
1378 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
1379 off = XFS_INO_TO_OFFSET(mp, agino);
1380
88b8e1d6
BN
1381 if (agino == 0 || agino == NULLAGINO || !valid_bno(agno, agbno) ||
1382 !valid_bno(agno, XFS_AGINO_TO_AGBNO(mp,
1383 agino + XFS_INODES_PER_CHUNK - 1))) {
1384 if (show_warnings)
1385 print_warning("bad inode number %llu (%u/%u)",
1386 XFS_AGINO_TO_INO(mp, agno, agino), agno, agino);
1387 return 1;
1388 }
1389
61983f67
BN
1390 push_cur();
1391 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
1392 XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)),
1393 DB_RING_IGN, NULL);
1394 if (iocur_top->data == NULL) {
1395 print_warning("cannot read inode block %u/%u", agno, agbno);
d24c0a90
BN
1396 rval = !stop_on_read_error;
1397 goto pop_out;
61983f67
BN
1398 }
1399
88b8e1d6
BN
1400 /*
1401 * check for basic assumptions about inode chunks, and if any
1402 * assumptions fail, don't process the inode chunk.
1403 */
1404
1405 if ((mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && off != 0) ||
1406 (mp->m_sb.sb_inopblock > XFS_INODES_PER_CHUNK &&
1407 off % XFS_INODES_PER_CHUNK != 0) ||
5e656dbb 1408 (xfs_sb_version_hasalign(&mp->m_sb) &&
88b8e1d6
BN
1409 agbno % mp->m_sb.sb_inoalignmt != 0)) {
1410 if (show_warnings)
1411 print_warning("badly aligned inode (start = %llu)",
1412 XFS_AGINO_TO_INO(mp, agno, agino));
1413 goto skip_processing;
1414 }
1415
61983f67
BN
1416 /*
1417 * scan through inodes and copy any btree extent lists, directory
1418 * contents and extended attributes.
1419 */
61983f67
BN
1420 for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
1421 xfs_dinode_t *dip;
1422
1423 if (XFS_INOBT_IS_FREE_DISK(rp, i))
1424 continue;
1425
1426 dip = (xfs_dinode_t *)((char *)iocur_top->data +
1427 ((off + i) << mp->m_sb.sb_inodelog));
1428
1429 if (!process_inode(agno, agino + i, dip))
d24c0a90 1430 goto pop_out;
61983f67 1431 }
88b8e1d6 1432skip_processing:
61983f67 1433 if (!write_buf(iocur_top))
d24c0a90 1434 goto pop_out;
61983f67
BN
1435
1436 inodes_copied += XFS_INODES_PER_CHUNK;
1437
1438 if (show_progress)
1439 print_progress("Copied %u of %u inodes (%u of %u AGs)",
1440 inodes_copied, mp->m_sb.sb_icount, agno,
1441 mp->m_sb.sb_agcount);
d24c0a90
BN
1442 rval = 1;
1443pop_out:
61983f67 1444 pop_cur();
d24c0a90 1445 return rval;
61983f67
BN
1446}
1447
1448static int
1449scanfunc_ino(
b194c7d8 1450 struct xfs_btree_block *block,
61983f67
BN
1451 xfs_agnumber_t agno,
1452 xfs_agblock_t agbno,
1453 int level,
1454 typnm_t btype,
1455 void *arg)
1456{
1457 xfs_inobt_rec_t *rp;
1458 xfs_inobt_ptr_t *pp;
1459 int i;
88b8e1d6
BN
1460 int numrecs;
1461
b194c7d8 1462 numrecs = be16_to_cpu(block->bb_numrecs);
61983f67
BN
1463
1464 if (level == 0) {
88b8e1d6
BN
1465 if (numrecs > mp->m_inobt_mxr[0]) {
1466 if (show_warnings)
1467 print_warning("invalid numrecs %d in %s "
1468 "block %u/%u", numrecs,
1469 typtab[btype].name, agno, agbno);
1470 numrecs = mp->m_inobt_mxr[0];
1471 }
b3563c19 1472 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
88b8e1d6 1473 for (i = 0; i < numrecs; i++, rp++) {
61983f67
BN
1474 if (!copy_inode_chunk(agno, rp))
1475 return 0;
1476 }
88b8e1d6
BN
1477 return 1;
1478 }
1479
1480 if (numrecs > mp->m_inobt_mxr[1]) {
1481 if (show_warnings)
1482 print_warning("invalid numrecs %d in %s block %u/%u",
1483 numrecs, typtab[btype].name, agno, agbno);
1484 numrecs = mp->m_inobt_mxr[1];
1485 }
1486
b3563c19 1487 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
88b8e1d6
BN
1488 for (i = 0; i < numrecs; i++) {
1489 if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
1490 if (show_warnings)
1491 print_warning("invalid block number (%u/%u) "
1492 "in %s block %u/%u",
1493 agno, be32_to_cpu(pp[i]),
1494 typtab[btype].name, agno, agbno);
1495 continue;
61983f67 1496 }
88b8e1d6
BN
1497 if (!scan_btree(agno, be32_to_cpu(pp[i]), level,
1498 btype, arg, scanfunc_ino))
1499 return 0;
61983f67
BN
1500 }
1501 return 1;
1502}
1503
1504static int
1505copy_inodes(
1506 xfs_agnumber_t agno,
1507 xfs_agi_t *agi)
1508{
1509 xfs_agblock_t root;
1510 int levels;
1511
1512 root = be32_to_cpu(agi->agi_root);
1513 levels = be32_to_cpu(agi->agi_level);
1514
1515 /* validate root and levels before processing the tree */
1516 if (root == 0 || root > mp->m_sb.sb_agblocks) {
1517 if (show_warnings)
1518 print_warning("invalid block number (%u) in inobt "
1519 "root in agi %u", root, agno);
1520 return 1;
1521 }
1522 if (levels >= XFS_BTREE_MAXLEVELS) {
1523 if (show_warnings)
1524 print_warning("invalid level (%u) in inobt root "
1525 "in agi %u", levels, agno);
1526 return 1;
1527 }
1528
1529 return scan_btree(agno, root, levels, TYP_INOBT, agi, scanfunc_ino);
1530}
1531
1532static int
1533scan_ag(
1534 xfs_agnumber_t agno)
1535{
1536 xfs_agf_t *agf;
1537 xfs_agi_t *agi;
d24c0a90
BN
1538 int stack_count = 0;
1539 int rval = 0;
61983f67
BN
1540
1541 /* copy the superblock of the AG */
1542 push_cur();
d24c0a90 1543 stack_count++;
61983f67
BN
1544 set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
1545 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
1546 if (!iocur_top->data) {
1547 print_warning("cannot read superblock for ag %u", agno);
1548 if (stop_on_read_error)
d24c0a90 1549 goto pop_out;
61983f67
BN
1550 } else {
1551 if (!write_buf(iocur_top))
d24c0a90 1552 goto pop_out;
61983f67
BN
1553 }
1554
1555 /* copy the AG free space btree root */
1556 push_cur();
d24c0a90 1557 stack_count++;
61983f67
BN
1558 set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
1559 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
1560 agf = iocur_top->data;
1561 if (iocur_top->data == NULL) {
1562 print_warning("cannot read agf block for ag %u", agno);
1563 if (stop_on_read_error)
d24c0a90 1564 goto pop_out;
61983f67
BN
1565 } else {
1566 if (!write_buf(iocur_top))
d24c0a90 1567 goto pop_out;
61983f67
BN
1568 }
1569
1570 /* copy the AG inode btree root */
1571 push_cur();
d24c0a90 1572 stack_count++;
61983f67
BN
1573 set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
1574 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
1575 agi = iocur_top->data;
1576 if (iocur_top->data == NULL) {
1577 print_warning("cannot read agi block for ag %u", agno);
1578 if (stop_on_read_error)
d24c0a90 1579 goto pop_out;
61983f67
BN
1580 } else {
1581 if (!write_buf(iocur_top))
d24c0a90 1582 goto pop_out;
61983f67
BN
1583 }
1584
1585 /* copy the AG free list header */
1586 push_cur();
d24c0a90 1587 stack_count++;
61983f67
BN
1588 set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
1589 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
1590 if (iocur_top->data == NULL) {
1591 print_warning("cannot read agfl block for ag %u", agno);
1592 if (stop_on_read_error)
d24c0a90 1593 goto pop_out;
61983f67
BN
1594 } else {
1595 if (!write_buf(iocur_top))
d24c0a90 1596 goto pop_out;
61983f67 1597 }
61983f67
BN
1598
1599 /* copy AG free space btrees */
1600 if (agf) {
1601 if (show_progress)
1602 print_progress("Copying free space trees of AG %u",
1603 agno);
1604 if (!copy_free_bno_btree(agno, agf))
d24c0a90 1605 goto pop_out;
61983f67 1606 if (!copy_free_cnt_btree(agno, agf))
d24c0a90 1607 goto pop_out;
61983f67
BN
1608 }
1609
1610 /* copy inode btrees and the inodes and their associated metadata */
1611 if (agi) {
1612 if (!copy_inodes(agno, agi))
d24c0a90 1613 goto pop_out;
61983f67 1614 }
d24c0a90
BN
1615 rval = 1;
1616pop_out:
1617 while (stack_count--)
1618 pop_cur();
1619 return rval;
61983f67
BN
1620}
1621
1622static int
1623copy_ino(
1624 xfs_ino_t ino,
1625 typnm_t itype)
1626{
1627 xfs_agnumber_t agno;
1628 xfs_agblock_t agbno;
1629 xfs_agino_t agino;
61983f67 1630 int offset;
d24c0a90 1631 int rval = 0;
61983f67
BN
1632
1633 if (ino == 0)
1634 return 1;
1635
1636 agno = XFS_INO_TO_AGNO(mp, ino);
1637 agino = XFS_INO_TO_AGINO(mp, ino);
1638 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
1639 offset = XFS_AGINO_TO_OFFSET(mp, agino);
1640
1641 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
1642 offset >= mp->m_sb.sb_inopblock) {
1643 if (show_warnings)
1644 print_warning("invalid %s inode number (%lld)",
1645 typtab[itype].name, (long long)ino);
1646 return 1;
1647 }
1648
1649 push_cur();
1650 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
1651 blkbb, DB_RING_IGN, NULL);
1652 if (iocur_top->data == NULL) {
1653 print_warning("cannot read %s inode %lld",
1654 typtab[itype].name, (long long)ino);
d24c0a90
BN
1655 rval = !stop_on_read_error;
1656 goto pop_out;
61983f67
BN
1657 }
1658 off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
1659
61983f67 1660 cur_ino = ino;
5e656dbb 1661 rval = process_inode_data(iocur_top->data, itype);
d24c0a90
BN
1662pop_out:
1663 pop_cur();
1664 return rval;
61983f67
BN
1665}
1666
1667
1668static int
1669copy_sb_inodes(void)
1670{
1671 if (!copy_ino(mp->m_sb.sb_rbmino, TYP_RTBITMAP))
1672 return 0;
1673
1674 if (!copy_ino(mp->m_sb.sb_rsumino, TYP_RTSUMMARY))
1675 return 0;
1676
1677 if (!copy_ino(mp->m_sb.sb_uquotino, TYP_DQBLK))
1678 return 0;
1679
1680 return copy_ino(mp->m_sb.sb_gquotino, TYP_DQBLK);
1681}
1682
1683static int
1684copy_log(void)
1685{
1686 if (show_progress)
1687 print_progress("Copying log");
1688
1689 push_cur();
1690 set_cur(&typtab[TYP_LOG], XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
1691 mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL);
1692 if (iocur_top->data == NULL) {
d24c0a90 1693 pop_cur();
61983f67
BN
1694 print_warning("cannot read log");
1695 return !stop_on_read_error;
1696 }
1697 return write_buf(iocur_top);
1698}
1699
1700static int
1701metadump_f(
1702 int argc,
1703 char **argv)
1704{
1705 xfs_agnumber_t agno;
1706 int c;
1707 int start_iocur_sp;
88b8e1d6 1708 char *p;
61983f67
BN
1709
1710 exitcode = 1;
1711 show_progress = 0;
1712 show_warnings = 0;
1713 stop_on_read_error = 0;
1714
1715 if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
1716 print_warning("bad superblock magic number %x, giving up",
1717 mp->m_sb.sb_magicnum);
1718 return 0;
1719 }
1720
88b8e1d6 1721 while ((c = getopt(argc, argv, "egm:ow")) != EOF) {
61983f67
BN
1722 switch (c) {
1723 case 'e':
1724 stop_on_read_error = 1;
1725 break;
1726 case 'g':
1727 show_progress = 1;
1728 break;
88b8e1d6
BN
1729 case 'm':
1730 max_extent_size = (int)strtol(optarg, &p, 0);
1731 if (*p != '\0' || max_extent_size <= 0) {
1732 print_warning("bad max extent size %s",
1733 optarg);
1734 return 0;
1735 }
1736 break;
61983f67
BN
1737 case 'o':
1738 dont_obfuscate = 1;
1739 break;
1740 case 'w':
1741 show_warnings = 1;
1742 break;
1743 default:
1744 print_warning("bad option for metadump command");
1745 return 0;
1746 }
1747 }
1748
1749 if (optind != argc - 1) {
1750 print_warning("too few options for metadump (no filename given)");
1751 return 0;
1752 }
1753
1754 metablock = (xfs_metablock_t *)calloc(BBSIZE + 1, BBSIZE);
1755 if (metablock == NULL) {
1756 print_warning("memory allocation failure");
1757 return 0;
1758 }
1759 metablock->mb_blocklog = BBSHIFT;
1760 metablock->mb_magic = cpu_to_be32(XFS_MD_MAGIC);
1761
61983f67
BN
1762 block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t));
1763 block_buffer = (char *)metablock + BBSIZE;
1764 num_indicies = (BBSIZE - sizeof(xfs_metablock_t)) / sizeof(__be64);
1765 cur_index = 0;
1766 start_iocur_sp = iocur_sp;
1767
1768 if (strcmp(argv[optind], "-") == 0) {
1769 if (isatty(fileno(stdout))) {
1770 print_warning("cannot write to a terminal");
61983f67
BN
1771 free(metablock);
1772 return 0;
1773 }
1774 outf = stdout;
1775 } else {
1776 outf = fopen(argv[optind], "wb");
1777 if (outf == NULL) {
1778 print_warning("cannot create dump file");
61983f67
BN
1779 free(metablock);
1780 return 0;
1781 }
1782 }
1783
1784 exitcode = 0;
1785
1786 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
1787 if (!scan_ag(agno)) {
1788 exitcode = 1;
1789 break;
1790 }
1791 }
1792
1793 /* copy realtime and quota inode contents */
1794 if (!exitcode)
1795 exitcode = !copy_sb_inodes();
1796
1797 /* copy log if it's internal */
1798 if ((mp->m_sb.sb_logstart != 0) && !exitcode)
1799 exitcode = !copy_log();
1800
1801 /* write the remaining index */
1802 if (!exitcode)
1803 exitcode = !write_index();
1804
1805 if (progress_since_warning)
1806 fputc('\n', (outf == stdout) ? stderr : stdout);
1807
1808 if (outf != stdout)
1809 fclose(outf);
1810
1811 /* cleanup iocur stack */
1812 while (iocur_sp > start_iocur_sp)
1813 pop_cur();
1814
61983f67
BN
1815 free(metablock);
1816
1817 return 0;
1818}