]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/dir2.c
Merge whitespace changes over
[thirdparty/xfsprogs-dev.git] / repair / dir2.c
1 /*
2 * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <libxfs.h>
34 #include "avl.h"
35 #include "globals.h"
36 #include "incore.h"
37 #include "err_protos.h"
38 #include "dinode.h"
39 #include "dir.h"
40 #include "dir2.h"
41 #include "bmap.h"
42
43 /*
44 * Tag bad directory entries with this.
45 * We can't tag them with -1 since that will look like a
46 * data_unused_t instead of a data_entry_t.
47 */
48 #define BADFSINO ((xfs_ino_t)0xfeffffffffffffffULL)
49
50 /*
51 * Known bad inode list. These are seen when the leaf and node
52 * block linkages are incorrect.
53 */
54 typedef struct dir2_bad {
55 xfs_ino_t ino;
56 struct dir2_bad *next;
57 } dir2_bad_t;
58 dir2_bad_t *dir2_bad_list;
59
60 void
61 dir2_add_badlist(
62 xfs_ino_t ino)
63 {
64 dir2_bad_t *l;
65
66 if ((l = malloc(sizeof(dir2_bad_t))) == NULL) {
67 do_error(
68 _("malloc failed (%u bytes) dir2_add_badlist:ino %llu\n"),
69 sizeof(dir2_bad_t), ino);
70 exit(1);
71 }
72 l->next = dir2_bad_list;
73 dir2_bad_list = l;
74 l->ino = ino;
75 }
76
77 int
78 dir2_is_badino(
79 xfs_ino_t ino)
80 {
81 dir2_bad_t *l;
82
83 for (l = dir2_bad_list; l; l = l->next)
84 if (l->ino == ino)
85 return 1;
86 return 0;
87 }
88
89 /*
90 * Multibuffer handling.
91 * V2 directory blocks can be noncontiguous, needing multiple buffers.
92 */
93 xfs_dabuf_t *
94 da_read_buf(
95 xfs_mount_t *mp,
96 int nex,
97 bmap_ext_t *bmp)
98 {
99 xfs_buf_t *bp;
100 xfs_buf_t **bplist;
101 xfs_dabuf_t *dabuf;
102 int i;
103 int off;
104
105 bplist = calloc(nex, sizeof(*bplist));
106 if (bplist == NULL) {
107 do_error(_("couldn't malloc dir2 buffer list\n"));
108 exit(1);
109 }
110 for (i = 0; i < nex; i++) {
111 bplist[i] = libxfs_readbuf(mp->m_dev,
112 XFS_FSB_TO_DADDR(mp, bmp[i].startblock),
113 XFS_FSB_TO_BB(mp, bmp[i].blockcount), 0);
114 if (!bplist[i])
115 goto failed;
116 }
117 dabuf = malloc(XFS_DA_BUF_SIZE(nex));
118 if (dabuf == NULL) {
119 do_error(_("couldn't malloc dir2 buffer header\n"));
120 exit(1);
121 }
122 dabuf->dirty = 0;
123 dabuf->nbuf = nex;
124 if (nex == 1) {
125 bp = bplist[0];
126 dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
127 dabuf->data = XFS_BUF_PTR(bp);
128 dabuf->bps[0] = bp;
129 } else {
130 for (i = 0, dabuf->bbcount = 0; i < nex; i++) {
131 dabuf->bps[i] = bp = bplist[i];
132 dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp));
133 }
134 dabuf->data = malloc(BBTOB(dabuf->bbcount));
135 if (dabuf->data == NULL) {
136 do_error(_("couldn't malloc dir2 buffer data\n"));
137 exit(1);
138 }
139 for (i = off = 0; i < nex; i++, off += XFS_BUF_COUNT(bp)) {
140 bp = bplist[i];
141 bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
142 XFS_BUF_COUNT(bp));
143 }
144 }
145 return dabuf;
146 failed:
147 for (i = 0; i < nex; i++)
148 libxfs_putbuf(bplist[i]);
149 free(bplist);
150 return NULL;
151 }
152
153 static void
154 da_buf_clean(
155 xfs_dabuf_t *dabuf)
156 {
157 xfs_buf_t *bp;
158 int i;
159 int off;
160
161 if (dabuf->dirty) {
162 dabuf->dirty = 0;
163 for (i=off=0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) {
164 bp = dabuf->bps[i];
165 bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
166 XFS_BUF_COUNT(bp));
167 }
168 }
169 }
170
171 static void
172 da_buf_done(
173 xfs_dabuf_t *dabuf)
174 {
175 da_buf_clean(dabuf);
176 if (dabuf->nbuf > 1)
177 free(dabuf->data);
178 free(dabuf);
179 }
180
181 int
182 da_bwrite(
183 xfs_mount_t *mp,
184 xfs_dabuf_t *dabuf)
185 {
186 xfs_buf_t *bp;
187 xfs_buf_t **bplist;
188 int e;
189 int error;
190 int i;
191 int nbuf;
192 int off;
193
194 if ((nbuf = dabuf->nbuf) == 1) {
195 bplist = &bp;
196 bp = dabuf->bps[0];
197 } else {
198 bplist = malloc(nbuf * sizeof(*bplist));
199 if (bplist == NULL) {
200 do_error(_("couldn't malloc dir2 buffer list\n"));
201 exit(1);
202 }
203 bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
204 for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
205 bp = bplist[i];
206 bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
207 XFS_BUF_COUNT(bp));
208 }
209 }
210 da_buf_done(dabuf);
211 for (i = error = 0; i < nbuf; i++) {
212 e = libxfs_writebuf(bplist[i], 0);
213 if (e)
214 error = e;
215 }
216 if (bplist != &bp)
217 free(bplist);
218 return error;
219 }
220
221 void
222 da_brelse(
223 xfs_dabuf_t *dabuf)
224 {
225 xfs_buf_t *bp;
226 xfs_buf_t **bplist;
227 int i;
228 int nbuf;
229
230 if ((nbuf = dabuf->nbuf) == 1) {
231 bplist = &bp;
232 bp = dabuf->bps[0];
233 } else {
234 bplist = malloc(nbuf * sizeof(*bplist));
235 if (bplist == NULL) {
236 do_error(_("couldn't malloc dir2 buffer list\n"));
237 exit(1);
238 }
239 bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
240 }
241 da_buf_done(dabuf);
242 for (i = 0; i < nbuf; i++)
243 libxfs_putbuf(bplist[i]);
244 if (bplist != &bp)
245 free(bplist);
246 }
247
248 /*
249 * walk tree from root to the left-most leaf block reading in
250 * blocks and setting up cursor. passes back file block number of the
251 * left-most leaf block if successful (bno). returns 1 if successful,
252 * 0 if unsuccessful.
253 */
254 int
255 traverse_int_dir2block(xfs_mount_t *mp,
256 dir2_bt_cursor_t *da_cursor,
257 xfs_dablk_t *rbno)
258 {
259 bmap_ext_t *bmp;
260 xfs_dablk_t bno;
261 xfs_dabuf_t *bp;
262 int i;
263 int nex;
264 xfs_da_intnode_t *node;
265
266 /*
267 * traverse down left-side of tree until we hit the
268 * left-most leaf block setting up the btree cursor along
269 * the way.
270 */
271 bno = mp->m_dirleafblk;
272 i = -1;
273 node = NULL;
274 da_cursor->active = 0;
275
276 do {
277 /*
278 * read in each block along the way and set up cursor
279 */
280 nex = blkmap_getn(da_cursor->blkmap, bno, mp->m_dirblkfsbs,
281 &bmp);
282
283 if (nex == 0)
284 goto error_out;
285
286 bp = da_read_buf(mp, nex, bmp);
287 free(bmp);
288 if (bp == NULL) {
289 do_warn(_("can't read block %u for directory inode "
290 "%llu\n"),
291 bno, da_cursor->ino);
292 goto error_out;
293 }
294
295 node = bp->data;
296
297 if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) ==
298 XFS_DIR2_LEAFN_MAGIC) {
299 if ( i != -1 ) {
300 do_warn(_("found non-root LEAFN node in inode "
301 "%llu bno = %u\n"),
302 da_cursor->ino, bno);
303 }
304 if (INT_GET(node->hdr.level, ARCH_CONVERT) >= 1) {
305 do_warn(_("LEAFN node level is %d inode %llu "
306 "bno = %u\n"),
307 INT_GET(node->hdr.level, ARCH_CONVERT),
308 da_cursor->ino, bno);
309 }
310 *rbno = 0;
311 da_brelse(bp);
312 return(1);
313 } else if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) !=
314 XFS_DA_NODE_MAGIC) {
315 da_brelse(bp);
316 do_warn(_("bad dir magic number 0x%x in inode %llu "
317 "bno = %u\n"),
318 INT_GET(node->hdr.info.magic, ARCH_CONVERT),
319 da_cursor->ino, bno);
320 goto error_out;
321 }
322 if (INT_GET(node->hdr.count, ARCH_CONVERT) >
323 mp->m_dir_node_ents) {
324 da_brelse(bp);
325 do_warn(_("bad record count in inode %llu, count = %d, "
326 "max = %d\n"), da_cursor->ino,
327 INT_GET(node->hdr.count, ARCH_CONVERT),
328 mp->m_dir_node_ents);
329 goto error_out;
330 }
331
332 /*
333 * maintain level counter
334 */
335 if (i == -1)
336 i = da_cursor->active =
337 INT_GET(node->hdr.level, ARCH_CONVERT);
338 else {
339 if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1) {
340 i--;
341 } else {
342 do_warn(_("bad directory btree for directory "
343 "inode %llu\n"),
344 da_cursor->ino);
345 da_brelse(bp);
346 goto error_out;
347 }
348 }
349
350 da_cursor->level[i].hashval =
351 INT_GET(node->btree[0].hashval, ARCH_CONVERT);
352 da_cursor->level[i].bp = bp;
353 da_cursor->level[i].bno = bno;
354 da_cursor->level[i].index = 0;
355
356 /*
357 * set up new bno for next level down
358 */
359 bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
360 } while (node != NULL && i > 1);
361
362 /*
363 * now return block number and get out
364 */
365 *rbno = da_cursor->level[0].bno = bno;
366 return(1);
367
368 error_out:
369 while (i > 1 && i <= da_cursor->active) {
370 da_brelse(da_cursor->level[i].bp);
371 i++;
372 }
373
374 return(0);
375 }
376
377 /*
378 * blow out buffer for this level and all the rest above as well
379 * if error == 0, we are not expecting to encounter any unreleased
380 * buffers (e.g. if we do, it's a mistake). if error == 1, we're
381 * in an error-handling case so unreleased buffers may exist.
382 */
383 void
384 release_dir2_cursor_int(xfs_mount_t *mp,
385 dir2_bt_cursor_t *cursor,
386 int prev_level,
387 int error)
388 {
389 int level = prev_level + 1;
390
391 if (cursor->level[level].bp != NULL) {
392 if (!error) {
393 do_warn(_("release_dir2_cursor_int got unexpected "
394 "non-null bp, dabno = %u\n"),
395 cursor->level[level].bno);
396 }
397 ASSERT(error != 0);
398
399 da_brelse(cursor->level[level].bp);
400 cursor->level[level].bp = NULL;
401 }
402
403 if (level < cursor->active)
404 release_dir2_cursor_int(mp, cursor, level, error);
405
406 return;
407 }
408
409 void
410 release_dir2_cursor(xfs_mount_t *mp,
411 dir2_bt_cursor_t *cursor,
412 int prev_level)
413 {
414 release_dir2_cursor_int(mp, cursor, prev_level, 0);
415 }
416
417 void
418 err_release_dir2_cursor(xfs_mount_t *mp,
419 dir2_bt_cursor_t *cursor,
420 int prev_level)
421 {
422 release_dir2_cursor_int(mp, cursor, prev_level, 1);
423 }
424
425 /*
426 * make sure that all entries in all blocks along the right side of
427 * of the tree are used and hashval's are consistent. level is the
428 * level of the descendent block. returns 0 if good (even if it had
429 * to be fixed up), and 1 if bad. The right edge of the tree is
430 * technically a block boundary. This routine should be used then
431 * instead of verify_dir2_path().
432 */
433 int
434 verify_final_dir2_path(xfs_mount_t *mp,
435 dir2_bt_cursor_t *cursor,
436 const int p_level)
437 {
438 xfs_da_intnode_t *node;
439 int bad = 0;
440 int entry;
441 int this_level = p_level + 1;
442
443 /*
444 * the index should point to the next "unprocessed" entry
445 * in the block which should be the final (rightmost) entry
446 */
447 entry = cursor->level[this_level].index;
448 node = (xfs_da_intnode_t *)(cursor->level[this_level].bp->data);
449 /*
450 * check internal block consistency on this level -- ensure
451 * that all entries are used, encountered and expected hashvals
452 * match, etc.
453 */
454 if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1) {
455 do_warn(
456 _("directory block used/count inconsistency - %d / %hu\n"),
457 entry, INT_GET(node->hdr.count, ARCH_CONVERT));
458 bad++;
459 }
460 /*
461 * hash values monotonically increasing ???
462 */
463 if (cursor->level[this_level].hashval >=
464 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
465 do_warn(_("directory/attribute block hashvalue inconsistency, "
466 "expected > %u / saw %u\n"),
467 cursor->level[this_level].hashval,
468 INT_GET(node->btree[entry].hashval, ARCH_CONVERT));
469 bad++;
470 }
471 if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0) {
472 do_warn(_("bad directory/attribute forward block pointer, "
473 "expected 0, saw %u\n"),
474 INT_GET(node->hdr.info.forw, ARCH_CONVERT));
475 bad++;
476 }
477 if (bad) {
478 do_warn(_("bad directory block in inode %llu\n"), cursor->ino);
479 return(1);
480 }
481 /*
482 * keep track of greatest block # -- that gets
483 * us the length of the directory
484 */
485 if (cursor->level[this_level].bno > cursor->greatest_bno)
486 cursor->greatest_bno = cursor->level[this_level].bno;
487
488 /*
489 * ok, now check descendant block number against this level
490 */
491 if (cursor->level[p_level].bno !=
492 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
493 return(1);
494 }
495
496 if (cursor->level[p_level].hashval !=
497 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
498 if (!no_modify) {
499 do_warn(_("correcting bad hashval in non-leaf dir "
500 "block\n\tin (level %d) in inode %llu.\n"),
501 this_level, cursor->ino);
502 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
503 cursor->level[p_level].hashval);
504 cursor->level[this_level].dirty++;
505 } else {
506 do_warn(_("would correct bad hashval in non-leaf dir "
507 "block\n\tin (level %d) in inode %llu.\n"),
508 this_level, cursor->ino);
509 }
510 }
511
512 /*
513 * release/write buffer
514 */
515 ASSERT(cursor->level[this_level].dirty == 0 ||
516 (cursor->level[this_level].dirty && !no_modify));
517
518 if (cursor->level[this_level].dirty && !no_modify)
519 da_bwrite(mp, cursor->level[this_level].bp);
520 else
521 da_brelse(cursor->level[this_level].bp);
522
523 cursor->level[this_level].bp = NULL;
524
525 /*
526 * bail out if this is the root block (top of tree)
527 */
528 if (this_level >= cursor->active) {
529 return(0);
530 }
531 /*
532 * set hashvalue to correctl reflect the now-validated
533 * last entry in this block and continue upwards validation
534 */
535 cursor->level[this_level].hashval =
536 INT_GET(node->btree[entry].hashval, ARCH_CONVERT);
537
538 return(verify_final_dir2_path(mp, cursor, this_level));
539 }
540
541 /*
542 * Verifies the path from a descendant block up to the root.
543 * Should be called when the descendant level traversal hits
544 * a block boundary before crossing the boundary (reading in a new
545 * block).
546 *
547 * the directory/attr btrees work differently to the other fs btrees.
548 * each interior block contains records that are <hashval, bno>
549 * pairs. The bno is a file bno, not a filesystem bno. The last
550 * hashvalue in the block <bno> will be <hashval>. BUT unlike
551 * the freespace btrees, the *last* value in each block gets
552 * propagated up the tree instead of the first value in each block.
553 * that is, the interior records point to child blocks and the *greatest*
554 * hash value contained by the child block is the one the block above
555 * uses as the key for the child block.
556 *
557 * level is the level of the descendent block. returns 0 if good,
558 * and 1 if bad. The descendant block may be a leaf block.
559 *
560 * the invariant here is that the values in the cursor for the
561 * levels beneath this level (this_level) and the cursor index
562 * for this level *must* be valid.
563 *
564 * that is, the hashval/bno info is accurate for all
565 * DESCENDANTS and match what the node[index] information
566 * for the current index in the cursor for this level.
567 *
568 * the index values in the cursor for the descendant level
569 * are allowed to be off by one as they will reflect the
570 * next entry at those levels to be processed.
571 *
572 * the hashvalue for the current level can't be set until
573 * we hit the last entry in the block so, it's garbage
574 * until set by this routine.
575 *
576 * bno and bp for the current block/level are always valid
577 * since they have to be set so we can get a buffer for the
578 * block.
579 */
580 int
581 verify_dir2_path(xfs_mount_t *mp,
582 dir2_bt_cursor_t *cursor,
583 const int p_level)
584 {
585 xfs_da_intnode_t *node;
586 xfs_da_intnode_t *newnode;
587 xfs_dablk_t dabno;
588 xfs_dabuf_t *bp;
589 int bad;
590 int entry;
591 int this_level = p_level + 1;
592 bmap_ext_t *bmp;
593 int nex;
594
595 /*
596 * index is currently set to point to the entry that
597 * should be processed now in this level.
598 */
599 entry = cursor->level[this_level].index;
600 node = cursor->level[this_level].bp->data;
601
602 /*
603 * if this block is out of entries, validate this
604 * block and move on to the next block.
605 * and update cursor value for said level
606 */
607 if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT)) {
608 /*
609 * update the hash value for this level before
610 * validating it. bno value should be ok since
611 * it was set when the block was first read in.
612 */
613 cursor->level[this_level].hashval =
614 INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT);
615
616 /*
617 * keep track of greatest block # -- that gets
618 * us the length of the directory
619 */
620 if (cursor->level[this_level].bno > cursor->greatest_bno)
621 cursor->greatest_bno = cursor->level[this_level].bno;
622
623 /*
624 * validate the path for the current used-up block
625 * before we trash it
626 */
627 if (verify_dir2_path(mp, cursor, this_level))
628 return(1);
629 /*
630 * ok, now get the next buffer and check sibling pointers
631 */
632 dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT);
633 ASSERT(dabno != 0);
634 nex = blkmap_getn(cursor->blkmap, dabno, mp->m_dirblkfsbs,
635 &bmp);
636 if (nex == 0) {
637 do_warn(_("can't get map info for block %u of "
638 "directory inode %llu\n"),
639 dabno, cursor->ino);
640 return(1);
641 }
642
643 bp = da_read_buf(mp, nex, bmp);
644
645 if (bp == NULL) {
646 do_warn(_("can't read block %u for directory inode "
647 "%llu\n"),
648 dabno, cursor->ino);
649 return(1);
650 }
651
652 newnode = bp->data;
653 /*
654 * verify magic number and back pointer, sanity-check
655 * entry count, verify level
656 */
657 bad = 0;
658 if (XFS_DA_NODE_MAGIC !=
659 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT)) {
660 do_warn(_("bad magic number %x in block %u for "
661 "directory inode %llu\n"),
662 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT),
663 dabno, cursor->ino);
664 bad++;
665 }
666 if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) !=
667 cursor->level[this_level].bno) {
668 do_warn(_("bad back pointer in block %u for directory "
669 "inode %llu\n"),
670 dabno, cursor->ino);
671 bad++;
672 }
673 if (INT_GET(newnode->hdr.count, ARCH_CONVERT) >
674 mp->m_dir_node_ents) {
675 do_warn(_("entry count %d too large in block %u for "
676 "directory inode %llu\n"),
677 INT_GET(newnode->hdr.count, ARCH_CONVERT),
678 dabno, cursor->ino);
679 bad++;
680 }
681 if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) {
682 do_warn(_("bad level %d in block %u for directory "
683 "inode %llu\n"),
684 INT_GET(newnode->hdr.level, ARCH_CONVERT),
685 dabno, cursor->ino);
686 bad++;
687 }
688 if (bad) {
689 da_brelse(bp);
690 return(1);
691 }
692 /*
693 * update cursor, write out the *current* level if
694 * required. don't write out the descendant level
695 */
696 ASSERT(cursor->level[this_level].dirty == 0 ||
697 (cursor->level[this_level].dirty && !no_modify));
698
699 if (cursor->level[this_level].dirty && !no_modify)
700 da_bwrite(mp, cursor->level[this_level].bp);
701 else
702 da_brelse(cursor->level[this_level].bp);
703 cursor->level[this_level].bp = bp;
704 cursor->level[this_level].dirty = 0;
705 cursor->level[this_level].bno = dabno;
706 cursor->level[this_level].hashval =
707 INT_GET(newnode->btree[0].hashval, ARCH_CONVERT);
708 node = newnode;
709
710 entry = cursor->level[this_level].index = 0;
711 }
712 /*
713 * ditto for block numbers
714 */
715 if (cursor->level[p_level].bno !=
716 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
717 return(1);
718 }
719 /*
720 * ok, now validate last hashvalue in the descendant
721 * block against the hashval in the current entry
722 */
723 if (cursor->level[p_level].hashval !=
724 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
725 if (!no_modify) {
726 do_warn(_("correcting bad hashval in interior dir "
727 "block\n\tin (level %d) in inode %llu.\n"),
728 this_level, cursor->ino);
729 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
730 cursor->level[p_level].hashval);
731 cursor->level[this_level].dirty++;
732 } else {
733 do_warn(_("would correct bad hashval in interior dir "
734 "block\n\tin (level %d) in inode %llu.\n"),
735 this_level, cursor->ino);
736 }
737 }
738 /*
739 * increment index for this level to point to next entry
740 * (which should point to the next descendant block)
741 */
742 cursor->level[this_level].index++;
743 return(0);
744 }
745
746 /*
747 * Fix up a shortform directory which was in long form (i8count set)
748 * and is now in short form (i8count clear).
749 * Return pointer to the end of the data when done.
750 */
751 void
752 process_sf_dir2_fixi8(
753 xfs_dir2_sf_t *sfp,
754 xfs_dir2_sf_entry_t **next_sfep)
755 {
756 xfs_ino_t ino;
757 xfs_dir2_sf_t *newsfp;
758 xfs_dir2_sf_entry_t *newsfep;
759 xfs_dir2_sf_t *oldsfp;
760 xfs_dir2_sf_entry_t *oldsfep;
761 int oldsize;
762
763 newsfp = sfp;
764 oldsize = (__psint_t)*next_sfep - (__psint_t)sfp;
765 oldsfp = malloc(oldsize);
766 if (oldsfp == NULL) {
767 do_error(_("couldn't malloc dir2 shortform copy\n"));
768 exit(1);
769 }
770 memmove(oldsfp, newsfp, oldsize);
771 INT_SET(newsfp->hdr.count, ARCH_CONVERT,
772 INT_GET(oldsfp->hdr.count, ARCH_CONVERT));
773 newsfp->hdr.i8count = 0;
774 ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
775 &oldsfp->hdr.parent, ARCH_CONVERT);
776 XFS_DIR2_SF_PUT_INUMBER_ARCH(newsfp, &ino,
777 &newsfp->hdr.parent, ARCH_CONVERT);
778 oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
779 newsfep = XFS_DIR2_SF_FIRSTENTRY(newsfp);
780 while ((int)((char *)oldsfep - (char *)oldsfp) < oldsize) {
781 newsfep->namelen = oldsfep->namelen;
782 XFS_DIR2_SF_PUT_OFFSET_ARCH(newsfep,
783 XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT),
784 ARCH_CONVERT);
785 memmove(newsfep->name, oldsfep->name, newsfep->namelen);
786 ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
787 XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
788 XFS_DIR2_SF_PUT_INUMBER_ARCH(newsfp, &ino,
789 XFS_DIR2_SF_INUMBERP(newsfep), ARCH_CONVERT);
790 oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep);
791 newsfep = XFS_DIR2_SF_NEXTENTRY(newsfp, newsfep);
792 }
793 *next_sfep = newsfep;
794 free(oldsfp);
795 }
796
797 /*
798 * Regenerate legal (minimal) offsets for the shortform directory.
799 */
800 static void
801 process_sf_dir2_fixoff(
802 xfs_dinode_t *dip)
803 {
804 int i;
805 int offset;
806 xfs_dir2_sf_entry_t *sfep;
807 xfs_dir2_sf_t *sfp;
808
809 for (i = 0, sfp = &dip->di_u.di_dir2sf,
810 sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
811 offset = XFS_DIR2_DATA_FIRST_OFFSET;
812 i < INT_GET(sfp->hdr.count, ARCH_CONVERT);
813 i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
814 XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
815 offset += XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
816 }
817 }
818
819 /*
820 * this routine performs inode discovery and tries to fix things
821 * in place. available redundancy -- inode data size should match
822 * used directory space in inode.
823 * a non-zero return value means the directory is bogus and should be blasted.
824 */
825 /* ARGSUSED */
826 static int
827 process_sf_dir2(
828 xfs_mount_t *mp,
829 xfs_ino_t ino,
830 xfs_dinode_t *dip,
831 int ino_discovery,
832 int *dino_dirty, /* out - 1 if dinode buffer dirty */
833 char *dirname, /* directory pathname */
834 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
835 int *repair) /* out - 1 if dir was fixed up */
836 {
837 int bad_offset;
838 int bad_sfnamelen;
839 int i;
840 int i8;
841 __int64_t ino_dir_size;
842 int ino_off;
843 ino_tree_node_t *irec_p;
844 int junkit;
845 char *junkreason = NULL;
846 xfs_ino_t lino;
847 int max_size;
848 char name[MAXNAMELEN + 1];
849 int namelen;
850 xfs_dir2_sf_entry_t *next_sfep;
851 int num_entries;
852 int offset;
853 xfs_dir2_sf_t *sfp;
854 xfs_dir2_sf_entry_t *sfep;
855 int tmp_elen;
856 int tmp_len;
857 xfs_dir2_sf_entry_t *tmp_sfep;
858 xfs_ino_t zero = 0;
859
860 sfp = &dip->di_u.di_dir2sf;
861 max_size = XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT);
862 num_entries = INT_GET(sfp->hdr.count, ARCH_CONVERT);
863 ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT);
864 offset = XFS_DIR2_DATA_FIRST_OFFSET;
865 bad_offset = *repair = 0;
866
867 ASSERT(ino_dir_size <= max_size);
868
869 /*
870 * Initialize i8 based on size of parent inode number.
871 */
872 i8 = (XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)
873 > XFS_DIR2_MAX_SHORT_INUM);
874
875 /*
876 * check for bad entry count
877 */
878 if (num_entries * XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, 1) +
879 XFS_DIR2_SF_HDR_SIZE(0) > max_size ||
880 num_entries == 0)
881 num_entries = 0xFF;
882
883 /*
884 * run through entries, stop at first bad entry, don't need
885 * to check for .. since that's encoded in its own field
886 */
887 sfep = next_sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
888 for (i = 0;
889 i < num_entries && ino_dir_size > (char *)next_sfep - (char *)sfp;
890 i++) {
891 tmp_sfep = NULL;
892 sfep = next_sfep;
893 junkit = 0;
894 bad_sfnamelen = 0;
895 lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
896 XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
897 /*
898 * if entry points to self, junk it since only '.' or '..'
899 * should do that and shortform dirs don't contain either
900 * entry. if inode number is invalid, trash entry.
901 * if entry points to special inodes, trash it.
902 * if inode is unknown but number is valid,
903 * add it to the list of uncertain inodes. don't
904 * have to worry about an entry pointing to a
905 * deleted lost+found inode because the entry was
906 * deleted at the same time that the inode was cleared.
907 */
908 if (lino == ino) {
909 junkit = 1;
910 junkreason = _("current");
911 } else if (verify_inum(mp, lino)) {
912 junkit = 1;
913 junkreason = _("invalid");
914 } else if (lino == mp->m_sb.sb_rbmino) {
915 junkit = 1;
916 junkreason = _("realtime bitmap");
917 } else if (lino == mp->m_sb.sb_rsumino) {
918 junkit = 1;
919 junkreason = _("realtime summary");
920 } else if (lino == mp->m_sb.sb_uquotino) {
921 junkit = 1;
922 junkreason = _("user quota");
923 } else if (lino == mp->m_sb.sb_gquotino) {
924 junkit = 1;
925 junkreason = _("group quota");
926 } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
927 XFS_INO_TO_AGINO(mp, lino))) != NULL) {
928 /*
929 * if inode is marked free and we're in inode
930 * discovery mode, leave the entry alone for now.
931 * if the inode turns out to be used, we'll figure
932 * that out when we scan it. If the inode really
933 * is free, we'll hit this code again in phase 4
934 * after we've finished inode discovery and blow
935 * out the entry then.
936 */
937 ino_off = XFS_INO_TO_AGINO(mp, lino) -
938 irec_p->ino_startnum;
939 ASSERT(is_inode_confirmed(irec_p, ino_off));
940 if (is_inode_free(irec_p, ino_off) && !ino_discovery) {
941 junkit = 1;
942 junkreason = _("free");
943 }
944 } else if (ino_discovery) {
945 /*
946 * put the inode on the uncertain list. we'll
947 * pull the inode off the list and check it later.
948 * if the inode turns out be bogus, we'll delete
949 * this entry in phase 6.
950 */
951 add_inode_uncertain(mp, lino, 0);
952 } else {
953 /*
954 * blow the entry out. we know about all
955 * undiscovered entries now (past inode discovery
956 * phase) so this is clearly a bogus entry.
957 */
958 junkit = 1;
959 junkreason = _("non-existent");
960 }
961 namelen = sfep->namelen;
962 if (junkit)
963 do_warn(_("entry \"%*.*s\" in shortform directory %llu "
964 "references %s inode %llu\n"),
965 namelen, namelen, sfep->name, ino, junkreason,
966 lino);
967 if (namelen == 0) {
968 /*
969 * if we're really lucky, this is
970 * the last entry in which case we
971 * can use the dir size to set the
972 * namelen value. otherwise, forget
973 * it because we're not going to be
974 * able to find the next entry.
975 */
976 bad_sfnamelen = 1;
977
978 if (i == num_entries - 1) {
979 namelen = ino_dir_size -
980 ((__psint_t) &sfep->name[0] -
981 (__psint_t) sfp);
982 if (!no_modify) {
983 do_warn(_("zero length entry in "
984 "shortform dir %llu, "
985 "resetting to %d\n"),
986 ino, namelen);
987 sfep->namelen = namelen;
988 } else {
989 do_warn(_("zero length entry in "
990 "shortform dir %llu, "
991 "would set to %d\n"),
992 ino, namelen);
993 }
994 } else {
995 do_warn(_("zero length entry in shortform dir "
996 "%llu"),
997 ino);
998 if (!no_modify)
999 do_warn(_(", junking %d entries\n"),
1000 num_entries - i);
1001 else
1002 do_warn(_(", would junk %d entries\n"),
1003 num_entries - i);
1004 /*
1005 * don't process the rest of the directory,
1006 * break out of processing looop
1007 */
1008 break;
1009 }
1010 } else if ((__psint_t) sfep - (__psint_t) sfp +
1011 + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)
1012 > ino_dir_size) {
1013 bad_sfnamelen = 1;
1014
1015 if (i == num_entries - 1) {
1016 namelen = ino_dir_size -
1017 ((__psint_t) &sfep->name[0] -
1018 (__psint_t) sfp);
1019 do_warn(_("size of last entry overflows space "
1020 "left in in shortform dir %llu, "),
1021 ino);
1022 if (!no_modify) {
1023 do_warn(_("resetting to %d\n"),
1024 namelen);
1025 sfep->namelen = namelen;
1026 *dino_dirty = 1;
1027 } else {
1028 do_warn(_("would reset to %d\n"),
1029 namelen);
1030 }
1031 } else {
1032 do_warn(_("size of entry #%d overflows space "
1033 "left in in shortform dir %llu\n"),
1034 i, ino);
1035 if (!no_modify) {
1036 if (i == num_entries - 1)
1037 do_warn(
1038 _("junking entry #%d\n"),
1039 i);
1040 else
1041 do_warn(
1042 _("junking %d entries\n"),
1043 num_entries - i);
1044 } else {
1045 if (i == num_entries - 1)
1046 do_warn(
1047 _("would junk entry #%d\n"),
1048 i);
1049 else
1050 do_warn(
1051 _("would junk %d entries\n"),
1052 num_entries - i);
1053 }
1054
1055 break;
1056 }
1057 }
1058
1059 /*
1060 * check for illegal chars in name.
1061 * no need to check for bad length because
1062 * the length value is stored in a byte
1063 * so it can't be too big, it can only wrap
1064 */
1065 if (namecheck((char *)&sfep->name[0], namelen)) {
1066 /*
1067 * junk entry
1068 */
1069 do_warn(_("entry contains illegal character "
1070 "in shortform dir %llu\n"),
1071 ino);
1072 junkit = 1;
1073 }
1074
1075 if (XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) < offset) {
1076 do_warn(_("entry contains offset out of order in "
1077 "shortform dir %llu\n"),
1078 ino);
1079 bad_offset = 1;
1080 }
1081 offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) +
1082 XFS_DIR2_DATA_ENTSIZE(namelen);
1083
1084 /*
1085 * junk the entry by copying up the rest of the
1086 * fork over the current entry and decrementing
1087 * the entry count. if we're in no_modify mode,
1088 * just issue the warning instead. then continue
1089 * the loop with the next_sfep pointer set to the
1090 * correct place in the fork and other counters
1091 * properly set to reflect the deletion if it
1092 * happened.
1093 */
1094 if (junkit) {
1095 bcopy(sfep->name, name, namelen);
1096 name[namelen] = '\0';
1097
1098 if (!no_modify) {
1099 tmp_elen =
1100 XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep);
1101 INT_MOD(dip->di_core.di_size, ARCH_CONVERT,
1102 -(tmp_elen));
1103 ino_dir_size -= tmp_elen;
1104
1105 tmp_sfep = (xfs_dir2_sf_entry_t *)
1106 ((__psint_t) sfep + tmp_elen);
1107 tmp_len = max_size - ((__psint_t) tmp_sfep
1108 - (__psint_t) sfp);
1109
1110 memmove(sfep, tmp_sfep, tmp_len);
1111
1112 INT_MOD(sfp->hdr.count, ARCH_CONVERT, -1);
1113 num_entries--;
1114 bzero((void *) ((__psint_t) sfep + tmp_len),
1115 tmp_elen);
1116
1117 /*
1118 * reset the tmp value to the current
1119 * pointer so we'll process the entry
1120 * we just moved up
1121 */
1122 tmp_sfep = sfep;
1123
1124 /*
1125 * WARNING: drop the index i by one
1126 * so it matches the decremented count
1127 * for accurate comparisons later
1128 */
1129 i--;
1130
1131 *dino_dirty = 1;
1132 *repair = 1;
1133
1134 do_warn(_("junking entry \"%s\" in directory "
1135 "inode %llu\n"),
1136 name, ino);
1137 } else {
1138 do_warn(_("would have junked entry \"%s\" in "
1139 "directory inode %llu\n"),
1140 name, ino);
1141 }
1142 } else if (lino > XFS_DIR2_MAX_SHORT_INUM)
1143 i8++;
1144 /*
1145 * go onto next entry unless we've just junked an
1146 * entry in which the current entry pointer points
1147 * to an unprocessed entry. have to take into zero-len
1148 * entries into account in no modify mode since we
1149 * calculate size based on next_sfep.
1150 */
1151 next_sfep = (tmp_sfep == NULL)
1152 ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
1153 + ((!bad_sfnamelen)
1154 ? XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,
1155 sfep)
1156 : XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,
1157 namelen)))
1158 : tmp_sfep;
1159 }
1160
1161 /* sync up sizes and entry counts */
1162
1163 if (INT_GET(sfp->hdr.count, ARCH_CONVERT) != i) {
1164 if (no_modify) {
1165 do_warn(_("would have corrected entry count "
1166 "in directory %llu from %d to %d\n"),
1167 ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i);
1168 } else {
1169 do_warn(_("corrected entry count in directory %llu, "
1170 "was %d, now %d\n"),
1171 ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i);
1172 INT_SET(sfp->hdr.count, ARCH_CONVERT, i);
1173 *dino_dirty = 1;
1174 *repair = 1;
1175 }
1176 }
1177
1178 if (sfp->hdr.i8count != i8) {
1179 if (no_modify) {
1180 do_warn(_("would have corrected i8 count in directory "
1181 "%llu from %d to %d\n"),
1182 ino, sfp->hdr.i8count, i8);
1183 } else {
1184 do_warn(_("corrected i8 count in directory %llu, "
1185 "was %d, now %d\n"),
1186 ino, sfp->hdr.i8count, i8);
1187 if (i8 == 0)
1188 process_sf_dir2_fixi8(sfp, &next_sfep);
1189 else
1190 sfp->hdr.i8count = i8;
1191 *dino_dirty = 1;
1192 *repair = 1;
1193 }
1194 }
1195
1196 if ((__psint_t) next_sfep - (__psint_t) sfp != ino_dir_size) {
1197 if (no_modify) {
1198 do_warn(_("would have corrected directory %llu size "
1199 "from %lld to %lld\n"),
1200 ino, (__int64_t) ino_dir_size,
1201 (__int64_t)((__psint_t)next_sfep -
1202 (__psint_t)sfp));
1203 } else {
1204 do_warn(_("corrected directory %llu size, was %lld, "
1205 "now %lld\n"),
1206 ino, (__int64_t) ino_dir_size,
1207 (__int64_t)((__psint_t)next_sfep -
1208 (__psint_t)sfp));
1209
1210 INT_SET(dip->di_core.di_size, ARCH_CONVERT,
1211 (xfs_fsize_t)((__psint_t)next_sfep -
1212 (__psint_t)sfp));
1213 *dino_dirty = 1;
1214 *repair = 1;
1215 }
1216 }
1217 if (offset +
1218 (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) *
1219 sizeof(xfs_dir2_leaf_entry_t) +
1220 sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) {
1221 do_warn(_("directory %llu offsets too high\n"), ino);
1222 bad_offset = 1;
1223 }
1224 if (bad_offset) {
1225 if (no_modify) {
1226 do_warn(_("would have corrected entry offsets in "
1227 "directory %llu\n"),
1228 ino);
1229 } else {
1230 do_warn(_("corrected entry offsets in "
1231 "directory %llu\n"),
1232 ino);
1233 process_sf_dir2_fixoff(dip);
1234 *dino_dirty = 1;
1235 *repair = 1;
1236 }
1237 }
1238
1239 /*
1240 * check parent (..) entry
1241 */
1242 *parent = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
1243 &sfp->hdr.parent, ARCH_CONVERT);
1244
1245 /*
1246 * if parent entry is bogus, null it out. we'll fix it later .
1247 */
1248 if (verify_inum(mp, *parent)) {
1249
1250 do_warn(_("bogus .. inode number (%llu) in directory inode "
1251 "%llu, "),
1252 *parent, ino);
1253 *parent = NULLFSINO;
1254 if (!no_modify) {
1255 do_warn(_("clearing inode number\n"));
1256
1257 XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &zero,
1258 &sfp->hdr.parent, ARCH_CONVERT);
1259 *dino_dirty = 1;
1260 *repair = 1;
1261 } else {
1262 do_warn(_("would clear inode number\n"));
1263 }
1264 } else if (ino == mp->m_sb.sb_rootino && ino != *parent) {
1265 /*
1266 * root directories must have .. == .
1267 */
1268 if (!no_modify) {
1269 do_warn(_("corrected root directory %llu .. entry, "
1270 "was %llu, now %llu\n"),
1271 ino, *parent, ino);
1272 *parent = ino;
1273 XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, parent,
1274 &sfp->hdr.parent, ARCH_CONVERT);
1275 *dino_dirty = 1;
1276 *repair = 1;
1277 } else {
1278 do_warn(_("would have corrected root directory %llu .. "
1279 "entry from %llu to %llu\n"),
1280 ino, *parent, ino);
1281 }
1282 } else if (ino == *parent && ino != mp->m_sb.sb_rootino) {
1283 /*
1284 * likewise, non-root directories can't have .. pointing
1285 * to .
1286 */
1287 *parent = NULLFSINO;
1288 do_warn(_("bad .. entry in directory inode %llu, points to "
1289 "self, "),
1290 ino);
1291 if (!no_modify) {
1292 do_warn(_("clearing inode number\n"));
1293
1294 XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &zero,
1295 &sfp->hdr.parent, ARCH_CONVERT);
1296 *dino_dirty = 1;
1297 *repair = 1;
1298 } else {
1299 do_warn(_("would clear inode number\n"));
1300 }
1301 }
1302
1303 return(0);
1304 }
1305
1306 /*
1307 * Process one directory data block.
1308 */
1309 /* ARGSUSED */
1310 static int
1311 process_dir2_data(
1312 xfs_mount_t *mp,
1313 xfs_ino_t ino,
1314 xfs_dinode_t *dip,
1315 int ino_discovery,
1316 char *dirname, /* directory pathname */
1317 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1318 xfs_dabuf_t *bp,
1319 int *dot, /* out - 1 if there is a dot, else 0 */
1320 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1321 xfs_dablk_t da_bno,
1322 char *endptr)
1323 {
1324 int badbest;
1325 xfs_dir2_data_free_t *bf;
1326 int clearino;
1327 char *clearreason = NULL;
1328 xfs_dir2_data_t *d;
1329 xfs_dir2_data_entry_t *dep;
1330 xfs_dir2_data_free_t *dfp;
1331 xfs_dir2_data_unused_t *dup;
1332 int freeseen;
1333 int i;
1334 int ino_off;
1335 ino_tree_node_t *irec_p;
1336 int junkit;
1337 int lastfree;
1338 int nm_illegal;
1339 char *ptr;
1340
1341 d = bp->data;
1342 bf = d->hdr.bestfree;
1343 ptr = (char *)d->u;
1344 badbest = lastfree = freeseen = 0;
1345 if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) {
1346 badbest |= INT_GET(bf[0].offset, ARCH_CONVERT) != 0;
1347 freeseen |= 1 << 0;
1348 }
1349 if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) {
1350 badbest |= INT_GET(bf[1].offset, ARCH_CONVERT) != 0;
1351 freeseen |= 1 << 1;
1352 }
1353 if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) {
1354 badbest |= INT_GET(bf[2].offset, ARCH_CONVERT) != 0;
1355 freeseen |= 1 << 2;
1356 }
1357 badbest |= INT_GET(bf[0].length, ARCH_CONVERT) < INT_GET(bf[1].length, ARCH_CONVERT);
1358 badbest |= INT_GET(bf[1].length, ARCH_CONVERT) < INT_GET(bf[2].length, ARCH_CONVERT);
1359 while (ptr < endptr) {
1360 dup = (xfs_dir2_data_unused_t *)ptr;
1361 /*
1362 * If it's unused, look for the space in the bestfree table.
1363 * If we find it, account for that, else make sure it doesn't
1364 * need to be there.
1365 */
1366 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
1367 if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr ||
1368 INT_GET(dup->length, ARCH_CONVERT) == 0 ||
1369 (INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1)))
1370 break;
1371 if (INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,
1372 ARCH_CONVERT), ARCH_CONVERT) !=
1373 (char *)dup - (char *)d)
1374 break;
1375 badbest |= lastfree != 0;
1376 dfp = xfs_dir2_data_freefind(d, dup);
1377 if (dfp) {
1378 i = dfp - bf;
1379 badbest |= (freeseen & (1 << i)) != 0;
1380 freeseen |= 1 << i;
1381 } else
1382 badbest |= INT_GET(dup->length, ARCH_CONVERT) >
1383 INT_GET(bf[2].length, ARCH_CONVERT);
1384 ptr += INT_GET(dup->length, ARCH_CONVERT);
1385 lastfree = 1;
1386 continue;
1387 }
1388 dep = (xfs_dir2_data_entry_t *)ptr;
1389 if (ptr + XFS_DIR2_DATA_ENTSIZE(dep->namelen) > endptr)
1390 break;
1391 if (INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) !=
1392 (char *)dep - (char *)d)
1393 break;
1394 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1395 lastfree = 0;
1396 }
1397 /*
1398 * Dropped out before we processed everything, give up.
1399 * Phase 6 will kill this block if we don't kill the inode.
1400 */
1401 if (ptr != endptr) {
1402 do_warn(_("corrupt block %u in directory inode %llu\n"),
1403 da_bno, ino);
1404 if (!no_modify)
1405 do_warn(_("\twill junk block\n"));
1406 else
1407 do_warn(_("\twould junk block\n"));
1408 return 1;
1409 }
1410 ptr = (char *)d->u;
1411 /*
1412 * Process the entries now.
1413 */
1414 while (ptr < endptr) {
1415 dup = (xfs_dir2_data_unused_t *)ptr;
1416 if (INT_GET(dup->freetag, ARCH_CONVERT) ==
1417 XFS_DIR2_DATA_FREE_TAG) {
1418 ptr += INT_GET(dup->length, ARCH_CONVERT);
1419 continue;
1420 }
1421 dep = (xfs_dir2_data_entry_t *)ptr;
1422 /*
1423 * We may have to blow out an entry because of bad inode
1424 * numbers. Do NOT touch the name until after we've computed
1425 * the hashvalue and done a namecheck() on the name.
1426 */
1427 if (!ino_discovery &&
1428 INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) {
1429 /*
1430 * Don't do a damned thing. We already found this
1431 * (or did it ourselves) during phase 3.
1432 */
1433 clearino = 0;
1434 } else if (verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT))) {
1435 /*
1436 * Bad inode number. Clear the inode number and the
1437 * entry will get removed later. We don't trash the
1438 * directory since it's still structurally intact.
1439 */
1440 clearino = 1;
1441 clearreason = _("invalid");
1442 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rbmino) {
1443 clearino = 1;
1444 clearreason = _("realtime bitmap");
1445 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rsumino) {
1446 clearino = 1;
1447 clearreason = _("realtime summary");
1448 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_uquotino) {
1449 clearino = 1;
1450 clearreason = _("user quota");
1451 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_gquotino) {
1452 clearino = 1;
1453 clearreason = _("group quota");
1454 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == old_orphanage_ino) {
1455 /*
1456 * Do nothing, silently ignore it, entry has already
1457 * been marked TBD since old_orphanage_ino is set
1458 * non-zero.
1459 */
1460 clearino = 0;
1461 } else if ((irec_p = find_inode_rec(
1462 XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber,
1463 ARCH_CONVERT)),
1464 XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber,
1465 ARCH_CONVERT)))) != NULL) {
1466 /*
1467 * Inode recs should have only confirmed inodes in them.
1468 */
1469 ino_off = XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber,
1470 ARCH_CONVERT)) - irec_p->ino_startnum;
1471 ASSERT(is_inode_confirmed(irec_p, ino_off));
1472 /*
1473 * If inode is marked free and we're in inode discovery
1474 * mode, leave the entry alone for now. If the inode
1475 * turns out to be used, we'll figure that out when we
1476 * scan it. If the inode really is free, we'll hit this
1477 * code again in phase 4 after we've finished inode
1478 * discovery and blow out the entry then.
1479 */
1480 if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
1481 clearino = 1;
1482 clearreason = _("free");
1483 } else
1484 clearino = 0;
1485 } else if (ino_discovery) {
1486 add_inode_uncertain(mp, INT_GET(dep->inumber, ARCH_CONVERT), 0);
1487 clearino = 0;
1488 } else {
1489 clearino = 1;
1490 clearreason = _("non-existent");
1491 }
1492 if (clearino)
1493 do_warn(_("entry \"%*.*s\" at block %u offset %d in "
1494 "directory inode %llu references %s inode "
1495 "%llu\n"),
1496 dep->namelen, dep->namelen, dep->name,
1497 da_bno, (char *)ptr - (char *)d, ino,
1498 clearreason,
1499 INT_GET(dep->inumber, ARCH_CONVERT));
1500 /*
1501 * If the name length is 0 (illegal) make it 1 and blast
1502 * the entry.
1503 */
1504 if (dep->namelen == 0) {
1505 do_warn(_("entry at block %u offset %d in directory "
1506 "inode %llu has 0 namelength\n"),
1507 da_bno, (char *)ptr - (char *)d, ino);
1508 if (!no_modify)
1509 dep->namelen = 1;
1510 clearino = 1;
1511 }
1512 /*
1513 * If needed to clear the inode number, do it now.
1514 */
1515 if (clearino) {
1516 if (!no_modify) {
1517 do_warn(_("\tclearing inode number in entry at "
1518 "offset %d...\n"),
1519 (char *)ptr - (char *)d);
1520 INT_SET(dep->inumber, ARCH_CONVERT, BADFSINO);
1521 bp->dirty = 1;
1522 } else {
1523 do_warn(_("\twould clear inode number in entry "
1524 "at offset %d...\n"),
1525 (char *)ptr - (char *)d);
1526 }
1527 }
1528 /*
1529 * Only complain about illegal names in phase 3 (when inode
1530 * discovery is turned on). Otherwise, we'd complain a lot
1531 * during phase 4.
1532 */
1533 junkit = INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO;
1534 nm_illegal = namecheck((char *)dep->name, dep->namelen);
1535 if (ino_discovery && nm_illegal) {
1536 do_warn(_("entry at block %u offset %d in directory "
1537 "inode %llu has illegal name \"%*.*s\": "),
1538 da_bno, (char *)ptr - (char *)d, ino,
1539 dep->namelen, dep->namelen, dep->name);
1540 junkit = 1;
1541 }
1542 /*
1543 * Now we can mark entries with BADFSINO's bad.
1544 */
1545 if (!no_modify &&
1546 INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) {
1547 dep->name[0] = '/';
1548 bp->dirty = 1;
1549 junkit = 0;
1550 }
1551 /*
1552 * Special .. entry processing.
1553 */
1554 if (dep->namelen == 2 &&
1555 dep->name[0] == '.' && dep->name[1] == '.') {
1556 if (!*dotdot) {
1557 (*dotdot)++;
1558 *parent = INT_GET(dep->inumber, ARCH_CONVERT);
1559 /*
1560 * What if .. == .? Legal only in the root
1561 * inode. Blow out entry and set parent to
1562 * NULLFSINO otherwise.
1563 */
1564 if (ino == INT_GET(dep->inumber, ARCH_CONVERT) &&
1565 ino != mp->m_sb.sb_rootino) {
1566 *parent = NULLFSINO;
1567 do_warn(_("bad .. entry in directory "
1568 "inode %llu, points to self: "),
1569 ino);
1570 junkit = 1;
1571 }
1572 /*
1573 * We have to make sure that . == .. in the
1574 * root inode.
1575 */
1576 else if (ino != INT_GET(dep->inumber, ARCH_CONVERT) &&
1577 ino == mp->m_sb.sb_rootino) {
1578 do_warn(_("bad .. entry in root "
1579 "directory inode %llu, was "
1580 "%llu: "),
1581 ino, INT_GET(dep->inumber, ARCH_CONVERT));
1582 if (!no_modify) {
1583 do_warn(_("correcting\n"));
1584 INT_SET(dep->inumber, ARCH_CONVERT, ino);
1585 bp->dirty = 1;
1586 } else {
1587 do_warn(_("would correct\n"));
1588 }
1589 }
1590 }
1591 /*
1592 * Can't fix the directory unless we know which ..
1593 * entry is the right one. Both have valid inode
1594 * numbers or we wouldn't be here. So since both
1595 * seem equally valid, trash this one.
1596 */
1597 else {
1598 do_warn(_("multiple .. entries in directory "
1599 "inode %llu: "),
1600 ino);
1601 junkit = 1;
1602 }
1603 }
1604 /*
1605 * Special . entry processing.
1606 */
1607 else if (dep->namelen == 1 && dep->name[0] == '.') {
1608 if (!*dot) {
1609 (*dot)++;
1610 if (INT_GET(dep->inumber, ARCH_CONVERT) != ino) {
1611 do_warn(_("bad . entry in directory "
1612 "inode %llu, was %llu: "),
1613 ino, INT_GET(dep->inumber, ARCH_CONVERT));
1614 if (!no_modify) {
1615 do_warn(_("correcting\n"));
1616 INT_SET(dep->inumber, ARCH_CONVERT, ino);
1617 bp->dirty = 1;
1618 } else {
1619 do_warn(_("would correct\n"));
1620 }
1621 }
1622 } else {
1623 do_warn(_("multiple . entries in directory "
1624 "inode %llu: "),
1625 ino);
1626 junkit = 1;
1627 }
1628 }
1629 /*
1630 * All other entries -- make sure only . references self.
1631 */
1632 else if (INT_GET(dep->inumber, ARCH_CONVERT) == ino) {
1633 do_warn(_("entry \"%*.*s\" in directory inode %llu "
1634 "points to self: "),
1635 dep->namelen, dep->namelen, dep->name, ino);
1636 junkit = 1;
1637 }
1638 /*
1639 * Clear junked entries.
1640 */
1641 if (junkit) {
1642 if (!no_modify) {
1643 dep->name[0] = '/';
1644 bp->dirty = 1;
1645 do_warn(_("clearing entry\n"));
1646 } else {
1647 do_warn(_("would clear entry\n"));
1648 }
1649 }
1650 /*
1651 * Advance to the next entry.
1652 */
1653 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1654 }
1655 /*
1656 * Check the bestfree table.
1657 */
1658 if (freeseen != 7 || badbest) {
1659 do_warn(_("bad bestfree table in block %u in directory inode "
1660 "%llu: "),
1661 da_bno, ino);
1662 if (!no_modify) {
1663 do_warn(_("repairing table\n"));
1664 libxfs_dir2_data_freescan(mp, d, &i, endptr);
1665 bp->dirty = 1;
1666 } else {
1667 do_warn(_("would repair table\n"));
1668 }
1669 }
1670 return 0;
1671 }
1672
1673 /*
1674 * Process a block-format directory.
1675 */
1676 /* ARGSUSED */
1677 static int
1678 process_block_dir2(
1679 xfs_mount_t *mp,
1680 xfs_ino_t ino,
1681 xfs_dinode_t *dip,
1682 int ino_discovery,
1683 int *dino_dirty, /* out - 1 if dinode buffer dirty */
1684 char *dirname, /* directory pathname */
1685 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1686 blkmap_t *blkmap,
1687 int *dot, /* out - 1 if there is a dot, else 0 */
1688 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1689 int *repair) /* out - 1 if something was fixed */
1690 {
1691 xfs_dir2_block_t *block;
1692 xfs_dir2_leaf_entry_t *blp;
1693 bmap_ext_t *bmp;
1694 xfs_dabuf_t *bp;
1695 xfs_dir2_block_tail_t *btp;
1696 int nex;
1697 int rval;
1698
1699 *repair = *dot = *dotdot = 0;
1700 *parent = NULLFSINO;
1701 nex = blkmap_getn(blkmap, mp->m_dirdatablk, mp->m_dirblkfsbs, &bmp);
1702 if (nex == 0) {
1703 do_warn(_("block %u for directory inode %llu is missing\n"),
1704 mp->m_dirdatablk, ino);
1705 return 1;
1706 }
1707 bp = da_read_buf(mp, nex, bmp);
1708 free(bmp);
1709 if (bp == NULL) {
1710 do_warn(_("can't read block %u for directory inode %llu\n"),
1711 mp->m_dirdatablk, ino);
1712 return 1;
1713 }
1714 /*
1715 * Verify the block
1716 */
1717 block = bp->data;
1718 if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC)
1719 do_warn(_("bad directory block magic # %#x in block %u for "
1720 "directory inode %llu\n"),
1721 INT_GET(block->hdr.magic, ARCH_CONVERT),
1722 mp->m_dirdatablk, ino);
1723 /*
1724 * process the data area
1725 * this also checks & fixes the bestfree
1726 */
1727 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
1728 blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
1729 /*
1730 * Don't let this go past the end of the block.
1731 */
1732 if ((char *)blp > (char *)btp)
1733 blp = (xfs_dir2_leaf_entry_t *)btp;
1734 rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent,
1735 bp, dot, dotdot, mp->m_dirdatablk, (char *)blp);
1736 if (bp->dirty && !no_modify) {
1737 *repair = 1;
1738 da_bwrite(mp, bp);
1739 } else
1740 da_brelse(bp);
1741 return rval;
1742 }
1743
1744 /*
1745 * Validates leaf contents, node format directories only.
1746 * magic number and sibling pointers checked by caller.
1747 * Returns 0 if block is ok, 1 if the block is bad.
1748 * Looking for: out of order hash values, bad stale counts.
1749 */
1750 static int
1751 process_leaf_block_dir2(
1752 xfs_mount_t *mp,
1753 xfs_dir2_leaf_t *leaf,
1754 xfs_dablk_t da_bno,
1755 xfs_ino_t ino,
1756 xfs_dahash_t last_hashval,
1757 xfs_dahash_t *next_hashval)
1758 {
1759 int i;
1760 int stale;
1761
1762 for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) {
1763 if ((char *)&leaf->ents[i] >= (char *)leaf + mp->m_dirblksize) {
1764 do_warn(_("bad entry count in block %u of directory "
1765 "inode %llu\n"),
1766 da_bno, ino);
1767 return 1;
1768 }
1769 if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) ==
1770 XFS_DIR2_NULL_DATAPTR)
1771 stale++;
1772 else if (INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <
1773 last_hashval) {
1774 do_warn(_("bad hash ordering in block %u of directory "
1775 "inode %llu\n"),
1776 da_bno, ino);
1777 return 1;
1778 }
1779 *next_hashval = last_hashval =
1780 INT_GET(leaf->ents[i].hashval, ARCH_CONVERT);
1781 }
1782 if (stale != INT_GET(leaf->hdr.stale, ARCH_CONVERT)) {
1783 do_warn(_("bad stale count in block %u of directory "
1784 "inode %llu\n"),
1785 da_bno, ino);
1786 return 1;
1787 }
1788 return 0;
1789 }
1790
1791 /*
1792 * Returns 0 if the directory is ok, 1 if it has to be rebuilt.
1793 */
1794 static int
1795 process_leaf_level_dir2(
1796 xfs_mount_t *mp,
1797 dir2_bt_cursor_t *da_cursor,
1798 int *repair)
1799 {
1800 bmap_ext_t *bmp;
1801 xfs_dabuf_t *bp;
1802 int buf_dirty;
1803 xfs_dahash_t current_hashval;
1804 xfs_dablk_t da_bno;
1805 xfs_dahash_t greatest_hashval;
1806 xfs_ino_t ino;
1807 xfs_dir2_leaf_t *leaf;
1808 int nex;
1809 xfs_dablk_t prev_bno;
1810
1811 da_bno = da_cursor->level[0].bno;
1812 ino = da_cursor->ino;
1813 prev_bno = 0;
1814 bmp = NULL;
1815 current_hashval = 0;
1816 buf_dirty = 0;
1817
1818 do {
1819 nex = blkmap_getn(da_cursor->blkmap, da_bno, mp->m_dirblkfsbs,
1820 &bmp);
1821 /*
1822 * Directory code uses 0 as the NULL block pointer since 0
1823 * is the root block and no directory block pointer can point
1824 * to the root block of the btree.
1825 */
1826 ASSERT(da_bno != 0);
1827
1828 if (nex == 0) {
1829 do_warn(_("can't map block %u for directory "
1830 "inode %llu\n"),
1831 da_bno, ino);
1832 goto error_out;
1833 }
1834 bp = da_read_buf(mp, nex, bmp);
1835 free(bmp);
1836 bmp = NULL;
1837 if (bp == NULL) {
1838 do_warn(_("can't read file block %u for directory "
1839 "inode %llu\n"),
1840 da_bno, ino);
1841 goto error_out;
1842 }
1843 leaf = bp->data;
1844 /*
1845 * Check magic number for leaf directory btree block.
1846 */
1847 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) !=
1848 XFS_DIR2_LEAFN_MAGIC) {
1849 do_warn(_("bad directory leaf magic # %#x for "
1850 "directory inode %llu block %u\n"),
1851 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT),
1852 ino, da_bno);
1853 da_brelse(bp);
1854 goto error_out;
1855 }
1856 buf_dirty = 0;
1857 /*
1858 * For each block, process the block, verify its path,
1859 * then get next block. Update cursor values along the way.
1860 */
1861 if (process_leaf_block_dir2(mp, leaf, da_bno, ino,
1862 current_hashval, &greatest_hashval)) {
1863 da_brelse(bp);
1864 goto error_out;
1865 }
1866 /*
1867 * Index can be set to hdr.count so match the indices of the
1868 * interior blocks -- which at the end of the block will point
1869 * to 1 after the final real entry in the block.
1870 */
1871 da_cursor->level[0].hashval = greatest_hashval;
1872 da_cursor->level[0].bp = bp;
1873 da_cursor->level[0].bno = da_bno;
1874 da_cursor->level[0].index =
1875 INT_GET(leaf->hdr.count, ARCH_CONVERT);
1876 da_cursor->level[0].dirty = buf_dirty;
1877
1878 if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
1879 do_warn(_("bad sibling back pointer for block %u in "
1880 "directory inode %llu\n"),
1881 da_bno, ino);
1882 da_brelse(bp);
1883 goto error_out;
1884 }
1885 prev_bno = da_bno;
1886 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1887 if (da_bno != 0) {
1888 if (verify_dir2_path(mp, da_cursor, 0)) {
1889 da_brelse(bp);
1890 goto error_out;
1891 }
1892 }
1893 current_hashval = greatest_hashval;
1894 ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
1895 if (buf_dirty && !no_modify) {
1896 *repair = 1;
1897 da_bwrite(mp, bp);
1898 } else
1899 da_brelse(bp);
1900 } while (da_bno != 0);
1901 if (verify_final_dir2_path(mp, da_cursor, 0)) {
1902 /*
1903 * Verify the final path up (right-hand-side) if still ok.
1904 */
1905 do_warn(_("bad hash path in directory %llu\n"), ino);
1906 goto error_out;
1907 }
1908 /*
1909 * Redundant but just for testing.
1910 */
1911 release_dir2_cursor(mp, da_cursor, 0);
1912 return 0;
1913
1914 error_out:
1915 /*
1916 * Release all buffers holding interior btree blocks.
1917 */
1918 err_release_dir2_cursor(mp, da_cursor, 0);
1919 if (bmp)
1920 free(bmp);
1921 return 1;
1922 }
1923
1924 /*
1925 * Return 1 if the directory's leaf/node space is corrupted and
1926 * needs to be rebuilt, 0 if it's ok.
1927 */
1928 static int
1929 process_node_dir2(
1930 xfs_mount_t *mp,
1931 xfs_ino_t ino,
1932 xfs_dinode_t *dip,
1933 blkmap_t *blkmap,
1934 int *repair)
1935 {
1936 xfs_dablk_t bno;
1937 dir2_bt_cursor_t da_cursor;
1938
1939 /*
1940 * Try again -- traverse down left-side of tree until we hit the
1941 * left-most leaf block setting up the btree cursor along the way.
1942 * Then walk the leaf blocks left-to-right, calling a parent
1943 * verification routine each time we traverse a block.
1944 */
1945 bzero(&da_cursor, sizeof(da_cursor));
1946 da_cursor.ino = ino;
1947 da_cursor.dip = dip;
1948 da_cursor.blkmap = blkmap;
1949
1950 /*
1951 * Now process interior node.
1952 */
1953 if (traverse_int_dir2block(mp, &da_cursor, &bno) == 0)
1954 return 1;
1955
1956 /*
1957 * Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC
1958 */
1959 if (bno == 0) {
1960 release_dir2_cursor(mp, &da_cursor, 0);
1961 return 0;
1962 } else {
1963 /*
1964 * Now pass cursor and bno into leaf-block processing routine.
1965 * The leaf dir level routine checks the interior paths up to
1966 * the root including the final right-most path.
1967 */
1968 return process_leaf_level_dir2(mp, &da_cursor, repair);
1969 }
1970 }
1971
1972 /*
1973 * Process leaf and node directories.
1974 * Process the data blocks then, if it's a node directory, check
1975 * the consistency of those blocks.
1976 */
1977 static int
1978 process_leaf_node_dir2(
1979 xfs_mount_t *mp,
1980 xfs_ino_t ino,
1981 xfs_dinode_t *dip,
1982 int ino_discovery,
1983 char *dirname, /* directory pathname */
1984 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1985 blkmap_t *blkmap,
1986 int *dot, /* out - 1 if there is a dot, else 0 */
1987 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1988 int *repair, /* out - 1 if something was fixed */
1989 int isnode) /* node directory not leaf */
1990 {
1991 bmap_ext_t *bmp;
1992 xfs_dabuf_t *bp;
1993 xfs_dir2_data_t *data;
1994 xfs_dfiloff_t dbno;
1995 int good;
1996 int i;
1997 xfs_dfiloff_t ndbno;
1998 int nex;
1999 int t;
2000
2001 *repair = *dot = *dotdot = good = 0;
2002 *parent = NULLFSINO;
2003 ndbno = NULLDFILOFF;
2004 while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
2005 nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp);
2006 ndbno = dbno + mp->m_dirblkfsbs - 1;
2007 if (nex == 0) {
2008 do_warn(_("block %llu for directory inode %llu is "
2009 "missing\n"),
2010 dbno, ino);
2011 continue;
2012 }
2013 bp = da_read_buf(mp, nex, bmp);
2014 free(bmp);
2015 if (bp == NULL) {
2016 do_warn(_("can't read block %llu for directory inode "
2017 "%llu\n"),
2018 dbno, ino);
2019 continue;
2020 }
2021 data = bp->data;
2022 if (INT_GET(data->hdr.magic, ARCH_CONVERT) !=
2023 XFS_DIR2_DATA_MAGIC)
2024 do_warn(_("bad directory block magic # %#x in block "
2025 "%llu for directory inode %llu\n"),
2026 INT_GET(data->hdr.magic, ARCH_CONVERT),
2027 dbno, ino);
2028 i = process_dir2_data(mp, ino, dip, ino_discovery, dirname,
2029 parent, bp, dot, dotdot, (xfs_dablk_t)dbno,
2030 (char *)data + mp->m_dirblksize);
2031 if (i == 0)
2032 good++;
2033 if (bp->dirty && !no_modify) {
2034 *repair = 1;
2035 da_bwrite(mp, bp);
2036 } else
2037 da_brelse(bp);
2038 }
2039 if (good == 0)
2040 return 1;
2041 if (!isnode)
2042 return 0;
2043 if (dir2_is_badino(ino))
2044 return 0;
2045
2046 if (process_node_dir2(mp, ino, dip, blkmap, repair))
2047 dir2_add_badlist(ino);
2048 return 0;
2049
2050 }
2051
2052 /*
2053 * Returns 1 if things are bad (directory needs to be junked)
2054 * and 0 if things are ok. If ino_discovery is 1, add unknown
2055 * inodes to uncertain inode list.
2056 */
2057 int
2058 process_dir2(
2059 xfs_mount_t *mp,
2060 xfs_ino_t ino,
2061 xfs_dinode_t *dip,
2062 int ino_discovery,
2063 int *dino_dirty,
2064 char *dirname,
2065 xfs_ino_t *parent,
2066 blkmap_t *blkmap)
2067 {
2068 int dot;
2069 int dotdot;
2070 xfs_dfiloff_t last;
2071 int repair;
2072 int res;
2073
2074 *parent = NULLFSINO;
2075 dot = dotdot = 0;
2076 last = 0;
2077
2078 /*
2079 * branch off depending on the type of inode. This routine
2080 * is only called ONCE so all the subordinate routines will
2081 * fix '.' and junk '..' if they're bogus.
2082 */
2083 if (blkmap)
2084 last = blkmap_last_off(blkmap);
2085 if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
2086 XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT) &&
2087 dip->di_core.di_format == XFS_DINODE_FMT_LOCAL) {
2088 dot = dotdot = 1;
2089 res = process_sf_dir2(mp, ino, dip, ino_discovery, dino_dirty,
2090 dirname, parent, &repair);
2091 } else if (last == mp->m_dirblkfsbs &&
2092 (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS ||
2093 dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) {
2094 res = process_block_dir2(mp, ino, dip, ino_discovery,
2095 dino_dirty, dirname, parent, blkmap, &dot, &dotdot,
2096 &repair);
2097 } else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs &&
2098 (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS ||
2099 dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) {
2100 res = process_leaf_node_dir2(mp, ino, dip, ino_discovery,
2101 dirname, parent, blkmap, &dot, &dotdot, &repair,
2102 last > mp->m_dirleafblk + mp->m_dirblkfsbs);
2103 } else {
2104 do_warn(_("bad size/format for directory %llu\n"), ino);
2105 return 1;
2106 }
2107 /*
2108 * bad . entries in all directories will be fixed up in phase 6
2109 */
2110 if (dot == 0) {
2111 do_warn(_("no . entry for directory %llu\n"), ino);
2112 }
2113
2114 /*
2115 * shortform dirs always have a .. entry. .. for all longform
2116 * directories will get fixed in phase 6. .. for other shortform
2117 * dirs also get fixed there. .. for a shortform root was
2118 * fixed in place since we know what it should be
2119 */
2120 if (dotdot == 0 && ino != mp->m_sb.sb_rootino) {
2121 do_warn(_("no .. entry for directory %llu\n"), ino);
2122 } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) {
2123 do_warn(_("no .. entry for root directory %llu\n"), ino);
2124 need_root_dotdot = 1;
2125 }
2126
2127 ASSERT((ino != mp->m_sb.sb_rootino && ino != *parent) ||
2128 (ino == mp->m_sb.sb_rootino &&
2129 (ino == *parent || need_root_dotdot == 1)));
2130
2131 return res;
2132 }