/* * Given a block number in a fork, return the next valid block number * (not a hole). * If this is the last block number then NULLFILEOFF is returned. * * This was originally in the kernel, but only used in xfs_repair. */ int libxfs_bmap_next_offset( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ xfs_fileoff_t *bnop, /* current block */ int whichfork) /* data or attr fork */ { xfs_fileoff_t bno; /* current block */ int eof; /* hit end of file */ int error; /* error return value */ xfs_bmbt_irec_t got; /* current extent value */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_extnum_t lastx; /* last extent used */ xfs_bmbt_irec_t prev; /* previous extent value */ if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) return XFS_ERROR(EIO); if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { *bnop = NULLFILEOFF; return 0; } ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; bno = *bnop + 1; xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); if (eof) *bnop = NULLFILEOFF; else *bnop = got.br_startoff < bno ? bno : got.br_startoff; return 0; }
int xfs_readlink(xfs_inode_t *ip, void *buffer, off_t offset, size_t len, int *last_extent) { memset(buffer, 0, len); if (!(ip->i_d.di_mode & S_IFLNK)) return XFS_ERROR(EINVAL); if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS) { return xfs_readlink_extents(ip, buffer, offset, len, last_extent); } else if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_LOCAL) { return xfs_readlink_local(ip, buffer, offset, len, last_extent); } return XFS_ERROR(EIO); }
int xfs_readfile(xfs_inode_t *ip, void *buffer, off_t offset, size_t len, int *last_extent) { /* TODO: make this better: */ /* Initialise the buffer to 0 to handle gaps in extents */ memset(buffer, 0, len); if (!(ip->i_d.di_mode & S_IFREG)) return XFS_ERROR(EINVAL); if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS) { return xfs_readfile_extents(ip, buffer, offset, len, last_extent); } else if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_BTREE) { return xfs_readfile_btree(ip, buffer, offset, len, last_extent); } return XFS_ERROR(EIO); }
/* * Count fsblocks of the given fork. */ int /* error */ xfs_bmap_count_blocks( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ int whichfork, /* data or attr fork */ int *count) /* out: count of blocks */ { struct xfs_btree_block *block; /* current btree block */ xfs_fsblock_t bno; /* block # of "block" */ xfs_ifork_t *ifp; /* fork structure */ int level; /* btree level, for checking */ xfs_mount_t *mp; /* file system mount structure */ __be64 *pp; /* pointer to block address */ bno = NULLFSBLOCK; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { xfs_bmap_count_leaves(ifp, 0, ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), count); return 0; } /* * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. */ block = ifp->if_broot; level = be16_to_cpu(block->bb_level); ASSERT(level > 0); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); bno = be64_to_cpu(*pp); ASSERT(bno != NULLDFSBNO); ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) { XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW, mp); return XFS_ERROR(EFSCORRUPTED); } return 0; }
int xfs_ifork_format(xfs_inode_t *ip, int w) { return XFS_IFORK_FORMAT(ip, w); }