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