1/* 2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 30 * support for mandatory and extensible security protections. This notice 31 * is included in support of clause 2.2 (b) of the Apple Public License, 32 * Version 2.0. 33 */ 34 35#include <sys/param.h> 36 37#include <sys/fcntl.h> 38#include <sys/fsevents.h> 39#include <sys/kernel.h> 40#include <sys/kauth.h> 41#include <sys/malloc.h> 42#include <sys/mount_internal.h> 43#include <sys/namei.h> 44#include <sys/proc_internal.h> 45#include <sys/stat.h> 46#include <sys/uio.h> 47#include <sys/utfconv.h> 48#include <sys/vnode.h> 49#include <sys/vnode_internal.h> 50#include <sys/xattr.h> 51 52#include <libkern/OSByteOrder.h> 53#include <vm/vm_kern.h> 54 55#if CONFIG_MACF 56#include <security/mac_framework.h> 57#endif 58 59#if !CONFIG_APPLEDOUBLE 60#define PANIC_ON_NOAPPLEDOUBLE 1 61#endif 62 63#if NAMEDSTREAMS 64 65static int shadow_sequence; 66 67/* 68 * We use %p to prevent loss of precision for pointers on varying architectures. 69 */ 70 71#define SHADOW_NAME_FMT ".vfs_rsrc_stream_%p%08x%p" 72#define SHADOW_DIR_FMT ".vfs_rsrc_streams_%p%x" 73#define SHADOW_DIR_CONTAINER "/var/run" 74 75#define MAKE_SHADOW_NAME(VP, NAME) \ 76 snprintf((NAME), sizeof((NAME)), (SHADOW_NAME_FMT), \ 77 ((void*)(VM_KERNEL_ADDRPERM(VP))), \ 78 (VP)->v_id, \ 79 ((void*)(VM_KERNEL_ADDRPERM((VP)->v_data)))) 80 81/* The full path to the shadow directory */ 82#define MAKE_SHADOW_DIRNAME(VP, NAME) \ 83 snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_CONTAINER "/" SHADOW_DIR_FMT), \ 84 ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence) 85 86/* The shadow directory as a 'leaf' entry */ 87#define MAKE_SHADOW_DIR_LEAF(VP, NAME) \ 88 snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_FMT), \ 89 ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence) 90 91static int default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context); 92 93static int default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context); 94 95static int default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context); 96 97static int getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context); 98 99static int get_shadow_dir(vnode_t *sdvpp); 100 101#endif /* NAMEDSTREAMS */ 102 103/* 104 * Default xattr support routines. 105 */ 106 107static int default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, 108 vfs_context_t context); 109static int default_setxattr(vnode_t vp, const char *name, uio_t uio, int options, 110 vfs_context_t context); 111static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, 112 vfs_context_t context); 113static int default_removexattr(vnode_t vp, const char *name, int options, 114 vfs_context_t context); 115 116/* 117 * Retrieve the data of an extended attribute. 118 */ 119int 120vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, 121 int options, vfs_context_t context) 122{ 123 int error; 124 125 if (!XATTR_VNODE_SUPPORTED(vp)) { 126 return (EPERM); 127 } 128#if NAMEDSTREAMS 129 /* getxattr calls are not allowed for streams. */ 130 if (vp->v_flag & VISNAMEDSTREAM) { 131 error = EPERM; 132 goto out; 133 } 134#endif 135 /* 136 * Non-kernel request need extra checks performed. 137 * 138 * The XATTR_NOSECURITY flag implies a kernel request. 139 */ 140 if (!(options & XATTR_NOSECURITY)) { 141#if CONFIG_MACF 142 error = mac_vnode_check_getextattr(context, vp, name, uio); 143 if (error) 144 goto out; 145#endif /* MAC */ 146 if ((error = xattr_validatename(name))) { 147 goto out; 148 } 149 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context))) { 150 goto out; 151 } 152 /* The offset can only be non-zero for resource forks. */ 153 if (uio != NULL && uio_offset(uio) != 0 && 154 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) { 155 error = EINVAL; 156 goto out; 157 } 158 } 159 160 /* The offset can only be non-zero for resource forks. */ 161 if (uio != NULL && uio_offset(uio) != 0 && 162 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) { 163 error = EINVAL; 164 goto out; 165 } 166 167 error = VNOP_GETXATTR(vp, name, uio, size, options, context); 168 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) { 169 /* 170 * A filesystem may keep some EAs natively and return ENOTSUP for others. 171 */ 172 error = default_getxattr(vp, name, uio, size, options, context); 173 } 174out: 175 return (error); 176} 177 178/* 179 * Set the data of an extended attribute. 180 */ 181int 182vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context) 183{ 184 int error; 185 186 if (!XATTR_VNODE_SUPPORTED(vp)) { 187 return (EPERM); 188 } 189#if NAMEDSTREAMS 190 /* setxattr calls are not allowed for streams. */ 191 if (vp->v_flag & VISNAMEDSTREAM) { 192 error = EPERM; 193 goto out; 194 } 195#endif 196 if ((options & (XATTR_REPLACE|XATTR_CREATE)) == (XATTR_REPLACE|XATTR_CREATE)) { 197 return (EINVAL); 198 } 199 if ((error = xattr_validatename(name))) { 200 return (error); 201 } 202 if (!(options & XATTR_NOSECURITY)) { 203#if CONFIG_MACF 204 error = mac_vnode_check_setextattr(context, vp, name, uio); 205 if (error) 206 goto out; 207#endif /* MAC */ 208 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context); 209 if (error) 210 goto out; 211 } 212 /* The offset can only be non-zero for resource forks. */ 213 if (uio_offset(uio) != 0 && 214 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0 ) { 215 error = EINVAL; 216 goto out; 217 } 218 219 error = VNOP_SETXATTR(vp, name, uio, options, context); 220#ifdef DUAL_EAS 221 /* 222 * An EJUSTRETURN is from a filesystem which keeps this xattr 223 * natively as well as in a dot-underscore file. In this case the 224 * EJUSTRETURN means the filesytem has done nothing, but identifies the 225 * EA as one which may be represented natively and/or in a DU, and 226 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in 227 * in vn_setxattr can we do the getxattrs needed to ascertain whether 228 * the XATTR_{CREATE,REPLACE} should yield an error. 229 */ 230 if (error == EJUSTRETURN) { 231 int native = 0, dufile = 0; 232 size_t sz; /* not used */ 233 234 native = VNOP_GETXATTR(vp, name, NULL, &sz, 0, context) ? 0 : 1; 235 dufile = default_getxattr(vp, name, NULL, &sz, 0, context) ? 0 : 1; 236 if (options & XATTR_CREATE && (native || dufile)) { 237 error = EEXIST; 238 goto out; 239 } 240 if (options & XATTR_REPLACE && !(native || dufile)) { 241 error = ENOATTR; 242 goto out; 243 } 244 /* 245 * Having determined no CREATE/REPLACE error should result, we 246 * zero those bits, so both backing stores get written to. 247 */ 248 options &= ~(XATTR_CREATE | XATTR_REPLACE); 249 error = VNOP_SETXATTR(vp, name, uio, options, context); 250 /* the mainline path here is to have error==ENOTSUP ... */ 251 } 252#endif /* DUAL_EAS */ 253 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) { 254 /* 255 * A filesystem may keep some EAs natively and return ENOTSUP for others. 256 */ 257 error = default_setxattr(vp, name, uio, options, context); 258 } 259#if CONFIG_MACF 260 if ((error == 0) && !(options & XATTR_NOSECURITY) && 261 (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL)) 262 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name); 263#endif 264out: 265 return (error); 266} 267 268/* 269 * Remove an extended attribute. 270 */ 271int 272vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context) 273{ 274 int error; 275 276 if (!XATTR_VNODE_SUPPORTED(vp)) { 277 return (EPERM); 278 } 279#if NAMEDSTREAMS 280 /* removexattr calls are not allowed for streams. */ 281 if (vp->v_flag & VISNAMEDSTREAM) { 282 error = EPERM; 283 goto out; 284 } 285#endif 286 if ((error = xattr_validatename(name))) { 287 return (error); 288 } 289 if (!(options & XATTR_NOSECURITY)) { 290#if CONFIG_MACF 291 error = mac_vnode_check_deleteextattr(context, vp, name); 292 if (error) 293 goto out; 294#endif /* MAC */ 295 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context); 296 if (error) 297 goto out; 298 } 299 error = VNOP_REMOVEXATTR(vp, name, options, context); 300 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) { 301 /* 302 * A filesystem may keep some EAs natively and return ENOTSUP for others. 303 */ 304 error = default_removexattr(vp, name, options, context); 305#ifdef DUAL_EAS 306 } else if (error == EJUSTRETURN) { 307 /* 308 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well 309 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove 310 * a native xattr, so failure to find it in a DU file during 311 * default_removexattr should not be considered an error. 312 */ 313 error = default_removexattr(vp, name, options, context); 314 if (error == ENOATTR) 315 error = 0; 316#endif /* DUAL_EAS */ 317 } 318#if CONFIG_MACF 319 if ((error == 0) && !(options & XATTR_NOSECURITY) && 320 (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL)) 321 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name); 322#endif 323out: 324 return (error); 325} 326 327/* 328 * Retrieve the list of extended attribute names. 329 */ 330int 331vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t context) 332{ 333 int error; 334 335 if (!XATTR_VNODE_SUPPORTED(vp)) { 336 return (EPERM); 337 } 338#if NAMEDSTREAMS 339 /* listxattr calls are not allowed for streams. */ 340 if (vp->v_flag & VISNAMEDSTREAM) { 341 return (EPERM); 342 } 343#endif 344 345 if (!(options & XATTR_NOSECURITY)) { 346#if CONFIG_MACF 347 error = mac_vnode_check_listextattr(context, vp); 348 if (error) 349 goto out; 350#endif /* MAC */ 351 352 error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context); 353 if (error) 354 goto out; 355 } 356 357 error = VNOP_LISTXATTR(vp, uio, size, options, context); 358 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) { 359 /* 360 * A filesystem may keep some but not all EAs natively, in which case 361 * the native EA names will have been uiomove-d out (or *size updated) 362 * and the default_listxattr here will finish the job. 363 */ 364 error = default_listxattr(vp, uio, size, options, context); 365 } 366out: 367 return (error); 368} 369 370int 371xattr_validatename(const char *name) 372{ 373 int namelen; 374 375 if (name == NULL || name[0] == '\0') { 376 return (EINVAL); 377 } 378 namelen = strnlen(name, XATTR_MAXNAMELEN); 379 if (name[namelen] != '\0') 380 return (ENAMETOOLONG); 381 382 if (utf8_validatestr((const unsigned char *)name, namelen) != 0) 383 return (EINVAL); 384 385 return (0); 386} 387 388 389/* 390 * Determine whether an EA is a protected system attribute. 391 */ 392int 393xattr_protected(const char *attrname) 394{ 395 return(!strncmp(attrname, "com.apple.system.", 17)); 396} 397 398 399#if NAMEDSTREAMS 400 401/* 402 * Obtain a named stream from vnode vp. 403 */ 404errno_t 405vnode_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, int flags, vfs_context_t context) 406{ 407 int error; 408 409 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) 410 error = VNOP_GETNAMEDSTREAM(vp, svpp, name, op, flags, context); 411 else 412 error = default_getnamedstream(vp, svpp, name, op, context); 413 414 if (error == 0) { 415 uint32_t streamflags = VISNAMEDSTREAM; 416 vnode_t svp = *svpp; 417 418 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) { 419 streamflags |= VISSHADOW; 420 } 421 422 /* Tag the vnode. */ 423 vnode_lock_spin(svp); 424 svp->v_flag |= streamflags; 425 vnode_unlock(svp); 426 427 /* Tag the parent so we know to flush credentials for streams on setattr */ 428 vnode_lock_spin(vp); 429 vp->v_lflag |= VL_HASSTREAMS; 430 vnode_unlock(vp); 431 432 /* Make the file it's parent. 433 * Note: This parent link helps us distinguish vnodes for 434 * shadow stream files from vnodes for resource fork on file 435 * systems that support namedstream natively (both have 436 * VISNAMEDSTREAM set) by allowing access to mount structure 437 * for checking MNTK_NAMED_STREAMS bit at many places in the 438 * code. 439 */ 440 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT); 441 } 442 443 return (error); 444} 445 446/* 447 * Make a named stream for vnode vp. 448 */ 449errno_t 450vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t context) 451{ 452 int error; 453 454 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) 455 error = VNOP_MAKENAMEDSTREAM(vp, svpp, name, flags, context); 456 else 457 error = default_makenamedstream(vp, svpp, name, context); 458 459 if (error == 0) { 460 uint32_t streamflags = VISNAMEDSTREAM; 461 vnode_t svp = *svpp; 462 463 /* Tag the vnode. */ 464 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) { 465 streamflags |= VISSHADOW; 466 } 467 468 /* Tag the vnode. */ 469 vnode_lock_spin(svp); 470 svp->v_flag |= streamflags; 471 vnode_unlock(svp); 472 473 /* Tag the parent so we know to flush credentials for streams on setattr */ 474 vnode_lock_spin(vp); 475 vp->v_lflag |= VL_HASSTREAMS; 476 vnode_unlock(vp); 477 478 /* Make the file it's parent. 479 * Note: This parent link helps us distinguish vnodes for 480 * shadow stream files from vnodes for resource fork on file 481 * systems that support namedstream natively (both have 482 * VISNAMEDSTREAM set) by allowing access to mount structure 483 * for checking MNTK_NAMED_STREAMS bit at many places in the 484 * code. 485 */ 486 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT); 487 } 488 return (error); 489} 490 491/* 492 * Remove a named stream from vnode vp. 493 */ 494errno_t 495vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t context) 496{ 497 int error; 498 499 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) 500 error = VNOP_REMOVENAMEDSTREAM(vp, svp, name, flags, context); 501 else 502 error = default_removenamedstream(vp, name, context); 503 504 return (error); 505} 506 507#define NS_IOBUFSIZE (128 * 1024) 508 509/* 510 * Release a named stream shadow file. 511 * 512 * Note: This function is called from two places where we do not need 513 * to check if the vnode has any references held before deleting the 514 * shadow file. Once from vclean() when the vnode is being reclaimed 515 * and we do not hold any references on the vnode. Second time from 516 * default_getnamedstream() when we get an error during shadow stream 517 * file initialization so that other processes who are waiting for the 518 * shadow stream file initialization by the creator will get opportunity 519 * to create and initialize the file again. 520 */ 521errno_t 522vnode_relenamedstream(vnode_t vp, vnode_t svp) { 523 vnode_t dvp; 524 struct componentname cn; 525 char tmpname[80]; 526 errno_t err; 527 528 /* 529 * We need to use the kernel context here. If we used the supplied 530 * VFS context we have no clue whether or not it originated from userland 531 * where it could be subject to a chroot jail. We need to ensure that all 532 * filesystem access to shadow files is done on the same FS regardless of 533 * userland process restrictions. 534 */ 535 vfs_context_t kernelctx = vfs_context_kernel(); 536 537 cache_purge(svp); 538 539 vnode_lock(svp); 540 MAKE_SHADOW_NAME(vp, tmpname); 541 vnode_unlock(svp); 542 543 cn.cn_nameiop = DELETE; 544 cn.cn_flags = ISLASTCN; 545 cn.cn_context = kernelctx; 546 cn.cn_pnbuf = tmpname; 547 cn.cn_pnlen = sizeof(tmpname); 548 cn.cn_nameptr = cn.cn_pnbuf; 549 cn.cn_namelen = strlen(tmpname); 550 551 /* 552 * Obtain the vnode for the shadow files directory. Make sure to 553 * use the kernel ctx as described above. 554 */ 555 err = get_shadow_dir(&dvp); 556 if (err != 0) { 557 return err; 558 } 559 560 (void) VNOP_REMOVE(dvp, svp, &cn, 0, kernelctx); 561 vnode_put(dvp); 562 563 return (0); 564} 565 566/* 567 * Flush a named stream shadow file. 568 * 569 * 'vp' represents the AppleDouble file. 570 * 'svp' represents the shadow file. 571 */ 572errno_t 573vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context) 574{ 575 struct vnode_attr va; 576 uio_t auio = NULL; 577 caddr_t bufptr = NULL; 578 size_t bufsize = 0; 579 size_t offset; 580 size_t iosize; 581 size_t datasize; 582 int error; 583 /* 584 * The kernel context must be used for all I/O to the shadow file 585 * and its namespace operations 586 */ 587 vfs_context_t kernelctx = vfs_context_kernel(); 588 589 /* The supplied context is used for access to the AD file itself */ 590 591 VATTR_INIT(&va); 592 VATTR_WANTED(&va, va_data_size); 593 if (VNOP_GETATTR(svp, &va, context) != 0 || 594 !VATTR_IS_SUPPORTED(&va, va_data_size)) { 595 return (0); 596 } 597 datasize = va.va_data_size; 598 if (datasize == 0) { 599 (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context); 600 return (0); 601 } 602 603 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE); 604 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) { 605 return (ENOMEM); 606 } 607 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 608 offset = 0; 609 610 /* 611 * Copy the shadow stream file data into the resource fork. 612 */ 613 error = VNOP_OPEN(svp, 0, kernelctx); 614 if (error) { 615 printf("vnode_flushnamedstream: err %d opening file\n", error); 616 goto out; 617 } 618 while (offset < datasize) { 619 iosize = MIN(datasize - offset, iosize); 620 621 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ); 622 uio_addiov(auio, (uintptr_t)bufptr, iosize); 623 error = VNOP_READ(svp, auio, 0, kernelctx); 624 if (error) { 625 break; 626 } 627 /* Since there's no truncate xattr we must remove the resource fork. */ 628 if (offset == 0) { 629 error = default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context); 630 if ((error != 0) && (error != ENOATTR)) { 631 break; 632 } 633 } 634 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE); 635 uio_addiov(auio, (uintptr_t)bufptr, iosize); 636 error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context); 637 if (error) { 638 break; 639 } 640 offset += iosize; 641 } 642 643 /* close shadowfile */ 644 (void) VNOP_CLOSE(svp, 0, kernelctx); 645out: 646 if (bufptr) { 647 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize); 648 } 649 if (auio) { 650 uio_free(auio); 651 } 652 return (error); 653} 654 655 656/* 657 * Verify that the vnode 'vp' is a vnode that lives in the shadow 658 * directory. We can't just query the parent pointer directly since 659 * the shadowfile is hooked up to the actual file it's a stream for. 660 */ 661errno_t vnode_verifynamedstream(vnode_t vp) { 662 int error; 663 struct vnode *shadow_dvp = NULL; 664 struct vnode *shadowfile = NULL; 665 struct componentname cn; 666 667 /* 668 * We need to use the kernel context here. If we used the supplied 669 * VFS context we have no clue whether or not it originated from userland 670 * where it could be subject to a chroot jail. We need to ensure that all 671 * filesystem access to shadow files is done on the same FS regardless of 672 * userland process restrictions. 673 */ 674 vfs_context_t kernelctx = vfs_context_kernel(); 675 char tmpname[80]; 676 677 678 /* Get the shadow directory vnode */ 679 error = get_shadow_dir(&shadow_dvp); 680 if (error) { 681 return error; 682 } 683 684 /* Re-generate the shadow name in the buffer */ 685 MAKE_SHADOW_NAME (vp, tmpname); 686 687 /* Look up item in shadow dir */ 688 bzero(&cn, sizeof(cn)); 689 cn.cn_nameiop = LOOKUP; 690 cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK; 691 cn.cn_context = kernelctx; 692 cn.cn_pnbuf = tmpname; 693 cn.cn_pnlen = sizeof(tmpname); 694 cn.cn_nameptr = cn.cn_pnbuf; 695 cn.cn_namelen = strlen(tmpname); 696 697 if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, kernelctx) == 0) { 698 /* is the pointer the same? */ 699 if (shadowfile == vp) { 700 error = 0; 701 } 702 else { 703 error = EPERM; 704 } 705 /* drop the iocount acquired */ 706 vnode_put (shadowfile); 707 } 708 709 /* Drop iocount on shadow dir */ 710 vnode_put (shadow_dvp); 711 return error; 712} 713 714/* 715 * Access or create the shadow file as needed. 716 * 717 * 'makestream' with non-zero value means that we need to guarantee we were the 718 * creator of the shadow file. 719 * 720 * 'context' is the user supplied context for the original VFS operation that 721 * caused us to need a shadow file. 722 * 723 * int pointed to by 'creator' is nonzero if we created the shadowfile. 724 */ 725static int 726getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, 727 int *creator, vfs_context_t context) 728{ 729 vnode_t dvp = NULLVP; 730 vnode_t svp = NULLVP; 731 struct componentname cn; 732 struct vnode_attr va; 733 char tmpname[80]; 734 size_t datasize = 0; 735 int error = 0; 736 int retries = 0; 737 vfs_context_t kernelctx = vfs_context_kernel(); 738 739retry_create: 740 *creator = 0; 741 /* Establish a unique file name. */ 742 MAKE_SHADOW_NAME(vp, tmpname); 743 bzero(&cn, sizeof(cn)); 744 cn.cn_nameiop = LOOKUP; 745 cn.cn_flags = ISLASTCN; 746 cn.cn_context = context; 747 cn.cn_pnbuf = tmpname; 748 cn.cn_pnlen = sizeof(tmpname); 749 cn.cn_nameptr = cn.cn_pnbuf; 750 cn.cn_namelen = strlen(tmpname); 751 752 /* Pick up uid, gid, mode and date from original file. */ 753 VATTR_INIT(&va); 754 VATTR_WANTED(&va, va_uid); 755 VATTR_WANTED(&va, va_gid); 756 VATTR_WANTED(&va, va_mode); 757 VATTR_WANTED(&va, va_create_time); 758 VATTR_WANTED(&va, va_modify_time); 759 if (VNOP_GETATTR(vp, &va, context) != 0 || 760 !VATTR_IS_SUPPORTED(&va, va_uid) || 761 !VATTR_IS_SUPPORTED(&va, va_gid) || 762 !VATTR_IS_SUPPORTED(&va, va_mode)) { 763 va.va_uid = KAUTH_UID_NONE; 764 va.va_gid = KAUTH_GID_NONE; 765 va.va_mode = S_IRUSR | S_IWUSR; 766 } 767 va.va_vaflags = VA_EXCLUSIVE; 768 VATTR_SET(&va, va_type, VREG); 769 /* We no longer change the access, but we still hide it. */ 770 VATTR_SET(&va, va_flags, UF_HIDDEN); 771 772 /* Obtain the vnode for the shadow files directory. */ 773 if (get_shadow_dir(&dvp) != 0) { 774 error = ENOTDIR; 775 goto out; 776 } 777 if (!makestream) { 778 /* See if someone else already has it open. */ 779 if (VNOP_LOOKUP(dvp, &svp, &cn, kernelctx) == 0) { 780 /* Double check existence by asking for size. */ 781 VATTR_INIT(&va); 782 VATTR_WANTED(&va, va_data_size); 783 if (VNOP_GETATTR(svp, &va, context) == 0 && 784 VATTR_IS_SUPPORTED(&va, va_data_size)) { 785 goto out; /* OK to use. */ 786 } 787 } 788 789 /* 790 * Otherwise make sure the resource fork data exists. 791 * Use the supplied context for accessing the AD file. 792 */ 793 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize, 794 XATTR_NOSECURITY, context); 795 /* 796 * To maintain binary compatibility with legacy Carbon 797 * emulated resource fork support, if the resource fork 798 * doesn't exist but the Finder Info does, then act as 799 * if an empty resource fork is present (see 4724359). 800 */ 801 if ((error == ENOATTR) && 802 (vn_getxattr(vp, XATTR_FINDERINFO_NAME, NULL, &datasize, 803 XATTR_NOSECURITY, context) == 0)) { 804 datasize = 0; 805 error = 0; 806 } else { 807 if (error) { 808 goto out; 809 } 810 811 /* If the resource fork exists, its size is expected to be non-zero. */ 812 if (datasize == 0) { 813 error = ENOATTR; 814 goto out; 815 } 816 } 817 } 818 /* Create the shadow stream file. */ 819 error = VNOP_CREATE(dvp, &svp, &cn, &va, kernelctx); 820 if (error == 0) { 821 vnode_recycle(svp); 822 *creator = 1; 823 } 824 else if ((error == EEXIST) && !makestream) { 825 error = VNOP_LOOKUP(dvp, &svp, &cn, kernelctx); 826 } 827 else if ((error == ENOENT) && !makestream) { 828 /* 829 * We could have raced with a rmdir on the shadow directory 830 * post-lookup. Retry from the beginning, 1x only, to 831 * try and see if we need to re-create the shadow directory 832 * in get_shadow_dir. 833 */ 834 if (retries == 0) { 835 retries++; 836 if (dvp) { 837 vnode_put (dvp); 838 dvp = NULLVP; 839 } 840 if (svp) { 841 vnode_put (svp); 842 svp = NULLVP; 843 } 844 goto retry_create; 845 } 846 /* Otherwise, just error out normally below */ 847 } 848 849out: 850 if (dvp) { 851 vnode_put(dvp); 852 } 853 if (error) { 854 /* On errors, clean up shadow stream file. */ 855 if (svp) { 856 vnode_put(svp); 857 svp = NULLVP; 858 } 859 } 860 *svpp = svp; 861 if (rsrcsize) { 862 *rsrcsize = datasize; 863 } 864 return (error); 865} 866 867 868static int 869default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context) 870{ 871 vnode_t svp = NULLVP; 872 uio_t auio = NULL; 873 caddr_t bufptr = NULL; 874 size_t bufsize = 0; 875 size_t datasize = 0; 876 int creator; 877 int error; 878 879 /* need the kernel context for accessing the shadowfile */ 880 vfs_context_t kernelctx = vfs_context_kernel(); 881 882 /* 883 * Only the "com.apple.ResourceFork" stream is supported here. 884 */ 885 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) { 886 *svpp = NULLVP; 887 return (ENOATTR); 888 } 889retry: 890 /* 891 * Obtain a shadow file for the resource fork I/O. 892 * 893 * Need to pass along the supplied context so that getshadowfile 894 * can access the AD file as needed, using it. 895 */ 896 error = getshadowfile(vp, &svp, 0, &datasize, &creator, context); 897 if (error) { 898 *svpp = NULLVP; 899 return (error); 900 } 901 902 /* 903 * The creator of the shadow file provides its file data, 904 * all other threads should wait until its ready. In order to 905 * prevent a deadlock during error codepaths, we need to check if the 906 * vnode is being created, or if it has failed out. Regardless of success or 907 * failure, we set the VISSHADOW bit on the vnode, so we check that 908 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't, 909 * then we can infer the creator isn't done yet. If it's there, but 910 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should 911 * try again. 912 */ 913 if (!creator) { 914 vnode_lock(svp); 915 if (svp->v_flag & VISNAMEDSTREAM) { 916 /* data is ready, go use it */ 917 vnode_unlock(svp); 918 goto out; 919 } else { 920 /* It's not ready, wait for it (sleep using v_parent as channel) */ 921 if ((svp->v_flag & VISSHADOW)) { 922 /* 923 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other 924 * thread is done with this vnode. Just unlock the vnode and try again 925 */ 926 vnode_unlock(svp); 927 } 928 else { 929 /* Otherwise, sleep if the shadow file is not created yet */ 930 msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP, 931 "getnamedstream", NULL); 932 } 933 vnode_put(svp); 934 svp = NULLVP; 935 goto retry; 936 } 937 } 938 939 /* 940 * Copy the real resource fork data into shadow stream file. 941 */ 942 if (op == NS_OPEN && datasize != 0) { 943 size_t offset; 944 size_t iosize; 945 946 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE); 947 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) { 948 error = ENOMEM; 949 goto out; 950 } 951 952 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 953 offset = 0; 954 955 /* open the shadow file */ 956 error = VNOP_OPEN(svp, 0, kernelctx); 957 if (error) { 958 goto out; 959 } 960 while (offset < datasize) { 961 size_t tmpsize; 962 963 iosize = MIN(datasize - offset, iosize); 964 965 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ); 966 uio_addiov(auio, (uintptr_t)bufptr, iosize); 967 /* use supplied ctx for AD file */ 968 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize, 969 XATTR_NOSECURITY, context); 970 if (error) { 971 break; 972 } 973 974 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE); 975 uio_addiov(auio, (uintptr_t)bufptr, iosize); 976 /* kernel context for writing shadowfile */ 977 error = VNOP_WRITE(svp, auio, 0, kernelctx); 978 if (error) { 979 break; 980 } 981 offset += iosize; 982 } 983 984 /* close shadow file */ 985 (void) VNOP_CLOSE(svp, 0, kernelctx); 986 } 987out: 988 /* Wake up anyone waiting for svp file content */ 989 if (creator) { 990 if (error == 0) { 991 vnode_lock(svp); 992 /* VISSHADOW would be set later on anyway, so we set it now */ 993 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW); 994 wakeup((caddr_t)&svp->v_parent); 995 vnode_unlock(svp); 996 } else { 997 /* On post create errors, get rid of the shadow file. This 998 * way if there is another process waiting for initialization 999 * of the shadowfile by the current process will wake up and 1000 * retry by creating and initializing the shadow file again. 1001 * Also add the VISSHADOW bit here to indicate we're done operating 1002 * on this vnode. 1003 */ 1004 (void)vnode_relenamedstream(vp, svp); 1005 vnode_lock (svp); 1006 svp->v_flag |= VISSHADOW; 1007 wakeup((caddr_t)&svp->v_parent); 1008 vnode_unlock(svp); 1009 } 1010 } 1011 1012 if (bufptr) { 1013 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize); 1014 } 1015 if (auio) { 1016 uio_free(auio); 1017 } 1018 if (error) { 1019 /* On errors, clean up shadow stream file. */ 1020 if (svp) { 1021 vnode_put(svp); 1022 svp = NULLVP; 1023 } 1024 } 1025 *svpp = svp; 1026 return (error); 1027} 1028 1029static int 1030default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context) 1031{ 1032 int creator; 1033 int error; 1034 1035 /* 1036 * Only the "com.apple.ResourceFork" stream is supported here. 1037 */ 1038 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) { 1039 *svpp = NULLVP; 1040 return (ENOATTR); 1041 } 1042 1043 /* Supply the context to getshadowfile so it can manipulate the AD file */ 1044 error = getshadowfile(vp, svpp, 1, NULL, &creator, context); 1045 1046 /* 1047 * Wake up any waiters over in default_getnamedstream(). 1048 */ 1049 if ((error == 0) && (*svpp != NULL) && creator) { 1050 vnode_t svp = *svpp; 1051 1052 vnode_lock(svp); 1053 /* If we're the creator, mark it as a named stream */ 1054 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW); 1055 /* Wakeup any waiters on the v_parent channel */ 1056 wakeup((caddr_t)&svp->v_parent); 1057 vnode_unlock(svp); 1058 1059 } 1060 1061 return (error); 1062} 1063 1064static int 1065default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context) 1066{ 1067 /* 1068 * Only the "com.apple.ResourceFork" stream is supported here. 1069 */ 1070 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) { 1071 return (ENOATTR); 1072 } 1073 /* 1074 * XXX - what about other opened instances? 1075 */ 1076 return default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context); 1077} 1078 1079static int 1080get_shadow_dir(vnode_t *sdvpp) { 1081 vnode_t dvp = NULLVP; 1082 vnode_t sdvp = NULLVP; 1083 struct componentname cn; 1084 struct vnode_attr va; 1085 char tmpname[80]; 1086 uint32_t tmp_fsid; 1087 int error; 1088 vfs_context_t kernelctx = vfs_context_kernel(); 1089 1090 bzero(tmpname, sizeof(tmpname)); 1091 MAKE_SHADOW_DIRNAME(rootvnode, tmpname); 1092 /* 1093 * Look up the shadow directory to ensure that it still exists. 1094 * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues 1095 * in caching it when multiple threads may be trying to manipulate the pointers. 1096 * 1097 * Make sure to use the kernel context. We want a singular view of 1098 * the shadow dir regardless of chrooted processes. 1099 */ 1100 error = vnode_lookup(tmpname, 0, &sdvp, kernelctx); 1101 if (error == 0) { 1102 /* 1103 * If we get here, then we have successfully looked up the shadow dir, 1104 * and it has an iocount from the lookup. Return the vp in the output argument. 1105 */ 1106 *sdvpp = sdvp; 1107 return (0); 1108 } 1109 /* In the failure case, no iocount is acquired */ 1110 sdvp = NULLVP; 1111 bzero (tmpname, sizeof(tmpname)); 1112 1113 /* 1114 * Obtain the vnode for "/var/run" directory using the kernel 1115 * context. 1116 * 1117 * This is defined in the SHADOW_DIR_CONTAINER macro 1118 */ 1119 if (vnode_lookup(SHADOW_DIR_CONTAINER, 0, &dvp, kernelctx) != 0) { 1120 error = ENOTSUP; 1121 goto out; 1122 } 1123 1124 /* 1125 * Create the shadow stream directory. 1126 * 'dvp' below suggests the parent directory so 1127 * we only need to provide the leaf entry name 1128 */ 1129 MAKE_SHADOW_DIR_LEAF(rootvnode, tmpname); 1130 bzero(&cn, sizeof(cn)); 1131 cn.cn_nameiop = LOOKUP; 1132 cn.cn_flags = ISLASTCN; 1133 cn.cn_context = kernelctx; 1134 cn.cn_pnbuf = tmpname; 1135 cn.cn_pnlen = sizeof(tmpname); 1136 cn.cn_nameptr = cn.cn_pnbuf; 1137 cn.cn_namelen = strlen(tmpname); 1138 1139 /* 1140 * owned by root, only readable by root, hidden 1141 */ 1142 VATTR_INIT(&va); 1143 VATTR_SET(&va, va_uid, 0); 1144 VATTR_SET(&va, va_gid, 0); 1145 VATTR_SET(&va, va_mode, S_IRUSR | S_IXUSR); 1146 VATTR_SET(&va, va_type, VDIR); 1147 VATTR_SET(&va, va_flags, UF_HIDDEN); 1148 va.va_vaflags = VA_EXCLUSIVE; 1149 1150 error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, kernelctx); 1151 1152 /* 1153 * There can be only one winner for an exclusive create. 1154 */ 1155 if (error == EEXIST) { 1156 /* loser has to look up directory */ 1157 error = VNOP_LOOKUP(dvp, &sdvp, &cn, kernelctx); 1158 if (error == 0) { 1159 /* Make sure its in fact a directory */ 1160 if (sdvp->v_type != VDIR) { 1161 goto baddir; 1162 } 1163 /* Obtain the fsid for /var/run directory */ 1164 VATTR_INIT(&va); 1165 VATTR_WANTED(&va, va_fsid); 1166 if (VNOP_GETATTR(dvp, &va, kernelctx) != 0 || 1167 !VATTR_IS_SUPPORTED(&va, va_fsid)) { 1168 goto baddir; 1169 } 1170 tmp_fsid = va.va_fsid; 1171 1172 VATTR_INIT(&va); 1173 VATTR_WANTED(&va, va_uid); 1174 VATTR_WANTED(&va, va_gid); 1175 VATTR_WANTED(&va, va_mode); 1176 VATTR_WANTED(&va, va_fsid); 1177 VATTR_WANTED(&va, va_dirlinkcount); 1178 VATTR_WANTED(&va, va_acl); 1179 /* Provide defaults for attrs that may not be supported */ 1180 va.va_dirlinkcount = 1; 1181 va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE; 1182 1183 if (VNOP_GETATTR(sdvp, &va, kernelctx) != 0 || 1184 !VATTR_IS_SUPPORTED(&va, va_uid) || 1185 !VATTR_IS_SUPPORTED(&va, va_gid) || 1186 !VATTR_IS_SUPPORTED(&va, va_mode) || 1187 !VATTR_IS_SUPPORTED(&va, va_fsid)) { 1188 goto baddir; 1189 } 1190 /* 1191 * Make sure its what we want: 1192 * - owned by root 1193 * - not writable by anyone 1194 * - on same file system as /var/run 1195 * - not a hard-linked directory 1196 * - no ACLs (they might grant write access) 1197 */ 1198 if ((va.va_uid != 0) || (va.va_gid != 0) || 1199 (va.va_mode & (S_IWUSR | S_IRWXG | S_IRWXO)) || 1200 (va.va_fsid != tmp_fsid) || 1201 (va.va_dirlinkcount != 1) || 1202 (va.va_acl != (kauth_acl_t) KAUTH_FILESEC_NONE)) { 1203 goto baddir; 1204 } 1205 } 1206 } 1207out: 1208 if (dvp) { 1209 vnode_put(dvp); 1210 } 1211 if (error) { 1212 /* On errors, clean up shadow stream directory. */ 1213 if (sdvp) { 1214 vnode_put(sdvp); 1215 sdvp = NULLVP; 1216 } 1217 } 1218 *sdvpp = sdvp; 1219 return (error); 1220 1221baddir: 1222 /* This is not the dir we're looking for, move along */ 1223 ++shadow_sequence; /* try something else next time */ 1224 error = ENOTDIR; 1225 goto out; 1226} 1227#endif /* NAMEDSTREAMS */ 1228 1229 1230#if CONFIG_APPLEDOUBLE 1231/* 1232 * Default Implementation (Non-native EA) 1233 */ 1234 1235 1236/* 1237 Typical "._" AppleDouble Header File layout: 1238 ------------------------------------------------------------ 1239 MAGIC 0x00051607 1240 VERSION 0x00020000 1241 FILLER 0 1242 COUNT 2 1243 .-- AD ENTRY[0] Finder Info Entry (must be first) 1244 .--+-- AD ENTRY[1] Resource Fork Entry (must be last) 1245 | '-> FINDER INFO 1246 | ///////////// Fixed Size Data (32 bytes) 1247 | EXT ATTR HDR 1248 | ///////////// 1249 | ATTR ENTRY[0] --. 1250 | ATTR ENTRY[1] --+--. 1251 | ATTR ENTRY[2] --+--+--. 1252 | ... | | | 1253 | ATTR ENTRY[N] --+--+--+--. 1254 | ATTR DATA 0 <-' | | | 1255 | //////////// | | | 1256 | ATTR DATA 1 <----' | | 1257 | ///////////// | | 1258 | ATTR DATA 2 <-------' | 1259 | ///////////// | 1260 | ... | 1261 | ATTR DATA N <----------' 1262 | ///////////// 1263 | Attribute Free Space 1264 | 1265 '----> RESOURCE FORK 1266 ///////////// Variable Sized Data 1267 ///////////// 1268 ///////////// 1269 ///////////// 1270 ///////////// 1271 ///////////// 1272 ... 1273 ///////////// 1274 1275 ------------------------------------------------------------ 1276 1277 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are 1278 stored as part of the Finder Info. The length in the Finder 1279 Info AppleDouble entry includes the length of the extended 1280 attribute header, attribute entries, and attribute data. 1281*/ 1282 1283 1284/* 1285 * On Disk Data Structures 1286 * 1287 * Note: Motorola 68K alignment and big-endian. 1288 * 1289 * See RFC 1740 for additional information about the AppleDouble file format. 1290 * 1291 */ 1292 1293#define ADH_MAGIC 0x00051607 1294#define ADH_VERSION 0x00020000 1295#define ADH_MACOSX "Mac OS X " 1296 1297/* 1298 * AppleDouble Entry ID's 1299 */ 1300#define AD_DATA 1 /* Data fork */ 1301#define AD_RESOURCE 2 /* Resource fork */ 1302#define AD_REALNAME 3 /* File�s name on home file system */ 1303#define AD_COMMENT 4 /* Standard Mac comment */ 1304#define AD_ICONBW 5 /* Mac black & white icon */ 1305#define AD_ICONCOLOR 6 /* Mac color icon */ 1306#define AD_UNUSED 7 /* Not used */ 1307#define AD_FILEDATES 8 /* File dates; create, modify, etc */ 1308#define AD_FINDERINFO 9 /* Mac Finder info & extended info */ 1309#define AD_MACINFO 10 /* Mac file info, attributes, etc */ 1310#define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */ 1311#define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */ 1312#define AD_AFPNAME 13 /* Short name on AFP server */ 1313#define AD_AFPINFO 14 /* AFP file info, attrib., etc */ 1314#define AD_AFPDIRID 15 /* AFP directory ID */ 1315#define AD_ATTRIBUTES AD_FINDERINFO 1316 1317 1318#define ATTR_FILE_PREFIX "._" 1319#define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */ 1320 1321#define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */ 1322 1323/* Implementation Limits */ 1324#define ATTR_MAX_SIZE AD_XATTR_MAXSIZE 1325#define ATTR_MAX_HDR_SIZE 65536 1326/* 1327 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header 1328 * size supported (including the attribute entries). All of 1329 * the attribute entries must reside within this limit. If 1330 * any of the attribute data crosses the ATTR_MAX_HDR_SIZE 1331 * boundry, then all of the attribute data I/O is performed 1332 * separately from the attribute header I/O. 1333 * 1334 * In particular, all of the attr_entry structures must lie 1335 * completely within the first ATTR_MAX_HDR_SIZE bytes of the 1336 * AppleDouble file. However, the attribute data (i.e. the 1337 * contents of the extended attributes) may extend beyond the 1338 * first ATTR_MAX_HDR_SIZE bytes of the file. Note that this 1339 * limit is to allow the implementation to optimize by reading 1340 * the first ATTR_MAX_HDR_SIZE bytes of the file. 1341 */ 1342 1343 1344#define FINDERINFOSIZE 32 1345 1346typedef struct apple_double_entry { 1347 u_int32_t type; /* entry type: see list, 0 invalid */ 1348 u_int32_t offset; /* entry data offset from the beginning of the file. */ 1349 u_int32_t length; /* entry data length in bytes. */ 1350} __attribute__((aligned(2), packed)) apple_double_entry_t; 1351 1352 1353typedef struct apple_double_header { 1354 u_int32_t magic; /* == ADH_MAGIC */ 1355 u_int32_t version; /* format version: 2 = 0x00020000 */ 1356 u_int32_t filler[4]; 1357 u_int16_t numEntries; /* number of entries which follow */ 1358 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */ 1359 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */ 1360 u_int8_t pad[2]; /* get better alignment inside attr_header */ 1361} __attribute__((aligned(2), packed)) apple_double_header_t; 1362 1363#define ADHDRSIZE (4+4+16+2) 1364 1365/* Entries are aligned on 4 byte boundaries */ 1366typedef struct attr_entry { 1367 u_int32_t offset; /* file offset to data */ 1368 u_int32_t length; /* size of attribute data */ 1369 u_int16_t flags; 1370 u_int8_t namelen; 1371 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */ 1372} __attribute__((aligned(2), packed)) attr_entry_t; 1373 1374 1375/* Header + entries must fit into 64K. Data may extend beyond 64K. */ 1376typedef struct attr_header { 1377 apple_double_header_t appledouble; 1378 u_int32_t magic; /* == ATTR_HDR_MAGIC */ 1379 u_int32_t debug_tag; /* for debugging == file id of owning file */ 1380 u_int32_t total_size; /* file offset of end of attribute header + entries + data */ 1381 u_int32_t data_start; /* file offset to attribute data area */ 1382 u_int32_t data_length; /* length of attribute data area */ 1383 u_int32_t reserved[3]; 1384 u_int16_t flags; 1385 u_int16_t num_attrs; 1386} __attribute__((aligned(2), packed)) attr_header_t; 1387 1388 1389/* Empty Resource Fork Header */ 1390typedef struct rsrcfork_header { 1391 u_int32_t fh_DataOffset; 1392 u_int32_t fh_MapOffset; 1393 u_int32_t fh_DataLength; 1394 u_int32_t fh_MapLength; 1395 u_int8_t systemData[112]; 1396 u_int8_t appData[128]; 1397 u_int32_t mh_DataOffset; 1398 u_int32_t mh_MapOffset; 1399 u_int32_t mh_DataLength; 1400 u_int32_t mh_MapLength; 1401 u_int32_t mh_Next; 1402 u_int16_t mh_RefNum; 1403 u_int8_t mh_Attr; 1404 u_int8_t mh_InMemoryAttr; 1405 u_int16_t mh_Types; 1406 u_int16_t mh_Names; 1407 u_int16_t typeCount; 1408} __attribute__((aligned(2), packed)) rsrcfork_header_t; 1409 1410#define RF_FIRST_RESOURCE 256 1411#define RF_NULL_MAP_LENGTH 30 1412#define RF_EMPTY_TAG "This resource fork intentionally left blank " 1413 1414/* Runtime information about the attribute file. */ 1415typedef struct attr_info { 1416 vfs_context_t context; 1417 vnode_t filevp; 1418 size_t filesize; 1419 size_t iosize; 1420 u_int8_t *rawdata; 1421 size_t rawsize; /* minimum of filesize or ATTR_MAX_HDR_SIZE */ 1422 apple_double_header_t *filehdr; 1423 apple_double_entry_t *finderinfo; 1424 apple_double_entry_t *rsrcfork; 1425 attr_header_t *attrhdr; 1426 attr_entry_t *attr_entry; 1427 u_int8_t readonly; 1428 u_int8_t emptyfinderinfo; 1429} attr_info_t; 1430 1431 1432#define ATTR_SETTING 1 1433 1434#define ATTR_ALIGN 3L /* Use four-byte alignment */ 1435 1436#define ATTR_ENTRY_LENGTH(namelen) \ 1437 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN)) 1438 1439#define ATTR_NEXT(ae) \ 1440 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen)) 1441 1442#define ATTR_VALID(ae, ai) \ 1443 ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize)) 1444 1445#define SWAP16(x) OSSwapBigToHostInt16((x)) 1446#define SWAP32(x) OSSwapBigToHostInt32((x)) 1447#define SWAP64(x) OSSwapBigToHostInt64((x)) 1448 1449 1450static u_int32_t emptyfinfo[8] = {0}; 1451 1452 1453/* 1454 * Local support routines 1455 */ 1456static void close_xattrfile(vnode_t xvp, int fileflags, vfs_context_t context); 1457 1458static int open_xattrfile(vnode_t vp, int fileflags, vnode_t *xvpp, vfs_context_t context); 1459 1460static int create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context); 1461 1462static int remove_xattrfile(vnode_t xvp, vfs_context_t context); 1463 1464static int get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context); 1465 1466static void rel_xattrinfo(attr_info_t *ainfop); 1467 1468static int write_xattrinfo(attr_info_t *ainfop); 1469 1470static void init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr); 1471 1472static int lock_xattrfile(vnode_t xvp, short locktype, vfs_context_t context); 1473 1474static int unlock_xattrfile(vnode_t xvp, vfs_context_t context); 1475 1476 1477#if BYTE_ORDER == LITTLE_ENDIAN 1478 static void swap_adhdr(apple_double_header_t *adh); 1479 static void swap_attrhdr(attr_header_t *ah, attr_info_t* info); 1480 1481#else 1482#define swap_adhdr(x) 1483#define swap_attrhdr(x, y) 1484#endif 1485 1486static int check_and_swap_attrhdr(attr_header_t *ah, attr_info_t* ainfop); 1487static int shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context); 1488static int shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context); 1489 1490 1491/* 1492 * Sanity check and swap the header of an AppleDouble file. Assumes the buffer 1493 * is in big endian (as it would exist on disk). Verifies the following: 1494 * - magic field 1495 * - version field 1496 * - number of entries 1497 * - that each entry fits within the file size 1498 * 1499 * If the header is invalid, ENOATTR is returned. 1500 * 1501 * NOTE: Does not attempt to validate the extended attributes header that 1502 * may be embedded in the Finder Info entry. 1503 */ 1504static int check_and_swap_apple_double_header(attr_info_t *ainfop) 1505{ 1506 int i, j; 1507 u_int32_t header_end; 1508 u_int32_t entry_end; 1509 size_t rawsize; 1510 apple_double_header_t *header; 1511 1512 rawsize = ainfop->rawsize; 1513 header = (apple_double_header_t *) ainfop->rawdata; 1514 1515 /* Is the file big enough to contain an AppleDouble header? */ 1516 if (rawsize < offsetof(apple_double_header_t, entries)) 1517 return ENOATTR; 1518 1519 /* Swap the AppleDouble header fields to native order */ 1520 header->magic = SWAP32(header->magic); 1521 header->version = SWAP32(header->version); 1522 header->numEntries = SWAP16(header->numEntries); 1523 1524 /* Sanity check the AppleDouble header fields */ 1525 if (header->magic != ADH_MAGIC || 1526 header->version != ADH_VERSION || 1527 header->numEntries < 1 || 1528 header->numEntries > 15) { 1529 return ENOATTR; 1530 } 1531 1532 /* Calculate where the entries[] array ends */ 1533 header_end = offsetof(apple_double_header_t, entries) + 1534 header->numEntries * sizeof(apple_double_entry_t); 1535 1536 /* Is the file big enough to contain the AppleDouble entries? */ 1537 if (rawsize < header_end) { 1538 return ENOATTR; 1539 } 1540 1541 /* Swap and sanity check each AppleDouble entry */ 1542 for (i=0; i<header->numEntries; i++) { 1543 /* Swap the per-entry fields to native order */ 1544 header->entries[i].type = SWAP32(header->entries[i].type); 1545 header->entries[i].offset = SWAP32(header->entries[i].offset); 1546 header->entries[i].length = SWAP32(header->entries[i].length); 1547 1548 entry_end = header->entries[i].offset + header->entries[i].length; 1549 1550 /* 1551 * Does the entry's content start within the header itself, 1552 * did the addition overflow, or does the entry's content 1553 * extend past the end of the file? 1554 */ 1555 if (header->entries[i].offset < header_end || 1556 entry_end < header->entries[i].offset || 1557 entry_end > ainfop->filesize) { 1558 return ENOATTR; 1559 } 1560 1561 /* 1562 * Does the current entry's content overlap with a previous 1563 * entry's content? 1564 * 1565 * Yes, this is O(N**2), and there are more efficient algorithms 1566 * for testing pairwise overlap of N ranges when N is large. 1567 * But we have already ensured N < 16, and N is almost always 2. 1568 * So there's no point in using a more complex algorithm. 1569 */ 1570 1571 for (j=0; j<i; j++) { 1572 if (entry_end > header->entries[j].offset && 1573 header->entries[j].offset + header->entries[j].length > header->entries[i].offset) { 1574 return ENOATTR; 1575 } 1576 } 1577 } 1578 1579 return 0; 1580} 1581 1582 1583 1584/* 1585 * Retrieve the data of an extended attribute. 1586 */ 1587static int 1588default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, 1589 __unused int options, vfs_context_t context) 1590{ 1591 vnode_t xvp = NULL; 1592 attr_info_t ainfo; 1593 attr_header_t *header; 1594 attr_entry_t *entry; 1595 u_int8_t *attrdata; 1596 size_t datalen; 1597 int namelen; 1598 int isrsrcfork; 1599 int fileflags; 1600 int i; 1601 int error; 1602 1603 fileflags = FREAD; 1604 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) { 1605 isrsrcfork = 1; 1606 /* 1607 * Open the file locked (shared) since the Carbon 1608 * File Manager may have the Apple Double file open 1609 * and could be changing the resource fork. 1610 */ 1611 fileflags |= O_SHLOCK; 1612 } else { 1613 isrsrcfork = 0; 1614 } 1615 1616 if ((error = open_xattrfile(vp, fileflags, &xvp, context))) { 1617 return (error); 1618 } 1619 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) { 1620 close_xattrfile(xvp, fileflags, context); 1621 return (error); 1622 } 1623 1624 /* Get the Finder Info. */ 1625 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) { 1626 1627 if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) { 1628 error = ENOATTR; 1629 } else if (uio == NULL) { 1630 *size = FINDERINFOSIZE; 1631 error = 0; 1632 } else if (uio_offset(uio) != 0) { 1633 error = EINVAL; 1634 } else if (uio_resid(uio) < FINDERINFOSIZE) { 1635 error = ERANGE; 1636 } else { 1637 attrdata = (u_int8_t*)ainfo.filehdr + ainfo.finderinfo->offset; 1638 error = uiomove((caddr_t)attrdata, FINDERINFOSIZE, uio); 1639 } 1640 goto out; 1641 } 1642 1643 /* Read the Resource Fork. */ 1644 if (isrsrcfork) { 1645 if (!vnode_isreg(vp)) { 1646 error = EPERM; 1647 } else if (ainfo.rsrcfork == NULL) { 1648 error = ENOATTR; 1649 } else if (uio == NULL) { 1650 *size = (size_t)ainfo.rsrcfork->length; 1651 } else { 1652 uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset); 1653 error = VNOP_READ(xvp, uio, 0, context); 1654 if (error == 0) 1655 uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset); 1656 } 1657 goto out; 1658 } 1659 1660 if (ainfo.attrhdr == NULL || ainfo.attr_entry == NULL) { 1661 error = ENOATTR; 1662 goto out; 1663 } 1664 if (uio_offset(uio) != 0) { 1665 error = EINVAL; 1666 goto out; 1667 } 1668 error = ENOATTR; 1669 namelen = strlen(name) + 1; 1670 header = ainfo.attrhdr; 1671 entry = ainfo.attr_entry; 1672 /* 1673 * Search for attribute name in the header. 1674 */ 1675 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) { 1676 if (strncmp((const char *)entry->name, name, namelen) == 0) { 1677 datalen = (size_t)entry->length; 1678 if (uio == NULL) { 1679 *size = datalen; 1680 error = 0; 1681 break; 1682 } 1683 if (uio_resid(uio) < (user_ssize_t)datalen) { 1684 error = ERANGE; 1685 break; 1686 } 1687 if (entry->offset + datalen < ATTR_MAX_HDR_SIZE) { 1688 attrdata = ((u_int8_t *)header + entry->offset); 1689 error = uiomove((caddr_t)attrdata, datalen, uio); 1690 } else { 1691 uio_setoffset(uio, entry->offset); 1692 error = VNOP_READ(xvp, uio, 0, context); 1693 uio_setoffset(uio, 0); 1694 } 1695 break; 1696 } 1697 entry = ATTR_NEXT(entry); 1698 } 1699out: 1700 rel_xattrinfo(&ainfo); 1701 close_xattrfile(xvp, fileflags, context); 1702 1703 return (error); 1704} 1705 1706/* 1707 * Set the data of an extended attribute. 1708 */ 1709static int 1710default_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context) 1711{ 1712 vnode_t xvp = NULL; 1713 attr_info_t ainfo; 1714 attr_header_t *header; 1715 attr_entry_t *entry; 1716 attr_entry_t *lastentry; 1717 u_int8_t *attrdata; 1718 size_t datalen; 1719 size_t entrylen; 1720 size_t datafreespace; 1721 int namelen; 1722 int found = 0; 1723 int i; 1724 int splitdata; 1725 int fileflags; 1726 int error; 1727 char finfo[FINDERINFOSIZE]; 1728 1729 datalen = uio_resid(uio); 1730 namelen = strlen(name) + 1; 1731 entrylen = ATTR_ENTRY_LENGTH(namelen); 1732 1733 /* 1734 * By convention, Finder Info that is all zeroes is equivalent to not 1735 * having a Finder Info EA. So if we're trying to set the Finder Info 1736 * to all zeroes, then delete it instead. If a file didn't have an 1737 * AppleDouble file before, this prevents creating an AppleDouble file 1738 * with no useful content. 1739 * 1740 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check 1741 * for all zeroes Finder Info before opening the AppleDouble file. 1742 * But if either of those options were specified, we need to open the 1743 * AppleDouble file to see whether there was already Finder Info (so we 1744 * can return an error if needed); this case is handled further below. 1745 * 1746 * NOTE: this copies the Finder Info data into the "finfo" local. 1747 */ 1748 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) { 1749 /* 1750 * TODO: check the XATTR_CREATE and XATTR_REPLACE flags. 1751 * That means we probably have to open_xattrfile and get_xattrinfo. 1752 */ 1753 if (uio_offset(uio) != 0 || datalen != FINDERINFOSIZE) { 1754 return EINVAL; 1755 } 1756 error = uiomove(finfo, datalen, uio); 1757 if (error) 1758 return error; 1759 if ((options & (XATTR_CREATE|XATTR_REPLACE)) == 0 && 1760 bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) { 1761 error = default_removexattr(vp, name, 0, context); 1762 if (error == ENOATTR) 1763 error = 0; 1764 return error; 1765 } 1766 } 1767 1768start: 1769 /* 1770 * Open the file locked since setting an attribute 1771 * can change the layout of the Apple Double file. 1772 */ 1773 fileflags = FREAD | FWRITE | O_EXLOCK; 1774 if ((error = open_xattrfile(vp, O_CREAT | fileflags, &xvp, context))) { 1775 return (error); 1776 } 1777 if ((error = get_xattrinfo(xvp, ATTR_SETTING, &ainfo, context))) { 1778 close_xattrfile(xvp, fileflags, context); 1779 return (error); 1780 } 1781 1782 /* Set the Finder Info. */ 1783 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) { 1784 if (ainfo.finderinfo && !ainfo.emptyfinderinfo) { 1785 /* attr exists and "create" was specified? */ 1786 if (options & XATTR_CREATE) { 1787 error = EEXIST; 1788 goto out; 1789 } 1790 } else { 1791 /* attr doesn't exists and "replace" was specified? */ 1792 if (options & XATTR_REPLACE) { 1793 error = ENOATTR; 1794 goto out; 1795 } 1796 } 1797 if (options != 0 && bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) { 1798 /* 1799 * Setting the Finder Info to all zeroes is equivalent to 1800 * removing it. Close the xattr file and let 1801 * default_removexattr do the work (including deleting 1802 * the xattr file if there are no other xattrs). 1803 * 1804 * Note that we have to handle the case where the 1805 * Finder Info was already all zeroes, and we ignore 1806 * ENOATTR. 1807 * 1808 * The common case where options == 0 was handled above. 1809 */ 1810 rel_xattrinfo(&ainfo); 1811 close_xattrfile(xvp, fileflags, context); 1812 error = default_removexattr(vp, name, 0, context); 1813 if (error == ENOATTR) 1814 error = 0; 1815 return error; 1816 } 1817 if (ainfo.finderinfo) { 1818 attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset; 1819 bcopy(finfo, attrdata, datalen); 1820 ainfo.iosize = sizeof(attr_header_t); 1821 error = write_xattrinfo(&ainfo); 1822 goto out; 1823 } 1824 error = ENOATTR; 1825 goto out; 1826 } 1827 1828 /* Write the Resource Fork. */ 1829 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) { 1830 u_int32_t endoffset; 1831 1832 if (!vnode_isreg(vp)) { 1833 error = EPERM; 1834 goto out; 1835 } 1836 /* Make sure we have a rsrc fork pointer.. */ 1837 if (ainfo.rsrcfork == NULL) { 1838 error = ENOATTR; 1839 goto out; 1840 } 1841 if (ainfo.rsrcfork) { 1842 if (ainfo.rsrcfork->length != 0) { 1843 if (options & XATTR_CREATE) { 1844 /* attr exists, and create specified ? */ 1845 error = EEXIST; 1846 goto out; 1847 } 1848 } 1849 else { 1850 /* Zero length AD rsrc fork */ 1851 if (options & XATTR_REPLACE) { 1852 /* attr doesn't exist (0-length), but replace specified ? */ 1853 error = ENOATTR; 1854 goto out; 1855 } 1856 } 1857 } 1858 else { 1859 /* We can't do much if we somehow didn't get an AD rsrc pointer */ 1860 error = ENOATTR; 1861 goto out; 1862 } 1863 1864 endoffset = uio_resid(uio) + uio_offset(uio); /* new size */ 1865 uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset); 1866 error = VNOP_WRITE(xvp, uio, 0, context); 1867 if (error) 1868 goto out; 1869 uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset); 1870 if (endoffset > ainfo.rsrcfork->length) { 1871 ainfo.rsrcfork->length = endoffset; 1872 ainfo.iosize = sizeof(attr_header_t); 1873 error = write_xattrinfo(&ainfo); 1874 goto out; 1875 } 1876 goto out; 1877 } 1878 1879 if (datalen > ATTR_MAX_SIZE) { 1880 return (E2BIG); /* EINVAL instead ? */ 1881 } 1882 1883 if (ainfo.attrhdr == NULL) { 1884 error = ENOATTR; 1885 goto out; 1886 } 1887 header = ainfo.attrhdr; 1888 entry = ainfo.attr_entry; 1889 1890 /* Check if data area crosses the maximum header size. */ 1891 if ((header->data_start + header->data_length + entrylen + datalen) > ATTR_MAX_HDR_SIZE) 1892 splitdata = 1; /* do data I/O separately */ 1893 else 1894 splitdata = 0; 1895 1896 /* 1897 * See if attribute already exists. 1898 */ 1899 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) { 1900 if (strncmp((const char *)entry->name, name, namelen) == 0) { 1901 found = 1; 1902 break; 1903 } 1904 entry = ATTR_NEXT(entry); 1905 } 1906 1907 if (found) { 1908 if (options & XATTR_CREATE) { 1909 error = EEXIST; 1910 goto out; 1911 } 1912 if (datalen == entry->length) { 1913 if (splitdata) { 1914 uio_setoffset(uio, entry->offset); 1915 error = VNOP_WRITE(xvp, uio, 0, context); 1916 uio_setoffset(uio, 0); 1917 if (error) { 1918 printf("setxattr: VNOP_WRITE error %d\n", error); 1919 } 1920 } else { 1921 attrdata = (u_int8_t *)header + entry->offset; 1922 error = uiomove((caddr_t)attrdata, datalen, uio); 1923 if (error) 1924 goto out; 1925 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length; 1926 error = write_xattrinfo(&ainfo); 1927 if (error) { 1928 printf("setxattr: write_xattrinfo error %d\n", error); 1929 } 1930 } 1931 goto out; 1932 } else { 1933 /* 1934 * Brute force approach - just remove old entry and set new entry. 1935 */ 1936 found = 0; 1937 rel_xattrinfo(&ainfo); 1938 close_xattrfile(xvp, fileflags, context); 1939 error = default_removexattr(vp, name, options, context); 1940 if (error) { 1941 return (error); 1942 } 1943 /* Clear XATTR_REPLACE option since we just removed the attribute. */ 1944 options &= ~XATTR_REPLACE; 1945 goto start; /* start over */ 1946 } 1947 1948 } 1949 1950 if (options & XATTR_REPLACE) { 1951 error = ENOATTR; /* nothing there to replace */ 1952 goto out; 1953 } 1954 /* Check if header size limit has been reached. */ 1955 if ((header->data_start + entrylen) > ATTR_MAX_HDR_SIZE) { 1956 error = ENOSPC; 1957 goto out; 1958 } 1959 1960 datafreespace = header->total_size - (header->data_start + header->data_length); 1961 1962 /* Check if we need more space. */ 1963 if ((datalen + entrylen) > datafreespace) { 1964 size_t growsize; 1965 1966 growsize = roundup((datalen + entrylen) - datafreespace, ATTR_BUF_SIZE); 1967 1968 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */ 1969 if (!splitdata && (header->total_size + growsize) > ATTR_MAX_HDR_SIZE) { 1970 growsize = ATTR_MAX_HDR_SIZE - header->total_size; 1971 } 1972 1973 ainfo.filesize += growsize; 1974 error = vnode_setsize(xvp, ainfo.filesize, 0, context); 1975 if (error) { 1976 printf("setxattr: VNOP_TRUNCATE error %d\n", error); 1977 } 1978 if (error) 1979 goto out; 1980 1981 /* 1982 * Move the resource fork out of the way. 1983 */ 1984 if (ainfo.rsrcfork) { 1985 if (ainfo.rsrcfork->length != 0) { 1986 shift_data_down(xvp, 1987 ainfo.rsrcfork->offset, 1988 ainfo.rsrcfork->length, 1989 growsize, context); 1990 } 1991 ainfo.rsrcfork->offset += growsize; 1992 } 1993 ainfo.finderinfo->length += growsize; 1994 header->total_size += growsize; 1995 } 1996 1997 /* Make space for a new entry. */ 1998 if (splitdata) { 1999 shift_data_down(xvp, 2000 header->data_start, 2001 header->data_length, 2002 entrylen, context); 2003 } else { 2004 bcopy((u_int8_t *)header + header->data_start, 2005 (u_int8_t *)header + header->data_start + entrylen, 2006 header->data_length); 2007 } 2008 header->data_start += entrylen; 2009 2010 /* Fix up entry data offsets. */ 2011 lastentry = entry; 2012 for (entry = ainfo.attr_entry; entry != lastentry && ATTR_VALID(entry, ainfo); entry = ATTR_NEXT(entry)) { 2013 entry->offset += entrylen; 2014 } 2015 2016 /* 2017 * If the attribute data area is entirely within 2018 * the header buffer, then just update the buffer, 2019 * otherwise we'll write it separately to the file. 2020 */ 2021 if (splitdata) { 2022 off_t offset; 2023 2024 /* Write new attribute data after the end of existing data. */ 2025 offset = header->data_start + header->data_length; 2026 uio_setoffset(uio, offset); 2027 error = VNOP_WRITE(xvp, uio, 0, context); 2028 uio_setoffset(uio, 0); 2029 if (error) { 2030 printf("setxattr: VNOP_WRITE error %d\n", error); 2031 goto out; 2032 } 2033 } else { 2034 attrdata = (u_int8_t *)header + header->data_start + header->data_length; 2035 2036 error = uiomove((caddr_t)attrdata, datalen, uio); 2037 if (error) { 2038 printf("setxattr: uiomove error %d\n", error); 2039 goto out; 2040 } 2041 } 2042 2043 /* Create the attribute entry. */ 2044 lastentry->length = datalen; 2045 lastentry->offset = header->data_start + header->data_length; 2046 lastentry->namelen = namelen; 2047 lastentry->flags = 0; 2048 bcopy(name, &lastentry->name[0], namelen); 2049 2050 /* Update the attributes header. */ 2051 header->num_attrs++; 2052 header->data_length += datalen; 2053 2054 if (splitdata) { 2055 /* Only write the entries, since the data was written separately. */ 2056 ainfo.iosize = ainfo.attrhdr->data_start; 2057 } else { 2058 /* The entry and data are both in the header; write them together. */ 2059 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length; 2060 } 2061 error = write_xattrinfo(&ainfo); 2062 if (error) { 2063 printf("setxattr: write_xattrinfo error %d\n", error); 2064 } 2065 2066out: 2067 rel_xattrinfo(&ainfo); 2068 close_xattrfile(xvp, fileflags, context); 2069 2070 /* Touch the change time if we changed an attribute. */ 2071 if (error == 0) { 2072 struct vnode_attr va; 2073 2074 /* Re-write the mtime to cause a ctime change. */ 2075 VATTR_INIT(&va); 2076 VATTR_WANTED(&va, va_modify_time); 2077 if (vnode_getattr(vp, &va, context) == 0) { 2078 VATTR_INIT(&va); 2079 VATTR_SET(&va, va_modify_time, va.va_modify_time); 2080 (void) vnode_setattr(vp, &va, context); 2081 } 2082 } 2083 2084 post_event_if_success(vp, error, NOTE_ATTRIB); 2085 2086 return (error); 2087} 2088 2089 2090/* 2091 * Remove an extended attribute. 2092 */ 2093static int 2094default_removexattr(vnode_t vp, const char *name, __unused int options, vfs_context_t context) 2095{ 2096 vnode_t xvp = NULL; 2097 attr_info_t ainfo; 2098 attr_header_t *header; 2099 attr_entry_t *entry; 2100 attr_entry_t *oldslot; 2101 u_int8_t *attrdata; 2102 u_int32_t dataoff; 2103 size_t datalen; 2104 size_t entrylen; 2105 int namelen; 2106 int found = 0, lastone = 0; 2107 int i; 2108 int splitdata; 2109 int attrcount = 0; 2110 int isrsrcfork; 2111 int fileflags; 2112 int error; 2113 2114 fileflags = FREAD | FWRITE; 2115 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) { 2116 isrsrcfork = 1; 2117 /* 2118 * Open the file locked (exclusive) since the Carbon 2119 * File Manager may have the Apple Double file open 2120 * and could be changing the resource fork. 2121 */ 2122 fileflags |= O_EXLOCK; 2123 } else { 2124 isrsrcfork = 0; 2125 } 2126 2127 if ((error = open_xattrfile(vp, fileflags, &xvp, context))) { 2128 return (error); 2129 } 2130 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) { 2131 close_xattrfile(xvp, fileflags, context); 2132 return (error); 2133 } 2134 if (ainfo.attrhdr) 2135 attrcount += ainfo.attrhdr->num_attrs; 2136 if (ainfo.rsrcfork) 2137 ++attrcount; 2138 if (ainfo.finderinfo && !ainfo.emptyfinderinfo) 2139 ++attrcount; 2140 2141 /* Clear the Finder Info. */ 2142 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) { 2143 if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) { 2144 error = ENOATTR; 2145 goto out; 2146 } 2147 /* On removal of last attribute the ._ file is removed. */ 2148 if (--attrcount == 0) 2149 goto out; 2150 attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset; 2151 bzero((caddr_t)attrdata, FINDERINFOSIZE); 2152 ainfo.iosize = sizeof(attr_header_t); 2153 error = write_xattrinfo(&ainfo); 2154 goto out; 2155 } 2156 2157 /* Clear the Resource Fork. */ 2158 if (isrsrcfork) { 2159 if (!vnode_isreg(vp)) { 2160 error = EPERM; 2161 goto out; 2162 } 2163 if (ainfo.rsrcfork == NULL || ainfo.rsrcfork->length == 0) { 2164 error = ENOATTR; 2165 goto out; 2166 } 2167 /* On removal of last attribute the ._ file is removed. */ 2168 if (--attrcount == 0) 2169 goto out; 2170 /* 2171 * XXX 2172 * If the resource fork isn't the last AppleDouble 2173 * entry then the space needs to be reclaimed by 2174 * shifting the entries after the resource fork. 2175 */ 2176 if ((ainfo.rsrcfork->offset + ainfo.rsrcfork->length) == ainfo.filesize) { 2177 ainfo.filesize -= ainfo.rsrcfork->length; 2178 error = vnode_setsize(xvp, ainfo.filesize, 0, context); 2179 } 2180 if (error == 0) { 2181 ainfo.rsrcfork->length = 0; 2182 ainfo.iosize = sizeof(attr_header_t); 2183 error = write_xattrinfo(&ainfo); 2184 } 2185 goto out; 2186 } 2187 2188 if (ainfo.attrhdr == NULL) { 2189 error = ENOATTR; 2190 goto out; 2191 } 2192 namelen = strlen(name) + 1; 2193 header = ainfo.attrhdr; 2194 entry = ainfo.attr_entry; 2195 2196 /* 2197 * See if this attribute exists. 2198 */ 2199 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) { 2200 if (strncmp((const char *)entry->name, name, namelen) == 0) { 2201 found = 1; 2202 if ((i+1) == header->num_attrs) 2203 lastone = 1; 2204 break; 2205 } 2206 entry = ATTR_NEXT(entry); 2207 } 2208 if (!found) { 2209 error = ENOATTR; 2210 goto out; 2211 } 2212 /* On removal of last attribute the ._ file is removed. */ 2213 if (--attrcount == 0) 2214 goto out; 2215 2216 datalen = entry->length; 2217 dataoff = entry->offset; 2218 entrylen = ATTR_ENTRY_LENGTH(namelen); 2219 if ((header->data_start + header->data_length) > ATTR_MAX_HDR_SIZE) 2220 splitdata = 1; 2221 else 2222 splitdata = 0; 2223 2224 /* Remove the attribute entry. */ 2225 if (!lastone) { 2226 bcopy((u_int8_t *)entry + entrylen, (u_int8_t *)entry, 2227 ((size_t)header + header->data_start) - ((size_t)entry + entrylen)); 2228 } 2229 2230 /* Adjust the attribute data. */ 2231 if (splitdata) { 2232 shift_data_up(xvp, 2233 header->data_start, 2234 dataoff - header->data_start, 2235 entrylen, 2236 context); 2237 if (!lastone) { 2238 shift_data_up(xvp, 2239 dataoff + datalen, 2240 (header->data_start + header->data_length) - (dataoff + datalen), 2241 datalen + entrylen, 2242 context); 2243 } 2244 /* XXX write zeros to freed space ? */ 2245 ainfo.iosize = ainfo.attrhdr->data_start - entrylen; 2246 } else { 2247 2248 2249 bcopy((u_int8_t *)header + header->data_start, 2250 (u_int8_t *)header + header->data_start - entrylen, 2251 dataoff - header->data_start); 2252 if (!lastone) { 2253 bcopy((u_int8_t *)header + dataoff + datalen, 2254 (u_int8_t *)header + dataoff - entrylen, 2255 (header->data_start + header->data_length) - (dataoff + datalen)); 2256 } 2257 bzero (((u_int8_t *)header + header->data_start + header->data_length) - (datalen + entrylen), (datalen + entrylen)); 2258 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length; 2259 } 2260 2261 /* Adjust the header values and entry offsets. */ 2262 header->num_attrs--; 2263 header->data_start -= entrylen; 2264 header->data_length -= datalen; 2265 2266 oldslot = entry; 2267 entry = ainfo.attr_entry; 2268 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) { 2269 entry->offset -= entrylen; 2270 if (entry >= oldslot) 2271 entry->offset -= datalen; 2272 entry = ATTR_NEXT(entry); 2273 } 2274 error = write_xattrinfo(&ainfo); 2275 if (error) { 2276 printf("removexattr: write_xattrinfo error %d\n", error); 2277 } 2278out: 2279 rel_xattrinfo(&ainfo); 2280 2281 /* When there are no more attributes remove the ._ file. */ 2282 if (attrcount == 0) { 2283 if (fileflags & O_EXLOCK) 2284 (void) unlock_xattrfile(xvp, context); 2285 VNOP_CLOSE(xvp, fileflags, context); 2286 vnode_rele(xvp); 2287 error = remove_xattrfile(xvp, context); 2288 vnode_put(xvp); 2289 } else { 2290 close_xattrfile(xvp, fileflags, context); 2291 } 2292 /* Touch the change time if we changed an attribute. */ 2293 if (error == 0) { 2294 struct vnode_attr va; 2295 2296 /* Re-write the mtime to cause a ctime change. */ 2297 VATTR_INIT(&va); 2298 VATTR_WANTED(&va, va_modify_time); 2299 if (vnode_getattr(vp, &va, context) == 0) { 2300 VATTR_INIT(&va); 2301 VATTR_SET(&va, va_modify_time, va.va_modify_time); 2302 (void) vnode_setattr(vp, &va, context); 2303 } 2304 } 2305 2306 post_event_if_success(vp, error, NOTE_ATTRIB); 2307 2308 return (error); 2309 2310} 2311 2312 2313/* 2314 * Retrieve the list of extended attribute names. 2315 */ 2316static int 2317default_listxattr(vnode_t vp, uio_t uio, size_t *size, __unused int options, vfs_context_t context) 2318{ 2319 vnode_t xvp = NULL; 2320 attr_info_t ainfo; 2321 attr_entry_t *entry; 2322 int i, count; 2323 int error; 2324 2325 /* 2326 * We do not zero "*size" here as we don't want to stomp a size set when 2327 * VNOP_LISTXATTR processed any native EAs. That size is initially zeroed by the 2328 * system call layer, up in listxattr or flistxattr. 2329 */ 2330 2331 if ((error = open_xattrfile(vp, FREAD, &xvp, context))) { 2332 if (error == ENOATTR) 2333 error = 0; 2334 return (error); 2335 } 2336 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) { 2337 if (error == ENOATTR) 2338 error = 0; 2339 close_xattrfile(xvp, FREAD, context); 2340 return (error); 2341 } 2342 2343 /* Check for Finder Info. */ 2344 if (ainfo.finderinfo && !ainfo.emptyfinderinfo) { 2345 if (uio == NULL) { 2346 *size += sizeof(XATTR_FINDERINFO_NAME); 2347 } else if (uio_resid(uio) < (user_ssize_t)sizeof(XATTR_FINDERINFO_NAME)) { 2348 error = ERANGE; 2349 goto out; 2350 } else { 2351 error = uiomove(XATTR_FINDERINFO_NAME, 2352 sizeof(XATTR_FINDERINFO_NAME), uio); 2353 if (error) { 2354 error = ERANGE; 2355 goto out; 2356 } 2357 } 2358 } 2359 2360 /* Check for Resource Fork. */ 2361 if (vnode_isreg(vp) && ainfo.rsrcfork) { 2362 if (uio == NULL) { 2363 *size += sizeof(XATTR_RESOURCEFORK_NAME); 2364 } else if (uio_resid(uio) < (user_ssize_t)sizeof(XATTR_RESOURCEFORK_NAME)) { 2365 error = ERANGE; 2366 goto out; 2367 } else { 2368 error = uiomove(XATTR_RESOURCEFORK_NAME, 2369 sizeof(XATTR_RESOURCEFORK_NAME), uio); 2370 if (error) { 2371 error = ERANGE; 2372 goto out; 2373 } 2374 } 2375 } 2376 2377 /* Check for attributes. */ 2378 if (ainfo.attrhdr) { 2379 count = ainfo.attrhdr->num_attrs; 2380 for (i = 0, entry = ainfo.attr_entry; i < count && ATTR_VALID(entry, ainfo); i++) { 2381 if (xattr_protected((const char *)entry->name) || 2382 xattr_validatename((const char *)entry->name) != 0) { 2383 entry = ATTR_NEXT(entry); 2384 continue; 2385 } 2386 if (uio == NULL) { 2387 *size += entry->namelen; 2388 entry = ATTR_NEXT(entry); 2389 continue; 2390 } 2391 if (uio_resid(uio) < entry->namelen) { 2392 error = ERANGE; 2393 break; 2394 } 2395 error = uiomove((caddr_t) entry->name, entry->namelen, uio); 2396 if (error) { 2397 if (error != EFAULT) 2398 error = ERANGE; 2399 break; 2400 } 2401 entry = ATTR_NEXT(entry); 2402 } 2403 } 2404out: 2405 rel_xattrinfo(&ainfo); 2406 close_xattrfile(xvp, FREAD, context); 2407 2408 return (error); 2409} 2410 2411static int 2412open_xattrfile(vnode_t vp, int fileflags, vnode_t *xvpp, vfs_context_t context) 2413{ 2414 vnode_t xvp = NULLVP; 2415 vnode_t dvp = NULLVP; 2416 struct vnode_attr va; 2417 struct nameidata nd; 2418 char smallname[64]; 2419 char *filename = NULL; 2420 const char *basename = NULL; 2421 size_t len; 2422 errno_t error; 2423 int opened = 0; 2424 int referenced = 0; 2425 2426 if (vnode_isvroot(vp) && vnode_isdir(vp)) { 2427 /* 2428 * For the root directory use "._." to hold the attributes. 2429 */ 2430 filename = &smallname[0]; 2431 snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, "."); 2432 dvp = vp; /* the "._." file resides in the root dir */ 2433 goto lookup; 2434 } 2435 if ( (dvp = vnode_getparent(vp)) == NULLVP) { 2436 error = ENOATTR; 2437 goto out; 2438 } 2439 if ( (basename = vnode_getname(vp)) == NULL) { 2440 error = ENOATTR; 2441 goto out; 2442 } 2443 2444 /* "._" Attribute files cannot have attributes */ 2445 if (vp->v_type == VREG && strlen(basename) > 2 && 2446 basename[0] == '.' && basename[1] == '_') { 2447 error = EPERM; 2448 goto out; 2449 } 2450 filename = &smallname[0]; 2451 len = snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, basename); 2452 if (len >= sizeof(smallname)) { 2453 len++; /* snprintf result doesn't include '\0' */ 2454 MALLOC(filename, char *, len, M_TEMP, M_WAITOK); 2455 len = snprintf(filename, len, "%s%s", ATTR_FILE_PREFIX, basename); 2456 } 2457 /* 2458 * Note that the lookup here does not authorize. Since we are looking 2459 * up in the same directory that we already have the file vnode in, 2460 * we must have been given the file vnode legitimately. Read/write 2461 * access has already been authorized in layers above for calls from 2462 * userspace, and the authorization code using this path to read 2463 * file security from the EA must always get access 2464 */ 2465lookup: 2466 NDINIT(&nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH, 2467 UIO_SYSSPACE, CAST_USER_ADDR_T(filename), context); 2468 nd.ni_dvp = dvp; 2469 2470 if (fileflags & O_CREAT) { 2471 nd.ni_cnd.cn_nameiop = CREATE; 2472#if CONFIG_TRIGGERS 2473 nd.ni_op = OP_LINK; 2474#endif 2475 if (dvp != vp) { 2476 nd.ni_cnd.cn_flags |= LOCKPARENT; 2477 } 2478 if ( (error = namei(&nd))) { 2479 nd.ni_dvp = NULLVP; 2480 error = ENOATTR; 2481 goto out; 2482 } 2483 if ( (xvp = nd.ni_vp) == NULLVP) { 2484 uid_t uid; 2485 gid_t gid; 2486 mode_t umode; 2487 2488 /* 2489 * Pick up uid/gid/mode from target file. 2490 */ 2491 VATTR_INIT(&va); 2492 VATTR_WANTED(&va, va_uid); 2493 VATTR_WANTED(&va, va_gid); 2494 VATTR_WANTED(&va, va_mode); 2495 if (VNOP_GETATTR(vp, &va, context) == 0 && 2496 VATTR_IS_SUPPORTED(&va, va_uid) && 2497 VATTR_IS_SUPPORTED(&va, va_gid) && 2498 VATTR_IS_SUPPORTED(&va, va_mode)) { 2499 uid = va.va_uid; 2500 gid = va.va_gid; 2501 umode = va.va_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 2502 } else /* fallback values */ { 2503 uid = KAUTH_UID_NONE; 2504 gid = KAUTH_GID_NONE; 2505 umode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; 2506 } 2507 2508 VATTR_INIT(&va); 2509 VATTR_SET(&va, va_type, VREG); 2510 VATTR_SET(&va, va_mode, umode); 2511 if (uid != KAUTH_UID_NONE) 2512 VATTR_SET(&va, va_uid, uid); 2513 if (gid != KAUTH_GID_NONE) 2514 VATTR_SET(&va, va_gid, gid); 2515 2516 error = vn_create(dvp, &nd.ni_vp, &nd, &va, 2517 VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL, 2518 0, NULL, 2519 context); 2520 if (error) 2521 error = ENOATTR; 2522 else 2523 xvp = nd.ni_vp; 2524 } 2525 nameidone(&nd); 2526 if (dvp != vp) { 2527 vnode_put(dvp); /* drop iocount from LOCKPARENT request above */ 2528 } 2529 if (error) 2530 goto out; 2531 } else { 2532 if ((error = namei(&nd))) { 2533 nd.ni_dvp = NULLVP; 2534 error = ENOATTR; 2535 goto out; 2536 } 2537 xvp = nd.ni_vp; 2538 nameidone(&nd); 2539 } 2540 nd.ni_dvp = NULLVP; 2541 2542 if (xvp->v_type != VREG) { 2543 error = ENOATTR; 2544 goto out; 2545 } 2546 /* 2547 * Owners must match. 2548 */ 2549 VATTR_INIT(&va); 2550 VATTR_WANTED(&va, va_uid); 2551 if (VNOP_GETATTR(vp, &va, context) == 0 && VATTR_IS_SUPPORTED(&va, va_uid)) { 2552 uid_t owner = va.va_uid; 2553 2554 VATTR_INIT(&va); 2555 VATTR_WANTED(&va, va_uid); 2556 if (VNOP_GETATTR(xvp, &va, context) == 0 && (owner != va.va_uid)) { 2557 error = ENOATTR; /* don't use this "._" file */ 2558 goto out; 2559 } 2560 } 2561 2562 if ( (error = VNOP_OPEN(xvp, fileflags & ~(O_EXLOCK | O_SHLOCK), context))) { 2563 error = ENOATTR; 2564 goto out; 2565 } 2566 opened = 1; 2567 2568 if ((error = vnode_ref(xvp))) { 2569 goto out; 2570 } 2571 referenced = 1; 2572 2573 /* If create was requested, make sure file header exists. */ 2574 if (fileflags & O_CREAT) { 2575 VATTR_INIT(&va); 2576 VATTR_WANTED(&va, va_data_size); 2577 VATTR_WANTED(&va, va_fileid); 2578 VATTR_WANTED(&va, va_nlink); 2579 if ( (error = vnode_getattr(xvp, &va, context)) != 0) { 2580 error = EPERM; 2581 goto out; 2582 } 2583 2584 /* If the file is empty then add a default header. */ 2585 if (va.va_data_size == 0) { 2586 /* Don't adopt hard-linked "._" files. */ 2587 if (VATTR_IS_SUPPORTED(&va, va_nlink) && va.va_nlink > 1) { 2588 error = EPERM; 2589 goto out; 2590 } 2591 if ( (error = create_xattrfile(xvp, (u_int32_t)va.va_fileid, context))) 2592 goto out; 2593 } 2594 } 2595 /* Apply file locking if requested. */ 2596 if (fileflags & (O_EXLOCK | O_SHLOCK)) { 2597 short locktype; 2598 2599 locktype = (fileflags & O_EXLOCK) ? F_WRLCK : F_RDLCK; 2600 error = lock_xattrfile(xvp, locktype, context); 2601 if (error) 2602 error = ENOATTR; 2603 } 2604out: 2605 if (error) { 2606 if (xvp != NULLVP) { 2607 if (opened) { 2608 (void) VNOP_CLOSE(xvp, fileflags, context); 2609 } 2610 2611 if (fileflags & O_CREAT) { 2612 /* Delete the xattr file if we encountered any errors */ 2613 (void) remove_xattrfile (xvp, context); 2614 } 2615 2616 if (referenced) { 2617 (void) vnode_rele(xvp); 2618 } 2619 (void) vnode_put(xvp); 2620 xvp = NULLVP; 2621 } 2622 if ((error == ENOATTR) && (fileflags & O_CREAT)) { 2623 error = EPERM; 2624 } 2625 } 2626 /* Release resources after error-handling */ 2627 if (dvp && (dvp != vp)) { 2628 vnode_put(dvp); 2629 } 2630 if (basename) { 2631 vnode_putname(basename); 2632 } 2633 if (filename && filename != &smallname[0]) { 2634 FREE(filename, M_TEMP); 2635 } 2636 2637 *xvpp = xvp; /* return a referenced vnode */ 2638 return (error); 2639} 2640 2641static void 2642close_xattrfile(vnode_t xvp, int fileflags, vfs_context_t context) 2643{ 2644// if (fileflags & FWRITE) 2645// (void) VNOP_FSYNC(xvp, MNT_WAIT, context); 2646 2647 if (fileflags & (O_EXLOCK | O_SHLOCK)) 2648 (void) unlock_xattrfile(xvp, context); 2649 2650 (void) VNOP_CLOSE(xvp, fileflags, context); 2651 (void) vnode_rele(xvp); 2652 (void) vnode_put(xvp); 2653} 2654 2655static int 2656remove_xattrfile(vnode_t xvp, vfs_context_t context) 2657{ 2658 vnode_t dvp; 2659 struct nameidata nd; 2660 char *path = NULL; 2661 int pathlen; 2662 int error = 0; 2663 2664 MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 2665 if (path == NULL) 2666 return ENOMEM; 2667 2668 pathlen = MAXPATHLEN; 2669 error = vn_getpath(xvp, path, &pathlen); 2670 if (error) { 2671 FREE_ZONE(path, MAXPATHLEN, M_NAMEI); 2672 return (error); 2673 } 2674 2675 NDINIT(&nd, DELETE, OP_UNLINK, LOCKPARENT | NOFOLLOW | DONOTAUTH, 2676 UIO_SYSSPACE, CAST_USER_ADDR_T(path), context); 2677 error = namei(&nd); 2678 FREE_ZONE(path, MAXPATHLEN, M_NAMEI); 2679 if (error) { 2680 return (error); 2681 } 2682 dvp = nd.ni_dvp; 2683 xvp = nd.ni_vp; 2684 2685 error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, context); 2686 nameidone(&nd); 2687 vnode_put(dvp); 2688 vnode_put(xvp); 2689 2690 return (error); 2691} 2692 2693/* 2694 * Read in and parse the AppleDouble header and entries, and the extended 2695 * attribute header and entries if any. Populates the fields of ainfop 2696 * based on the headers and entries found. 2697 * 2698 * The basic idea is to: 2699 * - Read in up to ATTR_MAX_HDR_SIZE bytes of the start of the file. All 2700 * AppleDouble entries, the extended attribute header, and extended 2701 * attribute entries must lie within this part of the file; the rest of 2702 * the AppleDouble handling code assumes this. Plus it allows us to 2703 * somewhat optimize by doing a smaller number of larger I/Os. 2704 * - Swap and sanity check the AppleDouble header (including the AppleDouble 2705 * entries). 2706 * - Find the Finder Info and Resource Fork entries, if any. 2707 * - If we're going to be writing, try to make sure the Finder Info entry has 2708 * room to store the extended attribute header, plus some space for extended 2709 * attributes. 2710 * - Swap and sanity check the extended attribute header and entries (if any). 2711 */ 2712static int 2713get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context) 2714{ 2715 uio_t auio = NULL; 2716 void * buffer = NULL; 2717 apple_double_header_t *filehdr; 2718 struct vnode_attr va; 2719 size_t iosize; 2720 int i; 2721 int error; 2722 2723 bzero(ainfop, sizeof(attr_info_t)); 2724 ainfop->filevp = xvp; 2725 ainfop->context = context; 2726 VATTR_INIT(&va); 2727 VATTR_WANTED(&va, va_data_size); 2728 VATTR_WANTED(&va, va_fileid); 2729 if ((error = vnode_getattr(xvp, &va, context))) { 2730 goto bail; 2731 } 2732 ainfop->filesize = va.va_data_size; 2733 2734 /* When setting attributes, allow room for the header to grow. */ 2735 if (setting) 2736 iosize = ATTR_MAX_HDR_SIZE; 2737 else 2738 iosize = MIN(ATTR_MAX_HDR_SIZE, ainfop->filesize); 2739 2740 if (iosize == 0) { 2741 error = ENOATTR; 2742 goto bail; 2743 } 2744 ainfop->iosize = iosize; 2745 MALLOC(buffer, void *, iosize, M_TEMP, M_WAITOK); 2746 if (buffer == NULL){ 2747 error = ENOMEM; 2748 goto bail; 2749 } 2750 2751 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 2752 uio_addiov(auio, (uintptr_t)buffer, iosize); 2753 2754 /* Read the file header. */ 2755 error = VNOP_READ(xvp, auio, 0, context); 2756 if (error) { 2757 goto bail; 2758 } 2759 ainfop->rawsize = iosize - uio_resid(auio); 2760 ainfop->rawdata = (u_int8_t *)buffer; 2761 2762 filehdr = (apple_double_header_t *)buffer; 2763 2764 error = check_and_swap_apple_double_header(ainfop); 2765 if (error) 2766 goto bail; 2767 2768 ainfop->filehdr = filehdr; /* valid AppleDouble header */ 2769 2770 /* rel_xattrinfo is responsible for freeing the header buffer */ 2771 buffer = NULL; 2772 2773 /* Find the Finder Info and Resource Fork entries, if any */ 2774 for (i = 0; i < filehdr->numEntries; ++i) { 2775 if (filehdr->entries[i].type == AD_FINDERINFO && 2776 filehdr->entries[i].length >= FINDERINFOSIZE) { 2777 /* We found the Finder Info entry. */ 2778 ainfop->finderinfo = &filehdr->entries[i]; 2779 2780 /* 2781 * Is the Finder Info "empty" (all zeroes)? If so, 2782 * we'll pretend like the Finder Info extended attribute 2783 * does not exist. 2784 * 2785 * Note: we have to make sure the Finder Info is 2786 * contained within the buffer we have already read, 2787 * to avoid accidentally accessing a bogus address. 2788 * If it is outside the buffer, we just assume the 2789 * Finder Info is non-empty. 2790 */ 2791 if (ainfop->finderinfo->offset + FINDERINFOSIZE <= ainfop->rawsize && 2792 bcmp((u_int8_t*)ainfop->filehdr + ainfop->finderinfo->offset, emptyfinfo, sizeof(emptyfinfo)) == 0) { 2793 ainfop->emptyfinderinfo = 1; 2794 } 2795 } 2796 if (filehdr->entries[i].type == AD_RESOURCE) { 2797 /* 2798 * Ignore zero-length resource forks when getting. If setting, 2799 * we need to remember the resource fork entry so it can be 2800 * updated once the new content has been written. 2801 */ 2802 if (filehdr->entries[i].length == 0 && !setting) 2803 continue; 2804 2805 /* 2806 * Check to see if any "empty" resource fork is ours (i.e. is ignorable). 2807 * 2808 * The "empty" resource headers we created have a system data tag of: 2809 * "This resource fork intentionally left blank " 2810 */ 2811 if (filehdr->entries[i].length == sizeof(rsrcfork_header_t) && !setting) { 2812 uio_t rf_uio; 2813 u_int8_t systemData[64]; 2814 int rf_err; 2815 2816 2817 /* Read the system data which starts at byte 16 */ 2818 rf_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 2819 uio_addiov(rf_uio, (uintptr_t)systemData, sizeof(systemData)); 2820 uio_setoffset(rf_uio, filehdr->entries[i].offset + 16); 2821 rf_err = VNOP_READ(xvp, rf_uio, 0, context); 2822 uio_free(rf_uio); 2823 2824 if (rf_err != 0 || 2825 bcmp(systemData, RF_EMPTY_TAG, sizeof(RF_EMPTY_TAG)) == 0) { 2826 continue; /* skip this resource fork */ 2827 } 2828 } 2829 ainfop->rsrcfork = &filehdr->entries[i]; 2830 if (i != (filehdr->numEntries - 1)) { 2831 printf("get_xattrinfo: resource fork not last entry\n"); 2832 ainfop->readonly = 1; 2833 } 2834 continue; 2835 } 2836 } 2837 2838 /* 2839 * See if this file looks like it is laid out correctly to contain 2840 * extended attributes. If so, then do the following: 2841 * 2842 * - If we're going to be writing, try to make sure the Finder Info 2843 * entry has room to store the extended attribute header, plus some 2844 * space for extended attributes. 2845 * 2846 * - Swap and sanity check the extended attribute header and entries 2847 * (if any). 2848 */ 2849 if (filehdr->numEntries == 2 && 2850 ainfop->finderinfo == &filehdr->entries[0] && 2851 ainfop->rsrcfork == &filehdr->entries[1] && 2852 ainfop->finderinfo->offset == offsetof(apple_double_header_t, finfo)) { 2853 attr_header_t *attrhdr; 2854 attrhdr = (attr_header_t *)filehdr; 2855 /* 2856 * If we're going to be writing, try to make sure the Finder 2857 * Info entry has room to store the extended attribute header, 2858 * plus some space for extended attributes. 2859 */ 2860 if (setting && ainfop->finderinfo->length == FINDERINFOSIZE) { 2861 size_t delta; 2862 size_t writesize; 2863 2864 delta = ATTR_BUF_SIZE - (filehdr->entries[0].offset + FINDERINFOSIZE); 2865 if (ainfop->rsrcfork && filehdr->entries[1].length) { 2866 /* Make some room before existing resource fork. */ 2867 shift_data_down(xvp, 2868 filehdr->entries[1].offset, 2869 filehdr->entries[1].length, 2870 delta, context); 2871 writesize = sizeof(attr_header_t); 2872 } else { 2873 /* Create a new, empty resource fork. */ 2874 rsrcfork_header_t *rsrcforkhdr; 2875 2876 vnode_setsize(xvp, filehdr->entries[1].offset + delta, 0, context); 2877 2878 /* Steal some space for an empty RF header. */ 2879 delta -= sizeof(rsrcfork_header_t); 2880 2881 bzero(&attrhdr->appledouble.pad[0], delta); 2882 rsrcforkhdr = (rsrcfork_header_t *)((char *)filehdr + filehdr->entries[1].offset + delta); 2883 2884 /* Fill in Empty Resource Fork Header. */ 2885 init_empty_resource_fork(rsrcforkhdr); 2886 2887 filehdr->entries[1].length = sizeof(rsrcfork_header_t); 2888 writesize = ATTR_BUF_SIZE; 2889 } 2890 filehdr->entries[0].length += delta; 2891 filehdr->entries[1].offset += delta; 2892 2893 /* Fill in Attribute Header. */ 2894 attrhdr->magic = ATTR_HDR_MAGIC; 2895 attrhdr->debug_tag = (u_int32_t)va.va_fileid; 2896 attrhdr->total_size = filehdr->entries[1].offset; 2897 attrhdr->data_start = sizeof(attr_header_t); 2898 attrhdr->data_length = 0; 2899 attrhdr->reserved[0] = 0; 2900 attrhdr->reserved[1] = 0; 2901 attrhdr->reserved[2] = 0; 2902 attrhdr->flags = 0; 2903 attrhdr->num_attrs = 0; 2904 2905 /* Push out new header */ 2906 uio_reset(auio, 0, UIO_SYSSPACE, UIO_WRITE); 2907 uio_addiov(auio, (uintptr_t)filehdr, writesize); 2908 2909 swap_adhdr(filehdr); /* to big endian */ 2910 swap_attrhdr(attrhdr, ainfop); /* to big endian */ 2911 error = VNOP_WRITE(xvp, auio, 0, context); 2912 swap_adhdr(filehdr); /* back to native */ 2913 /* The attribute header gets swapped below. */ 2914 } 2915 } 2916 /* 2917 * Swap and sanity check the extended attribute header and 2918 * entries (if any). The Finder Info content must be big enough 2919 * to include the extended attribute header; if not, we just 2920 * ignore it. 2921 * 2922 * Note that we're passing the offset + length (i.e. the end) 2923 * of the Finder Info instead of rawsize to validate_attrhdr. 2924 * This ensures that all extended attributes lie within the 2925 * Finder Info content according to the AppleDouble entry. 2926 * 2927 * Sets ainfop->attrhdr and ainfop->attr_entry if a valid 2928 * header was found. 2929 */ 2930 if (ainfop->finderinfo && 2931 ainfop->finderinfo == &filehdr->entries[0] && 2932 ainfop->finderinfo->length >= (sizeof(attr_header_t) - sizeof(apple_double_header_t))) { 2933 attr_header_t *attrhdr = (attr_header_t*)filehdr; 2934 2935 if ((error = check_and_swap_attrhdr(attrhdr, ainfop)) == 0) { 2936 ainfop->attrhdr = attrhdr; /* valid attribute header */ 2937 /* First attr_entry starts immediately following attribute header */ 2938 ainfop->attr_entry = (attr_entry_t *)&attrhdr[1]; 2939 } 2940 } 2941 2942 error = 0; 2943bail: 2944 if (auio != NULL) 2945 uio_free(auio); 2946 if (buffer != NULL) 2947 FREE(buffer, M_TEMP); 2948 return (error); 2949} 2950 2951 2952static int 2953create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context) 2954{ 2955 attr_header_t *xah; 2956 rsrcfork_header_t *rsrcforkhdr; 2957 void * buffer; 2958 uio_t auio; 2959 int rsrcforksize; 2960 int error; 2961 2962 MALLOC(buffer, void *, ATTR_BUF_SIZE, M_TEMP, M_WAITOK); 2963 bzero(buffer, ATTR_BUF_SIZE); 2964 2965 xah = (attr_header_t *)buffer; 2966 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE); 2967 uio_addiov(auio, (uintptr_t)buffer, ATTR_BUF_SIZE); 2968 rsrcforksize = sizeof(rsrcfork_header_t); 2969 rsrcforkhdr = (rsrcfork_header_t *) ((char *)buffer + ATTR_BUF_SIZE - rsrcforksize); 2970 2971 /* Fill in Apple Double Header. */ 2972 xah->appledouble.magic = SWAP32 (ADH_MAGIC); 2973 xah->appledouble.version = SWAP32 (ADH_VERSION); 2974 xah->appledouble.numEntries = SWAP16 (2); 2975 xah->appledouble.entries[0].type = SWAP32 (AD_FINDERINFO); 2976 xah->appledouble.entries[0].offset = SWAP32 (offsetof(apple_double_header_t, finfo)); 2977 xah->appledouble.entries[0].length = SWAP32 (ATTR_BUF_SIZE - offsetof(apple_double_header_t, finfo) - rsrcforksize); 2978 xah->appledouble.entries[1].type = SWAP32 (AD_RESOURCE); 2979 xah->appledouble.entries[1].offset = SWAP32 (ATTR_BUF_SIZE - rsrcforksize); 2980 xah->appledouble.entries[1].length = SWAP32 (rsrcforksize); 2981 bcopy(ADH_MACOSX, xah->appledouble.filler, sizeof(xah->appledouble.filler)); 2982 2983 /* Fill in Attribute Header. */ 2984 xah->magic = SWAP32 (ATTR_HDR_MAGIC); 2985 xah->debug_tag = SWAP32 (fileid); 2986 xah->total_size = SWAP32 (ATTR_BUF_SIZE - rsrcforksize); 2987 xah->data_start = SWAP32 (sizeof(attr_header_t)); 2988 2989 /* Fill in Empty Resource Fork Header. */ 2990 init_empty_resource_fork(rsrcforkhdr); 2991 2992 /* Push it out. */ 2993 error = VNOP_WRITE(xvp, auio, IO_UNIT, context); 2994 2995 /* Did we write out the full uio? */ 2996 if (uio_resid(auio) > 0) { 2997 error = ENOSPC; 2998 } 2999 3000 uio_free(auio); 3001 FREE(buffer, M_TEMP); 3002 3003 return (error); 3004} 3005 3006static void 3007init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr) 3008{ 3009 bzero(rsrcforkhdr, sizeof(rsrcfork_header_t)); 3010 rsrcforkhdr->fh_DataOffset = SWAP32 (RF_FIRST_RESOURCE); 3011 rsrcforkhdr->fh_MapOffset = SWAP32 (RF_FIRST_RESOURCE); 3012 rsrcforkhdr->fh_MapLength = SWAP32 (RF_NULL_MAP_LENGTH); 3013 rsrcforkhdr->mh_DataOffset = SWAP32 (RF_FIRST_RESOURCE); 3014 rsrcforkhdr->mh_MapOffset = SWAP32 (RF_FIRST_RESOURCE); 3015 rsrcforkhdr->mh_MapLength = SWAP32 (RF_NULL_MAP_LENGTH); 3016 rsrcforkhdr->mh_Types = SWAP16 (RF_NULL_MAP_LENGTH - 2 ); 3017 rsrcforkhdr->mh_Names = SWAP16 (RF_NULL_MAP_LENGTH); 3018 rsrcforkhdr->typeCount = SWAP16 (-1); 3019 bcopy(RF_EMPTY_TAG, rsrcforkhdr->systemData, sizeof(RF_EMPTY_TAG)); 3020} 3021 3022static void 3023rel_xattrinfo(attr_info_t *ainfop) 3024{ 3025 FREE(ainfop->filehdr, M_TEMP); 3026 bzero(ainfop, sizeof(attr_info_t)); 3027} 3028 3029static int 3030write_xattrinfo(attr_info_t *ainfop) 3031{ 3032 uio_t auio; 3033 int error; 3034 3035 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE); 3036 uio_addiov(auio, (uintptr_t)ainfop->filehdr, ainfop->iosize); 3037 3038 swap_adhdr(ainfop->filehdr); 3039 if (ainfop->attrhdr != NULL) { 3040 swap_attrhdr(ainfop->attrhdr, ainfop); 3041 } 3042 3043 error = VNOP_WRITE(ainfop->filevp, auio, 0, ainfop->context); 3044 3045 swap_adhdr(ainfop->filehdr); 3046 if (ainfop->attrhdr != NULL) { 3047 swap_attrhdr(ainfop->attrhdr, ainfop); 3048 } 3049 uio_free(auio); 3050 3051 return (error); 3052} 3053 3054#if BYTE_ORDER == LITTLE_ENDIAN 3055/* 3056 * Endian swap apple double header 3057 */ 3058static void 3059swap_adhdr(apple_double_header_t *adh) 3060{ 3061 int count; 3062 int i; 3063 3064 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries); 3065 3066 adh->magic = SWAP32 (adh->magic); 3067 adh->version = SWAP32 (adh->version); 3068 adh->numEntries = SWAP16 (adh->numEntries); 3069 3070 for (i = 0; i < count; i++) { 3071 adh->entries[i].type = SWAP32 (adh->entries[i].type); 3072 adh->entries[i].offset = SWAP32 (adh->entries[i].offset); 3073 adh->entries[i].length = SWAP32 (adh->entries[i].length); 3074 } 3075} 3076 3077/* 3078 * Endian swap extended attributes header 3079 */ 3080static void 3081swap_attrhdr(attr_header_t *ah, attr_info_t* info) 3082{ 3083 attr_entry_t *ae; 3084 int count; 3085 int i; 3086 3087 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs); 3088 3089 ah->magic = SWAP32 (ah->magic); 3090 ah->debug_tag = SWAP32 (ah->debug_tag); 3091 ah->total_size = SWAP32 (ah->total_size); 3092 ah->data_start = SWAP32 (ah->data_start); 3093 ah->data_length = SWAP32 (ah->data_length); 3094 ah->flags = SWAP16 (ah->flags); 3095 ah->num_attrs = SWAP16 (ah->num_attrs); 3096 3097 ae = (attr_entry_t *)(&ah[1]); 3098 for (i = 0; i < count && ATTR_VALID(ae, *info); i++, ae = ATTR_NEXT(ae)) { 3099 ae->offset = SWAP32 (ae->offset); 3100 ae->length = SWAP32 (ae->length); 3101 ae->flags = SWAP16 (ae->flags); 3102 } 3103} 3104#endif 3105 3106/* 3107 * Validate and swap the attributes header contents, and each attribute's 3108 * attr_entry_t. 3109 * 3110 * Note: Assumes the caller has verified that the Finder Info content is large 3111 * enough to contain the attr_header structure itself. Therefore, we can 3112 * swap the header fields before sanity checking them. 3113 */ 3114static int 3115check_and_swap_attrhdr(attr_header_t *ah, attr_info_t *ainfop) 3116{ 3117 attr_entry_t *ae; 3118 u_int8_t *buf_end; 3119 u_int32_t end; 3120 int count; 3121 int i; 3122 3123 if (ah == NULL) 3124 return EINVAL; 3125 3126 if (SWAP32(ah->magic) != ATTR_HDR_MAGIC) 3127 return EINVAL; 3128 3129 /* Swap the basic header fields */ 3130 ah->magic = SWAP32(ah->magic); 3131 ah->debug_tag = SWAP32 (ah->debug_tag); 3132 ah->total_size = SWAP32 (ah->total_size); 3133 ah->data_start = SWAP32 (ah->data_start); 3134 ah->data_length = SWAP32 (ah->data_length); 3135 ah->flags = SWAP16 (ah->flags); 3136 ah->num_attrs = SWAP16 (ah->num_attrs); 3137 3138 /* 3139 * Make sure the total_size fits within the Finder Info area, and the 3140 * extended attribute data area fits within total_size. 3141 */ 3142 end = ah->data_start + ah->data_length; 3143 if (ah->total_size > ainfop->finderinfo->offset + ainfop->finderinfo->length || 3144 end < ah->data_start || 3145 end > ah->total_size) { 3146 return EINVAL; 3147 } 3148 3149 /* 3150 * Make sure each of the attr_entry_t's fits within total_size. 3151 */ 3152 buf_end = ainfop->rawdata + ah->total_size; 3153 count = ah->num_attrs; 3154 ae = (attr_entry_t *)(&ah[1]); 3155 3156 for (i=0; i<count; i++) { 3157 /* Make sure the fixed-size part of this attr_entry_t fits. */ 3158 if ((u_int8_t *) &ae[1] > buf_end) 3159 return EINVAL; 3160 3161 /* Make sure the variable-length name fits (+1 is for NUL terminator) */ 3162 /* TODO: Make sure namelen matches strnlen(name,namelen+1)? */ 3163 if (&ae->name[ae->namelen+1] > buf_end) 3164 return EINVAL; 3165 3166 /* Swap the attribute entry fields */ 3167 ae->offset = SWAP32(ae->offset); 3168 ae->length = SWAP32(ae->length); 3169 ae->flags = SWAP16(ae->flags); 3170 3171 /* Make sure the attribute content fits. */ 3172 end = ae->offset + ae->length; 3173 if (end < ae->offset || end > ah->total_size) 3174 return EINVAL; 3175 3176 ae = ATTR_NEXT(ae); 3177 } 3178 3179 /* 3180 * TODO: Make sure the contents of attributes don't overlap the header 3181 * and don't overlap each other. The hard part is that we don't know 3182 * what the actual header size is until we have looped over all of the 3183 * variable-sized attribute entries. 3184 * 3185 * XXX Is there any guarantee that attribute entries are stored in 3186 * XXX order sorted by the contents' file offset? If so, that would 3187 * XXX make the pairwise overlap check much easier. 3188 */ 3189 3190 return 0; 3191} 3192 3193// 3194// "start" & "end" are byte offsets in the file. 3195// "to" is the byte offset we want to move the 3196// data to. "to" should be > "start". 3197// 3198// we do the copy backwards to avoid problems if 3199// there's an overlap. 3200// 3201static int 3202shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context) 3203{ 3204 int ret, iolen; 3205 size_t chunk, orig_chunk; 3206 char *buff; 3207 off_t pos; 3208 kauth_cred_t ucred = vfs_context_ucred(context); 3209 proc_t p = vfs_context_proc(context); 3210 3211 if (delta == 0 || len == 0) { 3212 return 0; 3213 } 3214 3215 chunk = 4096; 3216 if (len < chunk) { 3217 chunk = len; 3218 } 3219 orig_chunk = chunk; 3220 3221 if (kmem_alloc(kernel_map, (vm_offset_t *)&buff, chunk)) { 3222 return ENOMEM; 3223 } 3224 3225 for(pos=start+len-chunk; pos >= start; pos-=chunk) { 3226 ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED|IO_NOAUTH, ucred, &iolen, p); 3227 if (iolen != 0) { 3228 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n", 3229 pos, ret, chunk, ret); 3230 break; 3231 } 3232 3233 ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos + delta, UIO_SYSSPACE, IO_NODELOCKED|IO_NOAUTH, ucred, &iolen, p); 3234 if (iolen != 0) { 3235 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n", 3236 pos+delta, ret, chunk, ret); 3237 break; 3238 } 3239 3240 if ((pos - (off_t)chunk) < start) { 3241 chunk = pos - start; 3242 3243 if (chunk == 0) { // we're all done 3244 break; 3245 } 3246 } 3247 } 3248 kmem_free(kernel_map, (vm_offset_t)buff, orig_chunk); 3249 3250 return 0; 3251} 3252 3253 3254static int 3255shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context) 3256{ 3257 int ret, iolen; 3258 size_t chunk, orig_chunk; 3259 char *buff; 3260 off_t pos; 3261 off_t end; 3262 kauth_cred_t ucred = vfs_context_ucred(context); 3263 proc_t p = vfs_context_proc(context); 3264 3265 if (delta == 0 || len == 0) { 3266 return 0; 3267 } 3268 3269 chunk = 4096; 3270 if (len < chunk) { 3271 chunk = len; 3272 } 3273 orig_chunk = chunk; 3274 end = start + len; 3275 3276 if (kmem_alloc(kernel_map, (vm_offset_t *)&buff, chunk)) { 3277 return ENOMEM; 3278 } 3279 3280 for(pos = start; pos < end; pos += chunk) { 3281 ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED|IO_NOAUTH, ucred, &iolen, p); 3282 if (iolen != 0) { 3283 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n", 3284 pos, ret, chunk, ret); 3285 break; 3286 } 3287 3288 ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos - delta, UIO_SYSSPACE, IO_NODELOCKED|IO_NOAUTH, ucred, &iolen, p); 3289 if (iolen != 0) { 3290 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n", 3291 pos+delta, ret, chunk, ret); 3292 break; 3293 } 3294 3295 if ((pos + (off_t)chunk) > end) { 3296 chunk = end - pos; 3297 3298 if (chunk == 0) { // we're all done 3299 break; 3300 } 3301 } 3302 } 3303 kmem_free(kernel_map, (vm_offset_t)buff, orig_chunk); 3304 3305 return 0; 3306} 3307 3308static int 3309lock_xattrfile(vnode_t xvp, short locktype, vfs_context_t context) 3310{ 3311 struct flock lf; 3312 int error; 3313 3314 lf.l_whence = SEEK_SET; 3315 lf.l_start = 0; 3316 lf.l_len = 0; 3317 lf.l_type = locktype; /* F_WRLCK or F_RDLCK */ 3318 /* Note: id is just a kernel address that's not a proc */ 3319 error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_SETLK, &lf, F_FLOCK|F_WAIT, context, NULL); 3320 return (error == ENOTSUP ? 0 : error); 3321} 3322 3323 int 3324unlock_xattrfile(vnode_t xvp, vfs_context_t context) 3325{ 3326 struct flock lf; 3327 int error; 3328 3329 lf.l_whence = SEEK_SET; 3330 lf.l_start = 0; 3331 lf.l_len = 0; 3332 lf.l_type = F_UNLCK; 3333 /* Note: id is just a kernel address that's not a proc */ 3334 error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_UNLCK, &lf, F_FLOCK, context, NULL); 3335 return (error == ENOTSUP ? 0 : error); 3336} 3337 3338#else /* CONFIG_APPLEDOUBLE */ 3339 3340#undef panic 3341#define panic printf 3342 3343static int 3344default_getxattr(vnode_t vp, const char *name, 3345 __unused uio_t uio, __unused size_t *size, __unused int options, 3346 __unused vfs_context_t context) 3347{ 3348#if PANIC_ON_NOAPPLEDOUBLE 3349 panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name); 3350#endif 3351 return (ENOTSUP); 3352} 3353 3354static int 3355default_setxattr(vnode_t vp, const char *name, 3356 __unused uio_t uio, __unused int options, __unused vfs_context_t context) 3357{ 3358#if PANIC_ON_NOAPPLEDOUBLE 3359 panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name); 3360#endif 3361 return (ENOTSUP); 3362} 3363 3364static int 3365default_listxattr(vnode_t vp, 3366 __unused uio_t uio, __unused size_t *size, __unused int options, 3367 __unused vfs_context_t context) 3368{ 3369#if PANIC_ON_NOAPPLEDOUBLE 3370 panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, "."); 3371#endif 3372 return (ENOTSUP); 3373} 3374 3375static int 3376default_removexattr(vnode_t vp, const char *name, 3377 __unused int options, __unused vfs_context_t context) 3378{ 3379#if PANIC_ON_NOAPPLEDOUBLE 3380 panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name); 3381#endif 3382 return (ENOTSUP); 3383} 3384 3385#endif /* CONFIG_APPLEDOUBLE */ 3386