1 /*- 2 * Copyright (c) 2017, Fedor Uporov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/types.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/vnode.h> 35 #include <sys/bio.h> 36 #include <sys/buf.h> 37 #include <sys/endian.h> 38 #include <sys/conf.h> 39 #include <sys/extattr.h> 40 41 #include <fs/ext2fs/fs.h> 42 #include <fs/ext2fs/ext2fs.h> 43 #include <fs/ext2fs/inode.h> 44 #include <fs/ext2fs/ext2_dinode.h> 45 #include <fs/ext2fs/ext2_mount.h> 46 #include <fs/ext2fs/ext2_extattr.h> 47 48 49 static int 50 ext2_extattr_index_to_bsd(int index) 51 { 52 switch (index) { 53 case EXT4_XATTR_INDEX_USER: 54 return EXTATTR_NAMESPACE_USER; 55 56 case EXT4_XATTR_INDEX_SYSTEM: 57 return EXTATTR_NAMESPACE_SYSTEM; 58 59 default: 60 return EXTATTR_NAMESPACE_EMPTY; 61 } 62 } 63 64 int 65 ext2_extattr_inode_list(struct inode *ip, int attrnamespace, 66 struct uio *uio, size_t *size) 67 { 68 struct m_ext2fs *fs; 69 struct buf *bp; 70 struct ext2fs_extattr_dinode_header *header; 71 struct ext2fs_extattr_entry *entry; 72 struct ext2fs_extattr_entry *next; 73 char *end; 74 int error; 75 76 fs = ip->i_e2fs; 77 78 if ((error = bread(ip->i_devvp, 79 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 80 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 81 brelse(bp); 82 return (error); 83 } 84 85 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 86 ((char *)bp->b_data + 87 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 88 89 /* Check attributes magic value */ 90 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 91 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 92 93 if (header->h_magic != EXTATTR_MAGIC) { 94 brelse(bp); 95 return (0); 96 } 97 98 /* Check attributes integrity */ 99 entry = EXT2_IFIRST(header); 100 end = (char *)dinode + EXT2_INODE_SIZE(fs); 101 while (!EXT2_IS_LAST_ENTRY(entry)) { 102 next = EXT2_EXTATTR_NEXT(entry); 103 if ((char *)next >= end) { 104 brelse(bp); 105 return (EIO); 106 } 107 108 entry = next; 109 } 110 111 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 112 entry = EXT2_EXTATTR_NEXT(entry)) { 113 if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) 114 continue; 115 116 if (uio == NULL) 117 *size += entry->e_name_len + 1; 118 else { 119 char *attr_name = malloc(entry->e_name_len + 1, M_TEMP, M_WAITOK); 120 attr_name[0] = entry->e_name_len; 121 memcpy(&attr_name[1], entry->e_name, entry->e_name_len); 122 error = uiomove(attr_name, entry->e_name_len + 1, uio); 123 free(attr_name, M_TEMP); 124 } 125 } 126 127 brelse(bp); 128 129 return (0); 130 } 131 132 int 133 ext2_extattr_block_list(struct inode *ip, int attrnamespace, 134 struct uio *uio, size_t *size) 135 { 136 struct m_ext2fs *fs; 137 struct buf *bp; 138 struct ext2fs_extattr_header *header; 139 struct ext2fs_extattr_entry *entry; 140 struct ext2fs_extattr_entry *next; 141 char *end; 142 int error; 143 144 fs = ip->i_e2fs; 145 146 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 147 fs->e2fs_bsize, NOCRED, &bp); 148 if (error) { 149 brelse(bp); 150 return (error); 151 } 152 153 /* Check attributes magic value */ 154 header = EXT2_HDR(bp); 155 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 156 brelse(bp); 157 return (EINVAL); 158 } 159 160 /* Check attributes integrity */ 161 end = bp->b_data + bp->b_bufsize; 162 entry = EXT2_FIRST_ENTRY(bp); 163 while (!EXT2_IS_LAST_ENTRY(entry)) { 164 next = EXT2_EXTATTR_NEXT(entry); 165 if ((char *)next >= end) { 166 brelse(bp); 167 return (EIO); 168 } 169 170 entry = next; 171 } 172 173 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 174 entry = EXT2_EXTATTR_NEXT(entry)) { 175 if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) 176 continue; 177 178 if (uio == NULL) 179 *size += entry->e_name_len + 1; 180 else { 181 char *attr_name = malloc(entry->e_name_len + 1, M_TEMP, M_WAITOK); 182 attr_name[0] = entry->e_name_len; 183 memcpy(&attr_name[1], entry->e_name, entry->e_name_len); 184 error = uiomove(attr_name, entry->e_name_len + 1, uio); 185 free(attr_name, M_TEMP); 186 } 187 } 188 189 brelse(bp); 190 191 return (0); 192 } 193 194 int 195 ext2_extattr_inode_get(struct inode *ip, int attrnamespace, 196 const char *name, struct uio *uio, size_t *size) 197 { 198 struct m_ext2fs *fs; 199 struct buf *bp; 200 struct ext2fs_extattr_dinode_header *header; 201 struct ext2fs_extattr_entry *entry; 202 struct ext2fs_extattr_entry *next; 203 char *end; 204 int error; 205 206 fs = ip->i_e2fs; 207 208 if ((error = bread(ip->i_devvp, 209 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 210 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 211 brelse(bp); 212 return (error); 213 } 214 215 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 216 ((char *)bp->b_data + 217 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 218 219 /* Check attributes magic value */ 220 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 221 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 222 223 if (header->h_magic != EXTATTR_MAGIC) { 224 brelse(bp); 225 return (0); 226 } 227 228 /* Check attributes integrity */ 229 entry = EXT2_IFIRST(header); 230 end = (char *)dinode + EXT2_INODE_SIZE(fs); 231 while (!EXT2_IS_LAST_ENTRY(entry)) { 232 next = EXT2_EXTATTR_NEXT(entry); 233 if ((char *)next >= end) { 234 brelse(bp); 235 return (EIO); 236 } 237 238 entry = next; 239 } 240 241 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 242 entry = EXT2_EXTATTR_NEXT(entry)) { 243 if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) 244 continue; 245 246 if (strlen(name) == entry->e_name_len && 247 0 == strncmp(entry->e_name, name, entry->e_name_len)) { 248 if (uio == NULL) 249 *size += entry->e_value_size; 250 else { 251 error = uiomove(((char *)EXT2_IFIRST(header)) + entry->e_value_offs, 252 entry->e_value_size, uio); 253 if (error) { 254 brelse(bp); 255 return (error); 256 } 257 } 258 } 259 } 260 261 brelse(bp); 262 263 return (0); 264 } 265 266 int 267 ext2_extattr_block_get(struct inode *ip, int attrnamespace, 268 const char *name, struct uio *uio, size_t *size) 269 { 270 struct m_ext2fs *fs; 271 struct buf *bp; 272 struct ext2fs_extattr_header *header; 273 struct ext2fs_extattr_entry *entry; 274 struct ext2fs_extattr_entry *next; 275 char *end; 276 int error; 277 278 fs = ip->i_e2fs; 279 280 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 281 fs->e2fs_bsize, NOCRED, &bp); 282 if (error) { 283 brelse(bp); 284 return (error); 285 } 286 287 /* Check attributes magic value */ 288 header = EXT2_HDR(bp); 289 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 290 brelse(bp); 291 return (EINVAL); 292 } 293 294 /* Check attributes integrity */ 295 end = bp->b_data + bp->b_bufsize; 296 entry = EXT2_FIRST_ENTRY(bp); 297 while (!EXT2_IS_LAST_ENTRY(entry)) { 298 next = EXT2_EXTATTR_NEXT(entry); 299 if ((char *)next >= end) { 300 brelse(bp); 301 return (EIO); 302 } 303 304 entry = next; 305 } 306 307 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 308 entry = EXT2_EXTATTR_NEXT(entry)) { 309 if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) 310 continue; 311 312 if (strlen(name) == entry->e_name_len && 313 0 == strncmp(entry->e_name, name, entry->e_name_len)) { 314 if (uio == NULL) 315 *size += entry->e_value_size; 316 else { 317 error = uiomove(bp->b_data + entry->e_value_offs, 318 entry->e_value_size, uio); 319 if (error) { 320 brelse(bp); 321 return (error); 322 } 323 } 324 } 325 } 326 327 brelse(bp); 328 329 return (0); 330 } 331