1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/types.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/vnode.h> 37 #include <sys/bio.h> 38 #include <sys/buf.h> 39 #include <sys/endian.h> 40 #include <sys/conf.h> 41 #include <sys/extattr.h> 42 #include <sys/sdt.h> 43 44 #include <fs/ext2fs/fs.h> 45 #include <fs/ext2fs/ext2fs.h> 46 #include <fs/ext2fs/inode.h> 47 #include <fs/ext2fs/ext2_dinode.h> 48 #include <fs/ext2fs/ext2_mount.h> 49 #include <fs/ext2fs/ext2_extattr.h> 50 #include <fs/ext2fs/ext2_extern.h> 51 52 SDT_PROVIDER_DECLARE(ext2fs); 53 /* 54 * ext2fs trace probe: 55 * arg0: verbosity. Higher numbers give more verbose messages 56 * arg1: Textual message 57 */ 58 SDT_PROBE_DEFINE2(ext2fs, , trace, extattr, "int", "char*"); 59 60 static int 61 ext2_extattr_attrnamespace_to_bsd(int attrnamespace) 62 { 63 64 switch (attrnamespace) { 65 case EXT4_XATTR_INDEX_SYSTEM: 66 return (EXTATTR_NAMESPACE_SYSTEM); 67 68 case EXT4_XATTR_INDEX_USER: 69 return (EXTATTR_NAMESPACE_USER); 70 71 case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT: 72 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE); 73 74 case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS: 75 return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE); 76 } 77 78 return (EXTATTR_NAMESPACE_EMPTY); 79 } 80 81 static const char * 82 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len) 83 { 84 85 if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM) 86 return (name); 87 else if (attrnamespace == EXT4_XATTR_INDEX_USER) 88 return (name); 89 else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) { 90 *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME); 91 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME); 92 } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) { 93 *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME); 94 return (POSIX1E_ACL_ACCESS_EXTATTR_NAME); 95 } 96 97 /* 98 * XXX: Not all linux namespaces are mapped to bsd for now, 99 * return NULL, which will be converted to ENOTSUP on upper layer. 100 */ 101 SDT_PROBE2(ext2fs, , trace, extattr, 1, 102 "can not convert ext2fs name to bsd namespace"); 103 104 return (NULL); 105 } 106 107 static int 108 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name) 109 { 110 111 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE && 112 !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) 113 return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT); 114 115 if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE && 116 !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) 117 return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS); 118 119 switch (attrnamespace) { 120 case EXTATTR_NAMESPACE_SYSTEM: 121 return (EXT4_XATTR_INDEX_SYSTEM); 122 123 case EXTATTR_NAMESPACE_USER: 124 return (EXT4_XATTR_INDEX_USER); 125 } 126 127 /* 128 * In this case namespace conversion should be unique, 129 * so this point is unreachable. 130 */ 131 return (-1); 132 } 133 134 static const char * 135 ext2_extattr_name_to_linux(int attrnamespace, const char *name) 136 { 137 138 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE || 139 attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE) 140 return (""); 141 else 142 return (name); 143 } 144 145 int 146 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname) 147 { 148 if (attrnamespace == EXTATTR_NAMESPACE_EMPTY) 149 return (EINVAL); 150 151 if (strlen(attrname) == 0) 152 return (EINVAL); 153 154 if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX) 155 return (ENAMETOOLONG); 156 157 return (0); 158 } 159 160 static int 161 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end) 162 { 163 struct ext2fs_extattr_entry *next; 164 165 while (!EXT2_IS_LAST_ENTRY(entry)) { 166 next = EXT2_EXTATTR_NEXT(entry); 167 if ((char *)next >= end) 168 return (EIO); 169 170 entry = next; 171 } 172 173 return (0); 174 } 175 176 static int 177 ext2_extattr_block_check(struct inode *ip, struct buf *bp) 178 { 179 struct ext2fs_extattr_header *header; 180 int error; 181 182 header = (struct ext2fs_extattr_header *)bp->b_data; 183 184 error = ext2_extattr_check(EXT2_IFIRST(header), 185 bp->b_data + bp->b_bufsize); 186 if (error) 187 return (error); 188 189 return (ext2_extattr_blk_csum_verify(ip, bp)); 190 } 191 192 int 193 ext2_extattr_inode_list(struct inode *ip, int attrnamespace, 194 struct uio *uio, size_t *size) 195 { 196 struct m_ext2fs *fs; 197 struct buf *bp; 198 struct ext2fs_extattr_dinode_header *header; 199 struct ext2fs_extattr_entry *entry; 200 const char *attr_name; 201 int name_len; 202 int error; 203 204 fs = ip->i_e2fs; 205 206 if ((error = bread(ip->i_devvp, 207 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 208 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 209 brelse(bp); 210 return (error); 211 } 212 213 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 214 ((char *)bp->b_data + 215 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 216 217 /* Check attributes magic value */ 218 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 219 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 220 221 if (header->h_magic != EXTATTR_MAGIC) { 222 brelse(bp); 223 return (0); 224 } 225 226 error = ext2_extattr_check(EXT2_IFIRST(header), 227 (char *)dinode + EXT2_INODE_SIZE(fs)); 228 if (error) { 229 brelse(bp); 230 return (error); 231 } 232 233 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 234 entry = EXT2_EXTATTR_NEXT(entry)) { 235 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 236 attrnamespace) 237 continue; 238 239 name_len = entry->e_name_len; 240 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 241 entry->e_name, &name_len); 242 if (!attr_name) { 243 brelse(bp); 244 return (ENOTSUP); 245 } 246 247 if (size != NULL) 248 *size += name_len + 1; 249 250 if (uio != NULL) { 251 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK); 252 name[0] = name_len; 253 memcpy(&name[1], attr_name, name_len); 254 error = uiomove(name, name_len + 1, uio); 255 free(name, M_TEMP); 256 if (error) 257 break; 258 } 259 } 260 261 brelse(bp); 262 263 return (error); 264 } 265 266 int 267 ext2_extattr_block_list(struct inode *ip, int attrnamespace, 268 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 const char *attr_name; 275 int name_len; 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 error = ext2_extattr_block_check(ip, bp); 295 if (error) { 296 brelse(bp); 297 return (error); 298 } 299 300 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 301 entry = EXT2_EXTATTR_NEXT(entry)) { 302 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 303 attrnamespace) 304 continue; 305 306 name_len = entry->e_name_len; 307 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 308 entry->e_name, &name_len); 309 if (!attr_name) { 310 brelse(bp); 311 return (ENOTSUP); 312 } 313 314 if (size != NULL) 315 *size += name_len + 1; 316 317 if (uio != NULL) { 318 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK); 319 name[0] = name_len; 320 memcpy(&name[1], attr_name, name_len); 321 error = uiomove(name, name_len + 1, uio); 322 free(name, M_TEMP); 323 if (error) 324 break; 325 } 326 } 327 328 brelse(bp); 329 330 return (error); 331 } 332 333 int 334 ext2_extattr_inode_get(struct inode *ip, int attrnamespace, 335 const char *name, struct uio *uio, size_t *size) 336 { 337 struct m_ext2fs *fs; 338 struct buf *bp; 339 struct ext2fs_extattr_dinode_header *header; 340 struct ext2fs_extattr_entry *entry; 341 const char *attr_name; 342 int name_len; 343 int error; 344 345 fs = ip->i_e2fs; 346 347 if ((error = bread(ip->i_devvp, 348 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 349 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 350 brelse(bp); 351 return (error); 352 } 353 354 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 355 ((char *)bp->b_data + 356 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 357 358 /* Check attributes magic value */ 359 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 360 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 361 362 if (header->h_magic != EXTATTR_MAGIC) { 363 brelse(bp); 364 return (ENOATTR); 365 } 366 367 error = ext2_extattr_check(EXT2_IFIRST(header), 368 (char *)dinode + EXT2_INODE_SIZE(fs)); 369 if (error) { 370 brelse(bp); 371 return (error); 372 } 373 374 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 375 entry = EXT2_EXTATTR_NEXT(entry)) { 376 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 377 attrnamespace) 378 continue; 379 380 name_len = entry->e_name_len; 381 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 382 entry->e_name, &name_len); 383 if (!attr_name) { 384 brelse(bp); 385 return (ENOTSUP); 386 } 387 388 if (strlen(name) == name_len && 389 0 == strncmp(attr_name, name, name_len)) { 390 if (size != NULL) 391 *size += entry->e_value_size; 392 393 if (uio != NULL) 394 error = uiomove(((char *)EXT2_IFIRST(header)) + 395 entry->e_value_offs, entry->e_value_size, uio); 396 397 brelse(bp); 398 return (error); 399 } 400 } 401 402 brelse(bp); 403 404 return (ENOATTR); 405 } 406 407 int 408 ext2_extattr_block_get(struct inode *ip, int attrnamespace, 409 const char *name, struct uio *uio, size_t *size) 410 { 411 struct m_ext2fs *fs; 412 struct buf *bp; 413 struct ext2fs_extattr_header *header; 414 struct ext2fs_extattr_entry *entry; 415 const char *attr_name; 416 int name_len; 417 int error; 418 419 fs = ip->i_e2fs; 420 421 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 422 fs->e2fs_bsize, NOCRED, &bp); 423 if (error) { 424 brelse(bp); 425 return (error); 426 } 427 428 /* Check attributes magic value */ 429 header = EXT2_HDR(bp); 430 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 431 brelse(bp); 432 return (EINVAL); 433 } 434 435 error = ext2_extattr_block_check(ip, bp); 436 if (error) { 437 brelse(bp); 438 return (error); 439 } 440 441 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 442 entry = EXT2_EXTATTR_NEXT(entry)) { 443 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 444 attrnamespace) 445 continue; 446 447 name_len = entry->e_name_len; 448 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 449 entry->e_name, &name_len); 450 if (!attr_name) { 451 brelse(bp); 452 return (ENOTSUP); 453 } 454 455 if (strlen(name) == name_len && 456 0 == strncmp(attr_name, name, name_len)) { 457 if (size != NULL) 458 *size += entry->e_value_size; 459 460 if (uio != NULL) 461 error = uiomove(bp->b_data + entry->e_value_offs, 462 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 > next->e_value_offs && next->e_value_offs > 0) 486 min_offs = next->e_value_offs; 487 488 next = EXT2_EXTATTR_NEXT(next); 489 } 490 491 if (entry->e_value_size == 0) 492 return (min_offs); 493 494 memmove(off + min_offs + EXT2_EXTATTR_SIZE(entry->e_value_size), 495 off + min_offs, entry->e_value_offs - min_offs); 496 497 /* Adjust all value offsets */ 498 next = first_entry; 499 while (!EXT2_IS_LAST_ENTRY(next)) 500 { 501 if (next->e_value_offs > 0 && 502 next->e_value_offs < entry->e_value_offs) 503 next->e_value_offs += 504 EXT2_EXTATTR_SIZE(entry->e_value_size); 505 506 next = EXT2_EXTATTR_NEXT(next); 507 } 508 509 min_offs += EXT2_EXTATTR_SIZE(entry->e_value_size); 510 511 return (min_offs); 512 } 513 514 static void 515 ext2_extattr_delete_entry(char *off, 516 struct ext2fs_extattr_entry *first_entry, 517 struct ext2fs_extattr_entry *entry, char *end) 518 { 519 char *pad; 520 struct ext2fs_extattr_entry *next; 521 522 /* Clean entry value */ 523 ext2_extattr_delete_value(off, first_entry, entry, end); 524 525 /* Clean the entry */ 526 next = first_entry; 527 while (!EXT2_IS_LAST_ENTRY(next)) 528 next = EXT2_EXTATTR_NEXT(next); 529 530 pad = (char*)next + sizeof(uint32_t); 531 532 memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len), 533 pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len))); 534 } 535 536 int 537 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name) 538 { 539 struct m_ext2fs *fs; 540 struct buf *bp; 541 struct ext2fs_extattr_dinode_header *header; 542 struct ext2fs_extattr_entry *entry; 543 const char *attr_name; 544 int name_len; 545 int error; 546 547 fs = ip->i_e2fs; 548 549 if ((error = bread(ip->i_devvp, 550 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 551 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 552 brelse(bp); 553 return (error); 554 } 555 556 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 557 ((char *)bp->b_data + 558 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 559 560 /* Check attributes magic value */ 561 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 562 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 563 564 if (header->h_magic != EXTATTR_MAGIC) { 565 brelse(bp); 566 return (ENOATTR); 567 } 568 569 error = ext2_extattr_check(EXT2_IFIRST(header), 570 (char *)dinode + EXT2_INODE_SIZE(fs)); 571 if (error) { 572 brelse(bp); 573 return (error); 574 } 575 576 /* If I am last entry, just make magic zero */ 577 entry = EXT2_IFIRST(header); 578 if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) && 579 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) == 580 attrnamespace)) { 581 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 (header->h_magic != EXTATTR_MAGIC || header->h_refcount == 1) 641 return (EINVAL); 642 643 facl = ext2_alloc_meta(ip); 644 if (!facl) 645 return (ENOSPC); 646 647 cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0); 648 if (!cbp) { 649 ext2_blkfree(ip, facl, fs->e2fs_bsize); 650 return (EIO); 651 } 652 653 memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize); 654 header->h_refcount--; 655 bwrite(sbp); 656 657 ip->i_facl = facl; 658 ext2_update(ip->i_vnode, 1); 659 660 header = EXT2_HDR(cbp); 661 header->h_refcount = 1; 662 663 *bpp = cbp; 664 665 return (0); 666 } 667 668 int 669 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name) 670 { 671 struct m_ext2fs *fs; 672 struct buf *bp; 673 struct ext2fs_extattr_header *header; 674 struct ext2fs_extattr_entry *entry; 675 const char *attr_name; 676 int name_len; 677 int error; 678 679 fs = ip->i_e2fs; 680 681 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 682 fs->e2fs_bsize, NOCRED, &bp); 683 if (error) { 684 brelse(bp); 685 return (error); 686 } 687 688 /* Check attributes magic value */ 689 header = EXT2_HDR(bp); 690 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 691 brelse(bp); 692 return (EINVAL); 693 } 694 695 error = ext2_extattr_block_check(ip, bp); 696 if (error) { 697 brelse(bp); 698 return (error); 699 } 700 701 if (header->h_refcount > 1) { 702 error = ext2_extattr_block_clone(ip, &bp); 703 if (error) { 704 brelse(bp); 705 return (error); 706 } 707 } 708 709 /* If I am last entry, clean me and free the block */ 710 entry = EXT2_FIRST_ENTRY(bp); 711 if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) && 712 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) == 713 attrnamespace)) { 714 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 = offs; 781 entry->e_value_block = 0; 782 entry->e_value_size = size; 783 entry->e_hash = 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(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 = uio->uio_resid; 837 if (entry->e_value_size) 838 entry->e_value_offs = min_offs - 839 EXT2_EXTATTR_SIZE(uio->uio_resid); 840 else 841 entry->e_value_offs = 0; 842 843 uiomove(off + entry->e_value_offs, entry->e_value_size, uio); 844 } 845 846 static struct ext2fs_extattr_entry * 847 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry, 848 const char *name, int attrnamespace, char *end, struct uio *uio) 849 { 850 int name_len; 851 char *pad; 852 uint16_t min_offs; 853 struct ext2fs_extattr_entry *entry; 854 struct ext2fs_extattr_entry *new_entry; 855 856 /* Find pad's */ 857 min_offs = end - off; 858 entry = first_entry; 859 while (!EXT2_IS_LAST_ENTRY(entry)) { 860 if (min_offs > entry->e_value_offs && entry->e_value_offs > 0) 861 min_offs = entry->e_value_offs; 862 863 entry = EXT2_EXTATTR_NEXT(entry); 864 } 865 866 pad = (char*)entry + sizeof(uint32_t); 867 868 /* Find entry insert position */ 869 name_len = strlen(name); 870 entry = first_entry; 871 while (!EXT2_IS_LAST_ENTRY(entry)) { 872 if (!(attrnamespace - entry->e_name_index) && 873 !(name_len - entry->e_name_len)) 874 if (memcmp(name, entry->e_name, name_len) <= 0) 875 break; 876 877 entry = EXT2_EXTATTR_NEXT(entry); 878 } 879 880 /* Create new entry and insert it */ 881 new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0); 882 memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry, 883 pad - (char*)entry); 884 885 memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len)); 886 free_entry(new_entry); 887 888 new_entry = entry; 889 if (new_entry->e_value_size > 0) 890 new_entry->e_value_offs = min_offs - 891 EXT2_EXTATTR_SIZE(new_entry->e_value_size); 892 893 uiomove(off + new_entry->e_value_offs, new_entry->e_value_size, uio); 894 895 return (new_entry); 896 } 897 898 int 899 ext2_extattr_inode_set(struct inode *ip, int attrnamespace, 900 const char *name, struct uio *uio) 901 { 902 struct m_ext2fs *fs; 903 struct buf *bp; 904 struct ext2fs_extattr_dinode_header *header; 905 struct ext2fs_extattr_entry *entry; 906 const char *attr_name; 907 int name_len; 908 size_t size = 0, max_size; 909 int error; 910 911 fs = ip->i_e2fs; 912 913 if ((error = bread(ip->i_devvp, 914 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 915 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 916 brelse(bp); 917 return (error); 918 } 919 920 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) 921 ((char *)bp->b_data + 922 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); 923 924 /* Check attributes magic value */ 925 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + 926 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); 927 928 if (header->h_magic != EXTATTR_MAGIC) { 929 brelse(bp); 930 return (ENOSPC); 931 } 932 933 error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode + 934 EXT2_INODE_SIZE(fs)); 935 if (error) { 936 brelse(bp); 937 return (error); 938 } 939 940 /* Find if entry exist */ 941 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); 942 entry = EXT2_EXTATTR_NEXT(entry)) { 943 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 944 attrnamespace) 945 continue; 946 947 name_len = entry->e_name_len; 948 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 949 entry->e_name, &name_len); 950 if (!attr_name) { 951 brelse(bp); 952 return (ENOTSUP); 953 } 954 955 if (strlen(name) == name_len && 956 0 == strncmp(attr_name, name, name_len)) 957 break; 958 } 959 960 max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE - 961 dinode->e2di_extra_isize; 962 963 if (!EXT2_IS_LAST_ENTRY(entry)) { 964 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry, 965 sizeof(struct ext2fs_extattr_dinode_header), 966 entry->e_name_len, uio->uio_resid); 967 if (size > max_size) { 968 brelse(bp); 969 return (ENOSPC); 970 } 971 972 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header), 973 EXT2_IFIRST(header), entry, (char *)header + max_size, uio); 974 } else { 975 /* Ensure that the same entry does not exist in the block */ 976 if (ip->i_facl) { 977 error = ext2_extattr_block_get(ip, attrnamespace, name, 978 NULL, &size); 979 if (error != ENOATTR || size > 0) { 980 brelse(bp); 981 if (size > 0) 982 error = ENOSPC; 983 984 return (error); 985 } 986 } 987 988 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL, 989 sizeof(struct ext2fs_extattr_dinode_header), 990 entry->e_name_len, uio->uio_resid); 991 if (size > max_size) { 992 brelse(bp); 993 return (ENOSPC); 994 } 995 996 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header), 997 EXT2_IFIRST(header), name, attrnamespace, 998 (char *)header + max_size, uio); 999 } 1000 1001 return (bwrite(bp)); 1002 } 1003 1004 static void 1005 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header, 1006 struct ext2fs_extattr_entry *entry) 1007 { 1008 uint32_t hash = 0; 1009 char *name = entry->e_name; 1010 int n; 1011 1012 for (n=0; n < entry->e_name_len; n++) { 1013 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^ 1014 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^ 1015 (*name++); 1016 } 1017 1018 if (entry->e_value_block == 0 && entry->e_value_size != 0) { 1019 uint32_t *value = (uint32_t *)((char *)header + entry->e_value_offs); 1020 for (n = (entry->e_value_size + 1021 EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) { 1022 hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^ 1023 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^ 1024 (*value++); 1025 } 1026 } 1027 1028 entry->e_hash = hash; 1029 } 1030 1031 static void 1032 ext2_extattr_rehash(struct ext2fs_extattr_header *header, 1033 struct ext2fs_extattr_entry *entry) 1034 { 1035 struct ext2fs_extattr_entry *here; 1036 uint32_t hash = 0; 1037 1038 ext2_extattr_hash_entry(header, entry); 1039 1040 here = EXT2_ENTRY(header+1); 1041 while (!EXT2_IS_LAST_ENTRY(here)) { 1042 if (!here->e_hash) { 1043 /* Block is not shared if an entry's hash value == 0 */ 1044 hash = 0; 1045 break; 1046 } 1047 1048 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^ 1049 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^ 1050 here->e_hash; 1051 1052 here = EXT2_EXTATTR_NEXT(here); 1053 } 1054 1055 header->h_hash = hash; 1056 } 1057 1058 int 1059 ext2_extattr_block_set(struct inode *ip, int attrnamespace, 1060 const char *name, struct uio *uio) 1061 { 1062 struct m_ext2fs *fs; 1063 struct buf *bp; 1064 struct ext2fs_extattr_header *header; 1065 struct ext2fs_extattr_entry *entry; 1066 const char *attr_name; 1067 int name_len; 1068 size_t size; 1069 int error; 1070 1071 fs = ip->i_e2fs; 1072 1073 if (ip->i_facl) { 1074 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 1075 fs->e2fs_bsize, NOCRED, &bp); 1076 if (error) { 1077 brelse(bp); 1078 return (error); 1079 } 1080 1081 /* Check attributes magic value */ 1082 header = EXT2_HDR(bp); 1083 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 1084 brelse(bp); 1085 return (EINVAL); 1086 } 1087 1088 error = ext2_extattr_block_check(ip, bp); 1089 if (error) { 1090 brelse(bp); 1091 return (error); 1092 } 1093 1094 if (header->h_refcount > 1) { 1095 error = ext2_extattr_block_clone(ip, &bp); 1096 if (error) { 1097 brelse(bp); 1098 return (error); 1099 } 1100 1101 header = EXT2_HDR(bp); 1102 } 1103 1104 /* Find if entry exist */ 1105 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); 1106 entry = EXT2_EXTATTR_NEXT(entry)) { 1107 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) != 1108 attrnamespace) 1109 continue; 1110 1111 name_len = entry->e_name_len; 1112 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index, 1113 entry->e_name, &name_len); 1114 if (!attr_name) { 1115 brelse(bp); 1116 return (ENOTSUP); 1117 } 1118 1119 if (strlen(name) == name_len && 1120 0 == strncmp(attr_name, name, name_len)) 1121 break; 1122 } 1123 1124 if (!EXT2_IS_LAST_ENTRY(entry)) { 1125 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry, 1126 sizeof(struct ext2fs_extattr_header), 1127 entry->e_name_len, uio->uio_resid); 1128 if (size > bp->b_bufsize) { 1129 brelse(bp); 1130 return (ENOSPC); 1131 } 1132 1133 ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1134 entry, bp->b_data + bp->b_bufsize, uio); 1135 } else { 1136 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL, 1137 sizeof(struct ext2fs_extattr_header), 1138 strlen(name), uio->uio_resid); 1139 if (size > bp->b_bufsize) { 1140 brelse(bp); 1141 return (ENOSPC); 1142 } 1143 1144 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1145 name, attrnamespace, bp->b_data + bp->b_bufsize, uio); 1146 1147 /* Clean the same entry in the inode */ 1148 error = ext2_extattr_inode_delete(ip, attrnamespace, name); 1149 if (error && error != ENOATTR) { 1150 brelse(bp); 1151 return (error); 1152 } 1153 } 1154 1155 ext2_extattr_rehash(header, entry); 1156 ext2_extattr_blk_csum_set(ip, bp); 1157 1158 return (bwrite(bp)); 1159 } 1160 1161 size = ext2_extattr_get_size(NULL, NULL, 1162 sizeof(struct ext2fs_extattr_header), 1163 strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid); 1164 if (size > fs->e2fs_bsize) 1165 return (ENOSPC); 1166 1167 /* Allocate block, fill EA header and insert entry */ 1168 ip->i_facl = ext2_alloc_meta(ip); 1169 if (0 == ip->i_facl) 1170 return (ENOSPC); 1171 1172 ip->i_blocks += btodb(fs->e2fs_bsize); 1173 ext2_update(ip->i_vnode, 1); 1174 1175 bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0); 1176 if (!bp) { 1177 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize); 1178 ip->i_blocks -= btodb(fs->e2fs_bsize); 1179 ip->i_facl = 0; 1180 ext2_update(ip->i_vnode, 1); 1181 return (EIO); 1182 } 1183 1184 header = EXT2_HDR(bp); 1185 header->h_magic = EXTATTR_MAGIC; 1186 header->h_refcount = 1; 1187 header->h_blocks = 1; 1188 header->h_hash = 0; 1189 memset(header->h_reserved, 0, sizeof(header->h_reserved)); 1190 memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header)); 1191 memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t)); 1192 1193 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), 1194 name, attrnamespace, bp->b_data + bp->b_bufsize, uio); 1195 1196 /* Clean the same entry in the inode */ 1197 error = ext2_extattr_inode_delete(ip, attrnamespace, name); 1198 if (error && error != ENOATTR) { 1199 brelse(bp); 1200 return (error); 1201 } 1202 1203 ext2_extattr_rehash(header, entry); 1204 ext2_extattr_blk_csum_set(ip, bp); 1205 1206 return (bwrite(bp)); 1207 } 1208 1209 int ext2_extattr_free(struct inode *ip) 1210 { 1211 struct m_ext2fs *fs; 1212 struct buf *bp; 1213 struct ext2fs_extattr_header *header; 1214 int error; 1215 1216 fs = ip->i_e2fs; 1217 1218 if (!ip->i_facl) 1219 return (0); 1220 1221 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), 1222 fs->e2fs_bsize, NOCRED, &bp); 1223 if (error) { 1224 brelse(bp); 1225 return (error); 1226 } 1227 1228 /* Check attributes magic value */ 1229 header = EXT2_HDR(bp); 1230 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { 1231 brelse(bp); 1232 return (EINVAL); 1233 } 1234 1235 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), 1236 bp->b_data + bp->b_bufsize); 1237 if (error) { 1238 brelse(bp); 1239 return (error); 1240 } 1241 1242 if (header->h_refcount > 1) { 1243 header->h_refcount--; 1244 bwrite(bp); 1245 } else { 1246 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize); 1247 brelse(bp); 1248 } 1249 1250 ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize); 1251 ip->i_facl = 0; 1252 ext2_update(ip->i_vnode, 1); 1253 1254 return (0); 1255 } 1256