0001
0002
0003
0004
0005
0006
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_shared.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_error.h"
0016 #include "xfs_trans.h"
0017 #include "xfs_buf_item.h"
0018 #include "xfs_log.h"
0019
0020
0021
0022
0023
0024
0025 int
0026 xfs_symlink_blocks(
0027 struct xfs_mount *mp,
0028 int pathlen)
0029 {
0030 int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
0031
0032 return (pathlen + buflen - 1) / buflen;
0033 }
0034
0035 int
0036 xfs_symlink_hdr_set(
0037 struct xfs_mount *mp,
0038 xfs_ino_t ino,
0039 uint32_t offset,
0040 uint32_t size,
0041 struct xfs_buf *bp)
0042 {
0043 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0044
0045 if (!xfs_has_crc(mp))
0046 return 0;
0047
0048 memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
0049 dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
0050 dsl->sl_offset = cpu_to_be32(offset);
0051 dsl->sl_bytes = cpu_to_be32(size);
0052 uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
0053 dsl->sl_owner = cpu_to_be64(ino);
0054 dsl->sl_blkno = cpu_to_be64(xfs_buf_daddr(bp));
0055 bp->b_ops = &xfs_symlink_buf_ops;
0056
0057 return sizeof(struct xfs_dsymlink_hdr);
0058 }
0059
0060
0061
0062
0063
0064
0065 bool
0066 xfs_symlink_hdr_ok(
0067 xfs_ino_t ino,
0068 uint32_t offset,
0069 uint32_t size,
0070 struct xfs_buf *bp)
0071 {
0072 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0073
0074 if (offset != be32_to_cpu(dsl->sl_offset))
0075 return false;
0076 if (size != be32_to_cpu(dsl->sl_bytes))
0077 return false;
0078 if (ino != be64_to_cpu(dsl->sl_owner))
0079 return false;
0080
0081
0082 return true;
0083 }
0084
0085 static xfs_failaddr_t
0086 xfs_symlink_verify(
0087 struct xfs_buf *bp)
0088 {
0089 struct xfs_mount *mp = bp->b_mount;
0090 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0091
0092 if (!xfs_has_crc(mp))
0093 return __this_address;
0094 if (!xfs_verify_magic(bp, dsl->sl_magic))
0095 return __this_address;
0096 if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
0097 return __this_address;
0098 if (xfs_buf_daddr(bp) != be64_to_cpu(dsl->sl_blkno))
0099 return __this_address;
0100 if (be32_to_cpu(dsl->sl_offset) +
0101 be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
0102 return __this_address;
0103 if (dsl->sl_owner == 0)
0104 return __this_address;
0105 if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
0106 return __this_address;
0107
0108 return NULL;
0109 }
0110
0111 static void
0112 xfs_symlink_read_verify(
0113 struct xfs_buf *bp)
0114 {
0115 struct xfs_mount *mp = bp->b_mount;
0116 xfs_failaddr_t fa;
0117
0118
0119 if (!xfs_has_crc(mp))
0120 return;
0121
0122 if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
0123 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
0124 else {
0125 fa = xfs_symlink_verify(bp);
0126 if (fa)
0127 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0128 }
0129 }
0130
0131 static void
0132 xfs_symlink_write_verify(
0133 struct xfs_buf *bp)
0134 {
0135 struct xfs_mount *mp = bp->b_mount;
0136 struct xfs_buf_log_item *bip = bp->b_log_item;
0137 xfs_failaddr_t fa;
0138
0139
0140 if (!xfs_has_crc(mp))
0141 return;
0142
0143 fa = xfs_symlink_verify(bp);
0144 if (fa) {
0145 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0146 return;
0147 }
0148
0149 if (bip) {
0150 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0151 dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
0152 }
0153 xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
0154 }
0155
0156 const struct xfs_buf_ops xfs_symlink_buf_ops = {
0157 .name = "xfs_symlink",
0158 .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
0159 .verify_read = xfs_symlink_read_verify,
0160 .verify_write = xfs_symlink_write_verify,
0161 .verify_struct = xfs_symlink_verify,
0162 };
0163
0164 void
0165 xfs_symlink_local_to_remote(
0166 struct xfs_trans *tp,
0167 struct xfs_buf *bp,
0168 struct xfs_inode *ip,
0169 struct xfs_ifork *ifp)
0170 {
0171 struct xfs_mount *mp = ip->i_mount;
0172 char *buf;
0173
0174 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
0175
0176 if (!xfs_has_crc(mp)) {
0177 bp->b_ops = NULL;
0178 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
0179 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
0180 return;
0181 }
0182
0183
0184
0185
0186
0187 ASSERT(BBTOB(bp->b_length) >=
0188 ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
0189
0190 bp->b_ops = &xfs_symlink_buf_ops;
0191
0192 buf = bp->b_addr;
0193 buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
0194 memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
0195 xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
0196 ifp->if_bytes - 1);
0197 }
0198
0199
0200
0201
0202
0203 xfs_failaddr_t
0204 xfs_symlink_shortform_verify(
0205 struct xfs_inode *ip)
0206 {
0207 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
0208 char *sfp = (char *)ifp->if_u1.if_data;
0209 int size = ifp->if_bytes;
0210 char *endp = sfp + size;
0211
0212 ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
0213
0214
0215
0216
0217
0218 if (!size)
0219 return __this_address;
0220
0221
0222 if (size < 0 || size > XFS_SYMLINK_MAXLEN)
0223 return __this_address;
0224
0225
0226 if (memchr(sfp, 0, size - 1))
0227 return __this_address;
0228
0229
0230 if (*endp != 0)
0231 return __this_address;
0232 return NULL;
0233 }