]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_symlink_remote.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_symlink_remote.c
CommitLineData
37b3b4d6 1// SPDX-License-Identifier: GPL-2.0
9f76c5b5 2/*
270b1db1
DC
3 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
4 * Copyright (c) 2012-2013 Red Hat, Inc.
9f76c5b5
DC
5 * All rights reserved.
6 */
9c799827 7#include "libxfs_priv.h"
b626fb59
DC
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_bmap_btree.h"
15#include "xfs_inode.h"
16#include "xfs_trace.h"
17#include "xfs_cksum.h"
18#include "xfs_trans.h"
19
9f76c5b5
DC
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{
2019931a 30 int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
9f76c5b5 31
2019931a 32 return (pathlen + buflen - 1) / buflen;
9f76c5b5
DC
33}
34
f7b80291 35int
9f76c5b5
DC
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
a65d8d29 48 memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
9f76c5b5
DC
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);
9c4e12fb 52 uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
9f76c5b5
DC
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(
9f76c5b5
DC
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;
9f76c5b5
DC
83}
84
bc01119d 85static xfs_failaddr_t
9f76c5b5
DC
86xfs_symlink_verify(
87 struct xfs_buf *bp)
88{
89 struct xfs_mount *mp = bp->b_target->bt_mount;
90 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
91
92 if (!xfs_sb_version_hascrc(&mp->m_sb))
bc01119d 93 return __this_address;
9f76c5b5 94 if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
bc01119d 95 return __this_address;
9c4e12fb 96 if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
bc01119d 97 return __this_address;
9f76c5b5 98 if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
bc01119d 99 return __this_address;
9f76c5b5 100 if (be32_to_cpu(dsl->sl_offset) +
b8fb8c95 101 be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
bc01119d 102 return __this_address;
9f76c5b5 103 if (dsl->sl_owner == 0)
bc01119d 104 return __this_address;
a65d8d29 105 if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
bc01119d 106 return __this_address;
9f76c5b5 107
bc01119d 108 return NULL;
9f76c5b5
DC
109}
110
111static void
112xfs_symlink_read_verify(
113 struct xfs_buf *bp)
114{
115 struct xfs_mount *mp = bp->b_target->bt_mount;
1e697959 116 xfs_failaddr_t fa;
9f76c5b5
DC
117
118 /* no verification of non-crc buffers */
119 if (!xfs_sb_version_hascrc(&mp->m_sb))
120 return;
121
45922933 122 if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
1e697959
DW
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 }
9f76c5b5
DC
129}
130
131static void
132xfs_symlink_write_verify(
133 struct xfs_buf *bp)
134{
135 struct xfs_mount *mp = bp->b_target->bt_mount;
37d086ca 136 struct xfs_buf_log_item *bip = bp->b_log_item;
1e697959 137 xfs_failaddr_t fa;
9f76c5b5
DC
138
139 /* no verification of non-crc buffers */
140 if (!xfs_sb_version_hascrc(&mp->m_sb))
141 return;
142
1e697959
DW
143 fa = xfs_symlink_verify(bp);
144 if (fa) {
145 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
9f76c5b5
DC
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 }
43b5aeed 153 xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
9f76c5b5
DC
154}
155
156const struct xfs_buf_ops xfs_symlink_buf_ops = {
a3fac935 157 .name = "xfs_symlink",
9f76c5b5
DC
158 .verify_read = xfs_symlink_read_verify,
159 .verify_write = xfs_symlink_write_verify,
95d9582b 160 .verify_struct = xfs_symlink_verify,
9f76c5b5
DC
161};
162
88b66843
DC
163void
164xfs_symlink_local_to_remote(
165 struct xfs_trans *tp,
166 struct xfs_buf *bp,
167 struct xfs_inode *ip,
168 struct xfs_ifork *ifp)
169{
170 struct xfs_mount *mp = ip->i_mount;
171 char *buf;
172
19ebedcf
DC
173 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
174
88b66843
DC
175 if (!xfs_sb_version_hascrc(&mp->m_sb)) {
176 bp->b_ops = NULL;
177 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
f44fbde0 178 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
88b66843
DC
179 return;
180 }
181
182 /*
183 * As this symlink fits in an inode literal area, it must also fit in
184 * the smallest buffer the filesystem supports.
185 */
186 ASSERT(BBTOB(bp->b_length) >=
187 ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
188
189 bp->b_ops = &xfs_symlink_buf_ops;
190
191 buf = bp->b_addr;
192 buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
193 memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
f44fbde0
BF
194 xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
195 ifp->if_bytes - 1);
88b66843 196}
6db3a800 197
bf64a47a
DC
198/*
199 * Verify the in-memory consistency of an inline symlink data fork. This
200 * does not do on-disk format checks.
201 */
6db3a800
DW
202xfs_failaddr_t
203xfs_symlink_shortform_verify(
204 struct xfs_inode *ip)
205{
206 char *sfp;
207 char *endp;
208 struct xfs_ifork *ifp;
209 int size;
210
211 ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
212 ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
213 sfp = (char *)ifp->if_u1.if_data;
214 size = ifp->if_bytes;
215 endp = sfp + size;
216
bf64a47a
DC
217 /*
218 * Zero length symlinks should never occur in memory as they are
219 * never alllowed to exist on disk.
220 */
221 if (!size)
222 return __this_address;
6db3a800
DW
223
224 /* No negative sizes or overly long symlink targets. */
225 if (size < 0 || size > XFS_SYMLINK_MAXLEN)
226 return __this_address;
227
228 /* No NULLs in the target either. */
229 if (memchr(sfp, 0, size - 1))
230 return __this_address;
231
232 /* We /did/ null-terminate the buffer, right? */
233 if (*endp != 0)
234 return __this_address;
235 return NULL;
236}