]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_symlink_remote.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_symlink_remote.c
index 3b4c6abba9f54653c122f9d6d4e380e3a451b788..db58eb4eee1218be56f47244d010f6719c262e13 100644 (file)
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * Copyright (c) 2012-2013 Red Hat, Inc.
  * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "libxfs_priv.h"
 #include "xfs_fs.h"
@@ -94,7 +82,7 @@ xfs_symlink_hdr_ok(
        return true;
 }
 
-static bool
+static xfs_failaddr_t
 xfs_symlink_verify(
        struct xfs_buf          *bp)
 {
@@ -102,22 +90,22 @@ xfs_symlink_verify(
        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 
        if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return false;
+               return __this_address;
        if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
-               return false;
+               return __this_address;
        if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
-               return false;
+               return __this_address;
        if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
-               return false;
+               return __this_address;
        if (be32_to_cpu(dsl->sl_offset) +
                                be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
-               return false;
+               return __this_address;
        if (dsl->sl_owner == 0)
-               return false;
+               return __this_address;
        if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
-               return false;
+               return __this_address;
 
-       return true;
+       return NULL;
 }
 
 static void
@@ -125,15 +113,19 @@ xfs_symlink_read_verify(
        struct xfs_buf  *bp)
 {
        struct xfs_mount *mp = bp->b_target->bt_mount;
+       xfs_failaddr_t  fa;
 
        /* no verification of non-crc buffers */
        if (!xfs_sb_version_hascrc(&mp->m_sb))
                return;
 
        if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
-               xfs_verifier_error(bp, -EFSBADCRC);
-       else if (!xfs_symlink_verify(bp))
-               xfs_verifier_error(bp, -EFSCORRUPTED);
+               xfs_verifier_error(bp, -EFSBADCRC, __this_address);
+       else {
+               fa = xfs_symlink_verify(bp);
+               if (fa)
+                       xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+       }
 }
 
 static void
@@ -141,14 +133,16 @@ xfs_symlink_write_verify(
        struct xfs_buf  *bp)
 {
        struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       struct xfs_buf_log_item *bip = bp->b_log_item;
+       xfs_failaddr_t          fa;
 
        /* no verification of non-crc buffers */
        if (!xfs_sb_version_hascrc(&mp->m_sb))
                return;
 
-       if (!xfs_symlink_verify(bp)) {
-               xfs_verifier_error(bp, -EFSCORRUPTED);
+       fa = xfs_symlink_verify(bp);
+       if (fa) {
+               xfs_verifier_error(bp, -EFSCORRUPTED, fa);
                return;
        }
 
@@ -163,6 +157,7 @@ const struct xfs_buf_ops xfs_symlink_buf_ops = {
        .name = "xfs_symlink",
        .verify_read = xfs_symlink_read_verify,
        .verify_write = xfs_symlink_write_verify,
+       .verify_struct = xfs_symlink_verify,
 };
 
 void
@@ -199,3 +194,43 @@ xfs_symlink_local_to_remote(
        xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
                                        ifp->if_bytes - 1);
 }
+
+/*
+ * Verify the in-memory consistency of an inline symlink data fork. This
+ * does not do on-disk format checks.
+ */
+xfs_failaddr_t
+xfs_symlink_shortform_verify(
+       struct xfs_inode        *ip)
+{
+       char                    *sfp;
+       char                    *endp;
+       struct xfs_ifork        *ifp;
+       int                     size;
+
+       ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
+       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       sfp = (char *)ifp->if_u1.if_data;
+       size = ifp->if_bytes;
+       endp = sfp + size;
+
+       /*
+        * Zero length symlinks should never occur in memory as they are
+        * never alllowed to exist on disk.
+        */
+       if (!size)
+               return __this_address;
+
+       /* No negative sizes or overly long symlink targets. */
+       if (size < 0 || size > XFS_SYMLINK_MAXLEN)
+               return __this_address;
+
+       /* No NULLs in the target either. */
+       if (memchr(sfp, 0, size - 1))
+               return __this_address;
+
+       /* We /did/ null-terminate the buffer, right? */
+       if (*endp != 0)
+               return __this_address;
+       return NULL;
+}