2 * Copyright (c) 1995-2016 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>
56 #include <security/mac_framework.h>
59 #define ATTR_TIME_SIZE -1
62 * Structure describing the state of an in-progress attrlist operation.
64 struct _attrlist_buf
{
70 attribute_set_t actual
;
71 attribute_set_t valid
;
76 * Attempt to pack a fixed width attribute of size (count) bytes from
77 * source to our attrlist buffer.
80 attrlist_pack_fixed(struct _attrlist_buf
*ab
, void *source
, ssize_t count
)
83 * Use ssize_t for pointer math purposes,
84 * since a ssize_t is a signed long
89 * Compute the amount of remaining space in the attrlist buffer
90 * based on how much we've used for fixed width fields vs. the
91 * start of the attributes.
93 * If we've still got room, then 'fit' will contain the amount of
96 * Note that this math is safe because, in the event that the
97 * fixed-width cursor has moved beyond the end of the buffer,
98 * then, the second input into lmin() below will be negative, and
99 * we will fail the (fit > 0) check below.
101 fit
= lmin(count
, ab
->allocated
- (ab
->fixedcursor
- ab
->base
));
103 /* Copy in as much as we can */
104 bcopy(source
, ab
->fixedcursor
, fit
);
107 /* always move in increments of 4, even if we didn't pack an attribute. */
108 ab
->fixedcursor
+= roundup(count
, 4);
112 * Attempt to pack one (or two) variable width attributes into the attrlist
113 * buffer. If we are trying to pack two variable width attributes, they are treated
114 * as a single variable-width attribute from the POV of the system call caller.
116 * Recall that a variable-width attribute has two components: the fixed-width
117 * attribute that tells the caller where to look, and the actual variable width data.
120 attrlist_pack_variable2(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
,
121 const void *ext
, ssize_t extcount
)
123 /* Use ssize_t's for pointer math ease */
124 struct attrreference ar
;
128 * Pack the fixed-width component to the variable object.
129 * Note that we may be able to pack the fixed width attref, but not
130 * the variable (if there's no room).
132 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
133 ar
.attr_length
= count
+ extcount
;
134 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
137 * Use an lmin() to do a signed comparison. We use a signed comparison
138 * to detect the 'out of memory' conditions as described above in the
139 * fixed width check above.
141 * Then pack the first variable attribute as space allows. Note that we advance
142 * the variable cursor only if we we had some available space.
144 fit
= lmin(count
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
146 if (source
!= NULL
) {
147 bcopy(source
, ab
->varcursor
, fit
);
149 ab
->varcursor
+= fit
;
152 /* Compute the available space for the second attribute */
153 fit
= lmin(extcount
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
155 /* Copy in data for the second attribute (if needed) if there is room */
157 bcopy(ext
, ab
->varcursor
, fit
);
159 ab
->varcursor
+= fit
;
161 /* always move in increments of 4 */
162 ab
->varcursor
= (char *)roundup((uintptr_t)ab
->varcursor
, 4);
166 * Packing a single variable-width attribute is the same as calling the two, but with
167 * an invalid 2nd attribute.
170 attrlist_pack_variable(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
)
172 attrlist_pack_variable2(ab
, source
, count
, NULL
, 0);
176 * Attempt to pack a string. This is a special case of a variable width attribute.
178 * If "source" is NULL, then an empty string ("") will be packed. If "source" is
179 * not NULL, but "count" is zero, then "source" is assumed to be a NUL-terminated
180 * C-string. If "source" is not NULL and "count" is not zero, then only the first
181 * "count" bytes of "source" will be copied, and a NUL terminator will be added.
183 * If the attrlist buffer doesn't have enough room to hold the entire string (including
184 * NUL terminator), then copy as much as will fit. The attrlist buffer's "varcursor"
185 * will always be updated based on the entire length of the string (including NUL
186 * terminator); this means "varcursor" may end up pointing beyond the end of the
187 * allocated buffer space.
190 attrlist_pack_string(struct _attrlist_buf
*ab
, const char *source
, ssize_t count
)
192 struct attrreference ar
;
196 * Supplied count is character count of string text, excluding trailing nul
197 * which we always supply here.
199 if (source
== NULL
) {
201 } else if (count
== 0) {
202 count
= strlen(source
);
206 * Construct the fixed-width attribute that refers to this string.
208 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
209 ar
.attr_length
= count
+ 1;
210 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
213 * Now compute how much available memory we have to copy the string text.
215 * space = the number of bytes available in the attribute buffer to hold the
218 * fit = the number of bytes to copy from the start of the string into the
219 * attribute buffer, NOT including the NUL terminator. If the attribute
220 * buffer is large enough, this will be the string's length; otherwise, it
221 * will be equal to "space".
223 space
= ab
->allocated
- (ab
->varcursor
- ab
->base
);
224 fit
= lmin(count
, space
);
229 * If there is space remaining, copy data in, and
230 * accommodate the trailing NUL terminator.
232 * NOTE: if "space" is too small to hold the string and its NUL
233 * terminator (space < fit + 1), then the string value in the attribute
234 * buffer will NOT be NUL terminated!
236 * NOTE 2: bcopy() will do nothing if the length ("fit") is zero.
237 * Therefore, we don't bother checking for that here.
239 bcopy(source
, ab
->varcursor
, fit
);
240 /* is there room for our trailing nul? */
242 ab
->varcursor
[fit
++] = '\0';
243 /* 'fit' now the number of bytes AFTER adding in the NUL */
245 * Zero out any additional bytes we might have as a
246 * result of rounding up.
248 bytes_to_zero
= min((roundup(fit
, 4) - fit
),
251 bzero(&(ab
->varcursor
[fit
]), bytes_to_zero
);
255 * always move in increments of 4 (including the trailing NUL)
257 ab
->varcursor
+= roundup((count
+1), 4);
261 #define ATTR_PACK4(AB, V) \
263 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \
264 *(uint32_t *)AB.fixedcursor = V; \
265 AB.fixedcursor += 4; \
269 #define ATTR_PACK8(AB, V) \
271 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
272 *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \
273 AB.fixedcursor += 8; \
277 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
278 #define ATTR_PACK_CAST(b, t, v) \
284 #define ATTR_PACK_TIME(b, v, is64) \
287 struct user64_timespec us = {v.tv_sec, v.tv_nsec}; \
290 struct user32_timespec us = {v.tv_sec, v.tv_nsec}; \
297 * Table-driven setup for all valid common/volume attributes.
299 struct getvolattrlist_attrtab
{
302 #define VFSATTR_BIT(b) (VFSATTR_ ## b)
305 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = {
306 {ATTR_CMN_NAME
, 0, sizeof(struct attrreference
)},
307 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
)},
308 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
)},
309 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
)},
310 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
)},
311 {ATTR_CMN_OBJID
, 0, sizeof(fsobj_id_t
)},
312 {ATTR_CMN_OBJPERMANENTID
, 0, sizeof(fsobj_id_t
)},
313 {ATTR_CMN_PAROBJID
, 0, sizeof(fsobj_id_t
)},
314 {ATTR_CMN_SCRIPT
, 0, sizeof(text_encoding_t
)},
315 {ATTR_CMN_CRTIME
, VFSATTR_BIT(f_create_time
), ATTR_TIME_SIZE
},
316 {ATTR_CMN_MODTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
317 {ATTR_CMN_CHGTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
318 {ATTR_CMN_ACCTIME
, VFSATTR_BIT(f_access_time
), ATTR_TIME_SIZE
},
319 {ATTR_CMN_BKUPTIME
, VFSATTR_BIT(f_backup_time
), ATTR_TIME_SIZE
},
320 {ATTR_CMN_FNDRINFO
, 0, 32},
321 {ATTR_CMN_OWNERID
, 0, sizeof(uid_t
)},
322 {ATTR_CMN_GRPID
, 0, sizeof(gid_t
)},
323 {ATTR_CMN_ACCESSMASK
, 0, sizeof(uint32_t)},
324 {ATTR_CMN_FLAGS
, 0, sizeof(uint32_t)},
325 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t)},
326 {ATTR_CMN_EXTENDED_SECURITY
, 0, sizeof(struct attrreference
)},
327 {ATTR_CMN_UUID
, 0, sizeof(guid_t
)},
328 {ATTR_CMN_GRPUUID
, 0, sizeof(guid_t
)},
329 {ATTR_CMN_FILEID
, 0, sizeof(uint64_t)},
330 {ATTR_CMN_PARENTID
, 0, sizeof(uint64_t)},
331 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
)},
332 {ATTR_CMN_ERROR
, 0, sizeof(uint32_t)},
335 #define ATTR_CMN_VOL_INVALID \
336 (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \
337 ATTR_CMN_FILEID | ATTR_CMN_PARENTID)
339 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = {
340 {ATTR_VOL_FSTYPE
, 0, sizeof(uint32_t)},
341 {ATTR_VOL_SIGNATURE
, VFSATTR_BIT(f_signature
), sizeof(uint32_t)},
342 {ATTR_VOL_SIZE
, VFSATTR_BIT(f_blocks
), sizeof(off_t
)},
343 {ATTR_VOL_SPACEFREE
, VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
344 {ATTR_VOL_SPACEAVAIL
, VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
345 {ATTR_VOL_MINALLOCATION
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
346 {ATTR_VOL_ALLOCATIONCLUMP
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
347 {ATTR_VOL_IOBLOCKSIZE
, VFSATTR_BIT(f_iosize
), sizeof(uint32_t)},
348 {ATTR_VOL_OBJCOUNT
, VFSATTR_BIT(f_objcount
), sizeof(uint32_t)},
349 {ATTR_VOL_FILECOUNT
, VFSATTR_BIT(f_filecount
), sizeof(uint32_t)},
350 {ATTR_VOL_DIRCOUNT
, VFSATTR_BIT(f_dircount
), sizeof(uint32_t)},
351 {ATTR_VOL_MAXOBJCOUNT
, VFSATTR_BIT(f_maxobjcount
), sizeof(uint32_t)},
352 {ATTR_VOL_MOUNTPOINT
, 0, sizeof(struct attrreference
)},
353 {ATTR_VOL_NAME
, VFSATTR_BIT(f_vol_name
), sizeof(struct attrreference
)},
354 {ATTR_VOL_MOUNTFLAGS
, 0, sizeof(uint32_t)},
355 {ATTR_VOL_MOUNTEDDEVICE
, 0, sizeof(struct attrreference
)},
356 {ATTR_VOL_ENCODINGSUSED
, 0, sizeof(uint64_t)},
357 {ATTR_VOL_CAPABILITIES
, VFSATTR_BIT(f_capabilities
), sizeof(vol_capabilities_attr_t
)},
358 {ATTR_VOL_UUID
, VFSATTR_BIT(f_uuid
), sizeof(uuid_t
)},
359 {ATTR_VOL_QUOTA_SIZE
, VFSATTR_BIT(f_quota
), sizeof(off_t
)},
360 {ATTR_VOL_RESERVED_SIZE
, VFSATTR_BIT(f_reserved
), sizeof(off_t
)},
361 {ATTR_VOL_ATTRIBUTES
, VFSATTR_BIT(f_attributes
), sizeof(vol_attributes_attr_t
)},
362 {ATTR_VOL_INFO
, 0, 0},
367 getvolattrlist_parsetab(struct getvolattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vfs_attr
*vsp
,
368 ssize_t
*sizep
, int is_64bit
, unsigned int maxiter
)
370 attrgroup_t recognised
;
374 /* is this attribute set? */
375 if (tab
->attr
& attrs
) {
376 recognised
|= tab
->attr
;
377 vsp
->f_active
|= tab
->bits
;
378 if (tab
->size
== ATTR_TIME_SIZE
) {
380 *sizep
+= sizeof(struct user64_timespec
);
382 *sizep
+= sizeof(struct user32_timespec
);
388 } while (((++tab
)->attr
!= 0) && (--maxiter
> 0));
390 /* check to make sure that we recognised all of the passed-in attributes */
391 if (attrs
& ~recognised
)
397 * Given the attributes listed in alp, configure vap to request
398 * the data from a filesystem.
401 getvolattrlist_setupvfsattr(struct attrlist
*alp
, struct vfs_attr
*vsp
, ssize_t
*sizep
, int is_64bit
)
408 * Parse the above tables.
410 *sizep
= sizeof(uint32_t); /* length count */
411 if (alp
->commonattr
) {
412 if ((alp
->commonattr
& ATTR_CMN_VOL_INVALID
) &&
413 (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
) == 0) {
416 if ((error
= getvolattrlist_parsetab(getvolattrlist_common_tab
,
417 alp
->commonattr
, vsp
, sizep
,
419 sizeof(getvolattrlist_common_tab
)/sizeof(getvolattrlist_common_tab
[0]))) != 0) {
424 (error
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
, sizeof(getvolattrlist_vol_tab
)/sizeof(getvolattrlist_vol_tab
[0]))) != 0)
431 * Given the attributes listed in asp and those supported
432 * in the vsp, fixup the asp attributes to reflect any
433 * missing attributes from the file system
436 getvolattrlist_fixupattrs(attribute_set_t
*asp
, struct vfs_attr
*vsp
)
438 struct getvolattrlist_attrtab
*tab
;
440 if (asp
->commonattr
) {
441 tab
= getvolattrlist_common_tab
;
443 if ((tab
->attr
& asp
->commonattr
) &&
445 ((tab
->bits
& vsp
->f_supported
) == 0)) {
446 asp
->commonattr
&= ~tab
->attr
;
448 } while ((++tab
)->attr
!= 0);
451 tab
= getvolattrlist_vol_tab
;
453 if ((tab
->attr
& asp
->volattr
) &&
455 ((tab
->bits
& vsp
->f_supported
) == 0)) {
456 asp
->volattr
&= ~tab
->attr
;
458 } while ((++tab
)->attr
!= 0);
463 * Table-driven setup for all valid common/dir/file/fork attributes against files.
465 struct getattrlist_attrtab
{
468 #define VATTR_BIT(b) (VNODE_ATTR_ ## b)
470 kauth_action_t action
;
474 * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this
475 * information, and we will synthesize it at the VFS level.
477 static struct getattrlist_attrtab getattrlist_common_tab
[] = {
478 {ATTR_CMN_NAME
, VATTR_BIT(va_name
), sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
479 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
480 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
481 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
482 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
483 {ATTR_CMN_OBJID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
484 {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
485 {ATTR_CMN_PAROBJID
, VATTR_BIT(va_parentid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
486 {ATTR_CMN_SCRIPT
, VATTR_BIT(va_encoding
), sizeof(text_encoding_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
487 {ATTR_CMN_CRTIME
, VATTR_BIT(va_create_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
488 {ATTR_CMN_MODTIME
, VATTR_BIT(va_modify_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
489 {ATTR_CMN_CHGTIME
, VATTR_BIT(va_change_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
490 {ATTR_CMN_ACCTIME
, VATTR_BIT(va_access_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
491 {ATTR_CMN_BKUPTIME
, VATTR_BIT(va_backup_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
492 {ATTR_CMN_FNDRINFO
, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES
},
493 {ATTR_CMN_OWNERID
, VATTR_BIT(va_uid
), sizeof(uid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
494 {ATTR_CMN_GRPID
, VATTR_BIT(va_gid
), sizeof(gid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
495 {ATTR_CMN_ACCESSMASK
, VATTR_BIT(va_mode
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
496 {ATTR_CMN_FLAGS
, VATTR_BIT(va_flags
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
497 {ATTR_CMN_GEN_COUNT
, VATTR_BIT(va_write_gencount
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
498 {ATTR_CMN_DOCUMENT_ID
, VATTR_BIT(va_document_id
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
499 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
500 {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
), sizeof(struct attrreference
), KAUTH_VNODE_READ_SECURITY
},
501 {ATTR_CMN_UUID
, VATTR_BIT(va_uuuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
502 {ATTR_CMN_GRPUUID
, VATTR_BIT(va_guuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
503 {ATTR_CMN_FILEID
, VATTR_BIT(va_fileid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
504 {ATTR_CMN_PARENTID
, VATTR_BIT(va_parentid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
505 {ATTR_CMN_FULLPATH
, 0, sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
506 {ATTR_CMN_ADDEDTIME
, VATTR_BIT(va_addedtime
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
507 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
), 0},
508 {ATTR_CMN_ERROR
, 0, sizeof(uint32_t), 0},
509 {ATTR_CMN_DATA_PROTECT_FLAGS
, VATTR_BIT(va_dataprotect_class
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
513 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
514 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_dirlinkcount
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
515 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
516 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
517 {ATTR_DIR_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
518 {ATTR_DIR_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
519 {ATTR_DIR_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
522 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
523 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
524 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
525 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
526 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
527 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
528 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
529 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
530 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
531 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
535 //for forkattr bits repurposed as new common attributes
536 static struct getattrlist_attrtab getattrlist_common_extended_tab
[] = {
537 {ATTR_CMNEXT_RELPATH
, 0, sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
538 {ATTR_CMNEXT_PRIVATESIZE
, VATTR_BIT(va_private_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
543 * This table is for attributes which are only set from the getattrlistbulk(2)
544 * call. These attributes have already been set from the common, file and
545 * directory tables but the vattr bits have not been recorded. Since these
546 * vattr bits are only used from the bulk call, we have a seperate table for
548 * The sizes are not returned from here since the sizes have already been
549 * accounted from the common, file and directory tables.
551 static struct getattrlist_attrtab getattrlistbulk_common_tab
[] = {
552 {ATTR_CMN_DEVID
, VATTR_BIT(va_devid
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
553 {ATTR_CMN_FSID
, VATTR_BIT(va_fsid64
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
554 {ATTR_CMN_OBJTYPE
, VATTR_BIT(va_objtype
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
555 {ATTR_CMN_OBJTAG
, VATTR_BIT(va_objtag
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
556 {ATTR_CMN_USERACCESS
, VATTR_BIT(va_user_access
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
557 {ATTR_CMN_FNDRINFO
, VATTR_BIT(va_finderinfo
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
561 static struct getattrlist_attrtab getattrlistbulk_file_tab
[] = {
562 {ATTR_FILE_RSRCLENGTH
, VATTR_BIT(va_rsrc_length
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
563 {ATTR_FILE_RSRCALLOCSIZE
, VATTR_BIT(va_rsrc_alloc
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
567 static struct getattrlist_attrtab getattrlistbulk_common_extended_tab
[] = {
568 /* getattrlist_parsetab() expects > 1 entries */
574 * The following are attributes that VFS can derive.
576 * A majority of them are the same attributes that are required for stat(2) and statfs(2).
578 #define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
579 ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | ATTR_VOL_QUOTA_SIZE | ATTR_VOL_RESERVED_SIZE | \
580 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
581 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
582 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
583 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
584 ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
586 #define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
587 ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
588 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
589 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
590 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
591 ATTR_CMN_FNDRINFO | \
592 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
593 ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
594 ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
595 ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS | \
596 ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT | \
597 ATTR_CMN_DATA_PROTECT_FLAGS)
599 #define VFS_DFLT_ATT_CMN_EXT (ATTR_CMNEXT_PRIVATESIZE)
601 #define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
603 #define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
604 ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
605 ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
606 ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
607 ATTR_FILE_RSRCALLOCSIZE)
610 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
,
611 struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
,
612 int is_64bit
, unsigned int maxiter
)
614 attrgroup_t recognised
;
620 /* is this attribute set? */
621 if (tab
->attr
& attrs
) {
622 recognised
|= tab
->attr
;
624 vap
->va_active
|= tab
->bits
;
626 if (tab
->size
== ATTR_TIME_SIZE
) {
629 struct user64_timespec
);
632 struct user32_timespec
);
639 *actionp
|= tab
->action
;
640 if (attrs
== recognised
)
641 break; /* all done, get out */
643 } while (((++tab
)->attr
!= 0) && (--maxiter
> 0));
645 /* check to make sure that we recognised all of the passed-in attributes */
646 if (attrs
& ~recognised
)
652 * Given the attributes listed in alp, configure vap to request
653 * the data from a filesystem.
656 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
, int use_fork
)
661 * Parse the above tables.
663 *sizep
= sizeof(uint32_t); /* length count */
665 if (alp
->commonattr
&&
666 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_common_tab
)/sizeof(getattrlist_common_tab
[0]))) != 0)
668 if (isdir
&& alp
->dirattr
&&
669 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_dir_tab
)/sizeof(getattrlist_dir_tab
[0]))) != 0)
671 if (!isdir
&& alp
->fileattr
&&
672 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
, sizeof(getattrlist_file_tab
)/sizeof(getattrlist_file_tab
[0]))) != 0)
674 if (use_fork
&& alp
->forkattr
&&
675 (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)
682 * Given the attributes listed in alp, configure vap to request
683 * the data from a filesystem.
686 getattrlist_setupvattr_all(struct attrlist
*alp
, struct vnode_attr
*vap
,
687 enum vtype obj_type
, ssize_t
*fixedsize
, int is_64bit
, int use_fork
)
692 * Parse the above tables.
695 *fixedsize
= sizeof(uint32_t);
697 if (alp
->commonattr
) {
698 error
= getattrlist_parsetab(getattrlist_common_tab
,
699 alp
->commonattr
, vap
, fixedsize
, NULL
, is_64bit
,
700 sizeof(getattrlist_common_tab
)/sizeof(getattrlist_common_tab
[0]));
703 /* Ignore any errrors from the bulk table */
704 (void)getattrlist_parsetab(getattrlistbulk_common_tab
,
705 alp
->commonattr
, vap
, fixedsize
, NULL
, is_64bit
,
706 sizeof(getattrlistbulk_common_tab
)/sizeof(getattrlistbulk_common_tab
[0]));
708 * turn off va_fsid since we will be using only
709 * va_fsid64 for ATTR_CMN_FSID.
711 VATTR_CLEAR_ACTIVE(vap
, va_fsid
);
715 if (!error
&& (obj_type
== VNON
|| obj_type
== VDIR
) && alp
->dirattr
) {
716 error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
,
717 vap
, fixedsize
, NULL
, is_64bit
,
718 sizeof(getattrlist_dir_tab
)/sizeof(getattrlist_dir_tab
[0]));
721 if (!error
&& (obj_type
!= VDIR
) && alp
->fileattr
) {
722 error
= getattrlist_parsetab(getattrlist_file_tab
,
723 alp
->fileattr
, vap
, fixedsize
, NULL
, is_64bit
,
724 sizeof(getattrlist_file_tab
)/sizeof(getattrlist_file_tab
[0]));
727 /*Ignore any errors from the bulk table */
728 (void)getattrlist_parsetab(getattrlistbulk_file_tab
,
729 alp
->fileattr
, vap
, fixedsize
, NULL
, is_64bit
,
730 sizeof(getattrlistbulk_file_tab
)/sizeof(getattrlistbulk_file_tab
[0]));
734 /* fork attributes are like extended common attributes if enabled*/
735 if (!error
&& use_fork
&& alp
->forkattr
) {
736 error
= getattrlist_parsetab(getattrlist_common_extended_tab
,
737 alp
->forkattr
, vap
, fixedsize
, NULL
, is_64bit
,
738 sizeof(getattrlist_common_extended_tab
)/sizeof(getattrlist_common_extended_tab
[0]));
741 (void)getattrlist_parsetab(getattrlistbulk_common_extended_tab
,
742 alp
->forkattr
, vap
, fixedsize
, NULL
, is_64bit
,
743 sizeof(getattrlistbulk_common_extended_tab
)/sizeof(getattrlistbulk_common_extended_tab
[0]));
751 vfs_setup_vattr_from_attrlist(struct attrlist
*alp
, struct vnode_attr
*vap
,
752 enum vtype obj_vtype
, ssize_t
*attrs_fixed_sizep
, vfs_context_t ctx
)
754 // the caller passes us no options, we assume the caller wants the new fork
755 // attr behavior, hence the hardcoded 1
756 return (getattrlist_setupvattr_all(alp
, vap
, obj_vtype
,
757 attrs_fixed_sizep
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), 1));
764 * Given the attributes listed in asp and those supported
765 * in the vap, fixup the asp attributes to reflect any
766 * missing attributes from the file system
769 getattrlist_fixupattrs(attribute_set_t
*asp
, struct vnode_attr
*vap
, int use_fork
)
771 struct getattrlist_attrtab
*tab
;
773 if (asp
->commonattr
) {
774 tab
= getattrlist_common_tab
;
777 * This if() statement is slightly confusing. We're trying to
778 * iterate through all of the bits listed in the array
779 * getattr_common_tab, and see if the filesystem was expected
780 * to support it, and whether or not we need to do anything about this.
782 * This array is full of structs that have 4 fields (attr, bits, size, action).
783 * The first is used to store the ATTR_CMN_* bit that was being requested
784 * from userland. The second stores the VATTR_BIT corresponding to the field
785 * filled in vnode_attr struct. If it is 0, then we don't typically expect
786 * the filesystem to fill in this field. The third is the size of the field,
787 * and the fourth is the type of kauth actions needed.
789 * So, for all of the ATTR_CMN bits listed in this array, we iterate through
790 * them, and check to see if it was both passed down to the filesystem via the
791 * va_active bitfield, and whether or not we expect it to be emitted from
792 * the filesystem. If it wasn't supported, then we un-twiddle the bit and move
793 * on. This is done so that we can uncheck those bits and re-request
794 * a vnode_getattr from the filesystem again.
796 if ((tab
->attr
& asp
->commonattr
) &&
797 (tab
->bits
& vap
->va_active
) &&
798 (tab
->bits
& vap
->va_supported
) == 0) {
799 asp
->commonattr
&= ~tab
->attr
;
801 } while ((++tab
)->attr
!= 0);
804 tab
= getattrlist_dir_tab
;
806 if ((tab
->attr
& asp
->dirattr
) &&
807 (tab
->bits
& vap
->va_active
) &&
808 (vap
->va_supported
& tab
->bits
) == 0) {
809 asp
->dirattr
&= ~tab
->attr
;
811 } while ((++tab
)->attr
!= 0);
814 tab
= getattrlist_file_tab
;
816 if ((tab
->attr
& asp
->fileattr
) &&
817 (tab
->bits
& vap
->va_active
) &&
818 (vap
->va_supported
& tab
->bits
) == 0) {
819 asp
->fileattr
&= ~tab
->attr
;
821 } while ((++tab
)->attr
!= 0);
823 if (use_fork
&& asp
->forkattr
) {
824 tab
= getattrlist_common_extended_tab
;
826 if ((tab
->attr
& asp
->forkattr
) &&
827 (tab
->bits
& vap
->va_active
) &&
828 (vap
->va_supported
& tab
->bits
) == 0) {
829 asp
->forkattr
&= ~tab
->attr
;
831 } while ((++tab
)->attr
!= 0);
836 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
839 char uio_buf
[UIO_SIZEOF(1)];
842 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
845 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
846 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
851 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
852 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
860 * Find something resembling a terminal component name in the mountedonname for vp
864 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
870 * We're looking for the last sequence of non / characters, but
871 * not including any trailing / characters.
876 for (cp
= mn
; *cp
!= 0; cp
++) {
878 /* start of run of chars */
884 /* end of run of chars */
891 /* need to close run? */
898 getvolattrlist(vfs_context_t ctx
, vnode_t vp
, struct attrlist
*alp
,
899 user_addr_t attributeBuffer
, size_t bufferSize
, uint64_t options
,
900 enum uio_seg segflg
, int is_64bit
)
903 struct vnode_attr va
;
904 struct _attrlist_buf ab
;
906 ssize_t fixedsize
, varsize
;
907 const char *cnp
= NULL
; /* protected by ATTR_CMN_NAME */
908 ssize_t cnl
= 0; /* protected by ATTR_CMN_NAME */
917 vs
.f_vol_name
= NULL
;
921 /* Check for special packing semantics */
922 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
);
923 pack_invalid
= (options
& FSOPT_PACK_INVAL_ATTRS
);
925 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
930 /* Keep invalid attrs from being uninitialized */
931 bzero(&vs
, sizeof (vs
));
932 /* Generate a valid mask for post processing */
933 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
937 * For now, the vnode must be the root of its filesystem.
938 * To relax this, we need to be able to find the root vnode of a filesystem
939 * from any vnode in the filesystem.
941 if (!vnode_isvroot(vp
)) {
943 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
948 * Set up the vfs_attr structure and call the filesystem.
950 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
951 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
954 if (vs
.f_active
!= 0) {
955 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
956 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
957 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
958 if (vs
.f_vol_name
== NULL
) {
960 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
965 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
966 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
967 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
971 error
= mac_mount_check_getattr(ctx
, mnt
, &vs
);
973 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d", error
);
978 * Did we ask for something the filesystem doesn't support?
980 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
981 /* default value for volume subtype */
982 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
983 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
984 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
987 * If the file system didn't supply f_signature, then
988 * default it to 'BD', which is the generic signature
989 * that most Carbon file systems should return.
991 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
992 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
993 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
995 /* default for block size */
996 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
997 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
998 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
1000 /* default value for volume f_attributes */
1001 if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
)
1002 && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) {
1003 vol_attributes_attr_t
*attrp
= &vs
.f_attributes
;
1005 attrp
->validattr
.commonattr
= VFS_DFLT_ATTR_CMN
;
1006 attrp
->validattr
.volattr
= VFS_DFLT_ATTR_VOL
;
1007 attrp
->validattr
.dirattr
= VFS_DFLT_ATTR_DIR
;
1008 attrp
->validattr
.fileattr
= VFS_DFLT_ATTR_FILE
;
1009 attrp
->validattr
.forkattr
= 0;
1011 attrp
->nativeattr
.commonattr
= 0;
1012 attrp
->nativeattr
.volattr
= 0;
1013 attrp
->nativeattr
.dirattr
= 0;
1014 attrp
->nativeattr
.fileattr
= 0;
1015 attrp
->nativeattr
.forkattr
= 0;
1016 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
);
1019 /* default value for volume f_capabilities */
1020 if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) {
1021 /* getattrlist is always supported now. */
1022 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) {
1023 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0;
1024 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
1025 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1026 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1028 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0;
1029 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
1030 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1031 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1032 VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
);
1035 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
1036 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
1037 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
1041 /* check to see if our fixups were enough */
1042 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
1045 /* Fix up valid mask for post processing */
1046 getvolattrlist_fixupattrs(&ab
.valid
, &vs
);
1048 /* Force packing of everything asked for */
1049 vs
.f_supported
= vs
.f_active
;
1051 /* Adjust the requested attributes */
1052 getvolattrlist_fixupattrs((attribute_set_t
*)&alp
->commonattr
, &vs
);
1063 * Some fields require data from the root vp
1065 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
1066 VATTR_WANTED(&va
, va_uid
);
1067 VATTR_WANTED(&va
, va_gid
);
1068 VATTR_WANTED(&va
, va_mode
);
1069 VATTR_WANTED(&va
, va_flags
);
1070 VATTR_WANTED(&va
, va_encoding
);
1072 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
1073 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
1077 error
= mac_vnode_check_getattr(ctx
, NOCRED
, vp
, &va
);
1079 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d for root vnode", error
);
1083 if (VATTR_IS_ACTIVE(&va
, va_encoding
) &&
1084 !VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
1085 if (!return_valid
|| pack_invalid
)
1086 /* use kTextEncodingMacUnicode */
1087 VATTR_RETURN(&va
, va_encoding
, 0x7e);
1089 /* don't use a default */
1090 alp
->commonattr
&= ~ATTR_CMN_SCRIPT
;
1095 * Compute variable-size buffer requirements.
1098 if (alp
->commonattr
& ATTR_CMN_NAME
) {
1099 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
1100 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
1101 /* special case for boot volume. Use root name when it's
1102 * available (which is the volume name) or just the mount on
1103 * name of "/". we must do this for binary compatibility with
1104 * pre Tiger code. returning nothing for the boot volume name
1105 * breaks installers - 3961058
1107 cnp
= vnode_getname(vp
);
1109 /* just use "/" as name */
1110 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
1118 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
1120 if (alp
->commonattr
& ATTR_CMN_NAME
)
1121 varsize
+= roundup(cnl
+ 1, 4);
1123 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
1124 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
1125 if (alp
->volattr
& ATTR_VOL_NAME
) {
1126 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
1127 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
1129 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
1130 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
1133 * Allocate a target buffer for attribute results.
1134 * Note that since we won't ever copy out more than the caller requested,
1135 * we never need to allocate more than they offer.
1137 ab
.allocated
= ulmin(bufferSize
, fixedsize
+ varsize
);
1138 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1140 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1143 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_ZERO
| M_WAITOK
);
1144 if (ab
.base
== NULL
) {
1146 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1151 * Pack results into the destination buffer.
1153 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1155 ab
.fixedcursor
+= sizeof (attribute_set_t
);
1156 bzero(&ab
.actual
, sizeof (ab
.actual
));
1158 ab
.varcursor
= ab
.base
+ fixedsize
;
1159 ab
.needed
= fixedsize
+ varsize
;
1161 /* common attributes **************************************************/
1162 if (alp
->commonattr
& ATTR_CMN_NAME
) {
1163 attrlist_pack_string(&ab
, cnp
, cnl
);
1164 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
1166 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
1167 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
1168 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
1170 if (alp
->commonattr
& ATTR_CMN_FSID
) {
1171 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
);
1172 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
1174 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
1175 if (!return_valid
|| pack_invalid
)
1178 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
1179 ATTR_PACK4(ab
, vp
->v_tag
);
1180 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1182 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
1183 if (!return_valid
|| pack_invalid
) {
1184 fsobj_id_t f
= {0, 0};
1188 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1189 if (!return_valid
|| pack_invalid
) {
1190 fsobj_id_t f
= {0, 0};
1194 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
1195 if (!return_valid
|| pack_invalid
) {
1196 fsobj_id_t f
= {0, 0};
1200 /* note that this returns the encoding for the volume name, not the node name */
1201 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
1202 ATTR_PACK4(ab
, va
.va_encoding
);
1203 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1205 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
1206 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
);
1207 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1209 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
1210 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
1211 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1213 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
1214 if (!return_valid
|| pack_invalid
)
1215 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
1217 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
1218 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
);
1219 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1221 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
1222 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
);
1223 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1225 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
1228 * This attribute isn't really Finder Info, at least for HFS.
1230 if (vp
->v_tag
== VT_HFS
) {
1231 #define HFS_GET_BOOT_INFO (FCNTL_FS_SPECIFIC_BASE + 0x00004)
1232 error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
);
1234 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
1235 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1236 } else if (!return_valid
) {
1239 } else if (!return_valid
|| pack_invalid
) {
1240 /* XXX we could at least pass out the volume UUID here */
1241 bzero(&f
, sizeof(f
));
1242 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
1245 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
1246 ATTR_PACK4(ab
, va
.va_uid
);
1247 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1249 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
1250 ATTR_PACK4(ab
, va
.va_gid
);
1251 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1253 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
1254 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
1255 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1257 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
1258 ATTR_PACK4(ab
, va
.va_flags
);
1259 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1261 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
1263 if (vnode_isdir(vp
)) {
1264 if (vnode_authorize(vp
, NULL
,
1265 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1267 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1269 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1272 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1274 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1276 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1281 * Rather than MAC preceding DAC, in this case we want
1282 * the smallest set of permissions granted by both MAC & DAC
1283 * checks. We won't add back any permissions.
1286 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1289 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1292 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1295 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
1296 ATTR_PACK4(ab
, perms
);
1297 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1300 * The following common volume attributes are only
1301 * packed when the pack_invalid mode is enabled.
1306 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
)
1307 attrlist_pack_variable(&ab
, NULL
, 0);
1308 if (alp
->commonattr
& ATTR_CMN_UUID
)
1309 ATTR_PACK(&ab
, kauth_null_guid
);
1310 if (alp
->commonattr
& ATTR_CMN_GRPUUID
)
1311 ATTR_PACK(&ab
, kauth_null_guid
);
1312 if (alp
->commonattr
& ATTR_CMN_FILEID
)
1313 ATTR_PACK8(ab
, fid
);
1314 if (alp
->commonattr
& ATTR_CMN_PARENTID
)
1315 ATTR_PACK8(ab
, fid
);
1318 /* volume attributes **************************************************/
1320 if (alp
->volattr
& ATTR_VOL_FSTYPE
) {
1321 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
1322 ab
.actual
.volattr
|= ATTR_VOL_FSTYPE
;
1324 if (alp
->volattr
& ATTR_VOL_SIGNATURE
) {
1325 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
1326 ab
.actual
.volattr
|= ATTR_VOL_SIGNATURE
;
1328 if (alp
->volattr
& ATTR_VOL_SIZE
) {
1329 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
1330 ab
.actual
.volattr
|= ATTR_VOL_SIZE
;
1332 if (alp
->volattr
& ATTR_VOL_SPACEFREE
) {
1333 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
1334 ab
.actual
.volattr
|= ATTR_VOL_SPACEFREE
;
1336 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
) {
1337 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
1338 ab
.actual
.volattr
|= ATTR_VOL_SPACEAVAIL
;
1340 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
) {
1341 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
1342 ab
.actual
.volattr
|= ATTR_VOL_MINALLOCATION
;
1344 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
) {
1345 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
1346 ab
.actual
.volattr
|= ATTR_VOL_ALLOCATIONCLUMP
;
1348 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
) {
1349 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
1350 ab
.actual
.volattr
|= ATTR_VOL_IOBLOCKSIZE
;
1352 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
) {
1353 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
1354 ab
.actual
.volattr
|= ATTR_VOL_OBJCOUNT
;
1356 if (alp
->volattr
& ATTR_VOL_FILECOUNT
) {
1357 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
1358 ab
.actual
.volattr
|= ATTR_VOL_FILECOUNT
;
1360 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
) {
1361 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
1362 ab
.actual
.volattr
|= ATTR_VOL_DIRCOUNT
;
1364 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
) {
1365 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
1366 ab
.actual
.volattr
|= ATTR_VOL_MAXOBJCOUNT
;
1368 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
) {
1369 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
1370 ab
.actual
.volattr
|= ATTR_VOL_MOUNTPOINT
;
1372 if (alp
->volattr
& ATTR_VOL_NAME
) {
1373 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
1374 ab
.actual
.volattr
|= ATTR_VOL_NAME
;
1376 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
) {
1377 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
1378 ab
.actual
.volattr
|= ATTR_VOL_MOUNTFLAGS
;
1380 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
) {
1381 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
1382 ab
.actual
.volattr
|= ATTR_VOL_MOUNTEDDEVICE
;
1384 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
) {
1385 if (!return_valid
|| pack_invalid
)
1386 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
1388 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
1389 /* fix up volume capabilities */
1390 if (vfs_extendedsecurity(mnt
)) {
1391 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1393 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
1395 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1396 ATTR_PACK(&ab
, vs
.f_capabilities
);
1397 ab
.actual
.volattr
|= ATTR_VOL_CAPABILITIES
;
1399 if (alp
->volattr
& ATTR_VOL_UUID
) {
1400 ATTR_PACK(&ab
, vs
.f_uuid
);
1401 ab
.actual
.volattr
|= ATTR_VOL_UUID
;
1403 if (alp
->volattr
& ATTR_VOL_QUOTA_SIZE
) {
1404 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_quota
);
1405 ab
.actual
.volattr
|= ATTR_VOL_QUOTA_SIZE
;
1407 if (alp
->volattr
& ATTR_VOL_RESERVED_SIZE
) {
1408 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_reserved
);
1409 ab
.actual
.volattr
|= ATTR_VOL_RESERVED_SIZE
;
1411 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
1412 /* fix up volume attribute information */
1414 vs
.f_attributes
.validattr
.commonattr
|= VFS_DFLT_ATTR_CMN
;
1415 vs
.f_attributes
.validattr
.volattr
|= VFS_DFLT_ATTR_VOL
;
1416 vs
.f_attributes
.validattr
.dirattr
|= VFS_DFLT_ATTR_DIR
;
1417 vs
.f_attributes
.validattr
.fileattr
|= VFS_DFLT_ATTR_FILE
;
1419 if (vfs_extendedsecurity(mnt
)) {
1420 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1422 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1423 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1425 ATTR_PACK(&ab
, vs
.f_attributes
);
1426 ab
.actual
.volattr
|= ATTR_VOL_ATTRIBUTES
;
1430 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1431 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1432 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
1433 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1434 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1437 * In the compatible case, we report the smaller of the required and returned sizes.
1438 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1439 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1440 * they gave us, so they can always check for truncation themselves.
1442 *(uint32_t *)ab
.base
= (options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1444 /* Return attribute set output if requested. */
1446 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1448 /* Only report the attributes that are valid */
1449 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1450 ab
.actual
.volattr
&= ab
.valid
.volattr
;
1452 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1455 if (UIO_SEG_IS_USER_SPACE(segflg
))
1456 error
= copyout(ab
.base
, CAST_USER_ADDR_T(attributeBuffer
),
1459 bcopy(ab
.base
, (void *)attributeBuffer
, (size_t)ab
.allocated
);
1462 if (vs
.f_vol_name
!= NULL
)
1463 kfree(vs
.f_vol_name
, MAXPATHLEN
);
1467 if (ab
.base
!= NULL
)
1468 FREE(ab
.base
, M_TEMP
);
1469 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1474 * Pack ATTR_COMMON attributes into a user buffer.
1475 * alp is a pointer to the bitmap of attributes required.
1476 * abp is the state of the attribute filling operation.
1477 * The attribute data (along with some other fields that are required
1481 attr_pack_common(vfs_context_t ctx
, struct vnode
*vp
, struct attrlist
*alp
,
1482 struct _attrlist_buf
*abp
, struct vnode_attr
*vap
, int proc_is64
,
1483 const char *cnp
, ssize_t cnl
, const char *fullpathptr
,
1484 ssize_t fullpathlen
, int return_valid
, int pack_invalid
, int vtype
,
1490 if ((alp
->commonattr
& ATTR_CMN_ERROR
) &&
1491 (!return_valid
|| pack_invalid
)) {
1492 ATTR_PACK4((*abp
), 0);
1493 abp
->actual
.commonattr
|= ATTR_CMN_ERROR
;
1495 if (alp
->commonattr
& ATTR_CMN_NAME
) {
1496 attrlist_pack_string(abp
, cnp
, cnl
);
1497 abp
->actual
.commonattr
|= ATTR_CMN_NAME
;
1499 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
1502 vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1503 abp
->actual
.commonattr
|= ATTR_CMN_DEVID
;
1504 } else if (VATTR_IS_SUPPORTED(vap
, va_devid
)) {
1505 ATTR_PACK4((*abp
), vap
->va_devid
);
1506 abp
->actual
.commonattr
|= ATTR_CMN_DEVID
;
1507 } else if (!return_valid
|| pack_invalid
) {
1508 ATTR_PACK4((*abp
), 0);
1511 if (alp
->commonattr
& ATTR_CMN_FSID
) {
1514 vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1515 abp
->actual
.commonattr
|= ATTR_CMN_FSID
;
1516 } else if (VATTR_IS_SUPPORTED(vap
, va_fsid64
)) {
1517 ATTR_PACK8((*abp
), vap
->va_fsid64
);
1518 abp
->actual
.commonattr
|= ATTR_CMN_FSID
;
1519 } else if (!return_valid
|| pack_invalid
) {
1520 fsid_t fsid
= {{0}};
1522 ATTR_PACK8((*abp
), fsid
);
1525 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
1527 ATTR_PACK4((*abp
), vtype
);
1528 abp
->actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1529 } else if (VATTR_IS_SUPPORTED(vap
, va_objtype
)) {
1530 ATTR_PACK4((*abp
), vap
->va_objtype
);
1531 abp
->actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1532 } else if (!return_valid
|| pack_invalid
) {
1533 ATTR_PACK4((*abp
), 0);
1536 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
1538 ATTR_PACK4((*abp
), vp
->v_tag
);
1539 abp
->actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1540 } else if (VATTR_IS_SUPPORTED(vap
, va_objtag
)) {
1541 ATTR_PACK4((*abp
), vap
->va_objtag
);
1542 abp
->actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1543 } else if (!return_valid
|| pack_invalid
) {
1544 ATTR_PACK4((*abp
), 0);
1547 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
1549 * Carbon can't deal with us reporting the target ID
1550 * for links. So we ask the filesystem to give us the
1551 * source ID as well, and if it gives us one, we use
1554 if (vap
->va_vaflags
& VA_64BITOBJIDS
) {
1555 if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) {
1556 ATTR_PACK8((*abp
), vap
->va_linkid
);
1558 ATTR_PACK8((*abp
), vap
->va_fileid
);
1562 if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) {
1563 f
.fid_objno
= (uint32_t)vap
->va_linkid
;
1565 f
.fid_objno
= (uint32_t)vap
->va_fileid
;
1567 f
.fid_generation
= 0;
1568 ATTR_PACK8((*abp
), f
);
1570 abp
->actual
.commonattr
|= ATTR_CMN_OBJID
;
1572 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1574 * Carbon can't deal with us reporting the target ID
1575 * for links. So we ask the filesystem to give us the
1576 * source ID as well, and if it gives us one, we use
1579 if (vap
->va_vaflags
& VA_64BITOBJIDS
) {
1580 if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) {
1581 ATTR_PACK8((*abp
), vap
->va_linkid
);
1583 ATTR_PACK8((*abp
), vap
->va_fileid
);
1587 if (VATTR_IS_SUPPORTED(vap
, va_linkid
)) {
1588 f
.fid_objno
= (uint32_t)vap
->va_linkid
;
1590 f
.fid_objno
= (uint32_t)vap
->va_fileid
;
1592 f
.fid_generation
= 0;
1593 ATTR_PACK8((*abp
), f
);
1595 abp
->actual
.commonattr
|= ATTR_CMN_OBJPERMANENTID
;
1597 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
1598 if (vap
->va_vaflags
& VA_64BITOBJIDS
) {
1599 ATTR_PACK8((*abp
), vap
->va_parentid
);
1602 f
.fid_objno
= (uint32_t)vap
->va_parentid
;
1603 f
.fid_generation
= 0;
1604 ATTR_PACK8((*abp
), f
);
1606 abp
->actual
.commonattr
|= ATTR_CMN_PAROBJID
;
1608 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
1609 if (VATTR_IS_SUPPORTED(vap
, va_encoding
)) {
1610 ATTR_PACK4((*abp
), vap
->va_encoding
);
1611 abp
->actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1612 } else if (!return_valid
|| pack_invalid
) {
1613 ATTR_PACK4((*abp
), 0x7e);
1616 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
1617 ATTR_PACK_TIME((*abp
), vap
->va_create_time
, proc_is64
);
1618 abp
->actual
.commonattr
|= ATTR_CMN_CRTIME
;
1620 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
1621 ATTR_PACK_TIME((*abp
), vap
->va_modify_time
, proc_is64
);
1622 abp
->actual
.commonattr
|= ATTR_CMN_MODTIME
;
1624 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
1625 ATTR_PACK_TIME((*abp
), vap
->va_change_time
, proc_is64
);
1626 abp
->actual
.commonattr
|= ATTR_CMN_CHGTIME
;
1628 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
1629 ATTR_PACK_TIME((*abp
), vap
->va_access_time
, proc_is64
);
1630 abp
->actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1632 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
1633 ATTR_PACK_TIME((*abp
), vap
->va_backup_time
, proc_is64
);
1634 abp
->actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1637 * They are requesting user access, we should obtain this before getting
1638 * the finder info. For some network file systems this is a performance
1641 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1642 if (vp
&& !is_bulk
) {
1643 if (vtype
== VDIR
) {
1644 if (vnode_authorize(vp
, NULL
,
1645 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
|
1646 KAUTH_VNODE_ADD_SUBDIRECTORY
|
1647 KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1650 if (vnode_authorize(vp
, NULL
,
1651 KAUTH_VNODE_ACCESS
|
1652 KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1655 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
|
1656 KAUTH_VNODE_SEARCH
, ctx
) == 0)
1659 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
|
1660 KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1663 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1665 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1668 } else if (is_bulk
&&
1669 VATTR_IS_SUPPORTED(vap
, va_user_access
)) {
1670 perms
= vap
->va_user_access
;
1673 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
1677 if (vp
&& !is_bulk
) {
1679 char uio_buf
[UIO_SIZEOF(1)];
1681 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
,
1682 UIO_READ
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
1686 uio_addiov(auio
, CAST_USER_ADDR_T(abp
->fixedcursor
),
1688 /* fisize may be reset to 0 after this call */
1689 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
,
1690 &fisize
, XATTR_NOSECURITY
, ctx
);
1694 * Default to zeros if its not available,
1695 * unless ATTR_CMN_RETURNED_ATTRS was requested.
1698 (!return_valid
|| pack_invalid
) &&
1699 ((error
== ENOATTR
) || (error
== ENOENT
) ||
1700 (error
== ENOTSUP
) || (error
== EPERM
))) {
1701 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1702 bzero(abp
->fixedcursor
, 32);
1707 abp
->fixedcursor
+= 32;
1708 abp
->actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1709 } else if (!return_valid
) {
1713 * If we can inform the caller that we can't
1714 * return this attribute, reset error and
1715 * continue with the rest of the attributes.
1719 } else if (VATTR_IS_SUPPORTED(vap
, va_finderinfo
)) {
1720 bcopy(&vap
->va_finderinfo
[0], abp
->fixedcursor
, fisize
);
1721 abp
->fixedcursor
+= fisize
;
1722 abp
->actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1723 } else if (!return_valid
|| pack_invalid
) {
1724 bzero(abp
->fixedcursor
, fisize
);
1725 abp
->fixedcursor
+= fisize
;
1728 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
1729 ATTR_PACK4((*abp
), vap
->va_uid
);
1730 abp
->actual
.commonattr
|= ATTR_CMN_OWNERID
;
1732 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
1733 ATTR_PACK4((*abp
), vap
->va_gid
);
1734 abp
->actual
.commonattr
|= ATTR_CMN_GRPID
;
1736 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
1737 ATTR_PACK4((*abp
), vap
->va_mode
);
1738 abp
->actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1740 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
1741 ATTR_PACK4((*abp
), vap
->va_flags
);
1742 abp
->actual
.commonattr
|= ATTR_CMN_FLAGS
;
1744 if (alp
->commonattr
& ATTR_CMN_GEN_COUNT
) {
1745 if (VATTR_IS_SUPPORTED(vap
, va_write_gencount
)) {
1746 ATTR_PACK4((*abp
), vap
->va_write_gencount
);
1747 abp
->actual
.commonattr
|= ATTR_CMN_GEN_COUNT
;
1748 } else if (!return_valid
|| pack_invalid
) {
1749 ATTR_PACK4((*abp
), 0);
1753 if (alp
->commonattr
& ATTR_CMN_DOCUMENT_ID
) {
1754 if (VATTR_IS_SUPPORTED(vap
, va_document_id
)) {
1755 ATTR_PACK4((*abp
), vap
->va_document_id
);
1756 abp
->actual
.commonattr
|= ATTR_CMN_DOCUMENT_ID
;
1757 } else if (!return_valid
|| pack_invalid
) {
1758 ATTR_PACK4((*abp
), 0);
1761 /* We already obtain the user access, so just fill in the buffer here */
1762 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) {
1764 if (!is_bulk
&& vp
) {
1766 * Rather than MAC preceding DAC, in this case we want
1767 * the smallest set of permissions granted by both MAC &
1768 * DAC checks. We won't add back any permissions.
1771 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1774 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1777 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1781 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1782 if (!is_bulk
&& vp
) {
1783 ATTR_PACK4((*abp
), perms
);
1784 abp
->actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1785 } else if (is_bulk
&& VATTR_IS_SUPPORTED(vap
, va_user_access
)) {
1786 ATTR_PACK4((*abp
), perms
);
1787 abp
->actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1788 } else if (!return_valid
|| pack_invalid
) {
1789 ATTR_PACK4((*abp
), 0);
1792 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1793 if (VATTR_IS_SUPPORTED(vap
, va_acl
) && (vap
->va_acl
!= NULL
)) {
1794 struct kauth_filesec fsec
;
1796 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1798 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1799 fsec
.fsec_owner
= kauth_null_guid
;
1800 fsec
.fsec_group
= kauth_null_guid
;
1801 attrlist_pack_variable2(abp
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), vap
->va_acl
, KAUTH_ACL_COPYSIZE(vap
->va_acl
));
1802 abp
->actual
.commonattr
|= ATTR_CMN_EXTENDED_SECURITY
;
1803 } else if (!return_valid
|| pack_invalid
) {
1804 attrlist_pack_variable(abp
, NULL
, 0);
1807 if (alp
->commonattr
& ATTR_CMN_UUID
) {
1808 if (VATTR_IS_SUPPORTED(vap
, va_uuuid
)) {
1809 ATTR_PACK(abp
, vap
->va_uuuid
);
1810 abp
->actual
.commonattr
|= ATTR_CMN_UUID
;
1811 } else if (!return_valid
|| pack_invalid
) {
1812 ATTR_PACK(abp
, kauth_null_guid
);
1815 if (alp
->commonattr
& ATTR_CMN_GRPUUID
) {
1816 if (VATTR_IS_SUPPORTED(vap
, va_guuid
)) {
1817 ATTR_PACK(abp
, vap
->va_guuid
);
1818 abp
->actual
.commonattr
|= ATTR_CMN_GRPUUID
;
1819 } else if (!return_valid
|| pack_invalid
) {
1820 ATTR_PACK(abp
, kauth_null_guid
);
1823 if (alp
->commonattr
& ATTR_CMN_FILEID
) {
1824 ATTR_PACK8((*abp
), vap
->va_fileid
);
1825 abp
->actual
.commonattr
|= ATTR_CMN_FILEID
;
1827 if (alp
->commonattr
& ATTR_CMN_PARENTID
) {
1828 ATTR_PACK8((*abp
), vap
->va_parentid
);
1829 abp
->actual
.commonattr
|= ATTR_CMN_PARENTID
;
1832 if (alp
->commonattr
& ATTR_CMN_FULLPATH
) {
1834 attrlist_pack_string (abp
, fullpathptr
, fullpathlen
);
1835 abp
->actual
.commonattr
|= ATTR_CMN_FULLPATH
;
1839 if (alp
->commonattr
& ATTR_CMN_ADDEDTIME
) {
1840 if (VATTR_IS_SUPPORTED(vap
, va_addedtime
)) {
1841 ATTR_PACK_TIME((*abp
), vap
->va_addedtime
, proc_is64
);
1842 abp
->actual
.commonattr
|= ATTR_CMN_ADDEDTIME
;
1843 } else if (!return_valid
|| pack_invalid
) {
1844 struct timespec zerotime
= {0, 0};
1846 ATTR_PACK_TIME((*abp
), zerotime
, proc_is64
);
1849 if (alp
->commonattr
& ATTR_CMN_DATA_PROTECT_FLAGS
) {
1850 if (VATTR_IS_SUPPORTED(vap
, va_dataprotect_class
)) {
1851 ATTR_PACK4((*abp
), vap
->va_dataprotect_class
);
1852 abp
->actual
.commonattr
|= ATTR_CMN_DATA_PROTECT_FLAGS
;
1853 } else if (!return_valid
|| pack_invalid
) {
1854 ATTR_PACK4((*abp
), 0);
1862 attr_pack_dir(struct vnode
*vp
, struct attrlist
*alp
, struct _attrlist_buf
*abp
,
1863 struct vnode_attr
*vap
, int return_valid
, int pack_invalid
)
1865 if (alp
->dirattr
& ATTR_DIR_LINKCOUNT
) { /* full count of entries */
1866 ATTR_PACK4((*abp
), (uint32_t)vap
->va_dirlinkcount
);
1867 abp
->actual
.dirattr
|= ATTR_DIR_LINKCOUNT
;
1869 if (alp
->dirattr
& ATTR_DIR_ENTRYCOUNT
) {
1870 ATTR_PACK4((*abp
), (uint32_t)vap
->va_nchildren
);
1871 abp
->actual
.dirattr
|= ATTR_DIR_ENTRYCOUNT
;
1873 if (alp
->dirattr
& ATTR_DIR_MOUNTSTATUS
) {
1878 * The vnode that is passed down may either be a
1879 * top level vnode of a mount stack or a mounted
1880 * on vnode. In either case, the directory should
1881 * be reported as a mount point.
1883 if ((vp
->v_flag
& VROOT
) || vnode_mountedhere(vp
)) {
1884 mntstat
= DIR_MNTSTATUS_MNTPOINT
;
1890 * Report back on active vnode triggers
1891 * that can directly trigger a mount
1893 if (vp
->v_resolve
&&
1894 !(vp
->v_resolve
->vr_flags
& VNT_NO_DIRECT_MOUNT
)) {
1895 mntstat
|= DIR_MNTSTATUS_TRIGGER
;
1902 ATTR_PACK4((*abp
), mntstat
);
1903 abp
->actual
.dirattr
|= ATTR_DIR_MOUNTSTATUS
;
1905 if (alp
->dirattr
& ATTR_DIR_ALLOCSIZE
) {
1906 if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) {
1907 ATTR_PACK8((*abp
), vap
->va_data_alloc
);
1908 abp
->actual
.dirattr
|= ATTR_DIR_ALLOCSIZE
;
1909 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) {
1910 ATTR_PACK8((*abp
), vap
->va_total_alloc
);
1911 abp
->actual
.dirattr
|= ATTR_DIR_ALLOCSIZE
;
1912 } else if (!return_valid
|| pack_invalid
) {
1913 uint64_t zero_val
= 0;
1914 ATTR_PACK8((*abp
), zero_val
);
1917 if (alp
->dirattr
& ATTR_DIR_IOBLOCKSIZE
) {
1918 if (VATTR_IS_SUPPORTED(vap
, va_iosize
)) {
1919 ATTR_PACK4((*abp
), vap
->va_iosize
);
1920 abp
->actual
.dirattr
|= ATTR_DIR_IOBLOCKSIZE
;
1921 } else if (!return_valid
|| pack_invalid
) {
1922 ATTR_PACK4((*abp
), 0);
1926 * If the filesystem does not support datalength
1927 * or dataallocsize, then we infer that totalsize and
1928 * totalalloc are substitutes.
1930 if (alp
->dirattr
& ATTR_DIR_DATALENGTH
) {
1931 if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) {
1932 ATTR_PACK8((*abp
), vap
->va_data_size
);
1933 abp
->actual
.dirattr
|= ATTR_DIR_DATALENGTH
;
1934 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) {
1935 ATTR_PACK8((*abp
), vap
->va_total_size
);
1936 abp
->actual
.dirattr
|= ATTR_DIR_DATALENGTH
;
1937 } else if (!return_valid
|| pack_invalid
) {
1938 uint64_t zero_val
= 0;
1939 ATTR_PACK8((*abp
), zero_val
);
1947 * The is_bulk parameter differentiates whether the function is called from
1948 * getattrlist or getattrlistbulk. When coming in from getattrlistbulk,
1949 * the corresponding va_* values are expected to be the values filled and no
1950 * attempt is made to retrieve them by calling back into the filesystem.
1953 attr_pack_file(vfs_context_t ctx
, struct vnode
*vp
, struct attrlist
*alp
,
1954 struct _attrlist_buf
*abp
, struct vnode_attr
*vap
, int return_valid
,
1955 int pack_invalid
, int is_bulk
)
1958 uint64_t rlength
= 0;
1959 uint64_t ralloc
= 0;
1963 * Pre-fetch the rsrc attributes now so we only get them once.
1964 * Fetch the resource fork size/allocation via xattr interface
1966 if (vp
&& !is_bulk
&&
1967 (alp
->fileattr
& (ATTR_FILE_TOTALSIZE
| ATTR_FILE_ALLOCSIZE
|
1968 ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
))) {
1970 error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
,
1971 &rsize
, XATTR_NOSECURITY
, ctx
);
1973 if ((error
== ENOENT
) || (error
== ENOATTR
) ||
1974 (error
== ENOTSUP
) || (error
== EPERM
) ||
1975 (error
== EACCES
)) {
1984 if (alp
->fileattr
& (ATTR_FILE_RSRCALLOCSIZE
|
1985 ATTR_FILE_ALLOCSIZE
)) {
1988 blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1993 ralloc
= roundup(rsize
, blksize
);
1997 if (alp
->fileattr
& ATTR_FILE_LINKCOUNT
) {
1998 ATTR_PACK4((*abp
), (uint32_t)vap
->va_nlink
);
1999 abp
->actual
.fileattr
|= ATTR_FILE_LINKCOUNT
;
2002 * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes:
2003 * We infer that if the filesystem does not support va_data_size or va_data_alloc
2004 * it must not know about alternate forks. So when we need to gather
2005 * the total size or total alloc, it's OK to substitute the total size for
2006 * the data size below. This is because it is likely a flat filesystem and we must
2007 * be using AD files to store the rsrc fork and EAs.
2009 * Additionally, note that getattrlist is barred from being called on
2010 * resource fork paths. (Search for CN_ALLOWRSRCFORK). So if the filesystem does
2011 * support va_data_size, it is guaranteed to represent the data fork's size. This
2012 * is an important distinction to make because when we call vnode_getattr on
2013 * an HFS resource fork vnode, to get the size, it will vend out the resource
2014 * fork's size (it only gets the size of the passed-in vnode).
2016 if (alp
->fileattr
& ATTR_FILE_TOTALSIZE
) {
2018 uint64_t totalsize
= rlength
;
2020 if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) {
2021 totalsize
+= vap
->va_data_size
;
2022 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) {
2023 totalsize
+= vap
->va_total_size
;
2026 ATTR_PACK8((*abp
), totalsize
);
2027 abp
->actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
2028 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)) {
2029 ATTR_PACK8((*abp
), vap
->va_total_size
);
2030 abp
->actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
2031 } else if (!return_valid
|| pack_invalid
) {
2032 uint64_t zero_val
= 0;
2034 ATTR_PACK8((*abp
), zero_val
);
2037 if (alp
->fileattr
& ATTR_FILE_ALLOCSIZE
) {
2039 uint64_t totalalloc
= ralloc
;
2042 * If data_alloc is supported, then it must represent the
2045 if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) {
2046 totalalloc
+= vap
->va_data_alloc
;
2047 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) {
2048 totalalloc
+= vap
->va_total_alloc
;
2051 ATTR_PACK8((*abp
), totalalloc
);
2052 abp
->actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
2053 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)) {
2054 ATTR_PACK8((*abp
), vap
->va_total_alloc
);
2055 abp
->actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
2056 } else if (!return_valid
|| pack_invalid
) {
2057 uint64_t zero_val
= 0;
2059 ATTR_PACK8((*abp
), zero_val
);
2062 if (alp
->fileattr
& ATTR_FILE_IOBLOCKSIZE
) {
2063 if (VATTR_IS_SUPPORTED(vap
, va_iosize
)) {
2064 ATTR_PACK4((*abp
), vap
->va_iosize
);
2065 abp
->actual
.fileattr
|= ATTR_FILE_IOBLOCKSIZE
;
2066 } else if (!return_valid
|| pack_invalid
) {
2067 ATTR_PACK4((*abp
), 0);
2070 if (alp
->fileattr
& ATTR_FILE_CLUMPSIZE
) {
2071 if (!return_valid
|| pack_invalid
) {
2072 ATTR_PACK4((*abp
), 0); /* this value is deprecated */
2073 abp
->actual
.fileattr
|= ATTR_FILE_CLUMPSIZE
;
2076 if (alp
->fileattr
& ATTR_FILE_DEVTYPE
) {
2077 if (vp
&& (vp
->v_type
== VCHR
|| vp
->v_type
== VBLK
)) {
2080 if (vp
->v_specinfo
!= NULL
) {
2081 dev
= vp
->v_specinfo
->si_rdev
;
2082 } else if (VATTR_IS_SUPPORTED(vap
, va_rdev
)) {
2087 ATTR_PACK4((*abp
), dev
);
2088 abp
->actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
2090 ATTR_PACK4((*abp
), 0);
2091 abp
->actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
2092 } else if (VATTR_IS_SUPPORTED(vap
, va_rdev
)) {
2093 ATTR_PACK4((*abp
), vap
->va_rdev
);
2094 abp
->actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
2095 } else if (!return_valid
|| pack_invalid
) {
2096 ATTR_PACK4((*abp
), 0);
2100 * If the filesystem does not support datalength
2101 * or dataallocsize, then we infer that totalsize and
2102 * totalalloc are substitutes.
2104 if (alp
->fileattr
& ATTR_FILE_DATALENGTH
) {
2105 if (VATTR_IS_SUPPORTED(vap
, va_data_size
)) {
2106 ATTR_PACK8((*abp
), vap
->va_data_size
);
2107 abp
->actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
2108 } else if (VATTR_IS_SUPPORTED(vap
, va_total_size
)){
2109 ATTR_PACK8((*abp
), vap
->va_total_size
);
2110 abp
->actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
2111 } else if (!return_valid
|| pack_invalid
) {
2112 uint64_t zero_val
= 0;
2113 ATTR_PACK8((*abp
), zero_val
);
2116 if (alp
->fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
2117 if (VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) {
2118 ATTR_PACK8((*abp
), vap
->va_data_alloc
);
2119 abp
->actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
2120 } else if (VATTR_IS_SUPPORTED(vap
, va_total_alloc
)){
2121 ATTR_PACK8((*abp
), vap
->va_total_alloc
);
2122 abp
->actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
2123 } else if (!return_valid
|| pack_invalid
) {
2124 uint64_t zero_val
= 0;
2125 ATTR_PACK8((*abp
), zero_val
);
2128 /* already got the resource fork size/allocation above */
2129 if (alp
->fileattr
& ATTR_FILE_RSRCLENGTH
) {
2131 ATTR_PACK8((*abp
), rlength
);
2132 abp
->actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
2133 } else if (VATTR_IS_SUPPORTED(vap
, va_rsrc_length
)) {
2134 ATTR_PACK8((*abp
), vap
->va_rsrc_length
);
2135 abp
->actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
2136 } else if (!return_valid
|| pack_invalid
) {
2137 uint64_t zero_val
= 0;
2139 ATTR_PACK8((*abp
), zero_val
);
2142 if (alp
->fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
2144 ATTR_PACK8((*abp
), ralloc
);
2145 abp
->actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
2146 } else if (VATTR_IS_SUPPORTED(vap
, va_rsrc_alloc
)) {
2147 ATTR_PACK8((*abp
), vap
->va_rsrc_alloc
);
2148 abp
->actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
2149 } else if (!return_valid
|| pack_invalid
) {
2150 uint64_t zero_val
= 0;
2152 ATTR_PACK8((*abp
), zero_val
);
2160 * Pack FORKATTR attributes into a user buffer.
2161 * alp is a pointer to the bitmap of attributes required.
2162 * abp is the state of the attribute filling operation.
2163 * The attribute data (along with some other fields that are required
2167 attr_pack_common_extended(struct vnode
*vp
, struct attrlist
*alp
,
2168 struct _attrlist_buf
*abp
, const char *relpathptr
, ssize_t relpathlen
,
2169 struct vnode_attr
*vap
, int return_valid
, int pack_invalid
)
2171 if (vp
&& (alp
->forkattr
& ATTR_CMNEXT_RELPATH
)) {
2172 attrlist_pack_string(abp
, relpathptr
, relpathlen
);
2173 abp
->actual
.forkattr
|= ATTR_CMNEXT_RELPATH
;
2176 if (alp
->forkattr
& ATTR_CMNEXT_PRIVATESIZE
) {
2177 if (VATTR_IS_SUPPORTED(vap
, va_private_size
)) {
2178 ATTR_PACK8((*abp
), vap
->va_private_size
);
2179 abp
->actual
.forkattr
|= ATTR_CMNEXT_PRIVATESIZE
;
2180 } else if (!return_valid
|| pack_invalid
) {
2181 uint64_t zero_val
= 0;
2182 ATTR_PACK8((*abp
), zero_val
);
2190 vattr_get_alt_data(vnode_t vp
, struct attrlist
*alp
, struct vnode_attr
*vap
,
2191 int return_valid
, int is_bulk
, vfs_context_t ctx
)
2194 * There are a couple of special cases.
2195 * If we are after object IDs, we can make do with va_fileid.
2197 if ((alp
->commonattr
&
2198 (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
| ATTR_CMN_FILEID
)) &&
2199 !VATTR_IS_SUPPORTED(vap
, va_linkid
)) {
2200 /* forget we wanted this */
2201 VATTR_CLEAR_ACTIVE(vap
, va_linkid
);
2205 * Many filesystems don't know their parent object id.
2206 * If necessary, attempt to derive it from the vnode.
2208 if ((alp
->commonattr
& (ATTR_CMN_PAROBJID
| ATTR_CMN_PARENTID
)) &&
2209 !VATTR_IS_SUPPORTED(vap
, va_parentid
) && vp
&& !is_bulk
) {
2212 if ((dvp
= vnode_getparent(vp
)) != NULLVP
) {
2213 struct vnode_attr lva
;
2216 VATTR_WANTED(&lva
, va_fileid
);
2217 if (vnode_getattr(dvp
, &lva
, ctx
) == 0 &&
2218 VATTR_IS_SUPPORTED(vap
, va_fileid
)) {
2219 vap
->va_parentid
= lva
.va_fileid
;
2220 VATTR_SET_SUPPORTED(vap
, va_parentid
);
2226 * And we can report datasize/alloc from total.
2228 if ((alp
->fileattr
& ATTR_FILE_DATALENGTH
) &&
2229 !VATTR_IS_SUPPORTED(vap
, va_data_size
)) {
2230 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2233 if ((alp
->fileattr
& ATTR_FILE_DATAALLOCSIZE
) &&
2234 !VATTR_IS_SUPPORTED(vap
, va_data_alloc
)) {
2235 VATTR_CLEAR_ACTIVE(vap
, va_data_alloc
);
2239 * If we don't have an encoding, go with UTF-8
2241 if ((alp
->commonattr
& ATTR_CMN_SCRIPT
) &&
2242 !VATTR_IS_SUPPORTED(vap
, va_encoding
) && !return_valid
) {
2243 VATTR_RETURN(vap
, va_encoding
,
2244 0x7e /* kTextEncodingMacUnicode */);
2248 * If we don't have a name, we'll get one from the vnode or
2251 if ((alp
->commonattr
& ATTR_CMN_NAME
) &&
2252 !VATTR_IS_SUPPORTED(vap
, va_name
)) {
2253 VATTR_CLEAR_ACTIVE(vap
, va_name
);
2256 /* If va_dirlinkcount isn't supported use a default of 1. */
2257 if ((alp
->dirattr
& ATTR_DIR_LINKCOUNT
) &&
2258 !VATTR_IS_SUPPORTED(vap
, va_dirlinkcount
)) {
2259 VATTR_RETURN(vap
, va_dirlinkcount
, 1);
2264 calc_varsize(vnode_t vp
, struct attrlist
*alp
, struct vnode_attr
*vap
,
2265 ssize_t
*varsizep
, char *fullpathptr
, ssize_t
*fullpathlenp
,
2266 char *relpathptr
, ssize_t
*relpathlenp
, const char **vnamep
,
2267 const char **cnpp
, ssize_t
*cnlp
)
2271 *varsizep
= 0; /* length count */
2272 /* We may need to fix up the name attribute if requested */
2273 if (alp
->commonattr
& ATTR_CMN_NAME
) {
2274 if (VATTR_IS_SUPPORTED(vap
, va_name
)) {
2275 vap
->va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
2276 *cnpp
= vap
->va_name
;
2277 *cnlp
= strlen(*cnpp
);
2279 /* Filesystem did not support getting the name */
2280 if (vnode_isvroot(vp
)) {
2281 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
2282 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
2283 /* special case for boot volume. Use root name when it's
2284 * available (which is the volume name) or just the mount on
2285 * name of "/". we must do this for binary compatibility with
2286 * pre Tiger code. returning nothing for the boot volume name
2287 * breaks installers - 3961058
2289 *cnpp
= *vnamep
= vnode_getname(vp
);
2290 if (*cnpp
== NULL
) {
2291 /* just use "/" as name */
2292 *cnpp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
2294 *cnlp
= strlen(*cnpp
);
2297 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, cnpp
, cnlp
);
2301 *cnpp
= *vnamep
= vnode_getname(vp
);
2303 if (*cnpp
!= NULL
) {
2304 *cnlp
= strlen(*cnpp
);
2310 *varsizep
+= roundup(*cnlp
+ 1, 4);
2314 * Compute the full path to this vnode, if necessary. This attribute is almost certainly
2315 * not supported by any filesystem, so build the path to this vnode at this time.
2317 if (vp
&& (alp
->commonattr
& ATTR_CMN_FULLPATH
)) {
2318 int len
= MAXPATHLEN
;
2321 /* call build_path making sure NOT to use the cache-only behavior */
2322 err
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current());
2329 *fullpathlenp
= strlen(fullpathptr
);
2331 *varsizep
+= roundup(((*fullpathlenp
) + 1), 4);
2335 * Compute this vnode's volume relative path.
2337 if (vp
&& (alp
->forkattr
& ATTR_CMNEXT_RELPATH
)) {
2341 /* call build_path making sure NOT to use the cache-only behavior */
2342 err
= build_path(vp
, relpathptr
, MAXPATHLEN
, &len
, BUILDPATH_VOLUME_RELATIVE
, vfs_context_current());
2348 //`len' includes trailing null
2349 *relpathlenp
= len
- 1;
2350 *varsizep
+= roundup(len
, 4);
2354 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
2356 * XXX This needs to change at some point; since the blob is opaque in
2357 * user-space this is OK.
2359 if ((alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
2360 VATTR_IS_SUPPORTED(vap
, va_acl
) &&
2361 (vap
->va_acl
!= NULL
)) {
2364 * Since we have a kauth_acl_t (not a kauth_filesec_t), we have to check against
2365 * KAUTH_FILESEC_NOACL ourselves
2367 if (vap
->va_acl
->acl_entrycount
== KAUTH_FILESEC_NOACL
) {
2368 *varsizep
+= roundup((KAUTH_FILESEC_SIZE(0)), 4);
2371 *varsizep
+= roundup ((KAUTH_FILESEC_SIZE(vap
->va_acl
->acl_entrycount
)), 4);
2380 vfs_attr_pack_internal(vnode_t vp
, uio_t auio
, struct attrlist
*alp
,
2381 uint64_t options
, struct vnode_attr
*vap
, __unused
void *fndesc
,
2382 vfs_context_t ctx
, int is_bulk
, enum vtype vtype
, ssize_t fixedsize
)
2384 struct _attrlist_buf ab
;
2388 const char *vname
= NULL
;
2392 ssize_t fullpathlen
;
2399 int alloc_local_buf
;
2400 const int use_fork
= options
& FSOPT_ATTR_CMN_EXTENDED
;
2402 proc_is64
= proc_is64bit(vfs_context_proc(ctx
));
2411 alloc_local_buf
= 0;
2413 buf_size
= (ssize_t
)uio_resid(auio
);
2414 if ((buf_size
<= 0) || (uio_iovcnt(auio
) > 1))
2418 /* Check for special packing semantics */
2419 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
) ? 1 : 0;
2420 pack_invalid
= (options
& FSOPT_PACK_INVAL_ATTRS
) ? 1 : 0;
2423 /* Generate a valid mask for post processing */
2424 bcopy(&(alp
->commonattr
), &ab
.valid
, sizeof (attribute_set_t
));
2427 /* did we ask for something the filesystem doesn't support? */
2428 if (vap
->va_active
&& !VATTR_ALL_SUPPORTED(vap
)) {
2429 vattr_get_alt_data(vp
, alp
, vap
, return_valid
, is_bulk
,
2433 if (!VATTR_ALL_SUPPORTED(vap
)) {
2434 if (return_valid
&& pack_invalid
) {
2435 /* Fix up valid mask for post processing */
2436 getattrlist_fixupattrs(&ab
.valid
, vap
, use_fork
);
2438 /* Force packing of everything asked for */
2439 vap
->va_supported
= vap
->va_active
;
2440 } else if (return_valid
) {
2441 /* Adjust the requested attributes */
2442 getattrlist_fixupattrs(
2443 (attribute_set_t
*)&(alp
->commonattr
), vap
, use_fork
);
2453 //if a path is requested, allocate a temporary buffer to build it
2454 if (vp
&& (alp
->commonattr
& (ATTR_CMN_FULLPATH
))) {
2455 fullpathptr
= (char*) kalloc(MAXPATHLEN
);
2456 if (fullpathptr
== NULL
) {
2458 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
2461 bzero(fullpathptr
, MAXPATHLEN
);
2464 // only interpret fork attributes if they're used as new common attributes
2465 if (vp
&& use_fork
&& (alp
->forkattr
& (ATTR_CMNEXT_RELPATH
))) {
2466 relpathptr
= (char*) kalloc(MAXPATHLEN
);
2467 if (relpathptr
== NULL
) {
2469 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate relpath buffer");
2472 bzero(relpathptr
, MAXPATHLEN
);
2476 * Compute variable-space requirements.
2478 error
= calc_varsize(vp
, alp
, vap
, &varsize
, fullpathptr
, &fullpathlen
,
2479 relpathptr
, &relpathlen
, &vname
, &cnp
, &cnl
);
2484 * Allocate a target buffer for attribute results.
2486 * Note that we won't ever copy out more than the caller requested, even though
2487 * we might have to allocate more than they offer so that the diagnostic checks
2488 * don't result in a panic if the caller's buffer is too small..
2490 ab
.allocated
= fixedsize
+ varsize
;
2491 /* Cast 'allocated' to an unsigned to verify allocation size */
2492 if ( ((size_t)ab
.allocated
) > ATTR_MAX_BUFFER
) {
2494 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
2499 * Special handling for bulk calls, align to 8 (and only if enough
2503 if (buf_size
< ab
.allocated
) {
2508 newlen
= (ab
.allocated
+ 7) & ~0x07;
2509 /* Align only if enough space for alignment */
2510 if (newlen
<= (uint32_t)buf_size
)
2511 ab
.allocated
= newlen
;
2516 * See if we can reuse buffer passed in i.e. it is a kernel buffer
2519 if (uio_isuserspace(auio
) || (buf_size
< ab
.allocated
)) {
2520 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
,
2522 alloc_local_buf
= 1;
2525 * In case this is a kernel buffer and sufficiently
2526 * big, this function will try to use that buffer
2527 * instead of allocating another buffer and bcopy'ing
2530 * The calculation below figures out where to start
2531 * writing in the buffer and once all the data has been
2532 * filled in, uio_resid is updated to reflect the usage
2535 * uio_offset cannot be used here to determine the
2536 * starting location as uio_offset could be set to a
2537 * value which has nothing to do the location
2540 ab
.base
= (char *)uio_curriovbase(auio
) +
2541 ((ssize_t
)uio_curriovlen(auio
) - buf_size
);
2542 bzero(ab
.base
, ab
.allocated
);
2545 if (ab
.base
== NULL
) {
2547 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
2552 /* set the S_IFMT bits for the mode */
2553 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
2555 switch (vp
->v_type
) {
2557 vap
->va_mode
|= S_IFREG
;
2560 vap
->va_mode
|= S_IFDIR
;
2563 vap
->va_mode
|= S_IFBLK
;
2566 vap
->va_mode
|= S_IFCHR
;
2569 vap
->va_mode
|= S_IFLNK
;
2572 vap
->va_mode
|= S_IFSOCK
;
2575 vap
->va_mode
|= S_IFIFO
;
2585 * Pack results into the destination buffer.
2587 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
2589 ab
.fixedcursor
+= sizeof (attribute_set_t
);
2590 bzero(&ab
.actual
, sizeof (ab
.actual
));
2592 ab
.varcursor
= ab
.base
+ fixedsize
;
2593 ab
.needed
= ab
.allocated
;
2595 /* common attributes ************************************************/
2596 error
= attr_pack_common(ctx
, vp
, alp
, &ab
, vap
, proc_is64
, cnp
, cnl
,
2597 fullpathptr
, fullpathlen
, return_valid
, pack_invalid
, vtype
, is_bulk
);
2599 /* directory attributes *********************************************/
2600 if (!error
&& alp
->dirattr
&& (vtype
== VDIR
)) {
2601 error
= attr_pack_dir(vp
, alp
, &ab
, vap
, return_valid
, pack_invalid
);
2604 /* file attributes **************************************************/
2605 if (!error
&& alp
->fileattr
&& (vtype
!= VDIR
)) {
2606 error
= attr_pack_file(ctx
, vp
, alp
, &ab
, vap
, return_valid
,
2607 pack_invalid
, is_bulk
);
2610 /* common extended attributes *****************************************/
2611 if (!error
&& use_fork
) {
2612 error
= attr_pack_common_extended(vp
, alp
, &ab
, relpathptr
, relpathlen
,
2613 vap
, return_valid
, pack_invalid
);
2620 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
2621 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
2622 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
2623 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
2624 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
2627 * In the compatible case, we report the smaller of the required and returned sizes.
2628 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
2629 * of the result buffer, even if we copied less out. The caller knows how big a buffer
2630 * they gave us, so they can always check for truncation themselves.
2632 *(uint32_t *)ab
.base
= (options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
2634 /* Return attribute set output if requested. */
2636 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
2638 /* Only report the attributes that are valid */
2639 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
2640 ab
.actual
.dirattr
&= ab
.valid
.dirattr
;
2641 ab
.actual
.fileattr
&= ab
.valid
.fileattr
;
2643 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
2646 copy_size
= imin(buf_size
, ab
.allocated
);
2648 /* Only actually copyout as much out as the user buffer can hold */
2649 if (alloc_local_buf
) {
2650 error
= uiomove(ab
.base
, copy_size
, auio
);
2652 off_t orig_offset
= uio_offset(auio
);
2655 * The buffer in the uio struct was used directly
2656 * (i.e. it was a kernel buffer and big enough
2657 * to hold the data required) in order to avoid
2658 * un-needed allocation and copies.
2660 * At this point, update the resid value to what it
2661 * would be if this was the result of a uiomove. The
2662 * offset is also incremented, though it may not
2663 * mean anything to the caller but that is what
2664 * uiomove does as well.
2666 uio_setresid(auio
, buf_size
- copy_size
);
2667 uio_setoffset(auio
, orig_offset
+ (off_t
)copy_size
);
2672 vnode_putname(vname
);
2674 kfree(fullpathptr
, MAXPATHLEN
);
2676 kfree(relpathptr
, MAXPATHLEN
);
2677 if (ab
.base
!= NULL
&& alloc_local_buf
)
2678 FREE(ab
.base
, M_TEMP
);
2683 vfs_attr_pack(vnode_t vp
, uio_t uio
, struct attrlist
*alp
, uint64_t options
,
2684 struct vnode_attr
*vap
, __unused
void *fndesc
, vfs_context_t ctx
)
2688 uint64_t orig_active
;
2689 struct attrlist orig_al
;
2693 v_type
= vnode_vtype(vp
);
2695 v_type
= vap
->va_objtype
;
2698 orig_active
= vap
->va_active
;
2701 error
= getattrlist_setupvattr_all(alp
, vap
, v_type
, &fixedsize
,
2702 proc_is64bit(vfs_context_proc(ctx
)), options
& FSOPT_ATTR_CMN_EXTENDED
);
2706 "ATTRLIST - ERROR: setup for request failed");
2710 error
= vfs_attr_pack_internal(vp
, uio
, alp
,
2711 options
|FSOPT_REPORT_FULLSIZE
, vap
, NULL
, ctx
, 1, v_type
,
2714 VATTR_CLEAR_SUPPORTED_ALL(vap
);
2715 vap
->va_active
= orig_active
;
2722 * Obtain attribute information about a filesystem object.
2724 * Note: The alt_name parameter can be used by the caller to pass in the vnode
2725 * name obtained from some authoritative source (eg. readdir vnop); where
2726 * filesystems' getattr vnops do not support ATTR_CMN_NAME, the alt_name will be
2727 * used as the ATTR_CMN_NAME attribute returned in vnode_attr.va_name.
2731 getattrlist_internal(vfs_context_t ctx
, vnode_t vp
, struct attrlist
*alp
,
2732 user_addr_t attributeBuffer
, size_t bufferSize
, uint64_t options
,
2733 enum uio_seg segflg
, char* alt_name
, struct ucred
*file_cred
)
2735 struct vnode_attr va
;
2736 kauth_action_t action
;
2745 char uio_buf
[ UIO_SIZEOF(1)];
2746 // must be true for fork attributes to be used as new common attributes
2747 const int use_fork
= (options
& FSOPT_ATTR_CMN_EXTENDED
) != 0;
2749 proc_is64
= proc_is64bit(vfs_context_proc(ctx
));
2751 if (segflg
== UIO_USERSPACE
) {
2753 segflg
= UIO_USERSPACE64
;
2755 segflg
= UIO_USERSPACE32
;
2757 auio
= uio_createwithbuffer(1, 0, segflg
, UIO_READ
,
2758 &uio_buf
[0], sizeof(uio_buf
));
2759 uio_addiov(auio
, attributeBuffer
, bufferSize
);
2764 if (alp
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
2769 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
2770 vp
, p
->p_comm
, alp
->commonattr
, alp
->volattr
, alp
->fileattr
, alp
->dirattr
, alp
->forkattr
,
2771 (options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
2774 error
= mac_vnode_check_getattrlist(ctx
, vp
, alp
);
2780 * It is legal to request volume or file attributes, but not both.
2782 * 26903449 fork attributes can also be requested, but only if they're
2783 * interpreted as new, common attributes
2786 if (alp
->fileattr
|| alp
->dirattr
|| (alp
->forkattr
&& !use_fork
)) {
2788 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory attributes");
2791 /* handle volume attribute request */
2792 error
= getvolattrlist(ctx
, vp
, alp
, attributeBuffer
,
2793 bufferSize
, options
, segflg
, proc_is64
);
2798 * ATTR_CMN_GEN_COUNT and ATTR_CMN_DOCUMENT_ID reuse the bits
2799 * originally allocated to ATTR_CMN_NAMEDATTRCOUNT and
2800 * ATTR_CMN_NAMEDATTRLIST.
2802 if ((alp
->commonattr
& (ATTR_CMN_GEN_COUNT
| ATTR_CMN_DOCUMENT_ID
)) &&
2803 !(options
& FSOPT_ATTR_CMN_EXTENDED
)) {
2808 /* common extended attributes require FSOPT_ATTR_CMN_EXTENDED option */
2809 if (!(use_fork
) && (alp
->forkattr
& ATTR_CMNEXT_VALIDMASK
)) {
2814 /* FSOPT_ATTR_CMN_EXTENDED requires forkattrs are not referenced */
2815 if ((options
& FSOPT_ATTR_CMN_EXTENDED
) && (alp
->forkattr
& (ATTR_FORK_VALIDMASK
))) {
2820 /* Check for special packing semantics */
2821 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
) ? 1 : 0;
2822 pack_invalid
= (options
& FSOPT_PACK_INVAL_ATTRS
) ? 1 : 0;
2824 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
2825 if (!return_valid
|| (alp
->forkattr
&& !use_fork
)) {
2829 /* Keep invalid attrs from being uninitialized */
2830 bzero(&va
, sizeof (va
));
2833 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
2834 * will have a valid snapshot that we can work from here.
2839 * Set up the vnode_attr structure and authorise.
2841 if ((error
= getattrlist_setupvattr(alp
, &va
, &fixedsize
, &action
, proc_is64
, (vtype
== VDIR
), use_fork
)) != 0) {
2842 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
2845 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) {
2846 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
2851 if (va
.va_active
!= 0) {
2852 uint64_t va_active
= va
.va_active
;
2855 * If we're going to ask for va_name, allocate a buffer to point it at
2857 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
2858 MALLOC_ZONE(va_name
, char *, MAXPATHLEN
, M_NAMEI
,
2860 if (va_name
== NULL
) {
2862 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
2867 va
.va_name
= va_name
;
2870 * Call the filesystem.
2872 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
2873 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
2878 * Give MAC polices a chance to reject or filter the
2879 * attributes returned by the filesystem. Note that MAC
2880 * policies are consulted *after* calling the filesystem
2881 * because filesystems can return more attributes than
2882 * were requested so policies wouldn't be authoritative
2883 * is consulted beforehand. This also gives policies an
2884 * opportunity to change the values of attributes
2887 error
= mac_vnode_check_getattr(ctx
, file_cred
, vp
, &va
);
2889 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: MAC framework returned %d", error
);
2897 * If ATTR_CMN_NAME is not supported by filesystem and the
2898 * caller has provided a name, use that.
2899 * A (buggy) filesystem may change fields which belong
2900 * to us. We try to deal with that here as well.
2902 va
.va_active
= va_active
;
2903 if (alt_name
&& va_name
&&
2904 !(VATTR_IS_SUPPORTED(&va
, va_name
))) {
2905 strlcpy(va_name
, alt_name
, MAXPATHLEN
);
2906 VATTR_SET_SUPPORTED(&va
, va_name
);
2908 va
.va_name
= va_name
;
2911 error
= vfs_attr_pack_internal(vp
, auio
, alp
, options
, &va
, NULL
, ctx
,
2912 0, vtype
, fixedsize
);
2916 FREE_ZONE(va_name
, MAXPATHLEN
, M_NAMEI
);
2917 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
2918 kauth_acl_free(va
.va_acl
);
2920 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
2925 fgetattrlist(proc_t p
, struct fgetattrlist_args
*uap
, __unused
int32_t *retval
)
2931 struct fileproc
*fp
;
2933 ctx
= vfs_context_current();
2938 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2941 if ((error
= fp_lookup(p
, uap
->fd
, &fp
, 0)) != 0 ||
2942 (error
= vnode_getwithref(vp
)) != 0)
2946 * Fetch the attribute request.
2948 error
= copyin(uap
->alist
, &al
, sizeof(al
));
2952 /* Default to using the vnode's name. */
2953 error
= getattrlist_internal(ctx
, vp
, &al
, uap
->attributeBuffer
,
2954 uap
->bufferSize
, uap
->options
,
2955 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: \
2956 UIO_USERSPACE32
), NULL
,
2957 fp
->f_fglob
->fg_cred
);
2961 fp_drop(p
, uap
->fd
, fp
, 0);
2970 getattrlistat_internal(vfs_context_t ctx
, user_addr_t path
,
2971 struct attrlist
*alp
, user_addr_t attributeBuffer
, size_t bufferSize
,
2972 uint64_t options
, enum uio_seg segflg
, enum uio_seg pathsegflg
, int fd
)
2974 struct nameidata nd
;
2983 if (!(options
& FSOPT_NOFOLLOW
))
2984 nameiflags
|= FOLLOW
;
2986 nameiflags
|= AUDITVNPATH1
;
2987 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, nameiflags
, pathsegflg
,
2990 error
= nameiat(&nd
, fd
);
2997 error
= getattrlist_internal(ctx
, vp
, alp
, attributeBuffer
,
2998 bufferSize
, options
, segflg
, NULL
, NOCRED
);
3000 /* Retain the namei reference until the getattrlist completes. */
3007 getattrlist(proc_t p
, struct getattrlist_args
*uap
, __unused
int32_t *retval
)
3009 enum uio_seg segflg
;
3013 segflg
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3016 * Fetch the attribute request.
3018 error
= copyin(uap
->alist
, &al
, sizeof(al
));
3022 return (getattrlistat_internal(vfs_context_current(),
3023 CAST_USER_ADDR_T(uap
->path
), &al
,
3024 CAST_USER_ADDR_T(uap
->attributeBuffer
), uap
->bufferSize
,
3025 (uint64_t)uap
->options
, segflg
, segflg
, AT_FDCWD
));
3029 getattrlistat(proc_t p
, struct getattrlistat_args
*uap
, __unused
int32_t *retval
)
3031 enum uio_seg segflg
;
3035 segflg
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3038 * Fetch the attribute request.
3040 error
= copyin(uap
->alist
, &al
, sizeof(al
));
3044 return (getattrlistat_internal(vfs_context_current(),
3045 CAST_USER_ADDR_T(uap
->path
), &al
,
3046 CAST_USER_ADDR_T(uap
->attributeBuffer
), uap
->bufferSize
,
3047 (uint64_t)uap
->options
, segflg
, segflg
, uap
->fd
));
3051 * This refills the per-fd direntries cache by issuing a VNOP_READDIR.
3052 * It attempts to try and find a size the filesystem responds to, so
3053 * it first tries 1 direntry sized buffer and going from 1 to 2 to 4
3054 * direntry sized buffers to readdir. If the filesystem does not respond
3055 * to 4 * direntry it returns the error by the filesystem (if any) and sets
3058 * This function also tries again if the last "refill" returned an EOF
3059 * to try and get any additional entries if they were added after the last
3063 refill_fd_direntries(vfs_context_t ctx
, vnode_t dvp
, struct fd_vn_data
*fvd
,
3067 char uio_buf
[UIO_SIZEOF(1)];
3075 * If the last readdir returned EOF, don't try again.
3077 if (fvd
->fv_eofflag
) {
3080 FREE(fvd
->fv_buf
, M_FD_DIRBUF
);
3089 * If there is a cached allocation size of the dirbuf that should be
3090 * allocated, use that. Otherwise start with a allocation size of
3091 * FV_DIRBUF_START_SIZ. This start size may need to be increased if the
3092 * filesystem doesn't respond to the initial size.
3095 if (fvd
->fv_offset
&& fvd
->fv_bufallocsiz
) {
3096 rdirbufsiz
= fvd
->fv_bufallocsiz
;
3098 rdirbufsiz
= FV_DIRBUF_START_SIZ
;
3103 rdir_uio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3104 &uio_buf
[0], sizeof(uio_buf
));
3108 * Don't explicitly zero out this buffer since this is
3109 * not copied out to user space.
3112 MALLOC(fvd
->fv_buf
, caddr_t
, rdirbufsiz
, M_FD_DIRBUF
, M_WAITOK
);
3113 fvd
->fv_bufdone
= 0;
3116 uio_reset(rdir_uio
, fvd
->fv_eoff
, UIO_SYSSPACE
, UIO_READ
);
3117 uio_addiov(rdir_uio
, CAST_USER_ADDR_T(fvd
->fv_buf
), rdirbufsiz
);
3120 * Some filesystems do not set nentries or eofflag...
3124 error
= vnode_readdir64(dvp
, rdir_uio
, VNODE_READDIR_EXTENDED
,
3125 &eofflag
, &nentries
, ctx
);
3127 rdirbufused
= rdirbufsiz
- (size_t)uio_resid(rdir_uio
);
3129 if (!error
&& (rdirbufused
> 0) && (rdirbufused
<= rdirbufsiz
)) {
3131 fvd
->fv_soff
= fvd
->fv_eoff
;
3132 fvd
->fv_eoff
= uio_offset(rdir_uio
);
3133 /* Save eofflag state but don't return EOF for this time.*/
3134 fvd
->fv_eofflag
= eofflag
;
3136 /* Reset buffer parameters */
3137 fvd
->fv_bufsiz
= rdirbufused
;
3138 fvd
->fv_bufdone
= 0;
3139 bzero(fvd
->fv_buf
+ rdirbufused
, rdirbufsiz
- rdirbufused
);
3140 /* Cache allocation size the Filesystem responded to */
3141 fvd
->fv_bufallocsiz
= rdirbufsiz
;
3142 } else if (!eofflag
&& (rdirbufsiz
< FV_DIRBUF_MAX_SIZ
)) {
3144 * Some Filesystems have higher requirements for the
3145 * smallest buffer size they will respond to for a
3146 * directory listing. Start (relatively) small but increase
3147 * it upto FV_DIRBUF_MAX_SIZ. Most should be good with
3148 * 1*direntry. Cache the size found so that this does not need
3149 * need to be done every time. This also means that an error
3150 * from VNOP_READDIR is ignored until at least FV_DIRBUF_MAX_SIZ
3151 * has been attempted.
3153 FREE(fvd
->fv_buf
, M_FD_DIRBUF
);
3155 rdirbufsiz
= 2 * rdirbufsiz
;
3156 fvd
->fv_bufallocsiz
= 0;
3158 } else if (!error
) {
3160 * The Filesystem did not set eofflag but also did not
3161 * return any entries (or an error). It is presumed that
3162 * EOF has been reached.
3164 fvd
->fv_eofflag
= eofflag
= 1;
3168 * If the filesystem returned an error and it had previously returned
3169 * EOF, ignore the error and set EOF.
3171 if (error
&& fvd
->fv_eofflag
) {
3177 * If either the directory has either hit EOF or an error, now is a good
3178 * time to free up directory entry buffer.
3180 if ((error
|| eofflag
) && fvd
->fv_buf
) {
3181 FREE(fvd
->fv_buf
, M_FD_DIRBUF
);
3185 *eofflagp
= eofflag
;
3191 * gets the current direntry. To advance to the next direntry this has to be
3192 * paired with a direntry_done.
3194 * Since directories have restrictions on where directory enumeration
3195 * can restart from, entries are first read into* a per fd diectory entry
3196 * "cache" and entries provided from that cache.
3199 get_direntry(vfs_context_t ctx
, vnode_t dvp
, struct fd_vn_data
*fvd
,
3200 int *eofflagp
, struct direntry
**dpp
)
3208 if (!fvd
->fv_bufsiz
) {
3209 error
= refill_fd_direntries(ctx
, dvp
, fvd
, &eofflag
);
3214 *eofflagp
= eofflag
;
3219 *dpp
= (struct direntry
*)(fvd
->fv_buf
+ fvd
->fv_bufdone
);
3224 * Advances to the next direntry.
3227 direntry_done(struct fd_vn_data
*fvd
)
3229 struct direntry
*dp
;
3231 dp
= (struct direntry
*)(fvd
->fv_buf
+ fvd
->fv_bufdone
);
3233 fvd
->fv_bufdone
+= dp
->d_reclen
;
3234 if (fvd
->fv_bufdone
> fvd
->fv_bufsiz
) {
3235 fvd
->fv_bufdone
= fvd
->fv_bufsiz
;
3238 fvd
->fv_bufdone
= fvd
->fv_bufsiz
;
3242 * If we're at the end the fd direntries cache, reset the
3245 if (fvd
->fv_bufdone
== fvd
->fv_bufsiz
) {
3246 fvd
->fv_bufdone
= 0;
3252 * A stripped down version of getattrlist_internal to fill in only select
3253 * attributes in case of an error from getattrlist_internal.
3255 * It always returns at least ATTR_BULK_REQUIRED i.e. the name (but may also
3256 * return some other attributes which can be obtained from the vnode).
3258 * It does not change the value of the passed in attrlist.
3260 * The objective of this function is to fill in an "error entry", i.e.
3261 * an entry with ATTR_CMN_RETURNED_ATTRS & ATTR_CMN_NAME. If the caller
3262 * has also asked for ATTR_CMN_ERROR, it is filled in as well.
3265 * vp - vnode pointer
3266 * alp - pointer to attrlist struct.
3267 * options - options passed to getattrlistbulk(2)
3268 * kern_attr_buf - Kernel buffer to fill data (assumes offset 0 in
3270 * kern_attr_buf_siz - Size of buffer.
3271 * needs_error_attr - Whether the caller asked for ATTR_CMN_ERROR
3272 * error_attr - This value is used to fill ATTR_CMN_ERROR (if the user
3273 * has requested it in the attribute list.
3274 * namebuf - This is used to fill in the name.
3275 * ctx - vfs context of caller.
3278 get_error_attributes(vnode_t vp
, struct attrlist
*alp
, uint64_t options
,
3279 user_addr_t kern_attr_buf
, size_t kern_attr_buf_siz
, int error_attr
,
3280 caddr_t namebuf
, vfs_context_t ctx
)
3283 struct _attrlist_buf ab
;
3285 kauth_action_t action
;
3287 int needs_error_attr
= (alp
->commonattr
& ATTR_CMN_ERROR
);
3290 * To calculate fixed size required, in the FSOPT_PACK_INVAL_ATTRS case,
3291 * the fixedsize should include space for all the attributes asked by
3292 * the user. Only ATTR_BULK_REQUIRED (and ATTR_CMN_ERROR) will be filled
3293 * and will be valid. All other attributes are zeroed out later.
3295 * ATTR_CMN_RETURNED_ATTRS, ATTR_CMN_ERROR and ATTR_CMN_NAME
3296 * (the only valid ones being returned from here) happen to be
3297 * the first three attributes by order as well.
3300 if (!(options
& FSOPT_PACK_INVAL_ATTRS
)) {
3302 * In this case the fixedsize only needs to be only for the
3303 * attributes being actually returned.
3305 al
.commonattr
= ATTR_BULK_REQUIRED
;
3306 if (needs_error_attr
) {
3307 al
.commonattr
|= ATTR_CMN_ERROR
;
3314 * Passing NULL for the vnode_attr pointer is valid for
3315 * getattrlist_setupvattr. All that is required is the size.
3318 (void)getattrlist_setupvattr(&al
, NULL
, (ssize_t
*)&fsiz
,
3319 &action
, proc_is64bit(vfs_context_proc(ctx
)),
3320 (vnode_vtype(vp
) == VDIR
), (options
& FSOPT_ATTR_CMN_EXTENDED
));
3322 namelen
= strlen(namebuf
);
3324 vsiz
= ((vsiz
+ 3) & ~0x03);
3326 bzero(&ab
, sizeof(ab
));
3327 ab
.base
= (char *)kern_attr_buf
;
3328 ab
.needed
= fsiz
+ vsiz
;
3330 /* Fill in the size needed */
3331 *((uint32_t *)ab
.base
) = ab
.needed
;
3332 if (ab
.needed
> (ssize_t
)kern_attr_buf_siz
) {
3337 * Setup to pack results into the destination buffer.
3339 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
3341 * Zero out buffer, ab.fixedbuffer starts after the first uint32_t
3342 * which gives the length. This ensures everything that we don't
3343 * fill in explicitly later is zeroed out correctly.
3345 bzero(ab
.fixedcursor
, fsiz
);
3347 * variable size data should start after all the fixed
3350 ab
.varcursor
= ab
.base
+ fsiz
;
3352 * Initialise the value for ATTR_CMN_RETURNED_ATTRS and leave space
3353 * Leave space for filling in its value here at the end.
3355 bzero(&ab
.actual
, sizeof (ab
.actual
));
3356 ab
.fixedcursor
+= sizeof (attribute_set_t
);
3358 ab
.allocated
= ab
.needed
;
3360 /* Fill ATTR_CMN_ERROR (if asked for) */
3361 if (needs_error_attr
) {
3362 ATTR_PACK4(ab
, error_attr
);
3363 ab
.actual
.commonattr
|= ATTR_CMN_ERROR
;
3367 * Fill ATTR_CMN_NAME, The attrrefrence is packed at this location
3368 * but the actual string itself is packed after fixedsize which set
3369 * to different lengths based on whether FSOPT_PACK_INVAL_ATTRS
3372 attrlist_pack_string(&ab
, namebuf
, namelen
);
3375 * Now Fill in ATTR_CMN_RETURNED_ATTR. This copies to a
3376 * location after the count i.e. before ATTR_CMN_ERROR and
3379 ab
.actual
.commonattr
|= ATTR_CMN_NAME
| ATTR_CMN_RETURNED_ATTRS
;
3380 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
3386 * This is the buffer size required to return at least 1 entry. We need space
3387 * for the length, for ATTR_CMN_RETURNED_ATTRS and ATTR_CMN_NAME. Assuming the
3388 * smallest filename of a single byte we get
3391 #define MIN_BUF_SIZE_REQUIRED (sizeof(uint32_t) + sizeof(attribute_set_t) +\
3392 sizeof(attrreference_t))
3395 * Read directory entries and get attributes filled in for each directory
3398 readdirattr(vnode_t dvp
, struct fd_vn_data
*fvd
, uio_t auio
,
3399 struct attrlist
*alp
, uint64_t options
, int *count
, int *eofflagp
,
3402 caddr_t kern_attr_buf
;
3403 size_t kern_attr_buf_siz
;
3404 caddr_t max_path_name_buf
= NULL
;
3410 if (uio_iovcnt(auio
) > 1) {
3415 * We fill in a kernel buffer for the attributes and uiomove each
3416 * entry's attributes (as returned by getattrlist_internal)
3418 kern_attr_buf_siz
= uio_resid(auio
);
3419 if (kern_attr_buf_siz
> ATTR_MAX_BUFFER
) {
3420 kern_attr_buf_siz
= ATTR_MAX_BUFFER
;
3421 } else if (kern_attr_buf_siz
== 0) {
3426 MALLOC(kern_attr_buf
, caddr_t
, kern_attr_buf_siz
, M_TEMP
, M_WAITOK
);
3428 while (uio_resid(auio
) > (user_ssize_t
)MIN_BUF_SIZE_REQUIRED
) {
3429 struct direntry
*dp
;
3430 user_addr_t name_buffer
;
3431 struct nameidata nd
;
3440 * get_direntry returns the current direntry and does not
3441 * advance. A move to the next direntry only happens if
3442 * direntry_done is called.
3444 error
= get_direntry(ctx
, dvp
, fvd
, eofflagp
, &dp
);
3445 if (error
|| (*eofflagp
) || !dp
) {
3450 * skip "." and ".." (and a bunch of other invalid conditions.)
3452 if (!dp
->d_reclen
|| dp
->d_ino
== 0 || dp
->d_namlen
== 0 ||
3453 (dp
->d_namlen
== 1 && dp
->d_name
[0] == '.') ||
3454 (dp
->d_namlen
== 2 && dp
->d_name
[0] == '.' &&
3455 dp
->d_name
[1] == '.')) {
3461 * try to deal with not-null terminated filenames.
3463 if (dp
->d_name
[dp
->d_namlen
] != '\0') {
3464 if (!max_path_name_buf
) {
3465 MALLOC(max_path_name_buf
, caddr_t
, MAXPATHLEN
,
3468 bcopy(dp
->d_name
, max_path_name_buf
, dp
->d_namlen
);
3469 max_path_name_buf
[dp
->d_namlen
] = '\0';
3470 name_buffer
= CAST_USER_ADDR_T(max_path_name_buf
);
3472 name_buffer
= CAST_USER_ADDR_T(&(dp
->d_name
));
3476 * We have an iocount on the directory already.
3478 * Note that we supply NOCROSSMOUNT to the namei call as we attempt to acquire
3479 * a vnode for this particular entry. This is because the native call will
3480 * (likely) attempt to emit attributes based on its own metadata in order to avoid
3481 * creating vnodes where posssible. If the native call is not going to walk
3482 * up the vnode mounted-on chain in order to find the top-most mount point, then we
3483 * should not either in this emulated readdir+getattrlist() approach. We
3484 * will be responsible for setting DIR_MNTSTATUS_MNTPOINT on that directory that
3485 * contains a mount point.
3487 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, (AUDITVNPATH1
| USEDVP
| NOCROSSMOUNT
),
3488 UIO_SYSSPACE
, CAST_USER_ADDR_T(name_buffer
), ctx
);
3502 * getattrlist_internal can change the values of the
3503 * the required attribute list. Copy the current values
3504 * and use that one instead.
3508 error
= getattrlist_internal(ctx
, vp
, &al
,
3509 CAST_USER_ADDR_T(kern_attr_buf
), kern_attr_buf_siz
,
3510 options
| FSOPT_REPORT_FULLSIZE
, UIO_SYSSPACE
,
3511 CAST_DOWN_EXPLICIT(char *, name_buffer
),
3517 get_error_attributes(vp
, alp
, options
,
3518 CAST_USER_ADDR_T(kern_attr_buf
),
3519 kern_attr_buf_siz
, error
, (caddr_t
)name_buffer
,
3524 /* Done with vnode now */
3528 * Because FSOPT_REPORT_FULLSIZE was set, the first 4 bytes
3529 * of the buffer returned by getattrlist contains the size
3530 * (even if the provided buffer isn't sufficiently big). Use
3531 * that to check if we've run out of buffer space.
3533 * resid is a signed type, and the size of the buffer etc
3534 * are unsigned types. It is theoretically possible for
3535 * resid to be < 0 and in which case we would be assigning
3536 * an out of bounds value to bytes_left (which is unsigned)
3537 * uiomove takes care to not ever set resid to < 0, so it
3538 * is safe to do this here.
3540 bytes_left
= (size_t)((user_size_t
)uio_resid(auio
));
3541 entlen
= (size_t)(*((uint32_t *)(kern_attr_buf
)));
3542 if (!entlen
|| (entlen
> bytes_left
)) {
3547 * Will the pad bytes fit as well ? If they can't be, still use
3548 * this entry but this will be the last entry returned.
3550 pad_bytes
= ((entlen
+ 7) & ~0x07) - entlen
;
3552 if (pad_bytes
&& (entlen
+ pad_bytes
<= bytes_left
)) {
3554 * While entlen can never be > ATTR_MAX_BUFFER,
3555 * (entlen + pad_bytes) can be, handle that and
3556 * zero out the pad bytes. N.B. - Only zero
3557 * out information in the kernel buffer that is
3558 * going to be uiomove'ed out.
3560 if (entlen
+ pad_bytes
<= kern_attr_buf_siz
) {
3561 /* This is the normal case. */
3562 bzero(kern_attr_buf
+ entlen
, pad_bytes
);
3564 bzero(kern_attr_buf
+ entlen
,
3565 kern_attr_buf_siz
- entlen
);
3567 * Pad bytes left over, change the resid value
3568 * manually. We only got in here because
3569 * bytes_left >= entlen + pad_bytes so
3570 * new_resid (which is a signed type) is
3573 new_resid
= (ssize_t
)(bytes_left
-
3574 (entlen
+ pad_bytes
));
3576 entlen
+= pad_bytes
;
3578 *((uint32_t *)kern_attr_buf
) = (uint32_t)entlen
;
3579 error
= uiomove(kern_attr_buf
, min(entlen
, kern_attr_buf_siz
),
3587 uio_setresid(auio
, (user_ssize_t
)new_resid
);
3591 * At this point, the directory entry has been consumed, proceed
3598 if (max_path_name_buf
) {
3599 FREE(max_path_name_buf
, M_TEMP
);
3603 * At this point, kern_attr_buf is always allocated
3605 FREE(kern_attr_buf
, M_TEMP
);
3608 * Always set the offset to the last succesful offset
3609 * returned by VNOP_READDIR.
3611 uio_setoffset(auio
, fvd
->fv_eoff
);
3617 *int getattrlistbulk(int dirfd, struct attrlist *alist, void *attributeBuffer,
3618 * size_t bufferSize, uint64_t options)
3620 * Gets directory entries alongwith their attributes in the same way
3621 * getattrlist does for a single file system object.
3623 * On non error returns, retval will hold the count of entries returned.
3626 getattrlistbulk(proc_t p
, struct getattrlistbulk_args
*uap
, int32_t *retval
)
3630 struct fileproc
*fp
;
3631 struct fd_vn_data
*fvdata
;
3633 enum uio_seg segflg
;
3636 char uio_buf
[ UIO_SIZEOF(1) ];
3637 kauth_action_t action
;
3644 error
= fp_getfvp(p
, uap
->dirfd
, &fp
, &dvp
);
3651 ctx
= vfs_context_current();
3652 segflg
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3654 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
3656 AUDIT_ARG(vnpath_withref, dvp, ARG_VNODE1);
3662 if ((error
= vnode_getwithref(dvp
))) {
3667 if (uap
->options
& FSOPT_LIST_SNAPSHOT
) {
3670 if (!vfs_context_issuser(ctx
)) {
3675 if (!vnode_isvroot(dvp
)) {
3680 /* switch directory to snapshot directory */
3681 error
= vnode_get_snapdir(dvp
, &snapdvp
, ctx
);
3688 if (dvp
->v_type
!= VDIR
) {
3694 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
3700 * XXX : Audit Support
3701 *AUDIT_ARG(vnpath, dvp, ARG_VNODE1);
3704 options
= uap
->options
| FSOPT_ATTR_CMN_EXTENDED
;
3706 if ((error
= copyin(CAST_USER_ADDR_T(uap
->alist
), &al
,
3707 sizeof(struct attrlist
)))) {
3712 ((al
.commonattr
& ATTR_BULK_REQUIRED
) != ATTR_BULK_REQUIRED
)) {
3718 error
= mac_vnode_check_readdir(ctx
, dvp
);
3725 * If the only item requested is file names, we can let that past with
3726 * just LIST_DIRECTORY. If they want any other attributes, that means
3727 * they need SEARCH as well.
3729 action
= KAUTH_VNODE_LIST_DIRECTORY
;
3730 if ((al
.commonattr
& ~ATTR_CMN_NAME
) || al
.fileattr
|| al
.dirattr
)
3731 action
|= KAUTH_VNODE_SEARCH
;
3733 error
= vnode_authorize(dvp
, NULL
, action
, ctx
);
3738 fvdata
= (struct fd_vn_data
*)fp
->f_fglob
->fg_vn_data
;
3740 panic("Directory expected to have fg_vn_data");
3746 * getattrlistbulk(2) maintains its offset in fv_offset. However
3747 * if the offset in the file glob is set (or reset) to 0, the directory
3748 * traversal needs to be restarted (Any existing state in the
3749 * directory buffer is removed as well).
3751 if (!fp
->f_fglob
->fg_offset
) {
3752 fvdata
->fv_offset
= 0;
3754 FREE(fvdata
->fv_buf
, M_FD_DIRBUF
);
3755 fvdata
->fv_buf
= NULL
;
3756 fvdata
->fv_bufsiz
= 0;
3757 fvdata
->fv_bufdone
= 0;
3758 fvdata
->fv_soff
= 0;
3759 fvdata
->fv_eoff
= 0;
3760 fvdata
->fv_eofflag
= 0;
3763 auio
= uio_createwithbuffer(1, fvdata
->fv_offset
, segflg
, UIO_READ
,
3764 &uio_buf
[0], sizeof(uio_buf
));
3765 uio_addiov(auio
, uap
->attributeBuffer
, (user_size_t
)uap
->bufferSize
);
3768 * For "expensive" operations in which the native VNOP implementations
3769 * end up having to do just as much (if not more) work than the default
3770 * implementation, fall back to the default implementation.
3771 * The VNOP helper functions depend on the filesystem providing the
3772 * object type, if the caller has not requested ATTR_CMN_OBJTYPE, fall
3773 * back to the default implementation.
3775 if ((al
.commonattr
&
3776 (ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
| ATTR_CMN_EXTENDED_SECURITY
)) ||
3777 !(al
.commonattr
& ATTR_CMN_OBJTYPE
)) {
3780 struct vnode_attr va
;
3783 if (fvdata
->fv_eofflag
&& !fvdata
->fv_buf
) {
3785 * If the last successful VNOP_GETATTRLISTBULK or
3786 * VNOP_READDIR returned EOF, don't try again.
3796 MALLOC(va_name
, char *, MAXPATHLEN
, M_TEMP
,
3798 va
.va_name
= va_name
;
3800 (void)getattrlist_setupvattr_all(&al
, &va
, VNON
, NULL
,
3801 IS_64BIT_PROCESS(p
), (uap
->options
& FSOPT_ATTR_CMN_EXTENDED
));
3803 error
= VNOP_GETATTRLISTBULK(dvp
, &al
, &va
, auio
, NULL
,
3804 options
, &eofflag
, &count
, ctx
);
3806 FREE(va_name
, M_TEMP
);
3809 * cache state of eofflag.
3812 fvdata
->fv_eofflag
= eofflag
;
3818 * If the Filessytem does not natively support getattrlistbulk,
3819 * do the default implementation.
3821 if (error
== ENOTSUP
) {
3825 error
= readdirattr(dvp
, fvdata
, auio
, &al
, options
,
3826 &count
, &eofflag
, ctx
);
3830 fvdata
->fv_offset
= uio_offset(auio
);
3831 fp
->f_fglob
->fg_offset
= fvdata
->fv_offset
;
3834 } else if (!error
&& !eofflag
) {
3836 * This just means the buffer was too small to fit even a
3848 file_drop(uap
->dirfd
);
3854 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
3856 /* make sure we have enough source data */
3857 if ((*cursor
) + size
> end
)
3860 bcopy(*cursor
, buf
, size
);
3865 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
3866 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
3867 #define ATTR_UNPACK_TIME(v, is64) \
3870 struct user64_timespec us; \
3872 v.tv_sec = us.tv_sec; \
3873 v.tv_nsec = us.tv_nsec; \
3875 struct user32_timespec us; \
3877 v.tv_sec = us.tv_sec; \
3878 v.tv_nsec = us.tv_nsec; \
3887 setattrlist_internal(vnode_t vp
, struct setattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
3890 struct vnode_attr va
;
3891 struct attrreference ar
;
3892 kauth_action_t action
;
3893 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
3894 int proc_is64
, error
;
3896 kauth_filesec_t rfsec
;
3902 proc_is64
= proc_is64bit(p
);
3906 * Fetch the attribute set and validate.
3908 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
3910 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
3915 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
3916 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
3917 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
3920 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
3921 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
3925 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
3929 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
3930 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
3931 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
3932 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
3934 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
3940 * If the caller's bitmaps indicate that there are no attributes to set,
3941 * then exit early. In particular, we want to avoid the MALLOC below
3942 * since the caller's bufferSize could be zero, and MALLOC of zero bytes
3943 * returns a NULL pointer, which would cause setattrlist to return ENOMEM.
3945 if (al
.commonattr
== 0 &&
3946 (al
.volattr
& ~ATTR_VOL_INFO
) == 0 &&
3955 * Make the naive assumption that the caller has supplied a reasonable buffer
3956 * size. We could be more careful by pulling in the fixed-size region, checking
3957 * the attrref structures, then pulling in the variable section.
3958 * We need to reconsider this for handling large ACLs, as they should probably be
3959 * brought directly into a buffer. Multiple copyins will make this slower though.
3961 * We could also map the user buffer if it is larger than some sensible mimimum.
3963 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
3964 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
3968 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
3969 if (user_buf
== NULL
) {
3970 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
3974 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
3975 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
3978 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
3981 error
= mac_vnode_check_setattrlist(ctx
, vp
, &al
);
3987 * Unpack the argument buffer.
3990 bufend
= cursor
+ uap
->bufferSize
;
3993 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
3994 ATTR_UNPACK(va
.va_encoding
);
3995 VATTR_SET_ACTIVE(&va
, va_encoding
);
3997 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
3998 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
3999 VATTR_SET_ACTIVE(&va
, va_create_time
);
4001 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
4002 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
4003 VATTR_SET_ACTIVE(&va
, va_modify_time
);
4005 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
4006 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
4007 al
.commonattr
&= ~ATTR_CMN_CHGTIME
;
4008 /*quietly ignore change time; advisory in man page*/
4010 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
4011 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
4012 VATTR_SET_ACTIVE(&va
, va_access_time
);
4014 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
4015 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
4016 VATTR_SET_ACTIVE(&va
, va_backup_time
);
4018 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
4019 if ((cursor
+ 32) > bufend
) {
4021 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
4027 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
4028 ATTR_UNPACK(va
.va_uid
);
4029 VATTR_SET_ACTIVE(&va
, va_uid
);
4031 if (al
.commonattr
& ATTR_CMN_GRPID
) {
4032 ATTR_UNPACK(va
.va_gid
);
4033 VATTR_SET_ACTIVE(&va
, va_gid
);
4035 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
4036 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
4037 VATTR_SET_ACTIVE(&va
, va_mode
);
4039 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
4040 ATTR_UNPACK(va
.va_flags
);
4041 VATTR_SET_ACTIVE(&va
, va_flags
);
4043 if ((error
= mac_vnode_check_setflags(ctx
, vp
, va
.va_flags
)) != 0)
4047 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
4050 * We are (for now) passed a kauth_filesec_t, but all we want from
4055 if (ar
.attr_dataoffset
< 0) {
4056 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied", ar
.attr_dataoffset
);
4061 cp
+= ar
.attr_dataoffset
;
4062 rfsec
= (kauth_filesec_t
)cp
;
4063 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) || /* no space for acl */
4064 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
4065 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
4066 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
4068 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
4071 nace
= rfsec
->fsec_entrycount
;
4072 if (nace
== KAUTH_FILESEC_NOACL
)
4074 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
4076 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
4079 nace
= rfsec
->fsec_acl
.acl_entrycount
;
4080 if (nace
== KAUTH_FILESEC_NOACL
) {
4082 VATTR_SET(&va
, va_acl
, NULL
);
4085 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
4087 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
4090 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
4093 if (al
.commonattr
& ATTR_CMN_UUID
) {
4094 ATTR_UNPACK(va
.va_uuuid
);
4095 VATTR_SET_ACTIVE(&va
, va_uuuid
);
4097 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
4098 ATTR_UNPACK(va
.va_guuid
);
4099 VATTR_SET_ACTIVE(&va
, va_guuid
);
4101 /* Support setattrlist of data protection class */
4102 if (al
.commonattr
& ATTR_CMN_DATA_PROTECT_FLAGS
) {
4103 ATTR_UNPACK(va
.va_dataprotect_class
);
4104 VATTR_SET_ACTIVE(&va
, va_dataprotect_class
);
4108 if (al
.volattr
& ATTR_VOL_INFO
) {
4109 if (al
.volattr
& ATTR_VOL_NAME
) {
4112 /* attr_length cannot be 0! */
4113 if ((ar
.attr_dataoffset
< 0) || (ar
.attr_length
== 0) ||
4114 (ar
.attr_length
> uap
->bufferSize
) ||
4115 (uap
->bufferSize
- ar
.attr_length
< (unsigned)ar
.attr_dataoffset
)) {
4116 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied (2) ", ar
.attr_dataoffset
);
4121 if (volname
>= bufend
- ar
.attr_dataoffset
- ar
.attr_length
) {
4123 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
4126 volname
+= ar
.attr_dataoffset
;
4127 /* guarantee NUL termination */
4128 volname
[ar
.attr_length
- 1] = 0;
4133 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
4134 /* XXX does it actually make any sense to change this? */
4136 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
4141 * Validate and authorize.
4144 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) {
4145 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
4149 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
4150 * and will be auth'ed by the FS.
4152 if (fndrinfo
!= NULL
) {
4153 if (al
.volattr
& ATTR_VOL_INFO
) {
4154 if (vp
->v_tag
!= VT_HFS
) {
4159 action
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
4163 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4164 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
4169 * When we're setting both the access mask and the finder info, then
4170 * check if were about to remove write access for the owner. Since
4171 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
4172 * to consider their ordering.
4174 * If were about to remove write access for the owner we'll set the
4175 * Finder Info here before vnode_setattr. Otherwise we'll set it
4176 * after vnode_setattr since it may be adding owner write access.
4178 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
4179 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
4180 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
4183 fndrinfo
= NULL
; /* it was set here so skip setting below */
4187 * Write the attributes if we have any.
4189 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, ctx
)) != 0)) {
4190 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
4195 mac_vnode_notify_setattrlist(ctx
, vp
, &al
);
4196 if (VATTR_IS_ACTIVE(&va
, va_flags
))
4197 mac_vnode_notify_setflags(ctx
, vp
, va
.va_flags
);
4201 * Write the Finder Info if we have any.
4203 if (fndrinfo
!= NULL
) {
4204 if (al
.volattr
& ATTR_VOL_INFO
) {
4205 if (vp
->v_tag
== VT_HFS
) {
4206 #define HFS_SET_BOOT_INFO (FCNTL_FS_SPECIFIC_BASE + 0x00005)
4207 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
);
4211 /* XXX should never get here */
4213 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
4219 * Set the volume name, if we have one
4221 if (volname
!= NULL
)
4227 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
4228 VFSATTR_WANTED(&vs
, f_vol_name
);
4231 error
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
);
4236 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
4237 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
4241 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
4243 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
4248 /* all done and successful */
4251 if (user_buf
!= NULL
)
4252 FREE(user_buf
, M_TEMP
);
4253 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);
4258 setattrlist(proc_t p
, struct setattrlist_args
*uap
, __unused
int32_t *retval
)
4260 struct vfs_context
*ctx
;
4261 struct nameidata nd
;
4266 ctx
= vfs_context_current();
4271 nameiflags
= AUDITVNPATH1
;
4272 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
4273 nameiflags
|= FOLLOW
;
4274 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
4275 if ((error
= namei(&nd
)) != 0)
4280 error
= setattrlist_internal(vp
, uap
, p
, ctx
);
4288 fsetattrlist(proc_t p
, struct fsetattrlist_args
*uap
, __unused
int32_t *retval
)
4290 struct vfs_context
*ctx
;
4293 struct setattrlist_args ap
;
4295 ctx
= vfs_context_current();
4297 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
4300 if ((error
= vnode_getwithref(vp
)) != 0) {
4306 ap
.alist
= uap
->alist
;
4307 ap
.attributeBuffer
= uap
->attributeBuffer
;
4308 ap
.bufferSize
= uap
->bufferSize
;
4309 ap
.options
= uap
->options
;
4311 error
= setattrlist_internal(vp
, &ap
, p
, ctx
);