linux/fs/xfs/libxfs/xfs_symlink_remote.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
   4 * Copyright (c) 2012-2013 Red Hat, Inc.
   5 * All rights reserved.
   6 */
   7#include "xfs.h"
   8#include "xfs_fs.h"
   9#include "xfs_format.h"
  10#include "xfs_log_format.h"
  11#include "xfs_shared.h"
  12#include "xfs_trans_resv.h"
  13#include "xfs_mount.h"
  14#include "xfs_inode.h"
  15#include "xfs_error.h"
  16#include "xfs_trans.h"
  17#include "xfs_buf_item.h"
  18#include "xfs_log.h"
  19
  20
  21/*
  22 * Each contiguous block has a header, so it is not just a simple pathlen
  23 * to FSB conversion.
  24 */
  25int
  26xfs_symlink_blocks(
  27        struct xfs_mount *mp,
  28        int             pathlen)
  29{
  30        int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
  31
  32        return (pathlen + buflen - 1) / buflen;
  33}
  34
  35int
  36xfs_symlink_hdr_set(
  37        struct xfs_mount        *mp,
  38        xfs_ino_t               ino,
  39        uint32_t                offset,
  40        uint32_t                size,
  41        struct xfs_buf          *bp)
  42{
  43        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  44
  45        if (!xfs_sb_version_hascrc(&mp->m_sb))
  46                return 0;
  47
  48        memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
  49        dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
  50        dsl->sl_offset = cpu_to_be32(offset);
  51        dsl->sl_bytes = cpu_to_be32(size);
  52        uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
  53        dsl->sl_owner = cpu_to_be64(ino);
  54        dsl->sl_blkno = cpu_to_be64(bp->b_bn);
  55        bp->b_ops = &xfs_symlink_buf_ops;
  56
  57        return sizeof(struct xfs_dsymlink_hdr);
  58}
  59
  60/*
  61 * Checking of the symlink header is split into two parts. the verifier does
  62 * CRC, location and bounds checking, the unpacking function checks the path
  63 * parameters and owner.
  64 */
  65bool
  66xfs_symlink_hdr_ok(
  67        xfs_ino_t               ino,
  68        uint32_t                offset,
  69        uint32_t                size,
  70        struct xfs_buf          *bp)
  71{
  72        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  73
  74        if (offset != be32_to_cpu(dsl->sl_offset))
  75                return false;
  76        if (size != be32_to_cpu(dsl->sl_bytes))
  77                return false;
  78        if (ino != be64_to_cpu(dsl->sl_owner))
  79                return false;
  80
  81        /* ok */
  82        return true;
  83}
  84
  85static xfs_failaddr_t
  86xfs_symlink_verify(
  87        struct xfs_buf          *bp)
  88{
  89        struct xfs_mount        *mp = bp->b_mount;
  90        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  91
  92        if (!xfs_sb_version_hascrc(&mp->m_sb))
  93                return __this_address;
  94        if (!xfs_verify_magic(bp, dsl->sl_magic))
  95                return __this_address;
  96        if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
  97                return __this_address;
  98        if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
  99                return __this_address;
 100        if (be32_to_cpu(dsl->sl_offset) +
 101                                be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
 102                return __this_address;
 103        if (dsl->sl_owner == 0)
 104                return __this_address;
 105        if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
 106                return __this_address;
 107
 108        return NULL;
 109}
 110
 111static void
 112xfs_symlink_read_verify(
 113        struct xfs_buf  *bp)
 114{
 115        struct xfs_mount *mp = bp->b_mount;
 116        xfs_failaddr_t  fa;
 117
 118        /* no verification of non-crc buffers */
 119        if (!xfs_sb_version_hascrc(&mp->m_sb))
 120                return;
 121
 122        if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
 123                xfs_verifier_error(bp, -EFSBADCRC, __this_address);
 124        else {
 125                fa = xfs_symlink_verify(bp);
 126                if (fa)
 127                        xfs_verifier_error(bp, -EFSCORRUPTED, fa);
 128        }
 129}
 130
 131static void
 132xfs_symlink_write_verify(
 133        struct xfs_buf  *bp)
 134{
 135        struct xfs_mount *mp = bp->b_mount;
 136        struct xfs_buf_log_item *bip = bp->b_log_item;
 137        xfs_failaddr_t          fa;
 138
 139        /* no verification of non-crc buffers */
 140        if (!xfs_sb_version_hascrc(&mp->m_sb))
 141                return;
 142
 143        fa = xfs_symlink_verify(bp);
 144        if (fa) {
 145                xfs_verifier_error(bp, -EFSCORRUPTED, fa);
 146                return;
 147        }
 148
 149        if (bip) {
 150                struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 151                dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
 152        }
 153        xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
 154}
 155
 156const struct xfs_buf_ops xfs_symlink_buf_ops = {
 157        .name = "xfs_symlink",
 158        .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
 159        .verify_read = xfs_symlink_read_verify,
 160        .verify_write = xfs_symlink_write_verify,
 161        .verify_struct = xfs_symlink_verify,
 162};
 163
 164void
 165xfs_symlink_local_to_remote(
 166        struct xfs_trans        *tp,
 167        struct xfs_buf          *bp,
 168        struct xfs_inode        *ip,
 169        struct xfs_ifork        *ifp)
 170{
 171        struct xfs_mount        *mp = ip->i_mount;
 172        char                    *buf;
 173
 174        xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
 175
 176        if (!xfs_sb_version_hascrc(&mp->m_sb)) {
 177                bp->b_ops = NULL;
 178                memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
 179                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
 180                return;
 181        }
 182
 183        /*
 184         * As this symlink fits in an inode literal area, it must also fit in
 185         * the smallest buffer the filesystem supports.
 186         */
 187        ASSERT(BBTOB(bp->b_length) >=
 188                        ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
 189
 190        bp->b_ops = &xfs_symlink_buf_ops;
 191
 192        buf = bp->b_addr;
 193        buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
 194        memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
 195        xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
 196                                        ifp->if_bytes - 1);
 197}
 198
 199/*
 200 * Verify the in-memory consistency of an inline symlink data fork. This
 201 * does not do on-disk format checks.
 202 */
 203xfs_failaddr_t
 204xfs_symlink_shortform_verify(
 205        struct xfs_inode        *ip)
 206{
 207        char                    *sfp;
 208        char                    *endp;
 209        struct xfs_ifork        *ifp;
 210        int                     size;
 211
 212        ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
 213        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
 214        sfp = (char *)ifp->if_u1.if_data;
 215        size = ifp->if_bytes;
 216        endp = sfp + size;
 217
 218        /*
 219         * Zero length symlinks should never occur in memory as they are
 220         * never alllowed to exist on disk.
 221         */
 222        if (!size)
 223                return __this_address;
 224
 225        /* No negative sizes or overly long symlink targets. */
 226        if (size < 0 || size > XFS_SYMLINK_MAXLEN)
 227                return __this_address;
 228
 229        /* No NULLs in the target either. */
 230        if (memchr(sfp, 0, size - 1))
 231                return __this_address;
 232
 233        /* We /did/ null-terminate the buffer, right? */
 234        if (*endp != 0)
 235                return __this_address;
 236        return NULL;
 237}
 238