1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2017, Fedor Uporov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 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 #include <sys/sdt.h> 41 42 #include <fs/ext2fs/fs.h> 43 #include <fs/ext2fs/ext2fs.h> 44 #include <fs/ext2fs/inode.h> 45 #include <fs/ext2fs/ext2_dinode.h> 46 #include <fs/ext2fs/ext2_mount.h> 47 #include <fs/ext2fs/ext2_extattr.h> 48 #include <fs/ext2fs/ext2_extern.h> 49 50 SDT_PROVIDER_DECLARE(ext2fs); 51 /* 52 * ext2fs trace probe: 53 * arg0: verbosity. Higher numbers give more verbose messages 54 * arg1: Textual message 55 */ 56 SDT_PROBE_DEFINE2(ext2fs, , trace, extattr, "int", "char*"); 57 58 static int 59 ext2_extattr_attrnamespace_to_bsd(int attrnamespace) 60 { 61 62 switch (attrnamespace) { 63 case EXT4_XATTR_INDEX_SYSTEM: 64 return (EXTATTR_NAMESPACE_SYSTEM); 65 66 case EXT4_XATTR_INDEX_USER: 67 return (EXTATTR_NAMESPACE_USER); 68 69 case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT: 70 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE); 71 72 case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS: 73 return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE); 74 } 75 76 return (EXTATTR_NAMESPACE_EMPTY); 77 } 78 79 static const char * 80 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len) 81 { 82 83 if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM) 84 return (name); 85 else if (attrnamespace == EXT4_XATTR_INDEX_USER) 86 return (name); 87 else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) { 88 *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME); 89 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME); 90 } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) { 91 *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME); 92 return (POSIX1E_ACL_ACCESS_EXTATTR_NAME); 93 } 94 95 /* 96 * XXX: Not all linux namespaces are mapped to bsd for now, 97 * return NULL, which will be converted to ENOTSUP on upper layer. 98 */ 99 SDT_PROBE2(ext2fs, , trace, extattr, 1, 100 "can not convert ext2fs name to bsd namespace"); 101 102 return (NULL); 103 } 104 105 static int 106 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name) 107 { 108 109 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE && 110 !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) 111 return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT); 112 113 if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE && 114 !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) 115 return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS); 116 117 switch (attrnamespace) { 118 case EXTATTR_NAMESPACE_SYSTEM: 119 return (EXT4_XATTR_INDEX_SYSTEM); 120 121 case EXTATTR_NAMESPACE_USER: 122 return (EXT4_XATTR_INDEX_USER); 123 } 124 125 /* 126 * In this case namespace conversion should be unique, 127 * so this point is unreachable. 128 */ 129 return (-1); 130 } 131 132 static const char * 133 ext2_extattr_name_to_linux(int attrnamespace, const char *name) 134 { 135 136 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE || 137 attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE) 138 return (""); 139 else 140 return (name); 141 } 142 143 int 144 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname) 145 { 146 if (attrnamespace == EXTATTR_NAMESPACE_EMPTY) 147 return (EINVAL); 148 149 if (strlen(attrname) == 0) 150 return (EINVAL); 151 152 if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX) 153 return (ENAMETOOLONG); 154 155 return (0); 156 } 157 158 static int 159 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end) 160 { 161 struct ext2fs_extattr_entry *next; 162 163 while (!EXT2_IS_LAST_ENTRY(entry)) { 164 next = EXT2_EXTATTR_NEXT(entry); 165 if ((char *)next >= end) 166 return (EIO); 167 168 entry = next; 169 } 170 171 return (0); 172 } 173 174 static int 175 ext2_extattr_block_check(struct inode *ip, struct buf *bp) 176 { 177 struct ext2fs_extattr_header *header; 178 int error; 179 180 header = (struct ext2fs_extattr_header *)bp->b_data; 181 182 error = ext2_extattr_check(EXT2_IFIRST(header), 183 bp->b_data + bp->b_bufsize); 184 if (error) 185 return (error); 186 187 return (ext2_extattr_blk_csum_verify(ip, bp)); 188 } 189 190 int 191 ext2_extattr_inode_list(struct inode *ip, int attrnamespace, 192 struct uio *uio, size_t *size) 193 { 194 struct m_ext2fs *fs; 195 struct buf *bp; 196 struct ext2fs_extattr_dinode_header *header; 197 struct ext2fs_extattr_entry *entry; 198 const char *attr_name; 199 int name_len; 200 int error; 201 202 fs = ip->i_e2fs; 203 204 if ((error = bread(ip->i_devvp, 205 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 206 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 207 brelse(bp); 208 return (error); 209 } 210 211 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 212 ((char *)bp->b_data + 213 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 214 215 /* Check attributes magic value */ 216 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 217 E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize)); 218 219 if (le32toh(header->h_magic) != EXTATTR_MAGIC) { 220 brelse(bp); 221 return (0); 222 } 223 224 error = ext2_extattr_check(EXT2_IFIRST(header), 225 (char *)dinode + EXT2_INODE_SIZE(fs)); 226 if (error) { 227 brelse(bp); 228 return (error); 229 } 230 231 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 232 entry = EXT2_EXTATTR_NEXT(entry)) { 233 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 234 attrnamespace) 235 continue; 236 237 name_len = entry->e_name_len; 238 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 239 entry->e_name, &name_len); 240 if (!attr_name) { 241 brelse(bp); 242 return (ENOTSUP); 243 } 244 245 if (size != NULL) 246 *size += name_len + 1; 247 248 if (uio != NULL) { 249 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK); 250 name[0] = name_len; 251 memcpy(&name[1], attr_name, name_len); 252 error = uiomove(name, name_len + 1, uio); 253 free(name, M_TEMP); 254 if (error) 255 break; 256 } 257 } 258 259 brelse(bp); 260 261 return (error); 262 } 263 264 int 265 ext2_extattr_block_list(struct inode *ip, int attrnamespace, 266 struct uio *uio, size_t *size) 267 { 268 struct m_ext2fs *fs; 269 struct buf *bp; 270 struct ext2fs_extattr_header *header; 271 struct ext2fs_extattr_entry *entry; 272 const char *attr_name; 273 int name_len; 274 int error; 275 276 fs = ip->i_e2fs; 277 278 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 279 fs->e2fs_bsize, NOCRED, &bp); 280 if (error) { 281 return (error); 282 } 283 284 /* Check attributes magic value */ 285 header = EXT2_HDR(bp); 286 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 287 le32toh(header->h_blocks) != 1) { 288 brelse(bp); 289 return (EINVAL); 290 } 291 292 error = ext2_extattr_block_check(ip, bp); 293 if (error) { 294 brelse(bp); 295 return (error); 296 } 297 298 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 299 entry = EXT2_EXTATTR_NEXT(entry)) { 300 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 301 attrnamespace) 302 continue; 303 304 name_len = entry->e_name_len; 305 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 306 entry->e_name, &name_len); 307 if (!attr_name) { 308 brelse(bp); 309 return (ENOTSUP); 310 } 311 312 if (size != NULL) 313 *size += name_len + 1; 314 315 if (uio != NULL) { 316 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK); 317 name[0] = name_len; 318 memcpy(&name[1], attr_name, name_len); 319 error = uiomove(name, name_len + 1, uio); 320 free(name, M_TEMP); 321 if (error) 322 break; 323 } 324 } 325 326 brelse(bp); 327 328 return (error); 329 } 330 331 int 332 ext2_extattr_inode_get(struct inode *ip, int attrnamespace, 333 const char *name, struct uio *uio, size_t *size) 334 { 335 struct m_ext2fs *fs; 336 struct buf *bp; 337 struct ext2fs_extattr_dinode_header *header; 338 struct ext2fs_extattr_entry *entry; 339 const char *attr_name; 340 int name_len; 341 int error; 342 343 fs = ip->i_e2fs; 344 345 if ((error = bread(ip->i_devvp, 346 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 347 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 348 brelse(bp); 349 return (error); 350 } 351 352 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 353 ((char *)bp->b_data + 354 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 355 356 /* Check attributes magic value */ 357 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 358 E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize)); 359 360 if (le32toh(header->h_magic) != EXTATTR_MAGIC) { 361 brelse(bp); 362 return (ENOATTR); 363 } 364 365 error = ext2_extattr_check(EXT2_IFIRST(header), 366 (char *)dinode + EXT2_INODE_SIZE(fs)); 367 if (error) { 368 brelse(bp); 369 return (error); 370 } 371 372 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 373 entry = EXT2_EXTATTR_NEXT(entry)) { 374 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 375 attrnamespace) 376 continue; 377 378 name_len = entry->e_name_len; 379 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 380 entry->e_name, &name_len); 381 if (!attr_name) { 382 brelse(bp); 383 return (ENOTSUP); 384 } 385 386 if (strlen(name) == name_len && 387 0 == strncmp(attr_name, name, name_len)) { 388 if (size != NULL) 389 *size += le32toh(entry->e_value_size); 390 391 if (uio != NULL) 392 error = uiomove(((char *)EXT2_IFIRST(header)) + 393 le16toh(entry->e_value_offs), 394 le32toh(entry->e_value_size), uio); 395 396 brelse(bp); 397 return (error); 398 } 399 } 400 401 brelse(bp); 402 403 return (ENOATTR); 404 } 405 406 int 407 ext2_extattr_block_get(struct inode *ip, int attrnamespace, 408 const char *name, struct uio *uio, size_t *size) 409 { 410 struct m_ext2fs *fs; 411 struct buf *bp; 412 struct ext2fs_extattr_header *header; 413 struct ext2fs_extattr_entry *entry; 414 const char *attr_name; 415 int name_len; 416 int error; 417 418 fs = ip->i_e2fs; 419 420 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 421 fs->e2fs_bsize, NOCRED, &bp); 422 if (error) { 423 return (error); 424 } 425 426 /* Check attributes magic value */ 427 header = EXT2_HDR(bp); 428 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 429 le32toh(header->h_blocks) != 1) { 430 brelse(bp); 431 return (EINVAL); 432 } 433 434 error = ext2_extattr_block_check(ip, bp); 435 if (error) { 436 brelse(bp); 437 return (error); 438 } 439 440 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 441 entry = EXT2_EXTATTR_NEXT(entry)) { 442 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 443 attrnamespace) 444 continue; 445 446 name_len = entry->e_name_len; 447 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 448 entry->e_name, &name_len); 449 if (!attr_name) { 450 brelse(bp); 451 return (ENOTSUP); 452 } 453 454 if (strlen(name) == name_len && 455 0 == strncmp(attr_name, name, name_len)) { 456 if (size != NULL) 457 *size += le32toh(entry->e_value_size); 458 459 if (uio != NULL) 460 error = uiomove(bp->b_data + 461 le16toh(entry->e_value_offs), 462 le32toh(entry->e_value_size), uio); 463 464 brelse(bp); 465 return (error); 466 } 467 } 468 469 brelse(bp); 470 471 return (ENOATTR); 472 } 473 474 static uint16_t 475 ext2_extattr_delete_value(char *off, 476 struct ext2fs_extattr_entry *first_entry, 477 struct ext2fs_extattr_entry *entry, char *end) 478 { 479 uint16_t min_offs; 480 struct ext2fs_extattr_entry *next; 481 482 min_offs = end - off; 483 next = first_entry; 484 while (!EXT2_IS_LAST_ENTRY(next)) { 485 if (min_offs > le16toh(next->e_value_offs) && 486 le16toh(next->e_value_offs) > 0) 487 min_offs = le16toh(next->e_value_offs); 488 489 next = EXT2_EXTATTR_NEXT(next); 490 } 491 492 if (entry->e_value_size == 0) 493 return (min_offs); 494 495 memmove(off + min_offs + EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)), 496 off + min_offs, le16toh(entry->e_value_offs) - min_offs); 497 498 /* Adjust all value offsets */ 499 next = first_entry; 500 while (!EXT2_IS_LAST_ENTRY(next)) 501 { 502 if (le16toh(next->e_value_offs) > 0 && 503 le16toh(next->e_value_offs) < le16toh(entry->e_value_offs)) 504 next->e_value_offs = htole16(le16toh(next->e_value_offs) + 505 EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size))); 506 507 next = EXT2_EXTATTR_NEXT(next); 508 } 509 510 min_offs += EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)); 511 512 return (min_offs); 513 } 514 515 static void 516 ext2_extattr_delete_entry(char *off, 517 struct ext2fs_extattr_entry *first_entry, 518 struct ext2fs_extattr_entry *entry, char *end) 519 { 520 char *pad; 521 struct ext2fs_extattr_entry *next; 522 523 /* Clean entry value */ 524 ext2_extattr_delete_value(off, first_entry, entry, end); 525 526 /* Clean the entry */ 527 next = first_entry; 528 while (!EXT2_IS_LAST_ENTRY(next)) 529 next = EXT2_EXTATTR_NEXT(next); 530 531 pad = (char*)next + sizeof(uint32_t); 532 533 memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len), 534 pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len))); 535 } 536 537 int 538 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name) 539 { 540 struct m_ext2fs *fs; 541 struct buf *bp; 542 struct ext2fs_extattr_dinode_header *header; 543 struct ext2fs_extattr_entry *entry; 544 const char *attr_name; 545 int name_len; 546 int error; 547 548 fs = ip->i_e2fs; 549 550 if ((error = bread(ip->i_devvp, 551 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 552 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 553 brelse(bp); 554 return (error); 555 } 556 557 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 558 ((char *)bp->b_data + 559 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 560 561 /* Check attributes magic value */ 562 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 563 E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize)); 564 565 if (le32toh(header->h_magic) != EXTATTR_MAGIC) { 566 brelse(bp); 567 return (ENOATTR); 568 } 569 570 error = ext2_extattr_check(EXT2_IFIRST(header), 571 (char *)dinode + EXT2_INODE_SIZE(fs)); 572 if (error) { 573 brelse(bp); 574 return (error); 575 } 576 577 /* If I am last entry, just make magic zero */ 578 entry = EXT2_IFIRST(header); 579 if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) && 580 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) == 581 attrnamespace)) { 582 name_len = entry->e_name_len; 583 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 584 entry->e_name, &name_len); 585 if (!attr_name) { 586 brelse(bp); 587 return (ENOTSUP); 588 } 589 590 if (strlen(name) == name_len && 591 0 == strncmp(attr_name, name, name_len)) { 592 memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header)); 593 594 return (bwrite(bp)); 595 } 596 } 597 598 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 599 entry = EXT2_EXTATTR_NEXT(entry)) { 600 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 601 attrnamespace) 602 continue; 603 604 name_len = entry->e_name_len; 605 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 606 entry->e_name, &name_len); 607 if (!attr_name) { 608 brelse(bp); 609 return (ENOTSUP); 610 } 611 612 if (strlen(name) == name_len && 613 0 == strncmp(attr_name, name, name_len)) { 614 ext2_extattr_delete_entry((char *)EXT2_IFIRST(header), 615 EXT2_IFIRST(header), entry, 616 (char *)dinode + EXT2_INODE_SIZE(fs)); 617 618 return (bwrite(bp)); 619 } 620 } 621 622 brelse(bp); 623 624 return (ENOATTR); 625 } 626 627 static int 628 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp) 629 { 630 struct m_ext2fs *fs; 631 struct buf *sbp; 632 struct buf *cbp; 633 struct ext2fs_extattr_header *header; 634 uint64_t facl; 635 636 fs = ip->i_e2fs; 637 sbp = *bpp; 638 639 header = EXT2_HDR(sbp); 640 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 641 le32toh(header->h_refcount) == 1) 642 return (EINVAL); 643 644 facl = ext2_alloc_meta(ip); 645 if (!facl) 646 return (ENOSPC); 647 648 cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0); 649 if (!cbp) { 650 ext2_blkfree(ip, facl, fs->e2fs_bsize); 651 return (EIO); 652 } 653 654 memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize); 655 header->h_refcount = htole32(le32toh(header->h_refcount) - 1); 656 bwrite(sbp); 657 658 ip->i_facl = facl; 659 ext2_update(ip->i_vnode, 1); 660 661 header = EXT2_HDR(cbp); 662 header->h_refcount = htole32(1); 663 664 *bpp = cbp; 665 666 return (0); 667 } 668 669 int 670 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name) 671 { 672 struct m_ext2fs *fs; 673 struct buf *bp; 674 struct ext2fs_extattr_header *header; 675 struct ext2fs_extattr_entry *entry; 676 const char *attr_name; 677 int name_len; 678 int error; 679 680 fs = ip->i_e2fs; 681 682 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 683 fs->e2fs_bsize, NOCRED, &bp); 684 if (error) { 685 return (error); 686 } 687 688 /* Check attributes magic value */ 689 header = EXT2_HDR(bp); 690 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 691 le32toh(header->h_blocks) != 1) { 692 brelse(bp); 693 return (EINVAL); 694 } 695 696 error = ext2_extattr_block_check(ip, bp); 697 if (error) { 698 brelse(bp); 699 return (error); 700 } 701 702 if (le32toh(header->h_refcount) > 1) { 703 error = ext2_extattr_block_clone(ip, &bp); 704 if (error) { 705 brelse(bp); 706 return (error); 707 } 708 } 709 710 /* If I am last entry, clean me and free the block */ 711 entry = EXT2_FIRST_ENTRY(bp); 712 if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) && 713 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) == 714 attrnamespace)) { 715 name_len = entry->e_name_len; 716 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 717 entry->e_name, &name_len); 718 if (!attr_name) { 719 brelse(bp); 720 return (ENOTSUP); 721 } 722 723 if (strlen(name) == name_len && 724 0 == strncmp(attr_name, name, name_len)) { 725 ip->i_blocks -= btodb(fs->e2fs_bsize); 726 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize); 727 ip->i_facl = 0; 728 error = ext2_update(ip->i_vnode, 1); 729 730 brelse(bp); 731 return (error); 732 } 733 } 734 735 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 736 entry = EXT2_EXTATTR_NEXT(entry)) { 737 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 738 attrnamespace) 739 continue; 740 741 name_len = entry->e_name_len; 742 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 743 entry->e_name, &name_len); 744 if (!attr_name) { 745 brelse(bp); 746 return (ENOTSUP); 747 } 748 749 if (strlen(name) == name_len && 750 0 == strncmp(attr_name, name, name_len)) { 751 ext2_extattr_delete_entry(bp->b_data, 752 EXT2_FIRST_ENTRY(bp), entry, 753 bp->b_data + bp->b_bufsize); 754 755 return (bwrite(bp)); 756 } 757 } 758 759 brelse(bp); 760 761 return (ENOATTR); 762 } 763 764 static struct ext2fs_extattr_entry * 765 allocate_entry(const char *name, int attrnamespace, uint16_t offs, 766 uint32_t size, uint32_t hash) 767 { 768 const char *attr_name; 769 int name_len; 770 struct ext2fs_extattr_entry *entry; 771 772 attr_name = ext2_extattr_name_to_linux(attrnamespace, name); 773 name_len = strlen(attr_name); 774 775 entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len, 776 M_TEMP, M_WAITOK); 777 778 entry->e_name_len = name_len; 779 entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name); 780 entry->e_value_offs = htole16(offs); 781 entry->e_value_block = 0; 782 entry->e_value_size = htole32(size); 783 entry->e_hash = htole32(hash); 784 memcpy(entry->e_name, name, name_len); 785 786 return (entry); 787 } 788 789 static void 790 free_entry(struct ext2fs_extattr_entry *entry) 791 { 792 793 free(entry, M_TEMP); 794 } 795 796 static int 797 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry, 798 struct ext2fs_extattr_entry *exist_entry, int header_size, 799 int name_len, int new_size) 800 { 801 struct ext2fs_extattr_entry *entry; 802 int size; 803 804 size = header_size; 805 size += sizeof(uint32_t); 806 807 if (NULL == exist_entry) { 808 size += EXT2_EXTATTR_LEN(name_len); 809 size += EXT2_EXTATTR_SIZE(new_size); 810 } 811 812 if (first_entry) 813 for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry); 814 entry = EXT2_EXTATTR_NEXT(entry)) { 815 if (entry != exist_entry) 816 size += EXT2_EXTATTR_LEN(entry->e_name_len) + 817 EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)); 818 else 819 size += EXT2_EXTATTR_LEN(entry->e_name_len) + 820 EXT2_EXTATTR_SIZE(new_size); 821 } 822 823 return (size); 824 } 825 826 static void 827 ext2_extattr_set_exist_entry(char *off, 828 struct ext2fs_extattr_entry *first_entry, 829 struct ext2fs_extattr_entry *entry, 830 char *end, struct uio *uio) 831 { 832 uint16_t min_offs; 833 834 min_offs = ext2_extattr_delete_value(off, first_entry, entry, end); 835 836 entry->e_value_size = htole32(uio->uio_resid); 837 if (le32toh(entry->e_value_size)) 838 entry->e_value_offs = htole16(min_offs - 839 EXT2_EXTATTR_SIZE(uio->uio_resid)); 840 else 841 entry->e_value_offs = 0; 842 843 uiomove(off + le16toh(entry->e_value_offs), 844 le32toh(entry->e_value_size), uio); 845 } 846 847 static struct ext2fs_extattr_entry * 848 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry, 849 const char *name, int attrnamespace, char *end, struct uio *uio) 850 { 851 int name_len; 852 char *pad; 853 uint16_t min_offs; 854 struct ext2fs_extattr_entry *entry; 855 struct ext2fs_extattr_entry *new_entry; 856 857 /* Find pad's */ 858 min_offs = end - off; 859 entry = first_entry; 860 while (!EXT2_IS_LAST_ENTRY(entry)) { 861 if (min_offs > le16toh(entry->e_value_offs) && 862 le16toh(entry->e_value_offs) > 0) 863 min_offs = le16toh(entry->e_value_offs); 864 865 entry = EXT2_EXTATTR_NEXT(entry); 866 } 867 868 pad = (char*)entry + sizeof(uint32_t); 869 870 /* Find entry insert position */ 871 name_len = strlen(name); 872 entry = first_entry; 873 while (!EXT2_IS_LAST_ENTRY(entry)) { 874 if (!(attrnamespace - entry->e_name_index) && 875 !(name_len - entry->e_name_len)) 876 if (memcmp(name, entry->e_name, name_len) <= 0) 877 break; 878 879 entry = EXT2_EXTATTR_NEXT(entry); 880 } 881 882 /* Create new entry and insert it */ 883 new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0); 884 memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry, 885 pad - (char*)entry); 886 887 memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len)); 888 free_entry(new_entry); 889 890 new_entry = entry; 891 if (le32toh(new_entry->e_value_size) > 0) 892 new_entry->e_value_offs = htole16(min_offs - 893 EXT2_EXTATTR_SIZE(le32toh(new_entry->e_value_size))); 894 895 uiomove(off + le16toh(new_entry->e_value_offs), 896 le32toh(new_entry->e_value_size), uio); 897 898 return (new_entry); 899 } 900 901 int 902 ext2_extattr_inode_set(struct inode *ip, int attrnamespace, 903 const char *name, struct uio *uio) 904 { 905 struct m_ext2fs *fs; 906 struct buf *bp; 907 struct ext2fs_extattr_dinode_header *header; 908 struct ext2fs_extattr_entry *entry; 909 const char *attr_name; 910 int name_len; 911 size_t size = 0, max_size; 912 int error; 913 914 fs = ip->i_e2fs; 915 916 if ((error = bread(ip->i_devvp, 917 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 918 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 919 brelse(bp); 920 return (error); 921 } 922 923 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 924 ((char *)bp->b_data + 925 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 926 927 /* Check attributes magic value */ 928 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 929 E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize)); 930 931 if (le32toh(header->h_magic) != EXTATTR_MAGIC) { 932 brelse(bp); 933 return (ENOSPC); 934 } 935 936 error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode + 937 EXT2_INODE_SIZE(fs)); 938 if (error) { 939 brelse(bp); 940 return (error); 941 } 942 943 /* Find if entry exist */ 944 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 945 entry = EXT2_EXTATTR_NEXT(entry)) { 946 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 947 attrnamespace) 948 continue; 949 950 name_len = entry->e_name_len; 951 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 952 entry->e_name, &name_len); 953 if (!attr_name) { 954 brelse(bp); 955 return (ENOTSUP); 956 } 957 958 if (strlen(name) == name_len && 959 0 == strncmp(attr_name, name, name_len)) 960 break; 961 } 962 963 max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE - 964 le16toh(dinode->e2di_extra_isize); 965 966 if (!EXT2_IS_LAST_ENTRY(entry)) { 967 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry, 968 sizeof(struct ext2fs_extattr_dinode_header), 969 entry->e_name_len, uio->uio_resid); 970 if (size > max_size) { 971 brelse(bp); 972 return (ENOSPC); 973 } 974 975 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header), 976 EXT2_IFIRST(header), entry, (char *)header + max_size, uio); 977 } else { 978 /* Ensure that the same entry does not exist in the block */ 979 if (ip->i_facl) { 980 error = ext2_extattr_block_get(ip, attrnamespace, name, 981 NULL, &size); 982 if (error != ENOATTR || size > 0) { 983 brelse(bp); 984 if (size > 0) 985 error = ENOSPC; 986 987 return (error); 988 } 989 } 990 991 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL, 992 sizeof(struct ext2fs_extattr_dinode_header), 993 entry->e_name_len, uio->uio_resid); 994 if (size > max_size) { 995 brelse(bp); 996 return (ENOSPC); 997 } 998 999 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header), 1000 EXT2_IFIRST(header), name, attrnamespace, 1001 (char *)header + max_size, uio); 1002 } 1003 1004 return (bwrite(bp)); 1005 } 1006 1007 static void 1008 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header, 1009 struct ext2fs_extattr_entry *entry) 1010 { 1011 uint32_t hash = 0; 1012 char *name = entry->e_name; 1013 int n; 1014 1015 for (n=0; n < entry->e_name_len; n++) { 1016 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^ 1017 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^ 1018 (*name++); 1019 } 1020 1021 if (entry->e_value_block == 0 && entry->e_value_size != 0) { 1022 uint32_t *value = (uint32_t *)((char *)header + 1023 le16toh(entry->e_value_offs)); 1024 for (n = (le32toh(entry->e_value_size) + 1025 EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) { 1026 hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^ 1027 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^ 1028 le32toh(*value++); 1029 } 1030 } 1031 1032 entry->e_hash = htole32(hash); 1033 } 1034 1035 static void 1036 ext2_extattr_rehash(struct ext2fs_extattr_header *header, 1037 struct ext2fs_extattr_entry *entry) 1038 { 1039 struct ext2fs_extattr_entry *here; 1040 uint32_t hash = 0; 1041 1042 ext2_extattr_hash_entry(header, entry); 1043 1044 here = EXT2_ENTRY(header+1); 1045 while (!EXT2_IS_LAST_ENTRY(here)) { 1046 if (here->e_hash == 0) { 1047 /* Block is not shared if an entry's hash value == 0 */ 1048 hash = 0; 1049 break; 1050 } 1051 1052 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^ 1053 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^ 1054 le32toh(here->e_hash); 1055 1056 here = EXT2_EXTATTR_NEXT(here); 1057 } 1058 1059 header->h_hash = htole32(hash); 1060 } 1061 1062 int 1063 ext2_extattr_block_set(struct inode *ip, int attrnamespace, 1064 const char *name, struct uio *uio) 1065 { 1066 struct m_ext2fs *fs; 1067 struct buf *bp; 1068 struct ext2fs_extattr_header *header; 1069 struct ext2fs_extattr_entry *entry; 1070 const char *attr_name; 1071 int name_len; 1072 size_t size; 1073 int error; 1074 1075 fs = ip->i_e2fs; 1076 1077 if (ip->i_facl) { 1078 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 1079 fs->e2fs_bsize, NOCRED, &bp); 1080 if (error) { 1081 return (error); 1082 } 1083 1084 /* Check attributes magic value */ 1085 header = EXT2_HDR(bp); 1086 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 1087 le32toh(header->h_blocks) != 1) { 1088 brelse(bp); 1089 return (EINVAL); 1090 } 1091 1092 error = ext2_extattr_block_check(ip, bp); 1093 if (error) { 1094 brelse(bp); 1095 return (error); 1096 } 1097 1098 if (le32toh(header->h_refcount) > 1) { 1099 error = ext2_extattr_block_clone(ip, &bp); 1100 if (error) { 1101 brelse(bp); 1102 return (error); 1103 } 1104 1105 header = EXT2_HDR(bp); 1106 } 1107 1108 /* Find if entry exist */ 1109 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 1110 entry = EXT2_EXTATTR_NEXT(entry)) { 1111 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 1112 attrnamespace) 1113 continue; 1114 1115 name_len = entry->e_name_len; 1116 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 1117 entry->e_name, &name_len); 1118 if (!attr_name) { 1119 brelse(bp); 1120 return (ENOTSUP); 1121 } 1122 1123 if (strlen(name) == name_len && 1124 0 == strncmp(attr_name, name, name_len)) 1125 break; 1126 } 1127 1128 if (!EXT2_IS_LAST_ENTRY(entry)) { 1129 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry, 1130 sizeof(struct ext2fs_extattr_header), 1131 entry->e_name_len, uio->uio_resid); 1132 if (size > bp->b_bufsize) { 1133 brelse(bp); 1134 return (ENOSPC); 1135 } 1136 1137 ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1138 entry, bp->b_data + bp->b_bufsize, uio); 1139 } else { 1140 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL, 1141 sizeof(struct ext2fs_extattr_header), 1142 strlen(name), uio->uio_resid); 1143 if (size > bp->b_bufsize) { 1144 brelse(bp); 1145 return (ENOSPC); 1146 } 1147 1148 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1149 name, attrnamespace, bp->b_data + bp->b_bufsize, uio); 1150 1151 /* Clean the same entry in the inode */ 1152 error = ext2_extattr_inode_delete(ip, attrnamespace, name); 1153 if (error && error != ENOATTR) { 1154 brelse(bp); 1155 return (error); 1156 } 1157 } 1158 1159 ext2_extattr_rehash(header, entry); 1160 ext2_extattr_blk_csum_set(ip, bp); 1161 1162 return (bwrite(bp)); 1163 } 1164 1165 size = ext2_extattr_get_size(NULL, NULL, 1166 sizeof(struct ext2fs_extattr_header), 1167 strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid); 1168 if (size > fs->e2fs_bsize) 1169 return (ENOSPC); 1170 1171 /* Allocate block, fill EA header and insert entry */ 1172 ip->i_facl = ext2_alloc_meta(ip); 1173 if (0 == ip->i_facl) 1174 return (ENOSPC); 1175 1176 ip->i_blocks += btodb(fs->e2fs_bsize); 1177 ext2_update(ip->i_vnode, 1); 1178 1179 bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0); 1180 if (!bp) { 1181 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize); 1182 ip->i_blocks -= btodb(fs->e2fs_bsize); 1183 ip->i_facl = 0; 1184 ext2_update(ip->i_vnode, 1); 1185 return (EIO); 1186 } 1187 1188 header = EXT2_HDR(bp); 1189 header->h_magic = htole32(EXTATTR_MAGIC); 1190 header->h_refcount = htole32(1); 1191 header->h_blocks = htole32(1); 1192 header->h_hash = 0; 1193 memset(header->h_reserved, 0, sizeof(header->h_reserved)); 1194 memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header)); 1195 memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t)); 1196 1197 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1198 name, attrnamespace, bp->b_data + bp->b_bufsize, uio); 1199 1200 /* Clean the same entry in the inode */ 1201 error = ext2_extattr_inode_delete(ip, attrnamespace, name); 1202 if (error && error != ENOATTR) { 1203 brelse(bp); 1204 return (error); 1205 } 1206 1207 ext2_extattr_rehash(header, entry); 1208 ext2_extattr_blk_csum_set(ip, bp); 1209 1210 return (bwrite(bp)); 1211 } 1212 1213 int ext2_extattr_free(struct inode *ip) 1214 { 1215 struct m_ext2fs *fs; 1216 struct buf *bp; 1217 struct ext2fs_extattr_header *header; 1218 int error; 1219 1220 fs = ip->i_e2fs; 1221 1222 if (!ip->i_facl) 1223 return (0); 1224 1225 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 1226 fs->e2fs_bsize, NOCRED, &bp); 1227 if (error) { 1228 return (error); 1229 } 1230 1231 /* Check attributes magic value */ 1232 header = EXT2_HDR(bp); 1233 if (le32toh(header->h_magic) != EXTATTR_MAGIC || 1234 le32toh(header->h_blocks) != 1) { 1235 brelse(bp); 1236 return (EINVAL); 1237 } 1238 1239 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), 1240 bp->b_data + bp->b_bufsize); 1241 if (error) { 1242 brelse(bp); 1243 return (error); 1244 } 1245 1246 if (le32toh(header->h_refcount) > 1) { 1247 header->h_refcount = htole32(le32toh(header->h_refcount) - 1); 1248 bwrite(bp); 1249 } else { 1250 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize); 1251 brelse(bp); 1252 } 1253 1254 ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize); 1255 ip->i_facl = 0; 1256 ext2_update(ip->i_vnode, 1); 1257 1258 return (0); 1259 } 1260