From 2019931af194ee5b06c22cbd5f7a903303e07eb3 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 7 Jun 2013 10:26:10 +1000 Subject: [PATCH] xfs_repair: support CRC enabled remote symlinks Add support for verifying the contents of remote symlinks with CRCs. Factor the remote symlink checking code out of the symlink function so that it is clear what it is checking. This also reduces the indentation and makes the code clearer. Then add support for the CRC format by modelling the checking function directly on the code that is used in the kernel for reading and checking both remote symlink formats. Signed-off-by: Dave Chinner Reviewed-by: Ben Myers Signed-off-by: Ben Myers --- libxfs/xfs_symlink.c | 11 +--- repair/dinode.c | 132 ++++++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 55 deletions(-) diff --git a/libxfs/xfs_symlink.c b/libxfs/xfs_symlink.c index a3da965b1..860b12392 100644 --- a/libxfs/xfs_symlink.c +++ b/libxfs/xfs_symlink.c @@ -14,16 +14,9 @@ xfs_symlink_blocks( struct xfs_mount *mp, int pathlen) { - int fsblocks = 0; - int len = pathlen; + int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); - do { - fsblocks++; - len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); - } while (len > 0); - - ASSERT(fsblocks <= XFS_SYMLINK_MAPS); - return fsblocks; + return (pathlen + buflen - 1) / buflen; } /* diff --git a/repair/dinode.c b/repair/dinode.c index 13e5f35d5..e607f0b4b 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1449,6 +1449,86 @@ null_check(char *name, int length) return(0); } +static int +process_symlink_remote( + struct xfs_mount *mp, + xfs_ino_t lino, + struct xfs_dinode *dino, + struct blkmap *blkmap, + char *dst) +{ + xfs_dfsbno_t fsbno; + struct xfs_buf *bp; + char *src; + int pathlen; + int offset; + int i; + + offset = 0; + pathlen = be64_to_cpu(dino->di_size); + i = 0; + + while (pathlen > 0) { + int blk_cnt = 1; + int byte_cnt; + + fsbno = blkmap_get(blkmap, i); + if (fsbno == NULLDFSBNO) { + do_warn( +_("cannot read inode %" PRIu64 ", file block %d, NULL disk block\n"), + lino, i); + return 1; + } + + /* + * There's a symlink header for each contiguous extent. If + * there are contiguous blocks, read them in one go. + */ + while (blk_cnt <= max_symlink_blocks) { + if (blkmap_get(blkmap, i + 1) != fsbno + 1) + break; + blk_cnt++; + i++; + } + + byte_cnt = XFS_FSB_TO_B(mp, blk_cnt); + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + BTOBB(byte_cnt), 0, &xfs_symlink_buf_ops); + if (!bp) { + do_warn( +_("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), + lino, i, fsbno); + return 1; + } + + byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); + byte_cnt = MIN(pathlen, byte_cnt); + + src = bp->b_addr; + if (xfs_sb_version_hascrc(&mp->m_sb)) { + if (!libxfs_symlink_hdr_ok(mp, lino, offset, + byte_cnt, bp)) { + do_warn( +_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), + lino, i, fsbno); + libxfs_putbuf(bp); + return 1; + } + src += sizeof(struct xfs_dsymlink_hdr); + } + + memmove(dst + offset, src, byte_cnt); + + pathlen -= byte_cnt; + offset += byte_cnt; + i++; + + libxfs_putbuf(bp); + } + return 0; +} + /* * like usual, returns 0 if everything's ok and 1 if something's * bogus @@ -1460,10 +1540,7 @@ process_symlink( xfs_dinode_t *dino, blkmap_t *blkmap) { - xfs_dfsbno_t fsbno; - xfs_buf_t *bp = NULL; - char *symlink, *cptr, *buf_data; - int i, size, amountdone; + char *symlink, *cptr; char data[MAXPATHLEN]; /* @@ -1491,50 +1568,13 @@ process_symlink( memmove(symlink, XFS_DFORK_DPTR(dino), be64_to_cpu(dino->di_size)); } else { - /* - * stored in a meta-data file, have to bmap one block - * at a time and copy the symlink into the data area - */ - i = size = amountdone = 0; - cptr = symlink; - - while (amountdone < be64_to_cpu(dino->di_size)) { - fsbno = blkmap_get(blkmap, i); - if (fsbno != NULLDFSBNO) - bp = libxfs_readbuf(mp->m_dev, - XFS_FSB_TO_DADDR(mp, fsbno), - XFS_FSB_TO_BB(mp, 1), 0, - &xfs_symlink_buf_ops); - if (!bp || fsbno == NULLDFSBNO) { - do_warn( -_("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), - lino, i, fsbno); - return(1); - } - + int error; - buf_data = (char *)XFS_BUF_PTR(bp); - size = MIN(be64_to_cpu(dino->di_size) - amountdone, - XFS_SYMLINK_BUF_SPACE(mp, - mp->m_sb.sb_blocksize)); - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!libxfs_symlink_hdr_ok(mp, lino, amountdone, - size, bp)) { - do_warn( -_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), - lino, i, fsbno); - libxfs_putbuf(bp); - return(1); - } - buf_data += sizeof(struct xfs_dsymlink_hdr); - } - memmove(cptr, buf_data, size); - cptr += size; - amountdone += size; - i++; - libxfs_putbuf(bp); - } + error = process_symlink_remote(mp, lino, dino, blkmap, symlink); + if (error) + return error; } + data[be64_to_cpu(dino->di_size)] = '\0'; /* -- 2.47.2