2  * Copyright (c) 2004-2005 Apple Computer, 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 #include <sys/param.h> 
  31 #include <sys/fcntl.h> 
  32 #include <sys/fsevents.h> 
  33 #include <sys/kernel.h> 
  34 #include <sys/kauth.h> 
  35 #include <sys/malloc.h> 
  36 #include <sys/namei.h> 
  37 #include <sys/proc_internal.h> 
  40 #include <sys/utfconv.h> 
  41 #include <sys/vnode.h> 
  42 #include <sys/vnode_internal.h> 
  44 #include <sys/xattr.h> 
  46 #include <libkern/OSByteOrder.h> 
  47 #include <vm/vm_kern.h> 
  50  * Default xattr support routines. 
  52 static int default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, 
  53                             int options
, vfs_context_t context
); 
  55 static int default_setxattr(vnode_t vp
, const char *name
, uio_t uio
, 
  56                             int options
, vfs_context_t context
); 
  58 static int default_removexattr(vnode_t vp
, const char *name
, int options
, vfs_context_t context
); 
  60 static int default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
, 
  61                              vfs_context_t context
); 
  66  *  Retrieve the data of an extended attribute. 
  69 vn_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, 
  70             int options
, vfs_context_t context
) 
  74         if (!(vp
->v_type 
== VREG 
|| vp
->v_type 
== VDIR 
|| vp
->v_type 
== VLNK
)) { 
  77         if ((error 
= xattr_validatename(name
))) { 
  80         if (!(options 
& XATTR_NOSECURITY
) && (error 
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
))) 
  83         /* The offset can only be non-zero for resource forks. */ 
  84         if (uio 
!= NULL 
&& uio_offset(uio
) != 0 &&  
  85             bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0) { 
  90         error 
= VNOP_GETXATTR(vp
, name
, uio
, size
, options
, context
); 
  91         if (error 
== ENOTSUP
) { 
  93                  * A filesystem may keep some EAs natively and return ENOTSUP for others. 
  94                  * SMB returns ENOTSUP for finderinfo and resource forks. 
  96                 error 
= default_getxattr(vp
, name
, uio
, size
, options
, context
); 
 103  * Set the data of an extended attribute. 
 106 vn_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
) 
 110         if (!(vp
->v_type 
== VREG 
|| vp
->v_type 
== VDIR 
|| vp
->v_type 
== VLNK
)) { 
 113         if ((options 
& (XATTR_REPLACE
|XATTR_CREATE
)) == (XATTR_REPLACE
|XATTR_CREATE
)) { 
 116         if ((error 
= xattr_validatename(name
))) { 
 119         if (!(options 
& XATTR_NOSECURITY
) && (error 
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
))) 
 122         /* The offset can only be non-zero for resource forks. */ 
 123         if (uio_offset(uio
) != 0 &&  
 124             bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) != 0 ) { 
 129         error 
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
); 
 132          * An EJUSTRETURN is from a filesystem which keeps this xattr 
 133          * natively as well as in a dot-underscore file.  In this case the 
 134          * EJUSTRETURN means the filesytem has done nothing, but identifies the 
 135          * EA as one which may be represented natively and/or in a DU, and 
 136          * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in 
 137          * in vn_setxattr can we do the getxattrs needed to ascertain whether 
 138          * the XATTR_{CREATE,REPLACE} should yield an error. 
 140         if (error 
== EJUSTRETURN
) { 
 141                 int native 
= 0, dufile 
= 0; 
 142                 size_t sz
;      /* not used */ 
 144                 native 
= VNOP_GETXATTR(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1; 
 145                 dufile 
= default_getxattr(vp
, name
, NULL
, &sz
, 0, context
) ? 0 : 1; 
 146                 if (options 
& XATTR_CREATE 
&& (native 
|| dufile
)) { 
 150                 if (options 
& XATTR_REPLACE 
&& !(native 
|| dufile
)) { 
 155                  * Having determined no CREATE/REPLACE error should result, we 
 156                  * zero those bits, so both backing stores get written to. 
 158                 options 
&= ~(XATTR_CREATE 
| XATTR_REPLACE
); 
 159                 error 
= VNOP_SETXATTR(vp
, name
, uio
, options
, context
); 
 160                 /* the mainline path here is to have error==ENOTSUP ... */ 
 162 #endif /* DUAL_EAS */ 
 163         if (error 
== ENOTSUP
) { 
 165                  * A filesystem may keep some EAs natively and return ENOTSUP for others. 
 166                  * SMB returns ENOTSUP for finderinfo and resource forks. 
 168                 error 
= default_setxattr(vp
, name
, uio
, options
, context
); 
 175  * Remove an extended attribute. 
 178 vn_removexattr(vnode_t vp
, const char * name
, int options
, vfs_context_t context
) 
 182         if (!(vp
->v_type 
== VREG 
|| vp
->v_type 
== VDIR 
|| vp
->v_type 
== VLNK
)) { 
 185         if ((error 
= xattr_validatename(name
))) { 
 188         if (!(options 
& XATTR_NOSECURITY
) && (error 
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_EXTATTRIBUTES
, context
))) 
 190         error 
= VNOP_REMOVEXATTR(vp
, name
, options
, context
); 
 191         if (error 
== ENOTSUP
) { 
 193                  * A filesystem may keep some EAs natively and return ENOTSUP for others. 
 194                  * SMB returns ENOTSUP for finderinfo and resource forks. 
 196                 error 
= default_removexattr(vp
, name
, options
, context
); 
 198         } else if (error 
== EJUSTRETURN
) { 
 200                  * EJUSTRETURN is from a filesystem which keeps this xattr natively as well 
 201                  * as in a dot-underscore file.  EJUSTRETURN means the filesytem did remove 
 202                  * a native xattr, so failure to find it in a DU file during 
 203                  * default_removexattr should not be considered an error. 
 205                 error 
= default_removexattr(vp
, name
, options
, context
); 
 206                 if (error 
== ENOATTR
) 
 208 #endif /* DUAL_EAS */ 
 215  * Retrieve the list of extended attribute names. 
 218 vn_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
) 
 222         if (!(vp
->v_type 
== VREG 
|| vp
->v_type 
== VDIR 
|| vp
->v_type 
== VLNK
)) { 
 225         if (!(options 
& XATTR_NOSECURITY
) && (error 
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_EXTATTRIBUTES
, context
))) 
 228         error 
= VNOP_LISTXATTR(vp
, uio
, size
, options
, context
); 
 229         if (error 
== ENOTSUP
) { 
 231                  * A filesystem may keep some but not all EAs natively, in which case 
 232                  * the native EA names will have been uiomove-d out (or *size updated) 
 233                  * and the default_listxattr here will finish the job.  Note SMB takes 
 234                  * advantage of this for its finder-info and resource forks. 
 236                 error 
= default_listxattr(vp
, uio
, size
, options
, context
); 
 243 xattr_validatename(const char *name
) 
 247         if (name 
== NULL 
|| name
[0] == '\0') { 
 250         namelen 
= strlen(name
); 
 251         if (namelen 
> XATTR_MAXNAMELEN
) { 
 252                 return (ENAMETOOLONG
); 
 254         if (utf8_validatestr(name
, namelen
) != 0) { 
 262  * Determine whether an EA is a protected system attribute. 
 265 xattr_protected(const char *attrname
) 
 267         return(!strncmp(attrname
, "com.apple.system.", 17)); 
 272  * Default Implementation (Non-native EA)  
 277    Typical "._" AppleDouble Header File layout: 
 278   ------------------------------------------------------------ 
 283      .-- AD ENTRY[0]    Finder Info Entry (must be first) 
 284   .--+-- AD ENTRY[1]    Resource Fork Entry (must be last) 
 286   |      /////////////  Fixed Size Data (32 bytes) 
 290   |      ATTR ENTRY[1] --+--. 
 291   |      ATTR ENTRY[2] --+--+--. 
 293   |      ATTR ENTRY[N] --+--+--+--. 
 294   |      ATTR DATA 0   <-'  |  |  | 
 296   |      ATTR DATA 1   <----'  |  | 
 298   |      ATTR DATA 2   <-------'  | 
 301   |      ATTR DATA N   <----------' 
 303   |                      Attribute Free Space 
 306          /////////////   Variable Sized Data 
 315   ------------------------------------------------------------ 
 317    NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are 
 318    stored as part of the Finder Info.  The length in the Finder 
 319    Info AppleDouble entry includes the length of the extended 
 320    attribute header, attribute entries, and attribute data. 
 325  * On Disk Data Structures 
 327  * Note: Motorola 68K alignment and big-endian. 
 329  * See RFC 1740 for additional information about the AppleDouble file format. 
 333 #define ADH_MAGIC     0x00051607 
 334 #define ADH_VERSION   0x00020000 
 335 #define ADH_MACOSX    "Mac OS X        " 
 338  * AppleDouble Entry ID's 
 340 #define AD_DATA          1   /* Data fork */ 
 341 #define AD_RESOURCE      2   /* Resource fork */ 
 342 #define AD_REALNAME      3   /* FileÕs name on home file system */ 
 343 #define AD_COMMENT       4   /* Standard Mac comment */ 
 344 #define AD_ICONBW        5   /* Mac black & white icon */ 
 345 #define AD_ICONCOLOR     6   /* Mac color icon */ 
 346 #define AD_UNUSED        7   /* Not used */ 
 347 #define AD_FILEDATES     8   /* File dates; create, modify, etc */ 
 348 #define AD_FINDERINFO    9   /* Mac Finder info & extended info */ 
 349 #define AD_MACINFO      10   /* Mac file info, attributes, etc */ 
 350 #define AD_PRODOSINFO   11   /* Pro-DOS file info, attrib., etc */ 
 351 #define AD_MSDOSINFO    12   /* MS-DOS file info, attributes, etc */ 
 352 #define AD_AFPNAME      13   /* Short name on AFP server */ 
 353 #define AD_AFPINFO      14   /* AFP file info, attrib., etc */ 
 354 #define AD_AFPDIRID     15   /* AFP directory ID */  
 355 #define AD_ATTRIBUTES   AD_FINDERINFO 
 358 #define ATTR_FILE_PREFIX   "._" 
 359 #define ATTR_HDR_MAGIC     0x41545452   /* 'ATTR' */ 
 361 #define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */ 
 363 /* Implementation Limits */ 
 364 #define ATTR_MAX_SIZE      (128*1024)  /* 128K maximum attribute data size */ 
 365 #define ATTR_MAX_HDR_SIZE  65536 
 367  * Note: ATTR_MAX_HDR_SIZE is the largest attribute header 
 368  * size supported (including the attribute entries). All of 
 369  * the attribute entries must reside within this limit.  If 
 370  * any of the attribute data crosses the ATTR_MAX_HDR_SIZE 
 371  * boundry, then all of the attribute data I/O is performed 
 372  * seperately from the attribute header I/O. 
 376 #pragma options align=mac68k 
 378 #define FINDERINFOSIZE  32 
 380 typedef struct apple_double_entry 
{ 
 381         u_int32_t   type
;     /* entry type: see list, 0 invalid */  
 382         u_int32_t   offset
;   /* entry data offset from the beginning of the file. */ 
 383         u_int32_t   length
;   /* entry data length in bytes. */ 
 384 } apple_double_entry_t
; 
 387 typedef struct apple_double_header 
{ 
 388         u_int32_t   magic
;         /* == ADH_MAGIC */ 
 389         u_int32_t   version
;       /* format version: 2 = 0x00020000 */  
 391         u_int16_t   numEntries
;    /* number of entries which follow */  
 392         apple_double_entry_t   entries
[2];  /* 'finfo' & 'rsrc' always exist */ 
 393         u_int8_t    finfo
[FINDERINFOSIZE
];  /* Must start with Finder Info (32 bytes) */ 
 394         u_int8_t    pad
[2];        /* get better alignment inside attr_header */ 
 395 } apple_double_header_t
; 
 397 #define ADHDRSIZE  (4+4+16+2) 
 399 /* Entries are aligned on 4 byte boundaries */ 
 400 typedef struct attr_entry 
{ 
 401         u_int32_t   offset
;     /* file offset to data */ 
 402         u_int32_t   length
;     /* size of attribute data */ 
 405         u_int8_t    name
[1];    /* NULL-terminated UTF-8 name (up to 128 bytes max) */ 
 409 /* Header + entries must fit into 64K */ 
 410 typedef struct attr_header 
{ 
 411         apple_double_header_t  appledouble
; 
 412         u_int32_t   magic
;        /* == ATTR_HDR_MAGIC */ 
 413         u_int32_t   debug_tag
;    /* for debugging == file id of owning file */ 
 414         u_int32_t   total_size
;   /* total size of attribute header + entries + data */  
 415         u_int32_t   data_start
;   /* file offset to attribute data area */ 
 416         u_int32_t   data_length
;  /* length of attribute data area */ 
 417         u_int32_t   reserved
[3]; 
 423 /* Empty Resource Fork Header */ 
 424 typedef struct rsrcfork_header 
{ 
 425         u_int32_t    fh_DataOffset
; 
 426         u_int32_t    fh_MapOffset
; 
 427         u_int32_t    fh_DataLength
; 
 428         u_int32_t    fh_MapLength
; 
 429         u_int8_t     systemData
[112]; 
 430         u_int8_t     appData
[128]; 
 431         u_int32_t    mh_DataOffset
; 
 432         u_int32_t    mh_MapOffset
; 
 433         u_int32_t    mh_DataLength
; 
 434         u_int32_t    mh_MapLength
; 
 438         u_int8_t     mh_InMemoryAttr
; 
 444 #define RF_FIRST_RESOURCE    256 
 445 #define RF_NULL_MAP_LENGTH    30 
 446 #define RF_EMPTY_TAG  "This resource fork intentionally left blank   " 
 448 #pragma options align=reset 
 450 /* Runtime information about the attribute file. */ 
 451 typedef struct attr_info 
{ 
 452         vfs_context_t          context
; 
 457         size_t                 rawsize
;  /* raw size of AppleDouble file */ 
 458         apple_double_header_t  
*filehdr
; 
 459         apple_double_entry_t   
*finderinfo
; 
 460         apple_double_entry_t   
*rsrcfork
; 
 461         attr_header_t          
*attrhdr
; 
 462         attr_entry_t           
*attr_entry
; 
 464         u_int8_t               emptyfinderinfo
; 
 468 #define ATTR_SETTING  1 
 470 #define ATTR_ALIGN 3L  /* Use four-byte alignment */ 
 472 #define ATTR_ENTRY_LENGTH(namelen)  \ 
 473         ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN)) 
 475 #define ATTR_NEXT(ae)  \ 
 476          (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen)) 
 478 #define ATTR_VALID(ae, ai)  \ 
 479         ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize)) 
 482 #define SWAP16(x)  OSSwapBigToHostInt16((x)) 
 483 #define SWAP32(x)  OSSwapBigToHostInt32((x)) 
 484 #define SWAP64(x)  OSSwapBigToHostInt64((x)) 
 487 static u_int32_t emptyfinfo
[8] = {0}; 
 491  * Local support routines 
 493 static void  close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
); 
 495 static int  open_xattrfile(vnode_t vp
, int fileflags
, vnode_t 
*xvpp
, vfs_context_t context
); 
 497 static int  create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
); 
 499 static int  remove_xattrfile(vnode_t xvp
, vfs_context_t context
); 
 501 static int  get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t 
*ainfop
, vfs_context_t context
); 
 503 static void  rel_xattrinfo(attr_info_t 
*ainfop
); 
 505 static int  write_xattrinfo(attr_info_t 
*ainfop
); 
 507 static void  init_empty_resource_fork(rsrcfork_header_t 
* rsrcforkhdr
); 
 509 static int  lock_xattrfile(vnode_t xvp
, short locktype
, vfs_context_t context
); 
 511 static int  unlock_xattrfile(vnode_t xvp
, vfs_context_t context
); 
 514 #if BYTE_ORDER == LITTLE_ENDIAN 
 515   static void  swap_adhdr(apple_double_header_t 
*adh
); 
 516   static void  swap_attrhdr(attr_header_t 
*ah
); 
 519 #define swap_adhdr(x) 
 520 #define swap_attrhdr(x) 
 523 static int  validate_attrhdr(attr_header_t 
*ah
, size_t bufsize
); 
 524 static int  shift_data_down(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
); 
 525 static int  shift_data_up(vnode_t xvp
, off_t start
, size_t len
, off_t delta
, vfs_context_t context
); 
 529  * Retrieve the data of an extended attribute. 
 532 default_getxattr(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, 
 533                  __unused 
int options
, vfs_context_t context
) 
 537         attr_header_t 
*header
; 
 548         if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) { 
 551                  * Open the file locked (shared) since the Carbon 
 552                  * File Manager may have the Apple Double file open 
 553                  * and could be changing the resource fork. 
 555                 fileflags 
|= O_SHLOCK
; 
 560         if ((error 
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) { 
 563         if ((error 
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) { 
 564                 close_xattrfile(xvp
, fileflags
, context
); 
 568         /* Get the Finder Info. */ 
 569         if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) { 
 571                 if (ainfo
.finderinfo 
== NULL 
|| ainfo
.emptyfinderinfo
) { 
 573                 } else if (uio 
== NULL
) { 
 574                         *size 
= FINDERINFOSIZE
; 
 576                 } else if (uio_offset(uio
) != 0) { 
 578                 } else if (uio_resid(uio
) < FINDERINFOSIZE
) { 
 581                         attrdata 
= (u_int8_t
*)ainfo
.filehdr 
+ ainfo
.finderinfo
->offset
; 
 582                         error 
= uiomove((caddr_t
)attrdata
, FINDERINFOSIZE
, uio
); 
 587         /* Read the Resource Fork. */ 
 589                 if (!vnode_isreg(vp
)) { 
 591                 } else if (ainfo
.rsrcfork 
== NULL
) { 
 593                 } else if (uio 
== NULL
) { 
 594                         *size 
= (size_t)ainfo
.rsrcfork
->length
; 
 596                         uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
); 
 597                         error 
= VNOP_READ(xvp
, uio
, 0, context
); 
 599                                 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
); 
 604         if (ainfo
.attrhdr 
== NULL 
|| ainfo
.attr_entry 
== NULL
) { 
 608         if (uio_offset(uio
) != 0) { 
 613         namelen 
= strlen(name
) + 1; 
 614         header 
= ainfo
.attrhdr
; 
 615         entry 
= ainfo
.attr_entry
; 
 617          * Search for attribute name in the header. 
 619         for (i 
= 0; i 
< header
->num_attrs 
&& ATTR_VALID(entry
, ainfo
); i
++) { 
 620                 if (strncmp(entry
->name
, name
, namelen
) == 0) { 
 621                         datalen 
= (size_t)entry
->length
; 
 627                         if (uio_resid(uio
) < datalen
) { 
 631                         if (entry
->offset 
+ datalen 
< ATTR_MAX_HDR_SIZE
) { 
 632                                 attrdata 
= ((u_int8_t 
*)header 
+ entry
->offset
); 
 633                                 error 
= uiomove((caddr_t
)attrdata
, datalen
, uio
); 
 635                                 uio_setoffset(uio
, entry
->offset
); 
 636                                 error 
= VNOP_READ(xvp
, uio
, 0, context
); 
 637                                 uio_setoffset(uio
, 0); 
 641                 entry 
= ATTR_NEXT(entry
); 
 644         rel_xattrinfo(&ainfo
); 
 645         close_xattrfile(xvp
, fileflags
, context
); 
 651  * Set the data of an extended attribute. 
 654 default_setxattr(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
) 
 658         attr_header_t 
*header
; 
 660         attr_entry_t 
*lastentry
; 
 664         size_t datafreespace
; 
 672         datalen 
= uio_resid(uio
); 
 673         namelen 
= strlen(name
) + 1; 
 674         entrylen 
= ATTR_ENTRY_LENGTH(namelen
); 
 676         if (datalen 
> ATTR_MAX_SIZE
) { 
 677                 return (E2BIG
);  /* EINVAL instead ? */ 
 681          * Open the file locked since setting an attribute 
 682          * can change the layout of the Apple Double file. 
 684         fileflags 
= FREAD 
| FWRITE 
| O_EXLOCK
; 
 685         if ((error 
= open_xattrfile(vp
, O_CREAT 
| fileflags
, &xvp
, context
))) { 
 688         if ((error 
= get_xattrinfo(xvp
, ATTR_SETTING
, &ainfo
, context
))) { 
 689                 close_xattrfile(xvp
, fileflags
, context
); 
 693         /* Set the Finder Info. */ 
 694         if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) { 
 695                 if (ainfo
.finderinfo 
&& !ainfo
.emptyfinderinfo
) { 
 696                         /* attr exists and "create" was specified? */ 
 697                         if (options 
& XATTR_CREATE
) { 
 702                         /* attr doesn't exists and "replace" was specified? */ 
 703                         if (options 
& XATTR_REPLACE
) { 
 708                 if (uio_offset(uio
) != 0 || datalen 
!= FINDERINFOSIZE
) { 
 712                 if (ainfo
.finderinfo
) { 
 713                         attrdata 
= (u_int8_t 
*)ainfo
.filehdr 
+ ainfo
.finderinfo
->offset
; 
 714                         error 
= uiomove((caddr_t
)attrdata
, datalen
, uio
); 
 717                         ainfo
.iosize 
= sizeof(attr_header_t
); 
 718                         error 
= write_xattrinfo(&ainfo
); 
 725         /* Write the Resource Fork. */ 
 726         if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) { 
 729                 if (!vnode_isreg(vp
)) { 
 733                 if (ainfo
.rsrcfork 
&& ainfo
.rsrcfork
->length
) { 
 734                         /* attr exists and "create" was specified? */ 
 735                         if (options 
& XATTR_CREATE
) { 
 740                         /* attr doesn't exists and "replace" was specified? */ 
 741                         if (options 
& XATTR_REPLACE
) { 
 746                 endoffset 
= uio_resid(uio
) + uio_offset(uio
); /* new size */ 
 747                 uio_setoffset(uio
, uio_offset(uio
) + ainfo
.rsrcfork
->offset
); 
 748                 error 
= VNOP_WRITE(xvp
, uio
, 0, context
); 
 751                 uio_setoffset(uio
, uio_offset(uio
) - ainfo
.rsrcfork
->offset
); 
 752                 if (endoffset 
> ainfo
.rsrcfork
->length
) { 
 753                         ainfo
.rsrcfork
->length 
= endoffset
; 
 754                         ainfo
.iosize 
= sizeof(attr_header_t
); 
 755                         error 
= write_xattrinfo(&ainfo
); 
 761         if (ainfo
.attrhdr 
== NULL
) { 
 765         header 
= ainfo
.attrhdr
; 
 766         entry 
= ainfo
.attr_entry
; 
 768         /* Check if data area crosses the maximum header size. */ 
 769         if ((header
->data_start 
+ header
->data_length 
+ entrylen 
+ datalen
) > ATTR_MAX_HDR_SIZE
) 
 770                 splitdata 
= 1;  /* do data I/O separately */ 
 775          * See if attribute already exists. 
 777         for (i 
= 0; i 
< header
->num_attrs 
&& ATTR_VALID(entry
, ainfo
); i
++) { 
 778                 if (strncmp(entry
->name
, name
, namelen
) == 0) { 
 782                 entry 
= ATTR_NEXT(entry
); 
 786                 if (options 
& XATTR_CREATE
) { 
 790                 if (datalen 
== entry
->length
) { 
 792                                 uio_setoffset(uio
, entry
->offset
); 
 793                                 error 
= VNOP_WRITE(xvp
, uio
, 0, context
); 
 794                                 uio_setoffset(uio
, 0); 
 796                                         printf("setxattr: VNOP_WRITE error %d\n", error
); 
 799                                 attrdata 
= (u_int8_t 
*)header 
+ entry
->offset
; 
 800                                 error 
= uiomove((caddr_t
)attrdata
, datalen
, uio
); 
 803                                 ainfo
.iosize 
= ainfo
.attrhdr
->data_start 
+ ainfo
.attrhdr
->data_length
; 
 804                                 error 
= write_xattrinfo(&ainfo
); 
 806                                         printf("setxattr: write_xattrinfo error %d\n", error
); 
 812                          * Brute force approach - just remove old entry and set new entry. 
 815                         rel_xattrinfo(&ainfo
); 
 816                         close_xattrfile(xvp
, fileflags
, context
); 
 817                         error 
= default_removexattr(vp
, name
, options
, context
); 
 821                         goto start
; /* start over */ 
 826         if (options 
& XATTR_REPLACE
) { 
 827                 error 
= ENOATTR
;  /* nothing there to replace */ 
 830         /* Check if header size limit has been reached. */ 
 831         if ((header
->data_start 
+ entrylen
) > ATTR_MAX_HDR_SIZE
) { 
 836         datafreespace 
= header
->total_size 
- (header
->data_start 
+ header
->data_length
); 
 838         /* Check if we need more space. */ 
 839         if ((datalen 
+ entrylen
) > datafreespace
) { 
 842                 growsize 
= roundup((datalen 
+ entrylen
) - datafreespace
, ATTR_BUF_SIZE
); 
 844                 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */ 
 845                 if (!splitdata 
&& (header
->total_size 
+ growsize
) > ATTR_MAX_HDR_SIZE
) { 
 846                         growsize 
= ATTR_MAX_HDR_SIZE 
- header
->total_size
; 
 849                 ainfo
.filesize 
+= growsize
; 
 850                 error 
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
); 
 852                         printf("setxattr: VNOP_TRUNCATE error %d\n", error
); 
 858                  * Move the resource fork out of the way. 
 860                 if (ainfo
.rsrcfork
) { 
 861                         if (ainfo
.rsrcfork
->length 
!= 0) { 
 863                                                 ainfo
.rsrcfork
->offset
, 
 864                                                 ainfo
.rsrcfork
->length
, 
 867                         ainfo
.rsrcfork
->offset 
+= growsize
; 
 869                 ainfo
.finderinfo
->length 
+= growsize
; 
 870                 header
->total_size 
+= growsize
; 
 873         /* Make space for a new entry. */ 
 880                 bcopy((u_int8_t 
*)header 
+ header
->data_start
, 
 881                       (u_int8_t 
*)header 
+ header
->data_start 
+ entrylen
, 
 882                       header
->data_length
); 
 884         header
->data_start 
+= entrylen
; 
 886         /* Fix up entry data offsets. */ 
 888         for (entry 
= ainfo
.attr_entry
; entry 
!= lastentry 
&& ATTR_VALID(entry
, ainfo
); entry 
= ATTR_NEXT(entry
)) { 
 889                 entry
->offset 
+= entrylen
; 
 893          * If the attribute data area is entirely within 
 894          * the header buffer, then just update the buffer, 
 895          * otherwise we'll write it separately to the file. 
 900                 /* Write new attribute data after the end of existing data. */ 
 901                 offset 
= header
->data_start 
+ header
->data_length
; 
 902                 uio_setoffset(uio
, offset
); 
 903                 error 
= VNOP_WRITE(xvp
, uio
, 0, context
); 
 904                 uio_setoffset(uio
, 0); 
 906                         printf("setxattr: VNOP_WRITE error %d\n", error
); 
 910                 attrdata 
= (u_int8_t 
*)header 
+ header
->data_start 
+ header
->data_length
; 
 912                 error 
= uiomove((caddr_t
)attrdata
, datalen
, uio
); 
 914                         printf("setxattr: uiomove error %d\n", error
); 
 919         /* Create the attribute entry. */ 
 920         lastentry
->length 
= datalen
; 
 921         lastentry
->offset 
= header
->data_start 
+ header
->data_length
; 
 922         lastentry
->namelen 
= namelen
; 
 923         lastentry
->flags 
= 0; 
 924         bcopy(name
, &lastentry
->name
[0], namelen
); 
 926         /* Update the attributes header. */ 
 928         header
->data_length 
+= datalen
; 
 931                 /* Only write the entries, since the data was written separately. */ 
 932                 ainfo
.iosize 
= ainfo
.attrhdr
->data_start
; 
 934                  /* The entry and data are both in the header; write them together. */ 
 935                 ainfo
.iosize 
= ainfo
.attrhdr
->data_start 
+ ainfo
.attrhdr
->data_length
; 
 937         error 
= write_xattrinfo(&ainfo
); 
 939                 printf("setxattr: write_xattrinfo error %d\n", error
); 
 943         rel_xattrinfo(&ainfo
); 
 944         close_xattrfile(xvp
, fileflags
, context
); 
 946         /* Touch the change time if we changed an attribute. */ 
 948                 struct vnode_attr va
; 
 950                 /* Re-write the mtime to cause a ctime change. */ 
 952                 VATTR_WANTED(&va
, va_modify_time
); 
 953                 if (vnode_getattr(vp
, &va
, context
) == 0) { 
 955                         VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
); 
 956                         (void) vnode_setattr(vp
, &va
, context
); 
 964  * Remove an extended attribute. 
 967 default_removexattr(vnode_t vp
, const char *name
, __unused 
int options
, vfs_context_t context
) 
 971         attr_header_t 
*header
; 
 973         attr_entry_t 
*oldslot
; 
 979         int found 
= 0, lastone 
= 0; 
 987         fileflags 
= FREAD 
| FWRITE
; 
 988         if (bcmp(name
, XATTR_RESOURCEFORK_NAME
, sizeof(XATTR_RESOURCEFORK_NAME
)) == 0) { 
 991                  * Open the file locked (exclusive) since the Carbon 
 992                  * File Manager may have the Apple Double file open 
 993                  * and could be changing the resource fork. 
 995                 fileflags 
|= O_EXLOCK
; 
1000         if ((error 
= open_xattrfile(vp
, fileflags
, &xvp
, context
))) { 
1003         if ((error 
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) { 
1004                 close_xattrfile(xvp
, fileflags
, context
); 
1008                 attrcount 
+= ainfo
.attrhdr
->num_attrs
; 
1011         if (ainfo
.finderinfo 
&& !ainfo
.emptyfinderinfo
) 
1014         /* Clear the Finder Info. */ 
1015         if (bcmp(name
, XATTR_FINDERINFO_NAME
, sizeof(XATTR_FINDERINFO_NAME
)) == 0) { 
1016                 if (ainfo
.finderinfo 
== NULL 
|| ainfo
.emptyfinderinfo
) { 
1020                 /* On removal of last attribute the ._ file is removed. */ 
1021                 if (--attrcount 
== 0) 
1023                 attrdata 
= (u_int8_t 
*)ainfo
.filehdr 
+ ainfo
.finderinfo
->offset
; 
1024                 bzero((caddr_t
)attrdata
, FINDERINFOSIZE
); 
1025                 ainfo
.iosize 
= sizeof(attr_header_t
); 
1026                 error 
= write_xattrinfo(&ainfo
); 
1030         /* Clear the Resource Fork. */ 
1032                 if (!vnode_isreg(vp
)) { 
1036                 if (ainfo
.rsrcfork 
== NULL 
|| ainfo
.rsrcfork
->length 
== 0) { 
1040                 /* On removal of last attribute the ._ file is removed. */ 
1041                 if (--attrcount 
== 0) 
1045                  * If the resource fork isn't the last AppleDouble 
1046                  * entry then the space needs to be reclaimed by 
1047                  * shifting the entries after the resource fork. 
1049                 if ((ainfo
.rsrcfork
->offset 
+ ainfo
.rsrcfork
->length
) == ainfo
.filesize
) { 
1050                         ainfo
.filesize 
-= ainfo
.rsrcfork
->length
; 
1051                         error 
= vnode_setsize(xvp
, ainfo
.filesize
, 0, context
); 
1054                         ainfo
.rsrcfork
->length 
= 0; 
1055                         ainfo
.iosize 
= sizeof(attr_header_t
); 
1056                         error 
= write_xattrinfo(&ainfo
); 
1061         if (ainfo
.attrhdr 
== NULL
) { 
1065         namelen 
= strlen(name
) + 1; 
1066         header 
= ainfo
.attrhdr
; 
1067         entry 
= ainfo
.attr_entry
; 
1070          * See if this attribute exists. 
1072         for (i 
= 0; i 
< header
->num_attrs 
&& ATTR_VALID(entry
, ainfo
); i
++) { 
1073                 if (strncmp(entry
->name
, name
, namelen
) == 0) { 
1075                         if ((i
+1) == header
->num_attrs
) 
1079                 entry 
= ATTR_NEXT(entry
); 
1085         /* On removal of last attribute the ._ file is removed. */ 
1086         if (--attrcount 
== 0) 
1089         datalen 
= entry
->length
; 
1090         dataoff 
= entry
->offset
; 
1091         entrylen 
= ATTR_ENTRY_LENGTH(namelen
); 
1092         if ((header
->data_start 
+ header
->data_length
) > ATTR_MAX_HDR_SIZE
) 
1097         /* Remove the attribute entry. */ 
1099                 bcopy((u_int8_t 
*)entry 
+ entrylen
, (u_int8_t 
*)entry
, 
1100                       ((size_t)header 
+ header
->data_start
) - ((size_t)entry 
+ entrylen
)); 
1103         /* Adjust the attribute data. */ 
1107                               dataoff 
- header
->data_start
, 
1113                                       (header
->data_start 
+ header
->data_length
) - (dataoff 
+ datalen
), 
1117                 /* XXX write zeros to freed space ? */ 
1118                 ainfo
.iosize 
= ainfo
.attrhdr
->data_start 
- entrylen
; 
1122                 bcopy((u_int8_t 
*)header 
+ header
->data_start
, 
1123                       (u_int8_t 
*)header 
+ header
->data_start 
- entrylen
, 
1124                       dataoff 
- header
->data_start
); 
1126                         bcopy((u_int8_t 
*)header 
+ dataoff 
+ datalen
, 
1127                               (u_int8_t 
*)header 
+ dataoff 
- entrylen
, 
1128                               (header
->data_start 
+ header
->data_length
) - (dataoff 
+ datalen
)); 
1130                 bzero (((u_int8_t 
*)header 
+ header
->data_start 
+ header
->data_length
) - (datalen 
+ entrylen
), (datalen 
+ entrylen
)); 
1131                 ainfo
.iosize 
= ainfo
.attrhdr
->data_start 
+ ainfo
.attrhdr
->data_length
; 
1134         /* Adjust the header values and entry offsets. */ 
1135         header
->num_attrs
--; 
1136         header
->data_start 
-= entrylen
; 
1137         header
->data_length 
-= datalen
; 
1140         entry 
= ainfo
.attr_entry
; 
1141         for (i 
= 0; i 
< header
->num_attrs 
&& ATTR_VALID(entry
, ainfo
); i
++) { 
1142                 entry
->offset 
-= entrylen
; 
1143                 if (entry 
>= oldslot
) 
1144                         entry
->offset 
-= datalen
; 
1145                 entry 
= ATTR_NEXT(entry
); 
1147         error 
= write_xattrinfo(&ainfo
); 
1149                 printf("removexattr: write_xattrinfo error %d\n", error
); 
1152         rel_xattrinfo(&ainfo
); 
1154         /* When there are no more attributes remove the ._ file. */ 
1155         if (attrcount 
== 0) { 
1156                 if (fileflags 
& O_EXLOCK
) 
1157                         (void) unlock_xattrfile(xvp
, context
); 
1158                 VNOP_CLOSE(xvp
, fileflags
, context
); 
1160                 error 
= remove_xattrfile(xvp
, context
); 
1163                 close_xattrfile(xvp
, fileflags
, context
); 
1165         /* Touch the change time if we changed an attribute. */ 
1167                 struct vnode_attr va
; 
1169                 /* Re-write the mtime to cause a ctime change. */ 
1171                 VATTR_WANTED(&va
, va_modify_time
); 
1172                 if (vnode_getattr(vp
, &va
, context
) == 0) { 
1174                         VATTR_SET(&va
, va_modify_time
, va
.va_modify_time
); 
1175                         (void) vnode_setattr(vp
, &va
, context
); 
1184  * Retrieve the list of extended attribute names. 
1187 default_listxattr(vnode_t vp
, uio_t uio
, size_t *size
, __unused 
int options
, vfs_context_t context
) 
1191         attr_entry_t 
*entry
; 
1196          * We do not zero "*size" here as we don't want to stomp a size set when 
1197          * VNOP_LISTXATTR processed any native EAs.  That size is initially zeroed by the 
1198          * system call layer, up in listxattr or flistxattr. 
1201         if ((error 
= open_xattrfile(vp
, FREAD
, &xvp
, context
))) { 
1202                 if (error 
== ENOATTR
) 
1206         if ((error 
= get_xattrinfo(xvp
, 0, &ainfo
, context
))) { 
1207                 close_xattrfile(xvp
, FREAD
, context
); 
1211         /* Check for Finder Info. */ 
1212         if (ainfo
.finderinfo 
&& !ainfo
.emptyfinderinfo
) { 
1214                         *size 
+= sizeof(XATTR_FINDERINFO_NAME
); 
1215                 } else if (uio_resid(uio
) < sizeof(XATTR_FINDERINFO_NAME
)) { 
1219                         error 
= uiomove((caddr_t
)XATTR_FINDERINFO_NAME
, 
1220                                         sizeof(XATTR_FINDERINFO_NAME
), uio
); 
1228         /* Check for Resource Fork. */ 
1229         if (vnode_isreg(vp
) && ainfo
.rsrcfork
) { 
1231                         *size 
+= sizeof(XATTR_RESOURCEFORK_NAME
); 
1232                 } else if (uio_resid(uio
) < sizeof(XATTR_RESOURCEFORK_NAME
)) { 
1236                         error 
= uiomove((caddr_t
)XATTR_RESOURCEFORK_NAME
, 
1237                                         sizeof(XATTR_RESOURCEFORK_NAME
), uio
); 
1245         /* Check for attributes. */ 
1246         if (ainfo
.attrhdr
) { 
1247                 count 
= ainfo
.attrhdr
->num_attrs
; 
1248                 for (i 
= 0, entry 
= ainfo
.attr_entry
; i 
< count 
&& ATTR_VALID(entry
, ainfo
); i
++) { 
1249                         if (xattr_protected(entry
->name
) || 
1250                             xattr_validatename(entry
->name
) != 0) { 
1251                                 entry 
= ATTR_NEXT(entry
); 
1255                                 *size 
+= entry
->namelen
; 
1256                                 entry 
= ATTR_NEXT(entry
); 
1259                         if (uio_resid(uio
) < entry
->namelen
) { 
1263                         error 
= uiomove((caddr_t
) entry
->name
, entry
->namelen
, uio
); 
1265                                 if (error 
!= EFAULT
) 
1269                         entry 
= ATTR_NEXT(entry
); 
1273         rel_xattrinfo(&ainfo
); 
1274         close_xattrfile(xvp
, FREAD
, context
); 
1280 open_xattrfile(vnode_t vp
, int fileflags
, vnode_t 
*xvpp
, vfs_context_t context
) 
1282         vnode_t xvp 
= NULLVP
; 
1283         vnode_t dvp 
= NULLVP
; 
1284         struct vnode_attr va
; 
1285         struct nameidata nd
; 
1287         char *filename 
= NULL
; 
1288         char *basename 
= NULL
; 
1294         if (vnode_isvroot(vp
) && vnode_isdir(vp
)) { 
1296                  * For the root directory use "._." to hold the attributes. 
1298                 filename 
= &smallname
[0]; 
1299                 sprintf(filename
, "%s%s", ATTR_FILE_PREFIX
, "."); 
1300                 dvp 
= vp
;  /* the "._." file resides in the root dir */ 
1303         if ( (dvp 
= vnode_getparent(vp
)) == NULLVP
) { 
1307         if ( (basename 
= vnode_getname(vp
)) == NULL
) { 
1312         /* "._" Attribute files cannot have attributes */ 
1313         if (vp
->v_type 
== VREG 
&& strlen(basename
) > 2 && 
1314             basename
[0] == '.' && basename
[1] == '_') { 
1318         filename 
= &smallname
[0]; 
1319         len 
= snprintf(filename
, sizeof(smallname
), "%s%s", ATTR_FILE_PREFIX
, basename
); 
1320         if (len 
>= sizeof(smallname
)) { 
1321                 len
++;  /* snprintf result doesn't include '\0' */ 
1322                 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
); 
1323                 len 
= snprintf(filename
, len
, "%s%s", ATTR_FILE_PREFIX
, basename
); 
1326          * Note that the lookup here does not authorize.  Since we are looking 
1327          * up in the same directory that we already have the file vnode in, 
1328          * we must have been given the file vnode legitimately.  Read/write 
1329          * access has already been authorized in layers above for calls from 
1330          * userspace, and the authorization code using this path to read 
1331          * file security from the EA must always get access 
1334         NDINIT(&nd
, LOOKUP
, LOCKLEAF 
| NOFOLLOW 
| USEDVP 
| DONOTAUTH
, UIO_SYSSPACE
, 
1335                CAST_USER_ADDR_T(filename
), context
); 
1338         if (fileflags 
& O_CREAT
) { 
1339                 nd
.ni_cnd
.cn_nameiop 
= CREATE
; 
1341                         nd
.ni_cnd
.cn_flags 
|= LOCKPARENT
; 
1343                 if ( (error 
= namei(&nd
))) { 
1348                 if ( (xvp 
= nd
.ni_vp
) == NULLVP
) { 
1354                          * Pick up uid/gid/mode from target file. 
1357                         VATTR_WANTED(&va
, va_uid
); 
1358                         VATTR_WANTED(&va
, va_gid
); 
1359                         VATTR_WANTED(&va
, va_mode
); 
1360                         if (VNOP_GETATTR(vp
, &va
, context
) == 0  && 
1361                             VATTR_IS_SUPPORTED(&va
, va_uid
)  && 
1362                             VATTR_IS_SUPPORTED(&va
, va_gid
)  && 
1363                             VATTR_IS_SUPPORTED(&va
, va_mode
)) { 
1366                                 umode 
= va
.va_mode 
& (S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
); 
1367                         } else /* fallback values */ { 
1368                                 uid 
= KAUTH_UID_NONE
; 
1369                                 gid 
= KAUTH_GID_NONE
; 
1370                                 umode 
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
; 
1374                         VATTR_SET(&va
, va_type
, VREG
); 
1375                         VATTR_SET(&va
, va_mode
, umode
); 
1376                         if (uid 
!= KAUTH_UID_NONE
) 
1377                                 VATTR_SET(&va
, va_uid
, uid
); 
1378                         if (gid 
!= KAUTH_GID_NONE
) 
1379                                 VATTR_SET(&va
, va_gid
, gid
); 
1381                         error 
= vn_create(dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, 
1382                                           VN_CREATE_NOAUTH 
| VN_CREATE_NOINHERIT
, 
1389                         vnode_put(dvp
);  /* drop iocount from LOCKPARENT request above */ 
1394                 if ((error 
= namei(&nd
))) { 
1404         if (xvp
->v_type 
!= VREG
) { 
1409          * Owners must match. 
1412         VATTR_WANTED(&va
, va_uid
); 
1413         if (VNOP_GETATTR(vp
, &va
, context
) == 0 && VATTR_IS_SUPPORTED(&va
, va_uid
)) { 
1414                 uid_t owner 
= va
.va_uid
; 
1417                 VATTR_WANTED(&va
, va_uid
); 
1418                 if (VNOP_GETATTR(xvp
, &va
, context
) == 0 && (owner 
!= va
.va_uid
)) { 
1419                         error 
= ENOATTR
;  /* don't use this "._" file */ 
1424         if ( (error 
= VNOP_OPEN(xvp
, fileflags
, context
))) { 
1430         if ((error 
= vnode_ref(xvp
))) { 
1435         /* If create was requested, make sure file header exists. */ 
1436         if (fileflags 
& O_CREAT
) { 
1438                 VATTR_WANTED(&va
, va_data_size
); 
1439                 VATTR_WANTED(&va
, va_fileid
); 
1440                 VATTR_WANTED(&va
, va_nlink
); 
1441                 if ( (error 
= vnode_getattr(xvp
, &va
, context
)) != 0) { 
1446                 /* If the file is empty then add a default header. */ 
1447                 if (va
.va_data_size 
== 0) { 
1448                         /* Don't adopt hard-linked "._" files. */ 
1449                         if (VATTR_IS_SUPPORTED(&va
, va_nlink
) && va
.va_nlink 
> 1) { 
1453                         if ( (error 
= create_xattrfile(xvp
, (u_int32_t
)va
.va_fileid
, context
))) 
1457         /* Apply file locking if requested. */   
1458         if (fileflags 
& (O_EXLOCK 
| O_SHLOCK
)) { 
1461                 locktype 
= (fileflags 
& O_EXLOCK
) ? F_WRLCK 
: F_RDLCK
; 
1462                 error 
= lock_xattrfile(xvp
, locktype
, context
); 
1465         if (dvp 
&& (dvp 
!= vp
)) { 
1469                 vnode_putname(basename
); 
1471         if (filename 
&& filename 
!= &smallname
[0]) { 
1472                 FREE(filename
, M_TEMP
); 
1475                 if (xvp 
!= NULLVP
) { 
1477                                 (void) VNOP_CLOSE(xvp
, fileflags
, context
); 
1480                                 (void) vnode_rele(xvp
); 
1482                         (void) vnode_put(xvp
); 
1485                 if ((error 
== ENOATTR
) && (fileflags 
& O_CREAT
)) { 
1489         *xvpp 
= xvp
;  /* return a referenced vnode */ 
1494 close_xattrfile(vnode_t xvp
, int fileflags
, vfs_context_t context
) 
1496 //      if (fileflags & FWRITE) 
1497 //              (void) VNOP_FSYNC(xvp, MNT_WAIT, context); 
1499         if (fileflags 
& (O_EXLOCK 
| O_SHLOCK
)) 
1500                 (void) unlock_xattrfile(xvp
, context
); 
1502         (void) VNOP_CLOSE(xvp
, fileflags
, context
); 
1503         (void) vnode_rele(xvp
); 
1504         (void) vnode_put(xvp
); 
1508 remove_xattrfile(vnode_t xvp
, vfs_context_t context
) 
1511         struct nameidata nd
; 
1516         path 
= get_pathbuff(); 
1517         pathlen 
= MAXPATHLEN
; 
1518         vn_getpath(xvp
, path
, &pathlen
); 
1520         NDINIT(&nd
, DELETE
, LOCKPARENT 
| NOFOLLOW 
| DONOTAUTH
, 
1521                UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), context
); 
1523         release_pathbuff(path
); 
1530         error 
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, context
); 
1539 get_xattrinfo(vnode_t xvp
, int setting
, attr_info_t 
*ainfop
, vfs_context_t context
) 
1542         void * buffer 
= NULL
; 
1543         apple_double_header_t  
*filehdr
; 
1544         attr_header_t 
*attrhdr
; 
1545         struct vnode_attr va
; 
1550         bzero(ainfop
, sizeof(attr_info_t
)); 
1551         ainfop
->filevp 
= xvp
; 
1552         ainfop
->context 
= context
; 
1554         VATTR_WANTED(&va
, va_data_size
); 
1555         VATTR_WANTED(&va
, va_fileid
); 
1556         if ((error 
= vnode_getattr(xvp
, &va
, context
))) { 
1559         ainfop
->filesize 
= va
.va_data_size
; 
1561         /* When setting attributes, allow room for the header to grow. */ 
1563                 iosize 
= ATTR_MAX_HDR_SIZE
; 
1565                 iosize 
= MIN(ATTR_MAX_HDR_SIZE
, ainfop
->filesize
); 
1571         ainfop
->iosize 
= iosize
; 
1572         MALLOC(buffer
, void *, iosize
, M_TEMP
, M_WAITOK
); 
1573         auio 
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_READ
); 
1574         uio_addiov(auio
, (uintptr_t)buffer
, iosize
); 
1576         /* Read the file header. */ 
1577         error 
= VNOP_READ(xvp
, auio
, 0, context
); 
1581         ainfop
->rawsize 
= iosize 
- uio_resid(auio
); 
1582         ainfop
->rawdata 
= (u_int8_t 
*)buffer
; 
1584         filehdr 
= (apple_double_header_t 
*)buffer
; 
1586         /* Check for Apple Double file. */ 
1587         if (SWAP32(filehdr
->magic
) != ADH_MAGIC 
|| 
1588             SWAP32(filehdr
->version
) != ADH_VERSION 
|| 
1589             SWAP16(filehdr
->numEntries
) < 1 || 
1590             SWAP16(filehdr
->numEntries
) > 15) { 
1594         if (ADHDRSIZE 
+ (SWAP16(filehdr
->numEntries
) * sizeof(apple_double_entry_t
)) > ainfop
->rawsize
) { 
1599         swap_adhdr(filehdr
); 
1600         ainfop
->filehdr 
= filehdr
;  /* valid AppleDouble header */ 
1601         /* rel_xattrinfo is responsible for freeing the header buffer */ 
1604         /* Check the AppleDouble entries. */ 
1605         for (i 
= 0; i 
< filehdr
->numEntries
; ++i
) { 
1606                 if (filehdr
->entries
[i
].type 
== AD_FINDERINFO 
&& 
1607                     filehdr
->entries
[i
].length 
> 0) { 
1608                         ainfop
->finderinfo 
= &filehdr
->entries
[i
]; 
1609                         attrhdr 
= (attr_header_t 
*)filehdr
; 
1611                         if (bcmp((u_int8_t
*)ainfop
->filehdr 
+ ainfop
->finderinfo
->offset
, 
1612                                  emptyfinfo
, sizeof(emptyfinfo
)) == 0) { 
1613                                 ainfop
->emptyfinderinfo 
= 1; 
1619                         /* See if we need to convert this AppleDouble file. */ 
1620                         if (filehdr
->entries
[0].length 
== FINDERINFOSIZE
) { 
1625                                     filehdr
->entries
[1].type 
!= AD_RESOURCE 
|| 
1626                                     filehdr
->numEntries 
> 2) { 
1627                                         continue;  /* not expected layout */ 
1629                                 delta 
= ATTR_BUF_SIZE 
- (filehdr
->entries
[0].offset 
+ FINDERINFOSIZE
); 
1630                                 if (filehdr
->entries
[1].length
) { 
1631                                         /* Make some room. */ 
1632                                         shift_data_down(xvp
, 
1633                                                         filehdr
->entries
[1].offset
, 
1634                                                         filehdr
->entries
[1].length
, 
1636                                         writesize 
= sizeof(attr_header_t
); 
1638                                         rsrcfork_header_t 
*rsrcforkhdr
; 
1640                                         vnode_setsize(xvp
, filehdr
->entries
[1].offset 
+ delta
, 0, context
); 
1642                                         /* Steal some space for an empty RF header. */ 
1643                                         delta 
-= sizeof(rsrcfork_header_t
); 
1645                                         bzero(&attrhdr
->appledouble
.pad
[0], delta
); 
1646                                         rsrcforkhdr 
= (rsrcfork_header_t 
*)((char *)filehdr 
+ filehdr
->entries
[1].offset 
+ delta
); 
1648                                         /* Fill in Empty Resource Fork Header. */ 
1649                                         init_empty_resource_fork(rsrcforkhdr
); 
1651                                         filehdr
->entries
[1].length 
= sizeof(rsrcfork_header_t
); 
1652                                         writesize 
= ATTR_BUF_SIZE
; 
1654                                 filehdr
->entries
[0].length 
+= delta
; 
1655                                 filehdr
->entries
[1].offset 
+= delta
; 
1657                                 /* Fill in Attribute Header. */ 
1658                                 attrhdr
->magic       
= ATTR_HDR_MAGIC
; 
1659                                 attrhdr
->debug_tag   
= (u_int32_t
)va
.va_fileid
; 
1660                                 attrhdr
->total_size  
= filehdr
->entries
[1].offset
; 
1661                                 attrhdr
->data_start  
= sizeof(attr_header_t
); 
1662                                 attrhdr
->data_length 
= 0; 
1663                                 attrhdr
->reserved
[0] = 0; 
1664                                 attrhdr
->reserved
[1] = 0; 
1665                                 attrhdr
->reserved
[2] = 0; 
1667                                 attrhdr
->num_attrs   
= 0; 
1669                                 /* Push out new header */ 
1670                                 uio_reset(auio
, 0, UIO_SYSSPACE32
, UIO_WRITE
); 
1671                                 uio_addiov(auio
, (uintptr_t)filehdr
, writesize
); 
1673                                 swap_adhdr(filehdr
); 
1674                                 swap_attrhdr(attrhdr
); 
1675                                 error 
= VNOP_WRITE(xvp
, auio
, 0, context
); 
1676                                 swap_adhdr(filehdr
); 
1677                                 /* The attribute header gets swapped below. */ 
1679                         if (SWAP32 (attrhdr
->magic
) != ATTR_HDR_MAGIC 
|| 
1680                             validate_attrhdr(attrhdr
, ainfop
->rawsize
) != 0) { 
1681                                 printf("get_xattrinfo: invalid attribute header\n"); 
1684                         swap_attrhdr(attrhdr
); 
1685                         ainfop
->attrhdr 
= attrhdr
;  /* valid attribute header */ 
1686                         ainfop
->attr_entry 
= (attr_entry_t 
*)&attrhdr
[1]; 
1689                 if (filehdr
->entries
[i
].type 
== AD_RESOURCE 
&& 
1690                     (filehdr
->entries
[i
].length 
> sizeof(rsrcfork_header_t
) || setting
)) { 
1691                         ainfop
->rsrcfork 
= &filehdr
->entries
[i
]; 
1692                         if (i 
!= (filehdr
->numEntries 
- 1)) { 
1693                                 printf("get_xattrinfo: resource fork not last entry\n"); 
1694                                 ainfop
->readonly 
= 1; 
1704                 FREE(buffer
, M_TEMP
); 
1710 create_xattrfile(vnode_t xvp
, u_int32_t fileid
, vfs_context_t context
) 
1713         rsrcfork_header_t 
*rsrcforkhdr
; 
1719         MALLOC(buffer
, void *, ATTR_BUF_SIZE
, M_TEMP
, M_WAITOK
); 
1720         bzero(buffer
, ATTR_BUF_SIZE
); 
1722         xah 
= (attr_header_t 
*)buffer
; 
1723         auio 
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_WRITE
); 
1724         uio_addiov(auio
, (uintptr_t)buffer
, ATTR_BUF_SIZE
); 
1725         rsrcforksize 
= sizeof(rsrcfork_header_t
); 
1726         rsrcforkhdr 
= (rsrcfork_header_t 
*) ((char *)buffer 
+ ATTR_BUF_SIZE 
- rsrcforksize
); 
1728         /* Fill in Apple Double Header. */ 
1729         xah
->appledouble
.magic             
= SWAP32 (ADH_MAGIC
); 
1730         xah
->appledouble
.version           
= SWAP32 (ADH_VERSION
); 
1731         xah
->appledouble
.numEntries        
= SWAP16 (2); 
1732         xah
->appledouble
.entries
[0].type   
= SWAP32 (AD_FINDERINFO
); 
1733         xah
->appledouble
.entries
[0].offset 
= SWAP32 (offsetof(apple_double_header_t
, finfo
)); 
1734         xah
->appledouble
.entries
[0].length 
= SWAP32 (ATTR_BUF_SIZE 
- offsetof(apple_double_header_t
, finfo
) - rsrcforksize
); 
1735         xah
->appledouble
.entries
[1].type   
= SWAP32 (AD_RESOURCE
); 
1736         xah
->appledouble
.entries
[1].offset 
= SWAP32 (ATTR_BUF_SIZE 
- rsrcforksize
); 
1737         xah
->appledouble
.entries
[1].length 
= SWAP32 (rsrcforksize
); 
1738         bcopy(ADH_MACOSX
, xah
->appledouble
.filler
, sizeof(xah
->appledouble
.filler
)); 
1740         /* Fill in Attribute Header. */ 
1741         xah
->magic       
= SWAP32 (ATTR_HDR_MAGIC
); 
1742         xah
->debug_tag   
= SWAP32 (fileid
); 
1743         xah
->total_size  
= SWAP32 (ATTR_BUF_SIZE 
- rsrcforksize
); 
1744         xah
->data_start  
= SWAP32 (sizeof(attr_header_t
)); 
1746         /* Fill in Empty Resource Fork Header. */ 
1747         init_empty_resource_fork(rsrcforkhdr
); 
1750         error 
= VNOP_WRITE(xvp
, auio
, 0, context
); 
1753         FREE(buffer
, M_TEMP
); 
1759 init_empty_resource_fork(rsrcfork_header_t 
* rsrcforkhdr
) 
1761         bzero(rsrcforkhdr
, sizeof(rsrcfork_header_t
)); 
1762         rsrcforkhdr
->fh_DataOffset 
= SWAP32 (RF_FIRST_RESOURCE
); 
1763         rsrcforkhdr
->fh_MapOffset  
= SWAP32 (RF_FIRST_RESOURCE
); 
1764         rsrcforkhdr
->fh_MapLength  
= SWAP32 (RF_NULL_MAP_LENGTH
); 
1765         rsrcforkhdr
->mh_DataOffset 
= SWAP32 (RF_FIRST_RESOURCE
); 
1766         rsrcforkhdr
->mh_MapOffset  
= SWAP32 (RF_FIRST_RESOURCE
); 
1767         rsrcforkhdr
->mh_MapLength  
= SWAP32 (RF_NULL_MAP_LENGTH
); 
1768         rsrcforkhdr
->mh_Types      
= SWAP16 (RF_NULL_MAP_LENGTH 
- 2 ); 
1769         rsrcforkhdr
->mh_Names      
= SWAP16 (RF_NULL_MAP_LENGTH
); 
1770         rsrcforkhdr
->typeCount     
= SWAP16 (-1); 
1771         bcopy(RF_EMPTY_TAG
, rsrcforkhdr
->systemData
, sizeof(RF_EMPTY_TAG
)); 
1775 rel_xattrinfo(attr_info_t 
*ainfop
) 
1777         FREE(ainfop
->filehdr
, M_TEMP
); 
1778         bzero(ainfop
, sizeof(attr_info_t
)); 
1782 write_xattrinfo(attr_info_t 
*ainfop
) 
1787         auio 
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_WRITE
); 
1788         uio_addiov(auio
, (uintptr_t)ainfop
->filehdr
, ainfop
->iosize
); 
1790         swap_adhdr(ainfop
->filehdr
); 
1791         if (ainfop
->attrhdr 
!= NULL
) 
1792         swap_attrhdr(ainfop
->attrhdr
); 
1794         error 
= VNOP_WRITE(ainfop
->filevp
, auio
, 0, ainfop
->context
); 
1796         swap_adhdr(ainfop
->filehdr
); 
1797         if (ainfop
->attrhdr 
!= NULL
) 
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
);