2  * Copyright (c) 1995-2017 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 
  30  * support for mandatory and extensible security protections.  This notice 
  31  * is included in support of clause 2.2 (b) of the Apple Public License, 
  35 #include <sys/param.h> 
  36 #include <sys/systm.h> 
  37 #include <sys/namei.h> 
  38 #include <sys/kernel.h> 
  40 #include <sys/syslog.h> 
  41 #include <sys/vnode_internal.h> 
  42 #include <sys/mount_internal.h> 
  43 #include <sys/proc_internal.h> 
  44 #include <sys/file_internal.h> 
  45 #include <sys/kauth.h> 
  46 #include <sys/uio_internal.h> 
  47 #include <sys/malloc.h> 
  49 #include <sys/sysproto.h> 
  50 #include <sys/xattr.h> 
  51 #include <sys/fsevents.h> 
  52 #include <kern/kalloc.h> 
  53 #include <miscfs/specfs/specdev.h> 
  54 #include <security/audit/audit.h> 
  57 #include <security/mac_framework.h> 
  60 #define ATTR_TIME_SIZE  -1 
  63  * Structure describing the state of an in-progress attrlist operation. 
  65 struct _attrlist_buf 
{ 
  71         attribute_set_t actual
; 
  72         attribute_set_t valid
; 
  77  * Attempt to pack a fixed width attribute of size (count) bytes from 
  78  * source to our attrlist buffer. 
  81 attrlist_pack_fixed(struct _attrlist_buf 
*ab
, void *source
, ssize_t count
) 
  84          * Use ssize_t for pointer math purposes, 
  85          * since a ssize_t is a signed long 
  90          * Compute the amount of remaining space in the attrlist buffer 
  91          * based on how much we've used for fixed width fields vs. the 
  92          * start of the attributes.   
  94          * If we've still got room, then 'fit' will contain the amount of  
  97          * Note that this math is safe because, in the event that the  
  98          * fixed-width cursor has moved beyond the end of the buffer, 
  99          * then, the second input into lmin() below will be negative, and  
 100          * we will fail the (fit > 0) check below.  
 102         fit 
= lmin(count
, ab
->allocated 
- (ab
->fixedcursor 
- ab
->base
)); 
 104                 /* Copy in as much as we can */ 
 105                 bcopy(source
, ab
->fixedcursor
, fit
); 
 108         /* always move in increments of 4, even if we didn't pack an attribute. */ 
 109         ab
->fixedcursor 
+= roundup(count
, 4); 
 113  * Attempt to pack one (or two) variable width attributes into the attrlist 
 114  * buffer.  If we are trying to pack two variable width attributes, they are treated 
 115  * as a single variable-width attribute from the POV of the system call caller. 
 117  * Recall that a variable-width attribute has two components: the fixed-width  
 118  * attribute that tells the caller where to look, and the actual variable width data. 
 121 attrlist_pack_variable2(struct _attrlist_buf 
*ab
, const void *source
, ssize_t count
,  
 122                 const void *ext
, ssize_t extcount
)  
 124         /* Use ssize_t's for pointer math ease */ 
 125         struct attrreference ar
; 
 129          * Pack the fixed-width component to the variable object.  
 130          * Note that we may be able to pack the fixed width attref, but not 
 131          * the variable (if there's no room). 
 133         ar
.attr_dataoffset 
= ab
->varcursor 
- ab
->fixedcursor
; 
 134         ar
.attr_length 
= count 
+ extcount
; 
 135         attrlist_pack_fixed(ab
, &ar
, sizeof(ar
)); 
 138          * Use an lmin() to do a signed comparison. We use a signed comparison 
 139          * to detect the 'out of memory' conditions as described above in the 
 140          * fixed width check above. 
 142          * Then pack the first variable attribute as space allows.  Note that we advance 
 143          * the variable cursor only if we we had some available space.  
 145         fit 
= lmin(count
, ab
->allocated 
- (ab
->varcursor 
- ab
->base
)); 
 147                 if (source 
!= NULL
) { 
 148                         bcopy(source
, ab
->varcursor
, fit
); 
 150                 ab
->varcursor 
+= fit
; 
 153         /* Compute the available space for the second attribute */ 
 154         fit 
= lmin(extcount
, ab
->allocated 
- (ab
->varcursor 
- ab
->base
)); 
 156                 /* Copy in data for the second attribute (if needed) if there is room */ 
 158                         bcopy(ext
, ab
->varcursor
, fit
); 
 160                 ab
->varcursor 
+= fit
; 
 162         /* always move in increments of 4 */ 
 163         ab
->varcursor 
= (char *)roundup((uintptr_t)ab
->varcursor
, 4); 
 167  * Packing a single variable-width attribute is the same as calling the two, but with 
 168  * an invalid 2nd attribute. 
 171 attrlist_pack_variable(struct _attrlist_buf 
*ab
, const void *source
, ssize_t count
) 
 173         attrlist_pack_variable2(ab
, source
, count
, NULL
, 0); 
 177  * Attempt to pack a string. This is a special case of a variable width attribute. 
 179  * If "source" is NULL, then an empty string ("") will be packed.  If "source" is 
 180  * not NULL, but "count" is zero, then "source" is assumed to be a NUL-terminated 
 181  * C-string.  If "source" is not NULL and "count" is not zero, then only the first 
 182  * "count" bytes of "source" will be copied, and a NUL terminator will be added. 
 184  * If the attrlist buffer doesn't have enough room to hold the entire string (including 
 185  * NUL terminator), then copy as much as will fit.  The attrlist buffer's "varcursor" 
 186  * will always be updated based on the entire length of the string (including NUL 
 187  * terminator); this means "varcursor" may end up pointing beyond the end of the 
 188  * allocated buffer space. 
 191 attrlist_pack_string(struct _attrlist_buf 
*ab
, const char *source
, ssize_t count
) 
 193         struct attrreference ar
; 
 197          * Supplied count is character count of string text, excluding trailing nul 
 198          * which we always supply here. 
 200         if (source 
== NULL
) { 
 202         } else if (count 
== 0) { 
 203                 count 
= strlen(source
); 
 207          * Construct the fixed-width attribute that refers to this string.  
 209         ar
.attr_dataoffset 
= ab
->varcursor 
- ab
->fixedcursor
; 
 210         ar
.attr_length 
= count 
+ 1; 
 211         attrlist_pack_fixed(ab
, &ar
, sizeof(ar
)); 
 214          * Now compute how much available memory we have to copy the string text. 
 216          * space = the number of bytes available in the attribute buffer to hold the 
 219          * fit = the number of bytes to copy from the start of the string into the 
 220          *       attribute buffer, NOT including the NUL terminator.  If the attribute 
 221          *       buffer is large enough, this will be the string's length; otherwise, it 
 222          *       will be equal to "space". 
 224         space 
= ab
->allocated 
- (ab
->varcursor 
- ab
->base
); 
 225         fit 
= lmin(count
, space
); 
 230                  * If there is space remaining, copy data in, and  
 231                  * accommodate the trailing NUL terminator. 
 233                  * NOTE: if "space" is too small to hold the string and its NUL 
 234                  * terminator (space < fit + 1), then the string value in the attribute 
 235                  * buffer will NOT be NUL terminated! 
 237                  * NOTE 2: bcopy() will do nothing if the length ("fit") is zero. 
 238                  * Therefore, we don't bother checking for that here. 
 240                 bcopy(source
, ab
->varcursor
, fit
); 
 241                 /* is there room for our trailing nul? */ 
 243                         ab
->varcursor
[fit
++] = '\0'; 
 244                         /* 'fit' now the number of bytes AFTER adding in the NUL */ 
 246                          * Zero out any additional bytes we might have as a 
 247                          * result of rounding up. 
 249                         bytes_to_zero 
= min((roundup(fit
, 4) - fit
), 
 252                                 bzero(&(ab
->varcursor
[fit
]), bytes_to_zero
); 
 256          * always move in increments of 4 (including the trailing NUL) 
 258         ab
->varcursor 
+= roundup((count
+1), 4); 
 262 #define ATTR_PACK4(AB, V)                                                 \ 
 264                 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) {   \ 
 265                         *(uint32_t *)AB.fixedcursor = V;                  \ 
 266                         AB.fixedcursor += 4;                              \ 
 270 #define ATTR_PACK8(AB, V)                                                 \ 
 272                 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) {   \ 
 273                         memcpy(AB.fixedcursor, &V, 8);                    \ 
 274                         AB.fixedcursor += 8;                              \ 
 278 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v)) 
 279 #define ATTR_PACK_CAST(b, t, v)                                         \ 
 285 #define ATTR_PACK_TIME(b, v, is64)                                                      \ 
 288                         struct user64_timespec us = {v.tv_sec, v.tv_nsec};              \ 
 291                         struct user32_timespec us = {v.tv_sec, v.tv_nsec};              \ 
 298  * Table-driven setup for all valid common/volume attributes. 
 300 struct getvolattrlist_attrtab 
{ 
 303 #define VFSATTR_BIT(b)  (VFSATTR_ ## b) 
 306 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = { 
 307         {ATTR_CMN_NAME
,         0,                              sizeof(struct attrreference
)}, 
 308         {ATTR_CMN_DEVID
,        0,                              sizeof(dev_t
)}, 
 309         {ATTR_CMN_FSID
,         0,                              sizeof(fsid_t
)}, 
 310         {ATTR_CMN_OBJTYPE
,      0,                              sizeof(fsobj_type_t
)}, 
 311         {ATTR_CMN_OBJTAG
,       0,                              sizeof(fsobj_tag_t
)}, 
 312         {ATTR_CMN_OBJID
,        0,                              sizeof(fsobj_id_t
)}, 
 313         {ATTR_CMN_OBJPERMANENTID
, 0,                            sizeof(fsobj_id_t
)}, 
 314         {ATTR_CMN_PAROBJID
,     0,                              sizeof(fsobj_id_t
)}, 
 315         {ATTR_CMN_SCRIPT
,       0,                              sizeof(text_encoding_t
)}, 
 316         {ATTR_CMN_CRTIME
,       VFSATTR_BIT(f_create_time
),     ATTR_TIME_SIZE
}, 
 317         {ATTR_CMN_MODTIME
,      VFSATTR_BIT(f_modify_time
),     ATTR_TIME_SIZE
}, 
 318         {ATTR_CMN_CHGTIME
,      VFSATTR_BIT(f_modify_time
),     ATTR_TIME_SIZE
}, 
 319         {ATTR_CMN_ACCTIME
,      VFSATTR_BIT(f_access_time
),     ATTR_TIME_SIZE
}, 
 320         {ATTR_CMN_BKUPTIME
,     VFSATTR_BIT(f_backup_time
),     ATTR_TIME_SIZE
}, 
 321         {ATTR_CMN_FNDRINFO
,     0,                              32}, 
 322         {ATTR_CMN_OWNERID
,      0,                              sizeof(uid_t
)}, 
 323         {ATTR_CMN_GRPID
,        0,                              sizeof(gid_t
)}, 
 324         {ATTR_CMN_ACCESSMASK
,   0,                              sizeof(uint32_t)}, 
 325         {ATTR_CMN_FLAGS
,        0,                              sizeof(uint32_t)}, 
 326         {ATTR_CMN_USERACCESS
,   0,                              sizeof(uint32_t)}, 
 327         {ATTR_CMN_EXTENDED_SECURITY
, 0,                         sizeof(struct attrreference
)}, 
 328         {ATTR_CMN_UUID
,         0,                              sizeof(guid_t
)}, 
 329         {ATTR_CMN_GRPUUID
,      0,                              sizeof(guid_t
)}, 
 330         {ATTR_CMN_FILEID
,       0,                              sizeof(uint64_t)}, 
 331         {ATTR_CMN_PARENTID
,     0,                              sizeof(uint64_t)}, 
 332         {ATTR_CMN_RETURNED_ATTRS
, 0,                            sizeof(attribute_set_t
)}, 
 333         {ATTR_CMN_ERROR
,        0,                              sizeof(uint32_t)}, 
 336 #define ATTR_CMN_VOL_INVALID \ 
 337         (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \ 
 338          ATTR_CMN_FILEID | ATTR_CMN_PARENTID) 
 340 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = { 
 341         {ATTR_VOL_FSTYPE
,               0,                                              sizeof(uint32_t)}, 
 342         {ATTR_VOL_SIGNATURE
,            VFSATTR_BIT(f_signature
),                       sizeof(uint32_t)}, 
 343         {ATTR_VOL_SIZE
,                         VFSATTR_BIT(f_blocks
)  |  VFSATTR_BIT(f_bsize
),                         sizeof(off_t
)}, 
 344         {ATTR_VOL_SPACEFREE
,            VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
),    sizeof(off_t
)}, 
 345         {ATTR_VOL_SPACEAVAIL
,           VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
),   sizeof(off_t
)}, 
 346         {ATTR_VOL_MINALLOCATION
,        VFSATTR_BIT(f_bsize
),                           sizeof(off_t
)}, 
 347         {ATTR_VOL_ALLOCATIONCLUMP
,      VFSATTR_BIT(f_bsize
),                           sizeof(off_t
)}, 
 348         {ATTR_VOL_IOBLOCKSIZE
,          VFSATTR_BIT(f_iosize
),                          sizeof(uint32_t)}, 
 349         {ATTR_VOL_OBJCOUNT
,             VFSATTR_BIT(f_objcount
),                        sizeof(uint32_t)}, 
 350         {ATTR_VOL_FILECOUNT
,            VFSATTR_BIT(f_filecount
),                       sizeof(uint32_t)}, 
 351         {ATTR_VOL_DIRCOUNT
,             VFSATTR_BIT(f_dircount
),                        sizeof(uint32_t)}, 
 352         {ATTR_VOL_MAXOBJCOUNT
,          VFSATTR_BIT(f_maxobjcount
),                     sizeof(uint32_t)}, 
 353         {ATTR_VOL_MOUNTPOINT
,           0,                                              sizeof(struct attrreference
)}, 
 354         {ATTR_VOL_NAME
,                 VFSATTR_BIT(f_vol_name
),                        sizeof(struct attrreference
)}, 
 355         {ATTR_VOL_MOUNTFLAGS
,           0,                                              sizeof(uint32_t)}, 
 356         {ATTR_VOL_MOUNTEDDEVICE
,        0,                                              sizeof(struct attrreference
)}, 
 357         {ATTR_VOL_ENCODINGSUSED
,        0,                                              sizeof(uint64_t)}, 
 358         {ATTR_VOL_CAPABILITIES
,         VFSATTR_BIT(f_capabilities
),                    sizeof(vol_capabilities_attr_t
)}, 
 359         {ATTR_VOL_UUID
,                 VFSATTR_BIT(f_uuid
),                            sizeof(uuid_t
)}, 
 360         {ATTR_VOL_QUOTA_SIZE
,           VFSATTR_BIT(f_quota
) | VFSATTR_BIT(f_bsize
),    sizeof(off_t
)}, 
 361         {ATTR_VOL_RESERVED_SIZE
,        VFSATTR_BIT(f_reserved
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)}, 
 362         {ATTR_VOL_ATTRIBUTES
,           VFSATTR_BIT(f_attributes
),                      sizeof(vol_attributes_attr_t
)}, 
 363         {ATTR_VOL_INFO
, 0, 0}, 
 368 getvolattrlist_parsetab(struct getvolattrlist_attrtab 
*tab
, attrgroup_t attrs
, struct vfs_attr 
*vsp
, 
 369                 ssize_t 
*sizep
, int is_64bit
, unsigned int maxiter
) 
 371         attrgroup_t     recognised
; 
 375                 /* is this attribute set? */ 
 376                 if (tab
->attr 
& attrs
) { 
 377                         recognised 
|= tab
->attr
; 
 378                         vsp
->f_active 
|= tab
->bits
; 
 379                         if (tab
->size 
== ATTR_TIME_SIZE
) { 
 381                                         *sizep 
+= sizeof(struct user64_timespec
); 
 383                                         *sizep 
+= sizeof(struct user32_timespec
); 
 389         } while (((++tab
)->attr 
!= 0) && (--maxiter 
> 0)); 
 391         /* check to make sure that we recognised all of the passed-in attributes */ 
 392         if (attrs 
& ~recognised
) 
 398  * Given the attributes listed in alp, configure vap to request 
 399  * the data from a filesystem. 
 402 getvolattrlist_setupvfsattr(struct attrlist 
*alp
, struct vfs_attr 
*vsp
, ssize_t 
*sizep
, int is_64bit
) 
 409          * Parse the above tables. 
 411         *sizep 
= sizeof(uint32_t);      /* length count */ 
 412         if (alp
->commonattr
) { 
 413                 if ((alp
->commonattr 
& ATTR_CMN_VOL_INVALID
) && 
 414                     (alp
->commonattr 
& ATTR_CMN_RETURNED_ATTRS
) == 0) { 
 417                 if ((error 
= getvolattrlist_parsetab(getvolattrlist_common_tab
, 
 418                                 alp
->commonattr
, vsp
, sizep
, 
 420                                 sizeof(getvolattrlist_common_tab
)/sizeof(getvolattrlist_common_tab
[0]))) != 0) { 
 425             (error 
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
, sizeof(getvolattrlist_vol_tab
)/sizeof(getvolattrlist_vol_tab
[0]))) != 0) 
 432  * Given the attributes listed in asp and those supported 
 433  * in the vsp, fixup the asp attributes to reflect any 
 434  * missing attributes from the file system 
 437 getvolattrlist_fixupattrs(attribute_set_t 
*asp
, struct vfs_attr 
*vsp
) 
 439         struct getvolattrlist_attrtab 
*tab
; 
 441         if (asp
->commonattr
) { 
 442                 tab 
= getvolattrlist_common_tab
; 
 444                         if ((tab
->attr 
& asp
->commonattr
) && 
 446                             ((tab
->bits 
& vsp
->f_supported
) == 0)) { 
 447                                 asp
->commonattr 
&= ~tab
->attr
; 
 449                 } while ((++tab
)->attr 
!= 0); 
 452                 tab 
= getvolattrlist_vol_tab
; 
 454                         if ((tab
->attr 
& asp
->volattr
) && 
 456                             ((tab
->bits 
& vsp
->f_supported
) == 0)) { 
 457                                 asp
->volattr 
&= ~tab
->attr
; 
 459                 } while ((++tab
)->attr 
!= 0); 
 464  * Table-driven setup for all valid common/dir/file/fork attributes against files. 
 466 struct getattrlist_attrtab 
{ 
 469 #define VATTR_BIT(b)    (VNODE_ATTR_ ## b) 
 471         kauth_action_t  action
; 
 475  * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this  
 476  * information, and we will synthesize it at the VFS level. 
 478 static struct getattrlist_attrtab getattrlist_common_tab
[] = { 
 479         {ATTR_CMN_NAME
,         VATTR_BIT(va_name
),             sizeof(struct attrreference
),   KAUTH_VNODE_READ_ATTRIBUTES
}, 
 480         {ATTR_CMN_DEVID
,        0,                              sizeof(dev_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 481         {ATTR_CMN_FSID
,         0,                              sizeof(fsid_t
),                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 482         {ATTR_CMN_OBJTYPE
,      0,                              sizeof(fsobj_type_t
),           KAUTH_VNODE_READ_ATTRIBUTES
}, 
 483         {ATTR_CMN_OBJTAG
,       0,                              sizeof(fsobj_tag_t
),            KAUTH_VNODE_READ_ATTRIBUTES
}, 
 484         {ATTR_CMN_OBJID
,        VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 485         {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 486         {ATTR_CMN_PAROBJID
,     VATTR_BIT(va_parentid
),         sizeof(fsobj_id_t
),             KAUTH_VNODE_READ_ATTRIBUTES
}, 
 487         {ATTR_CMN_SCRIPT
,       VATTR_BIT(va_encoding
),         sizeof(text_encoding_t
),        KAUTH_VNODE_READ_ATTRIBUTES
}, 
 488         {ATTR_CMN_CRTIME
,       VATTR_BIT(va_create_time
),      ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 489         {ATTR_CMN_MODTIME
,      VATTR_BIT(va_modify_time
),      ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 490         {ATTR_CMN_CHGTIME
,      VATTR_BIT(va_change_time
),      ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 491         {ATTR_CMN_ACCTIME
,      VATTR_BIT(va_access_time
),      ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 492         {ATTR_CMN_BKUPTIME
,     VATTR_BIT(va_backup_time
),      ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 493         {ATTR_CMN_FNDRINFO
,     0,                              32,                             KAUTH_VNODE_READ_ATTRIBUTES
}, 
 494         {ATTR_CMN_OWNERID
,      VATTR_BIT(va_uid
),              sizeof(uid_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 495         {ATTR_CMN_GRPID
,        VATTR_BIT(va_gid
),              sizeof(gid_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 496         {ATTR_CMN_ACCESSMASK
,   VATTR_BIT(va_mode
),             sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 497         {ATTR_CMN_FLAGS
,        VATTR_BIT(va_flags
),            sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 498         {ATTR_CMN_GEN_COUNT
,    VATTR_BIT(va_write_gencount
),   sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 499         {ATTR_CMN_DOCUMENT_ID
,  VATTR_BIT(va_document_id
),      sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 500         {ATTR_CMN_USERACCESS
,   0,                              sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 501         {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
),         sizeof(struct attrreference
),   KAUTH_VNODE_READ_SECURITY
}, 
 502         {ATTR_CMN_UUID
,         VATTR_BIT(va_uuuid
),            sizeof(guid_t
),                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 503         {ATTR_CMN_GRPUUID
,      VATTR_BIT(va_guuid
),            sizeof(guid_t
),                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 504         {ATTR_CMN_FILEID
,       VATTR_BIT(va_fileid
),           sizeof(uint64_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 505         {ATTR_CMN_PARENTID
,     VATTR_BIT(va_parentid
),         sizeof(uint64_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 506         {ATTR_CMN_FULLPATH
,     0,                              sizeof(struct attrreference
),   KAUTH_VNODE_READ_ATTRIBUTES
}, 
 507         {ATTR_CMN_ADDEDTIME
,    VATTR_BIT(va_addedtime
),        ATTR_TIME_SIZE
,                 KAUTH_VNODE_READ_ATTRIBUTES
}, 
 508         {ATTR_CMN_RETURNED_ATTRS
, 0,                            sizeof(attribute_set_t
),        0}, 
 509         {ATTR_CMN_ERROR
,        0,                              sizeof(uint32_t),               0}, 
 510         {ATTR_CMN_DATA_PROTECT_FLAGS
, VATTR_BIT(va_dataprotect_class
), sizeof(uint32_t),        KAUTH_VNODE_READ_ATTRIBUTES
}, 
 514 static struct getattrlist_attrtab getattrlist_dir_tab
[] = { 
 515         {ATTR_DIR_LINKCOUNT
,    VATTR_BIT(va_dirlinkcount
),     sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 516         {ATTR_DIR_ENTRYCOUNT
,   VATTR_BIT(va_nchildren
),        sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 517         {ATTR_DIR_MOUNTSTATUS
,  0,                              sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 518         {ATTR_DIR_ALLOCSIZE
,    VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 519         {ATTR_DIR_IOBLOCKSIZE
,  VATTR_BIT(va_iosize
),           sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 520         {ATTR_DIR_DATALENGTH
,   VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 523 static struct getattrlist_attrtab getattrlist_file_tab
[] = { 
 524         {ATTR_FILE_LINKCOUNT
,   VATTR_BIT(va_nlink
),            sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 525         {ATTR_FILE_TOTALSIZE
,   VATTR_BIT(va_total_size
),       sizeof(off_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 526         {ATTR_FILE_ALLOCSIZE
,   VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 527         {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
),           sizeof(uint32_t),               KAUTH_VNODE_READ_ATTRIBUTES
}, 
 528         {ATTR_FILE_DEVTYPE
,     VATTR_BIT(va_rdev
),             sizeof(dev_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 529         {ATTR_FILE_DATALENGTH
,  VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 530         {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
}, 
 531         {ATTR_FILE_RSRCLENGTH
,  0,                              sizeof(off_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 532         {ATTR_FILE_RSRCALLOCSIZE
, 0,                            sizeof(off_t
),                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 536 //for forkattr bits repurposed as new common attributes 
 537 static struct getattrlist_attrtab getattrlist_common_extended_tab
[] = { 
 538         {ATTR_CMNEXT_RELPATH
,           0,                                                      sizeof(struct attrreference
),   KAUTH_VNODE_READ_ATTRIBUTES
}, 
 539         {ATTR_CMNEXT_PRIVATESIZE
,       VATTR_BIT(va_private_size
),     sizeof(off_t
),                                  KAUTH_VNODE_READ_ATTRIBUTES
}, 
 540         {ATTR_CMNEXT_LINKID
,            VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
),            sizeof(uint64_t),       KAUTH_VNODE_READ_ATTRIBUTES
}, 
 545  * This table is for attributes which are only set from the getattrlistbulk(2) 
 546  * call. These attributes have already been set from the common, file and 
 547  * directory tables but the vattr bits have not been recorded. Since these 
 548  * vattr bits are only used from the bulk call, we have a seperate table for 
 550  * The sizes are not returned from here since the sizes have already been 
 551  * accounted from the common, file and directory tables. 
 553 static struct getattrlist_attrtab getattrlistbulk_common_tab
[] = { 
 554         {ATTR_CMN_DEVID
,        VATTR_BIT(va_devid
),            0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 555         {ATTR_CMN_FSID
,         VATTR_BIT(va_fsid64
),           0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 556         {ATTR_CMN_OBJTYPE
,      VATTR_BIT(va_objtype
),          0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 557         {ATTR_CMN_OBJTAG
,       VATTR_BIT(va_objtag
),           0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 558         {ATTR_CMN_USERACCESS
,   VATTR_BIT(va_user_access
),      0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 559         {ATTR_CMN_FNDRINFO
,     VATTR_BIT(va_finderinfo
),       0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 563 static struct getattrlist_attrtab getattrlistbulk_file_tab
[] = { 
 564         {ATTR_FILE_RSRCLENGTH
,  VATTR_BIT(va_rsrc_length
),      0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 565         {ATTR_FILE_RSRCALLOCSIZE
, VATTR_BIT(va_rsrc_alloc
),     0,                      KAUTH_VNODE_READ_ATTRIBUTES
}, 
 569 static struct getattrlist_attrtab getattrlistbulk_common_extended_tab
[] = { 
 570         /* getattrlist_parsetab() expects > 1 entries */ 
 576  * The following are attributes that VFS can derive. 
 578  * A majority of them are the same attributes that are required for stat(2) and statfs(2). 
 580 #define VFS_DFLT_ATTR_VOL       (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE |  \ 
 581                                  ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE |  ATTR_VOL_QUOTA_SIZE | ATTR_VOL_RESERVED_SIZE | \ 
 582                                  ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION |  \ 
 583                                  ATTR_VOL_ALLOCATIONCLUMP |  ATTR_VOL_IOBLOCKSIZE |  \ 
 584                                  ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS |  \ 
 585                                  ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES |  \ 
 586                                  ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED) 
 588 #define VFS_DFLT_ATTR_CMN       (ATTR_CMN_NAME | ATTR_CMN_DEVID |  \ 
 589                                  ATTR_CMN_FSID | ATTR_CMN_OBJTYPE |  \ 
 590                                  ATTR_CMN_OBJTAG | ATTR_CMN_OBJID |  \ 
 591                                  ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT |  \ 
 592                                  ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME |  \ 
 593                                  ATTR_CMN_FNDRINFO |  \ 
 594                                  ATTR_CMN_OWNERID  | ATTR_CMN_GRPID |  \ 
 595                                  ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS |  \ 
 596                                  ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \ 
 597                                  ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS | \ 
 598                                  ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT | \ 
 599                                  ATTR_CMN_DATA_PROTECT_FLAGS) 
 601 #define VFS_DFLT_ATTR_CMN_EXT   (ATTR_CMNEXT_PRIVATESIZE | ATTR_CMNEXT_LINKID) 
 603 #define VFS_DFLT_ATTR_DIR       (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS) 
 605 #define VFS_DFLT_ATTR_FILE      (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE |  \ 
 606                                  ATTR_FILE_ALLOCSIZE  | ATTR_FILE_IOBLOCKSIZE |  \ 
 607                                  ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH |  \ 
 608                                  ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH |  \ 
 609                                  ATTR_FILE_RSRCALLOCSIZE) 
 612 getattrlist_parsetab(struct getattrlist_attrtab 
*tab
, attrgroup_t attrs
, 
 613     struct vnode_attr 
*vap
, ssize_t 
*sizep
, kauth_action_t 
*actionp
, 
 614     int is_64bit
, unsigned int maxiter
) 
 616         attrgroup_t     recognised
; 
 622                 /* is this attribute set? */ 
 623                 if (tab
->attr 
& attrs
) { 
 624                         recognised 
|= tab
->attr
; 
 626                                 vap
->va_active 
|= tab
->bits
; 
 628                                 if (tab
->size 
== ATTR_TIME_SIZE
) { 
 631                                                     struct user64_timespec
); 
 634                                                     struct user32_timespec
); 
 641                                 *actionp 
|= tab
->action
; 
 642                         if (attrs 
== recognised
) 
 643                                 break;  /* all done, get out */ 
 645         } while (((++tab
)->attr 
!= 0) && (--maxiter 
> 0)); 
 647         /* check to make sure that we recognised all of the passed-in attributes */ 
 648         if (attrs 
& ~recognised
) 
 654  * Given the attributes listed in alp, configure vap to request 
 655  * the data from a filesystem. 
 658 getattrlist_setupvattr(struct attrlist 
*alp
, struct vnode_attr 
*vap
, ssize_t 
*sizep
, kauth_action_t 
*actionp
, int is_64bit
, int isdir
, int use_fork
) 
 663          * Parse the above tables. 
 665         *sizep 
= sizeof(uint32_t);      /* length count */ 
 667         if (alp
->commonattr 
&& 
 668             (error 
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_common_tab
)/sizeof(getattrlist_common_tab
[0]))) != 0) 
 670         if (isdir 
&& alp
->dirattr 
&& 
 671             (error 
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_dir_tab
)/sizeof(getattrlist_dir_tab
[0]))) != 0) 
 673         if (!isdir 
&& alp
->fileattr 
&& 
 674             (error 
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_file_tab
)/sizeof(getattrlist_file_tab
[0]))) != 0) 
 676         if (use_fork 
&& alp
->forkattr 
&& 
 677             (error 
= getattrlist_parsetab(getattrlist_common_extended_tab
, alp
->forkattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_common_extended_tab
)/sizeof(getattrlist_common_extended_tab
[0]))) != 0) 
 684  * Given the attributes listed in alp, configure vap to request 
 685  * the data from a filesystem. 
 688 getattrlist_setupvattr_all(struct attrlist 
*alp
, struct vnode_attr 
*vap
, 
 689     enum vtype obj_type
, ssize_t 
*fixedsize
, int is_64bit
, int use_fork
) 
 694          * Parse the above tables. 
 697                 *fixedsize 
= sizeof(uint32_t); 
 699         if (alp
->commonattr
) { 
 700                 error 
= getattrlist_parsetab(getattrlist_common_tab
, 
 701                         alp
->commonattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 702                         sizeof(getattrlist_common_tab
)/sizeof(getattrlist_common_tab
[0])); 
 705                         /* Ignore any errrors from the bulk table */ 
 706                         (void)getattrlist_parsetab(getattrlistbulk_common_tab
, 
 707                                 alp
->commonattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 708                                 sizeof(getattrlistbulk_common_tab
)/sizeof(getattrlistbulk_common_tab
[0])); 
 710                          * turn off va_fsid since we will be using only 
 711                          * va_fsid64 for ATTR_CMN_FSID. 
 713                         VATTR_CLEAR_ACTIVE(vap
, va_fsid
); 
 717         if (!error 
&& (obj_type 
== VNON 
|| obj_type 
== VDIR
) && alp
->dirattr
) { 
 718                 error 
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, 
 719                                 vap
, fixedsize
, NULL
, is_64bit
, 
 720                                 sizeof(getattrlist_dir_tab
)/sizeof(getattrlist_dir_tab
[0])); 
 723         if (!error 
&& (obj_type 
!= VDIR
) && alp
->fileattr
) { 
 724                 error 
= getattrlist_parsetab(getattrlist_file_tab
, 
 725                         alp
->fileattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 726                         sizeof(getattrlist_file_tab
)/sizeof(getattrlist_file_tab
[0])); 
 729                         /*Ignore any errors from the bulk table */ 
 730                         (void)getattrlist_parsetab(getattrlistbulk_file_tab
, 
 731                                 alp
->fileattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 732                                 sizeof(getattrlistbulk_file_tab
)/sizeof(getattrlistbulk_file_tab
[0])); 
 736         /* fork attributes are like extended common attributes if enabled*/ 
 737         if (!error 
&& use_fork 
&& alp
->forkattr
) { 
 738                 error 
= getattrlist_parsetab(getattrlist_common_extended_tab
, 
 739                         alp
->forkattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 740                         sizeof(getattrlist_common_extended_tab
)/sizeof(getattrlist_common_extended_tab
[0])); 
 743                         (void)getattrlist_parsetab(getattrlistbulk_common_extended_tab
, 
 744                                 alp
->forkattr
, vap
, fixedsize
, NULL
, is_64bit
, 
 745                                 sizeof(getattrlistbulk_common_extended_tab
)/sizeof(getattrlistbulk_common_extended_tab
[0])); 
 753 vfs_setup_vattr_from_attrlist(struct attrlist 
*alp
, struct vnode_attr 
*vap
, 
 754     enum vtype obj_vtype
, ssize_t 
*attrs_fixed_sizep
, vfs_context_t ctx
) 
 756         // the caller passes us no options, we assume the caller wants the new fork 
 757         // attr behavior, hence the hardcoded 1 
 758         return (getattrlist_setupvattr_all(alp
, vap
, obj_vtype
, 
 759             attrs_fixed_sizep
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), 1)); 
 766  * Given the attributes listed in asp and those supported 
 767  * in the vap, fixup the asp attributes to reflect any 
 768  * missing attributes from the file system 
 771 getattrlist_fixupattrs(attribute_set_t 
*asp
, struct vnode_attr 
*vap
, int use_fork
) 
 773         struct getattrlist_attrtab 
*tab
; 
 775         if (asp
->commonattr
) { 
 776                 tab 
= getattrlist_common_tab
; 
 779                          * This if() statement is slightly confusing. We're trying to 
 780                          * iterate through all of the bits listed in the array  
 781                          * getattr_common_tab, and see if the filesystem was expected 
 782                          * to support it, and whether or not we need to do anything about this. 
 784                          * This array is full of structs that have 4 fields (attr, bits, size, action). 
 785                          * The first is used to store the ATTR_CMN_* bit that was being requested  
 786                          * from userland.  The second stores the VATTR_BIT corresponding to the field 
 787                          * filled in vnode_attr struct.  If it is 0, then we don't typically expect 
 788                          * the filesystem to fill in this field.  The third is the size of the field, 
 789                          * and the fourth is the type of kauth actions needed. 
 791                          * So, for all of the ATTR_CMN bits listed in this array, we iterate through  
 792                          * them, and check to see if it was both passed down to the filesystem via the 
 793                          * va_active bitfield, and whether or not we expect it to be emitted from 
 794                          * the filesystem.  If it wasn't supported, then we un-twiddle the bit and move 
 795                          * on.  This is done so that we can uncheck those bits and re-request 
 796                          * a vnode_getattr from the filesystem again. 
 798                         if ((tab
->attr 
& asp
->commonattr
) && 
 799                             (tab
->bits 
& vap
->va_active
) && 
 800                             (tab
->bits 
& vap
->va_supported
) == 0) { 
 801                                 asp
->commonattr 
&= ~tab
->attr
; 
 803                 } while ((++tab
)->attr 
!= 0); 
 806                 tab 
= getattrlist_dir_tab
; 
 808                         if ((tab
->attr 
& asp
->dirattr
) && 
 809                             (tab
->bits 
& vap
->va_active
) && 
 810                             (vap
->va_supported 
& tab
->bits
) == 0) { 
 811                                 asp
->dirattr 
&= ~tab
->attr
; 
 813                 } while ((++tab
)->attr 
!= 0); 
 816                 tab 
= getattrlist_file_tab
; 
 818                         if ((tab
->attr 
& asp
->fileattr
) && 
 819                             (tab
->bits 
& vap
->va_active
) && 
 820                             (vap
->va_supported 
& tab
->bits
) == 0) { 
 821                                 asp
->fileattr 
&= ~tab
->attr
; 
 823                 } while ((++tab
)->attr 
!= 0); 
 825         if (use_fork 
&& asp
->forkattr
) { 
 826                 tab 
= getattrlist_common_extended_tab
; 
 828                         if ((tab
->attr 
& asp
->forkattr
) && 
 829                             (tab
->bits 
& vap
->va_active
) && 
 830                             (vap
->va_supported 
& tab
->bits
) == 0) { 
 831                                 asp
->forkattr 
&= ~tab
->attr
; 
 833                 } while ((++tab
)->attr 
!= 0); 
 838 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context 
*ctx
) 
 841         char    uio_buf
[UIO_SIZEOF(1)]; 
 844         if ((auio 
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) { 
 847                 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32); 
 848                 error 
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
); 
 853         if (error 
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) { 
 854             add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
); 
 862  * Find something resembling a terminal component name in the mountedonname for vp 
 866 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t 
*nl
) 
 872          * We're looking for the last sequence of non / characters, but 
 873          * not including any trailing / characters. 
 878         for (cp 
= mn
; *cp 
!= 0; cp
++) { 
 880                         /* start of run of chars */ 
 886                         /* end of run of chars */ 
 893         /* need to close run? */ 
 900 getvolattrlist(vfs_context_t ctx
, vnode_t vp
, struct attrlist 
*alp
, 
 901                user_addr_t attributeBuffer
, size_t bufferSize
, uint64_t options
, 
 902                enum uio_seg segflg
, int is_64bit
) 
 905         struct vnode_attr va
; 
 906         struct _attrlist_buf ab
; 
 908         ssize_t         fixedsize
, varsize
; 
 909         const char      *cnp 
= NULL
;    /* protected by ATTR_CMN_NAME */ 
 910         ssize_t         cnl 
= 0;        /* protected by ATTR_CMN_NAME */ 
 919         vs
.f_vol_name 
= NULL
; 
 923         /* Check for special packing semantics */ 
 924         return_valid 
= (alp
->commonattr 
& ATTR_CMN_RETURNED_ATTRS
); 
 925         pack_invalid 
= (options 
& FSOPT_PACK_INVAL_ATTRS
); 
 927                 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */ 
 932                 /* Keep invalid attrs from being uninitialized */ 
 933                 bzero(&vs
, sizeof (vs
)); 
 934                 /* Generate a valid mask for post processing */ 
 935                 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
)); 
 939          * For now, the vnode must be the root of its filesystem. 
 940          * To relax this, we need to be able to find the root vnode of a filesystem 
 941          * from any vnode in the filesystem. 
 943         if (!vnode_isvroot(vp
)) { 
 945                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem"); 
 950          * Set up the vfs_attr structure and call the filesystem. 
 952         if ((error 
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) { 
 953                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed"); 
 956         if (vs
.f_active 
!= 0) { 
 957                 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */ 
 958                 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) { 
 959                         vs
.f_vol_name 
= (char *) kalloc(MAXPATHLEN
); 
 960                         if (vs
.f_vol_name 
== NULL
) { 
 962                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer"); 
 967                 VFS_DEBUG(ctx
, vp
, "ATTRLIST -       calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
); 
 968                 if ((error 
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) { 
 969                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
); 
 973                 error 
= mac_mount_check_getattr(ctx
, mnt
, &vs
); 
 975                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d", error
); 
 980                  * Did we ask for something the filesystem doesn't support? 
 982                 if (!VFSATTR_ALL_SUPPORTED(&vs
)) { 
 983                         /* default value for volume subtype */ 
 984                         if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
) 
 985                             && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
)) 
 986                                 VFSATTR_RETURN(&vs
, f_fssubtype
, 0); 
 989                          * If the file system didn't supply f_signature, then 
 990                          * default it to 'BD', which is the generic signature 
 991                          * that most Carbon file systems should return. 
 993                         if (VFSATTR_IS_ACTIVE(&vs
, f_signature
) 
 994                             && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
)) 
 995                                 VFSATTR_RETURN(&vs
, f_signature
, 0x4244); 
 997                         /* default for block size */ 
 998                         if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
) 
 999                             && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
)) 
1000                                 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
); 
1002                         /* default value for volume f_attributes */ 
1003                         if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
) 
1004                             && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) { 
1005                                 vol_attributes_attr_t 
*attrp 
= &vs
.f_attributes
; 
1007                                 attrp
->validattr
.commonattr 
= VFS_DFLT_ATTR_CMN
; 
1008                                 attrp
->validattr
.volattr 
= VFS_DFLT_ATTR_VOL
; 
1009                                 attrp
->validattr
.dirattr 
= VFS_DFLT_ATTR_DIR
; 
1010                                 attrp
->validattr
.fileattr 
= VFS_DFLT_ATTR_FILE
; 
1011                                 attrp
->validattr
.forkattr 
= VFS_DFLT_ATTR_CMN_EXT
; 
1013                                 attrp
->nativeattr
.commonattr 
=  0; 
1014                                 attrp
->nativeattr
.volattr 
= 0; 
1015                                 attrp
->nativeattr
.dirattr 
= 0; 
1016                                 attrp
->nativeattr
.fileattr 
= 0; 
1017                                 attrp
->nativeattr
.forkattr 
= 0; 
1018                                 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
); 
1021                         /* default value for volume f_capabilities */ 
1022                         if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) { 
1023                                 /* getattrlist is always supported now. */ 
1024                                 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) { 
1025                                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0; 
1026                                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
; 
1027                                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0; 
1028                                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0; 
1030                                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0; 
1031                                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
; 
1032                                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0; 
1033                                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0; 
1034                                         VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
); 
1037                                         /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */ 
1038                                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
; 
1039                                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
; 
1043                         /* check to see if our fixups were enough */ 
1044                         if (!VFSATTR_ALL_SUPPORTED(&vs
)) { 
1047                                                 /* Fix up valid mask for post processing */ 
1048                                                 getvolattrlist_fixupattrs(&ab
.valid
, &vs
); 
1050                                                 /* Force packing of everything asked for */ 
1051                                                 vs
.f_supported 
= vs
.f_active
; 
1053                                                 /* Adjust the requested attributes */ 
1054                                                 getvolattrlist_fixupattrs((attribute_set_t 
*)&alp
->commonattr
, &vs
); 
1065          * Some fields require data from the root vp 
1067         if (alp
->commonattr 
& (ATTR_CMN_OWNERID 
| ATTR_CMN_GRPID 
| ATTR_CMN_ACCESSMASK 
| ATTR_CMN_FLAGS 
| ATTR_CMN_SCRIPT
)) { 
1068                 VATTR_WANTED(&va
, va_uid
); 
1069                 VATTR_WANTED(&va
, va_gid
); 
1070                 VATTR_WANTED(&va
, va_mode
); 
1071                 VATTR_WANTED(&va
, va_flags
); 
1072                 VATTR_WANTED(&va
, va_encoding
); 
1074                 if ((error 
= vnode_getattr(vp
, &va
, ctx
)) != 0) { 
1075                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
); 
1079                 error 
= mac_vnode_check_getattr(ctx
, NOCRED
, vp
, &va
); 
1081                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d for root vnode", error
); 
1085                 if (VATTR_IS_ACTIVE(&va
, va_encoding
) && 
1086                     !VATTR_IS_SUPPORTED(&va
, va_encoding
)) { 
1087                         if (!return_valid 
|| pack_invalid
) 
1088                                 /* use kTextEncodingMacUnicode */ 
1089                                 VATTR_RETURN(&va
, va_encoding
, 0x7e); 
1091                                 /* don't use a default */ 
1092                                 alp
->commonattr 
&= ~ATTR_CMN_SCRIPT
; 
1097          * Compute variable-size buffer requirements. 
1100         if (alp
->commonattr 
& ATTR_CMN_NAME
) { 
1101                 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 && 
1102                         vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') { 
1103                         /* special case for boot volume.  Use root name when it's 
1104                          * available (which is the volume name) or just the mount on 
1105                          * name of "/".  we must do this for binary compatibility with 
1106                          * pre Tiger code.  returning nothing for the boot volume name 
1107                          * breaks installers - 3961058 
1109                         cnp 
= vnode_getname(vp
); 
1111                                 /* just use "/" as name */ 
1112                                 cnp 
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0]; 
1120                         getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
); 
1122                 if (alp
->commonattr 
& ATTR_CMN_NAME
) 
1123                         varsize 
+= roundup(cnl 
+ 1, 4); 
1125         if (alp
->volattr 
& ATTR_VOL_MOUNTPOINT
) 
1126                 varsize 
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4); 
1127         if (alp
->volattr 
& ATTR_VOL_NAME
) { 
1128                 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */ 
1129                 varsize 
+= roundup(strlen(vs
.f_vol_name
) + 1, 4); 
1131         if (alp
->volattr 
& ATTR_VOL_MOUNTEDDEVICE
) 
1132                 varsize 
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4); 
1135          * Allocate a target buffer for attribute results. 
1136          * Note that since we won't ever copy out more than the caller requested, 
1137          * we never need to allocate more than they offer. 
1139         ab
.allocated 
= ulmin(bufferSize
, fixedsize 
+ varsize
); 
1140         if (ab
.allocated 
> ATTR_MAX_BUFFER
) { 
1142                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
); 
1147             (ab
.allocated 
< (ssize_t
)(sizeof(uint32_t) + sizeof(attribute_set_t
))) && 
1148             !(options 
& FSOPT_REPORT_FULLSIZE
)) { 
1149                 uint32_t num_bytes_valid 
= sizeof(uint32_t); 
1151                  * Not enough to return anything and we don't have to report 
1152                  * how much space is needed. Get out now. 
1153                  * N.B. - We have only been called after having verified that 
1154                  * attributeBuffer is at least sizeof(uint32_t); 
1156                 if (UIO_SEG_IS_USER_SPACE(segflg
)) { 
1157                         error 
= copyout(&num_bytes_valid
, 
1158                             CAST_USER_ADDR_T(attributeBuffer
), num_bytes_valid
); 
1160                         bcopy(&num_bytes_valid
, (void *)attributeBuffer
, 
1161                             (size_t)num_bytes_valid
); 
1166         MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_ZERO 
| M_WAITOK
); 
1167         if (ab
.base 
== NULL
) { 
1169                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
); 
1174          * Pack results into the destination buffer. 
1176         ab
.fixedcursor 
= ab
.base 
+ sizeof(uint32_t); 
1178                 ab
.fixedcursor 
+= sizeof (attribute_set_t
); 
1179                 bzero(&ab
.actual
, sizeof (ab
.actual
)); 
1181         ab
.varcursor 
= ab
.base 
+ fixedsize
; 
1182         ab
.needed 
= fixedsize 
+ varsize
; 
1184         /* common attributes **************************************************/ 
1185         if (alp
->commonattr 
& ATTR_CMN_NAME
) { 
1186                 attrlist_pack_string(&ab
, cnp
, cnl
); 
1187                 ab
.actual
.commonattr 
|= ATTR_CMN_NAME
; 
1189         if (alp
->commonattr 
& ATTR_CMN_DEVID
) { 
1190                 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]); 
1191                 ab
.actual
.commonattr 
|= ATTR_CMN_DEVID
; 
1193         if (alp
->commonattr 
& ATTR_CMN_FSID
) { 
1194                 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
); 
1195                 ab
.actual
.commonattr 
|= ATTR_CMN_FSID
; 
1197         if (alp
->commonattr 
& ATTR_CMN_OBJTYPE
) { 
1198                 if (!return_valid 
|| pack_invalid
) 
1201         if (alp
->commonattr 
& ATTR_CMN_OBJTAG
) { 
1202                 ATTR_PACK4(ab
, vp
->v_tag
); 
1203                 ab
.actual
.commonattr 
|= ATTR_CMN_OBJTAG
; 
1205         if (alp
->commonattr 
& ATTR_CMN_OBJID
) { 
1206                 if (!return_valid 
|| pack_invalid
) { 
1207                         fsobj_id_t f 
= {0, 0}; 
1211         if (alp
->commonattr 
& ATTR_CMN_OBJPERMANENTID
) { 
1212                 if (!return_valid 
|| pack_invalid
) { 
1213                         fsobj_id_t f 
= {0, 0}; 
1217         if (alp
->commonattr 
& ATTR_CMN_PAROBJID
) { 
1218                 if (!return_valid 
|| pack_invalid
) { 
1219                         fsobj_id_t f 
= {0, 0}; 
1223         /* note that this returns the encoding for the volume name, not the node name */ 
1224         if (alp
->commonattr 
& ATTR_CMN_SCRIPT
) { 
1225                 ATTR_PACK4(ab
, va
.va_encoding
); 
1226                 ab
.actual
.commonattr 
|= ATTR_CMN_SCRIPT
; 
1228         if (alp
->commonattr 
& ATTR_CMN_CRTIME
) { 
1229                 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
); 
1230                 ab
.actual
.commonattr 
|= ATTR_CMN_CRTIME
; 
1232         if (alp
->commonattr 
& ATTR_CMN_MODTIME
) { 
1233                 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
); 
1234                 ab
.actual
.commonattr 
|= ATTR_CMN_MODTIME
; 
1236         if (alp
->commonattr 
& ATTR_CMN_CHGTIME
) { 
1237                 if (!return_valid 
|| pack_invalid
) 
1238                         ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
); 
1240         if (alp
->commonattr 
& ATTR_CMN_ACCTIME
) { 
1241                 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
); 
1242                 ab
.actual
.commonattr 
|= ATTR_CMN_ACCTIME
; 
1244         if (alp
->commonattr 
& ATTR_CMN_BKUPTIME
) { 
1245                 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
); 
1246                 ab
.actual
.commonattr 
|= ATTR_CMN_BKUPTIME
; 
1248         if (alp
->commonattr 
& ATTR_CMN_FNDRINFO
) { 
1251                  * This attribute isn't really Finder Info, at least for HFS. 
1253                 if (vp
->v_tag 
== VT_HFS
) { 
1254 #define HFS_GET_BOOT_INFO   (FCNTL_FS_SPECIFIC_BASE + 0x00004) 
1255                         error 
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
); 
1257                                 attrlist_pack_fixed(&ab
, f
, sizeof(f
)); 
1258                                 ab
.actual
.commonattr 
|= ATTR_CMN_FNDRINFO
; 
1259                         } else if (!return_valid
) { 
1262                 } else if (!return_valid 
|| pack_invalid
) { 
1263                         /* XXX we could at least pass out the volume UUID here */ 
1264                         bzero(&f
, sizeof(f
)); 
1265                         attrlist_pack_fixed(&ab
, f
, sizeof(f
)); 
1268         if (alp
->commonattr 
& ATTR_CMN_OWNERID
) { 
1269                 ATTR_PACK4(ab
, va
.va_uid
); 
1270                 ab
.actual
.commonattr 
|= ATTR_CMN_OWNERID
; 
1272         if (alp
->commonattr 
& ATTR_CMN_GRPID
) { 
1273                 ATTR_PACK4(ab
, va
.va_gid
); 
1274                 ab
.actual
.commonattr 
|= ATTR_CMN_GRPID
; 
1276         if (alp
->commonattr 
& ATTR_CMN_ACCESSMASK
) { 
1277                 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
); 
1278                 ab
.actual
.commonattr 
|= ATTR_CMN_ACCESSMASK
; 
1280         if (alp
->commonattr 
& ATTR_CMN_FLAGS
) { 
1281                 ATTR_PACK4(ab
, va
.va_flags
); 
1282                 ab
.actual
.commonattr 
|= ATTR_CMN_FLAGS
; 
1284         if (alp
->commonattr 
& ATTR_CMN_USERACCESS
) {    /* XXX this is expensive and also duplicate work */ 
1286                 if (vnode_isdir(vp
)) { 
1287                         if (vnode_authorize(vp
, NULL
, 
1288                                 KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_ADD_FILE 
| KAUTH_VNODE_ADD_SUBDIRECTORY 
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0) 
1290                         if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0) 
1292                         if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_SEARCH
, ctx
) == 0) 
1295                         if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0) 
1297                         if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_READ_DATA
, ctx
) == 0) 
1299                         if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_EXECUTE
, ctx
) == 0) 
1304                  * Rather than MAC preceding DAC, in this case we want 
1305                  * the smallest set of permissions granted by both MAC & DAC 
1306                  * checks.  We won't add back any permissions. 
1309                         if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0) 
1312                         if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0) 
1315                         if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0) 
1318                 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
); 
1319                 ATTR_PACK4(ab
, perms
); 
1320                 ab
.actual
.commonattr 
|= ATTR_CMN_USERACCESS
; 
1323          * The following common volume attributes are only 
1324          * packed when the pack_invalid mode is enabled. 
1329                 if (alp
->commonattr 
& ATTR_CMN_EXTENDED_SECURITY
) 
1330                         attrlist_pack_variable(&ab
, NULL
, 0); 
1331                 if (alp
->commonattr 
& ATTR_CMN_UUID
) 
1332                         ATTR_PACK(&ab
, kauth_null_guid
); 
1333                 if (alp
->commonattr 
& ATTR_CMN_GRPUUID
) 
1334                         ATTR_PACK(&ab
, kauth_null_guid
); 
1335                 if (alp
->commonattr 
& ATTR_CMN_FILEID
) 
1336                         ATTR_PACK8(ab
, fid
); 
1337                 if (alp
->commonattr 
& ATTR_CMN_PARENTID
) 
1338                         ATTR_PACK8(ab
, fid
); 
1341         /* volume attributes **************************************************/ 
1343         if (alp
->volattr 
& ATTR_VOL_FSTYPE
) { 
1344                 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
)); 
1345                 ab
.actual
.volattr 
|= ATTR_VOL_FSTYPE
; 
1347         if (alp
->volattr 
& ATTR_VOL_SIGNATURE
) { 
1348                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
); 
1349                 ab
.actual
.volattr 
|= ATTR_VOL_SIGNATURE
; 
1351         if (alp
->volattr 
& ATTR_VOL_SIZE
) { 
1352                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize 
* vs
.f_blocks
); 
1353                 ab
.actual
.volattr 
|= ATTR_VOL_SIZE
; 
1355         if (alp
->volattr 
& ATTR_VOL_SPACEFREE
) { 
1356                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize 
* vs
.f_bfree
); 
1357                 ab
.actual
.volattr 
|= ATTR_VOL_SPACEFREE
; 
1359         if (alp
->volattr 
& ATTR_VOL_SPACEAVAIL
) { 
1360                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize 
* vs
.f_bavail
); 
1361                 ab
.actual
.volattr 
|= ATTR_VOL_SPACEAVAIL
; 
1363         if (alp
->volattr 
& ATTR_VOL_MINALLOCATION
) { 
1364                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); 
1365                 ab
.actual
.volattr 
|= ATTR_VOL_MINALLOCATION
; 
1367         if (alp
->volattr 
& ATTR_VOL_ALLOCATIONCLUMP
) { 
1368                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);                 /* not strictly true */ 
1369                 ab
.actual
.volattr 
|= ATTR_VOL_ALLOCATIONCLUMP
; 
1371         if (alp
->volattr 
& ATTR_VOL_IOBLOCKSIZE
) { 
1372                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
); 
1373                 ab
.actual
.volattr 
|= ATTR_VOL_IOBLOCKSIZE
; 
1375         if (alp
->volattr 
& ATTR_VOL_OBJCOUNT
) { 
1376                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
); 
1377                 ab
.actual
.volattr 
|= ATTR_VOL_OBJCOUNT
; 
1379         if (alp
->volattr 
& ATTR_VOL_FILECOUNT
) { 
1380                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
); 
1381                 ab
.actual
.volattr 
|= ATTR_VOL_FILECOUNT
; 
1383         if (alp
->volattr 
& ATTR_VOL_DIRCOUNT
) { 
1384                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
); 
1385                 ab
.actual
.volattr 
|= ATTR_VOL_DIRCOUNT
; 
1387         if (alp
->volattr 
& ATTR_VOL_MAXOBJCOUNT
) { 
1388                 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
); 
1389                 ab
.actual
.volattr 
|= ATTR_VOL_MAXOBJCOUNT
; 
1391         if (alp
->volattr 
& ATTR_VOL_MOUNTPOINT
) { 
1392                 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0); 
1393                 ab
.actual
.volattr 
|= ATTR_VOL_MOUNTPOINT
; 
1395         if (alp
->volattr 
& ATTR_VOL_NAME
) { 
1396                 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0); 
1397                 ab
.actual
.volattr 
|= ATTR_VOL_NAME
; 
1399         if (alp
->volattr 
& ATTR_VOL_MOUNTFLAGS
) { 
1400                 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
); 
1401                 ab
.actual
.volattr 
|= ATTR_VOL_MOUNTFLAGS
; 
1403         if (alp
->volattr 
& ATTR_VOL_MOUNTEDDEVICE
) { 
1404                 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0); 
1405                 ab
.actual
.volattr 
|= ATTR_VOL_MOUNTEDDEVICE
; 
1407         if (alp
->volattr 
& ATTR_VOL_ENCODINGSUSED
) { 
1408                 if (!return_valid 
|| pack_invalid
) 
1409                         ATTR_PACK_CAST(&ab
, uint64_t, ~0LL);  /* return all encodings */ 
1411         if (alp
->volattr 
& ATTR_VOL_CAPABILITIES
) { 
1412                 /* fix up volume capabilities */ 
1413                 if (vfs_extendedsecurity(mnt
)) { 
1414                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
; 
1416                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
; 
1418                 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
; 
1421                  * if the filesystem doesn't mark either VOL_CAP_FMT_NO_IMMUTABLE_FILES 
1422                  * or VOL_CAP_FMT_NO_PERMISSIONS as valid, assume they're not supported 
1424                 if (!(vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_NO_IMMUTABLE_FILES
)) { 
1425                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] &= ~VOL_CAP_FMT_NO_IMMUTABLE_FILES
; 
1426                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] |= VOL_CAP_FMT_NO_IMMUTABLE_FILES
; 
1429                 if (!(vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_NO_PERMISSIONS
)) { 
1430                         vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] &= ~VOL_CAP_FMT_NO_PERMISSIONS
; 
1431                         vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] |= VOL_CAP_FMT_NO_PERMISSIONS
; 
1434                 ATTR_PACK(&ab
, vs
.f_capabilities
); 
1435                 ab
.actual
.volattr 
|= ATTR_VOL_CAPABILITIES
; 
1437         if (alp
->volattr 
& ATTR_VOL_UUID
) { 
1438                 ATTR_PACK(&ab
, vs
.f_uuid
); 
1439                 ab
.actual
.volattr 
|= ATTR_VOL_UUID
; 
1441         if (alp
->volattr 
& ATTR_VOL_QUOTA_SIZE
) { 
1442                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize 
* vs
.f_quota
); 
1443                 ab
.actual
.volattr 
|= ATTR_VOL_QUOTA_SIZE
; 
1445         if (alp
->volattr 
& ATTR_VOL_RESERVED_SIZE
) { 
1446                 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize 
* vs
.f_reserved
); 
1447                 ab
.actual
.volattr 
|= ATTR_VOL_RESERVED_SIZE
; 
1449         if (alp
->volattr 
& ATTR_VOL_ATTRIBUTES
) { 
1450                 /* fix up volume attribute information */ 
1452                 vs
.f_attributes
.validattr
.commonattr 
|= VFS_DFLT_ATTR_CMN
; 
1453                 vs
.f_attributes
.validattr
.volattr 
|= VFS_DFLT_ATTR_VOL
; 
1454                 vs
.f_attributes
.validattr
.dirattr 
|= VFS_DFLT_ATTR_DIR
; 
1455                 vs
.f_attributes
.validattr
.fileattr 
|= VFS_DFLT_ATTR_FILE
; 
1457                 if (vfs_extendedsecurity(mnt
)) { 
1458                         vs
.f_attributes
.validattr
.commonattr 
|= (ATTR_CMN_EXTENDED_SECURITY 
| ATTR_CMN_UUID 
| ATTR_CMN_GRPUUID
); 
1460                         vs
.f_attributes
.validattr
.commonattr 
&= ~(ATTR_CMN_EXTENDED_SECURITY 
| ATTR_CMN_UUID 
| ATTR_CMN_GRPUUID
); 
1461                         vs
.f_attributes
.nativeattr
.commonattr 
&= ~(ATTR_CMN_EXTENDED_SECURITY 
| ATTR_CMN_UUID 
| ATTR_CMN_GRPUUID
); 
1463                 ATTR_PACK(&ab
, vs
.f_attributes
); 
1464                 ab
.actual
.volattr 
|= ATTR_VOL_ATTRIBUTES
; 
1468         if (!return_valid 
&& (ab
.fixedcursor 
- ab
.base
) != fixedsize
) 
1469                 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x", 
1470                     fixedsize
, (long) (ab
.fixedcursor 
- ab
.base
), alp
->commonattr
, alp
->volattr
); 
1471         if (!return_valid 
&& ab
.varcursor 
!= (ab
.base 
+ ab
.needed
)) 
1472                 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor 
- ab
.base
), ab
.needed
); 
1475          * In the compatible case, we report the smaller of the required and returned sizes. 
1476          * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size 
1477          * of the result buffer, even if we copied less out.  The caller knows how big a buffer 
1478          * they gave us, so they can always check for truncation themselves. 
1480         *(uint32_t *)ab
.base 
= (options 
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed 
: imin(ab
.allocated
, ab
.needed
); 
1482         /* Return attribute set output if requested. */ 
1484             (ab
.allocated 
>= (ssize_t
)(sizeof(uint32_t) + sizeof(ab
.actual
)))) { 
1485                 ab
.actual
.commonattr 
|= ATTR_CMN_RETURNED_ATTRS
; 
1487                         /* Only report the attributes that are valid */ 
1488                         ab
.actual
.commonattr 
&= ab
.valid
.commonattr
; 
1489                         ab
.actual
.volattr 
&= ab
.valid
.volattr
; 
1491                 bcopy(&ab
.actual
, ab
.base 
+ sizeof(uint32_t), sizeof (ab
.actual
)); 
1494         if (UIO_SEG_IS_USER_SPACE(segflg
)) 
1495                 error 
= copyout(ab
.base
, CAST_USER_ADDR_T(attributeBuffer
), 
1498                 bcopy(ab
.base
, (void *)attributeBuffer
, (size_t)ab
.allocated
); 
1501         if (vs
.f_vol_name 
!= NULL
) 
1502                 kfree(vs
.f_vol_name
, MAXPATHLEN
); 
1506         if (ab
.base 
!= NULL
) 
1507                 FREE(ab
.base
, M_TEMP
); 
1508         VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
); 
1513  * Pack ATTR_COMMON attributes into a user buffer. 
1514  * alp is a pointer to the bitmap of attributes required. 
1515  * abp is the state of the attribute filling operation. 
1516  * The attribute data (along with some other fields that are required 
1520 attr_pack_common(vfs_context_t ctx
, struct vnode 
*vp
,  struct attrlist 
*alp
, 
1521     struct _attrlist_buf 
*abp
, struct vnode_attr 
*vap
, int proc_is64
, 
1522     const char *cnp
, ssize_t cnl
, const char *fullpathptr
, 
1523     ssize_t fullpathlen
, int return_valid
, int pack_invalid
, int vtype
, 
1529         if ((alp
->commonattr 
& ATTR_CMN_ERROR
) && 
1530             (!return_valid 
|| pack_invalid
)) { 
1531                 ATTR_PACK4((*abp
), 0); 
1532                 abp
->actual
.commonattr 
|= ATTR_CMN_ERROR
; 
1534         if (alp
->commonattr 
& ATTR_CMN_NAME
) { 
1535                 attrlist_pack_string(abp
, cnp
, cnl
); 
1536                 abp
->actual
.commonattr 
|= ATTR_CMN_NAME
; 
1538         if (alp
->commonattr 
& ATTR_CMN_DEVID
) { 
1541                             vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]); 
1542                         abp
->actual
.commonattr 
|= ATTR_CMN_DEVID
; 
1543                 } else if (VATTR_IS_SUPPORTED(vap
, va_devid
)) { 
1544                         ATTR_PACK4((*abp
), vap
->va_devid
); 
1545                         abp
->actual
.commonattr 
|= ATTR_CMN_DEVID
; 
1546                 } else if (!return_valid 
|| pack_invalid
) { 
1547                         ATTR_PACK4((*abp
), 0); 
1550         if (alp
->commonattr 
& ATTR_CMN_FSID
) { 
1553                             vp
->v_mount
->mnt_vfsstat
.f_fsid
); 
1554                         abp
->actual
.commonattr 
|= ATTR_CMN_FSID
; 
1555                 } else if (VATTR_IS_SUPPORTED(vap
, va_fsid64
)) { 
1556                         ATTR_PACK8((*abp
), vap
->va_fsid64
); 
1557                         abp
->actual
.commonattr 
|= ATTR_CMN_FSID
; 
1558                 } else if (!return_valid 
|| pack_invalid
) { 
1559                         fsid_t fsid 
= {{0}}; 
1561                         ATTR_PACK8((*abp
), fsid
); 
1564         if (alp
->commonattr 
& ATTR_CMN_OBJTYPE
) { 
1566                         ATTR_PACK4((*abp
), vtype
); 
1567                         abp
->actual
.commonattr 
|= ATTR_CMN_OBJTYPE
; 
1568                 } else if (VATTR_IS_SUPPORTED(vap
, va_objtype
)) { 
1569                         ATTR_PACK4((*abp
), vap
->va_objtype
); 
1570                         abp
->actual
.commonattr 
|= ATTR_CMN_OBJTYPE
; 
1571                 } else if (!return_valid 
|| pack_invalid
) { 
1572                         ATTR_PACK4((*abp
), 0); 
1575         if (alp
->commonattr 
& ATTR_CMN_OBJTAG
) { 
1577                         ATTR_PACK4((*abp
), vp
->v_tag
); 
1578                         abp
->actual
.commonattr 
|= ATTR_CMN_OBJTAG
; 
1579                 } else if (VATTR_IS_SUPPORTED(vap
, va_objtag
)) { 
1580                         ATTR_PACK4((*abp
), vap
->va_objtag
); 
1581                         abp
->actual
.commonattr 
|= ATTR_CMN_OBJTAG
; 
1582                 } else if (!return_valid 
|| pack_invalid
) { 
1583                         ATTR_PACK4((*abp
), 0); 
1586         if (alp
->commonattr 
& ATTR_CMN_OBJID
) { 
1588                  * Carbon can't deal with us reporting the target ID 
1589                  * for links.  So we ask the filesystem to give us the 
1590                  * source ID as well, and if it gives us one, we use 
1593                 if (vap
->va_vaflags 
& VA_64BITOBJIDS
) { 
1594                         if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) { 
1595                                 ATTR_PACK8((*abp
),  vap
->va_linkid
); 
1597                                 ATTR_PACK8((*abp
),  vap
->va_fileid
); 
1601                         if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) { 
1602                                 f
.fid_objno 
= (uint32_t)vap
->va_linkid
; 
1604                                 f
.fid_objno 
= (uint32_t)vap
->va_fileid
; 
1606                         f
.fid_generation 
= 0; 
1607                         ATTR_PACK8((*abp
), f
); 
1609                 abp
->actual
.commonattr 
|= ATTR_CMN_OBJID
; 
1611         if (alp
->commonattr 
& ATTR_CMN_OBJPERMANENTID
) { 
1613                  * Carbon can't deal with us reporting the target ID 
1614                  * for links.  So we ask the filesystem to give us the 
1615                  * source ID as well, and if it gives us one, we use 
1618                 if (vap
->va_vaflags 
& VA_64BITOBJIDS
) { 
1619                         if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) { 
1620                                 ATTR_PACK8((*abp
),  vap
->va_linkid
); 
1622                                 ATTR_PACK8((*abp
),  vap
->va_fileid
); 
1626                         if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) { 
1627                                 f
.fid_objno 
= (uint32_t)vap
->va_linkid
; 
1629                                 f
.fid_objno 
= (uint32_t)vap
->va_fileid
; 
1631                         f
.fid_generation 
= 0; 
1632                         ATTR_PACK8((*abp
), f
); 
1634                 abp
->actual
.commonattr 
|= ATTR_CMN_OBJPERMANENTID
; 
1636         if (alp
->commonattr 
& ATTR_CMN_PAROBJID
) { 
1637                 if (vap
->va_vaflags 
& VA_64BITOBJIDS
) { 
1638                         ATTR_PACK8((*abp
), vap
->va_parentid
); 
1641                         f
.fid_objno 
= (uint32_t)vap
->va_parentid
; 
1642                         f
.fid_generation 
= 0; 
1643                         ATTR_PACK8((*abp
), f
); 
1645                 abp
->actual
.commonattr 
|= ATTR_CMN_PAROBJID
; 
1647         if (alp
->commonattr 
& ATTR_CMN_SCRIPT
) { 
1648                 if (VATTR_IS_SUPPORTED(vap
, va_encoding
)) { 
1649                         ATTR_PACK4((*abp
), vap
->va_encoding
); 
1650                         abp
->actual
.commonattr 
|= ATTR_CMN_SCRIPT
; 
1651                 } else if (!return_valid 
|| pack_invalid
) { 
1652                         ATTR_PACK4((*abp
), 0x7e); 
1655         if (alp
->commonattr 
& ATTR_CMN_CRTIME
) { 
1656                 ATTR_PACK_TIME((*abp
), vap
->va_create_time
, proc_is64
); 
1657                 abp
->actual
.commonattr 
|= ATTR_CMN_CRTIME
; 
1659         if (alp
->commonattr 
& ATTR_CMN_MODTIME
) { 
1660                 ATTR_PACK_TIME((*abp
), vap
->va_modify_time
, proc_is64
); 
1661                 abp
->actual
.commonattr 
|= ATTR_CMN_MODTIME
; 
1663         if (alp
->commonattr 
& ATTR_CMN_CHGTIME
) { 
1664                 ATTR_PACK_TIME((*abp
), vap
->va_change_time
, proc_is64
); 
1665                 abp
->actual
.commonattr 
|= ATTR_CMN_CHGTIME
; 
1667         if (alp
->commonattr 
& ATTR_CMN_ACCTIME
) { 
1668                 ATTR_PACK_TIME((*abp
), vap
->va_access_time
, proc_is64
); 
1669                 abp
->actual
.commonattr 
|= ATTR_CMN_ACCTIME
; 
1671         if (alp
->commonattr 
& ATTR_CMN_BKUPTIME
) { 
1672                 ATTR_PACK_TIME((*abp
), vap
->va_backup_time
, proc_is64
); 
1673                 abp
->actual
.commonattr 
|= ATTR_CMN_BKUPTIME
; 
1676          * They are requesting user access, we should obtain this before getting  
1677          * the finder info. For some network file systems this is a performance 
1680         if (alp
->commonattr 
& ATTR_CMN_USERACCESS
) {    /* this is expensive */ 
1681                 if (vp 
&& !is_bulk
) { 
1682                         if (vtype 
== VDIR
) { 
1683                                 if (vnode_authorize(vp
, NULL
, 
1684                                     KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_ADD_FILE 
| 
1685                                     KAUTH_VNODE_ADD_SUBDIRECTORY 
| 
1686                                     KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0) 
1689                                 if (vnode_authorize(vp
, NULL
, 
1690                                     KAUTH_VNODE_ACCESS 
| 
1691                                     KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0) 
1694                                 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| 
1695                                     KAUTH_VNODE_SEARCH
, ctx
) == 0) 
1698                                 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| 
1699                                     KAUTH_VNODE_WRITE_DATA
, ctx
) == 0) 
1702                                 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_READ_DATA
, ctx
) == 0) 
1704                                 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS 
| KAUTH_VNODE_EXECUTE
, ctx
) == 0) 
1707                 } else if (is_bulk 
&& 
1708                     VATTR_IS_SUPPORTED(vap
, va_user_access
)) { 
1709                         perms 
= vap
->va_user_access
; 
1712         if (alp
->commonattr 
& ATTR_CMN_FNDRINFO
) { 
1716                 if (vp 
&& !is_bulk
) { 
1718                         char    uio_buf
[UIO_SIZEOF(1)]; 
1720                         if ((auio 
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, 
1721                             UIO_READ
, uio_buf
, sizeof(uio_buf
))) == NULL
) { 
1725                         uio_addiov(auio
, CAST_USER_ADDR_T(abp
->fixedcursor
), 
1727                         /* fisize may be reset to 0 after this call */ 
1728                         error 
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, 
1729                                             &fisize
, XATTR_NOSECURITY
, ctx
); 
1733                          * Default to zeros if its not available, 
1734                          * unless ATTR_CMN_RETURNED_ATTRS was requested. 
1737                             (!return_valid 
|| pack_invalid
) && 
1738                             ((error 
== ENOATTR
) || (error 
== ENOENT
) || 
1739                             (error 
== ENOTSUP
) || (error 
== EPERM
))) { 
1740                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes"); 
1741                                 bzero(abp
->fixedcursor
, 32); 
1746                                 abp
->fixedcursor 
+= 32; 
1747                                 abp
->actual
.commonattr 
|= ATTR_CMN_FNDRINFO
; 
1748                         } else if (!return_valid
) { 
1752                                  * If we can inform the caller that we can't 
1753                                  * return this attribute, reset error and 
1754                                  * continue with the rest of the attributes. 
1758                 } else if (VATTR_IS_SUPPORTED(vap
, va_finderinfo
)) { 
1759                         bcopy(&vap
->va_finderinfo
[0], abp
->fixedcursor
, fisize
); 
1760                         abp
->fixedcursor 
+= fisize
; 
1761                         abp
->actual
.commonattr 
|= ATTR_CMN_FNDRINFO
; 
1762                 } else if (!return_valid 
|| pack_invalid
) { 
1763                         bzero(abp
->fixedcursor
, fisize
); 
1764                         abp
->fixedcursor 
+= fisize
; 
1767         if (alp
->commonattr 
& ATTR_CMN_OWNERID
) { 
1768                 ATTR_PACK4((*abp
), vap
->va_uid
); 
1769                 abp
->actual
.commonattr 
|= ATTR_CMN_OWNERID
; 
1771         if (alp
->commonattr 
& ATTR_CMN_GRPID
) { 
1772                 ATTR_PACK4((*abp
), vap
->va_gid
); 
1773                 abp
->actual
.commonattr 
|= ATTR_CMN_GRPID
; 
1775         if (alp
->commonattr 
& ATTR_CMN_ACCESSMASK
) { 
1776                 ATTR_PACK4((*abp
), vap
->va_mode
); 
1777                 abp
->actual
.commonattr 
|= ATTR_CMN_ACCESSMASK
; 
1779         if (alp
->commonattr 
& ATTR_CMN_FLAGS
) { 
1780                 ATTR_PACK4((*abp
), vap
->va_flags
); 
1781                 abp
->actual
.commonattr 
|= ATTR_CMN_FLAGS
; 
1783         if (alp
->commonattr 
& ATTR_CMN_GEN_COUNT
) { 
1784                 if (VATTR_IS_SUPPORTED(vap
, va_write_gencount
)) { 
1785                         ATTR_PACK4((*abp
), vap
->va_write_gencount
); 
1786                         abp
->actual
.commonattr 
|= ATTR_CMN_GEN_COUNT
; 
1787                 } else if (!return_valid 
|| pack_invalid
) { 
1788                         ATTR_PACK4((*abp
), 0); 
1792         if (alp
->commonattr 
& ATTR_CMN_DOCUMENT_ID
) { 
1793                 if (VATTR_IS_SUPPORTED(vap
, va_document_id
)) { 
1794                         ATTR_PACK4((*abp
), vap
->va_document_id
); 
1795                         abp
->actual
.commonattr 
|= ATTR_CMN_DOCUMENT_ID
; 
1796                 } else if (!return_valid 
|| pack_invalid
) { 
1797                         ATTR_PACK4((*abp
), 0); 
1800         /* We already obtain the user access, so just fill in the buffer here */ 
1801         if (alp
->commonattr 
& ATTR_CMN_USERACCESS
) { 
1803                 if (!is_bulk 
&& vp
) { 
1805                          * Rather than MAC preceding DAC, in this case we want 
1806                          * the smallest set of permissions granted by both MAC & 
1807                          * DAC checks.  We won't add back any permissions. 
1810                                 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0) 
1813                                 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0) 
1816                                 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0) 
1820                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
); 
1821                 if (!is_bulk 
&& vp
) { 
1822                         ATTR_PACK4((*abp
), perms
); 
1823                         abp
->actual
.commonattr 
|= ATTR_CMN_USERACCESS
; 
1824                 } else if (is_bulk 
&& VATTR_IS_SUPPORTED(vap
, va_user_access
)) { 
1825                         ATTR_PACK4((*abp
), perms
); 
1826                         abp
->actual
.commonattr 
|= ATTR_CMN_USERACCESS
; 
1827                 } else if (!return_valid 
|| pack_invalid
) { 
1828                         ATTR_PACK4((*abp
), 0); 
1831         if (alp
->commonattr 
& ATTR_CMN_EXTENDED_SECURITY
) { 
1832                 if (VATTR_IS_SUPPORTED(vap
, va_acl
) && (vap
->va_acl 
!= NULL
)) { 
1833                         struct kauth_filesec fsec
; 
1835                          * We want to return a kauth_filesec (for now), but all we have is a kauth_acl. 
1837                         fsec
.fsec_magic 
= KAUTH_FILESEC_MAGIC
; 
1838                         fsec
.fsec_owner 
= kauth_null_guid
; 
1839                         fsec
.fsec_group 
= kauth_null_guid
; 
1840                         attrlist_pack_variable2(abp
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), vap
->va_acl
, KAUTH_ACL_COPYSIZE(vap
->va_acl
)); 
1841                         abp
->actual
.commonattr 
|= ATTR_CMN_EXTENDED_SECURITY
; 
1842                 } else if (!return_valid 
|| pack_invalid
) { 
1843                         attrlist_pack_variable(abp
, NULL
, 0); 
1846         if (alp
->commonattr 
& ATTR_CMN_UUID
) { 
1847                 if (VATTR_IS_SUPPORTED(vap
, va_uuuid
)) { 
1848                         ATTR_PACK(abp
, vap
->va_uuuid
); 
1849                         abp
->actual
.commonattr 
|= ATTR_CMN_UUID
; 
1850                 } else if (!return_valid 
|| pack_invalid
) { 
1851                         ATTR_PACK(abp
, kauth_null_guid
); 
1854         if (alp
->commonattr 
& ATTR_CMN_GRPUUID
) { 
1855                 if (VATTR_IS_SUPPORTED(vap
, va_guuid
)) { 
1856                         ATTR_PACK(abp
, vap
->va_guuid
); 
1857                         abp
->actual
.commonattr 
|= ATTR_CMN_GRPUUID
; 
1858                 } else if (!return_valid 
|| pack_invalid
) { 
1859                         ATTR_PACK(abp
, kauth_null_guid
); 
1862         if (alp
->commonattr 
& ATTR_CMN_FILEID
) { 
1863                 ATTR_PACK8((*abp
), vap
->va_fileid
); 
1864                 abp
->actual
.commonattr 
|= ATTR_CMN_FILEID
; 
1866         if (alp
->commonattr 
& ATTR_CMN_PARENTID
) { 
1867                 ATTR_PACK8((*abp
), vap
->va_parentid
); 
1868                 abp
->actual
.commonattr 
|= ATTR_CMN_PARENTID
; 
1871         if (alp
->commonattr 
& ATTR_CMN_FULLPATH
) { 
1873                         attrlist_pack_string (abp
, fullpathptr
, fullpathlen
); 
1874                         abp
->actual
.commonattr 
|= ATTR_CMN_FULLPATH
; 
1878         if (alp
->commonattr 
& ATTR_CMN_ADDEDTIME
) { 
1879                 if (VATTR_IS_SUPPORTED(vap
, va_addedtime
)) { 
1880                         ATTR_PACK_TIME((*abp
), vap
->va_addedtime
, proc_is64
); 
1881                         abp
->actual
.commonattr 
|= ATTR_CMN_ADDEDTIME
; 
1882                 } else if (!return_valid 
|| pack_invalid
) { 
1883                         struct timespec zerotime 
= {0, 0}; 
1885                         ATTR_PACK_TIME((*abp
), zerotime
, proc_is64
); 
1888         if (alp
->commonattr 
& ATTR_CMN_DATA_PROTECT_FLAGS
) { 
1889                 if (VATTR_IS_SUPPORTED(vap
, va_dataprotect_class
)) { 
1890                         ATTR_PACK4((*abp
), vap
->va_dataprotect_class
); 
1891                         abp
->actual
.commonattr 
|= ATTR_CMN_DATA_PROTECT_FLAGS
; 
1892                 } else if (!return_valid 
|| pack_invalid
) { 
1893                         ATTR_PACK4((*abp
), 0); 
1901 attr_pack_dir(struct vnode 
*vp
, struct attrlist 
*alp
, struct _attrlist_buf 
*abp
, 
1902     struct vnode_attr 
*vap
, int return_valid
, int pack_invalid
) 
1904         if (alp
->dirattr 
& ATTR_DIR_LINKCOUNT
) {  /* full count of entries */ 
1905                 ATTR_PACK4((*abp
), (uint32_t)vap
->va_dirlinkcount
); 
1906                 abp
->actual
.dirattr 
|= ATTR_DIR_LINKCOUNT
; 
1908         if (alp
->dirattr 
& ATTR_DIR_ENTRYCOUNT
) { 
1909                 ATTR_PACK4((*abp
), (uint32_t)vap
->va_nchildren
); 
1910                 abp
->actual
.dirattr 
|= ATTR_DIR_ENTRYCOUNT
; 
1912         if (alp
->dirattr 
& ATTR_DIR_MOUNTSTATUS
) { 
1917                          * The vnode that is passed down may either be a 
1918                          * top level vnode of a mount stack or a mounted 
1919                          * on vnode. In either case, the directory should 
1920                          * be reported as a mount point. 
1922                         if ((vp
->v_flag 
& VROOT
) ||  vnode_mountedhere(vp
)) { 
1923                                 mntstat 
= DIR_MNTSTATUS_MNTPOINT
; 
1929                          * Report back on active vnode triggers 
1930                          * that can directly trigger a mount 
1932                         if (vp
->v_resolve 
&& 
1933                             !(vp
->v_resolve
->vr_flags 
& VNT_NO_DIRECT_MOUNT
)) { 
1934                                 mntstat 
|= DIR_MNTSTATUS_TRIGGER
; 
1941                 ATTR_PACK4((*abp
), mntstat
); 
1942                 abp
->actual
.dirattr 
|= ATTR_DIR_MOUNTSTATUS
; 
1944         if (alp
->dirattr 
& ATTR_DIR_ALLOCSIZE
) { 
1945                 if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) { 
1946                         ATTR_PACK8((*abp
), vap
->va_data_alloc
); 
1947                         abp
->actual
.dirattr 
|= ATTR_DIR_ALLOCSIZE
; 
1948                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) { 
1949                         ATTR_PACK8((*abp
), vap
->va_total_alloc
); 
1950                         abp
->actual
.dirattr 
|= ATTR_DIR_ALLOCSIZE
; 
1951                 } else if (!return_valid 
|| pack_invalid
) { 
1952                         uint64_t zero_val 
= 0; 
1953                         ATTR_PACK8((*abp
), zero_val
); 
1956         if (alp
->dirattr 
& ATTR_DIR_IOBLOCKSIZE
) { 
1957                 if (VATTR_IS_SUPPORTED(vap
, va_iosize
)) { 
1958                         ATTR_PACK4((*abp
), vap
->va_iosize
); 
1959                         abp
->actual
.dirattr 
|= ATTR_DIR_IOBLOCKSIZE
; 
1960                 } else if (!return_valid 
|| pack_invalid
) { 
1961                         ATTR_PACK4((*abp
), 0); 
1965          * If the filesystem does not support datalength 
1966          * or dataallocsize, then we infer that totalsize and 
1967          * totalalloc are substitutes. 
1969         if (alp
->dirattr 
& ATTR_DIR_DATALENGTH
) { 
1970                 if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) { 
1971                         ATTR_PACK8((*abp
), vap
->va_data_size
); 
1972                         abp
->actual
.dirattr 
|= ATTR_DIR_DATALENGTH
; 
1973                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) { 
1974                         ATTR_PACK8((*abp
), vap
->va_total_size
); 
1975                         abp
->actual
.dirattr 
|= ATTR_DIR_DATALENGTH
; 
1976                 } else if (!return_valid 
|| pack_invalid
) { 
1977                         uint64_t zero_val 
= 0; 
1978                         ATTR_PACK8((*abp
), zero_val
); 
1986  * The is_bulk parameter differentiates whether the function is called from 
1987  * getattrlist or getattrlistbulk. When coming in from getattrlistbulk, 
1988  * the corresponding va_* values are expected to be the values filled and no 
1989  * attempt is made to retrieve them by calling back into the filesystem. 
1992 attr_pack_file(vfs_context_t ctx
, struct vnode 
*vp
,  struct attrlist 
*alp
, 
1993     struct _attrlist_buf 
*abp
, struct vnode_attr 
*vap
, int return_valid
, 
1994     int pack_invalid
, int is_bulk
) 
1997         uint64_t rlength 
= 0; 
1998         uint64_t ralloc 
= 0; 
2002          * Pre-fetch the rsrc attributes now so we only get them once. 
2003          * Fetch the resource fork size/allocation via xattr interface 
2005         if (vp 
&& !is_bulk 
&& 
2006             (alp
->fileattr 
& (ATTR_FILE_TOTALSIZE 
| ATTR_FILE_ALLOCSIZE 
| 
2007             ATTR_FILE_RSRCLENGTH 
| ATTR_FILE_RSRCALLOCSIZE
))) { 
2009                 error 
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, 
2010                     &rsize
, XATTR_NOSECURITY
, ctx
); 
2012                         if ((error 
== ENOENT
) || (error 
== ENOATTR
) || 
2013                             (error 
== ENOTSUP
) || (error 
== EPERM
) || 
2014                             (error 
== EACCES
)) { 
2023                 if (alp
->fileattr 
& (ATTR_FILE_RSRCALLOCSIZE 
| 
2024                     ATTR_FILE_ALLOCSIZE
)) { 
2027                         blksize 
= vp
->v_mount
->mnt_vfsstat
.f_bsize
; 
2032                         ralloc 
= roundup(rsize
, blksize
); 
2036         if (alp
->fileattr 
& ATTR_FILE_LINKCOUNT
) { 
2037                 ATTR_PACK4((*abp
), (uint32_t)vap
->va_nlink
); 
2038                 abp
->actual
.fileattr 
|= ATTR_FILE_LINKCOUNT
; 
2041          * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes: 
2042          * We infer that if the filesystem does not support va_data_size or va_data_alloc 
2043          * it must not know about alternate forks.  So when we need to gather 
2044          * the total size or total alloc, it's OK to substitute the total size for 
2045          * the data size below.  This is because it is likely a flat filesystem and we must 
2046          * be using AD files to store the rsrc fork and EAs. 
2048          * Additionally, note that getattrlist is barred from being called on 
2049          * resource fork paths. (Search for CN_ALLOWRSRCFORK).  So if the filesystem does 
2050          * support va_data_size, it is guaranteed to represent the data fork's size.  This 
2051          * is an important distinction to make because when we call vnode_getattr on 
2052          * an HFS resource fork vnode, to get the size, it will vend out the resource 
2053          * fork's size (it only gets the size of the passed-in vnode). 
2055         if (alp
->fileattr 
& ATTR_FILE_TOTALSIZE
) { 
2057                         uint64_t totalsize 
= rlength
; 
2059                         if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) { 
2060                                 totalsize 
+= vap
->va_data_size
; 
2061                         } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) { 
2062                                 totalsize 
+= vap
->va_total_size
; 
2065                         ATTR_PACK8((*abp
), totalsize
); 
2066                         abp
->actual
.fileattr 
|= ATTR_FILE_TOTALSIZE
; 
2067                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) { 
2068                         ATTR_PACK8((*abp
), vap
->va_total_size
); 
2069                         abp
->actual
.fileattr 
|= ATTR_FILE_TOTALSIZE
; 
2070                 } else if (!return_valid 
|| pack_invalid
) { 
2071                         uint64_t zero_val 
= 0; 
2073                         ATTR_PACK8((*abp
), zero_val
); 
2076         if (alp
->fileattr 
& ATTR_FILE_ALLOCSIZE
) { 
2078                         uint64_t totalalloc 
= ralloc
; 
2081                          * If data_alloc is supported, then it must represent the 
2084                         if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) { 
2085                                 totalalloc 
+= vap
->va_data_alloc
; 
2086                         } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) { 
2087                                 totalalloc 
+= vap
->va_total_alloc
; 
2090                         ATTR_PACK8((*abp
), totalalloc
); 
2091                         abp
->actual
.fileattr 
|= ATTR_FILE_ALLOCSIZE
; 
2092                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) { 
2093                         ATTR_PACK8((*abp
), vap
->va_total_alloc
); 
2094                         abp
->actual
.fileattr 
|= ATTR_FILE_ALLOCSIZE
; 
2095                 } else if (!return_valid 
|| pack_invalid
) { 
2096                         uint64_t zero_val 
= 0; 
2098                         ATTR_PACK8((*abp
), zero_val
); 
2101         if (alp
->fileattr 
& ATTR_FILE_IOBLOCKSIZE
) { 
2102                 if (VATTR_IS_SUPPORTED(vap
, va_iosize
)) { 
2103                         ATTR_PACK4((*abp
), vap
->va_iosize
); 
2104                         abp
->actual
.fileattr 
|= ATTR_FILE_IOBLOCKSIZE
; 
2105                 } else if (!return_valid 
|| pack_invalid
) { 
2106                         ATTR_PACK4((*abp
), 0); 
2109         if (alp
->fileattr 
& ATTR_FILE_CLUMPSIZE
) { 
2110                 if (!return_valid 
|| pack_invalid
) { 
2111                         ATTR_PACK4((*abp
), 0);     /* this value is deprecated */ 
2112                         abp
->actual
.fileattr 
|= ATTR_FILE_CLUMPSIZE
; 
2115         if (alp
->fileattr 
& ATTR_FILE_DEVTYPE
) { 
2116                 if (vp 
&& (vp
->v_type 
== VCHR 
|| vp
->v_type 
== VBLK
)) { 
2119                         if (vp
->v_specinfo 
!= NULL
) { 
2120                                 dev 
= vp
->v_specinfo
->si_rdev
; 
2121                         } else if (VATTR_IS_SUPPORTED(vap
, va_rdev
)) { 
2126                         ATTR_PACK4((*abp
), dev
); 
2127                         abp
->actual
.fileattr 
|= ATTR_FILE_DEVTYPE
; 
2129                         ATTR_PACK4((*abp
), 0); 
2130                         abp
->actual
.fileattr 
|= ATTR_FILE_DEVTYPE
; 
2131                 } else if (VATTR_IS_SUPPORTED(vap
, va_rdev
)) { 
2132                         ATTR_PACK4((*abp
), vap
->va_rdev
); 
2133                         abp
->actual
.fileattr 
|= ATTR_FILE_DEVTYPE
; 
2134                 } else if (!return_valid 
|| pack_invalid
) { 
2135                         ATTR_PACK4((*abp
), 0); 
2139          * If the filesystem does not support datalength 
2140          * or dataallocsize, then we infer that totalsize and 
2141          * totalalloc are substitutes. 
2143         if (alp
->fileattr 
& ATTR_FILE_DATALENGTH
) { 
2144                 if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) { 
2145                         ATTR_PACK8((*abp
), vap
->va_data_size
); 
2146                         abp
->actual
.fileattr 
|= ATTR_FILE_DATALENGTH
; 
2147                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)){ 
2148                         ATTR_PACK8((*abp
), vap
->va_total_size
); 
2149                         abp
->actual
.fileattr 
|= ATTR_FILE_DATALENGTH
; 
2150                 } else if (!return_valid 
|| pack_invalid
) { 
2151                         uint64_t zero_val 
= 0; 
2152                         ATTR_PACK8((*abp
), zero_val
); 
2155         if (alp
->fileattr 
& ATTR_FILE_DATAALLOCSIZE
) { 
2156                 if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) { 
2157                         ATTR_PACK8((*abp
), vap
->va_data_alloc
); 
2158                         abp
->actual
.fileattr 
|= ATTR_FILE_DATAALLOCSIZE
; 
2159                 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)){ 
2160                         ATTR_PACK8((*abp
), vap
->va_total_alloc
); 
2161                         abp
->actual
.fileattr 
|= ATTR_FILE_DATAALLOCSIZE
; 
2162                 } else if (!return_valid 
|| pack_invalid
) { 
2163                         uint64_t zero_val 
= 0; 
2164                         ATTR_PACK8((*abp
), zero_val
); 
2167         /* already got the resource fork size/allocation above */ 
2168         if (alp
->fileattr 
& ATTR_FILE_RSRCLENGTH
) { 
2170                         ATTR_PACK8((*abp
), rlength
); 
2171                         abp
->actual
.fileattr 
|= ATTR_FILE_RSRCLENGTH
; 
2172                 } else if (VATTR_IS_SUPPORTED(vap
, va_rsrc_length
)) { 
2173                         ATTR_PACK8((*abp
), vap
->va_rsrc_length
); 
2174                         abp
->actual
.fileattr 
|= ATTR_FILE_RSRCLENGTH
; 
2175                 } else if (!return_valid 
|| pack_invalid
) { 
2176                         uint64_t zero_val 
= 0; 
2178                         ATTR_PACK8((*abp
), zero_val
); 
2181         if (alp
->fileattr 
& ATTR_FILE_RSRCALLOCSIZE
) { 
2183                         ATTR_PACK8((*abp
), ralloc
); 
2184                         abp
->actual
.fileattr 
|= ATTR_FILE_RSRCALLOCSIZE
; 
2185                 } else if (VATTR_IS_SUPPORTED(vap
, va_rsrc_alloc
)) { 
2186                         ATTR_PACK8((*abp
), vap
->va_rsrc_alloc
); 
2187                         abp
->actual
.fileattr 
|= ATTR_FILE_RSRCALLOCSIZE
; 
2188                 } else if (!return_valid 
|| pack_invalid
) { 
2189                         uint64_t zero_val 
= 0; 
2191                         ATTR_PACK8((*abp
), zero_val
); 
2199  * Pack FORKATTR attributes into a user buffer. 
2200  * alp is a pointer to the bitmap of attributes required. 
2201  * abp is the state of the attribute filling operation. 
2202  * The attribute data (along with some other fields that are required 
2206 attr_pack_common_extended(struct vnode 
*vp
, struct attrlist 
*alp
, 
2207                 struct _attrlist_buf 
*abp
, const char *relpathptr
, ssize_t relpathlen
, 
2208                 struct vnode_attr 
*vap
, int return_valid
, int pack_invalid
) 
2210         if (vp 
&& (alp
->forkattr 
& ATTR_CMNEXT_RELPATH
)) { 
2211                 attrlist_pack_string(abp
, relpathptr
, relpathlen
); 
2212                 abp
->actual
.forkattr 
|= ATTR_CMNEXT_RELPATH
; 
2215         if (alp
->forkattr 
& ATTR_CMNEXT_PRIVATESIZE
) { 
2216                 if (VATTR_IS_SUPPORTED(vap
, va_private_size
)) { 
2217                         ATTR_PACK8((*abp
), vap
->va_private_size
); 
2218                         abp
->actual
.forkattr 
|= ATTR_CMNEXT_PRIVATESIZE
; 
2219                 } else if (!return_valid 
|| pack_invalid
) { 
2220                         uint64_t zero_val 
= 0; 
2221                         ATTR_PACK8((*abp
), zero_val
); 
2225         if (alp
->forkattr 
& ATTR_CMNEXT_LINKID
) { 
2228                 if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) 
2229                         linkid 
= vap
->va_linkid
; 
2231                         linkid 
= vap
->va_fileid
; 
2233                 ATTR_PACK8((*abp
), linkid
); 
2234                 abp
->actual
.forkattr 
|= ATTR_CMNEXT_LINKID
; 
2241 vattr_get_alt_data(vnode_t vp
, struct attrlist 
*alp
, struct vnode_attr 
*vap
, 
2242     int return_valid
, int is_bulk
, vfs_context_t ctx
) 
2245          * There are a couple of special cases. 
2246          * If we are after object IDs, we can make do with va_fileid. 
2248         if ((alp
->commonattr 
& 
2249             (ATTR_CMN_OBJID 
| ATTR_CMN_OBJPERMANENTID 
| ATTR_CMN_FILEID
)) && 
2250             !VATTR_IS_SUPPORTED(vap
, va_linkid
)) { 
2251                 /* forget we wanted this */ 
2252                 VATTR_CLEAR_ACTIVE(vap
, va_linkid
); 
2256          * Many filesystems don't know their parent object id. 
2257          * If necessary, attempt to derive it from the vnode. 
2259         if ((alp
->commonattr 
& (ATTR_CMN_PAROBJID 
| ATTR_CMN_PARENTID
)) && 
2260             !VATTR_IS_SUPPORTED(vap
, va_parentid
) && vp 
&& !is_bulk
) { 
2263                 if ((dvp 
= vnode_getparent(vp
)) != NULLVP
) { 
2264                         struct vnode_attr lva
; 
2267                         VATTR_WANTED(&lva
, va_fileid
); 
2268                         if (vnode_getattr(dvp
, &lva
, ctx
) == 0 && 
2269                             VATTR_IS_SUPPORTED(vap
, va_fileid
)) { 
2270                                 vap
->va_parentid 
= lva
.va_fileid
; 
2271                                 VATTR_SET_SUPPORTED(vap
, va_parentid
); 
2277          * And we can report datasize/alloc from total. 
2279         if ((alp
->fileattr 
& ATTR_FILE_DATALENGTH
) && 
2280             !VATTR_IS_SUPPORTED(vap
, va_data_size
)) { 
2281                 VATTR_CLEAR_ACTIVE(vap
, va_data_size
); 
2284         if ((alp
->fileattr 
& ATTR_FILE_DATAALLOCSIZE
) && 
2285             !VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) { 
2286                 VATTR_CLEAR_ACTIVE(vap
, va_data_alloc
); 
2290          * If we don't have an encoding, go with UTF-8 
2292         if ((alp
->commonattr 
& ATTR_CMN_SCRIPT
) && 
2293             !VATTR_IS_SUPPORTED(vap
, va_encoding
) && !return_valid
) { 
2294                 VATTR_RETURN(vap
, va_encoding
, 
2295                     0x7e /* kTextEncodingMacUnicode */); 
2299          * If we don't have a name, we'll get one from the vnode or 
2302         if ((alp
->commonattr 
& ATTR_CMN_NAME
) && 
2303             !VATTR_IS_SUPPORTED(vap
, va_name
)) { 
2304                 VATTR_CLEAR_ACTIVE(vap
, va_name
); 
2307         /* If va_dirlinkcount isn't supported use a default of 1. */ 
2308         if ((alp
->dirattr 
& ATTR_DIR_LINKCOUNT
) && 
2309             !VATTR_IS_SUPPORTED(vap
, va_dirlinkcount
)) { 
2310                 VATTR_RETURN(vap
, va_dirlinkcount
, 1); 
2315 calc_varsize(vnode_t vp
, struct attrlist 
*alp
, struct vnode_attr 
*vap
, 
2316    ssize_t 
*varsizep
, char *fullpathptr
, ssize_t 
*fullpathlenp
, 
2317    char *relpathptr
, ssize_t 
*relpathlenp
, const char **vnamep
, 
2318    const char **cnpp
, ssize_t 
*cnlp
) 
2322         *varsizep 
= 0; /* length count */ 
2323         /* We may need to fix up the name attribute if requested */ 
2324         if (alp
->commonattr 
& ATTR_CMN_NAME
) { 
2325                 if (VATTR_IS_SUPPORTED(vap
, va_name
)) { 
2326                         vap
->va_name
[MAXPATHLEN
-1] = '\0';      /* Ensure nul-termination */ 
2327                         *cnpp 
= vap
->va_name
; 
2328                         *cnlp 
= strlen(*cnpp
); 
2330                         /* Filesystem did not support getting the name */ 
2331                         if (vnode_isvroot(vp
)) { 
2332                                 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 && 
2333                                                 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') { 
2334                                         /* special case for boot volume.  Use root name when it's 
2335                                          * available (which is the volume name) or just the mount on 
2336                                          * name of "/".  we must do this for binary compatibility with 
2337                                          * pre Tiger code.  returning nothing for the boot volume name 
2338                                          * breaks installers - 3961058 
2340                                         *cnpp 
= *vnamep 
= vnode_getname(vp
); 
2341                                         if (*cnpp 
== NULL
) { 
2342                                                 /* just use "/" as name */ 
2343                                                 *cnpp 
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0]; 
2345                                         *cnlp 
= strlen(*cnpp
); 
2348                                         getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, cnpp
, cnlp
); 
2352                                 *cnpp 
= *vnamep 
= vnode_getname(vp
); 
2354                                 if (*cnpp 
!= NULL
) { 
2355                                         *cnlp 
= strlen(*cnpp
); 
2361                 *varsizep 
+= roundup(*cnlp 
+ 1, 4); 
2365          * Compute the full path to this vnode, if necessary. This attribute is almost certainly 
2366          * not supported by any filesystem, so build the path to this vnode at this time. 
2368         if (vp 
&& (alp
->commonattr 
& ATTR_CMN_FULLPATH
)) { 
2369                 int len 
= MAXPATHLEN
; 
2372                 /* call build_path making sure NOT to use the cache-only behavior */ 
2373                 err 
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current()); 
2380                         *fullpathlenp 
= strlen(fullpathptr
); 
2382                 *varsizep 
+= roundup(((*fullpathlenp
) + 1), 4); 
2386          * Compute this vnode's volume relative path. 
2388         if (vp 
&& (alp
->forkattr 
& ATTR_CMNEXT_RELPATH
)) { 
2392                 /* call build_path making sure NOT to use the cache-only behavior */ 
2393                 err 
= build_path(vp
, relpathptr
, MAXPATHLEN
, &len
, BUILDPATH_VOLUME_RELATIVE
, vfs_context_current()); 
2399                 //`len' includes trailing null 
2400                 *relpathlenp 
= len 
- 1; 
2401                 *varsizep 
+= roundup(len
, 4); 
2405          * We have a kauth_acl_t but we will be returning a kauth_filesec_t. 
2407          * XXX This needs to change at some point; since the blob is opaque in 
2408          * user-space this is OK. 
2410         if ((alp
->commonattr 
& ATTR_CMN_EXTENDED_SECURITY
) && 
2411                         VATTR_IS_SUPPORTED(vap
, va_acl
) && 
2412                         (vap
->va_acl 
!= NULL
)) { 
2415                  * Since we have a kauth_acl_t (not a kauth_filesec_t), we have to check against 
2416                  * KAUTH_FILESEC_NOACL ourselves 
2418                 if (vap
->va_acl
->acl_entrycount 
== KAUTH_FILESEC_NOACL
) { 
2419                         *varsizep 
+= roundup((KAUTH_FILESEC_SIZE(0)), 4); 
2422                         *varsizep 
+= roundup ((KAUTH_FILESEC_SIZE(vap
->va_acl
->acl_entrycount
)), 4); 
2431 vfs_attr_pack_internal(vnode_t vp
, uio_t auio
, struct attrlist 
*alp
, 
2432     uint64_t options
, struct vnode_attr 
*vap
, __unused 
void *fndesc
, 
2433     vfs_context_t ctx
, int is_bulk
, enum vtype vtype
, ssize_t fixedsize
) 
2435         struct _attrlist_buf ab
; 
2439         const char *vname 
= NULL
; 
2443         ssize_t fullpathlen
; 
2450         int alloc_local_buf
; 
2451         const int use_fork 
= options 
& FSOPT_ATTR_CMN_EXTENDED
; 
2453         proc_is64 
= proc_is64bit(vfs_context_proc(ctx
)); 
2462         alloc_local_buf 
= 0; 
2464         buf_size 
= (ssize_t
)uio_resid(auio
); 
2465         if ((buf_size 
<= 0) || (uio_iovcnt(auio
) > 1)) 
2469         /* Check for special packing semantics */ 
2470         return_valid 
= (alp
->commonattr 
& ATTR_CMN_RETURNED_ATTRS
) ? 1 : 0; 
2471         pack_invalid 
= (options 
& FSOPT_PACK_INVAL_ATTRS
) ? 1 : 0; 
2474                 /* Generate a valid mask for post processing */ 
2475                 bcopy(&(alp
->commonattr
), &ab
.valid
, sizeof (attribute_set_t
)); 
2478         /* did we ask for something the filesystem doesn't support? */ 
2479         if (vap
->va_active 
&& !VATTR_ALL_SUPPORTED(vap
)) { 
2480                 vattr_get_alt_data(vp
, alp
, vap
, return_valid
, is_bulk
, 
2484                 if (!VATTR_ALL_SUPPORTED(vap
)) { 
2485                         if (return_valid 
&& pack_invalid
) { 
2486                                 /* Fix up valid mask for post processing */ 
2487                                 getattrlist_fixupattrs(&ab
.valid
, vap
, use_fork
); 
2489                                 /* Force packing of everything asked for */ 
2490                                 vap
->va_supported 
= vap
->va_active
; 
2491                         } else if (return_valid
) { 
2492                                 /* Adjust the requested attributes */ 
2493                                 getattrlist_fixupattrs( 
2494                                     (attribute_set_t 
*)&(alp
->commonattr
), vap
, use_fork
); 
2504         //if a path is requested, allocate a temporary buffer to build it 
2505         if (vp 
&& (alp
->commonattr 
& (ATTR_CMN_FULLPATH
))) { 
2506                 fullpathptr 
= (char*) kalloc(MAXPATHLEN
); 
2507                 if (fullpathptr 
== NULL
) { 
2509                         VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer"); 
2512                 bzero(fullpathptr
, MAXPATHLEN
); 
2515         // only interpret fork attributes if they're used as new common attributes 
2516         if (vp 
&& use_fork 
&& (alp
->forkattr 
& (ATTR_CMNEXT_RELPATH
))) { 
2517                 relpathptr 
= (char*) kalloc(MAXPATHLEN
); 
2518                 if (relpathptr 
== NULL
) { 
2520                         VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate relpath buffer"); 
2523                 bzero(relpathptr
, MAXPATHLEN
); 
2527          * Compute variable-space requirements. 
2529         error 
= calc_varsize(vp
, alp
, vap
, &varsize
, fullpathptr
, &fullpathlen
, 
2530                         relpathptr
, &relpathlen
, &vname
, &cnp
, &cnl
); 
2535          * Allocate a target buffer for attribute results. 
2537          * Note that we won't ever copy out more than the caller requested, even though 
2538          * we might have to allocate more than they offer so that the diagnostic checks 
2539          * don't result in a panic if the caller's buffer is too small.. 
2541         ab
.allocated 
= fixedsize 
+ varsize
; 
2542         /* Cast 'allocated' to an unsigned to verify allocation size */ 
2543         if ( ((size_t)ab
.allocated
) > ATTR_MAX_BUFFER
) { 
2545                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
); 
2550          * Special handling for bulk calls, align to 8 (and only if enough 
2554                 if (buf_size 
< ab
.allocated
) { 
2559                         newlen 
= (ab
.allocated 
+ 7) & ~0x07; 
2560                         /* Align only if enough space for alignment */ 
2561                         if (newlen 
<= (uint32_t)buf_size
) 
2562                                 ab
.allocated 
= newlen
; 
2567          * See if we can reuse buffer passed in i.e. it is a kernel buffer 
2570         if (uio_isuserspace(auio
) || (buf_size 
< ab
.allocated
)) { 
2571                 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, 
2573                 alloc_local_buf 
= 1; 
2576                  * In case this is a kernel buffer and sufficiently 
2577                  * big, this function will try to use that buffer 
2578                  * instead of allocating another buffer and bcopy'ing 
2581                  * The calculation below figures out where to start 
2582                  * writing in the buffer and once all the data has been 
2583                  * filled in, uio_resid is updated to reflect the usage 
2586                  * uio_offset cannot be used here to determine the 
2587                  * starting location as uio_offset could be set to a 
2588                  * value which has nothing to do the location 
2591                 ab
.base 
= (char *)uio_curriovbase(auio
) + 
2592                     ((ssize_t
)uio_curriovlen(auio
) - buf_size
); 
2593                 bzero(ab
.base
, ab
.allocated
); 
2596         if (ab
.base 
== NULL
) { 
2598                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
); 
2603         /* set the S_IFMT bits for the mode */ 
2604         if (alp
->commonattr 
& ATTR_CMN_ACCESSMASK
) { 
2606                         switch (vp
->v_type
) { 
2608                                 vap
->va_mode 
|= S_IFREG
; 
2611                                 vap
->va_mode 
|= S_IFDIR
; 
2614                                 vap
->va_mode 
|= S_IFBLK
; 
2617                                 vap
->va_mode 
|= S_IFCHR
; 
2620                                 vap
->va_mode 
|= S_IFLNK
; 
2623                                 vap
->va_mode 
|= S_IFSOCK
; 
2626                                 vap
->va_mode 
|= S_IFIFO
; 
2636          * Pack results into the destination buffer. 
2638         ab
.fixedcursor 
= ab
.base 
+ sizeof(uint32_t); 
2640                 ab
.fixedcursor 
+= sizeof (attribute_set_t
); 
2641                 bzero(&ab
.actual
, sizeof (ab
.actual
)); 
2643         ab
.varcursor 
= ab
.base 
+ fixedsize
; 
2644         ab
.needed 
= ab
.allocated
; 
2646         /* common attributes ************************************************/ 
2647         error 
= attr_pack_common(ctx
, vp
, alp
, &ab
, vap
, proc_is64
, cnp
, cnl
, 
2648             fullpathptr
, fullpathlen
, return_valid
, pack_invalid
, vtype
, is_bulk
); 
2650         /* directory attributes *********************************************/ 
2651         if (!error 
&& alp
->dirattr 
&& (vtype 
== VDIR
)) { 
2652                 error 
= attr_pack_dir(vp
, alp
, &ab
, vap
, return_valid
, pack_invalid
); 
2655         /* file attributes **************************************************/ 
2656         if (!error 
&& alp
->fileattr 
&& (vtype 
!= VDIR
)) { 
2657                 error 
= attr_pack_file(ctx
, vp
, alp
, &ab
, vap
, return_valid
, 
2658                     pack_invalid
, is_bulk
); 
2661         /* common extended attributes *****************************************/ 
2662         if (!error 
&& use_fork
) { 
2663                 error 
= attr_pack_common_extended(vp
, alp
, &ab
, relpathptr
, relpathlen
, 
2664                     vap
, return_valid
, pack_invalid
); 
2671         if (!return_valid 
&& (ab
.fixedcursor 
- ab
.base
) != fixedsize
) 
2672                 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x", 
2673                     fixedsize
, (long) (ab
.fixedcursor 
- ab
.base
), alp
->commonattr
, alp
->volattr
); 
2674         if (!return_valid 
&& ab
.varcursor 
!= (ab
.base 
+ ab
.needed
)) 
2675                 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor 
- ab
.base
), ab
.needed
); 
2678          * In the compatible case, we report the smaller of the required and returned sizes. 
2679          * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size 
2680          * of the result buffer, even if we copied less out.  The caller knows how big a buffer 
2681          * they gave us, so they can always check for truncation themselves. 
2683         *(uint32_t *)ab
.base 
= (options 
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed 
: imin(ab
.allocated
, ab
.needed
); 
2685         /* Return attribute set output if requested. */ 
2687                 ab
.actual
.commonattr 
|= ATTR_CMN_RETURNED_ATTRS
; 
2689                         /* Only report the attributes that are valid */ 
2690                         ab
.actual
.commonattr 
&= ab
.valid
.commonattr
; 
2691                         ab
.actual
.dirattr 
&= ab
.valid
.dirattr
; 
2692                         ab
.actual
.fileattr 
&= ab
.valid
.fileattr
; 
2694                 bcopy(&ab
.actual
, ab
.base 
+ sizeof(uint32_t), sizeof (ab
.actual
)); 
2697         copy_size 
= imin(buf_size
, ab
.allocated
); 
2699         /* Only actually copyout as much out as the user buffer can hold */ 
2700         if (alloc_local_buf
) { 
2701                 error 
= uiomove(ab
.base
, copy_size
, auio
); 
2703                 off_t orig_offset 
= uio_offset(auio
); 
2706                  * The buffer in the uio struct was used directly 
2707                  * (i.e. it was a kernel buffer and big enough 
2708                  * to hold the data required) in order to avoid 
2709                  * un-needed allocation and copies. 
2711                  * At this point, update the resid value to what it 
2712                  * would be if this was the result of a uiomove. The 
2713                  * offset is also incremented, though it may not 
2714                  * mean anything to the caller but that is what 
2715                  * uiomove does as well. 
2717                 uio_setresid(auio
, buf_size 
- copy_size
); 
2718                 uio_setoffset(auio
, orig_offset 
+ (off_t
)copy_size
); 
2723                 vnode_putname(vname
); 
2725                 kfree(fullpathptr
, MAXPATHLEN
); 
2727                 kfree(relpathptr
, MAXPATHLEN
); 
2728         if (ab
.base 
!= NULL 
&& alloc_local_buf
) 
2729                 FREE(ab
.base
, M_TEMP
); 
2734 vfs_attr_pack(vnode_t vp
, uio_t uio
, struct attrlist 
*alp
, uint64_t options
, 
2735     struct vnode_attr 
*vap
, __unused 
void *fndesc
, vfs_context_t ctx
) 
2739         uint64_t orig_active
; 
2740         struct attrlist orig_al
; 
2744                 v_type 
= vnode_vtype(vp
); 
2746                 v_type 
= vap
->va_objtype
; 
2749         orig_active 
= vap
->va_active
; 
2752         error 
= getattrlist_setupvattr_all(alp
, vap
, v_type
, &fixedsize
, 
2753             proc_is64bit(vfs_context_proc(ctx
)), options 
& FSOPT_ATTR_CMN_EXTENDED
); 
2757                     "ATTRLIST - ERROR: setup for request failed"); 
2761         error 
= vfs_attr_pack_internal(vp
, uio
, alp
,  
2762             options
|FSOPT_REPORT_FULLSIZE
, vap
, NULL
, ctx
, 1, v_type
, 
2765         VATTR_CLEAR_SUPPORTED_ALL(vap
); 
2766         vap
->va_active 
= orig_active
; 
2773  * Obtain attribute information about a filesystem object. 
2775  * Note: The alt_name parameter can be used by the caller to pass in the vnode 
2776  * name obtained from some authoritative source (eg. readdir vnop); where 
2777  * filesystems' getattr vnops do not support ATTR_CMN_NAME, the alt_name will be 
2778  * used as the ATTR_CMN_NAME attribute returned in vnode_attr.va_name. 
2782 getattrlist_internal(vfs_context_t ctx
, vnode_t vp
, struct attrlist  
*alp
, 
2783     user_addr_t attributeBuffer
, size_t bufferSize
, uint64_t options
, 
2784     enum uio_seg segflg
, char* authoritative_name
, struct ucred 
*file_cred
) 
2786         struct vnode_attr va
; 
2787         kauth_action_t  action
; 
2796         char uio_buf
[ UIO_SIZEOF(1)]; 
2797         // must be true for fork attributes to be used as new common attributes 
2798         const int use_fork 
= (options 
& FSOPT_ATTR_CMN_EXTENDED
) != 0; 
2800         if (bufferSize 
< sizeof(uint32_t)) 
2803         proc_is64 
= proc_is64bit(vfs_context_proc(ctx
)); 
2805         if (segflg 
== UIO_USERSPACE
) { 
2807                         segflg 
= UIO_USERSPACE64
; 
2809                         segflg 
= UIO_USERSPACE32
; 
2811         auio 
= uio_createwithbuffer(1, 0, segflg
, UIO_READ
, 
2812                     &uio_buf
[0], sizeof(uio_buf
)); 
2813         uio_addiov(auio
, attributeBuffer
, bufferSize
); 
2818         if (alp
->bitmapcount 
!= ATTR_BIT_MAP_COUNT
) { 
2823         VFS_DEBUG(ctx
, vp
, "%p  ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'", 
2824             vp
, p
->p_comm
, alp
->commonattr
, alp
->volattr
, alp
->fileattr
, alp
->dirattr
, alp
->forkattr
, 
2825             (options 
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
); 
2828         error 
= mac_vnode_check_getattrlist(ctx
, vp
, alp
); 
2834          * It is legal to request volume or file attributes, but not both. 
2836          * 26903449 fork attributes can also be requested, but only if they're 
2837          * interpreted as new, common attributes 
2840                 if (alp
->fileattr 
|| alp
->dirattr 
|| (alp
->forkattr 
&& !use_fork
)) { 
2842                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory attributes"); 
2845                 /* handle volume attribute request */ 
2846                 error 
= getvolattrlist(ctx
, vp
, alp
, attributeBuffer
, 
2847                                        bufferSize
, options
, segflg
, proc_is64
); 
2852          * ATTR_CMN_GEN_COUNT and ATTR_CMN_DOCUMENT_ID reuse the bits 
2853          * originally allocated to ATTR_CMN_NAMEDATTRCOUNT and 
2854          * ATTR_CMN_NAMEDATTRLIST. 
2856         if ((alp
->commonattr 
& (ATTR_CMN_GEN_COUNT 
| ATTR_CMN_DOCUMENT_ID
)) && 
2857             !(options 
& FSOPT_ATTR_CMN_EXTENDED
)) { 
2862         /* common extended attributes require FSOPT_ATTR_CMN_EXTENDED option */ 
2863         if (!(use_fork
) && (alp
->forkattr 
& ATTR_CMNEXT_VALIDMASK
)) { 
2868         /* FSOPT_ATTR_CMN_EXTENDED requires forkattrs are not referenced */ 
2869         if ((options 
& FSOPT_ATTR_CMN_EXTENDED
) && (alp
->forkattr 
& (ATTR_FORK_VALIDMASK
))) { 
2874         /* Check for special packing semantics */ 
2875         return_valid 
= (alp
->commonattr 
& ATTR_CMN_RETURNED_ATTRS
) ? 1 : 0; 
2876         pack_invalid 
= (options 
& FSOPT_PACK_INVAL_ATTRS
) ? 1 : 0; 
2878                 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */ 
2879                 if (!return_valid 
|| (alp
->forkattr 
&& !use_fork
)) { 
2883                 /* Keep invalid attrs from being uninitialized */ 
2884                 bzero(&va
, sizeof (va
)); 
2887         /* Pick up the vnode type.  If the FS is bad and changes vnode types on us, we 
2888          * will have a valid snapshot that we can work from here. 
2893          * Set up the vnode_attr structure and authorise. 
2895         if ((error 
= getattrlist_setupvattr(alp
, &va
, &fixedsize
, &action
, proc_is64
, (vtype 
== VDIR
), use_fork
)) != 0) { 
2896                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed"); 
2899         if ((error 
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) { 
2900                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied"); 
2905         if (va
.va_active 
!= 0) { 
2906                 uint64_t va_active 
= va
.va_active
; 
2909                  * If we're going to ask for va_name, allocate a buffer to point it at 
2911                 if (VATTR_IS_ACTIVE(&va
, va_name
)) { 
2912                         MALLOC_ZONE(va_name
, char *, MAXPATHLEN
, M_NAMEI
, 
2914                         if (va_name 
== NULL
) { 
2916                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer"); 
2920                          * If we have an authoritative_name, prefer that name. 
2922                          * N.B. Since authoritative_name implies this is coming from getattrlistbulk, 
2923                          * we know the name is authoritative. For /dev/fd, we want to use the file 
2924                          * descriptor as the name not the underlying name of the associate vnode in a 
2925                          * particular file system. 
2927                         if (authoritative_name
) { 
2928                                 /* Don't ask the file system */ 
2929                                 VATTR_CLEAR_ACTIVE(&va
, va_name
); 
2930                                 strlcpy(va_name
, authoritative_name
, MAXPATHLEN
); 
2934                 va
.va_name 
= authoritative_name 
? NULL 
: va_name
; 
2937                  * Call the filesystem. 
2939                 if ((error 
= vnode_getattr(vp
, &va
, ctx
)) != 0) { 
2940                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
); 
2945                  * Give MAC polices a chance to reject or filter the 
2946                  * attributes returned by the filesystem.  Note that MAC 
2947                  * policies are consulted *after* calling the filesystem 
2948                  * because filesystems can return more attributes than 
2949                  * were requested so policies wouldn't be authoritative 
2950                  * is consulted beforehand.  This also gives policies an 
2951                  * opportunity to change the values of attributes 
2954                 error 
= mac_vnode_check_getattr(ctx
, file_cred
, vp
, &va
); 
2956                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d", error
); 
2964                  * It we ask for the name, i.e., vname is non null and 
2965                  * we have an authoritative name, then reset va_name is 
2966                  * active and if needed set va_name is supported. 
2968                  * A (buggy) filesystem may change fields which belong 
2969                  * to us. We try to deal with that here as well. 
2971                 va
.va_active 
= va_active
; 
2972                 if (authoritative_name  
&& va_name
) { 
2973                         VATTR_SET_ACTIVE(&va
, va_name
); 
2974                         if (!(VATTR_IS_SUPPORTED(&va
, va_name
))) { 
2975                                 VATTR_SET_SUPPORTED(&va
, va_name
); 
2978                 va
.va_name 
= va_name
; 
2981         error 
= vfs_attr_pack_internal(vp
, auio
, alp
, options
, &va
, NULL
, ctx
, 
2982             0, vtype
, fixedsize
); 
2986                 FREE_ZONE(va_name
, MAXPATHLEN
, M_NAMEI
); 
2987         if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl 
!= NULL
)) 
2988                 kauth_acl_free(va
.va_acl
); 
2990         VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
); 
2995 fgetattrlist(proc_t p
, struct fgetattrlist_args 
*uap
, __unused 
int32_t *retval
) 
3001         struct fileproc 
*fp
; 
3003         ctx 
= vfs_context_current(); 
3008         if ((error 
= file_vnode(uap
->fd
, &vp
)) != 0) 
3011         if ((error 
= fp_lookup(p
, uap
->fd
, &fp
, 0)) != 0 || 
3012             (error 
= vnode_getwithref(vp
)) != 0) 
3016          * Fetch the attribute request. 
3018         error 
= copyin(uap
->alist
, &al
, sizeof(al
)); 
3022         /* Default to using the vnode's name. */ 
3023         error 
= getattrlist_internal(ctx
, vp
, &al
, uap
->attributeBuffer
, 
3024                                      uap
->bufferSize
, uap
->options
, 
3025                                      (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64 
: \
 
3026                                      UIO_USERSPACE32
), NULL
, 
3027                                      fp
->f_fglob
->fg_cred
); 
3031                 fp_drop(p
, uap
->fd
, fp
, 0); 
3040 getattrlistat_internal(vfs_context_t ctx
, user_addr_t path
, 
3041     struct attrlist 
*alp
, user_addr_t attributeBuffer
, size_t bufferSize
, 
3042     uint64_t options
, enum uio_seg segflg
, enum uio_seg pathsegflg
, int fd
) 
3044         struct nameidata nd
; 
3053         if (!(options 
& FSOPT_NOFOLLOW
)) 
3054                 nameiflags 
|= FOLLOW
; 
3056         nameiflags 
|= AUDITVNPATH1
; 
3057         NDINIT(&nd
, LOOKUP
, OP_GETATTR
, nameiflags
, pathsegflg
, 
3060         error 
= nameiat(&nd
, fd
); 
3067         error 
= getattrlist_internal(ctx
, vp
, alp
, attributeBuffer
, 
3068             bufferSize
, options
, segflg
, NULL
, NOCRED
); 
3070         /* Retain the namei reference until the getattrlist completes. */ 
3077 getattrlist(proc_t p
, struct getattrlist_args 
*uap
, __unused 
int32_t *retval
) 
3079         enum uio_seg segflg
; 
3083         segflg 
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64 
: UIO_USERSPACE32
; 
3086          * Fetch the attribute request. 
3088         error 
= copyin(uap
->alist
, &al
, sizeof(al
)); 
3092         return (getattrlistat_internal(vfs_context_current(), 
3093             CAST_USER_ADDR_T(uap
->path
), &al
, 
3094             CAST_USER_ADDR_T(uap
->attributeBuffer
), uap
->bufferSize
, 
3095             (uint64_t)uap
->options
, segflg
, segflg
, AT_FDCWD
)); 
3099 getattrlistat(proc_t p
, struct getattrlistat_args 
*uap
, __unused 
int32_t *retval
) 
3101         enum uio_seg segflg
; 
3105         segflg 
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64 
: UIO_USERSPACE32
; 
3108          * Fetch the attribute request. 
3110         error 
= copyin(uap
->alist
, &al
, sizeof(al
)); 
3114         return (getattrlistat_internal(vfs_context_current(), 
3115             CAST_USER_ADDR_T(uap
->path
), &al
, 
3116             CAST_USER_ADDR_T(uap
->attributeBuffer
), uap
->bufferSize
, 
3117             (uint64_t)uap
->options
, segflg
, segflg
, uap
->fd
)); 
3121  * This refills the per-fd direntries cache by issuing a VNOP_READDIR. 
3122  * It attempts to try and find a size the filesystem responds to, so 
3123  * it first tries 1 direntry sized buffer and going from 1 to 2 to 4 
3124  * direntry sized buffers to readdir. If the filesystem does not respond 
3125  * to 4 * direntry it returns the error by the filesystem (if any) and sets 
3128  * This function also tries again if the last "refill" returned an EOF 
3129  * to try and get any additional entries if they were added after the last 
3133 refill_fd_direntries(vfs_context_t ctx
, vnode_t dvp
, struct fd_vn_data 
*fvd
, 
3137         char uio_buf
[UIO_SIZEOF(1)]; 
3145          * If the last readdir returned EOF, don't try again. 
3147         if (fvd
->fv_eofflag
) { 
3150                         FREE(fvd
->fv_buf
, M_FD_DIRBUF
); 
3159          * If there is a cached allocation size of the dirbuf that should be 
3160          * allocated, use that. Otherwise start with a allocation size of 
3161          * FV_DIRBUF_START_SIZ. This start size may need to be increased if the 
3162          * filesystem doesn't respond to the initial size. 
3165         if (fvd
->fv_offset 
&& fvd
->fv_bufallocsiz
) { 
3166                 rdirbufsiz 
= fvd
->fv_bufallocsiz
; 
3168                 rdirbufsiz 
= FV_DIRBUF_START_SIZ
; 
3173         rdir_uio 
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
, 
3174             &uio_buf
[0], sizeof(uio_buf
)); 
3178          * Don't explicitly zero out this buffer since this is 
3179          * not copied out to user space. 
3182                 MALLOC(fvd
->fv_buf
, caddr_t
, rdirbufsiz
, M_FD_DIRBUF
, M_WAITOK
); 
3183                 fvd
->fv_bufdone 
= 0; 
3186         uio_reset(rdir_uio
, fvd
->fv_eoff
, UIO_SYSSPACE
, UIO_READ
); 
3187         uio_addiov(rdir_uio
, CAST_USER_ADDR_T(fvd
->fv_buf
), rdirbufsiz
); 
3190          * Some filesystems do not set nentries or eofflag... 
3194         error 
= vnode_readdir64(dvp
, rdir_uio
, VNODE_READDIR_EXTENDED
, 
3195             &eofflag
, &nentries
, ctx
); 
3197         rdirbufused 
= rdirbufsiz 
- (size_t)uio_resid(rdir_uio
); 
3199         if (!error 
&& (rdirbufused 
> 0) && (rdirbufused 
<= rdirbufsiz
)) { 
3201                 fvd
->fv_soff 
= fvd
->fv_eoff
; 
3202                 fvd
->fv_eoff 
= uio_offset(rdir_uio
); 
3203                  /* Save eofflag state but don't return EOF for this time.*/ 
3204                 fvd
->fv_eofflag 
= eofflag
; 
3206                  /* Reset buffer parameters */ 
3207                 fvd
->fv_bufsiz 
= rdirbufused
; 
3208                 fvd
->fv_bufdone 
= 0; 
3209                 bzero(fvd
->fv_buf 
+ rdirbufused
, rdirbufsiz 
- rdirbufused
); 
3210                 /* Cache allocation size the Filesystem responded to */ 
3211                 fvd
->fv_bufallocsiz 
= rdirbufsiz
; 
3212         } else if (!eofflag 
&& (rdirbufsiz 
< FV_DIRBUF_MAX_SIZ
)) { 
3214                  * Some Filesystems have higher requirements for the 
3215                  * smallest buffer size they will respond to for a 
3216                  * directory listing. Start (relatively) small but increase 
3217                  * it upto FV_DIRBUF_MAX_SIZ. Most should be good with 
3218                  * 1*direntry. Cache the size found so that this does not need 
3219                  * need to be done every time. This also means that an error 
3220                  * from VNOP_READDIR is ignored until at least FV_DIRBUF_MAX_SIZ 
3221                  * has been attempted. 
3223                 FREE(fvd
->fv_buf
, M_FD_DIRBUF
); 
3225                 rdirbufsiz 
= 2 * rdirbufsiz
; 
3226                 fvd
->fv_bufallocsiz 
= 0; 
3228         } else if (!error
) { 
3230                  * The Filesystem did not set eofflag but also did not 
3231                  * return any entries (or an error). It is presumed that 
3232                  * EOF has been reached. 
3234                 fvd
->fv_eofflag 
= eofflag 
= 1; 
3238          * If the filesystem returned an error and it had previously returned 
3239          * EOF, ignore the error and set EOF. 
3241         if (error 
&& fvd
->fv_eofflag
) { 
3247          * If either the directory has either hit EOF or an error, now is a good 
3248          * time to free up directory entry buffer. 
3250         if ((error 
|| eofflag
) && fvd
->fv_buf
) { 
3251                 FREE(fvd
->fv_buf
, M_FD_DIRBUF
); 
3255         *eofflagp 
= eofflag
; 
3261  * gets the current direntry. To advance to the next direntry this has to be 
3262  * paired with a direntry_done. 
3264  * Since directories have restrictions on where directory enumeration 
3265  * can restart from, entries are first read into* a per fd diectory entry 
3266  * "cache" and entries provided from that cache. 
3269 get_direntry(vfs_context_t ctx
, vnode_t dvp
, struct fd_vn_data 
*fvd
, 
3270     int *eofflagp
, struct direntry 
**dpp
) 
3278         if (!fvd
->fv_bufsiz
) { 
3279                 error 
= refill_fd_direntries(ctx
, dvp
, fvd
, &eofflag
); 
3284                         *eofflagp 
= eofflag
; 
3289         *dpp 
= (struct direntry 
*)(fvd
->fv_buf 
+ fvd
->fv_bufdone
); 
3294  * Advances to the next direntry. 
3297 direntry_done(struct fd_vn_data 
*fvd
) 
3299         struct direntry 
*dp
; 
3301         dp 
= (struct direntry 
*)(fvd
->fv_buf 
+ fvd
->fv_bufdone
); 
3303                 fvd
->fv_bufdone 
+= dp
->d_reclen
; 
3304                 if (fvd
->fv_bufdone 
> fvd
->fv_bufsiz
) { 
3305                         fvd
->fv_bufdone 
= fvd
->fv_bufsiz
; 
3308                 fvd
->fv_bufdone 
= fvd
->fv_bufsiz
; 
3312          * If we're at the end the fd direntries cache, reset the 
3315         if (fvd
->fv_bufdone 
== fvd
->fv_bufsiz
) { 
3316                 fvd
->fv_bufdone 
= 0; 
3322  *  A stripped down version of getattrlist_internal to fill in only select 
3323  *  attributes in case of an error from getattrlist_internal. 
3325  *  It always returns at least ATTR_BULK_REQUIRED i.e. the name (but may also 
3326  *  return some other attributes which can be obtained from the vnode). 
3328  *  It does not change the value of the passed in attrlist. 
3330  *  The objective of this function is to fill in an "error entry", i.e. 
3331  *  an entry with ATTR_CMN_RETURNED_ATTRS & ATTR_CMN_NAME. If the caller 
3332  *  has also asked for ATTR_CMN_ERROR, it is filled in as well. 
3335  *       vp - vnode pointer 
3336  *       alp - pointer to attrlist struct. 
3337  *       options - options passed to getattrlistbulk(2) 
3338  *       kern_attr_buf - Kernel buffer to fill data (assumes offset 0 in 
3340  *       kern_attr_buf_siz - Size of buffer. 
3341  *       needs_error_attr - Whether the caller asked for ATTR_CMN_ERROR 
3342  *       error_attr - This value is used to fill ATTR_CMN_ERROR (if the user 
3343  *                  has requested it in the attribute list. 
3344  *       namebuf - This is used to fill in the name. 
3345  *       ctx - vfs context of caller. 
3348 get_error_attributes(vnode_t vp
, struct attrlist 
*alp
, uint64_t options
, 
3349     user_addr_t kern_attr_buf
, size_t kern_attr_buf_siz
, int error_attr
, 
3350     caddr_t namebuf
, vfs_context_t ctx
) 
3353         struct _attrlist_buf ab
; 
3355         kauth_action_t action
; 
3357         int needs_error_attr 
= (alp
->commonattr 
& ATTR_CMN_ERROR
); 
3360          * To calculate fixed size required, in the FSOPT_PACK_INVAL_ATTRS case, 
3361          * the fixedsize should include space for all the attributes asked by 
3362          * the user. Only ATTR_BULK_REQUIRED (and ATTR_CMN_ERROR) will be filled 
3363          * and will be valid. All other attributes are zeroed out later. 
3365          * ATTR_CMN_RETURNED_ATTRS, ATTR_CMN_ERROR and ATTR_CMN_NAME 
3366          * (the only valid ones being returned from here) happen to be 
3367          * the first three attributes by order as well. 
3370         if (!(options 
& FSOPT_PACK_INVAL_ATTRS
)) { 
3372                  * In this case the fixedsize only needs to be only for the 
3373                  * attributes being actually returned. 
3375                 al
.commonattr 
= ATTR_BULK_REQUIRED
; 
3376                 if (needs_error_attr
) { 
3377                         al
.commonattr 
|= ATTR_CMN_ERROR
; 
3384          * Passing NULL for the vnode_attr pointer is valid for 
3385          * getattrlist_setupvattr. All that is required is the size. 
3388         (void)getattrlist_setupvattr(&al
, NULL
, (ssize_t 
*)&fsiz
, 
3389             &action
, proc_is64bit(vfs_context_proc(ctx
)), 
3390             (vnode_vtype(vp
) == VDIR
), (options 
& FSOPT_ATTR_CMN_EXTENDED
)); 
3392         namelen 
= strlen(namebuf
); 
3394         vsiz 
= ((vsiz 
+ 3) & ~0x03); 
3396         bzero(&ab
, sizeof(ab
)); 
3397         ab
.base 
= (char *)kern_attr_buf
; 
3398         ab
.needed 
= fsiz 
+ vsiz
; 
3400         /* Fill in the size needed */ 
3401         *((uint32_t *)ab
.base
) = ab
.needed
; 
3402         if (ab
.needed 
> (ssize_t
)kern_attr_buf_siz
) { 
3407          * Setup to pack results into the destination buffer. 
3409         ab
.fixedcursor 
= ab
.base 
+ sizeof(uint32_t); 
3411          * Zero out buffer, ab.fixedbuffer starts after the first uint32_t 
3412          * which gives the length. This ensures everything that we don't 
3413          * fill in explicitly later is zeroed out correctly. 
3415         bzero(ab
.fixedcursor
, fsiz
); 
3417          * variable size data should start after all the fixed 
3420         ab
.varcursor 
= ab
.base 
+ fsiz
; 
3422          * Initialise the value for ATTR_CMN_RETURNED_ATTRS and leave space 
3423          * Leave space for filling in its value here at the end. 
3425         bzero(&ab
.actual
, sizeof (ab
.actual
)); 
3426         ab
.fixedcursor 
+= sizeof (attribute_set_t
); 
3428         ab
.allocated 
= ab
.needed
; 
3430         /* Fill ATTR_CMN_ERROR (if asked for) */ 
3431         if (needs_error_attr
) { 
3432                 ATTR_PACK4(ab
, error_attr
); 
3433                 ab
.actual
.commonattr 
|= ATTR_CMN_ERROR
; 
3437          * Fill ATTR_CMN_NAME, The attrrefrence is packed at this location 
3438          * but the actual string itself is packed after fixedsize which set 
3439          * to different lengths based on whether FSOPT_PACK_INVAL_ATTRS 
3442         attrlist_pack_string(&ab
, namebuf
, namelen
); 
3445          * Now Fill in ATTR_CMN_RETURNED_ATTR. This copies to a 
3446          * location after the count i.e. before ATTR_CMN_ERROR and 
3449         ab
.actual
.commonattr 
|= ATTR_CMN_NAME 
| ATTR_CMN_RETURNED_ATTRS
; 
3450         bcopy(&ab
.actual
, ab
.base 
+ sizeof(uint32_t), sizeof (ab
.actual
)); 
3456  * This is the buffer size required to return at least 1 entry. We need space 
3457  * for the length, for ATTR_CMN_RETURNED_ATTRS and ATTR_CMN_NAME. Assuming the 
3458  * smallest filename of a single byte we get 
3461 #define MIN_BUF_SIZE_REQUIRED  (sizeof(uint32_t) + sizeof(attribute_set_t) +\ 
3462     sizeof(attrreference_t)) 
3465  * Read directory entries and get attributes filled in for each directory 
3468 readdirattr(vnode_t dvp
, struct fd_vn_data 
*fvd
, uio_t auio
, 
3469     struct attrlist 
*alp
, uint64_t options
, int *count
, int *eofflagp
, 
3472         caddr_t kern_attr_buf
; 
3473         size_t kern_attr_buf_siz
; 
3474         caddr_t max_path_name_buf 
= NULL
; 
3480         if (uio_iovcnt(auio
) > 1) { 
3485          * We fill in a kernel buffer for the attributes and uiomove each 
3486          * entry's attributes (as returned by getattrlist_internal) 
3488         kern_attr_buf_siz 
= uio_resid(auio
); 
3489         if (kern_attr_buf_siz 
> ATTR_MAX_BUFFER
) { 
3490                 kern_attr_buf_siz 
= ATTR_MAX_BUFFER
; 
3491         } else if (kern_attr_buf_siz 
== 0) { 
3496         MALLOC(kern_attr_buf
, caddr_t
, kern_attr_buf_siz
, M_TEMP
, M_WAITOK
); 
3498         while (uio_resid(auio
) > (user_ssize_t
)MIN_BUF_SIZE_REQUIRED
) { 
3499                 struct direntry 
*dp
; 
3500                 user_addr_t name_buffer
; 
3501                 struct nameidata nd
; 
3510                  * get_direntry returns the current direntry and does not 
3511                  * advance. A move to the next direntry only happens if 
3512                  * direntry_done is called. 
3514                 error 
= get_direntry(ctx
, dvp
, fvd
, eofflagp
, &dp
); 
3515                 if (error 
|| (*eofflagp
) || !dp
) { 
3520                  * skip "." and ".." (and a bunch of other invalid conditions.) 
3522                 if (!dp
->d_reclen 
|| dp
->d_ino 
== 0 || dp
->d_namlen 
== 0 || 
3523                     (dp
->d_namlen 
== 1 && dp
->d_name
[0] == '.') || 
3524                     (dp
->d_namlen 
== 2 && dp
->d_name
[0] == '.' && 
3525                     dp
->d_name
[1] == '.')) { 
3531                  * try to deal with not-null terminated filenames. 
3533                 if (dp
->d_name
[dp
->d_namlen
] != '\0') { 
3534                         if (!max_path_name_buf
) { 
3535                                 MALLOC(max_path_name_buf
, caddr_t
, MAXPATHLEN
, 
3538                         bcopy(dp
->d_name
, max_path_name_buf
, dp
->d_namlen
); 
3539                         max_path_name_buf
[dp
->d_namlen
] = '\0'; 
3540                         name_buffer 
= CAST_USER_ADDR_T(max_path_name_buf
); 
3542                         name_buffer 
= CAST_USER_ADDR_T(&(dp
->d_name
)); 
3546                  * We have an iocount on the directory already. 
3548                  * Note that we supply NOCROSSMOUNT to the namei call as we attempt to acquire 
3549                  * a vnode for this particular entry.  This is because the native call will 
3550                  * (likely) attempt to emit attributes based on its own metadata in order to avoid 
3551                  * creating vnodes where posssible.  If the native call is not going to  walk 
3552                  * up the vnode mounted-on chain in order to find the top-most mount point, then we 
3553                  * should not either in this emulated readdir+getattrlist() approach.  We   
3554                  * will be responsible for setting DIR_MNTSTATUS_MNTPOINT on that directory that 
3555                  * contains a mount point.   
3557                 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, (AUDITVNPATH1 
| USEDVP 
| NOCROSSMOUNT
),  
3558                     UIO_SYSSPACE
, CAST_USER_ADDR_T(name_buffer
), ctx
); 
3572                  * getattrlist_internal can change the values of the 
3573                  * the required attribute list. Copy the current values 
3574                  * and use that one instead. 
3578                 error 
= getattrlist_internal(ctx
, vp
, &al
, 
3579                     CAST_USER_ADDR_T(kern_attr_buf
), kern_attr_buf_siz
, 
3580                     options 
| FSOPT_REPORT_FULLSIZE
, UIO_SYSSPACE
,  
3581                     CAST_DOWN_EXPLICIT(char *, name_buffer
), 
3587                         get_error_attributes(vp
, alp
, options
, 
3588                             CAST_USER_ADDR_T(kern_attr_buf
), 
3589                             kern_attr_buf_siz
, error
, (caddr_t
)name_buffer
, 
3594                 /* Done with vnode now */ 
3598                  * Because FSOPT_REPORT_FULLSIZE was set, the first 4 bytes 
3599                  * of the buffer returned by getattrlist contains the size 
3600                  * (even if the provided buffer isn't sufficiently big). Use 
3601                  * that to check if we've run out of buffer space. 
3603                  * resid is a signed type, and the size of the buffer etc 
3604                  * are unsigned types. It is theoretically possible for 
3605                  * resid to be < 0 and in which case we would be assigning 
3606                  * an out of bounds value to bytes_left (which is unsigned) 
3607                  * uiomove takes care to not ever set resid to < 0, so it 
3608                  * is safe to do this here. 
3610                 bytes_left 
= (size_t)((user_size_t
)uio_resid(auio
)); 
3611                 entlen 
= (size_t)(*((uint32_t *)(kern_attr_buf
))); 
3612                 if (!entlen 
|| (entlen 
> bytes_left
)) { 
3617                  * Will the pad bytes fit as well  ? If they can't be, still use 
3618                  * this entry but this will be the last entry returned. 
3620                 pad_bytes 
= ((entlen 
+ 7) & ~0x07) - entlen
; 
3622                 if (pad_bytes 
&& (entlen 
+ pad_bytes 
<= bytes_left
)) { 
3624                          * While entlen can never be > ATTR_MAX_BUFFER, 
3625                          * (entlen + pad_bytes) can be, handle that and 
3626                          * zero out the pad bytes. N.B. - Only zero 
3627                          * out information in the kernel buffer that is 
3628                          * going to be uiomove'ed out. 
3630                         if (entlen 
+ pad_bytes 
<= kern_attr_buf_siz
) { 
3631                                 /* This is the normal case. */ 
3632                                 bzero(kern_attr_buf 
+ entlen
, pad_bytes
); 
3634                                 bzero(kern_attr_buf 
+ entlen
, 
3635                                     kern_attr_buf_siz 
- entlen
); 
3637                                  * Pad bytes left over, change the resid value 
3638                                  * manually. We only got in here because 
3639                                  * bytes_left >= entlen + pad_bytes so 
3640                                  * new_resid (which is a signed type) is 
3643                                 new_resid 
= (ssize_t
)(bytes_left 
- 
3644                                     (entlen 
+ pad_bytes
)); 
3646                         entlen 
+= pad_bytes
; 
3648                 *((uint32_t *)kern_attr_buf
) = (uint32_t)entlen
; 
3649                 error 
= uiomove(kern_attr_buf
, min(entlen
, kern_attr_buf_siz
), 
3657                         uio_setresid(auio
, (user_ssize_t
)new_resid
); 
3661                  * At this point, the directory entry has been consumed, proceed 
3668         if (max_path_name_buf
) { 
3669                 FREE(max_path_name_buf
, M_TEMP
); 
3673          * At this point, kern_attr_buf is always allocated 
3675         FREE(kern_attr_buf
, M_TEMP
); 
3678          * Always set the offset to the last succesful offset 
3679          * returned by VNOP_READDIR. 
3681         uio_setoffset(auio
, fvd
->fv_eoff
); 
3687  *int getattrlistbulk(int dirfd, struct attrlist *alist, void *attributeBuffer, 
3688  *    size_t bufferSize, uint64_t options) 
3690  * Gets directory entries alongwith their attributes in the same way 
3691  * getattrlist does for a single file system object. 
3693  * On non error returns, retval will hold the count of entries returned. 
3696 getattrlistbulk(proc_t p
, struct getattrlistbulk_args 
*uap
, int32_t *retval
) 
3700         struct fileproc 
*fp
; 
3701         struct fd_vn_data 
*fvdata
; 
3703         enum uio_seg segflg
; 
3706         char uio_buf
[ UIO_SIZEOF(1) ]; 
3707         kauth_action_t action
; 
3714         error 
= fp_getfvp(p
, uap
->dirfd
, &fp
, &dvp
); 
3721         ctx 
= vfs_context_current(); 
3722         segflg 
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64 
: UIO_USERSPACE32
; 
3724         if ((fp
->f_fglob
->fg_flag 
& FREAD
) == 0) { 
3726                 AUDIT_ARG(vnpath_withref, dvp, ARG_VNODE1); 
3732         if ((error 
= vnode_getwithref(dvp
))) { 
3737         if (uap
->options 
& FSOPT_LIST_SNAPSHOT
) { 
3740                 if (!vnode_isvroot(dvp
)) { 
3745                 /* switch directory to snapshot directory */ 
3746                 error 
= vnode_get_snapdir(dvp
, &snapdvp
, ctx
); 
3753         if (dvp
->v_type 
!= VDIR
) { 
3759         error 
= mac_file_check_change_offset(vfs_context_ucred(ctx
), 
3765          * XXX : Audit Support 
3766          *AUDIT_ARG(vnpath, dvp, ARG_VNODE1); 
3769         options 
= uap
->options 
| FSOPT_ATTR_CMN_EXTENDED
; 
3771         if ((error 
= copyin(CAST_USER_ADDR_T(uap
->alist
), &al
, 
3772             sizeof(struct attrlist
)))) { 
3777             ((al
.commonattr 
& ATTR_BULK_REQUIRED
) != ATTR_BULK_REQUIRED
)) { 
3783         error 
= mac_vnode_check_readdir(ctx
, dvp
); 
3790          * If the only item requested is file names, we can let that past with 
3791          * just LIST_DIRECTORY.  If they want any other attributes, that means 
3792          * they need SEARCH as well. 
3794         action 
= KAUTH_VNODE_LIST_DIRECTORY
; 
3795         if ((al
.commonattr 
& ~ATTR_CMN_NAME
) || al
.fileattr 
|| al
.dirattr
) 
3796                 action 
|= KAUTH_VNODE_SEARCH
; 
3798         error 
= vnode_authorize(dvp
, NULL
, action
, ctx
); 
3803         fvdata 
= (struct fd_vn_data 
*)fp
->f_fglob
->fg_vn_data
; 
3805                 panic("Directory expected to have fg_vn_data"); 
3811          * getattrlistbulk(2) maintains its offset in fv_offset. However 
3812          * if the offset in the file glob is set (or reset) to 0, the directory 
3813          * traversal needs to be restarted (Any existing state in the 
3814          * directory buffer is removed as well). 
3816         if (!fp
->f_fglob
->fg_offset
) { 
3817                 fvdata
->fv_offset 
= 0; 
3819                         FREE(fvdata
->fv_buf
, M_FD_DIRBUF
); 
3820                 fvdata
->fv_buf 
= NULL
; 
3821                 fvdata
->fv_bufsiz 
= 0; 
3822                 fvdata
->fv_bufdone 
= 0; 
3823                 fvdata
->fv_soff 
= 0; 
3824                 fvdata
->fv_eoff 
= 0; 
3825                 fvdata
->fv_eofflag 
= 0; 
3828         auio 
= uio_createwithbuffer(1, fvdata
->fv_offset
, segflg
, UIO_READ
, 
3829             &uio_buf
[0], sizeof(uio_buf
)); 
3830         uio_addiov(auio
, uap
->attributeBuffer
, (user_size_t
)uap
->bufferSize
); 
3833          * For "expensive" operations in which the native VNOP implementations 
3834          * end up having to do just as much (if not more) work than the default 
3835          * implementation, fall back to the default implementation. 
3836          * The VNOP helper functions depend on the filesystem providing the 
3837          * object type, if the caller has not requested ATTR_CMN_OBJTYPE, fall 
3838          * back to the default implementation. 
3840         if ((al
.commonattr 
& 
3841             (ATTR_CMN_UUID 
| ATTR_CMN_GRPUUID 
| ATTR_CMN_EXTENDED_SECURITY
)) || 
3842             !(al
.commonattr 
& ATTR_CMN_OBJTYPE
)) { 
3845                 struct vnode_attr va
; 
3848                 if (fvdata
->fv_eofflag 
&& !fvdata
->fv_buf
) { 
3850                          * If the last successful VNOP_GETATTRLISTBULK or 
3851                          * VNOP_READDIR returned EOF, don't try again. 
3861                         MALLOC(va_name
, char *, MAXPATHLEN
, M_TEMP
, 
3863                         va
.va_name 
= va_name
; 
3865                         (void)getattrlist_setupvattr_all(&al
, &va
, VNON
, NULL
, 
3866                             IS_64BIT_PROCESS(p
), (uap
->options 
& FSOPT_ATTR_CMN_EXTENDED
)); 
3868                         error 
= VNOP_GETATTRLISTBULK(dvp
, &al
, &va
, auio
, NULL
, 
3869                             options
, &eofflag
, &count
, ctx
); 
3871                         FREE(va_name
, M_TEMP
); 
3874                          * cache state of eofflag. 
3877                                 fvdata
->fv_eofflag 
= eofflag
; 
3883          * If the Filessytem does not natively support getattrlistbulk, 
3884          * do the default implementation. 
3886         if (error 
== ENOTSUP
) { 
3890                 error 
= readdirattr(dvp
, fvdata
, auio
, &al
, options
, 
3891                     &count
, &eofflag
, ctx
); 
3895                 fvdata
->fv_offset 
= uio_offset(auio
); 
3896                 fp
->f_fglob
->fg_offset 
= fvdata
->fv_offset
; 
3899         } else if (!error 
&& !eofflag
) { 
3901                  * This just means the buffer was too small to fit even a 
3913         file_drop(uap
->dirfd
); 
3919 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
) 
3921         /* make sure we have enough source data */ 
3922         if ((*cursor
) + size 
> end
) 
3925         bcopy(*cursor
, buf
, size
); 
3930 #define ATTR_UNPACK(v)          do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0); 
3931 #define ATTR_UNPACK_CAST(t, v)  do { t _f; ATTR_UNPACK(_f); v = _f;} while(0) 
3932 #define ATTR_UNPACK_TIME(v, is64)                               \ 
3935                         struct user64_timespec us;              \ 
3937                         v.tv_sec = us.tv_sec;                   \ 
3938                         v.tv_nsec = us.tv_nsec;                 \ 
3940                         struct user32_timespec us;              \ 
3942                         v.tv_sec = us.tv_sec;                   \ 
3943                         v.tv_nsec = us.tv_nsec;                 \ 
3952 setattrlist_internal(vnode_t vp
, struct setattrlist_args 
*uap
, proc_t p
, vfs_context_t ctx
) 
3955         struct vnode_attr va
; 
3956         struct attrreference ar
; 
3957         kauth_action_t  action
; 
3958         char            *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
; 
3959         int             proc_is64
, error
; 
3961         kauth_filesec_t rfsec
; 
3967         proc_is64 
= proc_is64bit(p
); 
3971          * Fetch the attribute set and validate. 
3973         if ((error 
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
)))) 
3975         if (al
.bitmapcount 
!= ATTR_BIT_MAP_COUNT
) { 
3980 #if DEVELOPMENT || DEBUG 
3982          * XXX VSWAP: Check for entitlements or special flag here 
3983          * so we can restrict access appropriately. 
3985 #else /* DEVELOPMENT || DEBUG */ 
3987         if (vnode_isswap(vp
) && (ctx 
!= vfs_context_kernel())) { 
3991 #endif /* DEVELOPMENT || DEBUG */ 
3993         VFS_DEBUG(ctx
, vp
, "%p  ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'", 
3994             vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
, 
3995             (uap
->options 
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
); 
3998                 if ((al
.volattr 
& ~ATTR_VOL_SETMASK
) || 
3999                     (al
.commonattr 
& ~ATTR_CMN_VOLSETMASK
) || 
4003                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes"); 
4007                 if ((al
.commonattr 
& ~ATTR_CMN_SETMASK
) || 
4008                     (al
.fileattr 
& ~ATTR_FILE_SETMASK
) || 
4009                     (al
.dirattr 
& ~ATTR_DIR_SETMASK
) || 
4010                     (al
.forkattr 
& ~ATTR_FORK_SETMASK
)) { 
4012                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes"); 
4018          * If the caller's bitmaps indicate that there are no attributes to set, 
4019          * then exit early.  In particular, we want to avoid the MALLOC below 
4020          * since the caller's bufferSize could be zero, and MALLOC of zero bytes 
4021          * returns a NULL pointer, which would cause setattrlist to return ENOMEM. 
4023         if (al
.commonattr 
== 0 && 
4024                 (al
.volattr 
& ~ATTR_VOL_INFO
) == 0 && 
4033          * Make the naive assumption that the caller has supplied a reasonable buffer 
4034          * size.  We could be more careful by pulling in the fixed-size region, checking 
4035          * the attrref structures, then pulling in the variable section. 
4036          * We need to reconsider this for handling large ACLs, as they should probably be 
4037          * brought directly into a buffer.  Multiple copyins will make this slower though. 
4039          * We could also map the user buffer if it is larger than some sensible mimimum. 
4041         if (uap
->bufferSize 
> ATTR_MAX_BUFFER
) { 
4042                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
); 
4046         MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
); 
4047         if (user_buf 
== NULL
) { 
4048                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
); 
4052         if ((error 
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) { 
4053                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed"); 
4056         VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
); 
4059         error 
= mac_vnode_check_setattrlist(ctx
, vp
, &al
); 
4065          * Unpack the argument buffer. 
4068         bufend 
= cursor 
+ uap
->bufferSize
; 
4071         if (al
.commonattr 
& ATTR_CMN_SCRIPT
) { 
4072                 ATTR_UNPACK(va
.va_encoding
); 
4073                 VATTR_SET_ACTIVE(&va
, va_encoding
); 
4075         if (al
.commonattr 
& ATTR_CMN_CRTIME
) { 
4076                 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
); 
4077                 VATTR_SET_ACTIVE(&va
, va_create_time
); 
4079         if (al
.commonattr 
& ATTR_CMN_MODTIME
) { 
4080                 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
); 
4081                 VATTR_SET_ACTIVE(&va
, va_modify_time
); 
4083         if (al
.commonattr 
& ATTR_CMN_CHGTIME
) { 
4084                 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
); 
4085                 al
.commonattr 
&= ~ATTR_CMN_CHGTIME
; 
4086                 /*quietly ignore change time; advisory in man page*/ 
4088         if (al
.commonattr 
& ATTR_CMN_ACCTIME
) { 
4089                 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
); 
4090                 VATTR_SET_ACTIVE(&va
, va_access_time
); 
4092         if (al
.commonattr 
& ATTR_CMN_BKUPTIME
) { 
4093                 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
); 
4094                 VATTR_SET_ACTIVE(&va
, va_backup_time
); 
4096         if (al
.commonattr 
& ATTR_CMN_FNDRINFO
) { 
4097                 if ((cursor 
+ 32) > bufend
) { 
4099                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO"); 
4105         if (al
.commonattr 
& ATTR_CMN_OWNERID
) { 
4106                 ATTR_UNPACK(va
.va_uid
); 
4107                 VATTR_SET_ACTIVE(&va
, va_uid
); 
4109         if (al
.commonattr 
& ATTR_CMN_GRPID
) { 
4110                 ATTR_UNPACK(va
.va_gid
); 
4111                 VATTR_SET_ACTIVE(&va
, va_gid
); 
4113         if (al
.commonattr 
& ATTR_CMN_ACCESSMASK
) { 
4114                 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
); 
4115                 VATTR_SET_ACTIVE(&va
, va_mode
); 
4117         if (al
.commonattr 
& ATTR_CMN_FLAGS
) { 
4118                 ATTR_UNPACK(va
.va_flags
); 
4119                 VATTR_SET_ACTIVE(&va
, va_flags
); 
4121                 if ((error 
= mac_vnode_check_setflags(ctx
, vp
, va
.va_flags
)) != 0) 
4125         if (al
.commonattr 
& ATTR_CMN_EXTENDED_SECURITY
) { 
4128                  * We are (for now) passed a kauth_filesec_t, but all we want from 
4133                 if (ar
.attr_dataoffset 
< 0) { 
4134                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied", ar
.attr_dataoffset
); 
4139                 cp 
+= ar
.attr_dataoffset
; 
4140                 rfsec 
= (kauth_filesec_t
)cp
; 
4141                 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) ||                     /* no space for acl */ 
4142                     (rfsec
->fsec_magic 
!= KAUTH_FILESEC_MAGIC
) ||       /* bad magic */ 
4143                     (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */ 
4144                     ((cp 
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) {  /* ACEs overrun buffer */ 
4146                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
); 
4149                 nace 
= rfsec
->fsec_entrycount
; 
4150                 if (nace 
== KAUTH_FILESEC_NOACL
) 
4152                 if (nace 
> KAUTH_ACL_MAX_ENTRIES
) {                     /* ACL size invalid */ 
4154                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied"); 
4157                 nace 
= rfsec
->fsec_acl
.acl_entrycount
; 
4158                 if (nace 
== KAUTH_FILESEC_NOACL
) { 
4160                         VATTR_SET(&va
, va_acl
, NULL
); 
4163                         if (nace 
> KAUTH_ACL_MAX_ENTRIES
) {                     /* ACL size invalid */ 
4165                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large"); 
4168                         VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
); 
4171         if (al
.commonattr 
& ATTR_CMN_UUID
) { 
4172                 ATTR_UNPACK(va
.va_uuuid
); 
4173                 VATTR_SET_ACTIVE(&va
, va_uuuid
); 
4175         if (al
.commonattr 
& ATTR_CMN_GRPUUID
) { 
4176                 ATTR_UNPACK(va
.va_guuid
); 
4177                 VATTR_SET_ACTIVE(&va
, va_guuid
); 
4179         if (al
.commonattr 
& ATTR_CMN_ADDEDTIME
) { 
4180                 ATTR_UNPACK_TIME(va
.va_addedtime
, proc_is64
); 
4181                 VATTR_SET_ACTIVE(&va
, va_addedtime
); 
4183         /* Support setattrlist of data protection class */ 
4184         if (al
.commonattr 
& ATTR_CMN_DATA_PROTECT_FLAGS
) { 
4185                 ATTR_UNPACK(va
.va_dataprotect_class
); 
4186                 VATTR_SET_ACTIVE(&va
, va_dataprotect_class
); 
4190         if (al
.volattr 
& ATTR_VOL_INFO
) { 
4191                 if (al
.volattr 
& ATTR_VOL_NAME
) { 
4194                         /* attr_length cannot be 0! */ 
4195                         if ((ar
.attr_dataoffset 
< 0) || (ar
.attr_length 
== 0) || 
4196                                 (ar
.attr_length 
> uap
->bufferSize
) || 
4197                                 (uap
->bufferSize 
- ar
.attr_length 
< (unsigned)ar
.attr_dataoffset
)) { 
4198                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied (2) ", ar
.attr_dataoffset
); 
4203                         if (volname 
>= bufend 
- ar
.attr_dataoffset 
- ar
.attr_length
) { 
4205                                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer"); 
4208                         volname 
+= ar
.attr_dataoffset
; 
4209                         /* guarantee NUL termination */ 
4210                         volname
[ar
.attr_length 
- 1] = 0; 
4215         if (al
.fileattr 
& ATTR_FILE_DEVTYPE
) { 
4216                 /* XXX does it actually make any sense to change this? */ 
4218                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented"); 
4223          * Validate and authorize. 
4226         if ((va
.va_active 
!= 0LL) && ((error 
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) { 
4227                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
); 
4231          * We can auth file Finder Info here.  HFS volume FinderInfo is really boot data, 
4232          * and will be auth'ed by the FS. 
4234         if (fndrinfo 
!= NULL
) { 
4235                 if (al
.volattr 
& ATTR_VOL_INFO
) { 
4236                         if (vp
->v_tag 
!= VT_HFS
) { 
4241                         action 
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
; 
4245         if ((action 
!= 0) && ((error 
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) { 
4246                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed"); 
4251          * When we're setting both the access mask and the finder info, then 
4252          * check if were about to remove write access for the owner.  Since 
4253          * vnode_setattr and vn_setxattr invoke two separate vnops, we need 
4254          * to consider their ordering. 
4256          * If were about to remove write access for the owner we'll set the 
4257          * Finder Info here before vnode_setattr.  Otherwise we'll set it 
4258          * after vnode_setattr since it may be adding owner write access. 
4260         if ((fndrinfo 
!= NULL
) && !(al
.volattr 
& ATTR_VOL_INFO
) && 
4261             (al
.commonattr 
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode 
& S_IWUSR
)) { 
4262                 if ((error 
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) { 
4265                 fndrinfo 
= NULL
;  /* it was set here so skip setting below */ 
4269          * Write the attributes if we have any. 
4271         if ((va
.va_active 
!= 0LL) && ((error 
= vnode_setattr(vp
, &va
, ctx
)) != 0)) { 
4272                 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
); 
4277         mac_vnode_notify_setattrlist(ctx
, vp
, &al
); 
4278         if (VATTR_IS_ACTIVE(&va
, va_flags
)) 
4279                 mac_vnode_notify_setflags(ctx
, vp
, va
.va_flags
); 
4283          * Write the Finder Info if we have any. 
4285         if (fndrinfo 
!= NULL
) { 
4286                 if (al
.volattr 
& ATTR_VOL_INFO
) { 
4287                         if (vp
->v_tag 
== VT_HFS
) { 
4288 #define HFS_SET_BOOT_INFO   (FCNTL_FS_SPECIFIC_BASE + 0x00005) 
4289                                 error 
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
); 
4293                                 /* XXX should never get here */ 
4295                 } else if ((error 
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) { 
4301          * Set the volume name, if we have one 
4303         if (volname 
!= NULL
) 
4309                 vs
.f_vol_name 
= volname
;        /* References the setattrlist buffer directly */ 
4310                 VFSATTR_WANTED(&vs
, f_vol_name
); 
4313                 error 
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
); 
4318                 if ((error 
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) { 
4319                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed"); 
4323                 if (!VFSATTR_ALL_SUPPORTED(&vs
)) { 
4325                         VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name"); 
4330         /* all done and successful */ 
4333         if (user_buf 
!= NULL
) 
4334                 FREE(user_buf
, M_TEMP
); 
4335         VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
); 
4340 setattrlist(proc_t p
, struct setattrlist_args 
*uap
, __unused 
int32_t *retval
) 
4342         struct vfs_context 
*ctx
; 
4343         struct nameidata nd
; 
4348         ctx 
= vfs_context_current(); 
4353         nameiflags 
= AUDITVNPATH1
; 
4354         if ((uap
->options 
& FSOPT_NOFOLLOW
) == 0) 
4355                 nameiflags 
|= FOLLOW
; 
4356         NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
); 
4357         if ((error 
= namei(&nd
)) != 0) 
4362         error 
= setattrlist_internal(vp
, uap
, p
, ctx
); 
4370 setattrlistat(proc_t p
, struct setattrlistat_args 
*uap
, __unused 
int32_t *retval
) 
4372         struct setattrlist_args ap
; 
4373         struct vfs_context 
*ctx
; 
4374         struct nameidata nd
; 
4375         vnode_t vp 
= NULLVP
; 
4376         uint32_t nameiflags
; 
4379         ctx 
= vfs_context_current(); 
4381         AUDIT_ARG(fd
, uap
->fd
); 
4385         nameiflags 
= AUDITVNPATH1
; 
4386         if (!(uap
->options 
& FSOPT_NOFOLLOW
)) 
4387                 nameiflags 
|= FOLLOW
; 
4388         NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
); 
4389         if ((error 
= nameiat(&nd
, uap
->fd
)) != 0) 
4395         ap
.alist 
= uap
->alist
; 
4396         ap
.attributeBuffer 
= uap
->attributeBuffer
; 
4397         ap
.bufferSize 
= uap
->bufferSize
; 
4398         ap
.options 
= uap
->options
; 
4400         error 
= setattrlist_internal(vp
, &ap
, p
, ctx
); 
4408 fsetattrlist(proc_t p
, struct fsetattrlist_args 
*uap
, __unused 
int32_t *retval
) 
4410         struct vfs_context 
*ctx
; 
4413         struct setattrlist_args ap
; 
4415         ctx 
= vfs_context_current(); 
4417         if ((error 
= file_vnode(uap
->fd
, &vp
)) != 0) 
4420         if ((error 
= vnode_getwithref(vp
)) != 0) { 
4426         ap
.alist 
= uap
->alist
; 
4427         ap
.attributeBuffer 
= uap
->attributeBuffer
; 
4428         ap
.bufferSize 
= uap
->bufferSize
; 
4429         ap
.options 
= uap
->options
; 
4431         error 
= setattrlist_internal(vp
, &ap
, p
, ctx
);