From: Dave Chinner <dchinner@xxxxxxxxxx> 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 <dchinner@xxxxxxxxxx> --- 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 a3da965..860b123 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 31a26d7..b0f1396 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'; /* -- 1.7.10.4 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs