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