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