2 * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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,
35 #include <sys/param.h>
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>
47 #include <sys/utfconv.h>
48 #include <sys/vnode.h>
49 #include <sys/vnode_internal.h>
50 #include <sys/xattr.h>
52 #include <libkern/OSByteOrder.h>
53 #include <vm/vm_kern.h>
56 #include <security/mac_framework.h>
63 * We use %p to prevent loss of precision for pointers on varying architectures.
65 #define MAKE_SHADOW_NAME(VP, NAME) \
66 snprintf((NAME), sizeof((NAME)), ".vfs_rsrc_stream_%p%08x%p", (void*)(VP), (VP)->v_id, (VP)->v_data);
68 static vnode_t shadow_dvp
; /* tmp directory to hold stream shadow files */
69 static int shadow_vid
;
70 static int shadow_sequence
;
73 static int default_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, vfs_context_t context
);
75 static int default_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, vfs_context_t context
);
77 static int default_removenamedstream(vnode_t vp
, const char *name
, vfs_context_t context
);
79 static int getshadowfile(vnode_t vp
, vnode_t
*svpp
, int makestream
, size_t *rsrcsize
, int *creator
, vfs_context_t context
);
81 static int get_shadow_dir(vnode_t
*sdvpp
, vfs_context_t context
);
87 * Default xattr support routines.
90 static int default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
,
91 vfs_context_t context
);
96 * Retrieve the data of an extended attribute.
99 vn_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
100 int options
, vfs_context_t context
)
104 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
108 /* getxattr calls are not allowed for streams. */
109 if (vp
->v_flag
& VISNAMEDSTREAM
) {
115 * Non-kernel request need extra checks performed.
117 * The XATTR_NOSECURITY flag implies a kernel request.
119 if (!(options
& XATTR_NOSECURITY
)) {
121 error
= mac_vnode_check_getextattr(context
, vp
, name
, uio
);
125 if ((error
= xattr_validatename(name
))) {
128 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
))) {
131 /* The offset can only be non-zero for resource forks. */
132 if (uio
!= NULL
&& uio_offset(uio
) != 0 &&
133 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
139 /* The offset can only be non-zero for resource forks. */
140 if (uio
!= NULL
&& uio_offset(uio
) != 0 &&
141 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
146 error
= VNOP_GETXATTR(vp
, name
, uio
, size
, options
, context
);
147 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
149 * A filesystem may keep some EAs natively and return ENOTSUP for others.
150 * SMB returns ENOTSUP for finderinfo and resource forks.
152 error
= default_getxattr(vp
, name
, uio
, size
, options
, context
);
159 * Set the data of an extended attribute.
162 vn_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
166 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
170 /* setxattr calls are not allowed for streams. */
171 if (vp
->v_flag
& VISNAMEDSTREAM
) {
176 if ((options
& (XATTR_REPLACE
|XATTR_CREATE
)) == (XATTR_REPLACE
|XATTR_CREATE
)) {
179 if ((error
= xattr_validatename(name
))) {
182 if (!(options
& XATTR_NOSECURITY
)) {
184 error
= mac_vnode_check_setextattr(context
, vp
, name
, uio
);
188 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
);
192 /* The offset can only be non-zero for resource forks. */
193 if (uio_offset(uio
) != 0 &&
194 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0 ) {
199 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
202 * An EJUSTRETURN is from a filesystem which keeps this xattr
203 * natively as well as in a dot-underscore file. In this case the
204 * EJUSTRETURN means the filesytem has done nothing, but identifies the
205 * EA as one which may be represented natively and/or in a DU, and
206 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
207 * in vn_setxattr can we do the getxattrs needed to ascertain whether
208 * the XATTR_{CREATE,REPLACE} should yield an error.
210 if (error
== EJUSTRETURN
) {
211 int native
= 0, dufile
= 0;
212 size_t sz
; /* not used */
214 native
= VNOP_GETXATTR(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
215 dufile
= default_getxattr(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
216 if (options
& XATTR_CREATE
&& (native
|| dufile
)) {
220 if (options
& XATTR_REPLACE
&& !(native
|| dufile
)) {
225 * Having determined no CREATE/REPLACE error should result, we
226 * zero those bits, so both backing stores get written to.
228 options
&= ~(XATTR_CREATE
| XATTR_REPLACE
);
229 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
230 /* the mainline path here is to have error==ENOTSUP ... */
232 #endif /* DUAL_EAS */
233 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
235 * A filesystem may keep some EAs natively and return ENOTSUP for others.
236 * SMB returns ENOTSUP for finderinfo and resource forks.
238 error
= default_setxattr(vp
, name
, uio
, options
, context
);
241 if ((error
== 0) && !(options
& XATTR_NOSECURITY
) &&
242 (vfs_flags(vnode_mount(vp
)) & MNT_MULTILABEL
))
243 mac_vnode_label_update_extattr(vnode_mount(vp
), vp
, name
);
250 * Remove an extended attribute.
253 vn_removexattr(vnode_t vp
, const char * name
, int options
, vfs_context_t context
)
257 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
261 /* removexattr calls are not allowed for streams. */
262 if (vp
->v_flag
& VISNAMEDSTREAM
) {
267 if ((error
= xattr_validatename(name
))) {
270 if (!(options
& XATTR_NOSECURITY
)) {
272 error
= mac_vnode_check_deleteextattr(context
, vp
, name
);
276 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
);
280 error
= VNOP_REMOVEXATTR(vp
, name
, options
, context
);
281 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
283 * A filesystem may keep some EAs natively and return ENOTSUP for others.
284 * SMB returns ENOTSUP for finderinfo and resource forks.
286 error
= default_removexattr(vp
, name
, options
, context
);
288 } else if (error
== EJUSTRETURN
) {
290 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
291 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
292 * a native xattr, so failure to find it in a DU file during
293 * default_removexattr should not be considered an error.
295 error
= default_removexattr(vp
, name
, options
, context
);
296 if (error
== ENOATTR
)
298 #endif /* DUAL_EAS */
301 if ((error
== 0) && !(options
& XATTR_NOSECURITY
) &&
302 (vfs_flags(vnode_mount(vp
)) & MNT_MULTILABEL
))
303 mac_vnode_label_update_extattr(vnode_mount(vp
), vp
, name
);
310 * Retrieve the list of extended attribute names.
313 vn_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
)
317 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
321 /* listxattr calls are not allowed for streams. */
322 if (vp
->v_flag
& VISNAMEDSTREAM
) {
327 if (!(options
& XATTR_NOSECURITY
)) {
329 error
= mac_vnode_check_listextattr(context
, vp
);
334 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
);
339 error
= VNOP_LISTXATTR(vp
, uio
, size
, options
, context
);
340 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
342 * A filesystem may keep some but not all EAs natively, in which case
343 * the native EA names will have been uiomove-d out (or *size updated)
344 * and the default_listxattr here will finish the job. Note SMB takes
345 * advantage of this for its finder-info and resource forks.
347 error
= default_listxattr(vp
, uio
, size
, options
, context
);
354 xattr_validatename(const char *name
)
358 if (name
== NULL
|| name
[0] == '\0') {
361 namelen
= strnlen(name
, XATTR_MAXNAMELEN
);
362 if (name
[namelen
] != '\0')
363 return (ENAMETOOLONG
);
365 if (utf8_validatestr((const unsigned char *)name
, namelen
) != 0)
373 * Determine whether an EA is a protected system attribute.
376 xattr_protected(const char *attrname
)
378 return(!strncmp(attrname
, "com.apple.system.", 17));
384 * Obtain a named stream from vnode vp.
387 vnode_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, int flags
, vfs_context_t context
)
391 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
392 error
= VNOP_GETNAMEDSTREAM(vp
, svpp
, name
, op
, flags
, context
);
394 error
= default_getnamedstream(vp
, svpp
, name
, op
, context
);
397 uint32_t streamflags
= VISNAMEDSTREAM
;
400 if ((vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0) {
401 streamflags
|= VISSHADOW
;
405 vnode_lock_spin(svp
);
406 svp
->v_flag
|= streamflags
;
409 /* Tag the parent so we know to flush credentials for streams on setattr */
411 vp
->v_lflag
|= VL_HASSTREAMS
;
414 /* Make the file it's parent.
415 * Note: This parent link helps us distinguish vnodes for
416 * shadow stream files from vnodes for resource fork on file
417 * systems that support namedstream natively (both have
418 * VISNAMEDSTREAM set) by allowing access to mount structure
419 * for checking MNTK_NAMED_STREAMS bit at many places in the
422 vnode_update_identity(svp
, vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
429 * Make a named stream for vnode vp.
432 vnode_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, int flags
, vfs_context_t context
)
436 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
437 error
= VNOP_MAKENAMEDSTREAM(vp
, svpp
, name
, flags
, context
);
439 error
= default_makenamedstream(vp
, svpp
, name
, context
);
442 uint32_t streamflags
= VISNAMEDSTREAM
;
446 if ((vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0) {
447 streamflags
|= VISSHADOW
;
451 vnode_lock_spin(svp
);
452 svp
->v_flag
|= streamflags
;
455 /* Tag the parent so we know to flush credentials for streams on setattr */
457 vp
->v_lflag
|= VL_HASSTREAMS
;
460 /* Make the file it's parent.
461 * Note: This parent link helps us distinguish vnodes for
462 * shadow stream files from vnodes for resource fork on file
463 * systems that support namedstream natively (both have
464 * VISNAMEDSTREAM set) by allowing access to mount structure
465 * for checking MNTK_NAMED_STREAMS bit at many places in the
468 vnode_update_identity(svp
, vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
474 * Remove a named stream from vnode vp.
477 vnode_removenamedstream(vnode_t vp
, vnode_t svp
, const char *name
, int flags
, vfs_context_t context
)
481 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
482 error
= VNOP_REMOVENAMEDSTREAM(vp
, svp
, name
, flags
, context
);
484 error
= default_removenamedstream(vp
, name
, context
);
489 #define NS_IOBUFSIZE (128 * 1024)
492 * Release a named stream shadow file.
494 * Note: This function is called from two places where we do not need
495 * to check if the vnode has any references held before deleting the
496 * shadow file. Once from vclean() when the vnode is being reclaimed
497 * and we do not hold any references on the vnode. Second time from
498 * default_getnamedstream() when we get an error during shadow stream
499 * file initialization so that other processes who are waiting for the
500 * shadow stream file initialization by the creator will get opportunity
501 * to create and initialize the file again.
504 vnode_relenamedstream(vnode_t vp
, vnode_t svp
, vfs_context_t context
)
507 struct componentname cn
;
514 MAKE_SHADOW_NAME(vp
, tmpname
);
517 cn
.cn_nameiop
= DELETE
;
518 cn
.cn_flags
= ISLASTCN
;
519 cn
.cn_context
= context
;
520 cn
.cn_pnbuf
= tmpname
;
521 cn
.cn_pnlen
= sizeof(tmpname
);
522 cn
.cn_nameptr
= cn
.cn_pnbuf
;
523 cn
.cn_namelen
= strlen(tmpname
);
525 /* Obtain the vnode for the shadow files directory. */
526 err
= get_shadow_dir(&dvp
, context
);
531 (void) VNOP_REMOVE(dvp
, svp
, &cn
, 0, context
);
538 * Flush a named stream shadow file.
541 vnode_flushnamedstream(vnode_t vp
, vnode_t svp
, vfs_context_t context
)
543 struct vnode_attr va
;
545 caddr_t bufptr
= NULL
;
553 VATTR_WANTED(&va
, va_data_size
);
554 if (VNOP_GETATTR(svp
, &va
, context
) != 0 ||
555 !VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
558 datasize
= va
.va_data_size
;
559 if ((datasize
== 0)) {
560 (void) default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
564 iosize
= bufsize
= MIN(datasize
, NS_IOBUFSIZE
);
565 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&bufptr
, bufsize
)) {
568 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
572 * Copy the shadow stream file data into the resource fork.
574 error
= VNOP_OPEN(svp
, 0, context
);
576 printf("vnode_flushnamedstream: err %d opening file\n", error
);
579 while (offset
< datasize
) {
580 iosize
= MIN(datasize
- offset
, iosize
);
582 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_READ
);
583 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
584 error
= VNOP_READ(svp
, auio
, 0, context
);
588 /* Since there's no truncate xattr we must remove the resource fork. */
590 error
= default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
591 if ((error
!= 0) && (error
!= ENOATTR
)) {
595 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_WRITE
);
596 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
597 error
= vn_setxattr(vp
, XATTR_RESOURCEFORK_NAME
, auio
, XATTR_NOSECURITY
, context
);
603 (void) VNOP_CLOSE(svp
, 0, context
);
606 kmem_free(kernel_map
, (vm_offset_t
)bufptr
, bufsize
);
616 getshadowfile(vnode_t vp
, vnode_t
*svpp
, int makestream
, size_t *rsrcsize
,
617 int *creator
, vfs_context_t context
)
619 vnode_t dvp
= NULLVP
;
620 vnode_t svp
= NULLVP
;
621 struct componentname cn
;
622 struct vnode_attr va
;
629 /* Establish a unique file name. */
630 MAKE_SHADOW_NAME(vp
, tmpname
);
631 bzero(&cn
, sizeof(cn
));
632 cn
.cn_nameiop
= LOOKUP
;
633 cn
.cn_flags
= ISLASTCN
;
634 cn
.cn_context
= context
;
635 cn
.cn_pnbuf
= tmpname
;
636 cn
.cn_pnlen
= sizeof(tmpname
);
637 cn
.cn_nameptr
= cn
.cn_pnbuf
;
638 cn
.cn_namelen
= strlen(tmpname
);
640 /* Pick up uid, gid, mode and date from original file. */
642 VATTR_WANTED(&va
, va_uid
);
643 VATTR_WANTED(&va
, va_gid
);
644 VATTR_WANTED(&va
, va_mode
);
645 VATTR_WANTED(&va
, va_create_time
);
646 VATTR_WANTED(&va
, va_modify_time
);
647 if (VNOP_GETATTR(vp
, &va
, context
) != 0 ||
648 !VATTR_IS_SUPPORTED(&va
, va_uid
) ||
649 !VATTR_IS_SUPPORTED(&va
, va_gid
) ||
650 !VATTR_IS_SUPPORTED(&va
, va_mode
)) {
651 va
.va_uid
= KAUTH_UID_NONE
;
652 va
.va_gid
= KAUTH_GID_NONE
;
653 va
.va_mode
= S_IRUSR
| S_IWUSR
;
655 va
.va_vaflags
= VA_EXCLUSIVE
;
656 VATTR_SET(&va
, va_type
, VREG
);
657 /* We no longer change the access, but we still hide it. */
658 VATTR_SET(&va
, va_flags
, UF_HIDDEN
);
660 /* Obtain the vnode for the shadow files directory. */
661 if (get_shadow_dir(&dvp
, context
) != 0) {
666 /* See if someone else already has it open. */
667 if (VNOP_LOOKUP(dvp
, &svp
, &cn
, context
) == 0) {
668 /* Double check existence by asking for size. */
670 VATTR_WANTED(&va
, va_data_size
);
671 if (VNOP_GETATTR(svp
, &va
, context
) == 0 &&
672 VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
673 goto out
; /* OK to use. */
677 /* Otherwise make sure the resource fork data exists. */
678 error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &datasize
,
679 XATTR_NOSECURITY
, context
);
681 * To maintain binary compatibility with legacy Carbon
682 * emulated resource fork support, if the resource fork
683 * doesn't exist but the Finder Info does, then act as
684 * if an empty resource fork is present (see 4724359).
686 if ((error
== ENOATTR
) &&
687 (vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, NULL
, &datasize
,
688 XATTR_NOSECURITY
, context
) == 0)) {
696 /* If the resource fork exists, its size is expected to be non-zero. */
703 /* Create the shadow stream file. */
704 error
= VNOP_CREATE(dvp
, &svp
, &cn
, &va
, context
);
708 } else if ((error
== EEXIST
) && !makestream
) {
709 error
= VNOP_LOOKUP(dvp
, &svp
, &cn
, context
);
716 /* On errors, clean up shadow stream file. */
724 *rsrcsize
= datasize
;
731 default_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, vfs_context_t context
)
733 vnode_t svp
= NULLVP
;
735 caddr_t bufptr
= NULL
;
742 * Only the "com.apple.ResourceFork" stream is supported here.
744 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
750 * Obtain a shadow file for the resource fork I/O.
752 error
= getshadowfile(vp
, &svp
, 0, &datasize
, &creator
, context
);
759 * The creator of the shadow file provides its file data,
760 * all other threads should wait until its ready. In order to
761 * prevent a deadlock during error codepaths, we need to check if the
762 * vnode is being created, or if it has failed out. Regardless of success or
763 * failure, we set the VISSHADOW bit on the vnode, so we check that
764 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't,
765 * then we can infer the creator isn't done yet. If it's there, but
766 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
771 if (svp
->v_flag
& VISNAMEDSTREAM
) {
772 /* data is ready, go use it */
776 /* It's not ready, wait for it (sleep using v_parent as channel) */
777 if ((svp
->v_flag
& VISSHADOW
)) {
779 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
780 * thread is done with this vnode. Just unlock the vnode and try again
785 /* Otherwise, sleep if the shadow file is not created yet */
786 msleep((caddr_t
)&svp
->v_parent
, &svp
->v_lock
, PINOD
| PDROP
,
787 "getnamedstream", NULL
);
796 * Copy the real resource fork data into shadow stream file.
798 if (op
== NS_OPEN
&& datasize
!= 0) {
802 iosize
= bufsize
= MIN(datasize
, NS_IOBUFSIZE
);
803 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&bufptr
, bufsize
)) {
808 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
811 error
= VNOP_OPEN(svp
, 0, context
);
815 while (offset
< datasize
) {
818 iosize
= MIN(datasize
- offset
, iosize
);
820 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_READ
);
821 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
822 error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, auio
, &tmpsize
,
823 XATTR_NOSECURITY
, context
);
828 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_WRITE
);
829 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
830 error
= VNOP_WRITE(svp
, auio
, 0, context
);
836 (void) VNOP_CLOSE(svp
, 0, context
);
839 /* Wake up anyone waiting for svp file content */
843 /* VISSHADOW would be set later on anyway, so we set it now */
844 svp
->v_flag
|= (VISNAMEDSTREAM
| VISSHADOW
);
845 wakeup((caddr_t
)&svp
->v_parent
);
848 /* On post create errors, get rid of the shadow file. This
849 * way if there is another process waiting for initialization
850 * of the shadowfile by the current process will wake up and
851 * retry by creating and initializing the shadow file again.
852 * Also add the VISSHADOW bit here to indicate we're done operating
855 (void)vnode_relenamedstream(vp
, svp
, context
);
857 svp
->v_flag
|= VISSHADOW
;
858 wakeup((caddr_t
)&svp
->v_parent
);
864 kmem_free(kernel_map
, (vm_offset_t
)bufptr
, bufsize
);
870 /* On errors, clean up shadow stream file. */
881 default_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, vfs_context_t context
)
887 * Only the "com.apple.ResourceFork" stream is supported here.
889 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
893 error
= getshadowfile(vp
, svpp
, 1, NULL
, &creator
, context
);
896 * Wake up any waiters over in default_getnamedstream().
898 if ((error
== 0) && (*svpp
!= NULL
) && creator
) {
902 /* If we're the creator, mark it as a named stream */
903 svp
->v_flag
|= (VISNAMEDSTREAM
| VISSHADOW
);
904 /* Wakeup any waiters on the v_parent channel */
905 wakeup((caddr_t
)&svp
->v_parent
);
914 default_removenamedstream(vnode_t vp
, const char *name
, vfs_context_t context
)
917 * Only the "com.apple.ResourceFork" stream is supported here.
919 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
923 * XXX - what about other opened instances?
925 return default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
929 get_shadow_dir(vnode_t
*sdvpp
, vfs_context_t context
)
931 vnode_t dvp
= NULLVP
;
932 vnode_t sdvp
= NULLVP
;
933 struct componentname cn
;
934 struct vnode_attr va
;
939 /* Check if we've already created it. */
940 if (shadow_dvp
!= NULLVP
) {
941 if ((error
= vnode_getwithvid(shadow_dvp
, shadow_vid
))) {
949 /* Obtain the vnode for "/tmp" directory. */
950 if (vnode_lookup("/tmp", 0, &dvp
, context
) != 0) {
955 /* Create the shadow stream directory. */
956 snprintf(tmpname
, sizeof(tmpname
), ".vfs_rsrc_streams_%p%x",
957 (void*)rootvnode
, shadow_sequence
);
958 bzero(&cn
, sizeof(cn
));
959 cn
.cn_nameiop
= LOOKUP
;
960 cn
.cn_flags
= ISLASTCN
;
961 cn
.cn_context
= context
;
962 cn
.cn_pnbuf
= tmpname
;
963 cn
.cn_pnlen
= sizeof(tmpname
);
964 cn
.cn_nameptr
= cn
.cn_pnbuf
;
965 cn
.cn_namelen
= strlen(tmpname
);
968 * owned by root, only readable by root, hidden
971 VATTR_SET(&va
, va_uid
, 0);
972 VATTR_SET(&va
, va_gid
, 0);
973 VATTR_SET(&va
, va_mode
, S_IRUSR
| S_IXUSR
);
974 VATTR_SET(&va
, va_type
, VDIR
);
975 VATTR_SET(&va
, va_flags
, UF_HIDDEN
);
976 va
.va_vaflags
= VA_EXCLUSIVE
;
978 error
= VNOP_MKDIR(dvp
, &sdvp
, &cn
, &va
, context
);
981 * There can be only one winner for an exclusive create.
984 /* Take a long term ref to keep this dir around. */
985 error
= vnode_ref(sdvp
);
988 shadow_vid
= sdvp
->v_id
;
990 } else if (error
== EEXIST
) {
991 /* loser has to look up directory */
992 error
= VNOP_LOOKUP(dvp
, &sdvp
, &cn
, context
);
994 /* Make sure its in fact a directory */
995 if (sdvp
->v_type
!= VDIR
) {
998 /* Obtain the fsid for /tmp directory */
1000 VATTR_WANTED(&va
, va_fsid
);
1001 if (VNOP_GETATTR(dvp
, &va
, context
) != 0 ||
1002 !VATTR_IS_SUPPORTED(&va
, va_fsid
)) {
1005 tmp_fsid
= va
.va_fsid
;
1008 VATTR_WANTED(&va
, va_uid
);
1009 VATTR_WANTED(&va
, va_gid
);
1010 VATTR_WANTED(&va
, va_mode
);
1011 VATTR_WANTED(&va
, va_fsid
);
1012 VATTR_WANTED(&va
, va_dirlinkcount
);
1013 VATTR_WANTED(&va
, va_acl
);
1014 /* Provide defaults for attrs that may not be supported */
1015 va
.va_dirlinkcount
= 1;
1016 va
.va_acl
= (kauth_acl_t
) KAUTH_FILESEC_NONE
;
1018 if (VNOP_GETATTR(sdvp
, &va
, context
) != 0 ||
1019 !VATTR_IS_SUPPORTED(&va
, va_uid
) ||
1020 !VATTR_IS_SUPPORTED(&va
, va_gid
) ||
1021 !VATTR_IS_SUPPORTED(&va
, va_mode
) ||
1022 !VATTR_IS_SUPPORTED(&va
, va_fsid
)) {
1026 * Make sure its what we want:
1028 * - not writable by anyone
1029 * - on same file system as /tmp
1030 * - not a hard-linked directory
1031 * - no ACLs (they might grant write access)
1033 if ((va
.va_uid
!= 0) || (va
.va_gid
!= 0) ||
1034 (va
.va_mode
& (S_IWUSR
| S_IRWXG
| S_IRWXO
)) ||
1035 (va
.va_fsid
!= tmp_fsid
) ||
1036 (va
.va_dirlinkcount
!= 1) ||
1037 (va
.va_acl
!= (kauth_acl_t
) KAUTH_FILESEC_NONE
)) {
1047 /* On errors, clean up shadow stream directory. */
1057 /* This is not the dir we're looking for, move along */
1058 ++shadow_sequence
; /* try something else next time */
1067 * Default Implementation (Non-native EA)
1072 Typical "._" AppleDouble Header File layout:
1073 ------------------------------------------------------------
1078 .-- AD ENTRY[0] Finder Info Entry (must be first)
1079 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1081 | ///////////// Fixed Size Data (32 bytes)
1085 | ATTR ENTRY[1] --+--.
1086 | ATTR ENTRY[2] --+--+--.
1088 | ATTR ENTRY[N] --+--+--+--.
1089 | ATTR DATA 0 <-' | | |
1090 | //////////// | | |
1091 | ATTR DATA 1 <----' | |
1093 | ATTR DATA 2 <-------' |
1096 | ATTR DATA N <----------'
1098 | Attribute Free Space
1100 '----> RESOURCE FORK
1101 ///////////// Variable Sized Data
1110 ------------------------------------------------------------
1112 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1113 stored as part of the Finder Info. The length in the Finder
1114 Info AppleDouble entry includes the length of the extended
1115 attribute header, attribute entries, and attribute data.
1120 * On Disk Data Structures
1122 * Note: Motorola 68K alignment and big-endian.
1124 * See RFC 1740 for additional information about the AppleDouble file format.
1128 #define ADH_MAGIC 0x00051607
1129 #define ADH_VERSION 0x00020000
1130 #define ADH_MACOSX "Mac OS X "
1133 * AppleDouble Entry ID's
1135 #define AD_DATA 1 /* Data fork */
1136 #define AD_RESOURCE 2 /* Resource fork */
1137 #define AD_REALNAME 3 /* FileÕs name on home file system */
1138 #define AD_COMMENT 4 /* Standard Mac comment */
1139 #define AD_ICONBW 5 /* Mac black & white icon */
1140 #define AD_ICONCOLOR 6 /* Mac color icon */
1141 #define AD_UNUSED 7 /* Not used */
1142 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
1143 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
1144 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
1145 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
1146 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
1147 #define AD_AFPNAME 13 /* Short name on AFP server */
1148 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
1149 #define AD_AFPDIRID 15 /* AFP directory ID */
1150 #define AD_ATTRIBUTES AD_FINDERINFO
1153 #define ATTR_FILE_PREFIX "._"
1154 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
1156 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
1158 /* Implementation Limits */
1159 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
1160 #define ATTR_MAX_HDR_SIZE 65536
1162 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
1163 * size supported (including the attribute entries). All of
1164 * the attribute entries must reside within this limit. If
1165 * any of the attribute data crosses the ATTR_MAX_HDR_SIZE
1166 * boundry, then all of the attribute data I/O is performed
1167 * separately from the attribute header I/O.
1169 * In particular, all of the attr_entry structures must lie
1170 * completely within the first ATTR_MAX_HDR_SIZE bytes of the
1171 * AppleDouble file. However, the attribute data (i.e. the
1172 * contents of the extended attributes) may extend beyond the
1173 * first ATTR_MAX_HDR_SIZE bytes of the file. Note that this
1174 * limit is to allow the implementation to optimize by reading
1175 * the first ATTR_MAX_HDR_SIZE bytes of the file.
1179 #define FINDERINFOSIZE 32
1181 typedef struct apple_double_entry
{
1182 u_int32_t type
; /* entry type: see list, 0 invalid */
1183 u_int32_t offset
; /* entry data offset from the beginning of the file. */
1184 u_int32_t length
; /* entry data length in bytes. */
1185 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
1188 typedef struct apple_double_header
{
1189 u_int32_t magic
; /* == ADH_MAGIC */
1190 u_int32_t version
; /* format version: 2 = 0x00020000 */
1191 u_int32_t filler
[4];
1192 u_int16_t numEntries
; /* number of entries which follow */
1193 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
1194 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
1195 u_int8_t pad
[2]; /* get better alignment inside attr_header */
1196 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
1198 #define ADHDRSIZE (4+4+16+2)
1200 /* Entries are aligned on 4 byte boundaries */
1201 typedef struct attr_entry
{
1202 u_int32_t offset
; /* file offset to data */
1203 u_int32_t length
; /* size of attribute data */
1206 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
1207 } __attribute__((aligned(2), packed
)) attr_entry_t
;
1210 /* Header + entries must fit into 64K. Data may extend beyond 64K. */
1211 typedef struct attr_header
{
1212 apple_double_header_t appledouble
;
1213 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
1214 u_int32_t debug_tag
; /* for debugging == file id of owning file */
1215 u_int32_t total_size
; /* file offset of end of attribute header + entries + data */
1216 u_int32_t data_start
; /* file offset to attribute data area */
1217 u_int32_t data_length
; /* length of attribute data area */
1218 u_int32_t reserved
[3];
1220 u_int16_t num_attrs
;
1221 } __attribute__((aligned(2), packed
)) attr_header_t
;
1224 /* Empty Resource Fork Header */
1225 typedef struct rsrcfork_header
{
1226 u_int32_t fh_DataOffset
;
1227 u_int32_t fh_MapOffset
;
1228 u_int32_t fh_DataLength
;
1229 u_int32_t fh_MapLength
;
1230 u_int8_t systemData
[112];
1231 u_int8_t appData
[128];
1232 u_int32_t mh_DataOffset
;
1233 u_int32_t mh_MapOffset
;
1234 u_int32_t mh_DataLength
;
1235 u_int32_t mh_MapLength
;
1237 u_int16_t mh_RefNum
;
1239 u_int8_t mh_InMemoryAttr
;
1242 u_int16_t typeCount
;
1243 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
1245 #define RF_FIRST_RESOURCE 256
1246 #define RF_NULL_MAP_LENGTH 30
1247 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
1249 /* Runtime information about the attribute file. */
1250 typedef struct attr_info
{
1251 vfs_context_t context
;
1256 size_t rawsize
; /* minimum of filesize or ATTR_MAX_HDR_SIZE */
1257 apple_double_header_t
*filehdr
;
1258 apple_double_entry_t
*finderinfo
;
1259 apple_double_entry_t
*rsrcfork
;
1260 attr_header_t
*attrhdr
;
1261 attr_entry_t
*attr_entry
;
1263 u_int8_t emptyfinderinfo
;
1267 #define ATTR_SETTING 1
1269 #define ATTR_ALIGN 3L /* Use four-byte alignment */
1271 #define ATTR_ENTRY_LENGTH(namelen) \
1272 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
1274 #define ATTR_NEXT(ae) \
1275 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
1277 #define ATTR_VALID(ae, ai) \
1278 ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize))
1280 #define SWAP16(x) OSSwapBigToHostInt16((x))
1281 #define SWAP32(x) OSSwapBigToHostInt32((x))
1282 #define SWAP64(x) OSSwapBigToHostInt64((x))
1285 static u_int32_t emptyfinfo
[8] = {0};
1289 * Local support routines
1291 static void close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
);
1293 static int open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
);
1295 static int create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
);
1297 static int remove_xattrfile(vnode_t xvp
, vfs_context_t context
);
1299 static int get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
);
1301 static void rel_xattrinfo(attr_info_t
*ainfop
);
1303 static int write_xattrinfo(attr_info_t
*ainfop
);
1305 static void init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
);
1307 static int lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
);
1309 static int unlock_xattrfile(vnode_t xvp
, vfs_context_t context
);
1312 #if BYTE_ORDER == LITTLE_ENDIAN
1313 static void swap_adhdr(apple_double_header_t
*adh
);
1314 static void swap_attrhdr(attr_header_t
*ah
, attr_info_t
* info
);
1317 #define swap_adhdr(x)
1318 #define swap_attrhdr(x, y)
1321 static int check_and_swap_attrhdr(attr_header_t
*ah
, attr_info_t
* ainfop
);
1322 static int shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
1323 static int shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
1327 * Sanity check and swap the header of an AppleDouble file. Assumes the buffer
1328 * is in big endian (as it would exist on disk). Verifies the following:
1331 * - number of entries
1332 * - that each entry fits within the file size
1334 * If the header is invalid, ENOATTR is returned.
1336 * NOTE: Does not attempt to validate the extended attributes header that
1337 * may be embedded in the Finder Info entry.
1339 static int check_and_swap_apple_double_header(attr_info_t
*ainfop
)
1342 u_int32_t header_end
;
1343 u_int32_t entry_end
;
1345 apple_double_header_t
*header
;
1347 rawsize
= ainfop
->rawsize
;
1348 header
= (apple_double_header_t
*) ainfop
->rawdata
;
1350 /* Is the file big enough to contain an AppleDouble header? */
1351 if (rawsize
< offsetof(apple_double_header_t
, entries
))
1354 /* Swap the AppleDouble header fields to native order */
1355 header
->magic
= SWAP32(header
->magic
);
1356 header
->version
= SWAP32(header
->version
);
1357 header
->numEntries
= SWAP16(header
->numEntries
);
1359 /* Sanity check the AppleDouble header fields */
1360 if (header
->magic
!= ADH_MAGIC
||
1361 header
->version
!= ADH_VERSION
||
1362 header
->numEntries
< 1 ||
1363 header
->numEntries
> 15) {
1367 /* Calculate where the entries[] array ends */
1368 header_end
= offsetof(apple_double_header_t
, entries
) +
1369 header
->numEntries
* sizeof(apple_double_entry_t
);
1371 /* Is the file big enough to contain the AppleDouble entries? */
1372 if (rawsize
< header_end
) {
1376 /* Swap and sanity check each AppleDouble entry */
1377 for (i
=0; i
<header
->numEntries
; i
++) {
1378 /* Swap the per-entry fields to native order */
1379 header
->entries
[i
].type
= SWAP32(header
->entries
[i
].type
);
1380 header
->entries
[i
].offset
= SWAP32(header
->entries
[i
].offset
);
1381 header
->entries
[i
].length
= SWAP32(header
->entries
[i
].length
);
1383 entry_end
= header
->entries
[i
].offset
+ header
->entries
[i
].length
;
1386 * Does the entry's content start within the header itself,
1387 * did the addition overflow, or does the entry's content
1388 * extend past the end of the file?
1390 if (header
->entries
[i
].offset
< header_end
||
1391 entry_end
< header
->entries
[i
].offset
||
1392 entry_end
> ainfop
->filesize
) {
1397 * Does the current entry's content overlap with a previous
1400 * Yes, this is O(N**2), and there are more efficient algorithms
1401 * for testing pairwise overlap of N ranges when N is large.
1402 * But we have already ensured N < 16, and N is almost always 2.
1403 * So there's no point in using a more complex algorithm.
1406 for (j
=0; j
<i
; j
++) {
1407 if (entry_end
> header
->entries
[j
].offset
&&
1408 header
->entries
[j
].offset
+ header
->entries
[j
].length
> header
->entries
[i
].offset
) {
1420 * Retrieve the data of an extended attribute.
1423 default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
1424 __unused
int options
, vfs_context_t context
)
1428 attr_header_t
*header
;
1429 attr_entry_t
*entry
;
1439 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1442 * Open the file locked (shared) since the Carbon
1443 * File Manager may have the Apple Double file open
1444 * and could be changing the resource fork.
1446 fileflags
|= O_SHLOCK
;
1451 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
1454 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1455 close_xattrfile(xvp
, fileflags
, context
);
1459 /* Get the Finder Info. */
1460 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1462 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
1464 } else if (uio
== NULL
) {
1465 *size
= FINDERINFOSIZE
;
1467 } else if (uio_offset(uio
) != 0) {
1469 } else if (uio_resid(uio
) < FINDERINFOSIZE
) {
1472 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1473 error
= uiomove((caddr_t
)attrdata
, FINDERINFOSIZE
, uio
);
1478 /* Read the Resource Fork. */
1480 if (!vnode_isreg(vp
)) {
1482 } else if (ainfo
.rsrcfork
== NULL
) {
1484 } else if (uio
== NULL
) {
1485 *size
= (size_t)ainfo
.rsrcfork
->length
;
1487 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
1488 error
= VNOP_READ(xvp
, uio
, 0, context
);
1490 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
1495 if (ainfo
.attrhdr
== NULL
|| ainfo
.attr_entry
== NULL
) {
1499 if (uio_offset(uio
) != 0) {
1504 namelen
= strlen(name
) + 1;
1505 header
= ainfo
.attrhdr
;
1506 entry
= ainfo
.attr_entry
;
1508 * Search for attribute name in the header.
1510 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1511 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
1512 datalen
= (size_t)entry
->length
;
1518 if (uio_resid(uio
) < (user_ssize_t
)datalen
) {
1522 if (entry
->offset
+ datalen
< ATTR_MAX_HDR_SIZE
) {
1523 attrdata
= ((u_int8_t
*)header
+ entry
->offset
);
1524 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1526 uio_setoffset(uio
, entry
->offset
);
1527 error
= VNOP_READ(xvp
, uio
, 0, context
);
1528 uio_setoffset(uio
, 0);
1532 entry
= ATTR_NEXT(entry
);
1535 rel_xattrinfo(&ainfo
);
1536 close_xattrfile(xvp
, fileflags
, context
);
1542 * Set the data of an extended attribute.
1545 default_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
1549 attr_header_t
*header
;
1550 attr_entry_t
*entry
;
1551 attr_entry_t
*lastentry
;
1555 size_t datafreespace
;
1562 char finfo
[FINDERINFOSIZE
];
1564 datalen
= uio_resid(uio
);
1565 namelen
= strlen(name
) + 1;
1566 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
1569 * By convention, Finder Info that is all zeroes is equivalent to not
1570 * having a Finder Info EA. So if we're trying to set the Finder Info
1571 * to all zeroes, then delete it instead. If a file didn't have an
1572 * AppleDouble file before, this prevents creating an AppleDouble file
1573 * with no useful content.
1575 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check
1576 * for all zeroes Finder Info before opening the AppleDouble file.
1577 * But if either of those options were specified, we need to open the
1578 * AppleDouble file to see whether there was already Finder Info (so we
1579 * can return an error if needed); this case is handled further below.
1581 * NOTE: this copies the Finder Info data into the "finfo" local.
1583 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1585 * TODO: check the XATTR_CREATE and XATTR_REPLACE flags.
1586 * That means we probably have to open_xattrfile and get_xattrinfo.
1588 if (uio_offset(uio
) != 0 || datalen
!= FINDERINFOSIZE
) {
1591 error
= uiomove(finfo
, datalen
, uio
);
1594 if ((options
& (XATTR_CREATE
|XATTR_REPLACE
)) == 0 &&
1595 bcmp(finfo
, emptyfinfo
, FINDERINFOSIZE
) == 0) {
1596 error
= default_removexattr(vp
, name
, 0, context
);
1597 if (error
== ENOATTR
)
1605 * Open the file locked since setting an attribute
1606 * can change the layout of the Apple Double file.
1608 fileflags
= FREAD
| FWRITE
| O_EXLOCK
;
1609 if ((error
= open_xattrfile(vp
, O_CREAT
| fileflags
, &xvp
, context
))) {
1612 if ((error
= get_xattrinfo(xvp
, ATTR_SETTING
, &ainfo
, context
))) {
1613 close_xattrfile(xvp
, fileflags
, context
);
1617 /* Set the Finder Info. */
1618 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1619 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
1620 /* attr exists and "create" was specified? */
1621 if (options
& XATTR_CREATE
) {
1626 /* attr doesn't exists and "replace" was specified? */
1627 if (options
& XATTR_REPLACE
) {
1632 if (options
!= 0 && bcmp(finfo
, emptyfinfo
, FINDERINFOSIZE
) == 0) {
1634 * Setting the Finder Info to all zeroes is equivalent to
1635 * removing it. Close the xattr file and let
1636 * default_removexattr do the work (including deleting
1637 * the xattr file if there are no other xattrs).
1639 * Note that we have to handle the case where the
1640 * Finder Info was already all zeroes, and we ignore
1643 * The common case where options == 0 was handled above.
1645 rel_xattrinfo(&ainfo
);
1646 close_xattrfile(xvp
, fileflags
, context
);
1647 error
= default_removexattr(vp
, name
, 0, context
);
1648 if (error
== ENOATTR
)
1652 if (ainfo
.finderinfo
) {
1653 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1654 bcopy(finfo
, attrdata
, datalen
);
1655 ainfo
.iosize
= sizeof(attr_header_t
);
1656 error
= write_xattrinfo(&ainfo
);
1663 /* Write the Resource Fork. */
1664 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1665 u_int32_t endoffset
;
1667 if (!vnode_isreg(vp
)) {
1671 if (ainfo
.rsrcfork
&& ainfo
.rsrcfork
->length
) {
1672 /* attr exists and "create" was specified? */
1673 if (options
& XATTR_CREATE
) {
1678 /* attr doesn't exists and "replace" was specified? */
1679 if (options
& XATTR_REPLACE
) {
1684 endoffset
= uio_resid(uio
) + uio_offset(uio
); /* new size */
1685 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
1686 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1689 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
1690 if (endoffset
> ainfo
.rsrcfork
->length
) {
1691 ainfo
.rsrcfork
->length
= endoffset
;
1692 ainfo
.iosize
= sizeof(attr_header_t
);
1693 error
= write_xattrinfo(&ainfo
);
1699 if (datalen
> ATTR_MAX_SIZE
) {
1700 return (E2BIG
); /* EINVAL instead ? */
1703 if (ainfo
.attrhdr
== NULL
) {
1707 header
= ainfo
.attrhdr
;
1708 entry
= ainfo
.attr_entry
;
1710 /* Check if data area crosses the maximum header size. */
1711 if ((header
->data_start
+ header
->data_length
+ entrylen
+ datalen
) > ATTR_MAX_HDR_SIZE
)
1712 splitdata
= 1; /* do data I/O separately */
1717 * See if attribute already exists.
1719 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1720 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
1724 entry
= ATTR_NEXT(entry
);
1728 if (options
& XATTR_CREATE
) {
1732 if (datalen
== entry
->length
) {
1734 uio_setoffset(uio
, entry
->offset
);
1735 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1736 uio_setoffset(uio
, 0);
1738 printf("setxattr: VNOP_WRITE error %d\n", error
);
1741 attrdata
= (u_int8_t
*)header
+ entry
->offset
;
1742 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1745 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
1746 error
= write_xattrinfo(&ainfo
);
1748 printf("setxattr: write_xattrinfo error %d\n", error
);
1754 * Brute force approach - just remove old entry and set new entry.
1757 rel_xattrinfo(&ainfo
);
1758 close_xattrfile(xvp
, fileflags
, context
);
1759 error
= default_removexattr(vp
, name
, options
, context
);
1763 /* Clear XATTR_REPLACE option since we just removed the attribute. */
1764 options
&= ~XATTR_REPLACE
;
1765 goto start
; /* start over */
1770 if (options
& XATTR_REPLACE
) {
1771 error
= ENOATTR
; /* nothing there to replace */
1774 /* Check if header size limit has been reached. */
1775 if ((header
->data_start
+ entrylen
) > ATTR_MAX_HDR_SIZE
) {
1780 datafreespace
= header
->total_size
- (header
->data_start
+ header
->data_length
);
1782 /* Check if we need more space. */
1783 if ((datalen
+ entrylen
) > datafreespace
) {
1786 growsize
= roundup((datalen
+ entrylen
) - datafreespace
, ATTR_BUF_SIZE
);
1788 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */
1789 if (!splitdata
&& (header
->total_size
+ growsize
) > ATTR_MAX_HDR_SIZE
) {
1790 growsize
= ATTR_MAX_HDR_SIZE
- header
->total_size
;
1793 ainfo
.filesize
+= growsize
;
1794 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
1796 printf("setxattr: VNOP_TRUNCATE error %d\n", error
);
1802 * Move the resource fork out of the way.
1804 if (ainfo
.rsrcfork
) {
1805 if (ainfo
.rsrcfork
->length
!= 0) {
1806 shift_data_down(xvp
,
1807 ainfo
.rsrcfork
->offset
,
1808 ainfo
.rsrcfork
->length
,
1811 ainfo
.rsrcfork
->offset
+= growsize
;
1813 ainfo
.finderinfo
->length
+= growsize
;
1814 header
->total_size
+= growsize
;
1817 /* Make space for a new entry. */
1819 shift_data_down(xvp
,
1821 header
->data_length
,
1824 bcopy((u_int8_t
*)header
+ header
->data_start
,
1825 (u_int8_t
*)header
+ header
->data_start
+ entrylen
,
1826 header
->data_length
);
1828 header
->data_start
+= entrylen
;
1830 /* Fix up entry data offsets. */
1832 for (entry
= ainfo
.attr_entry
; entry
!= lastentry
&& ATTR_VALID(entry
, ainfo
); entry
= ATTR_NEXT(entry
)) {
1833 entry
->offset
+= entrylen
;
1837 * If the attribute data area is entirely within
1838 * the header buffer, then just update the buffer,
1839 * otherwise we'll write it separately to the file.
1844 /* Write new attribute data after the end of existing data. */
1845 offset
= header
->data_start
+ header
->data_length
;
1846 uio_setoffset(uio
, offset
);
1847 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1848 uio_setoffset(uio
, 0);
1850 printf("setxattr: VNOP_WRITE error %d\n", error
);
1854 attrdata
= (u_int8_t
*)header
+ header
->data_start
+ header
->data_length
;
1856 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1858 printf("setxattr: uiomove error %d\n", error
);
1863 /* Create the attribute entry. */
1864 lastentry
->length
= datalen
;
1865 lastentry
->offset
= header
->data_start
+ header
->data_length
;
1866 lastentry
->namelen
= namelen
;
1867 lastentry
->flags
= 0;
1868 bcopy(name
, &lastentry
->name
[0], namelen
);
1870 /* Update the attributes header. */
1871 header
->num_attrs
++;
1872 header
->data_length
+= datalen
;
1875 /* Only write the entries, since the data was written separately. */
1876 ainfo
.iosize
= ainfo
.attrhdr
->data_start
;
1878 /* The entry and data are both in the header; write them together. */
1879 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
1881 error
= write_xattrinfo(&ainfo
);
1883 printf("setxattr: write_xattrinfo error %d\n", error
);
1887 rel_xattrinfo(&ainfo
);
1888 close_xattrfile(xvp
, fileflags
, context
);
1890 /* Touch the change time if we changed an attribute. */
1892 struct vnode_attr va
;
1894 /* Re-write the mtime to cause a ctime change. */
1896 VATTR_WANTED(&va
, va_modify_time
);
1897 if (vnode_getattr(vp
, &va
, context
) == 0) {
1899 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
1900 (void) vnode_setattr(vp
, &va
, context
);
1904 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
1911 * Remove an extended attribute.
1914 default_removexattr(vnode_t vp
, const char *name
, __unused
int options
, vfs_context_t context
)
1918 attr_header_t
*header
;
1919 attr_entry_t
*entry
;
1920 attr_entry_t
*oldslot
;
1926 int found
= 0, lastone
= 0;
1934 fileflags
= FREAD
| FWRITE
;
1935 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1938 * Open the file locked (exclusive) since the Carbon
1939 * File Manager may have the Apple Double file open
1940 * and could be changing the resource fork.
1942 fileflags
|= O_EXLOCK
;
1947 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
1950 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1951 close_xattrfile(xvp
, fileflags
, context
);
1955 attrcount
+= ainfo
.attrhdr
->num_attrs
;
1958 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
)
1961 /* Clear the Finder Info. */
1962 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1963 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
1967 /* On removal of last attribute the ._ file is removed. */
1968 if (--attrcount
== 0)
1970 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1971 bzero((caddr_t
)attrdata
, FINDERINFOSIZE
);
1972 ainfo
.iosize
= sizeof(attr_header_t
);
1973 error
= write_xattrinfo(&ainfo
);
1977 /* Clear the Resource Fork. */
1979 if (!vnode_isreg(vp
)) {
1983 if (ainfo
.rsrcfork
== NULL
|| ainfo
.rsrcfork
->length
== 0) {
1987 /* On removal of last attribute the ._ file is removed. */
1988 if (--attrcount
== 0)
1992 * If the resource fork isn't the last AppleDouble
1993 * entry then the space needs to be reclaimed by
1994 * shifting the entries after the resource fork.
1996 if ((ainfo
.rsrcfork
->offset
+ ainfo
.rsrcfork
->length
) == ainfo
.filesize
) {
1997 ainfo
.filesize
-= ainfo
.rsrcfork
->length
;
1998 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
2001 ainfo
.rsrcfork
->length
= 0;
2002 ainfo
.iosize
= sizeof(attr_header_t
);
2003 error
= write_xattrinfo(&ainfo
);
2008 if (ainfo
.attrhdr
== NULL
) {
2012 namelen
= strlen(name
) + 1;
2013 header
= ainfo
.attrhdr
;
2014 entry
= ainfo
.attr_entry
;
2017 * See if this attribute exists.
2019 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
2020 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
2022 if ((i
+1) == header
->num_attrs
)
2026 entry
= ATTR_NEXT(entry
);
2032 /* On removal of last attribute the ._ file is removed. */
2033 if (--attrcount
== 0)
2036 datalen
= entry
->length
;
2037 dataoff
= entry
->offset
;
2038 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
2039 if ((header
->data_start
+ header
->data_length
) > ATTR_MAX_HDR_SIZE
)
2044 /* Remove the attribute entry. */
2046 bcopy((u_int8_t
*)entry
+ entrylen
, (u_int8_t
*)entry
,
2047 ((size_t)header
+ header
->data_start
) - ((size_t)entry
+ entrylen
));
2050 /* Adjust the attribute data. */
2054 dataoff
- header
->data_start
,
2060 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
),
2064 /* XXX write zeros to freed space ? */
2065 ainfo
.iosize
= ainfo
.attrhdr
->data_start
- entrylen
;
2069 bcopy((u_int8_t
*)header
+ header
->data_start
,
2070 (u_int8_t
*)header
+ header
->data_start
- entrylen
,
2071 dataoff
- header
->data_start
);
2073 bcopy((u_int8_t
*)header
+ dataoff
+ datalen
,
2074 (u_int8_t
*)header
+ dataoff
- entrylen
,
2075 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
));
2077 bzero (((u_int8_t
*)header
+ header
->data_start
+ header
->data_length
) - (datalen
+ entrylen
), (datalen
+ entrylen
));
2078 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
2081 /* Adjust the header values and entry offsets. */
2082 header
->num_attrs
--;
2083 header
->data_start
-= entrylen
;
2084 header
->data_length
-= datalen
;
2087 entry
= ainfo
.attr_entry
;
2088 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
2089 entry
->offset
-= entrylen
;
2090 if (entry
>= oldslot
)
2091 entry
->offset
-= datalen
;
2092 entry
= ATTR_NEXT(entry
);
2094 error
= write_xattrinfo(&ainfo
);
2096 printf("removexattr: write_xattrinfo error %d\n", error
);
2099 rel_xattrinfo(&ainfo
);
2101 /* When there are no more attributes remove the ._ file. */
2102 if (attrcount
== 0) {
2103 if (fileflags
& O_EXLOCK
)
2104 (void) unlock_xattrfile(xvp
, context
);
2105 VNOP_CLOSE(xvp
, fileflags
, context
);
2107 error
= remove_xattrfile(xvp
, context
);
2110 close_xattrfile(xvp
, fileflags
, context
);
2112 /* Touch the change time if we changed an attribute. */
2114 struct vnode_attr va
;
2116 /* Re-write the mtime to cause a ctime change. */
2118 VATTR_WANTED(&va
, va_modify_time
);
2119 if (vnode_getattr(vp
, &va
, context
) == 0) {
2121 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
2122 (void) vnode_setattr(vp
, &va
, context
);
2126 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
2134 * Retrieve the list of extended attribute names.
2137 default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, __unused
int options
, vfs_context_t context
)
2141 attr_entry_t
*entry
;
2146 * We do not zero "*size" here as we don't want to stomp a size set when
2147 * VNOP_LISTXATTR processed any native EAs. That size is initially zeroed by the
2148 * system call layer, up in listxattr or flistxattr.
2151 if ((error
= open_xattrfile(vp
, FREAD
, &xvp
, context
))) {
2152 if (error
== ENOATTR
)
2156 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
2157 if (error
== ENOATTR
)
2159 close_xattrfile(xvp
, FREAD
, context
);
2163 /* Check for Finder Info. */
2164 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
2166 *size
+= sizeof(XATTR_FINDERINFO_NAME
);
2167 } else if (uio_resid(uio
) < (user_ssize_t
)sizeof(XATTR_FINDERINFO_NAME
)) {
2171 error
= uiomove(XATTR_FINDERINFO_NAME
,
2172 sizeof(XATTR_FINDERINFO_NAME
), uio
);
2180 /* Check for Resource Fork. */
2181 if (vnode_isreg(vp
) && ainfo
.rsrcfork
) {
2183 *size
+= sizeof(XATTR_RESOURCEFORK_NAME
);
2184 } else if (uio_resid(uio
) < (user_ssize_t
)sizeof(XATTR_RESOURCEFORK_NAME
)) {
2188 error
= uiomove(XATTR_RESOURCEFORK_NAME
,
2189 sizeof(XATTR_RESOURCEFORK_NAME
), uio
);
2197 /* Check for attributes. */
2198 if (ainfo
.attrhdr
) {
2199 count
= ainfo
.attrhdr
->num_attrs
;
2200 for (i
= 0, entry
= ainfo
.attr_entry
; i
< count
&& ATTR_VALID(entry
, ainfo
); i
++) {
2201 if (xattr_protected((const char *)entry
->name
) ||
2202 xattr_validatename((const char *)entry
->name
) != 0) {
2203 entry
= ATTR_NEXT(entry
);
2207 *size
+= entry
->namelen
;
2208 entry
= ATTR_NEXT(entry
);
2211 if (uio_resid(uio
) < entry
->namelen
) {
2215 error
= uiomove((caddr_t
) entry
->name
, entry
->namelen
, uio
);
2217 if (error
!= EFAULT
)
2221 entry
= ATTR_NEXT(entry
);
2225 rel_xattrinfo(&ainfo
);
2226 close_xattrfile(xvp
, FREAD
, context
);
2232 * Check the header of a ._ file to verify that it is in fact an Apple Double
2233 * file. Returns 0 if the header is valid, non-zero if invalid.
2235 int check_appledouble_header(vnode_t vp
, vfs_context_t ctx
)
2239 struct vnode_attr va
;
2241 void *buffer
= NULL
;
2245 ainfo
.context
= ctx
;
2247 VATTR_WANTED(&va
, va_data_size
);
2248 if ((error
= vnode_getattr(vp
, &va
, ctx
))) {
2251 ainfo
.filesize
= va
.va_data_size
;
2253 iosize
= MIN(ATTR_MAX_HDR_SIZE
, ainfo
.filesize
);
2258 ainfo
.iosize
= iosize
;
2260 MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
);
2261 if (buffer
== NULL
) {
2266 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2267 uio_addiov(auio
, (uintptr_t)buffer
, iosize
);
2269 /* Read the header */
2270 error
= VNOP_READ(vp
, auio
, 0, ctx
);
2274 ainfo
.rawsize
= iosize
- uio_resid(auio
);
2275 ainfo
.rawdata
= (u_int8_t
*)buffer
;
2277 error
= check_and_swap_apple_double_header(&ainfo
);
2282 /* If we made it here, then the header is ok */
2289 FREE(buffer
, M_TEMP
);
2296 open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
)
2298 vnode_t xvp
= NULLVP
;
2299 vnode_t dvp
= NULLVP
;
2300 struct vnode_attr va
;
2301 struct nameidata nd
;
2303 char *filename
= NULL
;
2304 const char *basename
= NULL
;
2310 if (vnode_isvroot(vp
) && vnode_isdir(vp
)) {
2312 * For the root directory use "._." to hold the attributes.
2314 filename
= &smallname
[0];
2315 snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, ".");
2316 dvp
= vp
; /* the "._." file resides in the root dir */
2319 if ( (dvp
= vnode_getparent(vp
)) == NULLVP
) {
2323 if ( (basename
= vnode_getname(vp
)) == NULL
) {
2328 /* "._" Attribute files cannot have attributes */
2329 if (vp
->v_type
== VREG
&& strlen(basename
) > 2 &&
2330 basename
[0] == '.' && basename
[1] == '_') {
2334 filename
= &smallname
[0];
2335 len
= snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, basename
);
2336 if (len
>= sizeof(smallname
)) {
2337 len
++; /* snprintf result doesn't include '\0' */
2338 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
2339 len
= snprintf(filename
, len
, "%s%s", ATTR_FILE_PREFIX
, basename
);
2342 * Note that the lookup here does not authorize. Since we are looking
2343 * up in the same directory that we already have the file vnode in,
2344 * we must have been given the file vnode legitimately. Read/write
2345 * access has already been authorized in layers above for calls from
2346 * userspace, and the authorization code using this path to read
2347 * file security from the EA must always get access
2350 NDINIT(&nd
, LOOKUP
, LOCKLEAF
| NOFOLLOW
| USEDVP
| DONOTAUTH
, UIO_SYSSPACE
,
2351 CAST_USER_ADDR_T(filename
), context
);
2354 if (fileflags
& O_CREAT
) {
2355 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2357 nd
.ni_cnd
.cn_flags
|= LOCKPARENT
;
2359 if ( (error
= namei(&nd
))) {
2364 if ( (xvp
= nd
.ni_vp
) == NULLVP
) {
2370 * Pick up uid/gid/mode from target file.
2373 VATTR_WANTED(&va
, va_uid
);
2374 VATTR_WANTED(&va
, va_gid
);
2375 VATTR_WANTED(&va
, va_mode
);
2376 if (VNOP_GETATTR(vp
, &va
, context
) == 0 &&
2377 VATTR_IS_SUPPORTED(&va
, va_uid
) &&
2378 VATTR_IS_SUPPORTED(&va
, va_gid
) &&
2379 VATTR_IS_SUPPORTED(&va
, va_mode
)) {
2382 umode
= va
.va_mode
& (S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
);
2383 } else /* fallback values */ {
2384 uid
= KAUTH_UID_NONE
;
2385 gid
= KAUTH_GID_NONE
;
2386 umode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
;
2390 VATTR_SET(&va
, va_type
, VREG
);
2391 VATTR_SET(&va
, va_mode
, umode
);
2392 if (uid
!= KAUTH_UID_NONE
)
2393 VATTR_SET(&va
, va_uid
, uid
);
2394 if (gid
!= KAUTH_GID_NONE
)
2395 VATTR_SET(&va
, va_gid
, gid
);
2397 error
= vn_create(dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
,
2398 VN_CREATE_NOAUTH
| VN_CREATE_NOINHERIT
| VN_CREATE_NOLABEL
,
2407 vnode_put(dvp
); /* drop iocount from LOCKPARENT request above */
2412 if ((error
= namei(&nd
))) {
2422 if (xvp
->v_type
!= VREG
) {
2427 * Owners must match.
2430 VATTR_WANTED(&va
, va_uid
);
2431 if (VNOP_GETATTR(vp
, &va
, context
) == 0 && VATTR_IS_SUPPORTED(&va
, va_uid
)) {
2432 uid_t owner
= va
.va_uid
;
2435 VATTR_WANTED(&va
, va_uid
);
2436 if (VNOP_GETATTR(xvp
, &va
, context
) == 0 && (owner
!= va
.va_uid
)) {
2437 error
= ENOATTR
; /* don't use this "._" file */
2442 if ( (error
= VNOP_OPEN(xvp
, fileflags
& ~(O_EXLOCK
| O_SHLOCK
), context
))) {
2448 if ((error
= vnode_ref(xvp
))) {
2453 /* If create was requested, make sure file header exists. */
2454 if (fileflags
& O_CREAT
) {
2456 VATTR_WANTED(&va
, va_data_size
);
2457 VATTR_WANTED(&va
, va_fileid
);
2458 VATTR_WANTED(&va
, va_nlink
);
2459 if ( (error
= vnode_getattr(xvp
, &va
, context
)) != 0) {
2464 /* If the file is empty then add a default header. */
2465 if (va
.va_data_size
== 0) {
2466 /* Don't adopt hard-linked "._" files. */
2467 if (VATTR_IS_SUPPORTED(&va
, va_nlink
) && va
.va_nlink
> 1) {
2471 if ( (error
= create_xattrfile(xvp
, (u_int32_t
)va
.va_fileid
, context
)))
2475 /* Apply file locking if requested. */
2476 if (fileflags
& (O_EXLOCK
| O_SHLOCK
)) {
2479 locktype
= (fileflags
& O_EXLOCK
) ? F_WRLCK
: F_RDLCK
;
2480 error
= lock_xattrfile(xvp
, locktype
, context
);
2485 if (dvp
&& (dvp
!= vp
)) {
2489 vnode_putname(basename
);
2491 if (filename
&& filename
!= &smallname
[0]) {
2492 FREE(filename
, M_TEMP
);
2495 if (xvp
!= NULLVP
) {
2497 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
2500 (void) vnode_rele(xvp
);
2502 (void) vnode_put(xvp
);
2505 if ((error
== ENOATTR
) && (fileflags
& O_CREAT
)) {
2509 *xvpp
= xvp
; /* return a referenced vnode */
2514 close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
)
2516 // if (fileflags & FWRITE)
2517 // (void) VNOP_FSYNC(xvp, MNT_WAIT, context);
2519 if (fileflags
& (O_EXLOCK
| O_SHLOCK
))
2520 (void) unlock_xattrfile(xvp
, context
);
2522 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
2523 (void) vnode_rele(xvp
);
2524 (void) vnode_put(xvp
);
2528 remove_xattrfile(vnode_t xvp
, vfs_context_t context
)
2531 struct nameidata nd
;
2536 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2540 pathlen
= MAXPATHLEN
;
2541 error
= vn_getpath(xvp
, path
, &pathlen
);
2543 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2547 NDINIT(&nd
, DELETE
, LOCKPARENT
| NOFOLLOW
| DONOTAUTH
,
2548 UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), context
);
2550 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2557 error
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, context
);
2566 * Read in and parse the AppleDouble header and entries, and the extended
2567 * attribute header and entries if any. Populates the fields of ainfop
2568 * based on the headers and entries found.
2570 * The basic idea is to:
2571 * - Read in up to ATTR_MAX_HDR_SIZE bytes of the start of the file. All
2572 * AppleDouble entries, the extended attribute header, and extended
2573 * attribute entries must lie within this part of the file; the rest of
2574 * the AppleDouble handling code assumes this. Plus it allows us to
2575 * somewhat optimize by doing a smaller number of larger I/Os.
2576 * - Swap and sanity check the AppleDouble header (including the AppleDouble
2578 * - Find the Finder Info and Resource Fork entries, if any.
2579 * - If we're going to be writing, try to make sure the Finder Info entry has
2580 * room to store the extended attribute header, plus some space for extended
2582 * - Swap and sanity check the extended attribute header and entries (if any).
2585 get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
)
2588 void * buffer
= NULL
;
2589 apple_double_header_t
*filehdr
;
2590 struct vnode_attr va
;
2595 bzero(ainfop
, sizeof(attr_info_t
));
2596 ainfop
->filevp
= xvp
;
2597 ainfop
->context
= context
;
2599 VATTR_WANTED(&va
, va_data_size
);
2600 VATTR_WANTED(&va
, va_fileid
);
2601 if ((error
= vnode_getattr(xvp
, &va
, context
))) {
2604 ainfop
->filesize
= va
.va_data_size
;
2606 /* When setting attributes, allow room for the header to grow. */
2608 iosize
= ATTR_MAX_HDR_SIZE
;
2610 iosize
= MIN(ATTR_MAX_HDR_SIZE
, ainfop
->filesize
);
2616 ainfop
->iosize
= iosize
;
2617 MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
);
2618 if (buffer
== NULL
){
2623 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2624 uio_addiov(auio
, (uintptr_t)buffer
, iosize
);
2626 /* Read the file header. */
2627 error
= VNOP_READ(xvp
, auio
, 0, context
);
2631 ainfop
->rawsize
= iosize
- uio_resid(auio
);
2632 ainfop
->rawdata
= (u_int8_t
*)buffer
;
2634 filehdr
= (apple_double_header_t
*)buffer
;
2636 error
= check_and_swap_apple_double_header(ainfop
);
2640 ainfop
->filehdr
= filehdr
; /* valid AppleDouble header */
2642 /* rel_xattrinfo is responsible for freeing the header buffer */
2645 /* Find the Finder Info and Resource Fork entries, if any */
2646 for (i
= 0; i
< filehdr
->numEntries
; ++i
) {
2647 if (filehdr
->entries
[i
].type
== AD_FINDERINFO
&&
2648 filehdr
->entries
[i
].length
>= FINDERINFOSIZE
) {
2649 /* We found the Finder Info entry. */
2650 ainfop
->finderinfo
= &filehdr
->entries
[i
];
2653 * Is the Finder Info "empty" (all zeroes)? If so,
2654 * we'll pretend like the Finder Info extended attribute
2657 * Note: we have to make sure the Finder Info is
2658 * contained within the buffer we have already read,
2659 * to avoid accidentally accessing a bogus address.
2660 * If it is outside the buffer, we just assume the
2661 * Finder Info is non-empty.
2663 if (ainfop
->finderinfo
->offset
+ FINDERINFOSIZE
<= ainfop
->rawsize
&&
2664 bcmp((u_int8_t
*)ainfop
->filehdr
+ ainfop
->finderinfo
->offset
, emptyfinfo
, sizeof(emptyfinfo
)) == 0) {
2665 ainfop
->emptyfinderinfo
= 1;
2668 if (filehdr
->entries
[i
].type
== AD_RESOURCE
) {
2670 * Ignore zero-length resource forks when getting. If setting,
2671 * we need to remember the resource fork entry so it can be
2672 * updated once the new content has been written.
2674 if (filehdr
->entries
[i
].length
== 0 && !setting
)
2678 * Check to see if any "empty" resource fork is ours (i.e. is ignorable).
2680 * The "empty" resource headers we created have a system data tag of:
2681 * "This resource fork intentionally left blank "
2683 if (filehdr
->entries
[i
].length
== sizeof(rsrcfork_header_t
) && !setting
) {
2685 u_int8_t systemData
[64];
2689 /* Read the system data which starts at byte 16 */
2690 rf_uio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2691 uio_addiov(rf_uio
, (uintptr_t)systemData
, sizeof(systemData
));
2692 uio_setoffset(rf_uio
, filehdr
->entries
[i
].offset
+ 16);
2693 rf_err
= VNOP_READ(xvp
, rf_uio
, 0, context
);
2697 bcmp(systemData
, RF_EMPTY_TAG
, sizeof(RF_EMPTY_TAG
)) == 0) {
2698 continue; /* skip this resource fork */
2701 ainfop
->rsrcfork
= &filehdr
->entries
[i
];
2702 if (i
!= (filehdr
->numEntries
- 1)) {
2703 printf("get_xattrinfo: resource fork not last entry\n");
2704 ainfop
->readonly
= 1;
2711 * See if this file looks like it is laid out correctly to contain
2712 * extended attributes. If so, then do the following:
2714 * - If we're going to be writing, try to make sure the Finder Info
2715 * entry has room to store the extended attribute header, plus some
2716 * space for extended attributes.
2718 * - Swap and sanity check the extended attribute header and entries
2721 if (filehdr
->numEntries
== 2 &&
2722 ainfop
->finderinfo
== &filehdr
->entries
[0] &&
2723 ainfop
->rsrcfork
== &filehdr
->entries
[1] &&
2724 ainfop
->finderinfo
->offset
== offsetof(apple_double_header_t
, finfo
)) {
2725 attr_header_t
*attrhdr
;
2726 attrhdr
= (attr_header_t
*)filehdr
;
2728 * If we're going to be writing, try to make sure the Finder
2729 * Info entry has room to store the extended attribute header,
2730 * plus some space for extended attributes.
2732 if (setting
&& ainfop
->finderinfo
->length
== FINDERINFOSIZE
) {
2736 delta
= ATTR_BUF_SIZE
- (filehdr
->entries
[0].offset
+ FINDERINFOSIZE
);
2737 if (ainfop
->rsrcfork
&& filehdr
->entries
[1].length
) {
2738 /* Make some room before existing resource fork. */
2739 shift_data_down(xvp
,
2740 filehdr
->entries
[1].offset
,
2741 filehdr
->entries
[1].length
,
2743 writesize
= sizeof(attr_header_t
);
2745 /* Create a new, empty resource fork. */
2746 rsrcfork_header_t
*rsrcforkhdr
;
2748 vnode_setsize(xvp
, filehdr
->entries
[1].offset
+ delta
, 0, context
);
2750 /* Steal some space for an empty RF header. */
2751 delta
-= sizeof(rsrcfork_header_t
);
2753 bzero(&attrhdr
->appledouble
.pad
[0], delta
);
2754 rsrcforkhdr
= (rsrcfork_header_t
*)((char *)filehdr
+ filehdr
->entries
[1].offset
+ delta
);
2756 /* Fill in Empty Resource Fork Header. */
2757 init_empty_resource_fork(rsrcforkhdr
);
2759 filehdr
->entries
[1].length
= sizeof(rsrcfork_header_t
);
2760 writesize
= ATTR_BUF_SIZE
;
2762 filehdr
->entries
[0].length
+= delta
;
2763 filehdr
->entries
[1].offset
+= delta
;
2765 /* Fill in Attribute Header. */
2766 attrhdr
->magic
= ATTR_HDR_MAGIC
;
2767 attrhdr
->debug_tag
= (u_int32_t
)va
.va_fileid
;
2768 attrhdr
->total_size
= filehdr
->entries
[1].offset
;
2769 attrhdr
->data_start
= sizeof(attr_header_t
);
2770 attrhdr
->data_length
= 0;
2771 attrhdr
->reserved
[0] = 0;
2772 attrhdr
->reserved
[1] = 0;
2773 attrhdr
->reserved
[2] = 0;
2775 attrhdr
->num_attrs
= 0;
2777 /* Push out new header */
2778 uio_reset(auio
, 0, UIO_SYSSPACE
, UIO_WRITE
);
2779 uio_addiov(auio
, (uintptr_t)filehdr
, writesize
);
2781 swap_adhdr(filehdr
); /* to big endian */
2782 swap_attrhdr(attrhdr
, ainfop
); /* to big endian */
2783 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
2784 swap_adhdr(filehdr
); /* back to native */
2785 /* The attribute header gets swapped below. */
2789 * Swap and sanity check the extended attribute header and
2790 * entries (if any). The Finder Info content must be big enough
2791 * to include the extended attribute header; if not, we just
2794 * Note that we're passing the offset + length (i.e. the end)
2795 * of the Finder Info instead of rawsize to validate_attrhdr.
2796 * This ensures that all extended attributes lie within the
2797 * Finder Info content according to the AppleDouble entry.
2799 * Sets ainfop->attrhdr and ainfop->attr_entry if a valid
2802 if (ainfop
->finderinfo
&&
2803 ainfop
->finderinfo
== &filehdr
->entries
[0] &&
2804 ainfop
->finderinfo
->length
>= (sizeof(attr_header_t
) - sizeof(apple_double_header_t
))) {
2805 attr_header_t
*attrhdr
= (attr_header_t
*)filehdr
;
2807 if ((error
= check_and_swap_attrhdr(attrhdr
, ainfop
)) == 0) {
2808 ainfop
->attrhdr
= attrhdr
; /* valid attribute header */
2809 /* First attr_entry starts immediately following attribute header */
2810 ainfop
->attr_entry
= (attr_entry_t
*)&attrhdr
[1];
2819 FREE(buffer
, M_TEMP
);
2825 create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
)
2828 rsrcfork_header_t
*rsrcforkhdr
;
2834 MALLOC(buffer
, void *, ATTR_BUF_SIZE
, M_TEMP
, M_WAITOK
);
2835 bzero(buffer
, ATTR_BUF_SIZE
);
2837 xah
= (attr_header_t
*)buffer
;
2838 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_WRITE
);
2839 uio_addiov(auio
, (uintptr_t)buffer
, ATTR_BUF_SIZE
);
2840 rsrcforksize
= sizeof(rsrcfork_header_t
);
2841 rsrcforkhdr
= (rsrcfork_header_t
*) ((char *)buffer
+ ATTR_BUF_SIZE
- rsrcforksize
);
2843 /* Fill in Apple Double Header. */
2844 xah
->appledouble
.magic
= SWAP32 (ADH_MAGIC
);
2845 xah
->appledouble
.version
= SWAP32 (ADH_VERSION
);
2846 xah
->appledouble
.numEntries
= SWAP16 (2);
2847 xah
->appledouble
.entries
[0].type
= SWAP32 (AD_FINDERINFO
);
2848 xah
->appledouble
.entries
[0].offset
= SWAP32 (offsetof(apple_double_header_t
, finfo
));
2849 xah
->appledouble
.entries
[0].length
= SWAP32 (ATTR_BUF_SIZE
- offsetof(apple_double_header_t
, finfo
) - rsrcforksize
);
2850 xah
->appledouble
.entries
[1].type
= SWAP32 (AD_RESOURCE
);
2851 xah
->appledouble
.entries
[1].offset
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
2852 xah
->appledouble
.entries
[1].length
= SWAP32 (rsrcforksize
);
2853 bcopy(ADH_MACOSX
, xah
->appledouble
.filler
, sizeof(xah
->appledouble
.filler
));
2855 /* Fill in Attribute Header. */
2856 xah
->magic
= SWAP32 (ATTR_HDR_MAGIC
);
2857 xah
->debug_tag
= SWAP32 (fileid
);
2858 xah
->total_size
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
2859 xah
->data_start
= SWAP32 (sizeof(attr_header_t
));
2861 /* Fill in Empty Resource Fork Header. */
2862 init_empty_resource_fork(rsrcforkhdr
);
2865 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
2868 FREE(buffer
, M_TEMP
);
2874 init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
)
2876 bzero(rsrcforkhdr
, sizeof(rsrcfork_header_t
));
2877 rsrcforkhdr
->fh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2878 rsrcforkhdr
->fh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2879 rsrcforkhdr
->fh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
2880 rsrcforkhdr
->mh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2881 rsrcforkhdr
->mh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2882 rsrcforkhdr
->mh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
2883 rsrcforkhdr
->mh_Types
= SWAP16 (RF_NULL_MAP_LENGTH
- 2 );
2884 rsrcforkhdr
->mh_Names
= SWAP16 (RF_NULL_MAP_LENGTH
);
2885 rsrcforkhdr
->typeCount
= SWAP16 (-1);
2886 bcopy(RF_EMPTY_TAG
, rsrcforkhdr
->systemData
, sizeof(RF_EMPTY_TAG
));
2890 rel_xattrinfo(attr_info_t
*ainfop
)
2892 FREE(ainfop
->filehdr
, M_TEMP
);
2893 bzero(ainfop
, sizeof(attr_info_t
));
2897 write_xattrinfo(attr_info_t
*ainfop
)
2902 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_WRITE
);
2903 uio_addiov(auio
, (uintptr_t)ainfop
->filehdr
, ainfop
->iosize
);
2905 swap_adhdr(ainfop
->filehdr
);
2906 if (ainfop
->attrhdr
!= NULL
) {
2907 swap_attrhdr(ainfop
->attrhdr
, ainfop
);
2910 error
= VNOP_WRITE(ainfop
->filevp
, auio
, 0, ainfop
->context
);
2912 swap_adhdr(ainfop
->filehdr
);
2913 if (ainfop
->attrhdr
!= NULL
) {
2914 swap_attrhdr(ainfop
->attrhdr
, ainfop
);
2921 #if BYTE_ORDER == LITTLE_ENDIAN
2923 * Endian swap apple double header
2926 swap_adhdr(apple_double_header_t
*adh
)
2931 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2933 adh
->magic
= SWAP32 (adh
->magic
);
2934 adh
->version
= SWAP32 (adh
->version
);
2935 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2937 for (i
= 0; i
< count
; i
++) {
2938 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2939 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2940 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2945 * Endian swap extended attributes header
2948 swap_attrhdr(attr_header_t
*ah
, attr_info_t
* info
)
2954 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2956 ah
->magic
= SWAP32 (ah
->magic
);
2957 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2958 ah
->total_size
= SWAP32 (ah
->total_size
);
2959 ah
->data_start
= SWAP32 (ah
->data_start
);
2960 ah
->data_length
= SWAP32 (ah
->data_length
);
2961 ah
->flags
= SWAP16 (ah
->flags
);
2962 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2964 ae
= (attr_entry_t
*)(&ah
[1]);
2965 for (i
= 0; i
< count
&& ATTR_VALID(ae
, *info
); i
++, ae
= ATTR_NEXT(ae
)) {
2966 ae
->offset
= SWAP32 (ae
->offset
);
2967 ae
->length
= SWAP32 (ae
->length
);
2968 ae
->flags
= SWAP16 (ae
->flags
);
2974 * Validate and swap the attributes header contents, and each attribute's
2977 * Note: Assumes the caller has verified that the Finder Info content is large
2978 * enough to contain the attr_header structure itself. Therefore, we can
2979 * swap the header fields before sanity checking them.
2982 check_and_swap_attrhdr(attr_header_t
*ah
, attr_info_t
*ainfop
)
2993 if (SWAP32(ah
->magic
) != ATTR_HDR_MAGIC
)
2996 /* Swap the basic header fields */
2997 ah
->magic
= SWAP32(ah
->magic
);
2998 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2999 ah
->total_size
= SWAP32 (ah
->total_size
);
3000 ah
->data_start
= SWAP32 (ah
->data_start
);
3001 ah
->data_length
= SWAP32 (ah
->data_length
);
3002 ah
->flags
= SWAP16 (ah
->flags
);
3003 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3006 * Make sure the total_size fits within the Finder Info area, and the
3007 * extended attribute data area fits within total_size.
3009 end
= ah
->data_start
+ ah
->data_length
;
3010 if (ah
->total_size
> ainfop
->finderinfo
->offset
+ ainfop
->finderinfo
->length
||
3011 end
< ah
->data_start
||
3012 end
> ah
->total_size
) {
3017 * Make sure each of the attr_entry_t's fits within total_size.
3019 buf_end
= ainfop
->rawdata
+ ah
->total_size
;
3020 count
= ah
->num_attrs
;
3021 ae
= (attr_entry_t
*)(&ah
[1]);
3023 for (i
=0; i
<count
; i
++) {
3024 /* Make sure the fixed-size part of this attr_entry_t fits. */
3025 if ((u_int8_t
*) &ae
[1] > buf_end
)
3028 /* Make sure the variable-length name fits (+1 is for NUL terminator) */
3029 /* TODO: Make sure namelen matches strnlen(name,namelen+1)? */
3030 if (&ae
->name
[ae
->namelen
+1] > buf_end
)
3033 /* Swap the attribute entry fields */
3034 ae
->offset
= SWAP32(ae
->offset
);
3035 ae
->length
= SWAP32(ae
->length
);
3036 ae
->flags
= SWAP16(ae
->flags
);
3038 /* Make sure the attribute content fits. */
3039 end
= ae
->offset
+ ae
->length
;
3040 if (end
< ae
->offset
|| end
> ah
->total_size
)
3047 * TODO: Make sure the contents of attributes don't overlap the header
3048 * and don't overlap each other. The hard part is that we don't know
3049 * what the actual header size is until we have looped over all of the
3050 * variable-sized attribute entries.
3052 * XXX Is there any guarantee that attribute entries are stored in
3053 * XXX order sorted by the contents' file offset? If so, that would
3054 * XXX make the pairwise overlap check much easier.
3061 // "start" & "end" are byte offsets in the file.
3062 // "to" is the byte offset we want to move the
3063 // data to. "to" should be > "start".
3065 // we do the copy backwards to avoid problems if
3066 // there's an overlap.
3069 shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
3072 size_t chunk
, orig_chunk
;
3075 kauth_cred_t ucred
= vfs_context_ucred(context
);
3076 proc_t p
= vfs_context_proc(context
);
3078 if (delta
== 0 || len
== 0) {
3088 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
3092 for(pos
=start
+len
-chunk
; pos
>= start
; pos
-=chunk
) {
3093 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3095 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
3096 pos
, ret
, chunk
, ret
);
3100 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
+ delta
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3102 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
3103 pos
+delta
, ret
, chunk
, ret
);
3107 if ((pos
- (off_t
)chunk
) < start
) {
3108 chunk
= pos
- start
;
3110 if (chunk
== 0) { // we're all done
3115 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
3122 shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
3125 size_t chunk
, orig_chunk
;
3129 kauth_cred_t ucred
= vfs_context_ucred(context
);
3130 proc_t p
= vfs_context_proc(context
);
3132 if (delta
== 0 || len
== 0) {
3143 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
3147 for(pos
= start
; pos
< end
; pos
+= chunk
) {
3148 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3150 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
3151 pos
, ret
, chunk
, ret
);
3155 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
- delta
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3157 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
3158 pos
+delta
, ret
, chunk
, ret
);
3162 if ((pos
+ (off_t
)chunk
) > end
) {
3165 if (chunk
== 0) { // we're all done
3170 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
3176 lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
)
3181 lf
.l_whence
= SEEK_SET
;
3184 lf
.l_type
= locktype
; /* F_WRLCK or F_RDLCK */
3185 /* Note: id is just a kernel address that's not a proc */
3186 error
= VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_SETLK
, &lf
, F_FLOCK
|F_WAIT
, context
);
3187 return (error
== ENOTSUP
? 0 : error
);
3191 unlock_xattrfile(vnode_t xvp
, vfs_context_t context
)
3196 lf
.l_whence
= SEEK_SET
;
3199 lf
.l_type
= F_UNLCK
;
3200 /* Note: id is just a kernel address that's not a proc */
3201 error
= VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_UNLCK
, &lf
, F_FLOCK
, context
);
3202 return (error
== ENOTSUP
? 0 : error
);