2 * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <sys/param.h>
33 #include <sys/fcntl.h>
34 #include <sys/fsevents.h>
35 #include <sys/kernel.h>
36 #include <sys/kauth.h>
37 #include <sys/malloc.h>
38 #include <sys/namei.h>
39 #include <sys/proc_internal.h>
42 #include <sys/utfconv.h>
43 #include <sys/vnode.h>
44 #include <sys/vnode_internal.h>
46 #include <sys/xattr.h>
48 #include <architecture/byte_order.h>
49 #include <vm/vm_kern.h>
52 * Default xattr support routines.
54 static int default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
55 int options
, vfs_context_t context
);
57 static int default_setxattr(vnode_t vp
, const char *name
, uio_t uio
,
58 int options
, vfs_context_t context
);
60 static int default_removexattr(vnode_t vp
, const char *name
, int options
, vfs_context_t context
);
62 static int default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
,
63 vfs_context_t context
);
68 * Retrieve the data of an extended attribute.
71 vn_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
72 int options
, vfs_context_t context
)
76 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
79 if ((error
= xattr_validatename(name
))) {
82 if (!(options
& XATTR_NOSECURITY
) && (error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
)))
85 /* The offset can only be non-zero for resource forks. */
86 if (uio
!= NULL
&& uio_offset(uio
) != 0 &&
87 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) {
92 error
= VNOP_GETXATTR(vp
, name
, uio
, size
, options
, context
);
93 if (error
== ENOTSUP
) {
95 * A filesystem may keep some EAs natively and return ENOTSUP for others.
96 * SMB returns ENOTSUP for finderinfo and resource forks.
98 error
= default_getxattr(vp
, name
, uio
, size
, options
, context
);
105 * Set the data of an extended attribute.
108 vn_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
112 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
115 if ((options
& (XATTR_REPLACE
|XATTR_CREATE
)) == (XATTR_REPLACE
|XATTR_CREATE
)) {
118 if ((error
= xattr_validatename(name
))) {
121 if (!(options
& XATTR_NOSECURITY
) && (error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
)))
124 /* The offset can only be non-zero for resource forks. */
125 if (uio_offset(uio
) != 0 &&
126 bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0 ) {
131 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
134 * An EJUSTRETURN is from a filesystem which keeps this xattr
135 * natively as well as in a dot-underscore file. In this case the
136 * EJUSTRETURN means the filesytem has done nothing, but identifies the
137 * EA as one which may be represented natively and/or in a DU, and
138 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
139 * in vn_setxattr can we do the getxattrs needed to ascertain whether
140 * the XATTR_{CREATE,REPLACE} should yield an error.
142 if (error
== EJUSTRETURN
) {
143 int native
= 0, dufile
= 0;
144 size_t sz
; /* not used */
146 native
= VNOP_GETXATTR(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
147 dufile
= default_getxattr(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1;
148 if (options
& XATTR_CREATE
&& (native
|| dufile
)) {
152 if (options
& XATTR_REPLACE
&& !(native
|| dufile
)) {
157 * Having determined no CREATE/REPLACE error should result, we
158 * zero those bits, so both backing stores get written to.
160 options
&= ~(XATTR_CREATE
| XATTR_REPLACE
);
161 error
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
);
162 /* the mainline path here is to have error==ENOTSUP ... */
164 #endif /* DUAL_EAS */
165 if (error
== ENOTSUP
) {
167 * A filesystem may keep some EAs natively and return ENOTSUP for others.
168 * SMB returns ENOTSUP for finderinfo and resource forks.
170 error
= default_setxattr(vp
, name
, uio
, options
, context
);
177 * Remove an extended attribute.
180 vn_removexattr(vnode_t vp
, const char * name
, int options
, vfs_context_t context
)
184 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
187 if ((error
= xattr_validatename(name
))) {
190 if (!(options
& XATTR_NOSECURITY
) && (error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
)))
192 error
= VNOP_REMOVEXATTR(vp
, name
, options
, context
);
193 if (error
== ENOTSUP
) {
195 * A filesystem may keep some EAs natively and return ENOTSUP for others.
196 * SMB returns ENOTSUP for finderinfo and resource forks.
198 error
= default_removexattr(vp
, name
, options
, context
);
200 } else if (error
== EJUSTRETURN
) {
202 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
203 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
204 * a native xattr, so failure to find it in a DU file during
205 * default_removexattr should not be considered an error.
207 error
= default_removexattr(vp
, name
, options
, context
);
208 if (error
== ENOATTR
)
210 #endif /* DUAL_EAS */
217 * Retrieve the list of extended attribute names.
220 vn_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
)
224 if (!(vp
->v_type
== VREG
|| vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
)) {
227 if (!(options
& XATTR_NOSECURITY
) && (error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
)))
230 error
= VNOP_LISTXATTR(vp
, uio
, size
, options
, context
);
231 if (error
== ENOTSUP
) {
233 * A filesystem may keep some but not all EAs natively, in which case
234 * the native EA names will have been uiomove-d out (or *size updated)
235 * and the default_listxattr here will finish the job. Note SMB takes
236 * advantage of this for its finder-info and resource forks.
238 error
= default_listxattr(vp
, uio
, size
, options
, context
);
245 xattr_validatename(const char *name
)
249 if (name
== NULL
|| name
[0] == '\0') {
252 namelen
= strlen(name
);
253 if (namelen
> XATTR_MAXNAMELEN
) {
254 return (ENAMETOOLONG
);
256 if (utf8_validatestr(name
, namelen
) != 0) {
264 * Determine whether an EA is a protected system attribute.
267 xattr_protected(const char *attrname
)
269 return(!strncmp(attrname
, "com.apple.system.", 17));
274 * Default Implementation (Non-native EA)
279 Typical "._" AppleDouble Header File layout:
280 ------------------------------------------------------------
285 .-- AD ENTRY[0] Finder Info Entry (must be first)
286 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
288 | ///////////// Fixed Size Data (32 bytes)
292 | ATTR ENTRY[1] --+--.
293 | ATTR ENTRY[2] --+--+--.
295 | ATTR ENTRY[N] --+--+--+--.
296 | ATTR DATA 0 <-' | | |
298 | ATTR DATA 1 <----' | |
300 | ATTR DATA 2 <-------' |
303 | ATTR DATA N <----------'
305 | Attribute Free Space
308 ///////////// Variable Sized Data
317 ------------------------------------------------------------
319 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
320 stored as part of the Finder Info. The length in the Finder
321 Info AppleDouble entry includes the length of the extended
322 attribute header, attribute entries, and attribute data.
327 * On Disk Data Structures
329 * Note: Motorola 68K alignment and big-endian.
331 * See RFC 1740 for additional information about the AppleDouble file format.
335 #define ADH_MAGIC 0x00051607
336 #define ADH_VERSION 0x00020000
337 #define ADH_MACOSX "Mac OS X "
340 * AppleDouble Entry ID's
342 #define AD_DATA 1 /* Data fork */
343 #define AD_RESOURCE 2 /* Resource fork */
344 #define AD_REALNAME 3 /* FileÕs name on home file system */
345 #define AD_COMMENT 4 /* Standard Mac comment */
346 #define AD_ICONBW 5 /* Mac black & white icon */
347 #define AD_ICONCOLOR 6 /* Mac color icon */
348 #define AD_UNUSED 7 /* Not used */
349 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
350 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
351 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
352 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
353 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
354 #define AD_AFPNAME 13 /* Short name on AFP server */
355 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
356 #define AD_AFPDIRID 15 /* AFP directory ID */
357 #define AD_ATTRIBUTES AD_FINDERINFO
360 #define ATTR_FILE_PREFIX "._"
361 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
363 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
365 /* Implementation Limits */
366 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
367 #define ATTR_MAX_HDR_SIZE 65536
369 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
370 * size supported (including the attribute entries). All of
371 * the attribute entries must reside within this limit. If
372 * any of the attribute data crosses the ATTR_MAX_HDR_SIZE
373 * boundry, then all of the attribute data I/O is performed
374 * seperately from the attribute header I/O.
378 #pragma options align=mac68k
380 #define FINDERINFOSIZE 32
382 typedef struct apple_double_entry
{
383 u_int32_t type
; /* entry type: see list, 0 invalid */
384 u_int32_t offset
; /* entry data offset from the beginning of the file. */
385 u_int32_t length
; /* entry data length in bytes. */
386 } apple_double_entry_t
;
389 typedef struct apple_double_header
{
390 u_int32_t magic
; /* == ADH_MAGIC */
391 u_int32_t version
; /* format version: 2 = 0x00020000 */
393 u_int16_t numEntries
; /* number of entries which follow */
394 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
395 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
396 u_int8_t pad
[2]; /* get better alignment inside attr_header */
397 } apple_double_header_t
;
399 #define ADHDRSIZE (4+4+16+2)
401 /* Entries are aligned on 4 byte boundaries */
402 typedef struct attr_entry
{
403 u_int32_t offset
; /* file offset to data */
404 u_int32_t length
; /* size of attribute data */
407 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
411 /* Header + entries must fit into 64K */
412 typedef struct attr_header
{
413 apple_double_header_t appledouble
;
414 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
415 u_int32_t debug_tag
; /* for debugging == file id of owning file */
416 u_int32_t total_size
; /* total size of attribute header + entries + data */
417 u_int32_t data_start
; /* file offset to attribute data area */
418 u_int32_t data_length
; /* length of attribute data area */
419 u_int32_t reserved
[3];
425 /* Empty Resource Fork Header */
426 typedef struct rsrcfork_header
{
427 u_int32_t fh_DataOffset
;
428 u_int32_t fh_MapOffset
;
429 u_int32_t fh_DataLength
;
430 u_int32_t fh_MapLength
;
431 u_int8_t systemData
[112];
432 u_int8_t appData
[128];
433 u_int32_t mh_DataOffset
;
434 u_int32_t mh_MapOffset
;
435 u_int32_t mh_DataLength
;
436 u_int32_t mh_MapLength
;
440 u_int8_t mh_InMemoryAttr
;
446 #define RF_FIRST_RESOURCE 256
447 #define RF_NULL_MAP_LENGTH 30
448 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
450 #pragma options align=reset
452 /* Runtime information about the attribute file. */
453 typedef struct attr_info
{
454 vfs_context_t context
;
459 size_t rawsize
; /* raw size of AppleDouble file */
460 apple_double_header_t
*filehdr
;
461 apple_double_entry_t
*finderinfo
;
462 apple_double_entry_t
*rsrcfork
;
463 attr_header_t
*attrhdr
;
464 attr_entry_t
*attr_entry
;
466 u_int8_t emptyfinderinfo
;
470 #define ATTR_SETTING 1
472 #define ATTR_ALIGN 3L /* Use four-byte alignment */
474 #define ATTR_ENTRY_LENGTH(namelen) \
475 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
477 #define ATTR_NEXT(ae) \
478 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
480 #define ATTR_VALID(ae, ai) \
481 ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize))
484 #define SWAP16(x) NXSwapBigShortToHost((x))
485 #define SWAP32(x) NXSwapBigIntToHost((x))
486 #define SWAP64(x) NXSwapBigLongLongToHost((x))
489 static u_int32_t emptyfinfo
[8] = {0};
493 * Local support routines
495 static void close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
);
497 static int open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
);
499 static int create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
);
501 static int remove_xattrfile(vnode_t xvp
, vfs_context_t context
);
503 static int get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
);
505 static void rel_xattrinfo(attr_info_t
*ainfop
);
507 static int write_xattrinfo(attr_info_t
*ainfop
);
509 static void init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
);
511 static int lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
);
513 static int unlock_xattrfile(vnode_t xvp
, vfs_context_t context
);
516 #if BYTE_ORDER == LITTLE_ENDIAN
517 static void swap_adhdr(apple_double_header_t
*adh
);
518 static void swap_attrhdr(attr_header_t
*ah
);
521 #define swap_adhdr(x)
522 #define swap_attrhdr(x)
525 static int validate_attrhdr(attr_header_t
*ah
, size_t bufsize
);
526 static int shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
527 static int shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
);
531 * Retrieve the data of an extended attribute.
534 default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
,
535 __unused
int options
, vfs_context_t context
)
539 attr_header_t
*header
;
550 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
553 * Open the file locked (shared) since the Carbon
554 * File Manager may have the Apple Double file open
555 * and could be changing the resource fork.
557 fileflags
|= O_SHLOCK
;
562 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
565 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
566 close_xattrfile(xvp
, fileflags
, context
);
570 /* Get the Finder Info. */
571 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
573 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
575 } else if (uio
== NULL
) {
576 *size
= FINDERINFOSIZE
;
578 } else if (uio_offset(uio
) != 0) {
580 } else if (uio_resid(uio
) < FINDERINFOSIZE
) {
583 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
584 error
= uiomove((caddr_t
)attrdata
, FINDERINFOSIZE
, uio
);
589 /* Read the Resource Fork. */
591 if (!vnode_isreg(vp
)) {
593 } else if (ainfo
.rsrcfork
== NULL
) {
595 } else if (uio
== NULL
) {
596 *size
= (size_t)ainfo
.rsrcfork
->length
;
598 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
599 error
= VNOP_READ(xvp
, uio
, 0, context
);
601 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
606 if (ainfo
.attrhdr
== NULL
|| ainfo
.attr_entry
== NULL
) {
610 if (uio_offset(uio
) != 0) {
615 namelen
= strlen(name
) + 1;
616 header
= ainfo
.attrhdr
;
617 entry
= ainfo
.attr_entry
;
619 * Search for attribute name in the header.
621 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
622 if (strncmp(entry
->name
, name
, namelen
) == 0) {
623 datalen
= (size_t)entry
->length
;
629 if (uio_resid(uio
) < datalen
) {
633 if (entry
->offset
+ datalen
< ATTR_MAX_HDR_SIZE
) {
634 attrdata
= ((u_int8_t
*)header
+ entry
->offset
);
635 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
637 uio_setoffset(uio
, entry
->offset
);
638 error
= VNOP_READ(xvp
, uio
, 0, context
);
639 uio_setoffset(uio
, 0);
643 entry
= ATTR_NEXT(entry
);
646 rel_xattrinfo(&ainfo
);
647 close_xattrfile(xvp
, fileflags
, context
);
653 * Set the data of an extended attribute.
656 default_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
660 attr_header_t
*header
;
662 attr_entry_t
*lastentry
;
666 size_t datafreespace
;
674 datalen
= uio_resid(uio
);
675 namelen
= strlen(name
) + 1;
676 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
678 if (datalen
> ATTR_MAX_SIZE
) {
679 return (E2BIG
); /* EINVAL instead ? */
683 * Open the file locked since setting an attribute
684 * can change the layout of the Apple Double file.
686 fileflags
= FREAD
| FWRITE
| O_EXLOCK
;
687 if ((error
= open_xattrfile(vp
, O_CREAT
| fileflags
, &xvp
, context
))) {
690 if ((error
= get_xattrinfo(xvp
, ATTR_SETTING
, &ainfo
, context
))) {
691 close_xattrfile(xvp
, fileflags
, context
);
695 /* Set the Finder Info. */
696 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
697 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
698 /* attr exists and "create" was specified? */
699 if (options
& XATTR_CREATE
) {
704 /* attr doesn't exists and "replace" was specified? */
705 if (options
& XATTR_REPLACE
) {
710 if (uio_offset(uio
) != 0 || datalen
!= FINDERINFOSIZE
) {
714 if (ainfo
.finderinfo
) {
715 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
716 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
719 ainfo
.iosize
= sizeof(attr_header_t
);
720 error
= write_xattrinfo(&ainfo
);
727 /* Write the Resource Fork. */
728 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
731 if (!vnode_isreg(vp
)) {
735 if (ainfo
.rsrcfork
&& ainfo
.rsrcfork
->length
) {
736 /* attr exists and "create" was specified? */
737 if (options
& XATTR_CREATE
) {
742 /* attr doesn't exists and "replace" was specified? */
743 if (options
& XATTR_REPLACE
) {
748 endoffset
= uio_resid(uio
) + uio_offset(uio
); /* new size */
749 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
);
750 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
753 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
);
754 if (endoffset
> ainfo
.rsrcfork
->length
) {
755 ainfo
.rsrcfork
->length
= endoffset
;
756 ainfo
.iosize
= sizeof(attr_header_t
);
757 error
= write_xattrinfo(&ainfo
);
763 if (ainfo
.attrhdr
== NULL
) {
767 header
= ainfo
.attrhdr
;
768 entry
= ainfo
.attr_entry
;
770 /* Check if data area crosses the maximum header size. */
771 if ((header
->data_start
+ header
->data_length
+ entrylen
+ datalen
) > ATTR_MAX_HDR_SIZE
)
772 splitdata
= 1; /* do data I/O separately */
777 * See if attribute already exists.
779 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
780 if (strncmp(entry
->name
, name
, namelen
) == 0) {
784 entry
= ATTR_NEXT(entry
);
788 if (options
& XATTR_CREATE
) {
792 if (datalen
== entry
->length
) {
794 uio_setoffset(uio
, entry
->offset
);
795 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
796 uio_setoffset(uio
, 0);
798 printf("setxattr: VNOP_WRITE error %d\n", error
);
801 attrdata
= (u_int8_t
*)header
+ entry
->offset
;
802 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
805 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
806 error
= write_xattrinfo(&ainfo
);
808 printf("setxattr: write_xattrinfo error %d\n", error
);
814 * Brute force approach - just remove old entry and set new entry.
817 rel_xattrinfo(&ainfo
);
818 close_xattrfile(xvp
, fileflags
, context
);
819 error
= default_removexattr(vp
, name
, options
, context
);
823 goto start
; /* start over */
828 if (options
& XATTR_REPLACE
) {
829 error
= ENOATTR
; /* nothing there to replace */
832 /* Check if header size limit has been reached. */
833 if ((header
->data_start
+ entrylen
) > ATTR_MAX_HDR_SIZE
) {
838 datafreespace
= header
->total_size
- (header
->data_start
+ header
->data_length
);
840 /* Check if we need more space. */
841 if ((datalen
+ entrylen
) > datafreespace
) {
844 growsize
= roundup((datalen
+ entrylen
) - datafreespace
, ATTR_BUF_SIZE
);
846 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */
847 if (!splitdata
&& (header
->total_size
+ growsize
) > ATTR_MAX_HDR_SIZE
) {
848 growsize
= ATTR_MAX_HDR_SIZE
- header
->total_size
;
851 ainfo
.filesize
+= growsize
;
852 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
854 printf("setxattr: VNOP_TRUNCATE error %d\n", error
);
860 * Move the resource fork out of the way.
862 if (ainfo
.rsrcfork
) {
863 if (ainfo
.rsrcfork
->length
!= 0) {
865 ainfo
.rsrcfork
->offset
,
866 ainfo
.rsrcfork
->length
,
869 ainfo
.rsrcfork
->offset
+= growsize
;
871 ainfo
.finderinfo
->length
+= growsize
;
872 header
->total_size
+= growsize
;
875 /* Make space for a new entry. */
882 bcopy((u_int8_t
*)header
+ header
->data_start
,
883 (u_int8_t
*)header
+ header
->data_start
+ entrylen
,
884 header
->data_length
);
886 header
->data_start
+= entrylen
;
888 /* Fix up entry data offsets. */
890 for (entry
= ainfo
.attr_entry
; entry
!= lastentry
&& ATTR_VALID(entry
, ainfo
); entry
= ATTR_NEXT(entry
)) {
891 entry
->offset
+= entrylen
;
895 * If the attribute data area is entirely within
896 * the header buffer, then just update the buffer,
897 * otherwise we'll write it separately to the file.
902 /* Write new attribute data after the end of existing data. */
903 offset
= header
->data_start
+ header
->data_length
;
904 uio_setoffset(uio
, offset
);
905 error
= VNOP_WRITE(xvp
, uio
, 0, context
);
906 uio_setoffset(uio
, 0);
908 printf("setxattr: VNOP_WRITE error %d\n", error
);
912 attrdata
= (u_int8_t
*)header
+ header
->data_start
+ header
->data_length
;
914 error
= uiomove((caddr_t
)attrdata
, datalen
, uio
);
916 printf("setxattr: uiomove error %d\n", error
);
921 /* Create the attribute entry. */
922 lastentry
->length
= datalen
;
923 lastentry
->offset
= header
->data_start
+ header
->data_length
;
924 lastentry
->namelen
= namelen
;
925 lastentry
->flags
= 0;
926 bcopy(name
, &lastentry
->name
[0], namelen
);
928 /* Update the attributes header. */
930 header
->data_length
+= datalen
;
933 /* Only write the entries, since the data was written separately. */
934 ainfo
.iosize
= ainfo
.attrhdr
->data_start
;
936 /* The entry and data are both in the header; write them together. */
937 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
939 error
= write_xattrinfo(&ainfo
);
941 printf("setxattr: write_xattrinfo error %d\n", error
);
945 rel_xattrinfo(&ainfo
);
946 close_xattrfile(xvp
, fileflags
, context
);
948 /* Touch the change time if we changed an attribute. */
950 struct vnode_attr va
;
952 /* Re-write the mtime to cause a ctime change. */
954 VATTR_WANTED(&va
, va_modify_time
);
955 if (vnode_getattr(vp
, &va
, context
) == 0) {
957 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
958 (void) vnode_setattr(vp
, &va
, context
);
966 * Remove an extended attribute.
969 default_removexattr(vnode_t vp
, const char *name
, __unused
int options
, vfs_context_t context
)
973 attr_header_t
*header
;
975 attr_entry_t
*oldslot
;
981 int found
= 0, lastone
= 0;
989 fileflags
= FREAD
| FWRITE
;
990 if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) {
993 * Open the file locked (exclusive) since the Carbon
994 * File Manager may have the Apple Double file open
995 * and could be changing the resource fork.
997 fileflags
|= O_EXLOCK
;
1002 if ((error
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) {
1005 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1006 close_xattrfile(xvp
, fileflags
, context
);
1010 attrcount
+= ainfo
.attrhdr
->num_attrs
;
1013 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
)
1016 /* Clear the Finder Info. */
1017 if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) {
1018 if (ainfo
.finderinfo
== NULL
|| ainfo
.emptyfinderinfo
) {
1022 /* On removal of last attribute the ._ file is removed. */
1023 if (--attrcount
== 0)
1025 attrdata
= (u_int8_t
*)ainfo
.filehdr
+ ainfo
.finderinfo
->offset
;
1026 bzero((caddr_t
)attrdata
, FINDERINFOSIZE
);
1027 ainfo
.iosize
= sizeof(attr_header_t
);
1028 error
= write_xattrinfo(&ainfo
);
1032 /* Clear the Resource Fork. */
1034 if (!vnode_isreg(vp
)) {
1038 if (ainfo
.rsrcfork
== NULL
|| ainfo
.rsrcfork
->length
== 0) {
1042 /* On removal of last attribute the ._ file is removed. */
1043 if (--attrcount
== 0)
1047 * If the resource fork isn't the last AppleDouble
1048 * entry then the space needs to be reclaimed by
1049 * shifting the entries after the resource fork.
1051 if ((ainfo
.rsrcfork
->offset
+ ainfo
.rsrcfork
->length
) == ainfo
.filesize
) {
1052 ainfo
.filesize
-= ainfo
.rsrcfork
->length
;
1053 error
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
);
1056 ainfo
.rsrcfork
->length
= 0;
1057 ainfo
.iosize
= sizeof(attr_header_t
);
1058 error
= write_xattrinfo(&ainfo
);
1063 if (ainfo
.attrhdr
== NULL
) {
1067 namelen
= strlen(name
) + 1;
1068 header
= ainfo
.attrhdr
;
1069 entry
= ainfo
.attr_entry
;
1072 * See if this attribute exists.
1074 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1075 if (strncmp(entry
->name
, name
, namelen
) == 0) {
1077 if ((i
+1) == header
->num_attrs
)
1081 entry
= ATTR_NEXT(entry
);
1087 /* On removal of last attribute the ._ file is removed. */
1088 if (--attrcount
== 0)
1091 datalen
= entry
->length
;
1092 dataoff
= entry
->offset
;
1093 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
1094 if ((header
->data_start
+ header
->data_length
) > ATTR_MAX_HDR_SIZE
)
1099 /* Remove the attribute entry. */
1101 bcopy((u_int8_t
*)entry
+ entrylen
, (u_int8_t
*)entry
,
1102 ((size_t)header
+ header
->data_start
) - ((size_t)entry
+ entrylen
));
1105 /* Adjust the attribute data. */
1109 dataoff
- header
->data_start
,
1115 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
),
1119 /* XXX write zeros to freed space ? */
1120 ainfo
.iosize
= ainfo
.attrhdr
->data_start
- entrylen
;
1124 bcopy((u_int8_t
*)header
+ header
->data_start
,
1125 (u_int8_t
*)header
+ header
->data_start
- entrylen
,
1126 dataoff
- header
->data_start
);
1128 bcopy((u_int8_t
*)header
+ dataoff
+ datalen
,
1129 (u_int8_t
*)header
+ dataoff
- entrylen
,
1130 (header
->data_start
+ header
->data_length
) - (dataoff
+ datalen
));
1132 bzero (((u_int8_t
*)header
+ header
->data_start
+ header
->data_length
) - (datalen
+ entrylen
), (datalen
+ entrylen
));
1133 ainfo
.iosize
= ainfo
.attrhdr
->data_start
+ ainfo
.attrhdr
->data_length
;
1136 /* Adjust the header values and entry offsets. */
1137 header
->num_attrs
--;
1138 header
->data_start
-= entrylen
;
1139 header
->data_length
-= datalen
;
1142 entry
= ainfo
.attr_entry
;
1143 for (i
= 0; i
< header
->num_attrs
&& ATTR_VALID(entry
, ainfo
); i
++) {
1144 entry
->offset
-= entrylen
;
1145 if (entry
>= oldslot
)
1146 entry
->offset
-= datalen
;
1147 entry
= ATTR_NEXT(entry
);
1149 error
= write_xattrinfo(&ainfo
);
1151 printf("removexattr: write_xattrinfo error %d\n", error
);
1154 rel_xattrinfo(&ainfo
);
1156 /* When there are no more attributes remove the ._ file. */
1157 if (attrcount
== 0) {
1158 if (fileflags
& O_EXLOCK
)
1159 (void) unlock_xattrfile(xvp
, context
);
1160 VNOP_CLOSE(xvp
, fileflags
, context
);
1162 error
= remove_xattrfile(xvp
, context
);
1165 close_xattrfile(xvp
, fileflags
, context
);
1167 /* Touch the change time if we changed an attribute. */
1169 struct vnode_attr va
;
1171 /* Re-write the mtime to cause a ctime change. */
1173 VATTR_WANTED(&va
, va_modify_time
);
1174 if (vnode_getattr(vp
, &va
, context
) == 0) {
1176 VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
);
1177 (void) vnode_setattr(vp
, &va
, context
);
1186 * Retrieve the list of extended attribute names.
1189 default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, __unused
int options
, vfs_context_t context
)
1193 attr_entry_t
*entry
;
1198 * We do not zero "*size" here as we don't want to stomp a size set when
1199 * VNOP_LISTXATTR processed any native EAs. That size is initially zeroed by the
1200 * system call layer, up in listxattr or flistxattr.
1203 if ((error
= open_xattrfile(vp
, FREAD
, &xvp
, context
))) {
1204 if (error
== ENOATTR
)
1208 if ((error
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) {
1209 close_xattrfile(xvp
, FREAD
, context
);
1213 /* Check for Finder Info. */
1214 if (ainfo
.finderinfo
&& !ainfo
.emptyfinderinfo
) {
1216 *size
+= sizeof(XATTR_FINDERINFO_NAME
);
1217 } else if (uio_resid(uio
) < sizeof(XATTR_FINDERINFO_NAME
)) {
1221 error
= uiomove((caddr_t
)XATTR_FINDERINFO_NAME
,
1222 sizeof(XATTR_FINDERINFO_NAME
), uio
);
1230 /* Check for Resource Fork. */
1231 if (vnode_isreg(vp
) && ainfo
.rsrcfork
) {
1233 *size
+= sizeof(XATTR_RESOURCEFORK_NAME
);
1234 } else if (uio_resid(uio
) < sizeof(XATTR_RESOURCEFORK_NAME
)) {
1238 error
= uiomove((caddr_t
)XATTR_RESOURCEFORK_NAME
,
1239 sizeof(XATTR_RESOURCEFORK_NAME
), uio
);
1247 /* Check for attributes. */
1248 if (ainfo
.attrhdr
) {
1249 count
= ainfo
.attrhdr
->num_attrs
;
1250 for (i
= 0, entry
= ainfo
.attr_entry
; i
< count
&& ATTR_VALID(entry
, ainfo
); i
++) {
1251 if (xattr_protected(entry
->name
) ||
1252 xattr_validatename(entry
->name
) != 0) {
1253 entry
= ATTR_NEXT(entry
);
1257 *size
+= entry
->namelen
;
1258 entry
= ATTR_NEXT(entry
);
1261 if (uio_resid(uio
) < entry
->namelen
) {
1265 error
= uiomove((caddr_t
) entry
->name
, entry
->namelen
, uio
);
1267 if (error
!= EFAULT
)
1271 entry
= ATTR_NEXT(entry
);
1275 rel_xattrinfo(&ainfo
);
1276 close_xattrfile(xvp
, FREAD
, context
);
1282 open_xattrfile(vnode_t vp
, int fileflags
, vnode_t
*xvpp
, vfs_context_t context
)
1284 vnode_t xvp
= NULLVP
;
1285 vnode_t dvp
= NULLVP
;
1286 struct vnode_attr va
;
1287 struct nameidata nd
;
1289 char *filename
= NULL
;
1290 char *basename
= NULL
;
1296 if (vnode_isvroot(vp
) && vnode_isdir(vp
)) {
1298 * For the root directory use "._." to hold the attributes.
1300 filename
= &smallname
[0];
1301 sprintf(filename
, "%s%s", ATTR_FILE_PREFIX
, ".");
1302 dvp
= vp
; /* the "._." file resides in the root dir */
1305 if ( (dvp
= vnode_getparent(vp
)) == NULLVP
) {
1309 if ( (basename
= vnode_getname(vp
)) == NULL
) {
1314 /* "._" Attribute files cannot have attributes */
1315 if (vp
->v_type
== VREG
&& strlen(basename
) > 2 &&
1316 basename
[0] == '.' && basename
[1] == '_') {
1320 filename
= &smallname
[0];
1321 len
= snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, basename
);
1322 if (len
>= sizeof(smallname
)) {
1323 len
++; /* snprintf result doesn't include '\0' */
1324 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
1325 len
= snprintf(filename
, len
, "%s%s", ATTR_FILE_PREFIX
, basename
);
1328 * Note that the lookup here does not authorize. Since we are looking
1329 * up in the same directory that we already have the file vnode in,
1330 * we must have been given the file vnode legitimately. Read/write
1331 * access has already been authorized in layers above for calls from
1332 * userspace, and the authorization code using this path to read
1333 * file security from the EA must always get access
1336 NDINIT(&nd
, LOOKUP
, LOCKLEAF
| NOFOLLOW
| USEDVP
| DONOTAUTH
, UIO_SYSSPACE
,
1337 CAST_USER_ADDR_T(filename
), context
);
1340 if (fileflags
& O_CREAT
) {
1341 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1343 nd
.ni_cnd
.cn_flags
|= LOCKPARENT
;
1345 if ( (error
= namei(&nd
))) {
1350 if ( (xvp
= nd
.ni_vp
) == NULLVP
) {
1356 * Pick up uid/gid/mode from target file.
1359 VATTR_WANTED(&va
, va_uid
);
1360 VATTR_WANTED(&va
, va_gid
);
1361 VATTR_WANTED(&va
, va_mode
);
1362 if (VNOP_GETATTR(vp
, &va
, context
) == 0 &&
1363 VATTR_IS_SUPPORTED(&va
, va_uid
) &&
1364 VATTR_IS_SUPPORTED(&va
, va_gid
) &&
1365 VATTR_IS_SUPPORTED(&va
, va_mode
)) {
1368 umode
= va
.va_mode
& (S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
);
1369 } else /* fallback values */ {
1370 uid
= KAUTH_UID_NONE
;
1371 gid
= KAUTH_GID_NONE
;
1372 umode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
;
1376 VATTR_SET(&va
, va_type
, VREG
);
1377 VATTR_SET(&va
, va_mode
, umode
);
1378 if (uid
!= KAUTH_UID_NONE
)
1379 VATTR_SET(&va
, va_uid
, uid
);
1380 if (gid
!= KAUTH_GID_NONE
)
1381 VATTR_SET(&va
, va_gid
, gid
);
1383 error
= vn_create(dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
,
1384 VN_CREATE_NOAUTH
| VN_CREATE_NOINHERIT
,
1391 vnode_put(dvp
); /* drop iocount from LOCKPARENT request above */
1396 if ((error
= namei(&nd
))) {
1406 if (xvp
->v_type
!= VREG
) {
1411 * Owners must match.
1414 VATTR_WANTED(&va
, va_uid
);
1415 if (VNOP_GETATTR(vp
, &va
, context
) == 0 && VATTR_IS_SUPPORTED(&va
, va_uid
)) {
1416 uid_t owner
= va
.va_uid
;
1419 VATTR_WANTED(&va
, va_uid
);
1420 if (VNOP_GETATTR(xvp
, &va
, context
) == 0 && (owner
!= va
.va_uid
)) {
1421 error
= ENOATTR
; /* don't use this "._" file */
1426 if ( (error
= VNOP_OPEN(xvp
, fileflags
, context
))) {
1432 if ((error
= vnode_ref(xvp
))) {
1437 /* If create was requested, make sure file header exists. */
1438 if (fileflags
& O_CREAT
) {
1440 VATTR_WANTED(&va
, va_data_size
);
1441 VATTR_WANTED(&va
, va_fileid
);
1442 VATTR_WANTED(&va
, va_nlink
);
1443 if ( (error
= vnode_getattr(xvp
, &va
, context
)) != 0) {
1448 /* If the file is empty then add a default header. */
1449 if (va
.va_data_size
== 0) {
1450 /* Don't adopt hard-linked "._" files. */
1451 if (VATTR_IS_SUPPORTED(&va
, va_nlink
) && va
.va_nlink
> 1) {
1455 if ( (error
= create_xattrfile(xvp
, (u_int32_t
)va
.va_fileid
, context
)))
1459 /* Apply file locking if requested. */
1460 if (fileflags
& (O_EXLOCK
| O_SHLOCK
)) {
1463 locktype
= (fileflags
& O_EXLOCK
) ? F_WRLCK
: F_RDLCK
;
1464 error
= lock_xattrfile(xvp
, locktype
, context
);
1467 if (dvp
&& (dvp
!= vp
)) {
1471 vnode_putname(basename
);
1473 if (filename
&& filename
!= &smallname
[0]) {
1474 FREE(filename
, M_TEMP
);
1477 if (xvp
!= NULLVP
) {
1479 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
1482 (void) vnode_rele(xvp
);
1484 (void) vnode_put(xvp
);
1487 if ((error
== ENOATTR
) && (fileflags
& O_CREAT
)) {
1491 *xvpp
= xvp
; /* return a referenced vnode */
1496 close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
)
1498 // if (fileflags & FWRITE)
1499 // (void) VNOP_FSYNC(xvp, MNT_WAIT, context);
1501 if (fileflags
& (O_EXLOCK
| O_SHLOCK
))
1502 (void) unlock_xattrfile(xvp
, context
);
1504 (void) VNOP_CLOSE(xvp
, fileflags
, context
);
1505 (void) vnode_rele(xvp
);
1506 (void) vnode_put(xvp
);
1510 remove_xattrfile(vnode_t xvp
, vfs_context_t context
)
1513 struct nameidata nd
;
1518 path
= get_pathbuff();
1519 pathlen
= MAXPATHLEN
;
1520 vn_getpath(xvp
, path
, &pathlen
);
1522 NDINIT(&nd
, DELETE
, LOCKPARENT
| NOFOLLOW
| DONOTAUTH
,
1523 UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), context
);
1525 release_pathbuff(path
);
1532 error
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, context
);
1541 get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t
*ainfop
, vfs_context_t context
)
1544 void * buffer
= NULL
;
1545 apple_double_header_t
*filehdr
;
1546 attr_header_t
*attrhdr
;
1547 struct vnode_attr va
;
1552 bzero(ainfop
, sizeof(attr_info_t
));
1553 ainfop
->filevp
= xvp
;
1554 ainfop
->context
= context
;
1556 VATTR_WANTED(&va
, va_data_size
);
1557 VATTR_WANTED(&va
, va_fileid
);
1558 if ((error
= vnode_getattr(xvp
, &va
, context
))) {
1561 ainfop
->filesize
= va
.va_data_size
;
1563 /* When setting attributes, allow room for the header to grow. */
1565 iosize
= ATTR_MAX_HDR_SIZE
;
1567 iosize
= MIN(ATTR_MAX_HDR_SIZE
, ainfop
->filesize
);
1573 ainfop
->iosize
= iosize
;
1574 MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
);
1575 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_READ
);
1576 uio_addiov(auio
, (uintptr_t)buffer
, iosize
);
1578 /* Read the file header. */
1579 error
= VNOP_READ(xvp
, auio
, 0, context
);
1583 ainfop
->rawsize
= iosize
- uio_resid(auio
);
1584 ainfop
->rawdata
= (u_int8_t
*)buffer
;
1586 filehdr
= (apple_double_header_t
*)buffer
;
1588 /* Check for Apple Double file. */
1589 if (SWAP32(filehdr
->magic
) != ADH_MAGIC
||
1590 SWAP32(filehdr
->version
) != ADH_VERSION
||
1591 SWAP16(filehdr
->numEntries
) < 1 ||
1592 SWAP16(filehdr
->numEntries
) > 15) {
1596 if (ADHDRSIZE
+ (SWAP16(filehdr
->numEntries
) * sizeof(apple_double_entry_t
)) > ainfop
->rawsize
) {
1601 swap_adhdr(filehdr
);
1602 ainfop
->filehdr
= filehdr
; /* valid AppleDouble header */
1603 /* rel_xattrinfo is responsible for freeing the header buffer */
1606 /* Check the AppleDouble entries. */
1607 for (i
= 0; i
< filehdr
->numEntries
; ++i
) {
1608 if (filehdr
->entries
[i
].type
== AD_FINDERINFO
&&
1609 filehdr
->entries
[i
].length
> 0) {
1610 ainfop
->finderinfo
= &filehdr
->entries
[i
];
1611 attrhdr
= (attr_header_t
*)filehdr
;
1613 if (bcmp((u_int8_t
*)ainfop
->filehdr
+ ainfop
->finderinfo
->offset
,
1614 emptyfinfo
, sizeof(emptyfinfo
)) == 0) {
1615 ainfop
->emptyfinderinfo
= 1;
1621 /* See if we need to convert this AppleDouble file. */
1622 if (filehdr
->entries
[0].length
== FINDERINFOSIZE
) {
1627 filehdr
->entries
[1].type
!= AD_RESOURCE
||
1628 filehdr
->numEntries
> 2) {
1629 continue; /* not expected layout */
1631 delta
= ATTR_BUF_SIZE
- (filehdr
->entries
[0].offset
+ FINDERINFOSIZE
);
1632 if (filehdr
->entries
[1].length
) {
1633 /* Make some room. */
1634 shift_data_down(xvp
,
1635 filehdr
->entries
[1].offset
,
1636 filehdr
->entries
[1].length
,
1638 writesize
= sizeof(attr_header_t
);
1640 rsrcfork_header_t
*rsrcforkhdr
;
1642 vnode_setsize(xvp
, filehdr
->entries
[1].offset
+ delta
, 0, context
);
1644 /* Steal some space for an empty RF header. */
1645 delta
-= sizeof(rsrcfork_header_t
);
1647 bzero(&attrhdr
->appledouble
.pad
[0], delta
);
1648 rsrcforkhdr
= (rsrcfork_header_t
*)((char *)filehdr
+ filehdr
->entries
[1].offset
+ delta
);
1650 /* Fill in Empty Resource Fork Header. */
1651 init_empty_resource_fork(rsrcforkhdr
);
1653 filehdr
->entries
[1].length
= sizeof(rsrcfork_header_t
);
1654 writesize
= ATTR_BUF_SIZE
;
1656 filehdr
->entries
[0].length
+= delta
;
1657 filehdr
->entries
[1].offset
+= delta
;
1659 /* Fill in Attribute Header. */
1660 attrhdr
->magic
= ATTR_HDR_MAGIC
;
1661 attrhdr
->debug_tag
= (u_int32_t
)va
.va_fileid
;
1662 attrhdr
->total_size
= filehdr
->entries
[1].offset
;
1663 attrhdr
->data_start
= sizeof(attr_header_t
);
1664 attrhdr
->data_length
= 0;
1665 attrhdr
->reserved
[0] = 0;
1666 attrhdr
->reserved
[1] = 0;
1667 attrhdr
->reserved
[2] = 0;
1669 attrhdr
->num_attrs
= 0;
1671 /* Push out new header */
1672 uio_reset(auio
, 0, UIO_SYSSPACE32
, UIO_WRITE
);
1673 uio_addiov(auio
, (uintptr_t)filehdr
, writesize
);
1675 swap_adhdr(filehdr
);
1676 swap_attrhdr(attrhdr
);
1677 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
1678 swap_adhdr(filehdr
);
1679 /* The attribute header gets swapped below. */
1681 if (SWAP32 (attrhdr
->magic
) != ATTR_HDR_MAGIC
||
1682 validate_attrhdr(attrhdr
, ainfop
->rawsize
) != 0) {
1683 printf("get_xattrinfo: invalid attribute header\n");
1686 swap_attrhdr(attrhdr
);
1687 ainfop
->attrhdr
= attrhdr
; /* valid attribute header */
1688 ainfop
->attr_entry
= (attr_entry_t
*)&attrhdr
[1];
1691 if (filehdr
->entries
[i
].type
== AD_RESOURCE
&&
1692 (filehdr
->entries
[i
].length
> sizeof(rsrcfork_header_t
) || setting
)) {
1693 ainfop
->rsrcfork
= &filehdr
->entries
[i
];
1694 if (i
!= (filehdr
->numEntries
- 1)) {
1695 printf("get_xattrinfo: resource fork not last entry\n");
1696 ainfop
->readonly
= 1;
1706 FREE(buffer
, M_TEMP
);
1712 create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
)
1715 rsrcfork_header_t
*rsrcforkhdr
;
1721 MALLOC(buffer
, void *, ATTR_BUF_SIZE
, M_TEMP
, M_WAITOK
);
1722 bzero(buffer
, ATTR_BUF_SIZE
);
1724 xah
= (attr_header_t
*)buffer
;
1725 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_WRITE
);
1726 uio_addiov(auio
, (uintptr_t)buffer
, ATTR_BUF_SIZE
);
1727 rsrcforksize
= sizeof(rsrcfork_header_t
);
1728 rsrcforkhdr
= (rsrcfork_header_t
*) ((char *)buffer
+ ATTR_BUF_SIZE
- rsrcforksize
);
1730 /* Fill in Apple Double Header. */
1731 xah
->appledouble
.magic
= SWAP32 (ADH_MAGIC
);
1732 xah
->appledouble
.version
= SWAP32 (ADH_VERSION
);
1733 xah
->appledouble
.numEntries
= SWAP16 (2);
1734 xah
->appledouble
.entries
[0].type
= SWAP32 (AD_FINDERINFO
);
1735 xah
->appledouble
.entries
[0].offset
= SWAP32 (offsetof(apple_double_header_t
, finfo
));
1736 xah
->appledouble
.entries
[0].length
= SWAP32 (ATTR_BUF_SIZE
- offsetof(apple_double_header_t
, finfo
) - rsrcforksize
);
1737 xah
->appledouble
.entries
[1].type
= SWAP32 (AD_RESOURCE
);
1738 xah
->appledouble
.entries
[1].offset
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
1739 xah
->appledouble
.entries
[1].length
= SWAP32 (rsrcforksize
);
1740 bcopy(ADH_MACOSX
, xah
->appledouble
.filler
, sizeof(xah
->appledouble
.filler
));
1742 /* Fill in Attribute Header. */
1743 xah
->magic
= SWAP32 (ATTR_HDR_MAGIC
);
1744 xah
->debug_tag
= SWAP32 (fileid
);
1745 xah
->total_size
= SWAP32 (ATTR_BUF_SIZE
- rsrcforksize
);
1746 xah
->data_start
= SWAP32 (sizeof(attr_header_t
));
1748 /* Fill in Empty Resource Fork Header. */
1749 init_empty_resource_fork(rsrcforkhdr
);
1752 error
= VNOP_WRITE(xvp
, auio
, 0, context
);
1755 FREE(buffer
, M_TEMP
);
1761 init_empty_resource_fork(rsrcfork_header_t
* rsrcforkhdr
)
1763 bzero(rsrcforkhdr
, sizeof(rsrcfork_header_t
));
1764 rsrcforkhdr
->fh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
1765 rsrcforkhdr
->fh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
1766 rsrcforkhdr
->fh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
1767 rsrcforkhdr
->mh_DataOffset
= SWAP32 (RF_FIRST_RESOURCE
);
1768 rsrcforkhdr
->mh_MapOffset
= SWAP32 (RF_FIRST_RESOURCE
);
1769 rsrcforkhdr
->mh_MapLength
= SWAP32 (RF_NULL_MAP_LENGTH
);
1770 rsrcforkhdr
->mh_Types
= SWAP16 (RF_NULL_MAP_LENGTH
- 2 );
1771 rsrcforkhdr
->mh_Names
= SWAP16 (RF_NULL_MAP_LENGTH
);
1772 rsrcforkhdr
->typeCount
= SWAP16 (-1);
1773 bcopy(RF_EMPTY_TAG
, rsrcforkhdr
->systemData
, sizeof(RF_EMPTY_TAG
));
1777 rel_xattrinfo(attr_info_t
*ainfop
)
1779 FREE(ainfop
->filehdr
, M_TEMP
);
1780 bzero(ainfop
, sizeof(attr_info_t
));
1784 write_xattrinfo(attr_info_t
*ainfop
)
1789 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_WRITE
);
1790 uio_addiov(auio
, (uintptr_t)ainfop
->filehdr
, ainfop
->iosize
);
1792 swap_adhdr(ainfop
->filehdr
);
1793 swap_attrhdr(ainfop
->attrhdr
);
1795 error
= VNOP_WRITE(ainfop
->filevp
, auio
, 0, ainfop
->context
);
1797 swap_adhdr(ainfop
->filehdr
);
1798 swap_attrhdr(ainfop
->attrhdr
);
1802 #if BYTE_ORDER == LITTLE_ENDIAN
1804 * Endian swap apple double header
1807 swap_adhdr(apple_double_header_t
*adh
)
1812 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
1814 adh
->magic
= SWAP32 (adh
->magic
);
1815 adh
->version
= SWAP32 (adh
->version
);
1816 adh
->numEntries
= SWAP16 (adh
->numEntries
);
1818 for (i
= 0; i
< count
; i
++) {
1819 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
1820 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
1821 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
1826 * Endian swap extended attributes header
1829 swap_attrhdr(attr_header_t
*ah
)
1835 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
1837 ah
->magic
= SWAP32 (ah
->magic
);
1838 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
1839 ah
->total_size
= SWAP32 (ah
->total_size
);
1840 ah
->data_start
= SWAP32 (ah
->data_start
);
1841 ah
->data_length
= SWAP32 (ah
->data_length
);
1842 ah
->flags
= SWAP16 (ah
->flags
);
1843 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
1845 ae
= (attr_entry_t
*)(&ah
[1]);
1846 for (i
= 0; i
< count
; i
++, ae
= ATTR_NEXT(ae
)) {
1847 ae
->offset
= SWAP32 (ae
->offset
);
1848 ae
->length
= SWAP32 (ae
->length
);
1849 ae
->flags
= SWAP16 (ae
->flags
);
1855 * Validate attributes header contents
1858 validate_attrhdr(attr_header_t
*ah
, size_t bufsize
)
1868 bufend
= (u_int8_t
*)ah
+ bufsize
;
1869 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
1871 ae
= (attr_entry_t
*)(&ah
[1]);
1872 for (i
= 0; i
< count
&& (u_int8_t
*)ae
< bufend
; i
++, ae
= ATTR_NEXT(ae
)) {
1874 return (i
< count
? EINVAL
: 0);
1878 // "start" & "end" are byte offsets in the file.
1879 // "to" is the byte offset we want to move the
1880 // data to. "to" should be > "start".
1882 // we do the copy backwards to avoid problems if
1883 // there's an overlap.
1886 shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
1889 size_t chunk
, orig_chunk
;
1892 ucred_t ucred
= vfs_context_ucred(context
);
1893 proc_t p
= vfs_context_proc(context
);
1895 if (delta
== 0 || len
== 0) {
1905 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
1909 for(pos
=start
+len
-chunk
; pos
>= start
; pos
-=chunk
) {
1910 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
, ucred
, &iolen
, p
);
1912 printf("xattr:shift_data: error reading data @ %lld (read %d of %d) (%d)\n",
1913 pos
, ret
, chunk
, ret
);
1917 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
+ delta
, UIO_SYSSPACE
, IO_NODELOCKED
, ucred
, &iolen
, p
);
1919 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %d) (%d)\n",
1920 pos
+delta
, ret
, chunk
, ret
);
1924 if ((pos
- chunk
) < start
) {
1925 chunk
= pos
- start
;
1927 if (chunk
== 0) { // we're all done
1932 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
1939 shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
)
1942 size_t chunk
, orig_chunk
;
1946 ucred_t ucred
= vfs_context_ucred(context
);
1947 proc_t p
= vfs_context_proc(context
);
1949 if (delta
== 0 || len
== 0) {
1960 if (kmem_alloc(kernel_map
, (vm_offset_t
*)&buff
, chunk
)) {
1964 for(pos
= start
; pos
< end
; pos
+= chunk
) {
1965 ret
= vn_rdwr(UIO_READ
, xvp
, buff
, chunk
, pos
, UIO_SYSSPACE
, IO_NODELOCKED
, ucred
, &iolen
, p
);
1967 printf("xattr:shift_data: error reading data @ %lld (read %d of %d) (%d)\n",
1968 pos
, ret
, chunk
, ret
);
1972 ret
= vn_rdwr(UIO_WRITE
, xvp
, buff
, chunk
, pos
- delta
, UIO_SYSSPACE
, IO_NODELOCKED
, ucred
, &iolen
, p
);
1974 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %d) (%d)\n",
1975 pos
+delta
, ret
, chunk
, ret
);
1979 if ((pos
+ chunk
) > end
) {
1982 if (chunk
== 0) { // we're all done
1987 kmem_free(kernel_map
, (vm_offset_t
)buff
, orig_chunk
);
1993 lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
)
1997 lf
.l_whence
= SEEK_SET
;
2000 lf
.l_type
= locktype
; /* F_WRLCK or F_RDLCK */
2001 /* Note: id is just a kernel address that's not a proc */
2002 return VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_SETLK
, &lf
, F_FLOCK
, context
);
2006 unlock_xattrfile(vnode_t xvp
, vfs_context_t context
)
2010 lf
.l_whence
= SEEK_SET
;
2013 lf
.l_type
= F_UNLCK
;
2014 /* Note: id is just a kernel address that's not a proc */
2015 return VNOP_ADVLOCK(xvp
, (caddr_t
)xvp
, F_UNLCK
, &lf
, F_FLOCK
, context
);