HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
btblock.h bmroot.h check.h command.h convert.h debug.h \
- dir.h dir2.h dir2sf.h dirshort.h dquot.h echo.h faddr.h field.h \
+ dir2.h dir2sf.h dquot.h echo.h faddr.h field.h \
flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \
io.h malloc.h metadump.h output.h print.h quit.h sb.h sig.h strvec.h \
text.h type.h write.h attrset.h
xfs_dir2_data_unused_t *dup);
static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap,
inodata_t *id);
-static int process_dir_v1(xfs_dinode_t *dip, blkmap_t *blkmap,
- int *dot, int *dotdot, inodata_t *id,
- xfs_ino_t *parent);
static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap,
int *dot, int *dotdot, inodata_t *id,
xfs_ino_t *parent);
dbm_t type, xfs_drfsbno_t *totd,
xfs_drfsbno_t *toti, xfs_extnum_t *nex,
blkmap_t **blkmapp, int whichfork);
-static xfs_ino_t process_leaf_dir_v1(blkmap_t *blkmap, int *dot,
- int *dotdot, inodata_t *id);
-static xfs_ino_t process_leaf_dir_v1_int(int *dot, int *dotdot,
- inodata_t *id);
static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot,
int *dotdot, inodata_t *id,
xfs_fsize_t dirsize);
static void process_leaf_node_dir_v2_int(inodata_t *id, int v,
xfs_dablk_t dbno,
freetab_t *freetab);
-static xfs_ino_t process_node_dir_v1(blkmap_t *blkmap, int *dot,
- int *dotdot, inodata_t *id);
static void process_quota(qtype_t qtype, inodata_t *id,
blkmap_t *blkmap);
static void process_rtbitmap(blkmap_t *blkmap);
static void process_rtsummary(blkmap_t *blkmap);
static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot,
int *dotdot, inodata_t *id);
-static xfs_ino_t process_shortform_dir_v1(xfs_dinode_t *dip, int *dot,
- int *dotdot, inodata_t *id);
static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u,
int dq, xfs_qcnt_t bc, xfs_qcnt_t ic,
xfs_qcnt_t rc);
push_cur();
if (nex > 1)
make_bbmap(&bbmap, nex, bmp);
- set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock),
+ set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
mp->m_dirblkfsbs * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL);
for (x = 0; !v && x < nex; x++) {
for (b = bmp[x].startblock;
xfs_ino_t parent;
dot = dotdot = 0;
- if (xfs_sb_version_hasdirv2(&mp->m_sb)) {
- if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
- return;
- } else
- {
- if (process_dir_v1(dip, blkmap, &dot, &dotdot, id, &parent))
- return;
- }
+ if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
+ return;
+
bno = XFS_INO_TO_FSB(mp, id->ino);
if (dot == 0) {
if (!sflag || id->ilist || CHECK_BLIST(bno))
addparent_inode(id, parent);
}
-static int
-process_dir_v1(
- xfs_dinode_t *dip,
- blkmap_t *blkmap,
- int *dot,
- int *dotdot,
- inodata_t *id,
- xfs_ino_t *parent)
-{
- xfs_fsize_t size = be64_to_cpu(dip->di_size);
-
- if (size <= XFS_DFORK_DSIZE(dip, mp) &&
- dip->di_format == XFS_DINODE_FMT_LOCAL)
- *parent = process_shortform_dir_v1(dip, dot, dotdot, id);
- else if (size == XFS_LBSIZE(mp) &&
- (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
- dip->di_format == XFS_DINODE_FMT_BTREE))
- *parent = process_leaf_dir_v1(blkmap, dot, dotdot, id);
- else if (size >= XFS_LBSIZE(mp) &&
- (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
- dip->di_format == XFS_DINODE_FMT_BTREE))
- *parent = process_node_dir_v1(blkmap, dot, dotdot, id);
- else {
- dbprintf(_("bad size (%lld) or format (%d) for directory inode "
- "%lld\n"),
- size, dip->di_format, id->ino);
- error++;
- return 1;
- }
- return 0;
-}
-
static int
process_dir_v2(
xfs_dinode_t *dip,
}
}
-static xfs_ino_t
-process_leaf_dir_v1(
- blkmap_t *blkmap,
- int *dot,
- int *dotdot,
- inodata_t *id)
-{
- xfs_fsblock_t bno;
- xfs_ino_t parent;
-
- bno = blkmap_get(blkmap, 0);
- if (bno == NULLFSBLOCK) {
- if (!sflag || id->ilist)
- dbprintf(_("block 0 for directory inode %lld is "
- "missing\n"),
- id->ino);
- error++;
- return 0;
- }
- push_cur();
- set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN,
- NULL);
- if (iocur_top->data == NULL) {
- if (!sflag || id->ilist || CHECK_BLIST(bno))
- dbprintf(_("can't read block 0 for directory inode "
- "%lld\n"),
- id->ino);
- error++;
- pop_cur();
- return 0;
- }
- parent = process_leaf_dir_v1_int(dot, dotdot, id);
- pop_cur();
- return parent;
-}
-
-static xfs_ino_t
-process_leaf_dir_v1_int(
- int *dot,
- int *dotdot,
- inodata_t *id)
-{
- xfs_fsblock_t bno;
- inodata_t *cid;
- xfs_dir_leaf_entry_t *entry;
- int i;
- xfs_dir_leafblock_t *leaf;
- xfs_ino_t lino;
- xfs_dir_leaf_name_t *namest;
- xfs_ino_t parent = 0;
- int v;
-
- bno = XFS_DADDR_TO_FSB(mp, iocur_top->bb);
- v = verbose || id->ilist || CHECK_BLIST(bno);
- leaf = iocur_top->data;
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
- if (!sflag || id->ilist || CHECK_BLIST(bno))
- dbprintf(_("bad directory leaf magic # %#x for dir ino "
- "%lld\n"),
- be16_to_cpu(leaf->hdr.info.magic), id->ino);
- error++;
- return NULLFSINO;
- }
- entry = &leaf->entries[0];
- for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
- namest = xfs_dir_leaf_namestruct(leaf,
- be16_to_cpu(entry->nameidx));
- lino = XFS_GET_DIR_INO8(namest->inumber);
- cid = find_inode(lino, 1);
- if (v)
- dbprintf(_("dir %lld entry %*.*s %lld\n"), id->ino,
- entry->namelen, entry->namelen, namest->name,
- lino);
- if (cid)
- addlink_inode(cid);
- else {
- if (!sflag)
- dbprintf(_("dir %lld entry %*.*s bad inode "
- "number %lld\n"),
- id->ino, entry->namelen, entry->namelen,
- namest->name, lino);
- error++;
- }
- if (entry->namelen == 2 && namest->name[0] == '.' &&
- namest->name[1] == '.') {
- if (parent) {
- if (!sflag || id->ilist || CHECK_BLIST(bno))
- dbprintf(_("multiple .. entries in dir "
- "%lld (%lld, %lld)\n"),
- id->ino, parent, lino);
- error++;
- } else
- parent = cid ? lino : NULLFSINO;
- (*dotdot)++;
- } else if (entry->namelen != 1 || namest->name[0] != '.') {
- if (cid != NULL) {
- if (!cid->parent)
- cid->parent = id;
- addname_inode(cid, (char *)namest->name,
- entry->namelen);
- }
- } else {
- if (lino != id->ino) {
- if (!sflag)
- dbprintf(_("dir %lld entry . inode "
- "number mismatch (%lld)\n"),
- id->ino, lino);
- error++;
- }
- (*dot)++;
- }
- }
- return parent;
-}
-
static xfs_ino_t
process_leaf_node_dir_v2(
blkmap_t *blkmap,
push_cur();
if (nex > 1)
make_bbmap(&bbmap, nex, bmp);
- set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock),
+ set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
mp->m_dirblkfsbs * blkbb, DB_RING_IGN,
nex > 1 ? &bbmap : NULL);
free(bmp);
}
}
-static xfs_ino_t
-process_node_dir_v1(
- blkmap_t *blkmap,
- int *dot,
- int *dotdot,
- inodata_t *id)
-{
- xfs_fsblock_t bno;
- xfs_fileoff_t dbno;
- xfs_ino_t lino;
- xfs_ino_t parent;
- int t;
- int v;
- int v2;
-
- v = verbose || id->ilist;
- parent = 0;
- dbno = NULLFILEOFF;
- push_cur();
- while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) {
- bno = blkmap_get(blkmap, dbno);
- v2 = bno != NULLFSBLOCK && CHECK_BLIST(bno);
- if (bno == NULLFSBLOCK && dbno == 0) {
- if (!sflag || v)
- dbprintf(_("can't read root block for directory "
- "inode %lld\n"),
- id->ino);
- error++;
- }
- if (v || v2)
- dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino,
- (__uint32_t)dbno, (xfs_dfsbno_t)bno);
- if (bno == NULLFSBLOCK)
- continue;
- pop_cur();
- push_cur();
- set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb,
- DB_RING_IGN, NULL);
- if (iocur_top->data == NULL) {
- if (!sflag || v || v2)
- dbprintf(_("can't read block %u for directory "
- "inode %lld\n"),
- (__uint32_t)dbno, id->ino);
- error++;
- continue;
- }
- if (be16_to_cpu(((xfs_da_intnode_t *)iocur_top->data)->
- hdr.info.magic) == XFS_DA_NODE_MAGIC)
- continue;
- lino = process_leaf_dir_v1_int(dot, dotdot, id);
- if (lino) {
- if (parent) {
- if (!sflag || v || v2)
- dbprintf(_("multiple .. entries in dir "
- "%lld\n"),
- id->ino);
- error++;
- } else
- parent = lino;
- }
- }
- pop_cur();
- return parent;
-}
-
static void
process_quota(
qtype_t qtype,
return cid ? lino : NULLFSINO;
}
-static xfs_ino_t
-process_shortform_dir_v1(
- xfs_dinode_t *dip,
- int *dot,
- int *dotdot,
- inodata_t *id)
-{
- inodata_t *cid;
- int i;
- xfs_ino_t lino;
- xfs_dir_shortform_t *sf;
- xfs_dir_sf_entry_t *sfe;
- int v;
-
- sf = (xfs_dir_shortform_t *)XFS_DFORK_DPTR(dip);
- addlink_inode(id);
- v = verbose || id->ilist;
- if (v)
- dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
- (*dot)++;
- sfe = &sf->list[0];
- for (i = sf->hdr.count - 1; i >= 0; i--) {
- lino = XFS_GET_DIR_INO8(sfe->inumber);
- cid = find_inode(lino, 1);
- if (cid == NULL) {
- if (!sflag)
- dbprintf(_("dir %lld entry %*.*s bad inode "
- "number %lld\n"),
- id->ino, sfe->namelen, sfe->namelen,
- sfe->name, lino);
- error++;
- } else {
- addlink_inode(cid);
- if (!cid->parent)
- cid->parent = id;
- addname_inode(cid, (char *)sfe->name, sfe->namelen);
- }
- if (v)
- dbprintf(_("dir %lld entry %*.*s %lld\n"), id->ino,
- sfe->namelen, sfe->namelen, sfe->name, lino);
- sfe = xfs_dir_sf_nextentry(sfe);
- }
- if ((__psint_t)sfe - (__psint_t)sf != be64_to_cpu(dip->di_size))
- dbprintf(_("dir %llu size is %lld, should be %d\n"),
- id->ino, be64_to_cpu(dip->di_size),
- (int)((char *)sfe - (char *)sf));
- lino = XFS_GET_DIR_INO8(sf->hdr.parent);
- cid = find_inode(lino, 1);
- if (cid)
- addlink_inode(cid);
- else {
- if (!sflag)
- dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
- id->ino, lino);
- error++;
- }
- if (v)
- dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
- (*dotdot)++;
- return cid ? lino : NULLFSINO;
-}
static void
quota_add(
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <xfs/libxfs.h>
-#include "bit.h"
-#include "type.h"
-#include "faddr.h"
-#include "fprint.h"
-#include "field.h"
-#include "dir.h"
-#include "io.h"
-#include "init.h"
-
-static int dir_leaf_entries_count(void *obj, int startoff);
-static int dir_leaf_hdr_count(void *obj, int startoff);
-static int dir_leaf_name_count(void *obj, int startoff);
-static int dir_leaf_namelist_count(void *obj, int startoff);
-static int dir_leaf_namelist_offset(void *obj, int startoff, int idx);
-static int dir_node_btree_count(void *obj, int startoff);
-static int dir_node_hdr_count(void *obj, int startoff);
-
-const field_t dir_hfld[] = {
- { "", FLDT_DIR, OI(0), C1, 0, TYP_NONE },
- { NULL }
-};
-
-#define LOFF(f) bitize(offsetof(xfs_dir_leafblock_t, f))
-#define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f))
-const field_t dir_flds[] = {
- { "lhdr", FLDT_DIR_LEAF_HDR, OI(LOFF(hdr)), dir_leaf_hdr_count,
- FLD_COUNT, TYP_NONE },
- { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir_node_hdr_count,
- FLD_COUNT, TYP_NONE },
- { "entries", FLDT_DIR_LEAF_ENTRY, OI(LOFF(entries)),
- dir_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE },
- { "btree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)),
- dir_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE },
- { "namelist", FLDT_DIR_LEAF_NAME, dir_leaf_namelist_offset,
- dir_leaf_namelist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
- { NULL }
-};
-
-#define BOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f))
-const field_t dir_blkinfo_flds[] = {
- { "forw", FLDT_DIRBLOCK, OI(BOFF(forw)), C1, 0, TYP_INODATA },
- { "back", FLDT_DIRBLOCK, OI(BOFF(back)), C1, 0, TYP_INODATA },
- { "magic", FLDT_UINT16X, OI(BOFF(magic)), C1, 0, TYP_NONE },
- { "pad", FLDT_UINT16X, OI(BOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
- { NULL }
-};
-
-#define LEOFF(f) bitize(offsetof(xfs_dir_leaf_entry_t, f))
-const field_t dir_leaf_entry_flds[] = {
- { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE },
- { "nameidx", FLDT_UINT16D, OI(LEOFF(nameidx)), C1, 0, TYP_NONE },
- { "namelen", FLDT_UINT8D, OI(LEOFF(namelen)), C1, 0, TYP_NONE },
- { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE },
- { NULL }
-};
-
-#define LHOFF(f) bitize(offsetof(xfs_dir_leaf_hdr_t, f))
-const field_t dir_leaf_hdr_flds[] = {
- { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE },
- { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE },
- { "namebytes", FLDT_UINT16D, OI(LHOFF(namebytes)), C1, 0, TYP_NONE },
- { "firstused", FLDT_UINT16D, OI(LHOFF(firstused)), C1, 0, TYP_NONE },
- { "holes", FLDT_UINT8D, OI(LHOFF(holes)), C1, 0, TYP_NONE },
- { "pad1", FLDT_UINT8X, OI(LHOFF(pad1)), C1, FLD_SKIPALL, TYP_NONE },
- { "freemap", FLDT_DIR_LEAF_MAP, OI(LHOFF(freemap)),
- CI(XFS_DIR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE },
- { NULL }
-};
-
-#define LMOFF(f) bitize(offsetof(xfs_dir_leaf_map_t, f))
-const field_t dir_leaf_map_flds[] = {
- { "base", FLDT_UINT16D, OI(LMOFF(base)), C1, 0, TYP_NONE },
- { "size", FLDT_UINT16D, OI(LMOFF(size)), C1, 0, TYP_NONE },
- { NULL }
-};
-
-#define LNOFF(f) bitize(offsetof(xfs_dir_leaf_name_t, f))
-const field_t dir_leaf_name_flds[] = {
- { "inumber", FLDT_DIR_INO, OI(LNOFF(inumber)), C1, 0, TYP_INODE },
- { "name", FLDT_CHARNS, OI(LNOFF(name)), dir_leaf_name_count, FLD_COUNT,
- TYP_NONE },
- { NULL }
-};
-
-#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f))
-const field_t dir_node_entry_flds[] = {
- { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE },
- { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA },
- { NULL }
-};
-
-#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f))
-const field_t dir_node_hdr_flds[] = {
- { "info", FLDT_DIR_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE },
- { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE },
- { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE },
- { NULL }
-};
-
-/*ARGSUSED*/
-static int
-dir_leaf_entries_count(
- void *obj,
- int startoff)
-{
- xfs_dir_leafblock_t *block;
-
- ASSERT(startoff == 0);
- block = obj;
- if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)
- return 0;
- return be16_to_cpu(block->hdr.count);
-}
-
-/*ARGSUSED*/
-static int
-dir_leaf_hdr_count(
- void *obj,
- int startoff)
-{
- xfs_dir_leafblock_t *block;
-
- ASSERT(startoff == 0);
- block = obj;
- return be16_to_cpu(block->hdr.info.magic) == XFS_DIR_LEAF_MAGIC;
-}
-
-static int
-dir_leaf_name_count(
- void *obj,
- int startoff)
-{
- xfs_dir_leafblock_t *block;
- xfs_dir_leaf_entry_t *e;
- int i;
- int off;
-
- ASSERT(bitoffs(startoff) == 0);
- off = byteize(startoff);
- block = obj;
- if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)
- return 0;
- for (i = 0; i < be16_to_cpu(block->hdr.count); i++) {
- e = &block->entries[i];
- if (be16_to_cpu(e->nameidx) == off)
- return e->namelen;
- }
- return 0;
-}
-
-/*ARGSUSED*/
-int
-dir_leaf_name_size(
- void *obj,
- int startoff,
- int idx)
-{
- xfs_dir_leafblock_t *block;
- xfs_dir_leaf_entry_t *e;
-
- ASSERT(startoff == 0);
- block = obj;
- if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)
- return 0;
- e = &block->entries[idx];
- return bitize((int)xfs_dir_leaf_entsize_byentry(e));
-}
-
-/*ARGSUSED*/
-static int
-dir_leaf_namelist_count(
- void *obj,
- int startoff)
-{
- xfs_dir_leafblock_t *block;
-
- ASSERT(startoff == 0);
- block = obj;
- if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)
- return 0;
- return be16_to_cpu(block->hdr.count);
-}
-
-/*ARGSUSED*/
-static int
-dir_leaf_namelist_offset(
- void *obj,
- int startoff,
- int idx)
-{
- xfs_dir_leafblock_t *block;
- xfs_dir_leaf_entry_t *e;
-
- ASSERT(startoff == 0);
- block = obj;
- e = &block->entries[idx];
- return bitize(be16_to_cpu(e->nameidx));
-}
-
-/*ARGSUSED*/
-static int
-dir_node_btree_count(
- void *obj,
- int startoff)
-{
- xfs_da_intnode_t *block;
-
- ASSERT(startoff == 0); /* this is a base structure */
- block = obj;
- if (be16_to_cpu(block->hdr.info.magic) != XFS_DA_NODE_MAGIC)
- return 0;
- return be16_to_cpu(block->hdr.count);
-}
-
-/*ARGSUSED*/
-static int
-dir_node_hdr_count(
- void *obj,
- int startoff)
-{
- xfs_da_intnode_t *block;
-
- ASSERT(startoff == 0);
- block = obj;
- return be16_to_cpu(block->hdr.info.magic) == XFS_DA_NODE_MAGIC;
-}
-
-/*ARGSUSED*/
-int
-dir_size(
- void *obj,
- int startoff,
- int idx)
-{
- return bitize(mp->m_sb.sb_blocksize);
-}
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-extern const field_t dir_flds[];
-extern const field_t dir_hfld[];
-extern const field_t dir_blkinfo_flds[];
-extern const field_t dir_leaf_entry_flds[];
-extern const field_t dir_leaf_hdr_flds[];
-extern const field_t dir_leaf_map_flds[];
-extern const field_t dir_leaf_name_flds[];
-extern const field_t dir_node_entry_flds[];
-extern const field_t dir_node_hdr_flds[];
-
-extern int dir_leaf_name_size(void *obj, int startoff, int idx);
-extern int dir_size(void *obj, int startoff, int idx);
#include "faddr.h"
#include "fprint.h"
#include "field.h"
-#include "dir.h"
#include "dir2.h"
#include "init.h"
FLD_ARRAY|FLD_COUNT, TYP_NONE },
{ "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset,
dir2_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
- { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count,
+ { "nhdr", FLDT_DA_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count,
FLD_COUNT, TYP_NONE },
- { "nbtree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)), dir2_node_btree_count,
+ { "nbtree", FLDT_DA_NODE_ENTRY, OI(NOFF(btree)), dir2_node_btree_count,
FLD_ARRAY|FLD_COUNT, TYP_NONE },
{ "fhdr", FLDT_DIR2_FREE_HDR, OI(FOFF(hdr)), dir2_free_hdr_count,
FLD_COUNT, TYP_NONE },
#define LHOFF(f) bitize(offsetof(xfs_dir2_leaf_hdr_t, f))
const field_t dir2_leaf_hdr_flds[] = {
- { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE },
+ { "info", FLDT_DA_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE },
{ "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE },
{ "stale", FLDT_UINT16D, OI(LHOFF(stale)), C1, 0, TYP_NONE },
{ NULL }
{ NULL }
};
+#define DBOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f))
+const field_t da_blkinfo_flds[] = {
+ { "forw", FLDT_DIRBLOCK, OI(DBOFF(forw)), C1, 0, TYP_INODATA },
+ { "back", FLDT_DIRBLOCK, OI(DBOFF(back)), C1, 0, TYP_INODATA },
+ { "magic", FLDT_UINT16X, OI(DBOFF(magic)), C1, 0, TYP_NONE },
+ { "pad", FLDT_UINT16X, OI(DBOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
+ { NULL }
+};
+
+#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f))
+const field_t da_node_entry_flds[] = {
+ { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE },
+ { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA },
+ { NULL }
+};
+
+#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f))
+const field_t da_node_hdr_flds[] = {
+ { "info", FLDT_DA_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE },
+ { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE },
+ { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE },
+ { NULL }
+};
+
/*ARGSUSED*/
static int
dir2_block_hdr_count(
extern const field_t dir2_leaf_hdr_flds[];
extern const field_t dir2_leaf_tail_flds[];
+extern const field_t da_blkinfo_flds[];
+extern const field_t da_node_entry_flds[];
+extern const field_t da_node_hdr_flds[];
+
extern int dir2_data_union_size(void *obj, int startoff, int idx);
extern int dir2_size(void *obj, int startoff, int idx);
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <xfs/libxfs.h>
-#include "type.h"
-#include "faddr.h"
-#include "fprint.h"
-#include "field.h"
-#include "bit.h"
-#include "dirshort.h"
-
-static int dir_sf_entry_name_count(void *obj, int startoff);
-static int dir_shortform_list_count(void *obj, int startoff);
-static int dir_shortform_list_offset(void *obj, int startoff, int idx);
-
-#define OFF(f) bitize(offsetof(xfs_dir_shortform_t, f))
-const field_t dir_shortform_flds[] = {
- { "hdr", FLDT_DIR_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE },
- { "list", FLDT_DIR_SF_ENTRY, dir_shortform_list_offset,
- dir_shortform_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE },
- { NULL }
-};
-
-#define HOFF(f) bitize(offsetof(xfs_dir_sf_hdr_t, f))
-const field_t dir_sf_hdr_flds[] = {
- { "parent", FLDT_DIR_INO, OI(HOFF(parent)), C1, 0, TYP_INODE },
- { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE },
- { NULL }
-};
-
-#define EOFF(f) bitize(offsetof(xfs_dir_sf_entry_t, f))
-const field_t dir_sf_entry_flds[] = {
- { "inumber", FLDT_DIR_INO, OI(EOFF(inumber)), C1, 0, TYP_INODE },
- { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE },
- { "name", FLDT_CHARNS, OI(EOFF(name)), dir_sf_entry_name_count,
- FLD_COUNT, TYP_NONE },
- { NULL }
-};
-
-static int
-dir_sf_entry_name_count(
- void *obj,
- int startoff)
-{
- xfs_dir_sf_entry_t *e;
-
- ASSERT(bitoffs(startoff) == 0);
- e = (xfs_dir_sf_entry_t *)((char *)obj + byteize(startoff));
- return e->namelen;
-}
-
-int
-dir_sf_entry_size(
- void *obj,
- int startoff,
- int idx)
-{
- xfs_dir_sf_entry_t *e;
- int i;
- xfs_dir_shortform_t *sf;
-
- ASSERT(bitoffs(startoff) == 0);
- sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff));
- e = &sf->list[0];
- for (i = 0; i < idx; i++)
- e = xfs_dir_sf_nextentry(e);
- return bitize((int)xfs_dir_sf_entsize_byentry(e));
-}
-
-static int
-dir_shortform_list_count(
- void *obj,
- int startoff)
-{
- xfs_dir_shortform_t *sf;
-
- ASSERT(bitoffs(startoff) == 0);
- sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff));
- return sf->hdr.count;
-}
-
-static int
-dir_shortform_list_offset(
- void *obj,
- int startoff,
- int idx)
-{
- xfs_dir_sf_entry_t *e;
- int i;
- xfs_dir_shortform_t *sf;
-
- ASSERT(bitoffs(startoff) == 0);
- sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff));
- e = &sf->list[0];
- for (i = 0; i < idx; i++)
- e = xfs_dir_sf_nextentry(e);
- return bitize((int)((char *)e - (char *)sf));
-}
-
-int
-dirshort_size(
- void *obj,
- int startoff,
- int idx)
-{
- xfs_dir_sf_entry_t *e;
- int i;
- xfs_dir_shortform_t *sf;
-
- ASSERT(bitoffs(startoff) == 0);
- ASSERT(idx == 0);
- sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff));
- e = &sf->list[0];
- for (i = 0; i < sf->hdr.count; i++)
- e = xfs_dir_sf_nextentry(e);
- return bitize((int)((char *)e - (char *)sf));
-}
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-extern const field_t dir_sf_entry_flds[];
-extern const field_t dir_sf_hdr_flds[];
-extern const field_t dir_shortform_flds[];
-extern const field_t dirshort_hfld[];
-
-extern int dir_sf_entry_size(void *obj, int startoff, int idx);
-extern int dirshort_size(void *obj, int startoff, int idx);
#include "agfl.h"
#include "agi.h"
#include "sb.h"
-#include "dir.h"
-#include "dirshort.h"
#include "attr.h"
#include "attrshort.h"
#include "dquot.h"
SI(bitsz(__int8_t)), 0, NULL, NULL },
{ FLDT_DINODE_U, "dinode_u", NULL, (char *)inode_u_flds, inode_u_size,
FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_u_flds },
- { FLDT_DIR, "dir", NULL, (char *)dir_flds, dir_size, FTARG_SIZE, NULL,
- dir_flds },
{ FLDT_DIR2, "dir2", NULL, (char *)dir2_flds, dir2_size, FTARG_SIZE,
NULL, dir2_flds },
{ FLDT_DIR2_BLOCK_TAIL, "dir2_block_tail", NULL,
SI(bitsz(xfs_dir2_sf_off_t)), 0, NULL, NULL },
{ FLDT_DIR2SF, "dir2sf", NULL, (char *)dir2sf_flds, dir2sf_size,
FTARG_SIZE, NULL, dir2sf_flds },
- { FLDT_DIR_BLKINFO, "dir_blkinfo", NULL, (char *)dir_blkinfo_flds,
- SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, dir_blkinfo_flds },
- { FLDT_DIR_INO, "dir_ino", fp_num, "%llu", SI(bitsz(xfs_dir_ino_t)), 0,
- fa_ino, NULL },
- { FLDT_DIR_LEAF_ENTRY, "dir_leaf_entry", fp_sarray,
- (char *)dir_leaf_entry_flds, SI(bitsz(struct xfs_dir_leaf_entry)), 0,
- NULL, dir_leaf_entry_flds },
- { FLDT_DIR_LEAF_HDR, "dir_leaf_hdr", NULL, (char *)dir_leaf_hdr_flds,
- SI(bitsz(struct xfs_dir_leaf_hdr)), 0, NULL, dir_leaf_hdr_flds },
- { FLDT_DIR_LEAF_MAP, "dir_leaf_map", fp_sarray,
- (char *)dir_leaf_map_flds, SI(bitsz(struct xfs_dir_leaf_map)), 0,
- NULL, dir_leaf_map_flds },
- { FLDT_DIR_LEAF_NAME, "dir_leaf_name", NULL, (char *)dir_leaf_name_flds,
- dir_leaf_name_size, FTARG_SIZE, NULL, dir_leaf_name_flds },
- { FLDT_DIR_NODE_ENTRY, "dir_node_entry", fp_sarray,
- (char *)dir_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0,
- NULL, dir_node_entry_flds },
- { FLDT_DIR_NODE_HDR, "dir_node_hdr", NULL, (char *)dir_node_hdr_flds,
- SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, dir_node_hdr_flds },
- { FLDT_DIR_SF_ENTRY, "dir_sf_entry", NULL, (char *)dir_sf_entry_flds,
- dir_sf_entry_size, FTARG_SIZE, NULL, dir_sf_entry_flds },
- { FLDT_DIR_SF_HDR, "dir_sf_hdr", NULL, (char *)dir_sf_hdr_flds,
- SI(bitsz(struct xfs_dir_sf_hdr)), 0, NULL, dir_sf_hdr_flds },
+ { FLDT_DA_BLKINFO, "dir_blkinfo", NULL, (char *)da_blkinfo_flds,
+ SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, da_blkinfo_flds },
+ { FLDT_DA_NODE_ENTRY, "dir_node_entry", fp_sarray,
+ (char *)da_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0,
+ NULL, da_node_entry_flds },
+ { FLDT_DA_NODE_HDR, "dir_node_hdr", NULL, (char *)da_node_hdr_flds,
+ SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, da_node_hdr_flds },
{ FLDT_DIRBLOCK, "dirblock", fp_num, "%u", SI(bitsz(__uint32_t)), 0,
fa_dirblock, NULL },
- { FLDT_DIRSHORT, "dirshort", NULL, (char *)dir_shortform_flds,
- dirshort_size, FTARG_SIZE, NULL, dir_shortform_flds },
{ FLDT_DISK_DQUOT, "disk_dquot", NULL, (char *)disk_dquot_flds,
SI(bitsz(xfs_disk_dquot_t)), 0, NULL, disk_dquot_flds },
{ FLDT_DQBLK, "dqblk", NULL, (char *)dqblk_flds, SI(bitsz(xfs_dqblk_t)),
FLDT_DINODE_CORE,
FLDT_DINODE_FMT,
FLDT_DINODE_U,
- FLDT_DIR,
FLDT_DIR2,
FLDT_DIR2_BLOCK_TAIL,
FLDT_DIR2_DATA_FREE,
FLDT_DIR2_SF_HDR,
FLDT_DIR2_SF_OFF,
FLDT_DIR2SF,
- FLDT_DIR_BLKINFO,
- FLDT_DIR_INO,
- FLDT_DIR_LEAF_ENTRY,
- FLDT_DIR_LEAF_HDR,
- FLDT_DIR_LEAF_MAP,
- FLDT_DIR_LEAF_NAME,
- FLDT_DIR_NODE_ENTRY,
- FLDT_DIR_NODE_HDR,
- FLDT_DIR_SF_ENTRY,
- FLDT_DIR_SF_HDR,
+ FLDT_DA_BLKINFO,
+ FLDT_DA_NODE_ENTRY,
+ FLDT_DA_NODE_HDR,
FLDT_DIRBLOCK,
- FLDT_DIRSHORT,
FLDT_DISK_DQUOT,
FLDT_DQBLK,
FLDT_DQID,
static int inode_u_c_count(void *obj, int startoff);
static int inode_u_dev_count(void *obj, int startoff);
static int inode_u_muuid_count(void *obj, int startoff);
-static int inode_u_sfdir_count(void *obj, int startoff);
static int inode_u_sfdir2_count(void *obj, int startoff);
static int inode_u_symlink_count(void *obj, int startoff);
{ "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE },
{ "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE },
{ "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE },
- { "sfdir", FLDT_DIRSHORT, NULL, inode_u_sfdir_count, FLD_COUNT, TYP_NONE },
{ "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE },
{ "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT,
TYP_NONE },
{
switch (iocur_top->mode & S_IFMT) {
case S_IFDIR:
- return xfs_sb_version_hasdirv2(&mp->m_sb) ? TYP_DIR2 : TYP_DIR;
+ return TYP_DIR2;
case S_IFLNK:
return TYP_SYMLINK;
case S_IFREG:
return dip->di_format == XFS_DINODE_FMT_UUID;
}
-static int
-inode_u_sfdir_count(
- void *obj,
- int startoff)
-{
- xfs_dinode_t *dip;
-
- ASSERT(bitoffs(startoff) == 0);
- ASSERT(obj == iocur_top->data);
- dip = obj;
- ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
- return dip->di_format == XFS_DINODE_FMT_LOCAL &&
- (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR
- && !xfs_sb_version_hasdirv2(&mp->m_sb);
-}
-
static int
inode_u_sfdir2_count(
void *obj,
#include "agf.h"
#include "agfl.h"
#include "agi.h"
-#include "dir.h"
-#include "dirshort.h"
#include "io.h"
#include "output.h"
#include "write.h"
{ TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld },
{ TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld },
{ TYP_DATA, "data", handle_block, NULL },
- { TYP_DIR, "dir", handle_struct, dir_hfld },
{ TYP_DIR2, "dir2", handle_struct, dir2_hfld },
{ TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld },
{ TYP_INOBT, "inobt", handle_struct, inobt_hfld },
typedef enum typnm
{
TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA,
- TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR,
+ TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA,
TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE,
TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK,
TYP_TEXT, TYP_NONE
#define BLOCKSIZE 4096
#define INODESIZE 256
#define PERDIRENTRY \
- (sizeof(xfs_dir_leaf_entry_t) + sizeof(xfs_dir_leaf_name_t))
+ (sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_data_entry_t))
#define LOGSIZE 1000
#define FBLOCKS(n) ((n)/blocksize)
xfs_attr_sf.h xfs_bit.h xfs_bmap.h xfs_bmap_btree.h xfs_btree.h \
xfs_btree_trace.h xfs_buf_item.h xfs_da_btree.h xfs_dinode.h \
xfs_dir2.h xfs_dir2_block.h xfs_dir2_data.h xfs_dir2_leaf.h \
- xfs_dir2_node.h xfs_dir2_sf.h xfs_dir_leaf.h xfs_dir_sf.h \
+ xfs_dir2_node.h xfs_dir2_sf.h \
xfs_extfree_item.h xfs_ialloc.h xfs_ialloc_btree.h \
xfs_inode.h xfs_inode_item.h xfs_inum.h \
xfs_log.h xfs_log_priv.h xfs_log_recover.h xfs_metadump.h \
#include <xfs/xfs_bmap_btree.h>
#include <xfs/xfs_alloc_btree.h>
#include <xfs/xfs_ialloc_btree.h>
-#include <xfs/xfs_dir_sf.h>
#include <xfs/xfs_dir2_sf.h>
#include <xfs/xfs_attr_sf.h>
#include <xfs/xfs_dinode.h>
extern int xfs_imap_to_bp(xfs_mount_t *mp, xfs_trans_t *tp, struct xfs_imap *imap,
xfs_buf_t **bpp, uint buf_flags, uint iget_flags);
-#include <xfs/xfs_dir_leaf.h> /* dirv1 support in db & repair */
#include <xfs/xfs_dir2_data.h>
#include <xfs/xfs_dir2_leaf.h>
#include <xfs/xfs_dir2_block.h>
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __XFS_DIR_LEAF_H__
-#define __XFS_DIR_LEAF_H__
-
-/*
- * Version 1 Directory layout, internal structure, access macros, etc.
- * to allow various xfsprogs tools to read these structures.
- *
- * Large directories are structured around Btrees where all the data
- * elements are in the leaf nodes. Filenames are hashed into an int,
- * then that int is used as the index into the Btree. Since the hashval
- * of a filename may not be unique, we may have duplicate keys. The
- * internal links in the Btree are logical block offsets into the file.
- */
-
-/*========================================================================
- * Directory Structure when equal to XFS_LBSIZE(mp) bytes.
- *========================================================================*/
-
-/*
- * This is the structure of the leaf nodes in the Btree.
- *
- * Struct leaf_entry's are packed from the top. Names grow from the bottom
- * but are not packed. The freemap contains run-length-encoded entries
- * for the free bytes after the leaf_entry's, but only the N largest such,
- * smaller runs are dropped. When the freemap doesn't show enough space
- * for an allocation, we compact the namelist area and try again. If we
- * still don't have enough space, then we have to split the block.
- *
- * Since we have duplicate hash keys, for each key that matches, compare
- * the actual string. The root and intermediate node search always takes
- * the first-in-the-block key match found, so we should only have to work
- * "forw"ard. If none matches, continue with the "forw"ard leaf nodes
- * until the hash key changes or the filename is found.
- *
- * The parent directory and the self-pointer are explicitly represented
- * (ie: there are entries for "." and "..").
- *
- * Note that the count being a __uint16_t limits us to something like a
- * blocksize of 1.3MB in the face of worst case (short) filenames.
- */
-
-#define XFS_DIR_LEAF_MAGIC 0xfeeb
-
-#define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */
-
-
-typedef struct xfs_dir_leaf_map { /* RLE map of free bytes */
- __be16 base; /* base of free region */
- __be16 size; /* run length of free region */
-} xfs_dir_leaf_map_t;
-
-typedef struct xfs_dir_leaf_hdr { /* constant-structure header block */
- xfs_da_blkinfo_t info; /* block type, links, etc. */
- __be16 count; /* count of active leaf_entry's */
- __be16 namebytes; /* num bytes of name strings stored */
- __be16 firstused; /* first used byte in name area */
- __u8 holes; /* != 0 if blk needs compaction */
- __u8 pad1;
- xfs_dir_leaf_map_t freemap[XFS_DIR_LEAF_MAPSIZE];
-} xfs_dir_leaf_hdr_t;
-
-typedef struct xfs_dir_leaf_entry { /* sorted on key, not name */
- __be32 hashval; /* hash value of name */
- __be16 nameidx; /* index into buffer of name */
- __u8 namelen; /* length of name string */
- __u8 pad2;
-} xfs_dir_leaf_entry_t;
-
-typedef struct xfs_dir_leaf_name {
- xfs_dir_ino_t inumber; /* inode number for this key */
- __u8 name[1]; /* name string itself */
-} xfs_dir_leaf_name_t;
-
-typedef struct xfs_dir_leafblock {
- xfs_dir_leaf_hdr_t hdr; /* constant-structure header block */
- xfs_dir_leaf_entry_t entries[1]; /* var sized array */
- xfs_dir_leaf_name_t namelist[1]; /* grows from bottom of buf */
-} xfs_dir_leafblock_t;
-
-static inline int xfs_dir_leaf_entsize_byname(int len)
-{
- return (uint)sizeof(xfs_dir_leaf_name_t)-1 + len;
-}
-
-static inline int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry)
-{
- return (uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen;
-}
-
-static inline xfs_dir_leaf_name_t *
-xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset)
-{
- return (xfs_dir_leaf_name_t *)&((char *)(leafp))[offset];
-}
-
-#endif /* __XFS_DIR_LEAF_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __XFS_DIR_SF_H__
-#define __XFS_DIR_SF_H__
-
-/*
- * Directory layout when stored internal to an inode.
- *
- * Small directories are packed as tightly as possible so as to
- * fit into the literal area of the inode.
- */
-
-typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t;
-
-/*
- * The parent directory has a dedicated field, and the self-pointer must
- * be calculated on the fly.
- *
- * Entries are packed toward the top as tight as possible. The header
- * and the elements much be memcpy'd out into a work area to get correct
- * alignment for the inode number fields.
- */
-typedef struct xfs_dir_sf_hdr { /* constant-structure header block */
- xfs_dir_ino_t parent; /* parent dir inode number */
- __u8 count; /* count of active entries */
-} xfs_dir_sf_hdr_t;
-
-typedef struct xfs_dir_sf_entry {
- xfs_dir_ino_t inumber; /* referenced inode number */
- __u8 namelen; /* actual length of name (no NULL) */
- __u8 name[1]; /* name */
-} xfs_dir_sf_entry_t;
-
-typedef struct xfs_dir_shortform {
- xfs_dir_sf_hdr_t hdr;
- xfs_dir_sf_entry_t list[1]; /* variable sized array */
-} xfs_dir_shortform_t;
-
-/*
- * We generate this then sort it, so that readdirs are returned in
- * hash-order. Else seekdir won't work.
- */
-typedef struct xfs_dir_sf_sort {
- __u8 entno; /* .=0, ..=1, else entry# + 2 */
- __u8 seqno; /* sequence # with same hash value */
- __u8 namelen; /* length of name value (no null) */
- __be32 hash; /* this entry's hash value */
- xfs_intino_t ino; /* this entry's inode number */
- __u8 *name; /* name value, pointer into buffer */
-} xfs_dir_sf_sort_t;
-
-static inline void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to)
-{
- *to = XFS_GET_DIR_INO8(*from);
-}
-
-static inline void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to)
-{
- XFS_PUT_DIR_INO8(*from, *to);
-}
-
-static inline int xfs_dir_sf_entsize_byname(int len)
-{
- return sizeof(xfs_dir_sf_entry_t) - 1 + len;
-}
-
-static inline int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep)
-{
- return sizeof(xfs_dir_sf_entry_t) - 1 + sfep->namelen;
-}
-
-static inline xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep)
-{
- return (xfs_dir_sf_entry_t *)((char *)sfep +
- xfs_dir_sf_entsize_byentry(sfep));
-}
-
-static inline int xfs_dir_sf_allfit(int count, int totallen)
-{
- return sizeof(xfs_dir_sf_hdr_t) +
- (sizeof(xfs_dir_sf_entry_t) - 1) * count + totallen;
-}
-
-#endif /* __XFS_DIR_SF_H__ */
return 0;
}
-
-/*
- * Core dir v1 mount code for allowing reading of these dirs.
- */
-static void
-libxfs_dirv1_mount(
- xfs_mount_t *mp)
-{
- mp->m_dir_node_ents = mp->m_attr_node_ents =
- (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) /
- (uint)sizeof(xfs_da_node_entry_t);
- mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100;
- mp->m_dirblksize = mp->m_sb.sb_blocksize;
- mp->m_dirblkfsbs = 1;
-}
-
static int
libxfs_initialize_perag(
xfs_mount_t *mp,
}
/* Initialize the appropriate directory manager */
- if (xfs_sb_version_hasdirv2(sbp))
- xfs_dir_mount(mp);
- else {
- fprintf(stderr, _("%s: WARNING - filesystem uses v1 dirs,"
- "limited functionality provided.\n"), progname);
- libxfs_dirv1_mount(mp);
+ if (!xfs_sb_version_hasdirv2(sbp)) {
+
+ fprintf(stderr, _(
+ "%s: V1 directories unsupported. Please try an older xfsprogs.\n"),
+ progname);
+ exit(1);
}
+ xfs_dir_mount(mp);
/* Initialize cached values for the attribute manager */
mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;
}
void
-xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size)
+xlog_print_dir2_sf(xfs_dir2_sf_t *sfp, int size)
{
xfs_ino_t ino;
int count;
int i;
char namebuf[257];
- xfs_dir_sf_entry_t *sfep;
+ xfs_dir2_sf_entry_t *sfep;
/* XXX need to determine whether this is v1 or v2, then
print appropriate structure */
namebuf[sfep->namelen] = '\0';
printf(_("%s ino 0x%llx namelen %d\n"),
namebuf, (unsigned long long)ino, sfep->namelen);
- sfep = xfs_dir_sf_nextentry(sfep);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
}
case XFS_ILOG_DDATA:
printf(_("LOCAL inode data\n"));
if (mode == S_IFDIR)
- xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size);
+ xlog_print_dir2_sf((xfs_dir2_sf_t *)*ptr, size);
break;
default:
ASSERT((f->ilf_fields & XFS_ILOG_DFORK) == 0);
case XFS_ILOG_ADATA:
printf(_("LOCAL attr data\n"));
if (mode == S_IFDIR)
- xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size);
+ xlog_print_dir2_sf((xfs_dir2_sf_t *)*ptr, size);
break;
default:
ASSERT((f->ilf_fields & XFS_ILOG_AFORK) == 0);
LTCOMMAND = xfs_repair
HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h btree.h \
- dinode.h dir.h dir2.h err_protos.h globals.h incore.h protos.h rt.h \
+ dinode.h dir2.h err_protos.h globals.h incore.h protos.h rt.h \
progress.h scan.h versions.h prefetch.h threads.h
CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \
- dino_chunks.c dinode.c dir.c dir2.c globals.c incore.c \
+ dino_chunks.c dinode.c dir2.c globals.c incore.c \
incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \
phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \
progress.c prefetch.c rt.c sb.c scan.c threads.c \
#include "globals.h"
#include "err_protos.h"
#include "attr_repair.h"
-#include "dir.h"
#include "dinode.h"
#include "bmap.h"
#include "protos.h"
+#include "dir2.h"
static int xfs_acl_valid(xfs_acl_disk_t *daclp);
static int xfs_mac_valid(xfs_mac_label_t *lp);
+/*
+ * da node check/verify functions that the attribute tree relies on are first in
+ * the file before the actual attribute code. This used to be shared with the
+ * dir v1 code, but that format is no longer supported yb the userspace
+ * utilities and hence is now specific to the attribute tree implementation.
+ */
+#define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE
+
+typedef unsigned char da_freemap_t;
+
+/*
+ * the cursor gets passed up and down the da btree processing
+ * routines. The interior block processing routines use the
+ * cursor to determine if the pointers to and from the preceding
+ * and succeeding sibling blocks are ok and whether the values in
+ * the current block are consistent with the entries in the parent
+ * nodes. When a block is traversed, a parent-verification routine
+ * is called to verify if the next logical entry in the next level up
+ * is consistent with the greatest hashval in the next block of the
+ * current level. The verification routine is itself recursive and
+ * calls itself if it has to traverse an interior block to get
+ * the next logical entry. The routine recurses upwards through
+ * the tree until it finds a block where it can simply step to
+ * the next entry. The hashval in that entry should be equal to
+ * the hashval being passed to it (the greatest hashval in the block
+ * that the entry points to). If that isn't true, then the tree
+ * is blown and we need to trash it, salvage and trash it, or fix it.
+ * Currently, we just trash it.
+ */
+typedef struct da_level_state {
+ xfs_buf_t *bp; /* block bp */
+#ifdef XR_DIR_TRACE
+ xfs_da_intnode_t *n; /* bp data */
+#endif
+ xfs_dablk_t bno; /* file block number */
+ xfs_dahash_t hashval; /* last verified hashval */
+ int index; /* current index in block */
+ int dirty; /* is buffer dirty ? (1 == yes) */
+} da_level_state_t;
+
+typedef struct da_bt_cursor {
+ int active; /* highest level in tree (# levels-1) */
+ int type; /* 0 if dir, 1 if attr */
+ xfs_ino_t ino;
+ xfs_dablk_t greatest_bno;
+ xfs_dinode_t *dip;
+ da_level_state_t level[XFS_DA_NODE_MAXDEPTH];
+ struct blkmap *blkmap;
+} da_bt_cursor_t;
+
+
+/*
+ * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
+ * 1 == used, 0 == free.
+ */
+static da_freemap_t *
+alloc_da_freemap(struct xfs_mount *mp)
+{
+ return calloc(1, mp->m_sb.sb_blocksize / NBBY);
+}
+
+/*
+ * Set the he range [start, stop) in the directory freemap.
+ *
+ * Returns 1 if there is a conflict or 0 if everything's good.
+ *
+ * Within a char, the lowest bit of the char represents the byte with
+ * the smallest address
+ */
+static int
+set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
+{
+ const da_freemap_t mask = 0x1;
+ int i;
+
+ if (start > stop) {
+ /*
+ * allow == relation since [x, x) claims 1 byte
+ */
+ do_warn(_("bad range claimed [%d, %d) in da block\n"),
+ start, stop);
+ return(1);
+ }
+
+ if (stop > mp->m_sb.sb_blocksize) {
+ do_warn(
+ _("byte range end [%d %d) in da block larger than blocksize %d\n"),
+ start, stop, mp->m_sb.sb_blocksize);
+ return(1);
+ }
+
+ for (i = start; i < stop; i ++) {
+ if (map[i / NBBY] & (mask << i % NBBY)) {
+ do_warn(_("multiply claimed byte %d in da block\n"), i);
+ return(1);
+ }
+ map[i / NBBY] |= (mask << i % NBBY);
+ }
+
+ return(0);
+}
+
+/*
+ * walk tree from root to the left-most leaf block reading in
+ * blocks and setting up cursor. passes back file block number of the
+ * left-most leaf block if successful (bno). returns 1 if successful,
+ * 0 if unsuccessful.
+ */
+static int
+traverse_int_dablock(xfs_mount_t *mp,
+ da_bt_cursor_t *da_cursor,
+ xfs_dablk_t *rbno,
+ int whichfork)
+{
+ xfs_dablk_t bno;
+ int i;
+ xfs_da_intnode_t *node;
+ xfs_dfsbno_t fsbno;
+ xfs_buf_t *bp;
+
+ /*
+ * traverse down left-side of tree until we hit the
+ * left-most leaf block setting up the btree cursor along
+ * the way.
+ */
+ bno = 0;
+ i = -1;
+ node = NULL;
+ da_cursor->active = 0;
+
+ do {
+ /*
+ * read in each block along the way and set up cursor
+ */
+ fsbno = blkmap_get(da_cursor->blkmap, bno);
+
+ if (fsbno == NULLDFSBNO)
+ goto error_out;
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ XFS_FSB_TO_BB(mp, 1), 0);
+ if (!bp) {
+ if (whichfork == XFS_DATA_FORK)
+ do_warn(
+ _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"),
+ bno, fsbno, da_cursor->ino);
+ else
+ do_warn(
+ _("can't read block %u (fsbno %" PRIu64 ") for attrbute fork of inode %" PRIu64 "\n"),
+ bno, fsbno, da_cursor->ino);
+ goto error_out;
+ }
+
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ do_warn(_("bad dir/attr magic number in inode %" PRIu64 ", "
+ "file bno = %u, fsbno = %" PRIu64 "\n"),
+ da_cursor->ino, bno, fsbno);
+ libxfs_putbuf(bp);
+ goto error_out;
+ }
+ if (be16_to_cpu(node->hdr.count) >
+ mp->m_dir_node_ents) {
+ do_warn(_("bad record count in inode %" PRIu64 ", "
+ "count = %d, max = %d\n"),
+ da_cursor->ino,
+ be16_to_cpu(node->hdr.count),
+ mp->m_dir_node_ents);
+ libxfs_putbuf(bp);
+ goto error_out;
+ }
+
+ /*
+ * maintain level counter
+ */
+ if (i == -1)
+ i = da_cursor->active = be16_to_cpu(node->hdr.level);
+ else {
+ if (be16_to_cpu(node->hdr.level) == i - 1) {
+ i--;
+ } else {
+ if (whichfork == XFS_DATA_FORK)
+ do_warn(_("bad directory btree for "
+ "directory inode %" PRIu64 "\n"),
+ da_cursor->ino);
+ else
+ do_warn(_("bad attribute fork btree "
+ "for inode %" PRIu64 "\n"),
+ da_cursor->ino);
+ libxfs_putbuf(bp);
+ goto error_out;
+ }
+ }
+
+ da_cursor->level[i].hashval = be32_to_cpu(
+ node->btree[0].hashval);
+ da_cursor->level[i].bp = bp;
+ da_cursor->level[i].bno = bno;
+ da_cursor->level[i].index = 0;
+#ifdef XR_DIR_TRACE
+ da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp);
+#endif
+
+ /*
+ * set up new bno for next level down
+ */
+ bno = be32_to_cpu(node->btree[0].before);
+ } while (node != NULL && i > 1);
+
+ /*
+ * now return block number and get out
+ */
+ *rbno = da_cursor->level[0].bno = bno;
+ return(1);
+
+error_out:
+ while (i > 1 && i <= da_cursor->active) {
+ libxfs_putbuf(da_cursor->level[i].bp);
+ i++;
+ }
+
+ return(0);
+}
+
+/*
+ * blow out buffer for this level and all the rest above as well
+ * if error == 0, we are not expecting to encounter any unreleased
+ * buffers (e.g. if we do, it's a mistake). if error == 1, we're
+ * in an error-handling case so unreleased buffers may exist.
+ */
+static void
+release_da_cursor_int(xfs_mount_t *mp,
+ da_bt_cursor_t *cursor,
+ int prev_level,
+ int error)
+{
+ int level = prev_level + 1;
+
+ if (cursor->level[level].bp != NULL) {
+ if (!error) {
+ do_warn(_("release_da_cursor_int got unexpected "
+ "non-null bp, dabno = %u\n"),
+ cursor->level[level].bno);
+ }
+ ASSERT(error != 0);
+
+ libxfs_putbuf(cursor->level[level].bp);
+ cursor->level[level].bp = NULL;
+ }
+
+ if (level < cursor->active)
+ release_da_cursor_int(mp, cursor, level, error);
+
+ return;
+}
+
+static void
+release_da_cursor(xfs_mount_t *mp,
+ da_bt_cursor_t *cursor,
+ int prev_level)
+{
+ release_da_cursor_int(mp, cursor, prev_level, 0);
+}
+
+static void
+err_release_da_cursor(xfs_mount_t *mp,
+ da_bt_cursor_t *cursor,
+ int prev_level)
+{
+ release_da_cursor_int(mp, cursor, prev_level, 1);
+}
+
+/*
+ * make sure that all entries in all blocks along the right side of
+ * of the tree are used and hashval's are consistent. level is the
+ * level of the descendent block. returns 0 if good (even if it had
+ * to be fixed up), and 1 if bad. The right edge of the tree is
+ * technically a block boundary. this routine should be used then
+ * instead of verify_da_path().
+ */
+static int
+verify_final_da_path(xfs_mount_t *mp,
+ da_bt_cursor_t *cursor,
+ const int p_level)
+{
+ xfs_da_intnode_t *node;
+ xfs_dahash_t hashval;
+ int bad = 0;
+ int entry;
+ int this_level = p_level + 1;
+
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
+ this_level);
+#endif
+ /*
+ * the index should point to the next "unprocessed" entry
+ * in the block which should be the final (rightmost) entry
+ */
+ entry = cursor->level[this_level].index;
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
+ /*
+ * check internal block consistency on this level -- ensure
+ * that all entries are used, encountered and expected hashvals
+ * match, etc.
+ */
+ if (entry != be16_to_cpu(node->hdr.count) - 1) {
+ do_warn(_("directory/attribute block used/count "
+ "inconsistency - %d/%hu\n"),
+ entry, be16_to_cpu(node->hdr.count));
+ bad++;
+ }
+ /*
+ * hash values monotonically increasing ???
+ */
+ if (cursor->level[this_level].hashval >=
+ be32_to_cpu(node->btree[entry].hashval)) {
+ do_warn(_("directory/attribute block hashvalue inconsistency, "
+ "expected > %u / saw %u\n"),
+ cursor->level[this_level].hashval,
+ be32_to_cpu(node->btree[entry].hashval));
+ bad++;
+ }
+ if (be32_to_cpu(node->hdr.info.forw) != 0) {
+ do_warn(_("bad directory/attribute forward block pointer, "
+ "expected 0, saw %u\n"),
+ be32_to_cpu(node->hdr.info.forw));
+ bad++;
+ }
+ if (bad) {
+ do_warn(_("bad directory block in dir ino %" PRIu64 "\n"),
+ cursor->ino);
+ return(1);
+ }
+ /*
+ * keep track of greatest block # -- that gets
+ * us the length of the directory
+ */
+ if (cursor->level[this_level].bno > cursor->greatest_bno)
+ cursor->greatest_bno = cursor->level[this_level].bno;
+
+ /*
+ * ok, now check descendant block number against this level
+ */
+ if (cursor->level[p_level].bno != be32_to_cpu(
+ node->btree[entry].before)) {
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "bad directory btree pointer, child bno should "
+ "be %d, block bno is %d, hashval is %u\n",
+ be16_to_cpu(node->btree[entry].before),
+ cursor->level[p_level].bno,
+ cursor->level[p_level].hashval);
+ fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
+#endif
+ return(1);
+ }
+
+ if (cursor->level[p_level].hashval != be32_to_cpu(
+ node->btree[entry].hashval)) {
+ if (!no_modify) {
+ do_warn(_("correcting bad hashval in non-leaf "
+ "dir/attr block\n\tin (level %d) in "
+ "inode %" PRIu64 ".\n"),
+ this_level, cursor->ino);
+ node->btree[entry].hashval = cpu_to_be32(
+ cursor->level[p_level].hashval);
+ cursor->level[this_level].dirty++;
+ } else {
+ do_warn(_("would correct bad hashval in non-leaf "
+ "dir/attr block\n\tin (level %d) in "
+ "inode %" PRIu64 ".\n"),
+ this_level, cursor->ino);
+ }
+ }
+
+ /*
+ * Note: squirrel hashval away _before_ releasing the
+ * buffer, preventing a use-after-free problem.
+ */
+ hashval = be32_to_cpu(node->btree[entry].hashval);
+
+ /*
+ * release/write buffer
+ */
+ ASSERT(cursor->level[this_level].dirty == 0 ||
+ (cursor->level[this_level].dirty && !no_modify));
+
+ if (cursor->level[this_level].dirty && !no_modify)
+ libxfs_writebuf(cursor->level[this_level].bp, 0);
+ else
+ libxfs_putbuf(cursor->level[this_level].bp);
+
+ cursor->level[this_level].bp = NULL;
+
+ /*
+ * bail out if this is the root block (top of tree)
+ */
+ if (this_level >= cursor->active) {
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
+#endif
+ return(0);
+ }
+ /*
+ * set hashvalue to correctly reflect the now-validated
+ * last entry in this block and continue upwards validation
+ */
+ cursor->level[this_level].hashval = hashval;
+ return(verify_final_da_path(mp, cursor, this_level));
+}
+
+/*
+ * Verifies the path from a descendant block up to the root.
+ * Should be called when the descendant level traversal hits
+ * a block boundary before crossing the boundary (reading in a new
+ * block).
+ *
+ * the directory/attr btrees work differently to the other fs btrees.
+ * each interior block contains records that are <hashval, bno>
+ * pairs. The bno is a file bno, not a filesystem bno. The last
+ * hashvalue in the block <bno> will be <hashval>. BUT unlike
+ * the freespace btrees, the *last* value in each block gets
+ * propagated up the tree instead of the first value in each block.
+ * that is, the interior records point to child blocks and the *greatest*
+ * hash value contained by the child block is the one the block above
+ * uses as the key for the child block.
+ *
+ * level is the level of the descendent block. returns 0 if good,
+ * and 1 if bad. The descendant block may be a leaf block.
+ *
+ * the invariant here is that the values in the cursor for the
+ * levels beneath this level (this_level) and the cursor index
+ * for this level *must* be valid.
+ *
+ * that is, the hashval/bno info is accurate for all
+ * DESCENDANTS and match what the node[index] information
+ * for the current index in the cursor for this level.
+ *
+ * the index values in the cursor for the descendant level
+ * are allowed to be off by one as they will reflect the
+ * next entry at those levels to be processed.
+ *
+ * the hashvalue for the current level can't be set until
+ * we hit the last entry in the block so, it's garbage
+ * until set by this routine.
+ *
+ * bno and bp for the current block/level are always valid
+ * since they have to be set so we can get a buffer for the
+ * block.
+ */
+static int
+verify_da_path(xfs_mount_t *mp,
+ da_bt_cursor_t *cursor,
+ const int p_level)
+{
+ xfs_da_intnode_t *node;
+ xfs_da_intnode_t *newnode;
+ xfs_dfsbno_t fsbno;
+ xfs_dablk_t dabno;
+ xfs_buf_t *bp;
+ int bad;
+ int entry;
+ int this_level = p_level + 1;
+
+ /*
+ * index is currently set to point to the entry that
+ * should be processed now in this level.
+ */
+ entry = cursor->level[this_level].index;
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
+
+ /*
+ * if this block is out of entries, validate this
+ * block and move on to the next block.
+ * and update cursor value for said level
+ */
+ if (entry >= be16_to_cpu(node->hdr.count)) {
+ /*
+ * update the hash value for this level before
+ * validating it. bno value should be ok since
+ * it was set when the block was first read in.
+ */
+ cursor->level[this_level].hashval =
+ be32_to_cpu(node->btree[entry - 1].hashval);
+
+ /*
+ * keep track of greatest block # -- that gets
+ * us the length of the directory
+ */
+ if (cursor->level[this_level].bno > cursor->greatest_bno)
+ cursor->greatest_bno = cursor->level[this_level].bno;
+
+ /*
+ * validate the path for the current used-up block
+ * before we trash it
+ */
+ if (verify_da_path(mp, cursor, this_level))
+ return(1);
+ /*
+ * ok, now get the next buffer and check sibling pointers
+ */
+ dabno = be32_to_cpu(node->hdr.info.forw);
+ ASSERT(dabno != 0);
+ fsbno = blkmap_get(cursor->blkmap, dabno);
+
+ if (fsbno == NULLDFSBNO) {
+ do_warn(_("can't get map info for block %u "
+ "of directory inode %" PRIu64 "\n"),
+ dabno, cursor->ino);
+ return(1);
+ }
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ XFS_FSB_TO_BB(mp, 1), 0);
+ if (!bp) {
+ do_warn(
+ _("can't read block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
+ dabno, fsbno, cursor->ino);
+ return(1);
+ }
+
+ newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+ /*
+ * verify magic number and back pointer, sanity-check
+ * entry count, verify level
+ */
+ bad = 0;
+ if (XFS_DA_NODE_MAGIC != be16_to_cpu(newnode->hdr.info.magic)) {
+ do_warn(
+ _("bad magic number %x in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
+ be16_to_cpu(newnode->hdr.info.magic),
+ dabno, fsbno, cursor->ino);
+ bad++;
+ }
+ if (be32_to_cpu(newnode->hdr.info.back) !=
+ cursor->level[this_level].bno) {
+ do_warn(
+ _("bad back pointer in block %u (%"PRIu64 ") for directory inode %" PRIu64 "\n"),
+ dabno, fsbno, cursor->ino);
+ bad++;
+ }
+ if (be16_to_cpu(newnode->hdr.count) > mp->m_dir_node_ents) {
+ do_warn(
+ _("entry count %d too large in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
+ be16_to_cpu(newnode->hdr.count),
+ dabno, fsbno, cursor->ino);
+ bad++;
+ }
+ if (be16_to_cpu(newnode->hdr.level) != this_level) {
+ do_warn(
+ _("bad level %d in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
+ be16_to_cpu(newnode->hdr.level),
+ dabno, fsbno, cursor->ino);
+ bad++;
+ }
+ if (bad) {
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
+#endif
+ libxfs_putbuf(bp);
+ return(1);
+ }
+ /*
+ * update cursor, write out the *current* level if
+ * required. don't write out the descendant level
+ */
+ ASSERT(cursor->level[this_level].dirty == 0 ||
+ (cursor->level[this_level].dirty && !no_modify));
+
+ if (cursor->level[this_level].dirty && !no_modify)
+ libxfs_writebuf(cursor->level[this_level].bp, 0);
+ else
+ libxfs_putbuf(cursor->level[this_level].bp);
+ cursor->level[this_level].bp = bp;
+ cursor->level[this_level].dirty = 0;
+ cursor->level[this_level].bno = dabno;
+ cursor->level[this_level].hashval =
+ be32_to_cpu(newnode->btree[0].hashval);
+#ifdef XR_DIR_TRACE
+ cursor->level[this_level].n = newnode;
+#endif
+ node = newnode;
+
+ entry = cursor->level[this_level].index = 0;
+ }
+ /*
+ * ditto for block numbers
+ */
+ if (cursor->level[p_level].bno !=
+ be32_to_cpu(node->btree[entry].before)) {
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "bad directory btree pointer, child bno "
+ "should be %d, block bno is %d, hashval is %u\n",
+ be32_to_cpu(node->btree[entry].before),
+ cursor->level[p_level].bno,
+ cursor->level[p_level].hashval);
+ fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
+#endif
+ return(1);
+ }
+ /*
+ * ok, now validate last hashvalue in the descendant
+ * block against the hashval in the current entry
+ */
+ if (cursor->level[p_level].hashval !=
+ be32_to_cpu(node->btree[entry].hashval)) {
+ if (!no_modify) {
+ do_warn(_("correcting bad hashval in interior "
+ "dir/attr block\n\tin (level %d) in "
+ "inode %" PRIu64 ".\n"),
+ this_level, cursor->ino);
+ node->btree[entry].hashval = cpu_to_be32(
+ cursor->level[p_level].hashval);
+ cursor->level[this_level].dirty++;
+ } else {
+ do_warn(_("would correct bad hashval in interior "
+ "dir/attr block\n\tin (level %d) in "
+ "inode %" PRIu64 ".\n"),
+ this_level, cursor->ino);
+ }
+ }
+ /*
+ * increment index for this level to point to next entry
+ * (which should point to the next descendant block)
+ */
+ cursor->level[this_level].index++;
+#ifdef XR_DIR_TRACE
+ fprintf(stderr, "verify_da_path returns 0 (ok)\n");
+#endif
+ return(0);
+}
/*
* For attribute repair, there are 3 formats to worry about. First, is
#include "incore.h"
#include "protos.h"
#include "err_protos.h"
-#include "dir.h"
#include "dinode.h"
#include "versions.h"
#include "prefetch.h"
#include "incore.h"
#include "protos.h"
#include "err_protos.h"
-#include "dir.h"
#include "dir2.h"
#include "dinode.h"
#include "scan.h"
*/
switch (type) {
case XR_INO_DIR:
- if (xfs_sb_version_hasdirv2(&mp->m_sb) ?
- process_dir2(mp, lino, dino, ino_discovery,
- dirty, "", parent, dblkmap) :
- process_dir(mp, lino, dino, ino_discovery,
+ if (process_dir2(mp, lino, dino, ino_discovery,
dirty, "", parent, dblkmap)) {
do_warn(
_("problem with directory contents in inode %" PRIu64 "\n"),
+++ /dev/null
-/*
- * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <libxfs.h>
-#include "avl.h"
-#include "globals.h"
-#include "agheader.h"
-#include "incore.h"
-#include "protos.h"
-#include "err_protos.h"
-#include "dinode.h"
-#include "dir.h"
-#include "bmap.h"
-
-#if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE
-#define XR_DA_LEAF_MAPSIZE XFS_DIR_LEAF_MAPSIZE
-#else
-#define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE
-#endif
-
-
-
-typedef struct da_hole_map {
- int lost_holes;
- int num_holes;
- struct {
- int base;
- int size;
- } hentries[XR_DA_LEAF_MAPSIZE];
-} da_hole_map_t;
-
-/*
- * takes a name and length (name need not be null-terminated)
- * and returns 1 if the name contains a '/' or a \0, returns 0
- * otherwise
- */
-int
-namecheck(char *name, int length)
-{
- char *c;
- int i;
-
- ASSERT(length < MAXNAMELEN);
-
- for (c = name, i = 0; i < length; i++, c++) {
- if (*c == '/' || *c == '\0')
- return(1);
- }
-
- return(0);
-}
-
-/*
- * this routine performs inode discovery and tries to fix things
- * in place. available redundancy -- inode data size should match
- * used directory space in inode. returns number of valid directory
- * entries. a non-zero return value means the directory is bogus
- * and should be blasted.
- */
-static int
-process_shortform_dir(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dino_dirty, /* out - 1 if dinode buffer dirty? */
- xfs_ino_t *parent, /* out - NULLFSINO if entry doesn't exist */
- char *dirname, /* directory pathname */
- int *repair) /* out - 1 if dir was fixed up */
-{
- xfs_dir_shortform_t *sf;
- xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe;
- xfs_ino_t lino;
- int max_size;
- __int64_t ino_dir_size;
- int num_entries;
- int ino_off;
- int namelen;
- int i;
- int junkit;
- int tmp_len;
- int tmp_elen;
- int bad_sfnamelen;
- ino_tree_node_t *irec_p;
- char name[MAXNAMELEN + 1];
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_shortform_dir - inode %llu\n", ino);
-#endif
-
- sf = (xfs_dir_shortform_t *)XFS_DFORK_DPTR(dip);
- max_size = XFS_DFORK_DSIZE(dip, mp);
- num_entries = sf->hdr.count;
- ino_dir_size = be64_to_cpu(dip->di_size);
- *repair = 0;
-
- ASSERT(ino_dir_size <= max_size);
-
- /*
- * check for bad entry count
- */
- if (num_entries * sizeof(xfs_dir_sf_entry_t) + sizeof(xfs_dir_sf_hdr_t)
- > max_size || num_entries == 0)
- num_entries = 0xFF;
-
- /*
- * run through entries, stop at first bad entry, don't need
- * to check for .. since that's encoded in its own field
- */
- sf_entry = next_sfe = &sf->list[0];
- for (i = 0; i < num_entries && ino_dir_size >
- (__psint_t)next_sfe - (__psint_t)sf; i++) {
- tmp_sfe = NULL;
- sf_entry = next_sfe;
- junkit = 0;
- bad_sfnamelen = 0;
- xfs_dir_sf_get_dirino(&sf_entry->inumber, &lino);
-
- /*
- * if entry points to self, junk it since only '.' or '..'
- * should do that and shortform dirs don't contain either
- * entry. if inode number is invalid, trash entry.
- * if entry points to special inodes, trash it.
- * if inode is unknown but number is valid,
- * add it to the list of uncertain inodes. don't
- * have to worry about an entry pointing to a
- * deleted lost+found inode because the entry was
- * deleted at the same time that the inode was cleared.
- */
- if (lino == ino) {
- junkit = 1;
- } else if (verify_inum(mp, lino)) {
- /*
- * junk the entry, mark lino as NULL since it's bad
- */
- do_warn(
- _("invalid inode number %" PRIu64 " in directory %" PRIu64 "\n"), lino, ino);
- lino = NULLFSINO;
- junkit = 1;
- } else if (lino == mp->m_sb.sb_rbmino) {
- do_warn(
- _("entry in shortform dir %" PRIu64 " references rt bitmap inode %" PRIu64 "\n"),
- ino, lino);
- junkit = 1;
- } else if (lino == mp->m_sb.sb_rsumino) {
- do_warn(
- _("entry in shortform dir %" PRIu64 " references rt summary inode %" PRIu64 "\n"),
- ino, lino);
- junkit = 1;
- } else if (lino == mp->m_sb.sb_uquotino) {
- do_warn(
- _("entry in shortform dir %" PRIu64 " references user quota inode %" PRIu64 "\n"),
- ino, lino);
- junkit = 1;
- } else if (lino == mp->m_sb.sb_gquotino) {
- do_warn(
- _("entry in shortform dir %" PRIu64 " references group quota inode %" PRIu64 "\n"),
- ino, lino);
- junkit = 1;
- } else if ((irec_p = find_inode_rec(mp,
- XFS_INO_TO_AGNO(mp, lino),
- XFS_INO_TO_AGINO(mp, lino))) != NULL) {
- /*
- * if inode is marked free and we're in inode
- * discovery mode, leave the entry alone for now.
- * if the inode turns out to be used, we'll figure
- * that out when we scan it. If the inode really
- * is free, we'll hit this code again in phase 4
- * after we've finished inode discovery and blow
- * out the entry then.
- */
- ino_off = XFS_INO_TO_AGINO(mp, lino) -
- irec_p->ino_startnum;
- ASSERT(is_inode_confirmed(irec_p, ino_off));
-
- if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
- do_warn(
- _("entry references free inode %" PRIu64 " in shortform directory %" PRIu64 "\n"),
- lino, ino);
- junkit = 1;
- }
- } else if (ino_discovery) {
- /*
- * put the inode on the uncertain list. we'll
- * pull the inode off the list and check it later.
- * if the inode turns out be bogus, we'll delete
- * this entry in phase 6.
- */
- add_inode_uncertain(mp, lino, 0);
- } else {
- /*
- * blow the entry out. we know about all
- * undiscovered entries now (past inode discovery
- * phase) so this is clearly a bogus entry.
- */
- do_warn(
- _("entry references non-existent inode %" PRIu64 " in shortform dir %" PRIu64 "\n"),
- lino, ino);
- junkit = 1;
- }
-
- namelen = sf_entry->namelen;
-
- if (namelen == 0) {
- /*
- * if we're really lucky, this is
- * the last entry in which case we
- * can use the dir size to set the
- * namelen value. otherwise, forget
- * it because we're not going to be
- * able to find the next entry.
- */
- bad_sfnamelen = 1;
-
- if (i == num_entries - 1) {
- namelen = ino_dir_size -
- ((__psint_t) &sf_entry->name[0] -
- (__psint_t) sf);
- if (!no_modify) {
- do_warn(
- _("zero length entry in shortform dir %" PRIu64 ", resetting to %d\n"),
- ino, namelen);
- sf_entry->namelen = namelen;
- } else {
- do_warn(
- _("zero length entry in shortform dir %" PRIu64 ", would set to %d\n"),
- ino, namelen);
- }
- } else {
- do_warn(
- _("zero length entry in shortform dir %" PRIu64 ", "),
- ino);
- if (!no_modify)
- do_warn(_("junking %d entries\n"),
- num_entries - i);
- else
- do_warn(_("would junk %d entries\n"),
- num_entries - i);
- /*
- * don't process the rest of the directory,
- * break out of processing looop
- */
- break;
- }
- } else if ((__psint_t) sf_entry - (__psint_t) sf +
- + xfs_dir_sf_entsize_byentry(sf_entry)
- > ino_dir_size) {
- bad_sfnamelen = 1;
-
- if (i == num_entries - 1) {
- namelen = ino_dir_size -
- ((__psint_t) &sf_entry->name[0] -
- (__psint_t) sf);
- do_warn(
- _("size of last entry overflows space left in in shortform dir %" PRIu64 ", "),
- ino);
- if (!no_modify) {
- do_warn(_("resetting to %d\n"),
- namelen);
- sf_entry->namelen = namelen;
- *dino_dirty = 1;
- } else {
- do_warn(_("would reset to %d\n"),
- namelen);
- }
- } else {
- do_warn(
- _("size of entry #%d overflows space left in in shortform dir %" PRIu64 "\n"),
- i, ino);
- if (!no_modify) {
- if (i == num_entries - 1)
- do_warn(
- _("junking entry #%d\n"),
- i);
- else
- do_warn(
- _("junking %d entries\n"),
- num_entries - i);
- } else {
- if (i == num_entries - 1)
- do_warn(
- _("would junk entry #%d\n"),
- i);
- else
- do_warn(
- _("would junk %d entries\n"),
- num_entries - i);
- }
-
- break;
- }
- }
-
- /*
- * check for illegal chars in name.
- * no need to check for bad length because
- * the length value is stored in a byte
- * so it can't be too big, it can only wrap
- */
- if (namecheck((char *)&sf_entry->name[0], namelen)) {
- /*
- * junk entry
- */
- do_warn(
- _("entry contains illegal character in shortform dir %" PRIu64 "\n"),
- ino);
- junkit = 1;
- }
-
- /*
- * junk the entry by copying up the rest of the
- * fork over the current entry and decrementing
- * the entry count. if we're in no_modify mode,
- * just issue the warning instead. then continue
- * the loop with the next_sfe pointer set to the
- * correct place in the fork and other counters
- * properly set to reflect the deletion if it
- * happened.
- */
- if (junkit) {
- memmove(name, sf_entry->name, namelen);
- name[namelen] = '\0';
-
- if (!no_modify) {
- tmp_elen = xfs_dir_sf_entsize_byentry(sf_entry);
- be64_add_cpu(&dip->di_size, -tmp_elen);
- ino_dir_size -= tmp_elen;
-
- tmp_sfe = (xfs_dir_sf_entry_t *)
- ((__psint_t) sf_entry + tmp_elen);
- tmp_len = max_size - ((__psint_t) tmp_sfe
- - (__psint_t) sf);
-
- memmove(sf_entry, tmp_sfe, tmp_len);
-
- sf->hdr.count -= 1;
- num_entries--;
- memset((void *)((__psint_t)sf_entry + tmp_len),
- 0, tmp_elen);
-
- /*
- * reset the tmp value to the current
- * pointer so we'll process the entry
- * we just moved up
- */
- tmp_sfe = sf_entry;
-
- /*
- * WARNING: drop the index i by one
- * so it matches the decremented count
- * for accurate comparisons later
- */
- i--;
-
- *dino_dirty = 1;
- *repair = 1;
-
- do_warn(
- _("junking entry \"%s\" in directory inode %" PRIu64 "\n"),
- name, ino);
- } else {
- do_warn(
- _("would have junked entry \"%s\" in directory inode %" PRIu64 "\n"),
- name, ino);
- }
- }
-
- /*
- * go onto next entry unless we've just junked an
- * entry in which the current entry pointer points
- * to an unprocessed entry. have to take into zero-len
- * entries into account in no modify mode since we
- * calculate size based on next_sfe.
- */
- next_sfe = (tmp_sfe == NULL)
- ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry
- + ((!bad_sfnamelen)
- ? xfs_dir_sf_entsize_byentry(sf_entry)
- : sizeof(xfs_dir_sf_entry_t) - 1
- + namelen))
- : tmp_sfe;
- }
-
- /* sync up sizes and entry counts */
-
- if (sf->hdr.count != i) {
- if (no_modify) {
- do_warn(
- _("would have corrected entry count in directory %" PRIu64 " from %d to %d\n"),
- ino, sf->hdr.count, i);
- } else {
- do_warn(
- _("corrected entry count in directory %" PRIu64 ", was %d, now %d\n"),
- ino, sf->hdr.count, i);
- sf->hdr.count = i;
- *dino_dirty = 1;
- *repair = 1;
- }
- }
-
- if ((__psint_t) next_sfe - (__psint_t) sf != ino_dir_size) {
- if (no_modify) {
- do_warn(
- _("would have corrected directory %" PRIu64 " size from %" PRId64 "to %" PRIdPTR "\n"),
- ino, ino_dir_size,
- (intptr_t)next_sfe - (intptr_t )sf);
- } else {
- do_warn(
- _("corrected directory %" PRIu64 " size, was %" PRId64 ", now %" PRIdPTR "\n"),
- ino, ino_dir_size,
- (intptr_t)next_sfe - (intptr_t)sf);
-
- dip->di_size = cpu_to_be64((__psint_t)next_sfe
- - (__psint_t)sf);
- *dino_dirty = 1;
- *repair = 1;
- }
- }
- /*
- * check parent (..) entry
- */
- xfs_dir_sf_get_dirino(&sf->hdr.parent, parent);
-
- /*
- * if parent entry is bogus, null it out. we'll fix it later .
- */
- if (verify_inum(mp, *parent)) {
- *parent = NULLFSINO;
-
- do_warn(
- _("bogus .. inode number (%" PRIu64 ") in directory inode %" PRIu64 ", "),
- *parent, ino);
- if (!no_modify) {
- do_warn(_("clearing inode number\n"));
-
- xfs_dir_sf_put_dirino(parent, &sf->hdr.parent);
- *dino_dirty = 1;
- *repair = 1;
- } else {
- do_warn(_("would clear inode number\n"));
- }
- } else if (ino == mp->m_sb.sb_rootino && ino != *parent) {
- /*
- * root directories must have .. == .
- */
- if (!no_modify) {
- do_warn(
- _("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 "\n"),
- ino, *parent, ino);
- *parent = ino;
- xfs_dir_sf_put_dirino(parent, &sf->hdr.parent);
- *dino_dirty = 1;
- *repair = 1;
- } else {
- do_warn(
- _("would have corrected root directory %" PRIu64 " .. entry from %" PRIu64 " to %" PRIu64 "\n"),
- ino, *parent, ino);
- }
- } else if (ino == *parent && ino != mp->m_sb.sb_rootino) {
- /*
- * likewise, non-root directories can't have .. pointing
- * to .
- */
- *parent = NULLFSINO;
- do_warn(_("bad .. entry in dir ino %" PRIu64 ", points to self, "),
- ino);
- if (!no_modify) {
- do_warn(_("clearing inode number\n"));
-
- xfs_dir_sf_put_dirino(parent, &sf->hdr.parent);
- *dino_dirty = 1;
- *repair = 1;
- } else {
- do_warn(_("would clear inode number\n"));
- }
- }
-
- return(0);
-}
-
-/*
- * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
- * 1 == used, 0 == free.
- */
-da_freemap_t *
-alloc_da_freemap(struct xfs_mount *mp)
-{
- return calloc(1, mp->m_sb.sb_blocksize / NBBY);
-}
-
-/*
- * Set the he range [start, stop) in the directory freemap.
- *
- * Returns 1 if there is a conflict or 0 if everything's good.
- *
- * Within a char, the lowest bit of the char represents the byte with
- * the smallest address
- */
-int
-set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
-{
- const da_freemap_t mask = 0x1;
- int i;
-
- if (start > stop) {
- /*
- * allow == relation since [x, x) claims 1 byte
- */
- do_warn(_("bad range claimed [%d, %d) in da block\n"),
- start, stop);
- return(1);
- }
-
- if (stop > mp->m_sb.sb_blocksize) {
- do_warn(
- _("byte range end [%d %d) in da block larger than blocksize %d\n"),
- start, stop, mp->m_sb.sb_blocksize);
- return(1);
- }
-
- for (i = start; i < stop; i ++) {
- if (map[i / NBBY] & (mask << i % NBBY)) {
- do_warn(_("multiply claimed byte %d in da block\n"), i);
- return(1);
- }
- map[i / NBBY] |= (mask << i % NBBY);
- }
-
- return(0);
-}
-
-/*
- * returns 0 if holemap is consistent with reality (as expressed by
- * the da_freemap_t). returns 1 if there's a conflict.
- */
-static int
-verify_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes,
- xfs_ino_t ino, xfs_dablk_t da_bno)
-{
- int i, j, start, len;
- const da_freemap_t mask = 0x1;
-
- for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
- if (holes->hentries[i].size == 0)
- continue;
-
- start = holes->hentries[i].base;
- len = holes->hentries[i].size;
-
- if (start >= mp->m_sb.sb_blocksize ||
- start + len > mp->m_sb.sb_blocksize) {
- do_warn(
- _("hole (start %d, len %d) out of range, block %d, dir ino %" PRIu64 "\n"),
- start, len, da_bno, ino);
- return(1);
- }
-
- for (j = start; j < start + len; j++) {
- if ((map[j / NBBY] & (mask << (j % NBBY))) != 0) {
- /*
- * bad news -- hole claims a used byte is free
- */
- do_warn(
- _("hole claims used byte %d, block %d, dir ino %" PRIu64 "\n"),
- j, da_bno, ino);
- return(1);
- }
- }
- }
-
- return(0);
-}
-
-static void
-process_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes)
-{
- int i, j, in_hole, start, length, smallest, num_holes;
- const da_freemap_t mask = 0x1;
-
- num_holes = in_hole = start = length = 0;
-
- for (i = 0; i < mp->m_sb.sb_blocksize; i++) {
- if ((map[i / NBBY] & (mask << (i % NBBY))) == 0) {
- /*
- * byte is free (unused)
- */
- if (in_hole == 1)
- continue;
- /*
- * start of a new hole
- */
- in_hole = 1;
- start = i;
- } else {
- /*
- * byte is used
- */
- if (in_hole == 0)
- continue;
- /*
- * end of a hole
- */
- in_hole = 0;
- /*
- * if the hole disappears, throw it away
- */
- length = i - start;
-
- if (length <= 0)
- continue;
-
- num_holes++;
-
- for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) {
- if (holes->hentries[j].size <
- holes->hentries[smallest].size)
- smallest = j;
-
- }
- if (length > holes->hentries[smallest].size) {
- holes->hentries[smallest].base = start;
- holes->hentries[smallest].size = length;
- }
- }
- }
-
- /*
- * see if we have a big hole at the end
- */
- if (in_hole == 1) {
- /*
- * duplicate of hole placement code above
- */
- length = i - start;
-
- if (length > 0) {
- num_holes++;
-
- for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) {
- if (holes->hentries[j].size <
- holes->hentries[smallest].size)
- smallest = j;
-
- }
- if (length > holes->hentries[smallest].size) {
- holes->hentries[smallest].base = start;
- holes->hentries[smallest].size = length;
- }
- }
- }
-
- holes->lost_holes = MAX(num_holes - XR_DA_LEAF_MAPSIZE, 0);
- holes->num_holes = num_holes;
-
- return;
-}
-
-/*
- * returns 1 if the hole info doesn't match, 0 if it does
- */
-static int
-compare_da_freemaps(xfs_mount_t *mp, da_hole_map_t *holemap,
- da_hole_map_t *block_hmap, int entries,
- xfs_ino_t ino, xfs_dablk_t da_bno)
-{
- int i, k, res, found;
-
- res = 0;
-
- /*
- * we chop holemap->lost_holes down to being two-valued
- * value (1 or 0) for the test because the filesystem
- * value is two-valued
- */
- if ((holemap->lost_holes > 0 ? 1 : 0) != block_hmap->lost_holes) {
- if (verbose) {
- do_warn(
- _("- derived hole value %d, saw %d, block %d, dir ino %" PRIu64 "\n"),
- holemap->lost_holes, block_hmap->lost_holes,
- da_bno, ino);
- res = 1;
- } else
- return(1);
- }
-
- for (i = 0; i < entries; i++) {
- for (found = k = 0; k < entries; k++) {
- if (holemap->hentries[i].base ==
- block_hmap->hentries[k].base
- && holemap->hentries[i].size ==
- block_hmap->hentries[k].size)
- found = 1;
- }
- if (!found) {
- if (verbose) {
- do_warn(
-_("- derived hole (base %d, size %d) in block %d, dir inode %" PRIu64 " not found\n"),
- holemap->hentries[i].base,
- holemap->hentries[i].size,
- da_bno, ino);
- res = 1;
- } else
- return(1);
- }
- }
-
- return(res);
-}
-
-/*
- * walk tree from root to the left-most leaf block reading in
- * blocks and setting up cursor. passes back file block number of the
- * left-most leaf block if successful (bno). returns 1 if successful,
- * 0 if unsuccessful.
- */
-int
-traverse_int_dablock(xfs_mount_t *mp,
- da_bt_cursor_t *da_cursor,
- xfs_dablk_t *rbno,
- int whichfork)
-{
- xfs_dablk_t bno;
- int i;
- xfs_da_intnode_t *node;
- xfs_dfsbno_t fsbno;
- xfs_buf_t *bp;
-
- /*
- * traverse down left-side of tree until we hit the
- * left-most leaf block setting up the btree cursor along
- * the way.
- */
- bno = 0;
- i = -1;
- node = NULL;
- da_cursor->active = 0;
-
- do {
- /*
- * read in each block along the way and set up cursor
- */
- fsbno = blkmap_get(da_cursor->blkmap, bno);
-
- if (fsbno == NULLDFSBNO)
- goto error_out;
-
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
- XFS_FSB_TO_BB(mp, 1), 0);
- if (!bp) {
- if (whichfork == XFS_DATA_FORK)
- do_warn(
- _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"),
- bno, fsbno, da_cursor->ino);
- else
- do_warn(
- _("can't read block %u (fsbno %" PRIu64 ") for attrbute fork of inode %" PRIu64 "\n"),
- bno, fsbno, da_cursor->ino);
- goto error_out;
- }
-
- node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
-
- if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
- do_warn(_("bad dir/attr magic number in inode %" PRIu64 ", "
- "file bno = %u, fsbno = %" PRIu64 "\n"),
- da_cursor->ino, bno, fsbno);
- libxfs_putbuf(bp);
- goto error_out;
- }
- if (be16_to_cpu(node->hdr.count) >
- mp->m_dir_node_ents) {
- do_warn(_("bad record count in inode %" PRIu64 ", "
- "count = %d, max = %d\n"),
- da_cursor->ino,
- be16_to_cpu(node->hdr.count),
- mp->m_dir_node_ents);
- libxfs_putbuf(bp);
- goto error_out;
- }
-
- /*
- * maintain level counter
- */
- if (i == -1)
- i = da_cursor->active = be16_to_cpu(node->hdr.level);
- else {
- if (be16_to_cpu(node->hdr.level) == i - 1) {
- i--;
- } else {
- if (whichfork == XFS_DATA_FORK)
- do_warn(_("bad directory btree for "
- "directory inode %" PRIu64 "\n"),
- da_cursor->ino);
- else
- do_warn(_("bad attribute fork btree "
- "for inode %" PRIu64 "\n"),
- da_cursor->ino);
- libxfs_putbuf(bp);
- goto error_out;
- }
- }
-
- da_cursor->level[i].hashval = be32_to_cpu(
- node->btree[0].hashval);
- da_cursor->level[i].bp = bp;
- da_cursor->level[i].bno = bno;
- da_cursor->level[i].index = 0;
-#ifdef XR_DIR_TRACE
- da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp);
-#endif
-
- /*
- * set up new bno for next level down
- */
- bno = be32_to_cpu(node->btree[0].before);
- } while (node != NULL && i > 1);
-
- /*
- * now return block number and get out
- */
- *rbno = da_cursor->level[0].bno = bno;
- return(1);
-
-error_out:
- while (i > 1 && i <= da_cursor->active) {
- libxfs_putbuf(da_cursor->level[i].bp);
- i++;
- }
-
- return(0);
-}
-
-/*
- * blow out buffer for this level and all the rest above as well
- * if error == 0, we are not expecting to encounter any unreleased
- * buffers (e.g. if we do, it's a mistake). if error == 1, we're
- * in an error-handling case so unreleased buffers may exist.
- */
-static void
-release_da_cursor_int(xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- int prev_level,
- int error)
-{
- int level = prev_level + 1;
-
- if (cursor->level[level].bp != NULL) {
- if (!error) {
- do_warn(_("release_da_cursor_int got unexpected "
- "non-null bp, dabno = %u\n"),
- cursor->level[level].bno);
- }
- ASSERT(error != 0);
-
- libxfs_putbuf(cursor->level[level].bp);
- cursor->level[level].bp = NULL;
- }
-
- if (level < cursor->active)
- release_da_cursor_int(mp, cursor, level, error);
-
- return;
-}
-
-void
-release_da_cursor(xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- int prev_level)
-{
- release_da_cursor_int(mp, cursor, prev_level, 0);
-}
-
-void
-err_release_da_cursor(xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- int prev_level)
-{
- release_da_cursor_int(mp, cursor, prev_level, 1);
-}
-
-/*
- * make sure that all entries in all blocks along the right side of
- * of the tree are used and hashval's are consistent. level is the
- * level of the descendent block. returns 0 if good (even if it had
- * to be fixed up), and 1 if bad. The right edge of the tree is
- * technically a block boundary. this routine should be used then
- * instead of verify_da_path().
- */
-int
-verify_final_da_path(xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- const int p_level)
-{
- xfs_da_intnode_t *node;
- xfs_dahash_t hashval;
- int bad = 0;
- int entry;
- int this_level = p_level + 1;
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
- this_level);
-#endif
- /*
- * the index should point to the next "unprocessed" entry
- * in the block which should be the final (rightmost) entry
- */
- entry = cursor->level[this_level].index;
- node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
- /*
- * check internal block consistency on this level -- ensure
- * that all entries are used, encountered and expected hashvals
- * match, etc.
- */
- if (entry != be16_to_cpu(node->hdr.count) - 1) {
- do_warn(_("directory/attribute block used/count "
- "inconsistency - %d/%hu\n"),
- entry, be16_to_cpu(node->hdr.count));
- bad++;
- }
- /*
- * hash values monotonically increasing ???
- */
- if (cursor->level[this_level].hashval >=
- be32_to_cpu(node->btree[entry].hashval)) {
- do_warn(_("directory/attribute block hashvalue inconsistency, "
- "expected > %u / saw %u\n"),
- cursor->level[this_level].hashval,
- be32_to_cpu(node->btree[entry].hashval));
- bad++;
- }
- if (be32_to_cpu(node->hdr.info.forw) != 0) {
- do_warn(_("bad directory/attribute forward block pointer, "
- "expected 0, saw %u\n"),
- be32_to_cpu(node->hdr.info.forw));
- bad++;
- }
- if (bad) {
- do_warn(_("bad directory block in dir ino %" PRIu64 "\n"),
- cursor->ino);
- return(1);
- }
- /*
- * keep track of greatest block # -- that gets
- * us the length of the directory
- */
- if (cursor->level[this_level].bno > cursor->greatest_bno)
- cursor->greatest_bno = cursor->level[this_level].bno;
-
- /*
- * ok, now check descendant block number against this level
- */
- if (cursor->level[p_level].bno != be32_to_cpu(
- node->btree[entry].before)) {
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "bad directory btree pointer, child bno should "
- "be %d, block bno is %d, hashval is %u\n",
- be16_to_cpu(node->btree[entry].before),
- cursor->level[p_level].bno,
- cursor->level[p_level].hashval);
- fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
-#endif
- return(1);
- }
-
- if (cursor->level[p_level].hashval != be32_to_cpu(
- node->btree[entry].hashval)) {
- if (!no_modify) {
- do_warn(_("correcting bad hashval in non-leaf "
- "dir/attr block\n\tin (level %d) in "
- "inode %" PRIu64 ".\n"),
- this_level, cursor->ino);
- node->btree[entry].hashval = cpu_to_be32(
- cursor->level[p_level].hashval);
- cursor->level[this_level].dirty++;
- } else {
- do_warn(_("would correct bad hashval in non-leaf "
- "dir/attr block\n\tin (level %d) in "
- "inode %" PRIu64 ".\n"),
- this_level, cursor->ino);
- }
- }
-
- /*
- * Note: squirrel hashval away _before_ releasing the
- * buffer, preventing a use-after-free problem.
- */
- hashval = be32_to_cpu(node->btree[entry].hashval);
-
- /*
- * release/write buffer
- */
- ASSERT(cursor->level[this_level].dirty == 0 ||
- (cursor->level[this_level].dirty && !no_modify));
-
- if (cursor->level[this_level].dirty && !no_modify)
- libxfs_writebuf(cursor->level[this_level].bp, 0);
- else
- libxfs_putbuf(cursor->level[this_level].bp);
-
- cursor->level[this_level].bp = NULL;
-
- /*
- * bail out if this is the root block (top of tree)
- */
- if (this_level >= cursor->active) {
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
-#endif
- return(0);
- }
- /*
- * set hashvalue to correctly reflect the now-validated
- * last entry in this block and continue upwards validation
- */
- cursor->level[this_level].hashval = hashval;
- return(verify_final_da_path(mp, cursor, this_level));
-}
-
-/*
- * Verifies the path from a descendant block up to the root.
- * Should be called when the descendant level traversal hits
- * a block boundary before crossing the boundary (reading in a new
- * block).
- *
- * the directory/attr btrees work differently to the other fs btrees.
- * each interior block contains records that are <hashval, bno>
- * pairs. The bno is a file bno, not a filesystem bno. The last
- * hashvalue in the block <bno> will be <hashval>. BUT unlike
- * the freespace btrees, the *last* value in each block gets
- * propagated up the tree instead of the first value in each block.
- * that is, the interior records point to child blocks and the *greatest*
- * hash value contained by the child block is the one the block above
- * uses as the key for the child block.
- *
- * level is the level of the descendent block. returns 0 if good,
- * and 1 if bad. The descendant block may be a leaf block.
- *
- * the invariant here is that the values in the cursor for the
- * levels beneath this level (this_level) and the cursor index
- * for this level *must* be valid.
- *
- * that is, the hashval/bno info is accurate for all
- * DESCENDANTS and match what the node[index] information
- * for the current index in the cursor for this level.
- *
- * the index values in the cursor for the descendant level
- * are allowed to be off by one as they will reflect the
- * next entry at those levels to be processed.
- *
- * the hashvalue for the current level can't be set until
- * we hit the last entry in the block so, it's garbage
- * until set by this routine.
- *
- * bno and bp for the current block/level are always valid
- * since they have to be set so we can get a buffer for the
- * block.
- */
-int
-verify_da_path(xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- const int p_level)
-{
- xfs_da_intnode_t *node;
- xfs_da_intnode_t *newnode;
- xfs_dfsbno_t fsbno;
- xfs_dablk_t dabno;
- xfs_buf_t *bp;
- int bad;
- int entry;
- int this_level = p_level + 1;
-
- /*
- * index is currently set to point to the entry that
- * should be processed now in this level.
- */
- entry = cursor->level[this_level].index;
- node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
-
- /*
- * if this block is out of entries, validate this
- * block and move on to the next block.
- * and update cursor value for said level
- */
- if (entry >= be16_to_cpu(node->hdr.count)) {
- /*
- * update the hash value for this level before
- * validating it. bno value should be ok since
- * it was set when the block was first read in.
- */
- cursor->level[this_level].hashval =
- be32_to_cpu(node->btree[entry - 1].hashval);
-
- /*
- * keep track of greatest block # -- that gets
- * us the length of the directory
- */
- if (cursor->level[this_level].bno > cursor->greatest_bno)
- cursor->greatest_bno = cursor->level[this_level].bno;
-
- /*
- * validate the path for the current used-up block
- * before we trash it
- */
- if (verify_da_path(mp, cursor, this_level))
- return(1);
- /*
- * ok, now get the next buffer and check sibling pointers
- */
- dabno = be32_to_cpu(node->hdr.info.forw);
- ASSERT(dabno != 0);
- fsbno = blkmap_get(cursor->blkmap, dabno);
-
- if (fsbno == NULLDFSBNO) {
- do_warn(_("can't get map info for block %u "
- "of directory inode %" PRIu64 "\n"),
- dabno, cursor->ino);
- return(1);
- }
-
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
- XFS_FSB_TO_BB(mp, 1), 0);
- if (!bp) {
- do_warn(
- _("can't read block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
- dabno, fsbno, cursor->ino);
- return(1);
- }
-
- newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
- /*
- * verify magic number and back pointer, sanity-check
- * entry count, verify level
- */
- bad = 0;
- if (XFS_DA_NODE_MAGIC != be16_to_cpu(newnode->hdr.info.magic)) {
- do_warn(
- _("bad magic number %x in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
- be16_to_cpu(newnode->hdr.info.magic),
- dabno, fsbno, cursor->ino);
- bad++;
- }
- if (be32_to_cpu(newnode->hdr.info.back) !=
- cursor->level[this_level].bno) {
- do_warn(
- _("bad back pointer in block %u (%"PRIu64 ") for directory inode %" PRIu64 "\n"),
- dabno, fsbno, cursor->ino);
- bad++;
- }
- if (be16_to_cpu(newnode->hdr.count) > mp->m_dir_node_ents) {
- do_warn(
- _("entry count %d too large in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
- be16_to_cpu(newnode->hdr.count),
- dabno, fsbno, cursor->ino);
- bad++;
- }
- if (be16_to_cpu(newnode->hdr.level) != this_level) {
- do_warn(
- _("bad level %d in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
- be16_to_cpu(newnode->hdr.level),
- dabno, fsbno, cursor->ino);
- bad++;
- }
- if (bad) {
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
-#endif
- libxfs_putbuf(bp);
- return(1);
- }
- /*
- * update cursor, write out the *current* level if
- * required. don't write out the descendant level
- */
- ASSERT(cursor->level[this_level].dirty == 0 ||
- (cursor->level[this_level].dirty && !no_modify));
-
- if (cursor->level[this_level].dirty && !no_modify)
- libxfs_writebuf(cursor->level[this_level].bp, 0);
- else
- libxfs_putbuf(cursor->level[this_level].bp);
- cursor->level[this_level].bp = bp;
- cursor->level[this_level].dirty = 0;
- cursor->level[this_level].bno = dabno;
- cursor->level[this_level].hashval =
- be32_to_cpu(newnode->btree[0].hashval);
-#ifdef XR_DIR_TRACE
- cursor->level[this_level].n = newnode;
-#endif
- node = newnode;
-
- entry = cursor->level[this_level].index = 0;
- }
- /*
- * ditto for block numbers
- */
- if (cursor->level[p_level].bno !=
- be32_to_cpu(node->btree[entry].before)) {
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "bad directory btree pointer, child bno "
- "should be %d, block bno is %d, hashval is %u\n",
- be32_to_cpu(node->btree[entry].before),
- cursor->level[p_level].bno,
- cursor->level[p_level].hashval);
- fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
-#endif
- return(1);
- }
- /*
- * ok, now validate last hashvalue in the descendant
- * block against the hashval in the current entry
- */
- if (cursor->level[p_level].hashval !=
- be32_to_cpu(node->btree[entry].hashval)) {
- if (!no_modify) {
- do_warn(_("correcting bad hashval in interior "
- "dir/attr block\n\tin (level %d) in "
- "inode %" PRIu64 ".\n"),
- this_level, cursor->ino);
- node->btree[entry].hashval = cpu_to_be32(
- cursor->level[p_level].hashval);
- cursor->level[this_level].dirty++;
- } else {
- do_warn(_("would correct bad hashval in interior "
- "dir/attr block\n\tin (level %d) in "
- "inode %" PRIu64 ".\n"),
- this_level, cursor->ino);
- }
- }
- /*
- * increment index for this level to point to next entry
- * (which should point to the next descendant block)
- */
- cursor->level[this_level].index++;
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "verify_da_path returns 0 (ok)\n");
-#endif
- return(0);
-}
-
-/*
- * called by both node dir and leaf dir processing routines
- * validates all contents *but* the sibling pointers (forw/back)
- * and the magic number.
- *
- * returns 0 if the directory is ok or has been brought to the
- * stage that it can be fixed up later (in phase 6),
- * 1 if it has to be junked.
- *
- * Right now we fix a lot of things (TBD == to be deleted).
- *
- * incorrect . entries - inode # is corrected
- * entries with mismatched hashvalue/name strings - hashvalue reset
- * entries whose hashvalues are out-of-order - entry marked TBD
- * .. entries with invalid inode numbers - entry marked TBD
- * entries with invalid inode numbers - entry marked TBD
- * multiple . entries - all but the first entry are marked TBD
- * zero-length entries - entry is deleted
- * entries with an out-of-bounds name index ptr - entry is deleted
- *
- * entries marked TBD have the first character of the name (which
- * lives in the heap) have the first character in the name set
- * to '/' -- an illegal value.
- *
- * entries deleted right here are deleted by blowing away the entry
- * (but leaving the heap untouched). any space that was used
- * by the deleted entry will be reclaimed by the block freespace
- * (da_freemap) processing code.
- *
- * if two entries claim the same space in the heap (say, due to
- * bad entry name index pointers), we lose the directory. We could
- * try harder to fix this but it'll do for now.
- */
-static int
-process_leaf_dir_block(
- xfs_mount_t *mp,
- xfs_dir_leafblock_t *leaf,
- xfs_dablk_t da_bno,
- xfs_ino_t ino,
- xfs_dahash_t last_hashval, /* last hashval encountered */
- int ino_discovery,
- blkmap_t *blkmap,
- int *dot,
- int *dotdot,
- xfs_ino_t *parent,
- int *buf_dirty, /* is buffer dirty? */
- xfs_dahash_t *next_hashval) /* greatest hashval in block */
-{
- xfs_ino_t lino;
- xfs_dir_leaf_entry_t *entry;
- xfs_dir_leaf_entry_t *s_entry;
- xfs_dir_leaf_entry_t *d_entry;
- xfs_dir_leafblock_t *new_leaf;
- char *first_byte;
- xfs_dir_leaf_name_t *namest;
- ino_tree_node_t *irec_p;
- int num_entries;
- xfs_dahash_t hashval;
- int i;
- int nm_illegal;
- int bytes;
- int start;
- int stop;
- int res = 0;
- int ino_off;
- int first_used;
- int bytes_used;
- int reset_holes;
- int zero_len_entries;
- char fname[MAXNAMELEN + 1];
- da_hole_map_t holemap;
- da_hole_map_t bholemap;
- da_freemap_t *dir_freemap;
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "\tprocess_leaf_dir_block - ino %" PRIu64 "\n", ino);
-#endif
-
- /*
- * clear static dir block freespace bitmap
- */
- dir_freemap = alloc_da_freemap(mp);
-
- *buf_dirty = 0;
- first_used = mp->m_sb.sb_blocksize;
- zero_len_entries = 0;
- bytes_used = 0;
-
- i = stop = sizeof(xfs_dir_leaf_hdr_t);
- if (set_da_freemap(mp, dir_freemap, 0, stop)) {
- do_warn(
-_("directory block header conflicts with used space in directory inode %" PRIu64 "\n"),
- ino);
- res = 1;
- goto out;
- }
-
- /*
- * verify structure: monotonically increasing hash value for
- * all leaf entries, indexes for all entries must be within
- * this fs block (trivially true for 64K blocks). also track
- * used space so we can check the freespace map. check for
- * zero-length entries. for now, if anything's wrong, we
- * junk the directory and we'll pick up no-longer referenced
- * inodes on a later pass.
- */
- for (i = 0, entry = &leaf->entries[0];
- i < be16_to_cpu(leaf->hdr.count);
- i++, entry++) {
- /*
- * check that the name index isn't out of bounds
- * if it is, delete the entry since we can't
- * grab the inode #.
- */
- if (be16_to_cpu(entry->nameidx) >=
- mp->m_sb.sb_blocksize) {
- if (!no_modify) {
- *buf_dirty = 1;
-
- if (be16_to_cpu(leaf->hdr.count) > 1) {
- do_warn(
-_("nameidx %d for entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, deleting entry\n"),
- be16_to_cpu(entry->nameidx),
- i, da_bno, ino);
- ASSERT(be16_to_cpu(leaf->hdr.count) > i);
-
- bytes = (be16_to_cpu(leaf->hdr.count) - i) *
- sizeof(xfs_dir_leaf_entry_t);
-
- /*
- * compress table unless we're
- * only dealing with 1 entry
- * (the last one) in which case
- * just zero it.
- */
- if (bytes >
- sizeof(xfs_dir_leaf_entry_t)) {
- memmove(entry, entry + 1,
- bytes);
- memset((void *)
- ((__psint_t) entry + bytes), 0,
- sizeof(xfs_dir_leaf_entry_t));
- } else {
- memset(entry, 0,
- sizeof(xfs_dir_leaf_entry_t));
- }
-
- /*
- * sync vars to match smaller table.
- * don't have to worry about freespace
- * map since we haven't set it for
- * this entry yet.
- */
- be16_add_cpu(&leaf->hdr.count, -1);
- i--;
- entry--;
- } else {
- do_warn(
-_("nameidx %d, entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, marking entry bad\n"),
- be16_to_cpu(entry->nameidx),
- i, da_bno, ino);
- entry->nameidx = cpu_to_be16(
- mp->m_sb.sb_blocksize -
- sizeof(xfs_dir_leaf_name_t));
- namest = xfs_dir_leaf_namestruct(leaf,
- be16_to_cpu(entry->nameidx));
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino,
- &namest->inumber);
- namest->name[0] = '/';
- }
- } else {
- do_warn(
-_("nameidx %d, entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, would delete entry\n"),
- be16_to_cpu(entry->nameidx),
- i, da_bno, ino);
- }
- continue;
- }
- /*
- * inode processing -- make sure the inode
- * is in our tree or we add it to the uncertain
- * list if the inode # is valid. if namelen is 0,
- * we can still try for the inode as long as nameidx
- * is ok.
- */
- namest = xfs_dir_leaf_namestruct(leaf,
- be16_to_cpu(entry->nameidx));
- xfs_dir_sf_get_dirino(&namest->inumber, &lino);
-
- /*
- * we may have to blow out an entry because of bad
- * inode numbers. do NOT touch the name until after
- * we've computed the hashvalue and done a namecheck()
- * on the name.
- */
- if (!ino_discovery && lino == NULLFSINO) {
- /*
- * don't do a damned thing. We already
- * found this (or did it ourselves) during
- * phase 3.
- */
- } else if (verify_inum(mp, lino)) {
- /*
- * bad inode number. clear the inode
- * number and the entry will get removed
- * later. We don't trash the directory
- * since it's still structurally intact.
- */
- do_warn(
-_("invalid ino number %" PRIu64 " in dir ino %" PRIu64 ", entry #%d, bno %d\n"),
- lino, ino, i, da_bno);
- if (!no_modify) {
- do_warn(
- _("\tclearing ino number in entry %d...\n"),
- i);
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\twould clear ino number in entry %d...\n"),
- i);
- }
- } else if (lino == mp->m_sb.sb_rbmino) {
- do_warn(
-_("entry #%d, bno %d in directory %" PRIu64 " references realtime bitmap inode %" PRIu64 "\n"),
- i, da_bno, ino, lino);
- if (!no_modify) {
- do_warn(
- _("\tclearing ino number in entry %d...\n"),
- i);
-
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\twould clear ino number in entry %d...\n"),
- i);
- }
- } else if (lino == mp->m_sb.sb_rsumino) {
- do_warn(
-_("entry #%d, bno %d in directory %" PRIu64 " references realtime summary inode %" PRIu64 "\n"),
- i, da_bno, ino, lino);
- if (!no_modify) {
- do_warn(
- _("\tclearing ino number in entry %d...\n"), i);
-
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\twould clear ino number in entry %d...\n"),
- i);
- }
- } else if (lino == mp->m_sb.sb_uquotino) {
- do_warn(
-_("entry #%d, bno %d in directory %" PRIu64 " references user quota inode %" PRIu64 "\n"),
- i, da_bno, ino, lino);
- if (!no_modify) {
- do_warn(
- _("\tclearing ino number in entry %d...\n"),
- i);
-
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\twould clear ino number in entry %d...\n"),
- i);
- }
- } else if (lino == mp->m_sb.sb_gquotino) {
- do_warn(
-_("entry #%d, bno %d in directory %" PRIu64 " references group quota inode %" PRIu64 "\n"),
- i, da_bno, ino, lino);
- if (!no_modify) {
- do_warn(
- _("\tclearing ino number in entry %d...\n"),
- i);
-
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\twould clear ino number in entry %d...\n"),
- i);
- }
- } else if ((irec_p = find_inode_rec(mp,
- XFS_INO_TO_AGNO(mp, lino),
- XFS_INO_TO_AGINO(mp, lino))) != NULL) {
- /*
- * inode recs should have only confirmed
- * inodes in them
- */
- ino_off = XFS_INO_TO_AGINO(mp, lino) -
- irec_p->ino_startnum;
- ASSERT(is_inode_confirmed(irec_p, ino_off));
- /*
- * if inode is marked free and we're in inode
- * discovery mode, leave the entry alone for now.
- * if the inode turns out to be used, we'll figure
- * that out when we scan it. If the inode really
- * is free, we'll hit this code again in phase 4
- * after we've finished inode discovery and blow
- * out the entry then.
- */
- if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
- if (!no_modify) {
- do_warn(
-_("entry references free inode %" PRIu64 " in directory %" PRIu64 ", will clear entry\n"),
- lino, ino);
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino,
- &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
-_("entry references free inode %" PRIu64 " in directory %" PRIu64 ", would clear entry\n"),
- lino, ino);
- }
- }
- } else if (ino_discovery) {
- add_inode_uncertain(mp, lino, 0);
- } else {
- do_warn(
- _("bad ino number %" PRIu64 " in dir ino %" PRIu64 ", entry #%d, bno %d\n"),
- lino, ino, i, da_bno);
- if (!no_modify) {
- do_warn(_("clearing inode number...\n"));
- lino = NULLFSINO;
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(_("would clear inode number...\n"));
- }
- }
- /*
- * if we have a zero-length entry, trash it.
- * we may lose the inode (chunk) if we don't
- * finish the repair successfully and the inode
- * isn't mentioned anywhere else (like in the inode
- * tree) but the alternative is to risk losing the
- * entire directory by trying to use the next byte
- * to turn the entry into a 1-char entry. That's
- * probably a safe bet but if it didn't work, we'd
- * lose the entire directory the way we currently do
- * things. (Maybe we should change that later :-).
- */
- if (entry->namelen == 0) {
- *buf_dirty = 1;
-
- if (be16_to_cpu(leaf->hdr.count) > 1) {
- do_warn(
- _("entry #%d, dir inode %" PRIu64 ", has zero-len name, deleting entry\n"),
- i, ino);
- ASSERT(be16_to_cpu(leaf->hdr.count) > i);
-
- bytes = (be16_to_cpu(leaf->hdr.count) - i) *
- sizeof(xfs_dir_leaf_entry_t);
-
- /*
- * compress table unless we're
- * only dealing with 1 entry
- * (the last one) in which case
- * just zero it.
- */
- if (bytes > sizeof(xfs_dir_leaf_entry_t)) {
- memmove(entry, entry + 1, bytes);
- memset((void *)((__psint_t) entry +
- bytes), 0,
- sizeof(xfs_dir_leaf_entry_t));
- } else {
- memset(entry, 0,
- sizeof(xfs_dir_leaf_entry_t));
- }
-
- /*
- * sync vars to match smaller table.
- * don't have to worry about freespace
- * map since we haven't set it for
- * this entry yet.
- */
- be16_add_cpu(&leaf->hdr.count, -1);
- i--;
- entry--;
- } else {
- /*
- * if it's the only entry, preserve the
- * inode number for now
- */
- do_warn(
- _("entry #%d, dir inode %" PRIu64 ", has zero-len name, marking entry bad\n"),
- i, ino);
- entry->nameidx = cpu_to_be16(
- mp->m_sb.sb_blocksize -
- sizeof(xfs_dir_leaf_name_t));
- namest = xfs_dir_leaf_namestruct(leaf,
- be16_to_cpu(entry->nameidx));
- xfs_dir_sf_put_dirino(&lino, &namest->inumber);
- namest->name[0] = '/';
- }
- } else if (be16_to_cpu(entry->nameidx) + entry->namelen >
- XFS_LBSIZE(mp)) {
- do_warn(
-_("bad size, entry #%d in dir inode %" PRIu64 ", block %u -- entry overflows block\n"),
- i, ino, da_bno);
- res = 1;
- goto out;
- }
-
- start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;;
- stop = start + sizeof(xfs_dir_leaf_entry_t);
-
- if (set_da_freemap(mp, dir_freemap, start, stop)) {
- do_warn(
-_("dir entry slot %d in block %u conflicts with used space in dir inode %" PRIu64 "\n"),
- i, da_bno, ino);
- res = 1;
- goto out;
- }
-
- /*
- * check if the name is legal. if so, then
- * check that the name and hashvalues match.
- *
- * if the name is illegal, we don't check the
- * hashvalue computed from it. we just make
- * sure that the hashvalue in the entry is
- * monotonically increasing wrt to the previous
- * entry.
- *
- * Note that we do NOT have to check the length
- * because the length is stored in a one-byte
- * unsigned int which max's out at MAXNAMELEN
- * making it impossible for the stored length
- * value to be out of range.
- */
- memmove(fname, namest->name, entry->namelen);
- fname[entry->namelen] = '\0';
- hashval = libxfs_da_hashname((uchar_t *) fname, entry->namelen);
-
- /*
- * only complain about illegal names in phase 3 (when
- * inode discovery is turned on). Otherwise, we'd complain
- * a lot during phase 4. If the name is illegal, leave
- * the hash value in that entry alone.
- */
- nm_illegal = namecheck(fname, entry->namelen);
-
- if (ino_discovery && nm_illegal) {
- /*
- * junk the entry, illegal name
- */
- if (!no_modify) {
- do_warn(
-_("illegal name \"%s\" in directory inode %" PRIu64 ", entry will be cleared\n"),
- fname, ino);
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(
-_("illegal name \"%s\" in directory inode %" PRIu64 ", entry would be cleared\n"),
- fname, ino);
- }
- } else if (!nm_illegal &&
- be32_to_cpu(entry->hashval) != hashval) {
- /*
- * try resetting the hashvalue to the correct
- * value for the string, if the string has been
- * corrupted, too, that will get picked up next
- */
- do_warn(_("\tmismatched hash value for entry \"%s\"\n"),
- fname);
- if (!no_modify) {
- do_warn(
- _("\t\tin directory inode %" PRIu64 ". resetting hash value.\n"),
- ino);
- entry->hashval = cpu_to_be32(hashval);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\t\tin directory inode %" PRIu64 ". would reset hash value.\n"),
- ino);
- }
- }
-
- /*
- * now we can mark entries with NULLFSINO's bad
- */
- if (!no_modify && lino == NULLFSINO) {
- namest->name[0] = '/';
- *buf_dirty = 1;
- }
-
- /*
- * regardless of whether the entry has or hasn't been
- * marked for deletion, the hash value ordering must
- * be maintained.
- */
- if (be32_to_cpu(entry->hashval) < last_hashval) {
- /*
- * blow out the entry -- set hashval to sane value
- * and set the first character in the string to
- * the illegal value '/'. Reset the hash value
- * to the last hashvalue so that verify_da_path
- * will fix up the interior pointers correctly.
- * the entry will be deleted later (by routines
- * that need only the entry #). We keep the
- * inode number in the entry so we can attach
- * the inode to the orphanage later.
- */
- do_warn(_("\tbad hash ordering for entry \"%s\"\n"),
- fname);
- if (!no_modify) {
- do_warn(
- _("\t\tin directory inode %" PRIu64 ". will clear entry\n"),
- ino);
- entry->hashval = cpu_to_be32(last_hashval);
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(
- _("\t\tin directory inode %" PRIu64 ". would clear entry\n"),
- ino);
- }
- }
-
- *next_hashval = last_hashval = be32_to_cpu(entry->hashval);
-
- /*
- * if heap data conflicts with something,
- * blow it out and skip the rest of the loop
- */
- if (set_da_freemap(mp, dir_freemap, be16_to_cpu(entry->nameidx),
- be16_to_cpu(entry->nameidx)
- + sizeof(xfs_dir_leaf_name_t)
- + entry->namelen - 1)) {
- do_warn(
-_("name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %" PRIu64 "\n"),
- fname, da_bno, i, ino);
- if (!no_modify) {
- entry->namelen = 0;
- *buf_dirty = 1;
-
- do_warn(
- _("will clear entry \"%s\" (#%d) in directory inode %" PRIu64 "\n"),
- fname, i, ino);
- } else {
- do_warn(
- _("would clear entry \"%s\" (#%d)in directory inode %" PRIu64 "\n"),
- fname, i, ino);
- }
- continue;
- }
-
- /*
- * keep track of heap stats (first byte used, total bytes used)
- */
- if (be16_to_cpu(entry->nameidx) < first_used)
- first_used = be16_to_cpu(entry->nameidx);
- bytes_used += entry->namelen;
-
- /*
- * special . or .. entry processing
- */
- if (entry->namelen == 2 && namest->name[0] == '.' &&
- namest->name[1] == '.') {
- /*
- * the '..' case
- */
- if (!*dotdot) {
- (*dotdot)++;
- *parent = lino;
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_leaf_dir_block found .. entry (parent) = %" PRIu64 "\n", lino);
-#endif
- /*
- * what if .. == .? legal only in
- * the root inode. blow out entry
- * and set parent to NULLFSINO otherwise.
- */
- if (ino == lino &&
- ino != mp->m_sb.sb_rootino) {
- *parent = NULLFSINO;
- do_warn(
- _("bad .. entry in dir ino %" PRIu64 ", points to self"),
- ino);
- if (!no_modify) {
- do_warn(
- _("will clear entry\n"));
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(
- _("would clear entry\n"));
- }
- } else if (ino != lino &&
- ino == mp->m_sb.sb_rootino) {
- /*
- * we have to make sure that . == ..
- * in the root inode
- */
- if (!no_modify) {
- do_warn(
- _("correcting .. entry in root inode %" PRIu64 ", was %" PRIu64 "\n"),
- ino, *parent);
- xfs_dir_sf_put_dirino(
- &ino, &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
- _("bad .. entry (%" PRIu64 ") in root inode %" PRIu64 " should be %" PRIu64 "\n"),
- *parent,
- ino, ino);
- }
- }
- } else {
- /*
- * can't fix the directory unless we know
- * which .. entry is the right one. Both
- * have valid inode numbers, match the hash
- * value and the hash values are ordered
- * properly or we wouldn't be here. So
- * since both seem equally valid, trash
- * this one.
- */
- if (!no_modify) {
- do_warn(
-_("multiple .. entries in directory inode %" PRIu64 ", will clear second entry\n"),
- ino);
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(
-_("multiple .. entries in directory inode %" PRIu64 ", would clear second entry\n"),
- ino);
- }
- }
- } else if (entry->namelen == 1 && namest->name[0] == '.') {
- /*
- * the '.' case
- */
- if (!*dot) {
- (*dot)++;
- if (lino != ino) {
- if (!no_modify) {
- do_warn(
-_(". in directory inode %" PRIu64 " has wrong value (%" PRIu64 "), fixing entry...\n"),
- ino, lino);
- xfs_dir_sf_put_dirino(&ino,
- &namest->inumber);
- *buf_dirty = 1;
- } else {
- do_warn(
-_(". in directory inode %" PRIu64 " has wrong value (%" PRIu64 ")\n"),
- ino, lino);
- }
- }
- } else {
- do_warn(
-_("multiple . entries in directory inode %" PRIu64 "\n"),
- ino);
- /*
- * mark entry as to be junked.
- */
- if (!no_modify) {
- do_warn(
-_("will clear one . entry in directory inode %" PRIu64 "\n"),
- ino);
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(
-_("would clear one . entry in directory inode %" PRIu64 "\n"),
- ino);
- }
- }
- } else {
- /*
- * all the rest -- make sure only . references self
- */
- if (lino == ino) {
- do_warn(
- _("entry \"%s\" in directory inode %" PRIu64 " points to self, "),
- fname, ino);
- if (!no_modify) {
- do_warn(_("will clear entry\n"));
- namest->name[0] = '/';
- *buf_dirty = 1;
- } else {
- do_warn(_("would clear entry\n"));
- }
- }
- }
- }
-
- /*
- * compare top of heap values and reset as required. if the
- * holes flag is set, don't reset first_used unless it's
- * pointing to used bytes. we're being conservative here
- * since the block will get compacted anyhow by the kernel.
- */
- if ((leaf->hdr.holes == 0 &&
- first_used != be16_to_cpu(leaf->hdr.firstused)) ||
- be16_to_cpu(leaf->hdr.firstused) > first_used) {
- if (!no_modify) {
- if (verbose)
- do_warn(
-_("- resetting first used heap value from %d to %d in block %u of dir ino %" PRIu64 "\n"),
- be16_to_cpu(leaf->hdr.firstused),
- first_used, da_bno, ino);
- leaf->hdr.firstused = cpu_to_be16(first_used);
- *buf_dirty = 1;
- } else {
- if (verbose)
- do_warn(
-_("- would reset first used value from %d to %d in block %u of dir ino %" PRIu64 "\n"),
- be16_to_cpu(leaf->hdr.firstused),
- first_used, da_bno, ino);
- }
- }
-
- if (bytes_used != be16_to_cpu(leaf->hdr.namebytes)) {
- if (!no_modify) {
- if (verbose)
- do_warn(
-_("- resetting namebytes cnt from %d to %d in block %u of dir inode %" PRIu64 "\n"),
- be16_to_cpu(leaf->hdr.namebytes),
- bytes_used, da_bno, ino);
- leaf->hdr.namebytes = cpu_to_be16(bytes_used);
- *buf_dirty = 1;
- } else {
- if (verbose)
- do_warn(
-_("- would reset namebytes cnt from %d to %d in block %u of dir inode %" PRIu64 "\n"),
- be16_to_cpu(leaf->hdr.namebytes),
- bytes_used, da_bno, ino);
- }
- }
-
- /*
- * If the hole flag is not set, then we know that there can
- * be no lost holes. If the hole flag is set, then it's ok
- * if the on-disk holemap doesn't describe everything as long
- * as what it does describe doesn't conflict with reality.
- */
-
- reset_holes = 0;
-
- bholemap.lost_holes = leaf->hdr.holes;
- for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
- bholemap.hentries[i].base = be16_to_cpu(leaf->hdr.freemap[i].base);
- bholemap.hentries[i].size = be16_to_cpu(leaf->hdr.freemap[i].size);
- }
-
- /*
- * Ok, now set up our own freespace list
- * (XFS_DIR_LEAF_MAPSIZE (3) * biggest regions)
- * and see if they match what's in the block
- */
- memset(&holemap, 0, sizeof(da_hole_map_t));
- process_da_freemap(mp, dir_freemap, &holemap);
-
- if (zero_len_entries) {
- reset_holes = 1;
- } else if (leaf->hdr.holes == 0) {
- if (holemap.lost_holes > 0) {
- if (verbose)
- do_warn(
- _("- found unexpected lost holes in block %u, dir inode %" PRIu64 "\n"),
- da_bno, ino);
-
- reset_holes = 1;
- } else if (compare_da_freemaps(mp, &holemap, &bholemap,
- XFS_DIR_LEAF_MAPSIZE, ino, da_bno)) {
- if (verbose)
- do_warn(
- _("- hole info non-optimal in block %u, dir inode %" PRIu64 "\n"),
- da_bno, ino);
- reset_holes = 1;
- }
- } else if (verify_da_freemap(mp, dir_freemap, &holemap, ino, da_bno)) {
- if (verbose)
- do_warn(
- _("- hole info incorrect in block %u, dir inode %" PRIu64 "\n"),
- da_bno, ino);
- reset_holes = 1;
- }
-
- if (reset_holes) {
- /*
- * have to reset block hole info
- */
- if (verbose) {
- do_warn(
-_("- existing hole info for block %d, dir inode %" PRIu64 " (base, size) - \n"),
- da_bno, ino);
- do_warn("- \t");
- for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
- do_warn(
- "- (%d, %d) ", bholemap.hentries[i].base,
- bholemap.hentries[i].size);
- }
- do_warn(_("- holes flag = %d\n"), bholemap.lost_holes);
- }
-
- if (!no_modify) {
- if (verbose)
- do_warn(
- _("- compacting block %u in dir inode %" PRIu64 "\n"),
- da_bno, ino);
-
- new_leaf = malloc(mp->m_sb.sb_blocksize);
-
- /*
- * copy leaf block header
- */
- memmove(&new_leaf->hdr, &leaf->hdr,
- sizeof(xfs_dir_leaf_hdr_t));
-
- /*
- * reset count in case we have some zero length entries
- * that are being junked
- */
- num_entries = 0;
- first_used = XFS_LBSIZE(mp);
- first_byte = (char *) new_leaf
- + (__psint_t) XFS_LBSIZE(mp);
-
- /*
- * copy entry table and pack names starting from the end
- * of the block
- */
- for (i = 0, s_entry = &leaf->entries[0],
- d_entry = &new_leaf->entries[0];
- i < be16_to_cpu(leaf->hdr.count);
- i++, s_entry++) {
- /*
- * skip zero-length entries
- */
- if (s_entry->namelen == 0)
- continue;
-
- bytes = sizeof(xfs_dir_leaf_name_t)
- + s_entry->namelen - 1;
-
- if ((__psint_t) first_byte - bytes <
- sizeof(xfs_dir_leaf_entry_t)
- + (__psint_t) d_entry) {
- do_warn(
- _("not enough space in block %u of dir inode %" PRIu64 " for all entries\n"),
- da_bno, ino);
- free(new_leaf);
- break;
- }
-
- first_used -= bytes;
- first_byte -= bytes;
-
- d_entry->nameidx = cpu_to_be16(first_used);
- d_entry->hashval = s_entry->hashval;
- d_entry->namelen = s_entry->namelen;
- d_entry->pad2 = 0;
-
- memmove(first_byte, (char *)leaf +
- be16_to_cpu(s_entry->nameidx), bytes);
-
- num_entries++;
- d_entry++;
- }
-
- ASSERT((char *) first_byte >= (char *) d_entry);
- ASSERT(first_used <= XFS_LBSIZE(mp));
-
- /*
- * zero space between end of table and top of heap
- */
- memset(d_entry, 0, (__psint_t) first_byte
- - (__psint_t) d_entry);
-
- /*
- * reset header info
- */
- if (num_entries != be16_to_cpu(new_leaf->hdr.count))
- new_leaf->hdr.count = cpu_to_be16(num_entries);
-
- new_leaf->hdr.firstused = cpu_to_be16(first_used);
- new_leaf->hdr.holes = 0;
- new_leaf->hdr.pad1 = 0;
-
- new_leaf->hdr.freemap[0].base = cpu_to_be16(
- (__psint_t) d_entry - (__psint_t) new_leaf);
- new_leaf->hdr.freemap[0].size = cpu_to_be16(
- (__psint_t) first_byte - (__psint_t) d_entry);
-
- ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < first_used);
- ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) ==
- (__psint_t) (&new_leaf->entries[0])
- - (__psint_t) new_leaf
- + i * sizeof(xfs_dir_leaf_entry_t));
- ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < XFS_LBSIZE(mp));
- ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].size) < XFS_LBSIZE(mp));
- ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) +
- be16_to_cpu(new_leaf->hdr.freemap[0].size) == first_used);
-
- new_leaf->hdr.freemap[1].base = 0;
- new_leaf->hdr.freemap[1].size = 0;
- new_leaf->hdr.freemap[2].base = 0;
- new_leaf->hdr.freemap[2].size = 0;
-
- /*
- * final step, copy block back
- */
- memmove(leaf, new_leaf, mp->m_sb.sb_blocksize);
- free(new_leaf);
-
- *buf_dirty = 1;
- } else {
- if (verbose)
- do_warn(
- _("- would compact block %u in dir inode %" PRIu64 "\n"),
- da_bno, ino);
- }
- }
-#if 0
- if (!no_modify) {
- /*
- * now take care of deleting or marking the entries with
- * zero-length namelen's
- */
- junk_zerolen_dir_leaf_entries(mp, leaf, ino, buf_dirty);
- }
-#endif
-
-out:
- free(dir_freemap);
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_leaf_dir_block returns %d\n", res);
-#endif
- return res > 0 ? 1 : 0;
-}
-
-/*
- * returns 0 if the directory is ok, 1 if it has to be junked.
- */
-static int
-process_leaf_dir_level(xfs_mount_t *mp,
- da_bt_cursor_t *da_cursor,
- int ino_discovery,
- int *repair,
- int *dot,
- int *dotdot,
- xfs_ino_t *parent)
-{
- xfs_dir_leafblock_t *leaf;
- xfs_buf_t *bp;
- xfs_ino_t ino;
- xfs_dfsbno_t dev_bno;
- xfs_dablk_t da_bno;
- xfs_dablk_t prev_bno;
- int res = 0;
- int buf_dirty = 0;
- xfs_daddr_t bd_addr;
- xfs_dahash_t current_hashval = 0;
- xfs_dahash_t greatest_hashval;
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_leaf_dir_level - ino %" PRIu64 "\n", da_cursor->ino);
-#endif
- *repair = 0;
- da_bno = da_cursor->level[0].bno;
- ino = da_cursor->ino;
- prev_bno = 0;
-
- do {
- dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
- /*
- * directory code uses 0 as the NULL block pointer
- * since 0 is the root block and no directory block
- * pointer can point to the root block of the btree
- */
- ASSERT(da_bno != 0);
-
- if (dev_bno == NULLDFSBNO) {
- do_warn(
- _("can't map block %u for directory inode %" PRIu64 "\n"),
- da_bno, ino);
- goto error_out;
- }
-
- bd_addr = (xfs_daddr_t)XFS_FSB_TO_DADDR(mp, dev_bno);
-
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
- XFS_FSB_TO_BB(mp, 1), 0);
- if (!bp) {
- do_warn(
- _("can't read file block %u (fsbno %" PRIu64 ", daddr %" PRId64 ") "
- "for directory inode %" PRIu64 "\n"),
- da_bno, dev_bno, bd_addr, ino);
- goto error_out;
- }
-
- leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
-
- /*
- * check magic number for leaf directory btree block
- */
- if (XFS_DIR_LEAF_MAGIC !=
- be16_to_cpu(leaf->hdr.info.magic)) {
- do_warn(
- _("bad directory leaf magic # %#x for dir ino %" PRIu64"\n"),
- be16_to_cpu(leaf->hdr.info.magic),
- ino);
- libxfs_putbuf(bp);
- goto error_out;
- }
- /*
- * keep track of greatest block # -- that gets
- * us the length of the directory
- */
- if (da_bno > da_cursor->greatest_bno)
- da_cursor->greatest_bno = da_bno;
-
- buf_dirty = 0;
- /*
- * for each block, process the block, verify its path,
- * then get next block. update cursor values along the way
- */
- if (process_leaf_dir_block(mp, leaf, da_bno, ino,
- current_hashval, ino_discovery,
- da_cursor->blkmap, dot, dotdot, parent,
- &buf_dirty, &greatest_hashval)) {
- libxfs_putbuf(bp);
- goto error_out;
- }
-
- /*
- * index can be set to hdr.count so match the
- * indexes of the interior blocks -- which at the
- * end of the block will point to 1 after the final
- * real entry in the block
- */
- da_cursor->level[0].hashval = greatest_hashval;
- da_cursor->level[0].bp = bp;
- da_cursor->level[0].bno = da_bno;
- da_cursor->level[0].index = be16_to_cpu(leaf->hdr.count);
- da_cursor->level[0].dirty = buf_dirty;
-
- if (be32_to_cpu(leaf->hdr.info.back) != prev_bno) {
- do_warn(
- _("bad sibling back pointer for directory block %u in directory inode %" PRIu64 "\n"),
- da_bno, ino);
- libxfs_putbuf(bp);
- goto error_out;
- }
-
- prev_bno = da_bno;
- da_bno = be32_to_cpu(leaf->hdr.info.forw);
-
- if (da_bno != 0)
- if (verify_da_path(mp, da_cursor, 0)) {
- libxfs_putbuf(bp);
- goto error_out;
- }
-
- current_hashval = greatest_hashval;
-
- ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
-
- if (buf_dirty && !no_modify) {
- *repair = 1;
- libxfs_writebuf(bp, 0);
- }
- else
- libxfs_putbuf(bp);
- } while (da_bno != 0 && res == 0);
-
- if (verify_final_da_path(mp, da_cursor, 0)) {
- /*
- * verify the final path up (right-hand-side) if still ok
- */
- do_warn(_("bad hash path in directory %" PRIu64 "\n"), da_cursor->ino);
- goto error_out;
- }
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_leaf_dir_level returns %d (%s)\n",
- res, ((res) ? "bad" : "ok"));
-#endif
- /*
- * redundant but just for testing
- */
- release_da_cursor(mp, da_cursor, 0);
-
- return(res);
-
-error_out:
- /*
- * release all buffers holding interior btree blocks
- */
- err_release_da_cursor(mp, da_cursor, 0);
-
- return(1);
-}
-
-/*
- * a node directory is a true btree directory -- where the directory
- * has gotten big enough that it is represented as a non-trivial (e.g.
- * has more than just a root block) btree.
- *
- * Note that if we run into any problems, we trash the
- * directory. Even if it's the root directory,
- * we'll be able to traverse all the disconnected
- * subtrees later (phase 6).
- *
- * one day, if we actually fix things, we'll set repair to 1 to
- * indicate that we have or that we should.
- *
- * dirname can be set to NULL if the name is unknown (or to
- * the string representation of the inode)
- *
- * returns 0 if things are ok, 1 if bad (directory needs to be junked)
- */
-static int
-process_node_dir(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- blkmap_t *blkmap,
- int *dot,
- int *dotdot,
- xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */
- char *dirname,
- int *repair)
-{
- xfs_dablk_t bno;
- int error = 0;
- da_bt_cursor_t da_cursor;
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_node_dir - ino %" PRIu64 "\n", ino);
-#endif
- *repair = *dot = *dotdot = 0;
- *parent = NULLFSINO;
-
- /*
- * try again -- traverse down left-side of tree until we hit
- * the left-most leaf block setting up the btree cursor along
- * the way. Then walk the leaf blocks left-to-right, calling
- * a parent-verification routine each time we traverse a block.
- */
- memset(&da_cursor, 0, sizeof(da_bt_cursor_t));
-
- da_cursor.active = 0;
- da_cursor.type = 0;
- da_cursor.ino = ino;
- da_cursor.dip = dip;
- da_cursor.greatest_bno = 0;
- da_cursor.blkmap = blkmap;
-
- /*
- * now process interior node
- */
-
- error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK);
-
- if (error == 0)
- return(1);
-
- /*
- * now pass cursor and bno into leaf-block processing routine
- * the leaf dir level routine checks the interior paths
- * up to the root including the final right-most path.
- */
-
- error = process_leaf_dir_level(mp, &da_cursor, ino_discovery,
- repair, dot, dotdot, parent);
-
- if (error)
- return(1);
-
- /*
- * sanity check inode size
- */
- if (be64_to_cpu(dip->di_size) <
- (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize) {
- if ((xfs_fsize_t) da_cursor.greatest_bno
- * mp->m_sb.sb_blocksize > UINT_MAX) {
- do_warn(
-_("out of range internal directory block numbers (inode %" PRIu64 ")\n"),
- ino);
- return(1);
- }
-
- do_warn(
-_("setting directory inode (%" PRIu64 ") size to %" PRIu64 " bytes, was %" PRId64 " bytes\n"),
- ino, (xfs_dfiloff_t) (da_cursor.greatest_bno + 1)
- * mp->m_sb.sb_blocksize,
- (__int64_t)be64_to_cpu(dip->di_size));
-
- dip->di_size = cpu_to_be64((da_cursor.greatest_bno + 1)
- * mp->m_sb.sb_blocksize);
- }
- return(0);
-}
-
-/*
- * a leaf directory is one where the directory is too big for
- * the inode data fork but is small enough to fit into one
- * directory btree block (filesystem block) outside the inode
- *
- * returns NULLFSINO if the directory is cannot be salvaged
- * and the .. ino if things are ok (even if the directory had
- * to be altered to make it ok).
- *
- * dirname can be set to NULL if the name is unknown (or to
- * the string representation of the inode)
- *
- * returns 0 if things are ok, 1 if bad (directory needs to be junked)
- */
-static int
-process_leaf_dir(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dino_dirty,
- blkmap_t *blkmap,
- int *dot, /* out - 1 if there is a dot, else 0 */
- int *dotdot, /* out - 1 if there's a dotdot, else 0 */
- xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */
- char *dirname, /* in - directory pathname */
- int *repair) /* out - 1 if something was fixed */
-{
- xfs_dir_leafblock_t *leaf;
- xfs_dahash_t next_hashval;
- xfs_dfsbno_t bno;
- xfs_buf_t *bp;
- int buf_dirty = 0;
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "process_leaf_dir - ino %" PRIu64 "\n", ino);
-#endif
- *repair = *dot = *dotdot = 0;
- *parent = NULLFSINO;
-
- bno = blkmap_get(blkmap, 0);
- if (bno == NULLDFSBNO) {
- do_warn(_("block 0 for directory inode %" PRIu64 " is missing\n"),
- ino);
- return(1);
- }
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
- XFS_FSB_TO_BB(mp, 1), 0);
- if (!bp) {
- do_warn(_("can't read block 0 for directory inode %" PRIu64 "\n"),
- ino);
- return(1);
- }
- /*
- * verify leaf block
- */
- leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
-
- /*
- * check magic number for leaf directory btree block
- */
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
- do_warn(_("bad directory leaf magic # %#x for dir ino %" PRIu64 "\n"),
- be16_to_cpu(leaf->hdr.info.magic), ino);
- libxfs_putbuf(bp);
- return(1);
- }
-
- if (process_leaf_dir_block(mp, leaf, 0, ino, 0, ino_discovery, blkmap,
- dot, dotdot, parent, &buf_dirty, &next_hashval)) {
- /*
- * the block is bad. lose the directory.
- * XXX - later, we should try and just lose
- * the block without losing the entire directory
- */
- ASSERT(*dotdot == 0 || (*dotdot == 1 && *parent != NULLFSINO));
- libxfs_putbuf(bp);
- return(1);
- }
-
- /*
- * check sibling pointers in leaf block (above doesn't do it)
- */
- if (leaf->hdr.info.forw || leaf->hdr.info.back) {
- if (!no_modify) {
- do_warn(_("clearing forw/back pointers for "
- "directory inode %" PRIu64 "\n"), ino);
- buf_dirty = 1;
- leaf->hdr.info.forw = 0;
- leaf->hdr.info.back = 0;
- } else {
- do_warn(_("would clear forw/back pointers for "
- "directory inode %" PRIu64 "\n"), ino);
- }
- }
-
- ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
-
- if (buf_dirty && !no_modify)
- libxfs_writebuf(bp, 0);
- else
- libxfs_putbuf(bp);
-
- return(0);
-}
-
-/*
- * returns 1 if things are bad (directory needs to be junked)
- * and 0 if things are ok. If ino_discovery is 1, add unknown
- * inodes to uncertain inode list.
- */
-int
-process_dir(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dino_dirty,
- char *dirname,
- xfs_ino_t *parent,
- blkmap_t *blkmap)
-{
- int dot;
- int dotdot;
- int repair = 0;
- int res = 0;
-
- *parent = NULLFSINO;
- dot = dotdot = 0;
-
- /*
- * branch off depending on the type of inode. This routine
- * is only called ONCE so all the subordinate routines will
- * fix '.' and junk '..' if they're bogus.
- */
- if (be64_to_cpu(dip->di_size) <= XFS_DFORK_DSIZE(dip, mp)) {
- dot = 1;
- dotdot = 1;
- if (process_shortform_dir(mp, ino, dip, ino_discovery,
- dino_dirty, parent, dirname, &repair))
- res = 1;
- } else if (be64_to_cpu(dip->di_size) <= XFS_LBSIZE(mp)) {
- if (process_leaf_dir(mp, ino, dip, ino_discovery,
- dino_dirty, blkmap, &dot, &dotdot,
- parent, dirname, &repair))
- res = 1;
- } else {
- if (process_node_dir(mp, ino, dip, ino_discovery,
- blkmap, &dot, &dotdot,
- parent, dirname, &repair))
- res = 1;
- }
- /*
- * bad . entries in all directories will be fixed up in phase 6
- */
- if (dot == 0)
- do_warn(_("no . entry for directory %" PRIu64 "\n"), ino);
-
- /*
- * shortform dirs always have a .. entry. .. for all longform
- * directories will get fixed in phase 6. .. for other shortform
- * dirs also get fixed there. .. for a shortform root was
- * fixed in place since we know what it should be
- */
- if (dotdot == 0 && ino != mp->m_sb.sb_rootino) {
- do_warn(_("no .. entry for directory %" PRIu64 "\n"), ino);
- } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) {
- do_warn(_("no .. entry for root directory %" PRIu64 "\n"), ino);
- need_root_dotdot = 1;
- }
-
-#ifdef XR_DIR_TRACE
- fprintf(stderr, "(process_dir), parent of %" PRIu64 " is %" PRIu64 "\n", ino, parent);
-#endif
- return(res);
-}
+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _XR_DIR_H
-#define _XR_DIR_H
-
-struct blkmap;
-
-typedef unsigned char da_freemap_t;
-
-/*
- * the cursor gets passed up and down the da btree processing
- * routines. The interior block processing routines use the
- * cursor to determine if the pointers to and from the preceding
- * and succeeding sibling blocks are ok and whether the values in
- * the current block are consistent with the entries in the parent
- * nodes. When a block is traversed, a parent-verification routine
- * is called to verify if the next logical entry in the next level up
- * is consistent with the greatest hashval in the next block of the
- * current level. The verification routine is itself recursive and
- * calls itself if it has to traverse an interior block to get
- * the next logical entry. The routine recurses upwards through
- * the tree until it finds a block where it can simply step to
- * the next entry. The hashval in that entry should be equal to
- * the hashval being passed to it (the greatest hashval in the block
- * that the entry points to). If that isn't true, then the tree
- * is blown and we need to trash it, salvage and trash it, or fix it.
- * Currently, we just trash it.
- */
-typedef struct da_level_state {
- xfs_buf_t *bp; /* block bp */
-#ifdef XR_DIR_TRACE
- xfs_da_intnode_t *n; /* bp data */
-#endif
- xfs_dablk_t bno; /* file block number */
- xfs_dahash_t hashval; /* last verified hashval */
- int index; /* current index in block */
- int dirty; /* is buffer dirty ? (1 == yes) */
-} da_level_state_t;
-
-typedef struct da_bt_cursor {
- int active; /* highest level in tree (# levels-1) */
- int type; /* 0 if dir, 1 if attr */
- xfs_ino_t ino;
- xfs_dablk_t greatest_bno;
- xfs_dinode_t *dip;
- da_level_state_t level[XFS_DA_NODE_MAXDEPTH];
- struct blkmap *blkmap;
-} da_bt_cursor_t;
-
-
-/* ROUTINES */
-
-void
-err_release_da_cursor(
- xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- int prev_level);
-
-da_freemap_t *
-alloc_da_freemap(
- xfs_mount_t *mp);
-
-int
-namecheck(
- char *name,
- int length);
-
-int
-process_dir(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dirty,
- char *dirname,
- xfs_ino_t *parent,
- struct blkmap *blkmap);
-
-void
-release_da_cursor(
- xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- int prev_level);
-
-int
-set_da_freemap(
- xfs_mount_t *mp, da_freemap_t *map,
- int start, int stop);
-
-int
-traverse_int_dablock(
- xfs_mount_t *mp,
- da_bt_cursor_t *da_cursor,
- xfs_dablk_t *rbno,
- int whichfork);
-
-int
-verify_da_path(
- xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- const int p_level);
-
-int
-verify_final_da_path(
- xfs_mount_t *mp,
- da_bt_cursor_t *cursor,
- const int p_level);
-
-
-#endif /* _XR_DIR_H */
#include "incore.h"
#include "err_protos.h"
#include "dinode.h"
-#include "dir.h"
#include "dir2.h"
#include "bmap.h"
#include "prefetch.h"
return 0;
}
+/*
+ * takes a name and length (name need not be null-terminated)
+ * and returns 1 if the name contains a '/' or a \0, returns 0
+ * otherwise
+ */
+int
+namecheck(char *name, int length)
+{
+ char *c;
+ int i;
+
+ ASSERT(length < MAXNAMELEN);
+
+ for (c = name, i = 0; i < length; i++, c++) {
+ if (*c == '/' || *c == '\0')
+ return(1);
+ }
+
+ return(0);
+}
+
/*
* Multibuffer handling.
* V2 directory blocks can be noncontiguous, needing multiple buffers.
dir2_is_badino(
xfs_ino_t ino);
+int
+namecheck(
+ char *name,
+ int length);
+
#endif /* _XR_DIR2_H */
#include "err_protos.h"
#include "pthread.h"
#include "avl.h"
-#include "dir.h"
#include "bmap.h"
#include "incore.h"
#include "prefetch.h"
#include "protos.h"
#include "err_protos.h"
#include "dinode.h"
-#include "dir.h"
#include "bmap.h"
#include "versions.h"
#include "dir2.h"
#include "globals.h"
#include "agheader.h"
#include "incore.h"
-#include "dir.h"
#include "dir2.h"
#include "protos.h"
#include "err_protos.h"
}
}
-/*
- * Returns the fsbno of the first (leftmost) block in the directory leaf.
- * sets *bno to the directory block # corresponding to the returned fsbno.
- */
-static xfs_dfsbno_t
-map_first_dblock_fsbno(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- xfs_dablk_t *bno)
-{
- xfs_fsblock_t fblock;
- xfs_da_intnode_t *node;
- xfs_buf_t *bp;
- xfs_dablk_t da_bno;
- xfs_dfsbno_t fsbno;
- xfs_bmbt_irec_t map;
- int nmap;
- int i;
- int error;
- char *ftype;
-
- /*
- * traverse down left-side of tree until we hit the
- * left-most leaf block setting up the btree cursor along
- * the way.
- */
- da_bno = 0;
- *bno = 0;
- i = -1;
- node = NULL;
- fblock = NULLFSBLOCK;
- ftype = _("dir");
-
- nmap = 1;
- error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1,
- XFS_BMAPI_METADATA, &fblock, 0,
- &map, &nmap, NULL);
- if (error || nmap != 1) {
- if (!no_modify)
- do_error(
-_("can't map block %d in %s inode %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ftype, ino, error, nmap);
- else {
- do_warn(
-_("can't map block %d in %s inode %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ftype, ino, error, nmap);
- return(NULLDFSBNO);
- }
- }
-
- if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
- if (!no_modify)
- do_error(
- _("block %d in %s ino %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- else {
- do_warn(
- _("block %d in %s ino %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- return(NULLDFSBNO);
- }
- }
-
- if (ip->i_d.di_size <= XFS_LBSIZE(mp))
- return(fsbno);
-
- if (xfs_sb_version_hasdirv2(&mp->m_sb))
- return(fsbno);
-
- do {
- /*
- * walk down left side of btree, release buffers as you
- * go. if the root block is a leaf (single-level btree),
- * just return it.
- *
- */
-
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
- XFS_FSB_TO_BB(mp, 1), 0);
-
- if (!bp) {
- do_warn(
- _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"),
- da_bno, fsbno, ino);
- return(NULLDFSBNO);
- }
-
- node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
-
- if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
- libxfs_putbuf(bp);
- do_warn(
-_("bad dir/attr magic number in inode %" PRIu64 ", file bno = %u, fsbno = %" PRIu64 "\n"),
- ino, da_bno, fsbno);
- return(NULLDFSBNO);
- }
-
- if (i == -1)
- i = be16_to_cpu(node->hdr.level);
-
- da_bno = be32_to_cpu(node->btree[0].before);
-
- libxfs_putbuf(bp);
- bp = NULL;
-
- nmap = 1;
- error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1,
- XFS_BMAPI_METADATA, &fblock, 0,
- &map, &nmap, NULL);
- if (error || nmap != 1) {
- if (!no_modify)
- do_error(
-_("can't map block %d in %s ino %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ftype, ino, error, nmap);
- else {
- do_warn(
-_("can't map block %d in %s ino %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ftype, ino, error, nmap);
- return(NULLDFSBNO);
- }
- }
- if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
- if (!no_modify)
- do_error(
- _("block %d in %s inode %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- else {
- do_warn(
- _("block %d in %s inode %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- return(NULLDFSBNO);
- }
- }
-
- i--;
- } while(i > 0);
-
- *bno = da_bno;
- return(fsbno);
-}
-
static int
entry_junked(
const char *msg,
if (!no_modify) {
if (verbose)
do_warn(_(", marking entry to be junked\n"));
- else
- do_warn("\n");
- } else
- do_warn(_(", would junk entry\n"));
- return !no_modify;
-}
-
-/*
- * process a leaf block, also checks for .. entry
- * and corrects it to match what we think .. should be
- */
-static void
-lf_block_dir_entry_check(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dir_leafblock_t *leaf,
- int *dirty,
- int *num_illegal,
- int *need_dot,
- ino_tree_node_t *current_irec,
- int current_ino_offset,
- dir_hash_tab_t *hashtab,
- xfs_dablk_t da_bno)
-{
- xfs_dir_leaf_entry_t *entry;
- ino_tree_node_t *irec;
- xfs_ino_t lino;
- xfs_ino_t parent;
- xfs_dir_leaf_name_t *namest;
- int i;
- int junkit;
- int ino_offset;
- int nbad;
- char fname[MAXNAMELEN + 1];
-
- entry = &leaf->entries[0];
- *dirty = 0;
- nbad = 0;
-
- /*
- * look at each entry. reference inode pointed to by each
- * entry in the incore inode tree.
- * if not a directory, set reached flag, increment link count
- * if a directory and reached, mark entry as to be deleted.
- * if a directory, check to see if recorded parent
- * matches current inode #,
- * if so, then set reached flag, increment link count
- * of current and child dir inodes, push the child
- * directory inode onto the directory stack.
- * if current inode != parent, then mark entry to be deleted.
- *
- * return
- */
- for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
- /*
- * snag inode #, update link counts, and make sure
- * this isn't a loop if the child is a directory
- */
- namest = xfs_dir_leaf_namestruct(leaf,
- be16_to_cpu(entry->nameidx));
-
- /*
- * skip bogus entries (leading '/'). they'll be deleted
- * later
- */
- if (namest->name[0] == '/') {
- nbad++;
- continue;
- }
-
- junkit = 0;
-
- xfs_dir_sf_get_dirino(&namest->inumber, &lino);
- memmove(fname, namest->name, entry->namelen);
- fname[entry->namelen] = '\0';
-
- ASSERT(lino != NULLFSINO);
-
- /*
- * skip the '..' entry since it's checked when the
- * directory is reached by something else. if it never
- * gets reached, it'll be moved to the orphanage and we'll
- * take care of it then.
- */
- if (entry->namelen == 2 && namest->name[0] == '.' &&
- namest->name[1] == '.')
- continue;
-
- ASSERT(no_modify || !verify_inum(mp, lino));
-
- /*
- * special case the . entry. we know there's only one
- * '.' and only '.' points to itself because bogus entries
- * got trashed in phase 3 if there were > 1.
- * bump up link count for '.' but don't set reached
- * until we're actually reached by another directory
- * '..' is already accounted for or will be taken care
- * of when directory is moved to orphanage.
- */
- if (ino == lino) {
- ASSERT(namest->name[0] == '.' && entry->namelen == 1);
- add_inode_ref(current_irec, current_ino_offset);
- *need_dot = 0;
- continue;
- }
-
- /*
- * skip entries with bogus inumbers if we're in no modify mode
- */
- if (no_modify && verify_inum(mp, lino))
- continue;
-
- /*
- * ok, now handle the rest of the cases besides '.' and '..'
- */
- irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino),
- XFS_INO_TO_AGINO(mp, lino));
-
- if (irec == NULL) {
- nbad++;
- if (entry_junked(
- _("entry \"%s\" in dir inode %" PRIu64 " points to non-existent inode %" PRIu64),
- fname, ino, lino)) {
- namest->name[0] = '/';
- *dirty = 1;
- }
- continue;
- }
-
- ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
-
- /*
- * if it's a free inode, blow out the entry.
- * by now, any inode that we think is free
- * really is free.
- */
- if (is_inode_free(irec, ino_offset)) {
- nbad++;
- if (entry_junked(
- _("entry \"%s\" in dir inode %" PRIu64 " points to free inode %" PRIu64),
- fname, ino, lino)) {
- namest->name[0] = '/';
- *dirty = 1;
- }
- continue;
- }
- /*
- * check if this inode is lost+found dir in the root
- */
- if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) {
- /* root inode, "lost+found", if it's not a directory,
- * trash it, otherwise, assign it */
- if (!inode_isadir(irec, ino_offset)) {
- nbad++;
- if (entry_junked(
- _("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"),
- ORPHANAGE, lino, ino)) {
- namest->name[0] = '/';
- *dirty = 1;
- }
- continue;
- }
- /*
- * if this is a dup, it will be picked up below,
- * otherwise, mark it as the orphanage for later.
- */
- if (!orphanage_ino)
- orphanage_ino = lino;
- }
- /*
- * check for duplicate names in directory.
- */
- if (!dir_hash_add(mp, hashtab, (da_bno << mp->m_sb.sb_blocklog)
- + be16_to_cpu(entry->nameidx), lino,
- entry->namelen, namest->name)) {
- nbad++;
- if (entry_junked(
- _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
- fname, lino, ino)) {
- namest->name[0] = '/';
- *dirty = 1;
- }
- if (lino == orphanage_ino)
- orphanage_ino = 0;
- continue;
- }
- /*
- * check easy case first, regular inode, just bump
- * the link count and continue
- */
- if (!inode_isadir(irec, ino_offset)) {
- add_inode_reached(irec, ino_offset);
- continue;
- }
-
- parent = get_inode_parent(irec, ino_offset);
- ASSERT(parent != 0);
-
- /*
- * bump up the link counts in parent and child
- * directory but if the link doesn't agree with
- * the .. in the child, blow out the entry.
- * if the directory has already been reached,
- * blow away the entry also.
- */
- if (is_inode_reached(irec, ino_offset)) {
- junkit = 1;
- do_warn(
- _("entry \"%s\" in dir ino %" PRIu64 " points to an already connected dir inode %" PRIu64 ",\n"),
- fname, ino, lino);
- } else if (parent == ino) {
- add_inode_reached(irec, ino_offset);
- add_inode_ref(current_irec, current_ino_offset);
- } else if (parent == NULLFSINO) {
- /* ".." was missing, but this entry refers to it,
- so, set it as the parent and mark for rebuild */
- do_warn(
- _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"),
- fname, ino, lino);
- set_inode_parent(irec, ino_offset, ino);
- add_inode_reached(irec, ino_offset);
- add_inode_ref(current_irec, current_ino_offset);
- } else {
- junkit = 1;
- do_warn(
- _("entry \"%s\" in dir ino %" PRIu64 " not consistent with .. value (%" PRIu64 ") in ino %" PRIu64 ",\n"),
- fname, ino, parent, lino);
- }
-
- if (junkit) {
- if (lino == orphanage_ino)
- orphanage_ino = 0;
- junkit = 0;
- nbad++;
- if (!no_modify) {
- namest->name[0] = '/';
- *dirty = 1;
- if (verbose)
- do_warn(
- _("\twill clear entry \"%s\"\n"),
- fname);
- } else {
- do_warn(_("\twould clear entry \"%s\"\n"),
- fname);
- }
- }
- }
-
- *num_illegal += nbad;
-}
-
-/*
- * succeeds or dies, inode never gets dirtied since all changes
- * happen in file blocks. the inode size and other core info
- * is already correct, it's just the leaf entries that get altered.
- */
-static void
-longform_dir_entry_check(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- int *num_illegal,
- int *need_dot,
- ino_tree_node_t *irec,
- int ino_offset,
- dir_hash_tab_t *hashtab)
-{
- xfs_dir_leafblock_t *leaf;
- xfs_buf_t *bp;
- xfs_dfsbno_t fsbno;
- xfs_fsblock_t fblock;
- xfs_dablk_t da_bno;
- int dirty;
- int nmap;
- int error;
- int skipit;
- xfs_bmbt_irec_t map;
- char *ftype;
-
- da_bno = 0;
- fblock = NULLFSBLOCK;
- *need_dot = 1;
- ftype = _("dir");
-
- fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno);
-
- if (fsbno == NULLDFSBNO && no_modify) {
- do_warn(
- _("cannot map block 0 of directory inode %" PRIu64 "\n"), ino);
- return;
- }
-
- do {
- ASSERT(fsbno != NULLDFSBNO);
- skipit = 0;
-
- bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
- XFS_FSB_TO_BB(mp, 1), 0);
-
- if (!bp) {
- do_error(
- _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"),
- da_bno, fsbno, ino);
- /* NOTREACHED */
- }
-
- leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
-
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
- if (!no_modify) {
- do_error(
-_("bad magic # (0x%x) for dir ino %" PRIu64 " leaf block (bno %u fsbno %" PRIu64 ")\n"),
- be16_to_cpu(leaf->hdr.info.magic),
- ino, da_bno, fsbno);
- /* NOTREACHED */
- } else {
- /*
- * this block's bad but maybe the
- * forward pointer is good...
- */
- skipit = 1;
- dirty = 0;
- }
- }
-
- if (!skipit)
- lf_block_dir_entry_check(mp, ino, leaf, &dirty,
- num_illegal, need_dot, irec,
- ino_offset, hashtab, da_bno);
-
- da_bno = be32_to_cpu(leaf->hdr.info.forw);
-
- ASSERT(dirty == 0 || (dirty && !no_modify));
-
- if (dirty && !no_modify)
- libxfs_writebuf(bp, 0);
- else
- libxfs_putbuf(bp);
- bp = NULL;
-
- if (da_bno != 0) {
- nmap = 1;
- error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t)da_bno, 1,
- XFS_BMAPI_METADATA, &fblock, 0,
- &map, &nmap, NULL);
- if (error || nmap != 1) {
- if (!no_modify)
- do_error(
-_("can't map leaf block %d in dir %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ino, error, nmap);
- else {
- do_warn(
-_("can't map leaf block %d in dir %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"),
- da_bno, ino, error, nmap);
- return;
- }
- }
- fsbno = map.br_startblock;
- if (fsbno == HOLESTARTBLOCK) {
- if (!no_modify)
- do_error(
- _("block %d in %s ino %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- else {
- do_warn(
- _("block %d in %s ino %" PRIu64 " doesn't exist\n"),
- da_bno, ftype, ino);
- return;
- }
- }
- }
- } while (da_bno != 0);
+ else
+ do_warn("\n");
+ } else
+ do_warn(_(", would junk entry\n"));
+ return !no_modify;
}
/*
free(freetab);
}
-/*
- * shortform directory processing routines -- entry verification and
- * bad entry deletion (pruning).
- */
-static void
-shortform_dir_entry_check(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- int *ino_dirty,
- ino_tree_node_t *current_irec,
- int current_ino_offset,
- dir_hash_tab_t *hashtab)
-{
- xfs_ino_t lino;
- xfs_ino_t parent;
- xfs_dir_shortform_t *sf;
- xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe;
- xfs_ifork_t *ifp;
- ino_tree_node_t *irec;
- int max_size;
- int ino_offset;
- int i;
- int junkit;
- int tmp_len;
- int tmp_elen;
- int bad_sfnamelen;
- int namelen;
- int bytes_deleted;
- char fname[MAXNAMELEN + 1];
-
- ifp = &ip->i_df;
- sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data;
- *ino_dirty = 0;
- bytes_deleted = 0;
-
- max_size = ifp->if_bytes;
- ASSERT(ip->i_d.di_size <= ifp->if_bytes);
-
- /*
- * no '.' entry in shortform dirs, just bump up ref count by 1
- * '..' was already (or will be) accounted for and checked when
- * the directory is reached or will be taken care of when the
- * directory is moved to orphanage.
- */
- add_inode_ref(current_irec, current_ino_offset);
-
- /*
- * now run through entries, stop at first bad entry, don't need
- * to skip over '..' since that's encoded in its own field and
- * no need to worry about '.' since it doesn't exist.
- */
- sf_entry = next_sfe = &sf->list[0];
- if (sf == NULL) {
- junkit = 1;
- do_warn(
- _("shortform dir inode %" PRIu64 " has null data entries \n"),
- ino);
-
- }
- else {
- for (i = 0; i < sf->hdr.count && max_size >
- (__psint_t)next_sfe - (__psint_t)sf;
- sf_entry = next_sfe, i++) {
- junkit = 0;
- bad_sfnamelen = 0;
- tmp_sfe = NULL;
-
- xfs_dir_sf_get_dirino(&sf_entry->inumber, &lino);
-
- namelen = sf_entry->namelen;
-
- ASSERT(no_modify || namelen > 0);
-
- if (no_modify && namelen == 0) {
- /*
- * if we're really lucky, this is
- * the last entry in which case we
- * can use the dir size to set the
- * namelen value. otherwise, forget
- * it because we're not going to be
- * able to find the next entry.
- */
- bad_sfnamelen = 1;
-
- if (i == sf->hdr.count - 1) {
- namelen = ip->i_d.di_size -
- ((__psint_t) &sf_entry->name[0] -
- (__psint_t) sf);
- } else {
- /*
- * don't process the rest of the directory,
- * break out of processing looop
- */
- break;
- }
- } else if (no_modify && (__psint_t) sf_entry - (__psint_t) sf +
- + xfs_dir_sf_entsize_byentry(sf_entry)
- > ip->i_d.di_size) {
- bad_sfnamelen = 1;
-
- if (i == sf->hdr.count - 1) {
- namelen = ip->i_d.di_size -
- ((__psint_t) &sf_entry->name[0] -
- (__psint_t) sf);
- } else {
- /*
- * don't process the rest of the directory,
- * break out of processing looop
- */
- break;
- }
- }
-
- memmove(fname, sf_entry->name, sf_entry->namelen);
- fname[sf_entry->namelen] = '\0';
-
- ASSERT(no_modify || lino != NULLFSINO);
- ASSERT(no_modify || !verify_inum(mp, lino));
-
- irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino),
- XFS_INO_TO_AGINO(mp, lino));
- if (irec == NULL) {
- do_warn(
- _("entry \"%s\" in shortform dir %" PRIu64 " references non-existent ino %" PRIu64 "\n"),
- fname, ino, lino);
- goto do_junkit;
- }
- ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
-
- /*
- * if it's a free inode, blow out the entry.
- * by now, any inode that we think is free
- * really is free.
- */
- if (!is_inode_free(irec, ino_offset)) {
- do_warn(
- _("entry \"%s\" in shortform dir inode %" PRIu64 " points to free inode %" PRIu64"\n"),
- fname, ino, lino);
- goto do_junkit;
- }
- /*
- * check if this inode is lost+found dir in the root
- */
- if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) {
- /*
- * if it's not a directory, trash it
- */
- if (!inode_isadir(irec, ino_offset)) {
- do_warn(
- _("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"),
- ORPHANAGE, lino, ino);
- goto do_junkit;
- }
- /*
- * if this is a dup, it will be picked up below,
- * otherwise, mark it as the orphanage for later.
- */
- if (!orphanage_ino)
- orphanage_ino = lino;
- }
- /*
- * check for duplicate names in directory.
- */
- if (!dir_hash_add(mp, hashtab, (xfs_dir2_dataptr_t)
- (sf_entry - &sf->list[0]), lino,
- sf_entry->namelen, sf_entry->name)) {
- do_warn(
-_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
- fname, lino, ino);
- goto do_junkit;
- }
- if (!inode_isadir(irec, ino_offset)) {
- /*
- * check easy case first, regular inode, just bump
- * the link count and continue
- */
- add_inode_reached(irec, ino_offset);
-
- next_sfe = (xfs_dir_sf_entry_t *)((__psint_t)sf_entry +
- xfs_dir_sf_entsize_byentry(sf_entry));
- continue;
- } else {
- parent = get_inode_parent(irec, ino_offset);
-
- /*
- * bump up the link counts in parent and child.
- * directory but if the link doesn't agree with
- * the .. in the child, blow out the entry
- */
- if (is_inode_reached(irec, ino_offset)) {
- junkit = 1;
- do_warn(
- _("entry \"%s\" in dir %" PRIu64 " references already connected dir ino %" PRIu64 ".\n"),
- fname, ino, lino);
- } else if (parent == ino) {
- add_inode_reached(irec, ino_offset);
- add_inode_ref(current_irec, current_ino_offset);
- } else if (parent == NULLFSINO) {
- /* ".." was missing, but this entry refers to it,
- so, set it as the parent and mark for rebuild */
- do_warn(
- _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"),
- fname, ino, lino);
- set_inode_parent(irec, ino_offset, ino);
- add_inode_reached(irec, ino_offset);
- add_inode_ref(current_irec, current_ino_offset);
- } else {
- junkit = 1;
- do_warn(
- _("entry \"%s\" in dir %" PRIu64 " not consistent with .. value (%" PRIu64 ") in dir ino %" PRIu64".\n"),
- fname, ino, parent, lino);
- }
- }
- if (junkit) {
-do_junkit:
- if (lino == orphanage_ino)
- orphanage_ino = 0;
- if (!no_modify) {
- tmp_elen = xfs_dir_sf_entsize_byentry(sf_entry);
- tmp_sfe = (xfs_dir_sf_entry_t *)
- ((__psint_t) sf_entry + tmp_elen);
- tmp_len = max_size - ((__psint_t) tmp_sfe
- - (__psint_t) sf);
- max_size -= tmp_elen;
- bytes_deleted += tmp_elen;
-
- memmove(sf_entry, tmp_sfe, tmp_len);
-
- sf->hdr.count -= 1;
- memset((void *)((__psint_t)sf_entry + tmp_len),
- 0, tmp_elen);
-
- /*
- * set the tmp value to the current
- * pointer so we'll process the entry
- * we just moved up
- */
- tmp_sfe = sf_entry;
-
- /*
- * WARNING: drop the index i by one
- * so it matches the decremented count for
- * accurate comparisons in the loop test
- */
- i--;
-
- *ino_dirty = 1;
-
- if (verbose)
- do_warn(_("junking entry\n"));
- else
- do_warn("\n");
- } else {
- do_warn(_("would junk entry\n"));
- }
- }
-
- /*
- * go onto next entry unless we've just junked an
- * entry in which the current entry pointer points
- * to an unprocessed entry. have to take into entries
- * with bad namelen into account in no modify mode since we
- * calculate size based on next_sfe.
- */
- ASSERT(no_modify || bad_sfnamelen == 0);
-
- next_sfe = (tmp_sfe == NULL)
- ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry
- + ((!bad_sfnamelen)
- ? xfs_dir_sf_entsize_byentry(sf_entry)
- : sizeof(xfs_dir_sf_entry_t) - 1
- + namelen))
- : tmp_sfe;
- }
- }
-
- /*
- * sync up sizes if required
- */
- if (*ino_dirty) {
- ASSERT(bytes_deleted > 0);
- ASSERT(!no_modify);
- libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
- ip->i_d.di_size -= bytes_deleted;
- }
-
- if (ip->i_d.di_size != ip->i_df.if_bytes) {
- ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
- ((__psint_t) next_sfe - (__psint_t) sf));
- ip->i_d.di_size = (xfs_fsize_t)
- ((__psint_t) next_sfe - (__psint_t) sf);
- do_warn(
- _("setting size to %" PRId64 " bytes to reflect junked entries\n"),
- ip->i_d.di_size);
- *ino_dirty = 1;
- }
-}
-
/*
* shortform directory v2 processing routines -- entry verification and
* bad entry deletion (pruning).
* the directory is connected to lost+found. but
* we need to create '.' entries here.
*/
- if (xfs_sb_version_hasdirv2(&mp->m_sb))
- longform_dir2_entry_check(mp, ino, ip,
- &num_illegal, &need_dot,
- irec, ino_offset,
- hashtab);
- else
- longform_dir_entry_check(mp, ino, ip,
- &num_illegal, &need_dot,
- irec, ino_offset,
- hashtab);
+ longform_dir2_entry_check(mp, ino, ip,
+ &num_illegal, &need_dot,
+ irec, ino_offset,
+ hashtab);
break;
case XFS_DINODE_FMT_LOCAL:
libxfs_trans_ijoin(tp, ip, 0);
libxfs_trans_ihold(tp, ip);
- if (xfs_sb_version_hasdirv2(&mp->m_sb))
- shortform_dir2_entry_check(mp, ino, ip, &dirty,
- irec, ino_offset,
- hashtab);
- else
- shortform_dir_entry_check(mp, ino, ip, &dirty,
- irec, ino_offset,
- hashtab);
+ shortform_dir2_entry_check(mp, ino, ip, &dirty,
+ irec, ino_offset,
+ hashtab);
ASSERT(dirty == 0 || (dirty && !no_modify));
if (dirty) {
}
dir_hash_done(hashtab);
- /*
- * We don't support repairing of v1 dir anymore, report errors and exit
- */
- if (!xfs_sb_version_hasdirv2(&mp->m_sb)) {
- if (need_root_dotdot && ino == mp->m_sb.sb_rootino)
- do_warn(_("missing root directory .. entry, cannot "
- "fix in V1 dir filesystem\n"));
-
- if (num_illegal > 0) {
- ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL);
-
- do_warn(
- _("%d bad entries found in dir inode %" PRIu64 ", cannot fix in V1 dir filesystem\n"),
- num_illegal, ino);
- }
- if (need_dot) {
- add_inode_ref(irec, ino_offset);
-
- do_warn(
- _("missing \".\" entry in dir ino %" PRIu64 ", cannot in fix V1 dir filesystem\n"), ino);
- }
- goto out;
- }
-
/*
* if we have to create a .. for /, do it now *before*
* we delete the bogus entries, otherwise the directory
|XFS_TRANS_SYNC);
}
}
-out:
libxfs_iput(ip, 0);
}
do_warn(_("disconnected dir inode %" PRIu64 ", "), ino);
else
do_warn(_("disconnected inode %" PRIu64 ", "), ino);
- if (!xfs_sb_version_hasdirv2(&mp->m_sb))
- do_warn(_("cannot fix in V1 dir filesystem\n"));
- else if (!no_modify) {
- if (!orphanage_ino)
+ if (!no_modify) {
+ if (!orphanage_ino)
orphanage_ino = mk_orphanage(mp);
do_warn(_("moving to %s\n"), ORPHANAGE);
mv_orphanage(mp, ino, inode_isadir(irec, i));
* inodes in its chunk if a new chunk was created) are ok
*/
if (need_root_inode) {
- if (!xfs_sb_version_hasdirv2(&mp->m_sb))
- do_warn(_("need to reinitialize root directory, "
- "but not supported on V1 dir filesystem\n"));
- else if (!no_modify) {
+ if (!no_modify) {
do_warn(_("reinitializing root directory\n"));
mk_root_dir(mp);
need_root_inode = 0;
#include "globals.h"
#include "agheader.h"
#include "incore.h"
-#include "dir.h"
#include "dir2.h"
#include "protos.h"
#include "err_protos.h"