diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 132 |
1 files changed, 60 insertions, 72 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 36318c66a7b..bde4a1ad90f 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -951,6 +951,53 @@ xfs_access( */ #define SYMLINK_MAPS 2 +STATIC int +xfs_readlink_bmap( + xfs_inode_t *ip, + char *link) +{ + xfs_mount_t *mp = ip->i_mount; + int pathlen = ip->i_d.di_size; + int nmaps = SYMLINK_MAPS; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + xfs_daddr_t d; + int byte_cnt; + int n; + xfs_buf_t *bp; + int error = 0; + + error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0, + mval, &nmaps, NULL, NULL); + if (error) + goto out; + + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); + + bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); + error = XFS_BUF_GETERROR(bp); + if (error) { + xfs_ioerror_alert("xfs_readlink", + ip->i_mount, bp, XFS_BUF_ADDR(bp)); + xfs_buf_relse(bp); + goto out; + } + if (pathlen < byte_cnt) + byte_cnt = pathlen; + pathlen -= byte_cnt; + + memcpy(link, XFS_BUF_PTR(bp), byte_cnt); + xfs_buf_relse(bp); + } + + link[ip->i_d.di_size] = '\0'; + error = 0; + + out: + return error; +} + /* * xfs_readlink * @@ -958,29 +1005,14 @@ xfs_access( STATIC int xfs_readlink( bhv_desc_t *bdp, - uio_t *uiop, - int ioflags, - cred_t *credp) + char *link) { - xfs_inode_t *ip; - int count; - xfs_off_t offset; + xfs_inode_t *ip = XFS_BHVTOI(bdp); + xfs_mount_t *mp = ip->i_mount; int pathlen; - bhv_vnode_t *vp; int error = 0; - xfs_mount_t *mp; - int nmaps; - xfs_bmbt_irec_t mval[SYMLINK_MAPS]; - xfs_daddr_t d; - int byte_cnt; - int n; - xfs_buf_t *bp; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; + vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -988,68 +1020,24 @@ xfs_readlink( xfs_ilock(ip, XFS_ILOCK_SHARED); ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); + ASSERT(ip->i_d.di_size <= MAXPATHLEN); - offset = uiop->uio_offset; - count = uiop->uio_resid; - - if (offset < 0) { - error = XFS_ERROR(EINVAL); - goto error_return; - } - if (count <= 0) { - error = 0; - goto error_return; - } - - /* - * See if the symlink is stored inline. - */ - pathlen = (int)ip->i_d.di_size; + pathlen = ip->i_d.di_size; + if (!pathlen) + goto out; if (ip->i_df.if_flags & XFS_IFINLINE) { - error = xfs_uio_read(ip->i_df.if_u1.if_data, pathlen, uiop); - } - else { - /* - * Symlink not inline. Call bmap to get it in. - */ - nmaps = SYMLINK_MAPS; - - error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), - 0, NULL, 0, mval, &nmaps, NULL, NULL); - - if (error) { - goto error_return; - } - - for (n = 0; n < nmaps; n++) { - d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); - byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - bp = xfs_buf_read(mp->m_ddev_targp, d, - BTOBB(byte_cnt), 0); - error = XFS_BUF_GETERROR(bp); - if (error) { - xfs_ioerror_alert("xfs_readlink", - ip->i_mount, bp, XFS_BUF_ADDR(bp)); - xfs_buf_relse(bp); - goto error_return; - } - if (pathlen < byte_cnt) - byte_cnt = pathlen; - pathlen -= byte_cnt; - - error = xfs_uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop); - xfs_buf_relse (bp); - } - + memcpy(link, ip->i_df.if_u1.if_data, pathlen); + link[pathlen] = '\0'; + } else { + error = xfs_readlink_bmap(ip, link); } -error_return: + out: xfs_iunlock(ip, XFS_ILOCK_SHARED); return error; } - /* * xfs_fsync * |