2 * Copyright (c) 2004-2010 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 int shadow_sequence
;
71 static int default_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, vfs_context_t context
);
73 static int default_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, vfs_context_t context
);
75 static int default_removenamedstream(vnode_t vp
, const char *name
, vfs_context_t context
);
77 static int getshadowfile(vnode_t vp
, vnode_t
*svpp
, int makestream
, size_t *rsrcsize
, int *creator
, vfs_context_t context
);
79 static int get_shadow_dir(vnode_t
*sdvpp
, vfs_context_t context
);
85 * Default xattr support routines.
88 static int default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
,
89 vfs_context_t context
);
94 * Retrieve the data of an extended attribute.
97 vn_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
98 int options
, vfs_context_t context
)
102 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
106 /* getxattr calls are not allowed for streams. */
107 if (vp
->v_flag
& VISNAMEDSTREAM
) {
113 * Non-kernel request need extra checks performed.
115 * The XATTR_NOSECURITY flag implies a kernel request.
117 if (!(options
& XATTR_NOSECURITY
)) {
119 error
= mac_vnode_check_getextattr(context
, vp
, name
, uio
);
123 if ((error
= xattr_validatename(name
))) {
126 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
))) {
129 /* The offset can only be non-zero for resource forks. */
130 if (uio
!= NULL
&& uio_offset(uio
) != 0 &&
131 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
137 /* The offset can only be non-zero for resource forks. */
138 if (uio
!= NULL
&& uio_offset(uio
) != 0 &&
139 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
144 error
= VNOP_GETXATTR(vp
, name
, uio
, size
, options
, context
);
145 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
147 * A filesystem may keep some EAs natively and return ENOTSUP for others.
148 * SMB returns ENOTSUP for finderinfo and resource forks.
150 error
= default_getxattr(vp
, name
, uio
, size
, options
, context
);
157 * Set the data of an extended attribute.
160 vn_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
164 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
168 /* setxattr calls are not allowed for streams. */
169 if (vp
->v_flag
& VISNAMEDSTREAM
) {
174 if ((options
& (XATTR_REPLACE
|XATTR_CREATE
)) == (XATTR_REPLACE
|XATTR_CREATE
)) {
177 if ((error
= xattr_validatename(name
))) {
180 if (!(options
& XATTR_NOSECURITY
)) {
182 error
= mac_vnode_check_setextattr(context
, vp
, name
, uio
);
186 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
);
190 /* The offset can only be non-zero for resource forks. */
191 if (uio_offset(uio
) != 0 &&
192 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0 ) {
197 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
200 * An EJUSTRETURN is from a filesystem which keeps this xattr
201 * natively as well as in a dot-underscore file. In this case the
202 * EJUSTRETURN means the filesytem has done nothing, but identifies the
203 * EA as one which may be represented natively and/or in a DU, and
204 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
205 * in vn_setxattr can we do the getxattrs needed to ascertain whether
206 * the XATTR_{CREATE,REPLACE} should yield an error.
208 if (error
== EJUSTRETURN
) {
209 int native
= 0, dufile
= 0;
210 size_t sz
; /* not used */
212 native
= VNOP_GETXATTR(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
213 dufile
= default_getxattr(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
214 if (options
& XATTR_CREATE
&& (native
|| dufile
)) {
218 if (options
& XATTR_REPLACE
&& !(native
|| dufile
)) {
223 * Having determined no CREATE/REPLACE error should result, we
224 * zero those bits, so both backing stores get written to.
226 options
&= ~(XATTR_CREATE
| XATTR_REPLACE
);
227 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
228 /* the mainline path here is to have error==ENOTSUP ... */
230 #endif /* DUAL_EAS */
231 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
233 * A filesystem may keep some EAs natively and return ENOTSUP for others.
234 * SMB returns ENOTSUP for finderinfo and resource forks.
236 error
= default_setxattr(vp
, name
, uio
, options
, context
);
239 if ((error
== 0) && !(options
& XATTR_NOSECURITY
) &&
240 (vfs_flags(vnode_mount(vp
)) & MNT_MULTILABEL
))
241 mac_vnode_label_update_extattr(vnode_mount(vp
), vp
, name
);
248 * Remove an extended attribute.
251 vn_removexattr(vnode_t vp
, const char * name
, int options
, vfs_context_t context
)
255 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
259 /* removexattr calls are not allowed for streams. */
260 if (vp
->v_flag
& VISNAMEDSTREAM
) {
265 if ((error
= xattr_validatename(name
))) {
268 if (!(options
& XATTR_NOSECURITY
)) {
270 error
= mac_vnode_check_deleteextattr(context
, vp
, name
);
274 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
);
278 error
= VNOP_REMOVEXATTR(vp
, name
, options
, context
);
279 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
281 * A filesystem may keep some EAs natively and return ENOTSUP for others.
282 * SMB returns ENOTSUP for finderinfo and resource forks.
284 error
= default_removexattr(vp
, name
, options
, context
);
286 } else if (error
== EJUSTRETURN
) {
288 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
289 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
290 * a native xattr, so failure to find it in a DU file during
291 * default_removexattr should not be considered an error.
293 error
= default_removexattr(vp
, name
, options
, context
);
294 if (error
== ENOATTR
)
296 #endif /* DUAL_EAS */
299 if ((error
== 0) && !(options
& XATTR_NOSECURITY
) &&
300 (vfs_flags(vnode_mount(vp
)) & MNT_MULTILABEL
))
301 mac_vnode_label_update_extattr(vnode_mount(vp
), vp
, name
);
308 * Retrieve the list of extended attribute names.
311 vn_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
)
315 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
319 /* listxattr calls are not allowed for streams. */
320 if (vp
->v_flag
& VISNAMEDSTREAM
) {
325 if (!(options
& XATTR_NOSECURITY
)) {
327 error
= mac_vnode_check_listextattr(context
, vp
);
332 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
);
337 error
= VNOP_LISTXATTR(vp
, uio
, size
, options
, context
);
338 if (error
== ENOTSUP
&& !(options
& XATTR_NODEFAULT
)) {
340 * A filesystem may keep some but not all EAs natively, in which case
341 * the native EA names will have been uiomove-d out (or *size updated)
342 * and the default_listxattr here will finish the job. Note SMB takes
343 * advantage of this for its finder-info and resource forks.
345 error
= default_listxattr(vp
, uio
, size
, options
, context
);
352 xattr_validatename(const char *name
)
356 if (name
== NULL
|| name
[0] == '\0') {
359 namelen
= strnlen(name
, XATTR_MAXNAMELEN
);
360 if (name
[namelen
] != '\0')
361 return (ENAMETOOLONG
);
363 if (utf8_validatestr((const unsigned char *)name
, namelen
) != 0)
371 * Determine whether an EA is a protected system attribute.
374 xattr_protected(const char *attrname
)
376 return(!strncmp(attrname
, "com.apple.system.", 17));
382 * Obtain a named stream from vnode vp.
385 vnode_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, int flags
, vfs_context_t context
)
389 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
390 error
= VNOP_GETNAMEDSTREAM(vp
, svpp
, name
, op
, flags
, context
);
392 error
= default_getnamedstream(vp
, svpp
, name
, op
, context
);
395 uint32_t streamflags
= VISNAMEDSTREAM
;
398 if ((vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0) {
399 streamflags
|= VISSHADOW
;
403 vnode_lock_spin(svp
);
404 svp
->v_flag
|= streamflags
;
407 /* Tag the parent so we know to flush credentials for streams on setattr */
409 vp
->v_lflag
|= VL_HASSTREAMS
;
412 /* Make the file it's parent.
413 * Note: This parent link helps us distinguish vnodes for
414 * shadow stream files from vnodes for resource fork on file
415 * systems that support namedstream natively (both have
416 * VISNAMEDSTREAM set) by allowing access to mount structure
417 * for checking MNTK_NAMED_STREAMS bit at many places in the
420 vnode_update_identity(svp
, vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
427 * Make a named stream for vnode vp.
430 vnode_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, int flags
, vfs_context_t context
)
434 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
435 error
= VNOP_MAKENAMEDSTREAM(vp
, svpp
, name
, flags
, context
);
437 error
= default_makenamedstream(vp
, svpp
, name
, context
);
440 uint32_t streamflags
= VISNAMEDSTREAM
;
444 if ((vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0) {
445 streamflags
|= VISSHADOW
;
449 vnode_lock_spin(svp
);
450 svp
->v_flag
|= streamflags
;
453 /* Tag the parent so we know to flush credentials for streams on setattr */
455 vp
->v_lflag
|= VL_HASSTREAMS
;
458 /* Make the file it's parent.
459 * Note: This parent link helps us distinguish vnodes for
460 * shadow stream files from vnodes for resource fork on file
461 * systems that support namedstream natively (both have
462 * VISNAMEDSTREAM set) by allowing access to mount structure
463 * for checking MNTK_NAMED_STREAMS bit at many places in the
466 vnode_update_identity(svp
, vp
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
472 * Remove a named stream from vnode vp.
475 vnode_removenamedstream(vnode_t vp
, vnode_t svp
, const char *name
, int flags
, vfs_context_t context
)
479 if (vp
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)
480 error
= VNOP_REMOVENAMEDSTREAM(vp
, svp
, name
, flags
, context
);
482 error
= default_removenamedstream(vp
, name
, context
);
487 #define NS_IOBUFSIZE (128 * 1024)
490 * Release a named stream shadow file.
492 * Note: This function is called from two places where we do not need
493 * to check if the vnode has any references held before deleting the
494 * shadow file. Once from vclean() when the vnode is being reclaimed
495 * and we do not hold any references on the vnode. Second time from
496 * default_getnamedstream() when we get an error during shadow stream
497 * file initialization so that other processes who are waiting for the
498 * shadow stream file initialization by the creator will get opportunity
499 * to create and initialize the file again.
502 vnode_relenamedstream(vnode_t vp
, vnode_t svp
, vfs_context_t context
)
505 struct componentname cn
;
512 MAKE_SHADOW_NAME(vp
, tmpname
);
515 cn
.cn_nameiop
= DELETE
;
516 cn
.cn_flags
= ISLASTCN
;
517 cn
.cn_context
= context
;
518 cn
.cn_pnbuf
= tmpname
;
519 cn
.cn_pnlen
= sizeof(tmpname
);
520 cn
.cn_nameptr
= cn
.cn_pnbuf
;
521 cn
.cn_namelen
= strlen(tmpname
);
523 /* Obtain the vnode for the shadow files directory. */
524 err
= get_shadow_dir(&dvp
, context
);
529 (void) VNOP_REMOVE(dvp
, svp
, &cn
, 0, context
);
536 * Flush a named stream shadow file.
539 vnode_flushnamedstream(vnode_t vp
, vnode_t svp
, vfs_context_t context
)
541 struct vnode_attr va
;
543 caddr_t bufptr
= NULL
;
551 VATTR_WANTED(&va
, va_data_size
);
552 if (VNOP_GETATTR(svp
, &va
, context
) != 0 ||
553 !VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
556 datasize
= va
.va_data_size
;
558 (void) default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
562 iosize
= bufsize
= MIN(datasize
, NS_IOBUFSIZE
);
563 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&bufptr
, bufsize
)) {
566 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
570 * Copy the shadow stream file data into the resource fork.
572 error
= VNOP_OPEN(svp
, 0, context
);
574 printf("vnode_flushnamedstream: err %d opening file\n", error
);
577 while (offset
< datasize
) {
578 iosize
= MIN(datasize
- offset
, iosize
);
580 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_READ
);
581 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
582 error
= VNOP_READ(svp
, auio
, 0, context
);
586 /* Since there's no truncate xattr we must remove the resource fork. */
588 error
= default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
589 if ((error
!= 0) && (error
!= ENOATTR
)) {
593 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_WRITE
);
594 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
595 error
= vn_setxattr(vp
, XATTR_RESOURCEFORK_NAME
, auio
, XATTR_NOSECURITY
, context
);
601 (void) VNOP_CLOSE(svp
, 0, context
);
604 kmem_free(kernel_map
, (vm_offset_t
)bufptr
, bufsize
);
614 getshadowfile(vnode_t vp
, vnode_t
*svpp
, int makestream
, size_t *rsrcsize
,
615 int *creator
, vfs_context_t context
)
617 vnode_t dvp
= NULLVP
;
618 vnode_t svp
= NULLVP
;
619 struct componentname cn
;
620 struct vnode_attr va
;
628 /* Establish a unique file name. */
629 MAKE_SHADOW_NAME(vp
, tmpname
);
630 bzero(&cn
, sizeof(cn
));
631 cn
.cn_nameiop
= LOOKUP
;
632 cn
.cn_flags
= ISLASTCN
;
633 cn
.cn_context
= context
;
634 cn
.cn_pnbuf
= tmpname
;
635 cn
.cn_pnlen
= sizeof(tmpname
);
636 cn
.cn_nameptr
= cn
.cn_pnbuf
;
637 cn
.cn_namelen
= strlen(tmpname
);
639 /* Pick up uid, gid, mode and date from original file. */
641 VATTR_WANTED(&va
, va_uid
);
642 VATTR_WANTED(&va
, va_gid
);
643 VATTR_WANTED(&va
, va_mode
);
644 VATTR_WANTED(&va
, va_create_time
);
645 VATTR_WANTED(&va
, va_modify_time
);
646 if (VNOP_GETATTR(vp
, &va
, context
) != 0 ||
647 !VATTR_IS_SUPPORTED(&va
, va_uid
) ||
648 !VATTR_IS_SUPPORTED(&va
, va_gid
) ||
649 !VATTR_IS_SUPPORTED(&va
, va_mode
)) {
650 va
.va_uid
= KAUTH_UID_NONE
;
651 va
.va_gid
= KAUTH_GID_NONE
;
652 va
.va_mode
= S_IRUSR
| S_IWUSR
;
654 va
.va_vaflags
= VA_EXCLUSIVE
;
655 VATTR_SET(&va
, va_type
, VREG
);
656 /* We no longer change the access, but we still hide it. */
657 VATTR_SET(&va
, va_flags
, UF_HIDDEN
);
659 /* Obtain the vnode for the shadow files directory. */
660 if (get_shadow_dir(&dvp
, context
) != 0) {
665 /* See if someone else already has it open. */
666 if (VNOP_LOOKUP(dvp
, &svp
, &cn
, context
) == 0) {
667 /* Double check existence by asking for size. */
669 VATTR_WANTED(&va
, va_data_size
);
670 if (VNOP_GETATTR(svp
, &va
, context
) == 0 &&
671 VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
672 goto out
; /* OK to use. */
676 /* Otherwise make sure the resource fork data exists. */
677 error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &datasize
,
678 XATTR_NOSECURITY
, context
);
680 * To maintain binary compatibility with legacy Carbon
681 * emulated resource fork support, if the resource fork
682 * doesn't exist but the Finder Info does, then act as
683 * if an empty resource fork is present (see 4724359).
685 if ((error
== ENOATTR
) &&
686 (vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, NULL
, &datasize
,
687 XATTR_NOSECURITY
, context
) == 0)) {
695 /* If the resource fork exists, its size is expected to be non-zero. */
702 /* Create the shadow stream file. */
703 error
= VNOP_CREATE(dvp
, &svp
, &cn
, &va
, context
);
708 else if ((error
== EEXIST
) && !makestream
) {
709 error
= VNOP_LOOKUP(dvp
, &svp
, &cn
, context
);
711 else if ((error
== ENOENT
) && !makestream
) {
713 * We could have raced with a rmdir on the shadow directory
714 * post-lookup. Retry from the beginning, 1x only, to
715 * try and see if we need to re-create the shadow directory
730 /* Otherwise, just error out normally below */
738 /* On errors, clean up shadow stream file. */
746 *rsrcsize
= datasize
;
753 default_getnamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation op
, vfs_context_t context
)
755 vnode_t svp
= NULLVP
;
757 caddr_t bufptr
= NULL
;
764 * Only the "com.apple.ResourceFork" stream is supported here.
766 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
772 * Obtain a shadow file for the resource fork I/O.
774 error
= getshadowfile(vp
, &svp
, 0, &datasize
, &creator
, context
);
781 * The creator of the shadow file provides its file data,
782 * all other threads should wait until its ready. In order to
783 * prevent a deadlock during error codepaths, we need to check if the
784 * vnode is being created, or if it has failed out. Regardless of success or
785 * failure, we set the VISSHADOW bit on the vnode, so we check that
786 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't,
787 * then we can infer the creator isn't done yet. If it's there, but
788 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
793 if (svp
->v_flag
& VISNAMEDSTREAM
) {
794 /* data is ready, go use it */
798 /* It's not ready, wait for it (sleep using v_parent as channel) */
799 if ((svp
->v_flag
& VISSHADOW
)) {
801 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
802 * thread is done with this vnode. Just unlock the vnode and try again
807 /* Otherwise, sleep if the shadow file is not created yet */
808 msleep((caddr_t
)&svp
->v_parent
, &svp
->v_lock
, PINOD
| PDROP
,
809 "getnamedstream", NULL
);
818 * Copy the real resource fork data into shadow stream file.
820 if (op
== NS_OPEN
&& datasize
!= 0) {
824 iosize
= bufsize
= MIN(datasize
, NS_IOBUFSIZE
);
825 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&bufptr
, bufsize
)) {
830 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
833 error
= VNOP_OPEN(svp
, 0, context
);
837 while (offset
< datasize
) {
840 iosize
= MIN(datasize
- offset
, iosize
);
842 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_READ
);
843 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
844 error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, auio
, &tmpsize
,
845 XATTR_NOSECURITY
, context
);
850 uio_reset(auio
, offset
, UIO_SYSSPACE
, UIO_WRITE
);
851 uio_addiov(auio
, (uintptr_t)bufptr
, iosize
);
852 error
= VNOP_WRITE(svp
, auio
, 0, context
);
858 (void) VNOP_CLOSE(svp
, 0, context
);
861 /* Wake up anyone waiting for svp file content */
865 /* VISSHADOW would be set later on anyway, so we set it now */
866 svp
->v_flag
|= (VISNAMEDSTREAM
| VISSHADOW
);
867 wakeup((caddr_t
)&svp
->v_parent
);
870 /* On post create errors, get rid of the shadow file. This
871 * way if there is another process waiting for initialization
872 * of the shadowfile by the current process will wake up and
873 * retry by creating and initializing the shadow file again.
874 * Also add the VISSHADOW bit here to indicate we're done operating
877 (void)vnode_relenamedstream(vp
, svp
, context
);
879 svp
->v_flag
|= VISSHADOW
;
880 wakeup((caddr_t
)&svp
->v_parent
);
886 kmem_free(kernel_map
, (vm_offset_t
)bufptr
, bufsize
);
892 /* On errors, clean up shadow stream file. */
903 default_makenamedstream(vnode_t vp
, vnode_t
*svpp
, const char *name
, vfs_context_t context
)
909 * Only the "com.apple.ResourceFork" stream is supported here.
911 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
915 error
= getshadowfile(vp
, svpp
, 1, NULL
, &creator
, context
);
918 * Wake up any waiters over in default_getnamedstream().
920 if ((error
== 0) && (*svpp
!= NULL
) && creator
) {
924 /* If we're the creator, mark it as a named stream */
925 svp
->v_flag
|= (VISNAMEDSTREAM
| VISSHADOW
);
926 /* Wakeup any waiters on the v_parent channel */
927 wakeup((caddr_t
)&svp
->v_parent
);
936 default_removenamedstream(vnode_t vp
, const char *name
, vfs_context_t context
)
939 * Only the "com.apple.ResourceFork" stream is supported here.
941 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
945 * XXX - what about other opened instances?
947 return default_removexattr(vp
, XATTR_RESOURCEFORK_NAME
, 0, context
);
951 get_shadow_dir(vnode_t
*sdvpp
, vfs_context_t context
)
953 vnode_t dvp
= NULLVP
;
954 vnode_t sdvp
= NULLVP
;
955 struct componentname cn
;
956 struct vnode_attr va
;
962 bzero(tmpname
, sizeof(tmpname
));
963 snprintf(tmpname
, sizeof(tmpname
), "/var/run/.vfs_rsrc_streams_%p%x",
964 (void*)rootvnode
, shadow_sequence
);
966 * Look up the shadow directory to ensure that it still exists.
967 * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues
968 * in caching it when multiple threads may be trying to manipulate the pointers.
970 error
= vnode_lookup(tmpname
, 0, &sdvp
, context
);
973 * If we get here, then we have successfully looked up the shadow dir,
974 * and it has an iocount from the lookup. Return the vp in the output argument.
979 /* In the failure case, no iocount is acquired */
981 bzero (tmpname
, sizeof(tmpname
));
983 /* Obtain the vnode for "/var/run" directory. */
984 if (vnode_lookup("/var/run", 0, &dvp
, context
) != 0) {
989 /* Create the shadow stream directory. */
990 snprintf(tmpname
, sizeof(tmpname
), ".vfs_rsrc_streams_%p%x",
991 (void*)rootvnode
, shadow_sequence
);
992 bzero(&cn
, sizeof(cn
));
993 cn
.cn_nameiop
= LOOKUP
;
994 cn
.cn_flags
= ISLASTCN
;
995 cn
.cn_context
= context
;
996 cn
.cn_pnbuf
= tmpname
;
997 cn
.cn_pnlen
= sizeof(tmpname
);
998 cn
.cn_nameptr
= cn
.cn_pnbuf
;
999 cn
.cn_namelen
= strlen(tmpname
);
1002 * owned by root, only readable by root, hidden
1005 VATTR_SET(&va
, va_uid
, 0);
1006 VATTR_SET(&va
, va_gid
, 0);
1007 VATTR_SET(&va
, va_mode
, S_IRUSR
| S_IXUSR
);
1008 VATTR_SET(&va
, va_type
, VDIR
);
1009 VATTR_SET(&va
, va_flags
, UF_HIDDEN
);
1010 va
.va_vaflags
= VA_EXCLUSIVE
;
1012 error
= VNOP_MKDIR(dvp
, &sdvp
, &cn
, &va
, context
);
1015 * There can be only one winner for an exclusive create.
1017 if (error
== EEXIST
) {
1018 /* loser has to look up directory */
1019 error
= VNOP_LOOKUP(dvp
, &sdvp
, &cn
, context
);
1021 /* Make sure its in fact a directory */
1022 if (sdvp
->v_type
!= VDIR
) {
1025 /* Obtain the fsid for /tmp directory */
1027 VATTR_WANTED(&va
, va_fsid
);
1028 if (VNOP_GETATTR(dvp
, &va
, context
) != 0 ||
1029 !VATTR_IS_SUPPORTED(&va
, va_fsid
)) {
1032 tmp_fsid
= va
.va_fsid
;
1035 VATTR_WANTED(&va
, va_uid
);
1036 VATTR_WANTED(&va
, va_gid
);
1037 VATTR_WANTED(&va
, va_mode
);
1038 VATTR_WANTED(&va
, va_fsid
);
1039 VATTR_WANTED(&va
, va_dirlinkcount
);
1040 VATTR_WANTED(&va
, va_acl
);
1041 /* Provide defaults for attrs that may not be supported */
1042 va
.va_dirlinkcount
= 1;
1043 va
.va_acl
= (kauth_acl_t
) KAUTH_FILESEC_NONE
;
1045 if (VNOP_GETATTR(sdvp
, &va
, context
) != 0 ||
1046 !VATTR_IS_SUPPORTED(&va
, va_uid
) ||
1047 !VATTR_IS_SUPPORTED(&va
, va_gid
) ||
1048 !VATTR_IS_SUPPORTED(&va
, va_mode
) ||
1049 !VATTR_IS_SUPPORTED(&va
, va_fsid
)) {
1053 * Make sure its what we want:
1055 * - not writable by anyone
1056 * - on same file system as /tmp
1057 * - not a hard-linked directory
1058 * - no ACLs (they might grant write access)
1060 if ((va
.va_uid
!= 0) || (va
.va_gid
!= 0) ||
1061 (va
.va_mode
& (S_IWUSR
| S_IRWXG
| S_IRWXO
)) ||
1062 (va
.va_fsid
!= tmp_fsid
) ||
1063 (va
.va_dirlinkcount
!= 1) ||
1064 (va
.va_acl
!= (kauth_acl_t
) KAUTH_FILESEC_NONE
)) {
1074 /* On errors, clean up shadow stream directory. */
1084 /* This is not the dir we're looking for, move along */
1085 ++shadow_sequence
; /* try something else next time */
1094 * Default Implementation (Non-native EA)
1099 Typical "._" AppleDouble Header File layout:
1100 ------------------------------------------------------------
1105 .-- AD ENTRY[0] Finder Info Entry (must be first)
1106 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1108 | ///////////// Fixed Size Data (32 bytes)
1112 | ATTR ENTRY[1] --+--.
1113 | ATTR ENTRY[2] --+--+--.
1115 | ATTR ENTRY[N] --+--+--+--.
1116 | ATTR DATA 0 <-' | | |
1117 | //////////// | | |
1118 | ATTR DATA 1 <----' | |
1120 | ATTR DATA 2 <-------' |
1123 | ATTR DATA N <----------'
1125 | Attribute Free Space
1127 '----> RESOURCE FORK
1128 ///////////// Variable Sized Data
1137 ------------------------------------------------------------
1139 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1140 stored as part of the Finder Info. The length in the Finder
1141 Info AppleDouble entry includes the length of the extended
1142 attribute header, attribute entries, and attribute data.
1147 * On Disk Data Structures
1149 * Note: Motorola 68K alignment and big-endian.
1151 * See RFC 1740 for additional information about the AppleDouble file format.
1155 #define ADH_MAGIC 0x00051607
1156 #define ADH_VERSION 0x00020000
1157 #define ADH_MACOSX "Mac OS X "
1160 * AppleDouble Entry ID's
1162 #define AD_DATA 1 /* Data fork */
1163 #define AD_RESOURCE 2 /* Resource fork */
1164 #define AD_REALNAME 3 /* FileÕs name on home file system */
1165 #define AD_COMMENT 4 /* Standard Mac comment */
1166 #define AD_ICONBW 5 /* Mac black & white icon */
1167 #define AD_ICONCOLOR 6 /* Mac color icon */
1168 #define AD_UNUSED 7 /* Not used */
1169 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
1170 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
1171 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
1172 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
1173 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
1174 #define AD_AFPNAME 13 /* Short name on AFP server */
1175 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
1176 #define AD_AFPDIRID 15 /* AFP directory ID */
1177 #define AD_ATTRIBUTES AD_FINDERINFO
1180 #define ATTR_FILE_PREFIX "._"
1181 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
1183 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
1185 /* Implementation Limits */
1186 #define ATTR_MAX_SIZE AD_XATTR_MAXSIZE
1187 #define ATTR_MAX_HDR_SIZE 65536
1189 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
1190 * size supported (including the attribute entries). All of
1191 * the attribute entries must reside within this limit. If
1192 * any of the attribute data crosses the ATTR_MAX_HDR_SIZE
1193 * boundry, then all of the attribute data I/O is performed
1194 * separately from the attribute header I/O.
1196 * In particular, all of the attr_entry structures must lie
1197 * completely within the first ATTR_MAX_HDR_SIZE bytes of the
1198 * AppleDouble file. However, the attribute data (i.e. the
1199 * contents of the extended attributes) may extend beyond the
1200 * first ATTR_MAX_HDR_SIZE bytes of the file. Note that this
1201 * limit is to allow the implementation to optimize by reading
1202 * the first ATTR_MAX_HDR_SIZE bytes of the file.
1206 #define FINDERINFOSIZE 32
1208 typedef struct apple_double_entry
{
1209 u_int32_t type
; /* entry type: see list, 0 invalid */
1210 u_int32_t offset
; /* entry data offset from the beginning of the file. */
1211 u_int32_t length
; /* entry data length in bytes. */
1212 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
1215 typedef struct apple_double_header
{
1216 u_int32_t magic
; /* == ADH_MAGIC */
1217 u_int32_t version
; /* format version: 2 = 0x00020000 */
1218 u_int32_t filler
[4];
1219 u_int16_t numEntries
; /* number of entries which follow */
1220 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
1221 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
1222 u_int8_t pad
[2]; /* get better alignment inside attr_header */
1223 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
1225 #define ADHDRSIZE (4+4+16+2)
1227 /* Entries are aligned on 4 byte boundaries */
1228 typedef struct attr_entry
{
1229 u_int32_t offset
; /* file offset to data */
1230 u_int32_t length
; /* size of attribute data */
1233 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
1234 } __attribute__((aligned(2), packed
)) attr_entry_t
;
1237 /* Header + entries must fit into 64K. Data may extend beyond 64K. */
1238 typedef struct attr_header
{
1239 apple_double_header_t appledouble
;
1240 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
1241 u_int32_t debug_tag
; /* for debugging == file id of owning file */
1242 u_int32_t total_size
; /* file offset of end of attribute header + entries + data */
1243 u_int32_t data_start
; /* file offset to attribute data area */
1244 u_int32_t data_length
; /* length of attribute data area */
1245 u_int32_t reserved
[3];
1247 u_int16_t num_attrs
;
1248 } __attribute__((aligned(2), packed
)) attr_header_t
;
1251 /* Empty Resource Fork Header */
1252 typedef struct rsrcfork_header
{
1253 u_int32_t fh_DataOffset
;
1254 u_int32_t fh_MapOffset
;
1255 u_int32_t fh_DataLength
;
1256 u_int32_t fh_MapLength
;
1257 u_int8_t systemData
[112];
1258 u_int8_t appData
[128];
1259 u_int32_t mh_DataOffset
;
1260 u_int32_t mh_MapOffset
;
1261 u_int32_t mh_DataLength
;
1262 u_int32_t mh_MapLength
;
1264 u_int16_t mh_RefNum
;
1266 u_int8_t mh_InMemoryAttr
;
1269 u_int16_t typeCount
;
1270 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
1272 #define RF_FIRST_RESOURCE 256
1273 #define RF_NULL_MAP_LENGTH 30
1274 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
1276 /* Runtime information about the attribute file. */
1277 typedef struct attr_info
{
1278 vfs_context_t context
;
1283 size_t rawsize
; /* minimum of filesize or ATTR_MAX_HDR_SIZE */
1284 apple_double_header_t
*filehdr
;
1285 apple_double_entry_t
*finderinfo
;
1286 apple_double_entry_t
*rsrcfork
;
1287 attr_header_t
*attrhdr
;
1288 attr_entry_t
*attr_entry
;
1290 u_int8_t emptyfinderinfo
;
1294 #define ATTR_SETTING 1
1296 #define ATTR_ALIGN 3L /* Use four-byte alignment */
1298 #define ATTR_ENTRY_LENGTH(namelen) \
1299 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
1301 #define ATTR_NEXT(ae) \
1302 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
1304 #define ATTR_VALID(ae, ai) \
1305 ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize))
1307 #define SWAP16(x) OSSwapBigToHostInt16((x))
1308 #define SWAP32(x) OSSwapBigToHostInt32((x))
1309 #define SWAP64(x) OSSwapBigToHostInt64((x))
1312 static u_int32_t emptyfinfo
[8] = {0};
1316 * Local support routines
1318 static void close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
);
1320 static int open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
);
1322 static int create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
);
1324 static int remove_xattrfile(vnode_t xvp
, vfs_context_t context
);
1326 static int get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
);
1328 static void rel_xattrinfo(attr_info_t
*ainfop
);
1330 static int write_xattrinfo(attr_info_t
*ainfop
);
1332 static void init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
);
1334 static int lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
);
1336 static int unlock_xattrfile(vnode_t xvp
, vfs_context_t context
);
1339 #if BYTE_ORDER == LITTLE_ENDIAN
1340 static void swap_adhdr(apple_double_header_t
*adh
);
1341 static void swap_attrhdr(attr_header_t
*ah
, attr_info_t
* info
);
1344 #define swap_adhdr(x)
1345 #define swap_attrhdr(x, y)
1348 static int check_and_swap_attrhdr(attr_header_t
*ah
, attr_info_t
* ainfop
);
1349 static int shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
1350 static int shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
1354 * Sanity check and swap the header of an AppleDouble file. Assumes the buffer
1355 * is in big endian (as it would exist on disk). Verifies the following:
1358 * - number of entries
1359 * - that each entry fits within the file size
1361 * If the header is invalid, ENOATTR is returned.
1363 * NOTE: Does not attempt to validate the extended attributes header that
1364 * may be embedded in the Finder Info entry.
1366 static int check_and_swap_apple_double_header(attr_info_t
*ainfop
)
1369 u_int32_t header_end
;
1370 u_int32_t entry_end
;
1372 apple_double_header_t
*header
;
1374 rawsize
= ainfop
->rawsize
;
1375 header
= (apple_double_header_t
*) ainfop
->rawdata
;
1377 /* Is the file big enough to contain an AppleDouble header? */
1378 if (rawsize
< offsetof(apple_double_header_t
, entries
))
1381 /* Swap the AppleDouble header fields to native order */
1382 header
->magic
= SWAP32(header
->magic
);
1383 header
->version
= SWAP32(header
->version
);
1384 header
->numEntries
= SWAP16(header
->numEntries
);
1386 /* Sanity check the AppleDouble header fields */
1387 if (header
->magic
!= ADH_MAGIC
||
1388 header
->version
!= ADH_VERSION
||
1389 header
->numEntries
< 1 ||
1390 header
->numEntries
> 15) {
1394 /* Calculate where the entries[] array ends */
1395 header_end
= offsetof(apple_double_header_t
, entries
) +
1396 header
->numEntries
* sizeof(apple_double_entry_t
);
1398 /* Is the file big enough to contain the AppleDouble entries? */
1399 if (rawsize
< header_end
) {
1403 /* Swap and sanity check each AppleDouble entry */
1404 for (i
=0; i
<header
->numEntries
; i
++) {
1405 /* Swap the per-entry fields to native order */
1406 header
->entries
[i
].type
= SWAP32(header
->entries
[i
].type
);
1407 header
->entries
[i
].offset
= SWAP32(header
->entries
[i
].offset
);
1408 header
->entries
[i
].length
= SWAP32(header
->entries
[i
].length
);
1410 entry_end
= header
->entries
[i
].offset
+ header
->entries
[i
].length
;
1413 * Does the entry's content start within the header itself,
1414 * did the addition overflow, or does the entry's content
1415 * extend past the end of the file?
1417 if (header
->entries
[i
].offset
< header_end
||
1418 entry_end
< header
->entries
[i
].offset
||
1419 entry_end
> ainfop
->filesize
) {
1424 * Does the current entry's content overlap with a previous
1427 * Yes, this is O(N**2), and there are more efficient algorithms
1428 * for testing pairwise overlap of N ranges when N is large.
1429 * But we have already ensured N < 16, and N is almost always 2.
1430 * So there's no point in using a more complex algorithm.
1433 for (j
=0; j
<i
; j
++) {
1434 if (entry_end
> header
->entries
[j
].offset
&&
1435 header
->entries
[j
].offset
+ header
->entries
[j
].length
> header
->entries
[i
].offset
) {
1447 * Retrieve the data of an extended attribute.
1450 default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
1451 __unused
int options
, vfs_context_t context
)
1455 attr_header_t
*header
;
1456 attr_entry_t
*entry
;
1466 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1469 * Open the file locked (shared) since the Carbon
1470 * File Manager may have the Apple Double file open
1471 * and could be changing the resource fork.
1473 fileflags
|= O_SHLOCK
;
1478 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
1481 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1482 close_xattrfile(xvp
, fileflags
, context
);
1486 /* Get the Finder Info. */
1487 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1489 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
1491 } else if (uio
== NULL
) {
1492 *size
= FINDERINFOSIZE
;
1494 } else if (uio_offset(uio
) != 0) {
1496 } else if (uio_resid(uio
) < FINDERINFOSIZE
) {
1499 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1500 error
= uiomove((caddr_t
)attrdata
, FINDERINFOSIZE
, uio
);
1505 /* Read the Resource Fork. */
1507 if (!vnode_isreg(vp
)) {
1509 } else if (ainfo
.rsrcfork
== NULL
) {
1511 } else if (uio
== NULL
) {
1512 *size
= (size_t)ainfo
.rsrcfork
->length
;
1514 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
1515 error
= VNOP_READ(xvp
, uio
, 0, context
);
1517 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
1522 if (ainfo
.attrhdr
== NULL
|| ainfo
.attr_entry
== NULL
) {
1526 if (uio_offset(uio
) != 0) {
1531 namelen
= strlen(name
) + 1;
1532 header
= ainfo
.attrhdr
;
1533 entry
= ainfo
.attr_entry
;
1535 * Search for attribute name in the header.
1537 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1538 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
1539 datalen
= (size_t)entry
->length
;
1545 if (uio_resid(uio
) < (user_ssize_t
)datalen
) {
1549 if (entry
->offset
+ datalen
< ATTR_MAX_HDR_SIZE
) {
1550 attrdata
= ((u_int8_t
*)header
+ entry
->offset
);
1551 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1553 uio_setoffset(uio
, entry
->offset
);
1554 error
= VNOP_READ(xvp
, uio
, 0, context
);
1555 uio_setoffset(uio
, 0);
1559 entry
= ATTR_NEXT(entry
);
1562 rel_xattrinfo(&ainfo
);
1563 close_xattrfile(xvp
, fileflags
, context
);
1569 * Set the data of an extended attribute.
1572 default_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
1576 attr_header_t
*header
;
1577 attr_entry_t
*entry
;
1578 attr_entry_t
*lastentry
;
1582 size_t datafreespace
;
1589 char finfo
[FINDERINFOSIZE
];
1591 datalen
= uio_resid(uio
);
1592 namelen
= strlen(name
) + 1;
1593 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
1596 * By convention, Finder Info that is all zeroes is equivalent to not
1597 * having a Finder Info EA. So if we're trying to set the Finder Info
1598 * to all zeroes, then delete it instead. If a file didn't have an
1599 * AppleDouble file before, this prevents creating an AppleDouble file
1600 * with no useful content.
1602 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check
1603 * for all zeroes Finder Info before opening the AppleDouble file.
1604 * But if either of those options were specified, we need to open the
1605 * AppleDouble file to see whether there was already Finder Info (so we
1606 * can return an error if needed); this case is handled further below.
1608 * NOTE: this copies the Finder Info data into the "finfo" local.
1610 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1612 * TODO: check the XATTR_CREATE and XATTR_REPLACE flags.
1613 * That means we probably have to open_xattrfile and get_xattrinfo.
1615 if (uio_offset(uio
) != 0 || datalen
!= FINDERINFOSIZE
) {
1618 error
= uiomove(finfo
, datalen
, uio
);
1621 if ((options
& (XATTR_CREATE
|XATTR_REPLACE
)) == 0 &&
1622 bcmp(finfo
, emptyfinfo
, FINDERINFOSIZE
) == 0) {
1623 error
= default_removexattr(vp
, name
, 0, context
);
1624 if (error
== ENOATTR
)
1632 * Open the file locked since setting an attribute
1633 * can change the layout of the Apple Double file.
1635 fileflags
= FREAD
| FWRITE
| O_EXLOCK
;
1636 if ((error
= open_xattrfile(vp
, O_CREAT
| fileflags
, &xvp
, context
))) {
1639 if ((error
= get_xattrinfo(xvp
, ATTR_SETTING
, &ainfo
, context
))) {
1640 close_xattrfile(xvp
, fileflags
, context
);
1644 /* Set the Finder Info. */
1645 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1646 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
1647 /* attr exists and "create" was specified? */
1648 if (options
& XATTR_CREATE
) {
1653 /* attr doesn't exists and "replace" was specified? */
1654 if (options
& XATTR_REPLACE
) {
1659 if (options
!= 0 && bcmp(finfo
, emptyfinfo
, FINDERINFOSIZE
) == 0) {
1661 * Setting the Finder Info to all zeroes is equivalent to
1662 * removing it. Close the xattr file and let
1663 * default_removexattr do the work (including deleting
1664 * the xattr file if there are no other xattrs).
1666 * Note that we have to handle the case where the
1667 * Finder Info was already all zeroes, and we ignore
1670 * The common case where options == 0 was handled above.
1672 rel_xattrinfo(&ainfo
);
1673 close_xattrfile(xvp
, fileflags
, context
);
1674 error
= default_removexattr(vp
, name
, 0, context
);
1675 if (error
== ENOATTR
)
1679 if (ainfo
.finderinfo
) {
1680 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1681 bcopy(finfo
, attrdata
, datalen
);
1682 ainfo
.iosize
= sizeof(attr_header_t
);
1683 error
= write_xattrinfo(&ainfo
);
1690 /* Write the Resource Fork. */
1691 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1692 u_int32_t endoffset
;
1694 if (!vnode_isreg(vp
)) {
1698 if (ainfo
.rsrcfork
&& ainfo
.rsrcfork
->length
) {
1699 /* attr exists and "create" was specified? */
1700 if (options
& XATTR_CREATE
) {
1705 /* attr doesn't exists and "replace" was specified? */
1706 if (options
& XATTR_REPLACE
) {
1711 endoffset
= uio_resid(uio
) + uio_offset(uio
); /* new size */
1712 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
1713 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1716 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
1717 if (endoffset
> ainfo
.rsrcfork
->length
) {
1718 ainfo
.rsrcfork
->length
= endoffset
;
1719 ainfo
.iosize
= sizeof(attr_header_t
);
1720 error
= write_xattrinfo(&ainfo
);
1726 if (datalen
> ATTR_MAX_SIZE
) {
1727 return (E2BIG
); /* EINVAL instead ? */
1730 if (ainfo
.attrhdr
== NULL
) {
1734 header
= ainfo
.attrhdr
;
1735 entry
= ainfo
.attr_entry
;
1737 /* Check if data area crosses the maximum header size. */
1738 if ((header
->data_start
+ header
->data_length
+ entrylen
+ datalen
) > ATTR_MAX_HDR_SIZE
)
1739 splitdata
= 1; /* do data I/O separately */
1744 * See if attribute already exists.
1746 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1747 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
1751 entry
= ATTR_NEXT(entry
);
1755 if (options
& XATTR_CREATE
) {
1759 if (datalen
== entry
->length
) {
1761 uio_setoffset(uio
, entry
->offset
);
1762 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1763 uio_setoffset(uio
, 0);
1765 printf("setxattr: VNOP_WRITE error %d\n", error
);
1768 attrdata
= (u_int8_t
*)header
+ entry
->offset
;
1769 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1772 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
1773 error
= write_xattrinfo(&ainfo
);
1775 printf("setxattr: write_xattrinfo error %d\n", error
);
1781 * Brute force approach - just remove old entry and set new entry.
1784 rel_xattrinfo(&ainfo
);
1785 close_xattrfile(xvp
, fileflags
, context
);
1786 error
= default_removexattr(vp
, name
, options
, context
);
1790 /* Clear XATTR_REPLACE option since we just removed the attribute. */
1791 options
&= ~XATTR_REPLACE
;
1792 goto start
; /* start over */
1797 if (options
& XATTR_REPLACE
) {
1798 error
= ENOATTR
; /* nothing there to replace */
1801 /* Check if header size limit has been reached. */
1802 if ((header
->data_start
+ entrylen
) > ATTR_MAX_HDR_SIZE
) {
1807 datafreespace
= header
->total_size
- (header
->data_start
+ header
->data_length
);
1809 /* Check if we need more space. */
1810 if ((datalen
+ entrylen
) > datafreespace
) {
1813 growsize
= roundup((datalen
+ entrylen
) - datafreespace
, ATTR_BUF_SIZE
);
1815 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */
1816 if (!splitdata
&& (header
->total_size
+ growsize
) > ATTR_MAX_HDR_SIZE
) {
1817 growsize
= ATTR_MAX_HDR_SIZE
- header
->total_size
;
1820 ainfo
.filesize
+= growsize
;
1821 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
1823 printf("setxattr: VNOP_TRUNCATE error %d\n", error
);
1829 * Move the resource fork out of the way.
1831 if (ainfo
.rsrcfork
) {
1832 if (ainfo
.rsrcfork
->length
!= 0) {
1833 shift_data_down(xvp
,
1834 ainfo
.rsrcfork
->offset
,
1835 ainfo
.rsrcfork
->length
,
1838 ainfo
.rsrcfork
->offset
+= growsize
;
1840 ainfo
.finderinfo
->length
+= growsize
;
1841 header
->total_size
+= growsize
;
1844 /* Make space for a new entry. */
1846 shift_data_down(xvp
,
1848 header
->data_length
,
1851 bcopy((u_int8_t
*)header
+ header
->data_start
,
1852 (u_int8_t
*)header
+ header
->data_start
+ entrylen
,
1853 header
->data_length
);
1855 header
->data_start
+= entrylen
;
1857 /* Fix up entry data offsets. */
1859 for (entry
= ainfo
.attr_entry
; entry
!= lastentry
&& ATTR_VALID(entry
, ainfo
); entry
= ATTR_NEXT(entry
)) {
1860 entry
->offset
+= entrylen
;
1864 * If the attribute data area is entirely within
1865 * the header buffer, then just update the buffer,
1866 * otherwise we'll write it separately to the file.
1871 /* Write new attribute data after the end of existing data. */
1872 offset
= header
->data_start
+ header
->data_length
;
1873 uio_setoffset(uio
, offset
);
1874 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
1875 uio_setoffset(uio
, 0);
1877 printf("setxattr: VNOP_WRITE error %d\n", error
);
1881 attrdata
= (u_int8_t
*)header
+ header
->data_start
+ header
->data_length
;
1883 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
1885 printf("setxattr: uiomove error %d\n", error
);
1890 /* Create the attribute entry. */
1891 lastentry
->length
= datalen
;
1892 lastentry
->offset
= header
->data_start
+ header
->data_length
;
1893 lastentry
->namelen
= namelen
;
1894 lastentry
->flags
= 0;
1895 bcopy(name
, &lastentry
->name
[0], namelen
);
1897 /* Update the attributes header. */
1898 header
->num_attrs
++;
1899 header
->data_length
+= datalen
;
1902 /* Only write the entries, since the data was written separately. */
1903 ainfo
.iosize
= ainfo
.attrhdr
->data_start
;
1905 /* The entry and data are both in the header; write them together. */
1906 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
1908 error
= write_xattrinfo(&ainfo
);
1910 printf("setxattr: write_xattrinfo error %d\n", error
);
1914 rel_xattrinfo(&ainfo
);
1915 close_xattrfile(xvp
, fileflags
, context
);
1917 /* Touch the change time if we changed an attribute. */
1919 struct vnode_attr va
;
1921 /* Re-write the mtime to cause a ctime change. */
1923 VATTR_WANTED(&va
, va_modify_time
);
1924 if (vnode_getattr(vp
, &va
, context
) == 0) {
1926 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
1927 (void) vnode_setattr(vp
, &va
, context
);
1931 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
1938 * Remove an extended attribute.
1941 default_removexattr(vnode_t vp
, const char *name
, __unused
int options
, vfs_context_t context
)
1945 attr_header_t
*header
;
1946 attr_entry_t
*entry
;
1947 attr_entry_t
*oldslot
;
1953 int found
= 0, lastone
= 0;
1961 fileflags
= FREAD
| FWRITE
;
1962 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
1965 * Open the file locked (exclusive) since the Carbon
1966 * File Manager may have the Apple Double file open
1967 * and could be changing the resource fork.
1969 fileflags
|= O_EXLOCK
;
1974 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
1977 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1978 close_xattrfile(xvp
, fileflags
, context
);
1982 attrcount
+= ainfo
.attrhdr
->num_attrs
;
1985 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
)
1988 /* Clear the Finder Info. */
1989 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1990 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
1994 /* On removal of last attribute the ._ file is removed. */
1995 if (--attrcount
== 0)
1997 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1998 bzero((caddr_t
)attrdata
, FINDERINFOSIZE
);
1999 ainfo
.iosize
= sizeof(attr_header_t
);
2000 error
= write_xattrinfo(&ainfo
);
2004 /* Clear the Resource Fork. */
2006 if (!vnode_isreg(vp
)) {
2010 if (ainfo
.rsrcfork
== NULL
|| ainfo
.rsrcfork
->length
== 0) {
2014 /* On removal of last attribute the ._ file is removed. */
2015 if (--attrcount
== 0)
2019 * If the resource fork isn't the last AppleDouble
2020 * entry then the space needs to be reclaimed by
2021 * shifting the entries after the resource fork.
2023 if ((ainfo
.rsrcfork
->offset
+ ainfo
.rsrcfork
->length
) == ainfo
.filesize
) {
2024 ainfo
.filesize
-= ainfo
.rsrcfork
->length
;
2025 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
2028 ainfo
.rsrcfork
->length
= 0;
2029 ainfo
.iosize
= sizeof(attr_header_t
);
2030 error
= write_xattrinfo(&ainfo
);
2035 if (ainfo
.attrhdr
== NULL
) {
2039 namelen
= strlen(name
) + 1;
2040 header
= ainfo
.attrhdr
;
2041 entry
= ainfo
.attr_entry
;
2044 * See if this attribute exists.
2046 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
2047 if (strncmp((const char *)entry
->name
, name
, namelen
) == 0) {
2049 if ((i
+1) == header
->num_attrs
)
2053 entry
= ATTR_NEXT(entry
);
2059 /* On removal of last attribute the ._ file is removed. */
2060 if (--attrcount
== 0)
2063 datalen
= entry
->length
;
2064 dataoff
= entry
->offset
;
2065 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
2066 if ((header
->data_start
+ header
->data_length
) > ATTR_MAX_HDR_SIZE
)
2071 /* Remove the attribute entry. */
2073 bcopy((u_int8_t
*)entry
+ entrylen
, (u_int8_t
*)entry
,
2074 ((size_t)header
+ header
->data_start
) - ((size_t)entry
+ entrylen
));
2077 /* Adjust the attribute data. */
2081 dataoff
- header
->data_start
,
2087 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
),
2091 /* XXX write zeros to freed space ? */
2092 ainfo
.iosize
= ainfo
.attrhdr
->data_start
- entrylen
;
2096 bcopy((u_int8_t
*)header
+ header
->data_start
,
2097 (u_int8_t
*)header
+ header
->data_start
- entrylen
,
2098 dataoff
- header
->data_start
);
2100 bcopy((u_int8_t
*)header
+ dataoff
+ datalen
,
2101 (u_int8_t
*)header
+ dataoff
- entrylen
,
2102 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
));
2104 bzero (((u_int8_t
*)header
+ header
->data_start
+ header
->data_length
) - (datalen
+ entrylen
), (datalen
+ entrylen
));
2105 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
2108 /* Adjust the header values and entry offsets. */
2109 header
->num_attrs
--;
2110 header
->data_start
-= entrylen
;
2111 header
->data_length
-= datalen
;
2114 entry
= ainfo
.attr_entry
;
2115 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
2116 entry
->offset
-= entrylen
;
2117 if (entry
>= oldslot
)
2118 entry
->offset
-= datalen
;
2119 entry
= ATTR_NEXT(entry
);
2121 error
= write_xattrinfo(&ainfo
);
2123 printf("removexattr: write_xattrinfo error %d\n", error
);
2126 rel_xattrinfo(&ainfo
);
2128 /* When there are no more attributes remove the ._ file. */
2129 if (attrcount
== 0) {
2130 if (fileflags
& O_EXLOCK
)
2131 (void) unlock_xattrfile(xvp
, context
);
2132 VNOP_CLOSE(xvp
, fileflags
, context
);
2134 error
= remove_xattrfile(xvp
, context
);
2137 close_xattrfile(xvp
, fileflags
, context
);
2139 /* Touch the change time if we changed an attribute. */
2141 struct vnode_attr va
;
2143 /* Re-write the mtime to cause a ctime change. */
2145 VATTR_WANTED(&va
, va_modify_time
);
2146 if (vnode_getattr(vp
, &va
, context
) == 0) {
2148 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
2149 (void) vnode_setattr(vp
, &va
, context
);
2153 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
2161 * Retrieve the list of extended attribute names.
2164 default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, __unused
int options
, vfs_context_t context
)
2168 attr_entry_t
*entry
;
2173 * We do not zero "*size" here as we don't want to stomp a size set when
2174 * VNOP_LISTXATTR processed any native EAs. That size is initially zeroed by the
2175 * system call layer, up in listxattr or flistxattr.
2178 if ((error
= open_xattrfile(vp
, FREAD
, &xvp
, context
))) {
2179 if (error
== ENOATTR
)
2183 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
2184 if (error
== ENOATTR
)
2186 close_xattrfile(xvp
, FREAD
, context
);
2190 /* Check for Finder Info. */
2191 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
2193 *size
+= sizeof(XATTR_FINDERINFO_NAME
);
2194 } else if (uio_resid(uio
) < (user_ssize_t
)sizeof(XATTR_FINDERINFO_NAME
)) {
2198 error
= uiomove(XATTR_FINDERINFO_NAME
,
2199 sizeof(XATTR_FINDERINFO_NAME
), uio
);
2207 /* Check for Resource Fork. */
2208 if (vnode_isreg(vp
) && ainfo
.rsrcfork
) {
2210 *size
+= sizeof(XATTR_RESOURCEFORK_NAME
);
2211 } else if (uio_resid(uio
) < (user_ssize_t
)sizeof(XATTR_RESOURCEFORK_NAME
)) {
2215 error
= uiomove(XATTR_RESOURCEFORK_NAME
,
2216 sizeof(XATTR_RESOURCEFORK_NAME
), uio
);
2224 /* Check for attributes. */
2225 if (ainfo
.attrhdr
) {
2226 count
= ainfo
.attrhdr
->num_attrs
;
2227 for (i
= 0, entry
= ainfo
.attr_entry
; i
< count
&& ATTR_VALID(entry
, ainfo
); i
++) {
2228 if (xattr_protected((const char *)entry
->name
) ||
2229 xattr_validatename((const char *)entry
->name
) != 0) {
2230 entry
= ATTR_NEXT(entry
);
2234 *size
+= entry
->namelen
;
2235 entry
= ATTR_NEXT(entry
);
2238 if (uio_resid(uio
) < entry
->namelen
) {
2242 error
= uiomove((caddr_t
) entry
->name
, entry
->namelen
, uio
);
2244 if (error
!= EFAULT
)
2248 entry
= ATTR_NEXT(entry
);
2252 rel_xattrinfo(&ainfo
);
2253 close_xattrfile(xvp
, FREAD
, context
);
2259 * Check the header of a ._ file to verify that it is in fact an Apple Double
2260 * file. Returns 0 if the header is valid, non-zero if invalid.
2262 int check_appledouble_header(vnode_t vp
, vfs_context_t ctx
)
2266 struct vnode_attr va
;
2268 void *buffer
= NULL
;
2272 ainfo
.context
= ctx
;
2274 VATTR_WANTED(&va
, va_data_size
);
2275 if ((error
= vnode_getattr(vp
, &va
, ctx
))) {
2278 ainfo
.filesize
= va
.va_data_size
;
2280 iosize
= MIN(ATTR_MAX_HDR_SIZE
, ainfo
.filesize
);
2285 ainfo
.iosize
= iosize
;
2287 MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
);
2288 if (buffer
== NULL
) {
2293 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2294 uio_addiov(auio
, (uintptr_t)buffer
, iosize
);
2296 /* Read the header */
2297 error
= VNOP_READ(vp
, auio
, 0, ctx
);
2301 ainfo
.rawsize
= iosize
- uio_resid(auio
);
2302 ainfo
.rawdata
= (u_int8_t
*)buffer
;
2304 error
= check_and_swap_apple_double_header(&ainfo
);
2309 /* If we made it here, then the header is ok */
2316 FREE(buffer
, M_TEMP
);
2323 open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
)
2325 vnode_t xvp
= NULLVP
;
2326 vnode_t dvp
= NULLVP
;
2327 struct vnode_attr va
;
2328 struct nameidata nd
;
2330 char *filename
= NULL
;
2331 const char *basename
= NULL
;
2337 if (vnode_isvroot(vp
) && vnode_isdir(vp
)) {
2339 * For the root directory use "._." to hold the attributes.
2341 filename
= &smallname
[0];
2342 snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, ".");
2343 dvp
= vp
; /* the "._." file resides in the root dir */
2346 if ( (dvp
= vnode_getparent(vp
)) == NULLVP
) {
2350 if ( (basename
= vnode_getname(vp
)) == NULL
) {
2355 /* "._" Attribute files cannot have attributes */
2356 if (vp
->v_type
== VREG
&& strlen(basename
) > 2 &&
2357 basename
[0] == '.' && basename
[1] == '_') {
2361 filename
= &smallname
[0];
2362 len
= snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, basename
);
2363 if (len
>= sizeof(smallname
)) {
2364 len
++; /* snprintf result doesn't include '\0' */
2365 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
2366 len
= snprintf(filename
, len
, "%s%s", ATTR_FILE_PREFIX
, basename
);
2369 * Note that the lookup here does not authorize. Since we are looking
2370 * up in the same directory that we already have the file vnode in,
2371 * we must have been given the file vnode legitimately. Read/write
2372 * access has already been authorized in layers above for calls from
2373 * userspace, and the authorization code using this path to read
2374 * file security from the EA must always get access
2377 NDINIT(&nd
, LOOKUP
, OP_OPEN
, LOCKLEAF
| NOFOLLOW
| USEDVP
| DONOTAUTH
,
2378 UIO_SYSSPACE
, CAST_USER_ADDR_T(filename
), context
);
2381 if (fileflags
& O_CREAT
) {
2382 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2387 nd
.ni_cnd
.cn_flags
|= LOCKPARENT
;
2389 if ( (error
= namei(&nd
))) {
2394 if ( (xvp
= nd
.ni_vp
) == NULLVP
) {
2400 * Pick up uid/gid/mode from target file.
2403 VATTR_WANTED(&va
, va_uid
);
2404 VATTR_WANTED(&va
, va_gid
);
2405 VATTR_WANTED(&va
, va_mode
);
2406 if (VNOP_GETATTR(vp
, &va
, context
) == 0 &&
2407 VATTR_IS_SUPPORTED(&va
, va_uid
) &&
2408 VATTR_IS_SUPPORTED(&va
, va_gid
) &&
2409 VATTR_IS_SUPPORTED(&va
, va_mode
)) {
2412 umode
= va
.va_mode
& (S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
);
2413 } else /* fallback values */ {
2414 uid
= KAUTH_UID_NONE
;
2415 gid
= KAUTH_GID_NONE
;
2416 umode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
;
2420 VATTR_SET(&va
, va_type
, VREG
);
2421 VATTR_SET(&va
, va_mode
, umode
);
2422 if (uid
!= KAUTH_UID_NONE
)
2423 VATTR_SET(&va
, va_uid
, uid
);
2424 if (gid
!= KAUTH_GID_NONE
)
2425 VATTR_SET(&va
, va_gid
, gid
);
2427 error
= vn_create(dvp
, &nd
.ni_vp
, &nd
, &va
,
2428 VN_CREATE_NOAUTH
| VN_CREATE_NOINHERIT
| VN_CREATE_NOLABEL
,
2438 vnode_put(dvp
); /* drop iocount from LOCKPARENT request above */
2443 if ((error
= namei(&nd
))) {
2453 if (xvp
->v_type
!= VREG
) {
2458 * Owners must match.
2461 VATTR_WANTED(&va
, va_uid
);
2462 if (VNOP_GETATTR(vp
, &va
, context
) == 0 && VATTR_IS_SUPPORTED(&va
, va_uid
)) {
2463 uid_t owner
= va
.va_uid
;
2466 VATTR_WANTED(&va
, va_uid
);
2467 if (VNOP_GETATTR(xvp
, &va
, context
) == 0 && (owner
!= va
.va_uid
)) {
2468 error
= ENOATTR
; /* don't use this "._" file */
2473 if ( (error
= VNOP_OPEN(xvp
, fileflags
& ~(O_EXLOCK
| O_SHLOCK
), context
))) {
2479 if ((error
= vnode_ref(xvp
))) {
2484 /* If create was requested, make sure file header exists. */
2485 if (fileflags
& O_CREAT
) {
2487 VATTR_WANTED(&va
, va_data_size
);
2488 VATTR_WANTED(&va
, va_fileid
);
2489 VATTR_WANTED(&va
, va_nlink
);
2490 if ( (error
= vnode_getattr(xvp
, &va
, context
)) != 0) {
2495 /* If the file is empty then add a default header. */
2496 if (va
.va_data_size
== 0) {
2497 /* Don't adopt hard-linked "._" files. */
2498 if (VATTR_IS_SUPPORTED(&va
, va_nlink
) && va
.va_nlink
> 1) {
2502 if ( (error
= create_xattrfile(xvp
, (u_int32_t
)va
.va_fileid
, context
)))
2506 /* Apply file locking if requested. */
2507 if (fileflags
& (O_EXLOCK
| O_SHLOCK
)) {
2510 locktype
= (fileflags
& O_EXLOCK
) ? F_WRLCK
: F_RDLCK
;
2511 error
= lock_xattrfile(xvp
, locktype
, context
);
2516 if (dvp
&& (dvp
!= vp
)) {
2520 vnode_putname(basename
);
2522 if (filename
&& filename
!= &smallname
[0]) {
2523 FREE(filename
, M_TEMP
);
2526 if (xvp
!= NULLVP
) {
2528 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
2531 (void) vnode_rele(xvp
);
2533 (void) vnode_put(xvp
);
2536 if ((error
== ENOATTR
) && (fileflags
& O_CREAT
)) {
2540 *xvpp
= xvp
; /* return a referenced vnode */
2545 close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
)
2547 // if (fileflags & FWRITE)
2548 // (void) VNOP_FSYNC(xvp, MNT_WAIT, context);
2550 if (fileflags
& (O_EXLOCK
| O_SHLOCK
))
2551 (void) unlock_xattrfile(xvp
, context
);
2553 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
2554 (void) vnode_rele(xvp
);
2555 (void) vnode_put(xvp
);
2559 remove_xattrfile(vnode_t xvp
, vfs_context_t context
)
2562 struct nameidata nd
;
2567 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2571 pathlen
= MAXPATHLEN
;
2572 error
= vn_getpath(xvp
, path
, &pathlen
);
2574 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2578 NDINIT(&nd
, DELETE
, OP_UNLINK
, LOCKPARENT
| NOFOLLOW
| DONOTAUTH
,
2579 UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), context
);
2581 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2588 error
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, context
);
2597 * Read in and parse the AppleDouble header and entries, and the extended
2598 * attribute header and entries if any. Populates the fields of ainfop
2599 * based on the headers and entries found.
2601 * The basic idea is to:
2602 * - Read in up to ATTR_MAX_HDR_SIZE bytes of the start of the file. All
2603 * AppleDouble entries, the extended attribute header, and extended
2604 * attribute entries must lie within this part of the file; the rest of
2605 * the AppleDouble handling code assumes this. Plus it allows us to
2606 * somewhat optimize by doing a smaller number of larger I/Os.
2607 * - Swap and sanity check the AppleDouble header (including the AppleDouble
2609 * - Find the Finder Info and Resource Fork entries, if any.
2610 * - If we're going to be writing, try to make sure the Finder Info entry has
2611 * room to store the extended attribute header, plus some space for extended
2613 * - Swap and sanity check the extended attribute header and entries (if any).
2616 get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
)
2619 void * buffer
= NULL
;
2620 apple_double_header_t
*filehdr
;
2621 struct vnode_attr va
;
2626 bzero(ainfop
, sizeof(attr_info_t
));
2627 ainfop
->filevp
= xvp
;
2628 ainfop
->context
= context
;
2630 VATTR_WANTED(&va
, va_data_size
);
2631 VATTR_WANTED(&va
, va_fileid
);
2632 if ((error
= vnode_getattr(xvp
, &va
, context
))) {
2635 ainfop
->filesize
= va
.va_data_size
;
2637 /* When setting attributes, allow room for the header to grow. */
2639 iosize
= ATTR_MAX_HDR_SIZE
;
2641 iosize
= MIN(ATTR_MAX_HDR_SIZE
, ainfop
->filesize
);
2647 ainfop
->iosize
= iosize
;
2648 MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
);
2649 if (buffer
== NULL
){
2654 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2655 uio_addiov(auio
, (uintptr_t)buffer
, iosize
);
2657 /* Read the file header. */
2658 error
= VNOP_READ(xvp
, auio
, 0, context
);
2662 ainfop
->rawsize
= iosize
- uio_resid(auio
);
2663 ainfop
->rawdata
= (u_int8_t
*)buffer
;
2665 filehdr
= (apple_double_header_t
*)buffer
;
2667 error
= check_and_swap_apple_double_header(ainfop
);
2671 ainfop
->filehdr
= filehdr
; /* valid AppleDouble header */
2673 /* rel_xattrinfo is responsible for freeing the header buffer */
2676 /* Find the Finder Info and Resource Fork entries, if any */
2677 for (i
= 0; i
< filehdr
->numEntries
; ++i
) {
2678 if (filehdr
->entries
[i
].type
== AD_FINDERINFO
&&
2679 filehdr
->entries
[i
].length
>= FINDERINFOSIZE
) {
2680 /* We found the Finder Info entry. */
2681 ainfop
->finderinfo
= &filehdr
->entries
[i
];
2684 * Is the Finder Info "empty" (all zeroes)? If so,
2685 * we'll pretend like the Finder Info extended attribute
2688 * Note: we have to make sure the Finder Info is
2689 * contained within the buffer we have already read,
2690 * to avoid accidentally accessing a bogus address.
2691 * If it is outside the buffer, we just assume the
2692 * Finder Info is non-empty.
2694 if (ainfop
->finderinfo
->offset
+ FINDERINFOSIZE
<= ainfop
->rawsize
&&
2695 bcmp((u_int8_t
*)ainfop
->filehdr
+ ainfop
->finderinfo
->offset
, emptyfinfo
, sizeof(emptyfinfo
)) == 0) {
2696 ainfop
->emptyfinderinfo
= 1;
2699 if (filehdr
->entries
[i
].type
== AD_RESOURCE
) {
2701 * Ignore zero-length resource forks when getting. If setting,
2702 * we need to remember the resource fork entry so it can be
2703 * updated once the new content has been written.
2705 if (filehdr
->entries
[i
].length
== 0 && !setting
)
2709 * Check to see if any "empty" resource fork is ours (i.e. is ignorable).
2711 * The "empty" resource headers we created have a system data tag of:
2712 * "This resource fork intentionally left blank "
2714 if (filehdr
->entries
[i
].length
== sizeof(rsrcfork_header_t
) && !setting
) {
2716 u_int8_t systemData
[64];
2720 /* Read the system data which starts at byte 16 */
2721 rf_uio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
2722 uio_addiov(rf_uio
, (uintptr_t)systemData
, sizeof(systemData
));
2723 uio_setoffset(rf_uio
, filehdr
->entries
[i
].offset
+ 16);
2724 rf_err
= VNOP_READ(xvp
, rf_uio
, 0, context
);
2728 bcmp(systemData
, RF_EMPTY_TAG
, sizeof(RF_EMPTY_TAG
)) == 0) {
2729 continue; /* skip this resource fork */
2732 ainfop
->rsrcfork
= &filehdr
->entries
[i
];
2733 if (i
!= (filehdr
->numEntries
- 1)) {
2734 printf("get_xattrinfo: resource fork not last entry\n");
2735 ainfop
->readonly
= 1;
2742 * See if this file looks like it is laid out correctly to contain
2743 * extended attributes. If so, then do the following:
2745 * - If we're going to be writing, try to make sure the Finder Info
2746 * entry has room to store the extended attribute header, plus some
2747 * space for extended attributes.
2749 * - Swap and sanity check the extended attribute header and entries
2752 if (filehdr
->numEntries
== 2 &&
2753 ainfop
->finderinfo
== &filehdr
->entries
[0] &&
2754 ainfop
->rsrcfork
== &filehdr
->entries
[1] &&
2755 ainfop
->finderinfo
->offset
== offsetof(apple_double_header_t
, finfo
)) {
2756 attr_header_t
*attrhdr
;
2757 attrhdr
= (attr_header_t
*)filehdr
;
2759 * If we're going to be writing, try to make sure the Finder
2760 * Info entry has room to store the extended attribute header,
2761 * plus some space for extended attributes.
2763 if (setting
&& ainfop
->finderinfo
->length
== FINDERINFOSIZE
) {
2767 delta
= ATTR_BUF_SIZE
- (filehdr
->entries
[0].offset
+ FINDERINFOSIZE
);
2768 if (ainfop
->rsrcfork
&& filehdr
->entries
[1].length
) {
2769 /* Make some room before existing resource fork. */
2770 shift_data_down(xvp
,
2771 filehdr
->entries
[1].offset
,
2772 filehdr
->entries
[1].length
,
2774 writesize
= sizeof(attr_header_t
);
2776 /* Create a new, empty resource fork. */
2777 rsrcfork_header_t
*rsrcforkhdr
;
2779 vnode_setsize(xvp
, filehdr
->entries
[1].offset
+ delta
, 0, context
);
2781 /* Steal some space for an empty RF header. */
2782 delta
-= sizeof(rsrcfork_header_t
);
2784 bzero(&attrhdr
->appledouble
.pad
[0], delta
);
2785 rsrcforkhdr
= (rsrcfork_header_t
*)((char *)filehdr
+ filehdr
->entries
[1].offset
+ delta
);
2787 /* Fill in Empty Resource Fork Header. */
2788 init_empty_resource_fork(rsrcforkhdr
);
2790 filehdr
->entries
[1].length
= sizeof(rsrcfork_header_t
);
2791 writesize
= ATTR_BUF_SIZE
;
2793 filehdr
->entries
[0].length
+= delta
;
2794 filehdr
->entries
[1].offset
+= delta
;
2796 /* Fill in Attribute Header. */
2797 attrhdr
->magic
= ATTR_HDR_MAGIC
;
2798 attrhdr
->debug_tag
= (u_int32_t
)va
.va_fileid
;
2799 attrhdr
->total_size
= filehdr
->entries
[1].offset
;
2800 attrhdr
->data_start
= sizeof(attr_header_t
);
2801 attrhdr
->data_length
= 0;
2802 attrhdr
->reserved
[0] = 0;
2803 attrhdr
->reserved
[1] = 0;
2804 attrhdr
->reserved
[2] = 0;
2806 attrhdr
->num_attrs
= 0;
2808 /* Push out new header */
2809 uio_reset(auio
, 0, UIO_SYSSPACE
, UIO_WRITE
);
2810 uio_addiov(auio
, (uintptr_t)filehdr
, writesize
);
2812 swap_adhdr(filehdr
); /* to big endian */
2813 swap_attrhdr(attrhdr
, ainfop
); /* to big endian */
2814 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
2815 swap_adhdr(filehdr
); /* back to native */
2816 /* The attribute header gets swapped below. */
2820 * Swap and sanity check the extended attribute header and
2821 * entries (if any). The Finder Info content must be big enough
2822 * to include the extended attribute header; if not, we just
2825 * Note that we're passing the offset + length (i.e. the end)
2826 * of the Finder Info instead of rawsize to validate_attrhdr.
2827 * This ensures that all extended attributes lie within the
2828 * Finder Info content according to the AppleDouble entry.
2830 * Sets ainfop->attrhdr and ainfop->attr_entry if a valid
2833 if (ainfop
->finderinfo
&&
2834 ainfop
->finderinfo
== &filehdr
->entries
[0] &&
2835 ainfop
->finderinfo
->length
>= (sizeof(attr_header_t
) - sizeof(apple_double_header_t
))) {
2836 attr_header_t
*attrhdr
= (attr_header_t
*)filehdr
;
2838 if ((error
= check_and_swap_attrhdr(attrhdr
, ainfop
)) == 0) {
2839 ainfop
->attrhdr
= attrhdr
; /* valid attribute header */
2840 /* First attr_entry starts immediately following attribute header */
2841 ainfop
->attr_entry
= (attr_entry_t
*)&attrhdr
[1];
2850 FREE(buffer
, M_TEMP
);
2856 create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
)
2859 rsrcfork_header_t
*rsrcforkhdr
;
2865 MALLOC(buffer
, void *, ATTR_BUF_SIZE
, M_TEMP
, M_WAITOK
);
2866 bzero(buffer
, ATTR_BUF_SIZE
);
2868 xah
= (attr_header_t
*)buffer
;
2869 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_WRITE
);
2870 uio_addiov(auio
, (uintptr_t)buffer
, ATTR_BUF_SIZE
);
2871 rsrcforksize
= sizeof(rsrcfork_header_t
);
2872 rsrcforkhdr
= (rsrcfork_header_t
*) ((char *)buffer
+ ATTR_BUF_SIZE
- rsrcforksize
);
2874 /* Fill in Apple Double Header. */
2875 xah
->appledouble
.magic
= SWAP32 (ADH_MAGIC
);
2876 xah
->appledouble
.version
= SWAP32 (ADH_VERSION
);
2877 xah
->appledouble
.numEntries
= SWAP16 (2);
2878 xah
->appledouble
.entries
[0].type
= SWAP32 (AD_FINDERINFO
);
2879 xah
->appledouble
.entries
[0].offset
= SWAP32 (offsetof(apple_double_header_t
, finfo
));
2880 xah
->appledouble
.entries
[0].length
= SWAP32 (ATTR_BUF_SIZE
- offsetof(apple_double_header_t
, finfo
) - rsrcforksize
);
2881 xah
->appledouble
.entries
[1].type
= SWAP32 (AD_RESOURCE
);
2882 xah
->appledouble
.entries
[1].offset
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
2883 xah
->appledouble
.entries
[1].length
= SWAP32 (rsrcforksize
);
2884 bcopy(ADH_MACOSX
, xah
->appledouble
.filler
, sizeof(xah
->appledouble
.filler
));
2886 /* Fill in Attribute Header. */
2887 xah
->magic
= SWAP32 (ATTR_HDR_MAGIC
);
2888 xah
->debug_tag
= SWAP32 (fileid
);
2889 xah
->total_size
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
2890 xah
->data_start
= SWAP32 (sizeof(attr_header_t
));
2892 /* Fill in Empty Resource Fork Header. */
2893 init_empty_resource_fork(rsrcforkhdr
);
2896 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
2899 FREE(buffer
, M_TEMP
);
2905 init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
)
2907 bzero(rsrcforkhdr
, sizeof(rsrcfork_header_t
));
2908 rsrcforkhdr
->fh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2909 rsrcforkhdr
->fh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2910 rsrcforkhdr
->fh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
2911 rsrcforkhdr
->mh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2912 rsrcforkhdr
->mh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
2913 rsrcforkhdr
->mh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
2914 rsrcforkhdr
->mh_Types
= SWAP16 (RF_NULL_MAP_LENGTH
- 2 );
2915 rsrcforkhdr
->mh_Names
= SWAP16 (RF_NULL_MAP_LENGTH
);
2916 rsrcforkhdr
->typeCount
= SWAP16 (-1);
2917 bcopy(RF_EMPTY_TAG
, rsrcforkhdr
->systemData
, sizeof(RF_EMPTY_TAG
));
2921 rel_xattrinfo(attr_info_t
*ainfop
)
2923 FREE(ainfop
->filehdr
, M_TEMP
);
2924 bzero(ainfop
, sizeof(attr_info_t
));
2928 write_xattrinfo(attr_info_t
*ainfop
)
2933 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_WRITE
);
2934 uio_addiov(auio
, (uintptr_t)ainfop
->filehdr
, ainfop
->iosize
);
2936 swap_adhdr(ainfop
->filehdr
);
2937 if (ainfop
->attrhdr
!= NULL
) {
2938 swap_attrhdr(ainfop
->attrhdr
, ainfop
);
2941 error
= VNOP_WRITE(ainfop
->filevp
, auio
, 0, ainfop
->context
);
2943 swap_adhdr(ainfop
->filehdr
);
2944 if (ainfop
->attrhdr
!= NULL
) {
2945 swap_attrhdr(ainfop
->attrhdr
, ainfop
);
2952 #if BYTE_ORDER == LITTLE_ENDIAN
2954 * Endian swap apple double header
2957 swap_adhdr(apple_double_header_t
*adh
)
2962 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2964 adh
->magic
= SWAP32 (adh
->magic
);
2965 adh
->version
= SWAP32 (adh
->version
);
2966 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2968 for (i
= 0; i
< count
; i
++) {
2969 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2970 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2971 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2976 * Endian swap extended attributes header
2979 swap_attrhdr(attr_header_t
*ah
, attr_info_t
* info
)
2985 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2987 ah
->magic
= SWAP32 (ah
->magic
);
2988 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2989 ah
->total_size
= SWAP32 (ah
->total_size
);
2990 ah
->data_start
= SWAP32 (ah
->data_start
);
2991 ah
->data_length
= SWAP32 (ah
->data_length
);
2992 ah
->flags
= SWAP16 (ah
->flags
);
2993 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2995 ae
= (attr_entry_t
*)(&ah
[1]);
2996 for (i
= 0; i
< count
&& ATTR_VALID(ae
, *info
); i
++, ae
= ATTR_NEXT(ae
)) {
2997 ae
->offset
= SWAP32 (ae
->offset
);
2998 ae
->length
= SWAP32 (ae
->length
);
2999 ae
->flags
= SWAP16 (ae
->flags
);
3005 * Validate and swap the attributes header contents, and each attribute's
3008 * Note: Assumes the caller has verified that the Finder Info content is large
3009 * enough to contain the attr_header structure itself. Therefore, we can
3010 * swap the header fields before sanity checking them.
3013 check_and_swap_attrhdr(attr_header_t
*ah
, attr_info_t
*ainfop
)
3024 if (SWAP32(ah
->magic
) != ATTR_HDR_MAGIC
)
3027 /* Swap the basic header fields */
3028 ah
->magic
= SWAP32(ah
->magic
);
3029 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
3030 ah
->total_size
= SWAP32 (ah
->total_size
);
3031 ah
->data_start
= SWAP32 (ah
->data_start
);
3032 ah
->data_length
= SWAP32 (ah
->data_length
);
3033 ah
->flags
= SWAP16 (ah
->flags
);
3034 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3037 * Make sure the total_size fits within the Finder Info area, and the
3038 * extended attribute data area fits within total_size.
3040 end
= ah
->data_start
+ ah
->data_length
;
3041 if (ah
->total_size
> ainfop
->finderinfo
->offset
+ ainfop
->finderinfo
->length
||
3042 end
< ah
->data_start
||
3043 end
> ah
->total_size
) {
3048 * Make sure each of the attr_entry_t's fits within total_size.
3050 buf_end
= ainfop
->rawdata
+ ah
->total_size
;
3051 count
= ah
->num_attrs
;
3052 ae
= (attr_entry_t
*)(&ah
[1]);
3054 for (i
=0; i
<count
; i
++) {
3055 /* Make sure the fixed-size part of this attr_entry_t fits. */
3056 if ((u_int8_t
*) &ae
[1] > buf_end
)
3059 /* Make sure the variable-length name fits (+1 is for NUL terminator) */
3060 /* TODO: Make sure namelen matches strnlen(name,namelen+1)? */
3061 if (&ae
->name
[ae
->namelen
+1] > buf_end
)
3064 /* Swap the attribute entry fields */
3065 ae
->offset
= SWAP32(ae
->offset
);
3066 ae
->length
= SWAP32(ae
->length
);
3067 ae
->flags
= SWAP16(ae
->flags
);
3069 /* Make sure the attribute content fits. */
3070 end
= ae
->offset
+ ae
->length
;
3071 if (end
< ae
->offset
|| end
> ah
->total_size
)
3078 * TODO: Make sure the contents of attributes don't overlap the header
3079 * and don't overlap each other. The hard part is that we don't know
3080 * what the actual header size is until we have looped over all of the
3081 * variable-sized attribute entries.
3083 * XXX Is there any guarantee that attribute entries are stored in
3084 * XXX order sorted by the contents' file offset? If so, that would
3085 * XXX make the pairwise overlap check much easier.
3092 // "start" & "end" are byte offsets in the file.
3093 // "to" is the byte offset we want to move the
3094 // data to. "to" should be > "start".
3096 // we do the copy backwards to avoid problems if
3097 // there's an overlap.
3100 shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
3103 size_t chunk
, orig_chunk
;
3106 kauth_cred_t ucred
= vfs_context_ucred(context
);
3107 proc_t p
= vfs_context_proc(context
);
3109 if (delta
== 0 || len
== 0) {
3119 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
3123 for(pos
=start
+len
-chunk
; pos
>= start
; pos
-=chunk
) {
3124 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3126 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
3127 pos
, ret
, chunk
, ret
);
3131 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
+ delta
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3133 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
3134 pos
+delta
, ret
, chunk
, ret
);
3138 if ((pos
- (off_t
)chunk
) < start
) {
3139 chunk
= pos
- start
;
3141 if (chunk
== 0) { // we're all done
3146 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
3153 shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
3156 size_t chunk
, orig_chunk
;
3160 kauth_cred_t ucred
= vfs_context_ucred(context
);
3161 proc_t p
= vfs_context_proc(context
);
3163 if (delta
== 0 || len
== 0) {
3174 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
3178 for(pos
= start
; pos
< end
; pos
+= chunk
) {
3179 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3181 printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
3182 pos
, ret
, chunk
, ret
);
3186 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
- delta
, UIO_SYSSPACE
, IO_NODELOCKED
|IO_NOAUTH
, ucred
, &iolen
, p
);
3188 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
3189 pos
+delta
, ret
, chunk
, ret
);
3193 if ((pos
+ (off_t
)chunk
) > end
) {
3196 if (chunk
== 0) { // we're all done
3201 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
3207 lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
)
3212 lf
.l_whence
= SEEK_SET
;
3215 lf
.l_type
= locktype
; /* F_WRLCK or F_RDLCK */
3216 /* Note: id is just a kernel address that's not a proc */
3217 error
= VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_SETLK
, &lf
, F_FLOCK
|F_WAIT
, context
);
3218 return (error
== ENOTSUP
? 0 : error
);
3222 unlock_xattrfile(vnode_t xvp
, vfs_context_t context
)
3227 lf
.l_whence
= SEEK_SET
;
3230 lf
.l_type
= F_UNLCK
;
3231 /* Note: id is just a kernel address that's not a proc */
3232 error
= VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_UNLCK
, &lf
, F_FLOCK
, context
);
3233 return (error
== ENOTSUP
? 0 : error
);