2 * Copyright (c) 1995-2012 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/vnode_internal.h>
41 #include <sys/mount_internal.h>
42 #include <sys/proc_internal.h>
43 #include <sys/kauth.h>
44 #include <sys/uio_internal.h>
45 #include <sys/malloc.h>
47 #include <sys/sysproto.h>
48 #include <sys/xattr.h>
49 #include <sys/fsevents.h>
50 #include <kern/kalloc.h>
51 #include <miscfs/specfs/specdev.h>
55 #include <security/mac_framework.h>
58 #define ATTR_TIME_SIZE -1
61 * Structure describing the state of an in-progress attrlist operation.
63 struct _attrlist_buf
{
69 attribute_set_t actual
;
70 attribute_set_t valid
;
75 * Attempt to pack a fixed width attribute of size (count) bytes from
76 * source to our attrlist buffer.
79 attrlist_pack_fixed(struct _attrlist_buf
*ab
, void *source
, ssize_t count
)
82 * Use ssize_t for pointer math purposes,
83 * since a ssize_t is a signed long
88 * Compute the amount of remaining space in the attrlist buffer
89 * based on how much we've used for fixed width fields vs. the
90 * start of the attributes.
92 * If we've still got room, then 'fit' will contain the amount of
95 * Note that this math is safe because, in the event that the
96 * fixed-width cursor has moved beyond the end of the buffer,
97 * then, the second input into lmin() below will be negative, and
98 * we will fail the (fit > 0) check below.
100 fit
= lmin(count
, ab
->allocated
- (ab
->fixedcursor
- ab
->base
));
102 /* Copy in as much as we can */
103 bcopy(source
, ab
->fixedcursor
, fit
);
106 /* always move in increments of 4, even if we didn't pack an attribute. */
107 ab
->fixedcursor
+= roundup(count
, 4);
111 * Attempt to pack one (or two) variable width attributes into the attrlist
112 * buffer. If we are trying to pack two variable width attributes, they are treated
113 * as a single variable-width attribute from the POV of the system call caller.
115 * Recall that a variable-width attribute has two components: the fixed-width
116 * attribute that tells the caller where to look, and the actual variable width data.
119 attrlist_pack_variable2(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
,
120 const void *ext
, ssize_t extcount
) {
122 /* Use ssize_t's for pointer math ease */
123 struct attrreference ar
;
127 * Pack the fixed-width component to the variable object.
128 * Note that we may be able to pack the fixed width attref, but not
129 * the variable (if there's no room).
131 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
132 ar
.attr_length
= count
+ extcount
;
133 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
136 * Use an lmin() to do a signed comparison. We use a signed comparison
137 * to detect the 'out of memory' conditions as described above in the
138 * fixed width check above.
140 * Then pack the first variable attribute as space allows. Note that we advance
141 * the variable cursor only if we we had some available space.
143 fit
= lmin(count
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
145 if (source
!= NULL
) {
146 bcopy(source
, ab
->varcursor
, fit
);
148 ab
->varcursor
+= fit
;
151 /* Compute the available space for the second attribute */
152 fit
= lmin(extcount
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
154 /* Copy in data for the second attribute (if needed) if there is room */
156 bcopy(ext
, ab
->varcursor
, fit
);
158 ab
->varcursor
+= fit
;
160 /* always move in increments of 4 */
161 ab
->varcursor
= (char *)roundup((uintptr_t)ab
->varcursor
, 4);
165 * Packing a single variable-width attribute is the same as calling the two, but with
166 * an invalid 2nd attribute.
169 attrlist_pack_variable(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
)
171 attrlist_pack_variable2(ab
, source
, count
, NULL
, 0);
175 * Attempt to pack a string. This is a special case of a variable width attribute.
177 * If "source" is NULL, then an empty string ("") will be packed. If "source" is
178 * not NULL, but "count" is zero, then "source" is assumed to be a NUL-terminated
179 * C-string. If "source" is not NULL and "count" is not zero, then only the first
180 * "count" bytes of "source" will be copied, and a NUL terminator will be added.
182 * If the attrlist buffer doesn't have enough room to hold the entire string (including
183 * NUL terminator), then copy as much as will fit. The attrlist buffer's "varcursor"
184 * will always be updated based on the entire length of the string (including NUL
185 * terminator); this means "varcursor" may end up pointing beyond the end of the
186 * allocated buffer space.
189 attrlist_pack_string(struct _attrlist_buf
*ab
, const char *source
, ssize_t count
)
191 struct attrreference ar
;
195 * Supplied count is character count of string text, excluding trailing nul
196 * which we always supply here.
198 if (source
== NULL
) {
200 } else if (count
== 0) {
201 count
= strlen(source
);
205 * Construct the fixed-width attribute that refers to this string.
207 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
208 ar
.attr_length
= count
+ 1;
209 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
212 * Now compute how much available memory we have to copy the string text.
214 * space = the number of bytes available in the attribute buffer to hold the
217 * fit = the number of bytes to copy from the start of the string into the
218 * attribute buffer, NOT including the NUL terminator. If the attribute
219 * buffer is large enough, this will be the string's length; otherwise, it
220 * will be equal to "space".
222 space
= ab
->allocated
- (ab
->varcursor
- ab
->base
);
223 fit
= lmin(count
, space
);
226 * If there is space remaining, copy data in, and
227 * accommodate the trailing NUL terminator.
229 * NOTE: if "space" is too small to hold the string and its NUL
230 * terminator (space < fit + 1), then the string value in the attribute
231 * buffer will NOT be NUL terminated!
233 * NOTE 2: bcopy() will do nothing if the length ("fit") is zero.
234 * Therefore, we don't bother checking for that here.
236 bcopy(source
, ab
->varcursor
, fit
);
237 /* is there room for our trailing nul? */
239 ab
->varcursor
[fit
++] = '\0';
240 /* 'fit' now the number of bytes AFTER adding in the NUL */
244 * always move in increments of 4 (including the trailing NUL)
246 ab
->varcursor
+= roundup((count
+1), 4);
250 #define ATTR_PACK4(AB, V) \
252 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \
253 *(uint32_t *)AB.fixedcursor = V; \
254 AB.fixedcursor += 4; \
258 #define ATTR_PACK8(AB, V) \
260 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
261 *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \
262 AB.fixedcursor += 8; \
266 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
267 #define ATTR_PACK_CAST(b, t, v) \
273 #define ATTR_PACK_TIME(b, v, is64) \
276 struct user64_timespec us = {v.tv_sec, v.tv_nsec}; \
279 struct user32_timespec us = {v.tv_sec, v.tv_nsec}; \
286 * Table-driven setup for all valid common/volume attributes.
288 struct getvolattrlist_attrtab
{
291 #define VFSATTR_BIT(b) (VFSATTR_ ## b)
294 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = {
295 {ATTR_CMN_NAME
, 0, sizeof(struct attrreference
)},
296 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
)},
297 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
)},
298 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
)},
299 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
)},
300 {ATTR_CMN_OBJID
, 0, sizeof(fsobj_id_t
)},
301 {ATTR_CMN_OBJPERMANENTID
, 0, sizeof(fsobj_id_t
)},
302 {ATTR_CMN_PAROBJID
, 0, sizeof(fsobj_id_t
)},
303 {ATTR_CMN_SCRIPT
, 0, sizeof(text_encoding_t
)},
304 {ATTR_CMN_CRTIME
, VFSATTR_BIT(f_create_time
), ATTR_TIME_SIZE
},
305 {ATTR_CMN_MODTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
306 {ATTR_CMN_CHGTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
307 {ATTR_CMN_ACCTIME
, VFSATTR_BIT(f_access_time
), ATTR_TIME_SIZE
},
308 {ATTR_CMN_BKUPTIME
, VFSATTR_BIT(f_backup_time
), ATTR_TIME_SIZE
},
309 {ATTR_CMN_FNDRINFO
, 0, 32},
310 {ATTR_CMN_OWNERID
, 0, sizeof(uid_t
)},
311 {ATTR_CMN_GRPID
, 0, sizeof(gid_t
)},
312 {ATTR_CMN_ACCESSMASK
, 0, sizeof(uint32_t)},
313 {ATTR_CMN_FLAGS
, 0, sizeof(uint32_t)},
314 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t)},
315 {ATTR_CMN_EXTENDED_SECURITY
, 0, sizeof(struct attrreference
)},
316 {ATTR_CMN_UUID
, 0, sizeof(guid_t
)},
317 {ATTR_CMN_GRPUUID
, 0, sizeof(guid_t
)},
318 {ATTR_CMN_FILEID
, 0, sizeof(uint64_t)},
319 {ATTR_CMN_PARENTID
, 0, sizeof(uint64_t)},
320 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
)},
323 #define ATTR_CMN_VOL_INVALID \
324 (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \
325 ATTR_CMN_FILEID | ATTR_CMN_PARENTID)
327 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = {
328 {ATTR_VOL_FSTYPE
, 0, sizeof(uint32_t)},
329 {ATTR_VOL_SIGNATURE
, VFSATTR_BIT(f_signature
), sizeof(uint32_t)},
330 {ATTR_VOL_SIZE
, VFSATTR_BIT(f_blocks
), sizeof(off_t
)},
331 {ATTR_VOL_SPACEFREE
, VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
332 {ATTR_VOL_SPACEAVAIL
, VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
333 {ATTR_VOL_MINALLOCATION
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
334 {ATTR_VOL_ALLOCATIONCLUMP
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
335 {ATTR_VOL_IOBLOCKSIZE
, VFSATTR_BIT(f_iosize
), sizeof(uint32_t)},
336 {ATTR_VOL_OBJCOUNT
, VFSATTR_BIT(f_objcount
), sizeof(uint32_t)},
337 {ATTR_VOL_FILECOUNT
, VFSATTR_BIT(f_filecount
), sizeof(uint32_t)},
338 {ATTR_VOL_DIRCOUNT
, VFSATTR_BIT(f_dircount
), sizeof(uint32_t)},
339 {ATTR_VOL_MAXOBJCOUNT
, VFSATTR_BIT(f_maxobjcount
), sizeof(uint32_t)},
340 {ATTR_VOL_MOUNTPOINT
, 0, sizeof(struct attrreference
)},
341 {ATTR_VOL_NAME
, VFSATTR_BIT(f_vol_name
), sizeof(struct attrreference
)},
342 {ATTR_VOL_MOUNTFLAGS
, 0, sizeof(uint32_t)},
343 {ATTR_VOL_MOUNTEDDEVICE
, 0, sizeof(struct attrreference
)},
344 {ATTR_VOL_ENCODINGSUSED
, 0, sizeof(uint64_t)},
345 {ATTR_VOL_CAPABILITIES
, VFSATTR_BIT(f_capabilities
), sizeof(vol_capabilities_attr_t
)},
346 {ATTR_VOL_UUID
, VFSATTR_BIT(f_uuid
), sizeof(uuid_t
)},
347 {ATTR_VOL_ATTRIBUTES
, VFSATTR_BIT(f_attributes
), sizeof(vol_attributes_attr_t
)},
348 {ATTR_VOL_INFO
, 0, 0},
353 getvolattrlist_parsetab(struct getvolattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vfs_attr
*vsp
,
354 ssize_t
*sizep
, int is_64bit
)
356 attrgroup_t recognised
;
360 /* is this attribute set? */
361 if (tab
->attr
& attrs
) {
362 recognised
|= tab
->attr
;
363 vsp
->f_active
|= tab
->bits
;
364 if (tab
->size
== ATTR_TIME_SIZE
) {
366 *sizep
+= sizeof(struct user64_timespec
);
368 *sizep
+= sizeof(struct user32_timespec
);
374 } while ((++tab
)->attr
!= 0);
376 /* check to make sure that we recognised all of the passed-in attributes */
377 if (attrs
& ~recognised
)
383 * Given the attributes listed in alp, configure vap to request
384 * the data from a filesystem.
387 getvolattrlist_setupvfsattr(struct attrlist
*alp
, struct vfs_attr
*vsp
, ssize_t
*sizep
, int is_64bit
)
392 * Parse the above tables.
394 *sizep
= sizeof(uint32_t); /* length count */
395 if (alp
->commonattr
) {
396 if ((alp
->commonattr
& ATTR_CMN_VOL_INVALID
) &&
397 (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
) == 0) {
400 if ((error
= getvolattrlist_parsetab(getvolattrlist_common_tab
,
401 alp
->commonattr
, vsp
, sizep
,
407 (error
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
)) != 0)
414 * Given the attributes listed in asp and those supported
415 * in the vsp, fixup the asp attributes to reflect any
416 * missing attributes from the file system
419 getvolattrlist_fixupattrs(attribute_set_t
*asp
, struct vfs_attr
*vsp
)
421 struct getvolattrlist_attrtab
*tab
;
423 if (asp
->commonattr
) {
424 tab
= getvolattrlist_common_tab
;
426 if ((tab
->attr
& asp
->commonattr
) &&
428 ((tab
->bits
& vsp
->f_supported
) == 0)) {
429 asp
->commonattr
&= ~tab
->attr
;
431 } while ((++tab
)->attr
!= 0);
434 tab
= getvolattrlist_vol_tab
;
436 if ((tab
->attr
& asp
->volattr
) &&
438 ((tab
->bits
& vsp
->f_supported
) == 0)) {
439 asp
->volattr
&= ~tab
->attr
;
441 } while ((++tab
)->attr
!= 0);
446 * Table-driven setup for all valid common/dir/file/fork attributes against files.
448 struct getattrlist_attrtab
{
451 #define VATTR_BIT(b) (VNODE_ATTR_ ## b)
453 kauth_action_t action
;
457 * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this
458 * information, and we will synthesize it at the VFS level.
460 static struct getattrlist_attrtab getattrlist_common_tab
[] = {
461 {ATTR_CMN_NAME
, VATTR_BIT(va_name
), sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
462 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
463 {ATTR_CMN_FSID
, VATTR_BIT(va_fsid
), sizeof(fsid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
464 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
465 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
466 {ATTR_CMN_OBJID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
467 {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
468 {ATTR_CMN_PAROBJID
, VATTR_BIT(va_parentid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
469 {ATTR_CMN_SCRIPT
, VATTR_BIT(va_encoding
), sizeof(text_encoding_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
470 {ATTR_CMN_CRTIME
, VATTR_BIT(va_create_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
471 {ATTR_CMN_MODTIME
, VATTR_BIT(va_modify_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
472 {ATTR_CMN_CHGTIME
, VATTR_BIT(va_change_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
473 {ATTR_CMN_ACCTIME
, VATTR_BIT(va_access_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
474 {ATTR_CMN_BKUPTIME
, VATTR_BIT(va_backup_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
475 {ATTR_CMN_FNDRINFO
, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES
},
476 {ATTR_CMN_OWNERID
, VATTR_BIT(va_uid
), sizeof(uid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
477 {ATTR_CMN_GRPID
, VATTR_BIT(va_gid
), sizeof(gid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
478 {ATTR_CMN_ACCESSMASK
, VATTR_BIT(va_mode
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
479 {ATTR_CMN_FLAGS
, VATTR_BIT(va_flags
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
480 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
481 {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
), sizeof(struct attrreference
), KAUTH_VNODE_READ_SECURITY
},
482 {ATTR_CMN_UUID
, VATTR_BIT(va_uuuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
483 {ATTR_CMN_GRPUUID
, VATTR_BIT(va_guuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
484 {ATTR_CMN_FILEID
, VATTR_BIT(va_fileid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
485 {ATTR_CMN_PARENTID
, VATTR_BIT(va_parentid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
486 {ATTR_CMN_FULLPATH
, 0, sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
487 {ATTR_CMN_ADDEDTIME
, VATTR_BIT(va_addedtime
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
488 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
), 0},
492 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
493 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_dirlinkcount
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
494 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
495 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
498 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
499 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
500 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
501 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
502 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
503 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
504 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
505 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
506 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
507 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
512 * The following are attributes that VFS can derive.
514 * A majority of them are the same attributes that are required for stat(2) and statfs(2).
516 #define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
517 ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
518 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
519 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
520 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
521 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
522 ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
524 #define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
525 ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
526 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
527 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
528 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
529 ATTR_CMN_FNDRINFO | \
530 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
531 ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
532 ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
533 ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS)
535 #define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
537 #define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
538 ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
539 ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
540 ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
541 ATTR_FILE_RSRCALLOCSIZE)
544 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vnode_attr
*vap
,
545 ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
)
547 attrgroup_t recognised
;
551 /* is this attribute set? */
552 if (tab
->attr
& attrs
) {
553 recognised
|= tab
->attr
;
554 vap
->va_active
|= tab
->bits
;
555 if (tab
->size
== ATTR_TIME_SIZE
) {
557 *sizep
+= sizeof(struct user64_timespec
);
559 *sizep
+= sizeof(struct user32_timespec
);
564 *actionp
|= tab
->action
;
565 if (attrs
== recognised
)
566 break; /* all done, get out */
568 } while ((++tab
)->attr
!= 0);
570 /* check to make sure that we recognised all of the passed-in attributes */
571 if (attrs
& ~recognised
)
577 * Given the attributes listed in alp, configure vap to request
578 * the data from a filesystem.
581 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
)
586 * Parse the above tables.
588 *sizep
= sizeof(uint32_t); /* length count */
590 if (alp
->commonattr
&&
591 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
593 if (isdir
&& alp
->dirattr
&&
594 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
596 if (!isdir
&& alp
->fileattr
&&
597 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
604 * Given the attributes listed in asp and those supported
605 * in the vap, fixup the asp attributes to reflect any
606 * missing attributes from the file system
609 getattrlist_fixupattrs(attribute_set_t
*asp
, struct vnode_attr
*vap
)
611 struct getattrlist_attrtab
*tab
;
613 if (asp
->commonattr
) {
614 tab
= getattrlist_common_tab
;
617 * This if() statement is slightly confusing. We're trying to
618 * iterate through all of the bits listed in the array
619 * getattr_common_tab, and see if the filesystem was expected
620 * to support it, and whether or not we need to do anything about this.
622 * This array is full of structs that have 4 fields (attr, bits, size, action).
623 * The first is used to store the ATTR_CMN_* bit that was being requested
624 * from userland. The second stores the VATTR_BIT corresponding to the field
625 * filled in vnode_attr struct. If it is 0, then we don't typically expect
626 * the filesystem to fill in this field. The third is the size of the field,
627 * and the fourth is the type of kauth actions needed.
629 * So, for all of the ATTR_CMN bits listed in this array, we iterate through
630 * them, and check to see if it was both passed down to the filesystem via the
631 * va_active bitfield, and whether or not we expect it to be emitted from
632 * the filesystem. If it wasn't supported, then we un-twiddle the bit and move
633 * on. This is done so that we can uncheck those bits and re-request
634 * a vnode_getattr from the filesystem again.
636 if ((tab
->attr
& asp
->commonattr
) &&
637 (tab
->bits
& vap
->va_active
) &&
638 (tab
->bits
& vap
->va_supported
) == 0) {
639 asp
->commonattr
&= ~tab
->attr
;
641 } while ((++tab
)->attr
!= 0);
644 tab
= getattrlist_dir_tab
;
646 if ((tab
->attr
& asp
->dirattr
) &&
647 (tab
->bits
& vap
->va_active
) &&
648 (vap
->va_supported
& tab
->bits
) == 0) {
649 asp
->dirattr
&= ~tab
->attr
;
651 } while ((++tab
)->attr
!= 0);
654 tab
= getattrlist_file_tab
;
656 if ((tab
->attr
& asp
->fileattr
) &&
657 (tab
->bits
& vap
->va_active
) &&
658 (vap
->va_supported
& tab
->bits
) == 0) {
659 asp
->fileattr
&= ~tab
->attr
;
661 } while ((++tab
)->attr
!= 0);
666 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
669 char uio_buf
[UIO_SIZEOF(1)];
672 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
675 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
676 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
681 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
682 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
690 * Find something resembling a terminal component name in the mountedonname for vp
694 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
700 * We're looking for the last sequence of non / characters, but
701 * not including any trailing / characters.
706 for (cp
= mn
; *cp
!= 0; cp
++) {
708 /* start of run of chars */
714 /* end of run of chars */
721 /* need to close run? */
728 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
,
729 vfs_context_t ctx
, int is_64bit
)
732 struct vnode_attr va
;
733 struct _attrlist_buf ab
;
735 ssize_t fixedsize
, varsize
;
736 const char *cnp
= NULL
; /* protected by ATTR_CMN_NAME */
737 ssize_t cnl
= 0; /* protected by ATTR_CMN_NAME */
746 vs
.f_vol_name
= NULL
;
749 /* Check for special packing semantics */
750 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
);
751 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
753 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
758 /* Keep invalid attrs from being uninitialized */
759 bzero(&vs
, sizeof (vs
));
760 /* Generate a valid mask for post processing */
761 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
765 * For now, the vnode must be the root of its filesystem.
766 * To relax this, we need to be able to find the root vnode of a filesystem
767 * from any vnode in the filesystem.
769 if (!vnode_isvroot(vp
)) {
771 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
776 * Set up the vfs_attr structure and call the filesystem.
778 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
779 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
782 if (vs
.f_active
!= 0) {
783 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
784 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
785 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
786 if (vs
.f_vol_name
== NULL
) {
788 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
794 error
= mac_mount_check_getattr(ctx
, mnt
, &vs
);
798 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
799 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
800 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
805 * Did we ask for something the filesystem doesn't support?
807 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
808 /* default value for volume subtype */
809 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
810 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
811 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
814 * If the file system didn't supply f_signature, then
815 * default it to 'BD', which is the generic signature
816 * that most Carbon file systems should return.
818 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
819 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
820 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
822 /* default for block size */
823 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
824 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
825 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
827 /* default value for volume f_attributes */
828 if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
)
829 && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) {
830 vol_attributes_attr_t
*attrp
= &vs
.f_attributes
;
832 attrp
->validattr
.commonattr
= VFS_DFLT_ATTR_CMN
;
833 attrp
->validattr
.volattr
= VFS_DFLT_ATTR_VOL
;
834 attrp
->validattr
.dirattr
= VFS_DFLT_ATTR_DIR
;
835 attrp
->validattr
.fileattr
= VFS_DFLT_ATTR_FILE
;
836 attrp
->validattr
.forkattr
= 0;
838 attrp
->nativeattr
.commonattr
= 0;
839 attrp
->nativeattr
.volattr
= 0;
840 attrp
->nativeattr
.dirattr
= 0;
841 attrp
->nativeattr
.fileattr
= 0;
842 attrp
->nativeattr
.forkattr
= 0;
843 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
);
846 /* default value for volume f_capabilities */
847 if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) {
848 /* getattrlist is always supported now. */
849 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) {
850 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0;
851 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
852 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
853 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
855 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0;
856 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
857 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
858 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
859 VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
);
862 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
863 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
864 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
868 /* check to see if our fixups were enough */
869 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
872 /* Fix up valid mask for post processing */
873 getvolattrlist_fixupattrs(&ab
.valid
, &vs
);
875 /* Force packing of everything asked for */
876 vs
.f_supported
= vs
.f_active
;
878 /* Adjust the requested attributes */
879 getvolattrlist_fixupattrs((attribute_set_t
*)&alp
->commonattr
, &vs
);
890 * Some fields require data from the root vp
892 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
893 VATTR_WANTED(&va
, va_uid
);
894 VATTR_WANTED(&va
, va_gid
);
895 VATTR_WANTED(&va
, va_mode
);
896 VATTR_WANTED(&va
, va_flags
);
897 VATTR_WANTED(&va
, va_encoding
);
899 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
900 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
904 if (VATTR_IS_ACTIVE(&va
, va_encoding
) &&
905 !VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
906 if (!return_valid
|| pack_invalid
)
907 /* use kTextEncodingMacUnicode */
908 VATTR_RETURN(&va
, va_encoding
, 0x7e);
910 /* don't use a default */
911 alp
->commonattr
&= ~ATTR_CMN_SCRIPT
;
916 * Compute variable-size buffer requirements.
919 if (alp
->commonattr
& ATTR_CMN_NAME
) {
920 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
921 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
922 /* special case for boot volume. Use root name when it's
923 * available (which is the volume name) or just the mount on
924 * name of "/". we must do this for binary compatibility with
925 * pre Tiger code. returning nothing for the boot volume name
926 * breaks installers - 3961058
928 cnp
= vnode_getname(vp
);
930 /* just use "/" as name */
931 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
939 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
941 if (alp
->commonattr
& ATTR_CMN_NAME
)
942 varsize
+= roundup(cnl
+ 1, 4);
944 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
945 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
946 if (alp
->volattr
& ATTR_VOL_NAME
) {
947 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
948 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
950 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
951 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
954 * Allocate a target buffer for attribute results.
955 * Note that since we won't ever copy out more than the caller requested,
956 * we never need to allocate more than they offer.
958 ab
.allocated
= ulmin(uap
->bufferSize
, fixedsize
+ varsize
);
959 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
961 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
964 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
965 if (ab
.base
== NULL
) {
967 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
972 * Pack results into the destination buffer.
974 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
976 ab
.fixedcursor
+= sizeof (attribute_set_t
);
977 bzero(&ab
.actual
, sizeof (ab
.actual
));
979 ab
.varcursor
= ab
.base
+ fixedsize
;
980 ab
.needed
= fixedsize
+ varsize
;
982 /* common attributes **************************************************/
983 if (alp
->commonattr
& ATTR_CMN_NAME
) {
984 attrlist_pack_string(&ab
, cnp
, cnl
);
985 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
987 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
988 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
989 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
991 if (alp
->commonattr
& ATTR_CMN_FSID
) {
992 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
);
993 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
995 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
996 if (!return_valid
|| pack_invalid
)
999 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
1000 ATTR_PACK4(ab
, vp
->v_tag
);
1001 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1003 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
1004 if (!return_valid
|| pack_invalid
) {
1005 fsobj_id_t f
= {0, 0};
1009 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1010 if (!return_valid
|| pack_invalid
) {
1011 fsobj_id_t f
= {0, 0};
1015 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
1016 if (!return_valid
|| pack_invalid
) {
1017 fsobj_id_t f
= {0, 0};
1021 /* note that this returns the encoding for the volume name, not the node name */
1022 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
1023 ATTR_PACK4(ab
, va
.va_encoding
);
1024 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1026 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
1027 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
);
1028 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1030 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
1031 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
1032 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1034 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
1035 if (!return_valid
|| pack_invalid
)
1036 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
1038 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
1039 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
);
1040 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1042 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
1043 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
);
1044 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1046 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
1049 * This attribute isn't really Finder Info, at least for HFS.
1051 if (vp
->v_tag
== VT_HFS
) {
1052 error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
);
1054 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
1055 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1056 } else if (!return_valid
) {
1059 } else if (!return_valid
|| pack_invalid
) {
1060 /* XXX we could at least pass out the volume UUID here */
1061 bzero(&f
, sizeof(f
));
1062 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
1065 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
1066 ATTR_PACK4(ab
, va
.va_uid
);
1067 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1069 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
1070 ATTR_PACK4(ab
, va
.va_gid
);
1071 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1073 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
1074 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
1075 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1077 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
1078 ATTR_PACK4(ab
, va
.va_flags
);
1079 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1081 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
1083 if (vnode_isdir(vp
)) {
1084 if (vnode_authorize(vp
, NULL
,
1085 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1087 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1089 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1092 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1094 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1096 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1101 * Rather than MAC preceding DAC, in this case we want
1102 * the smallest set of permissions granted by both MAC & DAC
1103 * checks. We won't add back any permissions.
1106 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1109 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1112 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1115 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
1116 ATTR_PACK4(ab
, perms
);
1117 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1120 * The following common volume attributes are only
1121 * packed when the pack_invalid mode is enabled.
1126 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
)
1127 attrlist_pack_variable(&ab
, NULL
, 0);
1128 if (alp
->commonattr
& ATTR_CMN_UUID
)
1129 ATTR_PACK(&ab
, kauth_null_guid
);
1130 if (alp
->commonattr
& ATTR_CMN_GRPUUID
)
1131 ATTR_PACK(&ab
, kauth_null_guid
);
1132 if (alp
->commonattr
& ATTR_CMN_FILEID
)
1133 ATTR_PACK8(ab
, fid
);
1134 if (alp
->commonattr
& ATTR_CMN_PARENTID
)
1135 ATTR_PACK8(ab
, fid
);
1138 /* volume attributes **************************************************/
1140 if (alp
->volattr
& ATTR_VOL_FSTYPE
) {
1141 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
1142 ab
.actual
.volattr
|= ATTR_VOL_FSTYPE
;
1144 if (alp
->volattr
& ATTR_VOL_SIGNATURE
) {
1145 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
1146 ab
.actual
.volattr
|= ATTR_VOL_SIGNATURE
;
1148 if (alp
->volattr
& ATTR_VOL_SIZE
) {
1149 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
1150 ab
.actual
.volattr
|= ATTR_VOL_SIZE
;
1152 if (alp
->volattr
& ATTR_VOL_SPACEFREE
) {
1153 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
1154 ab
.actual
.volattr
|= ATTR_VOL_SPACEFREE
;
1156 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
) {
1157 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
1158 ab
.actual
.volattr
|= ATTR_VOL_SPACEAVAIL
;
1160 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
) {
1161 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
1162 ab
.actual
.volattr
|= ATTR_VOL_MINALLOCATION
;
1164 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
) {
1165 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
1166 ab
.actual
.volattr
|= ATTR_VOL_ALLOCATIONCLUMP
;
1168 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
) {
1169 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
1170 ab
.actual
.volattr
|= ATTR_VOL_IOBLOCKSIZE
;
1172 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
) {
1173 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
1174 ab
.actual
.volattr
|= ATTR_VOL_OBJCOUNT
;
1176 if (alp
->volattr
& ATTR_VOL_FILECOUNT
) {
1177 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
1178 ab
.actual
.volattr
|= ATTR_VOL_FILECOUNT
;
1180 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
) {
1181 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
1182 ab
.actual
.volattr
|= ATTR_VOL_DIRCOUNT
;
1184 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
) {
1185 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
1186 ab
.actual
.volattr
|= ATTR_VOL_MAXOBJCOUNT
;
1188 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
) {
1189 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
1190 ab
.actual
.volattr
|= ATTR_VOL_MOUNTPOINT
;
1192 if (alp
->volattr
& ATTR_VOL_NAME
) {
1193 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
1194 ab
.actual
.volattr
|= ATTR_VOL_NAME
;
1196 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
) {
1197 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
1198 ab
.actual
.volattr
|= ATTR_VOL_MOUNTFLAGS
;
1200 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
) {
1201 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
1202 ab
.actual
.volattr
|= ATTR_VOL_MOUNTEDDEVICE
;
1204 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
) {
1205 if (!return_valid
|| pack_invalid
)
1206 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
1208 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
1209 /* fix up volume capabilities */
1210 if (vfs_extendedsecurity(mnt
)) {
1211 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1213 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
1215 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1216 ATTR_PACK(&ab
, vs
.f_capabilities
);
1217 ab
.actual
.volattr
|= ATTR_VOL_CAPABILITIES
;
1219 if (alp
->volattr
& ATTR_VOL_UUID
) {
1220 ATTR_PACK(&ab
, vs
.f_uuid
);
1221 ab
.actual
.volattr
|= ATTR_VOL_UUID
;
1223 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
1224 /* fix up volume attribute information */
1226 vs
.f_attributes
.validattr
.commonattr
|= VFS_DFLT_ATTR_CMN
;
1227 vs
.f_attributes
.validattr
.volattr
|= VFS_DFLT_ATTR_VOL
;
1228 vs
.f_attributes
.validattr
.dirattr
|= VFS_DFLT_ATTR_DIR
;
1229 vs
.f_attributes
.validattr
.fileattr
|= VFS_DFLT_ATTR_FILE
;
1231 if (vfs_extendedsecurity(mnt
)) {
1232 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1234 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1235 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1237 ATTR_PACK(&ab
, vs
.f_attributes
);
1238 ab
.actual
.volattr
|= ATTR_VOL_ATTRIBUTES
;
1242 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1243 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1244 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
1245 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1246 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1249 * In the compatible case, we report the smaller of the required and returned sizes.
1250 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1251 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1252 * they gave us, so they can always check for truncation themselves.
1254 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1256 /* Return attribute set output if requested. */
1258 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1260 /* Only report the attributes that are valid */
1261 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1262 ab
.actual
.volattr
&= ab
.valid
.volattr
;
1264 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1266 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
1269 if (vs
.f_vol_name
!= NULL
)
1270 kfree(vs
.f_vol_name
, MAXPATHLEN
);
1274 if (ab
.base
!= NULL
)
1275 FREE(ab
.base
, M_TEMP
);
1276 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1281 * Obtain attribute information about a filesystem object.
1285 getattrlist_internal(vnode_t vp
, struct getattrlist_args
*uap
,
1286 __unused
struct componentname
*getattr_name
, proc_t p
, vfs_context_t ctx
)
1289 struct vnode_attr va
;
1290 struct _attrlist_buf ab
;
1291 kauth_action_t action
;
1292 ssize_t fixedsize
, varsize
;
1294 const char *vname
= NULL
;
1296 ssize_t fullpathlen
;
1305 proc_is64
= proc_is64bit(p
);
1315 * Fetch the attribute request.
1317 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
1319 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1324 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1325 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1326 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1329 error
= mac_vnode_check_getattrlist(ctx
, vp
, &al
);
1335 * It is legal to request volume or file attributes,
1339 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
1341 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
1344 /* handle volume attribute request */
1345 error
= getvolattrlist(vp
, uap
, &al
, ctx
, proc_is64
);
1349 /* Check for special packing semantics */
1350 return_valid
= (al
.commonattr
& ATTR_CMN_RETURNED_ATTRS
);
1351 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
1353 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
1354 if (!return_valid
|| al
.forkattr
) {
1358 /* Keep invalid attrs from being uninitialized */
1359 bzero(&va
, sizeof (va
));
1360 /* Generate a valid mask for post processing */
1361 bcopy(&al
.commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
1364 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
1365 * will have a valid snapshot that we can work from here.
1371 * Set up the vnode_attr structure and authorise.
1373 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64
, (vtype
== VDIR
))) != 0) {
1374 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
1377 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) {
1378 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
1383 * If we're asking for the full path, allocate a buffer for that.
1385 if (al
.commonattr
& (ATTR_CMN_FULLPATH
)) {
1386 fullpathptr
= (char*) kalloc(MAXPATHLEN
);
1387 if (fullpathptr
== NULL
) {
1389 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
1395 if (va
.va_active
!= 0) {
1397 * If we're going to ask for va_name, allocate a buffer to point it at
1399 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
1400 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
1401 if (va
.va_name
== NULL
) {
1403 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
1409 * Call the filesystem.
1411 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
1412 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1416 /* did we ask for something the filesystem doesn't support? */
1417 if (!VATTR_ALL_SUPPORTED(&va
)) {
1420 * There are a couple of special cases. If we are after object IDs,
1421 * we can make do with va_fileid.
1423 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
| ATTR_CMN_FILEID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
1424 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
1427 * Many filesystems don't know their parent object id.
1428 * If necessary, attempt to derive it from the vnode.
1430 if ((al
.commonattr
& (ATTR_CMN_PAROBJID
| ATTR_CMN_PARENTID
)) &&
1431 !VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1434 if ((dvp
= vnode_getparent(vp
)) != NULLVP
) {
1435 struct vnode_attr lva
;
1438 VATTR_WANTED(&lva
, va_fileid
);
1439 if (vnode_getattr(dvp
, &lva
, ctx
) == 0 &&
1440 VATTR_IS_SUPPORTED(&va
, va_fileid
)) {
1441 va
.va_parentid
= lva
.va_fileid
;
1442 VATTR_SET_SUPPORTED(&va
, va_parentid
);
1448 * And we can report datasize/alloc from total.
1450 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
1451 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
1452 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
1453 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
1456 * If we don't have an encoding, go with UTF-8
1458 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) &&
1459 !VATTR_IS_SUPPORTED(&va
, va_encoding
) && !return_valid
)
1460 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
1463 * If we don't have a name, we'll get one from the vnode or mount point.
1465 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
1466 VATTR_CLEAR_ACTIVE(&va
, va_name
);
1469 /* If va_dirlinkcount isn't supported use a default of 1. */
1470 if ((al
.dirattr
& ATTR_DIR_LINKCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_dirlinkcount
)) {
1471 VATTR_RETURN(&va
, va_dirlinkcount
, 1);
1475 if (!VATTR_ALL_SUPPORTED(&va
)) {
1478 /* Fix up valid mask for post processing */
1479 getattrlist_fixupattrs(&ab
.valid
, &va
);
1481 /* Force packing of everything asked for */
1482 va
.va_supported
= va
.va_active
;
1484 /* Adjust the requested attributes */
1485 getattrlist_fixupattrs((attribute_set_t
*)&al
.commonattr
, &va
);
1496 * Compute variable-space requirements.
1498 varsize
= 0; /* length count */
1500 /* We may need to fix up the name attribute if requested */
1501 if (al
.commonattr
& ATTR_CMN_NAME
) {
1502 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
1503 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
1508 /* Filesystem did not support getting the name */
1509 if (vnode_isvroot(vp
)) {
1510 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
1511 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
1512 /* special case for boot volume. Use root name when it's
1513 * available (which is the volume name) or just the mount on
1514 * name of "/". we must do this for binary compatibility with
1515 * pre Tiger code. returning nothing for the boot volume name
1516 * breaks installers - 3961058
1518 cnp
= vname
= vnode_getname(vp
);
1520 /* just use "/" as name */
1521 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
1526 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
1530 cnp
= vname
= vnode_getname(vp
);
1537 varsize
+= roundup(cnl
+ 1, 4);
1541 * Compute the full path to this vnode, if necessary. This attribute is almost certainly
1542 * not supported by any filesystem, so build the path to this vnode at this time.
1544 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1545 int len
= MAXPATHLEN
;
1547 /* call build_path making sure NOT to use the cache-only behavior */
1548 err
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current());
1555 fullpathlen
= strlen(fullpathptr
);
1557 varsize
+= roundup(fullpathlen
+1, 4);
1561 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
1563 * XXX This needs to change at some point; since the blob is opaque in
1564 * user-space this is OK.
1566 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
1567 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
1568 (va
.va_acl
!= NULL
)) {
1571 * Since we have a kauth_acl_t (not a kauth_filesec_t), we have to check against
1572 * KAUTH_FILESEC_NOACL ourselves
1574 if (va
.va_acl
->acl_entrycount
== KAUTH_FILESEC_NOACL
) {
1575 varsize
+= roundup((KAUTH_FILESEC_SIZE(0)), 4);
1578 varsize
+= roundup ((KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
)), 4);
1583 * Allocate a target buffer for attribute results.
1585 * Note that we won't ever copy out more than the caller requested, even though
1586 * we might have to allocate more than they offer so that the diagnostic checks
1587 * don't result in a panic if the caller's buffer is too small..
1589 ab
.allocated
= fixedsize
+ varsize
;
1590 /* Cast 'allocated' to an unsigned to verify allocation size */
1591 if ( ((size_t)ab
.allocated
) > ATTR_MAX_BUFFER
) {
1593 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1596 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1597 if (ab
.base
== NULL
) {
1599 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1603 /* set the S_IFMT bits for the mode */
1604 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1605 switch (vp
->v_type
) {
1607 va
.va_mode
|= S_IFREG
;
1610 va
.va_mode
|= S_IFDIR
;
1613 va
.va_mode
|= S_IFBLK
;
1616 va
.va_mode
|= S_IFCHR
;
1619 va
.va_mode
|= S_IFLNK
;
1622 va
.va_mode
|= S_IFSOCK
;
1625 va
.va_mode
|= S_IFIFO
;
1634 * Pack results into the destination buffer.
1636 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1638 ab
.fixedcursor
+= sizeof (attribute_set_t
);
1639 bzero(&ab
.actual
, sizeof (ab
.actual
));
1641 ab
.varcursor
= ab
.base
+ fixedsize
;
1642 ab
.needed
= ab
.allocated
;
1644 /* common attributes **************************************************/
1645 if (al
.commonattr
& ATTR_CMN_NAME
) {
1646 attrlist_pack_string(&ab
, cnp
, cnl
);
1647 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
1649 if (al
.commonattr
& ATTR_CMN_DEVID
) {
1650 ATTR_PACK4(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1651 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
1653 if (al
.commonattr
& ATTR_CMN_FSID
) {
1654 ATTR_PACK8(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1655 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
1657 if (al
.commonattr
& ATTR_CMN_OBJTYPE
) {
1658 ATTR_PACK4(ab
, vtype
);
1659 ab
.actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1661 if (al
.commonattr
& ATTR_CMN_OBJTAG
) {
1662 ATTR_PACK4(ab
, vp
->v_tag
);
1663 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1665 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1668 * Carbon can't deal with us reporting the target ID
1669 * for links. So we ask the filesystem to give us the
1670 * source ID as well, and if it gives us one, we use
1673 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1674 f
.fid_objno
= va
.va_linkid
;
1676 f
.fid_objno
= va
.va_fileid
;
1678 f
.fid_generation
= 0;
1680 ab
.actual
.commonattr
|= ATTR_CMN_OBJID
;
1682 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1685 * Carbon can't deal with us reporting the target ID
1686 * for links. So we ask the filesystem to give us the
1687 * source ID as well, and if it gives us one, we use
1690 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1691 f
.fid_objno
= va
.va_linkid
;
1693 f
.fid_objno
= va
.va_fileid
;
1695 f
.fid_generation
= 0;
1697 ab
.actual
.commonattr
|= ATTR_CMN_OBJPERMANENTID
;
1699 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1702 f
.fid_objno
= va
.va_parentid
; /* could be lossy here! */
1703 f
.fid_generation
= 0;
1705 ab
.actual
.commonattr
|= ATTR_CMN_PAROBJID
;
1707 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1708 if (VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
1709 ATTR_PACK4(ab
, va
.va_encoding
);
1710 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1711 } else if (!return_valid
|| pack_invalid
) {
1712 ATTR_PACK4(ab
, 0x7e);
1715 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1716 ATTR_PACK_TIME(ab
, va
.va_create_time
, proc_is64
);
1717 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1719 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1720 ATTR_PACK_TIME(ab
, va
.va_modify_time
, proc_is64
);
1721 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1723 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1724 ATTR_PACK_TIME(ab
, va
.va_change_time
, proc_is64
);
1725 ab
.actual
.commonattr
|= ATTR_CMN_CHGTIME
;
1727 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1728 ATTR_PACK_TIME(ab
, va
.va_access_time
, proc_is64
);
1729 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1731 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1732 ATTR_PACK_TIME(ab
, va
.va_backup_time
, proc_is64
);
1733 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1736 * They are requesting user access, we should obtain this before getting
1737 * the finder info. For some network file systems this is a performance
1740 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1741 if (vtype
== VDIR
) {
1742 if (vnode_authorize(vp
, NULL
,
1743 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1745 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1747 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1750 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1752 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1754 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1759 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1762 char uio_buf
[UIO_SIZEOF(1)];
1764 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1765 uio_buf
, sizeof(uio_buf
))) == NULL
) {
1769 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1770 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
,
1771 &fisize
, XATTR_NOSECURITY
, ctx
);
1774 * Default to zeros if its not available,
1775 * unless ATTR_CMN_RETURNED_ATTRS was requested.
1778 (!return_valid
|| pack_invalid
) &&
1779 ((error
== ENOATTR
) || (error
== ENOENT
) ||
1780 (error
== ENOTSUP
) || (error
== EPERM
))) {
1781 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1782 bzero(ab
.fixedcursor
, 32);
1786 ab
.fixedcursor
+= 32;
1787 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1788 } else if (!return_valid
) {
1789 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1793 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1794 ATTR_PACK4(ab
, va
.va_uid
);
1795 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1797 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1798 ATTR_PACK4(ab
, va
.va_gid
);
1799 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1801 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1802 ATTR_PACK4(ab
, va
.va_mode
);
1803 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1805 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1806 ATTR_PACK4(ab
, va
.va_flags
);
1807 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1809 /* We already obtain the user access, so just fill in the buffer here */
1810 if (al
.commonattr
& ATTR_CMN_USERACCESS
) {
1813 * Rather than MAC preceding DAC, in this case we want
1814 * the smallest set of permissions granted by both MAC & DAC
1815 * checks. We won't add back any permissions.
1818 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1821 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1824 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1827 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1828 ATTR_PACK4(ab
, perms
);
1829 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1831 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1832 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1833 struct kauth_filesec fsec
;
1835 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1837 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1838 fsec
.fsec_owner
= kauth_null_guid
;
1839 fsec
.fsec_group
= kauth_null_guid
;
1840 attrlist_pack_variable2(&ab
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1841 ab
.actual
.commonattr
|= ATTR_CMN_EXTENDED_SECURITY
;
1842 } else if (!return_valid
|| pack_invalid
) {
1843 attrlist_pack_variable(&ab
, NULL
, 0);
1846 if (al
.commonattr
& ATTR_CMN_UUID
) {
1847 if (VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1848 ATTR_PACK(&ab
, va
.va_uuuid
);
1849 ab
.actual
.commonattr
|= ATTR_CMN_UUID
;
1850 } else if (!return_valid
|| pack_invalid
) {
1851 ATTR_PACK(&ab
, kauth_null_guid
);
1854 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1855 if (VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1856 ATTR_PACK(&ab
, va
.va_guuid
);
1857 ab
.actual
.commonattr
|= ATTR_CMN_GRPUUID
;
1858 } else if (!return_valid
|| pack_invalid
) {
1859 ATTR_PACK(&ab
, kauth_null_guid
);
1862 if (al
.commonattr
& ATTR_CMN_FILEID
) {
1863 ATTR_PACK8(ab
, va
.va_fileid
);
1864 ab
.actual
.commonattr
|= ATTR_CMN_FILEID
;
1866 if (al
.commonattr
& ATTR_CMN_PARENTID
) {
1867 ATTR_PACK8(ab
, va
.va_parentid
);
1868 ab
.actual
.commonattr
|= ATTR_CMN_PARENTID
;
1871 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1872 attrlist_pack_string (&ab
, fullpathptr
, fullpathlen
);
1873 ab
.actual
.commonattr
|= ATTR_CMN_FULLPATH
;
1876 if (al
.commonattr
& ATTR_CMN_ADDEDTIME
) {
1877 ATTR_PACK_TIME(ab
, va
.va_addedtime
, proc_is64
);
1878 ab
.actual
.commonattr
|= ATTR_CMN_ADDEDTIME
;
1881 /* directory attributes *********************************************/
1882 if (al
.dirattr
&& (vtype
== VDIR
)) {
1883 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) { /* full count of entries */
1884 ATTR_PACK4(ab
, (uint32_t)va
.va_dirlinkcount
);
1885 ab
.actual
.dirattr
|= ATTR_DIR_LINKCOUNT
;
1887 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) {
1888 ATTR_PACK4(ab
, (uint32_t)va
.va_nchildren
);
1889 ab
.actual
.dirattr
|= ATTR_DIR_ENTRYCOUNT
;
1891 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
) {
1894 mntstat
= (vp
->v_flag
& VROOT
) ? DIR_MNTSTATUS_MNTPOINT
: 0;
1897 * Report back on active vnode triggers
1898 * that can directly trigger a mount
1900 if (vp
->v_resolve
&&
1901 !(vp
->v_resolve
->vr_flags
& VNT_NO_DIRECT_MOUNT
)) {
1902 mntstat
|= DIR_MNTSTATUS_TRIGGER
;
1905 ATTR_PACK4(ab
, mntstat
);
1906 ab
.actual
.dirattr
|= ATTR_DIR_MOUNTSTATUS
;
1910 /* file attributes **************************************************/
1911 if (al
.fileattr
&& (vtype
!= VDIR
)) {
1914 uint64_t rlength
= 0;
1915 uint64_t ralloc
= 0;
1917 * Pre-fetch the rsrc attributes now so we only get them once.
1918 * Fetch the resource fork size/allocation via xattr interface
1920 if (al
.fileattr
& (ATTR_FILE_TOTALSIZE
| ATTR_FILE_ALLOCSIZE
| ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1921 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, ctx
)) != 0) {
1922 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)|| (error
== EACCES
)) {
1931 if (al
.fileattr
& (ATTR_FILE_RSRCALLOCSIZE
| ATTR_FILE_ALLOCSIZE
)) {
1932 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1936 ralloc
= roundup(rsize
, blksize
);
1940 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
) {
1941 ATTR_PACK4(ab
, (uint32_t)va
.va_nlink
);
1942 ab
.actual
.fileattr
|= ATTR_FILE_LINKCOUNT
;
1945 * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes:
1946 * We infer that if the filesystem does not support va_data_size or va_data_alloc
1947 * it must not know about alternate forks. So when we need to gather
1948 * the total size or total alloc, it's OK to substitute the total size for
1949 * the data size below. This is because it is likely a flat filesystem and we must
1950 * be using AD files to store the rsrc fork and EAs.
1952 * Additionally, note that getattrlist is barred from being called on
1953 * resource fork paths. (Search for CN_ALLOWRSRCFORK). So if the filesystem does
1954 * support va_data_size, it is guaranteed to represent the data fork's size. This
1955 * is an important distinction to make because when we call vnode_getattr on
1956 * an HFS resource fork vnode, to get the size, it will vend out the resource
1957 * fork's size (it only gets the size of the passed-in vnode).
1959 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
) {
1960 uint64_t totalsize
= rlength
;
1962 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1963 totalsize
+= va
.va_data_size
;
1965 totalsize
+= va
.va_total_size
;
1968 ATTR_PACK8(ab
, totalsize
);
1969 ab
.actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
1971 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
) {
1972 uint64_t totalalloc
= ralloc
;
1975 * If data_alloc is supported, then it must represent the
1978 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1979 totalalloc
+= va
.va_data_alloc
;
1982 totalalloc
+= va
.va_total_alloc
;
1985 ATTR_PACK8(ab
, totalalloc
);
1986 ab
.actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
1988 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
) {
1989 ATTR_PACK4(ab
, va
.va_iosize
);
1990 ab
.actual
.fileattr
|= ATTR_FILE_IOBLOCKSIZE
;
1992 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
) {
1993 if (!return_valid
|| pack_invalid
) {
1994 ATTR_PACK4(ab
, 0); /* this value is deprecated */
1995 ab
.actual
.fileattr
|= ATTR_FILE_CLUMPSIZE
;
1998 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
2001 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
2002 if (vp
->v_specinfo
!= NULL
)
2003 dev
= vp
->v_specinfo
->si_rdev
;
2009 ATTR_PACK4(ab
, dev
);
2010 ab
.actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
2014 * If the filesystem does not support datalength
2015 * or dataallocsize, then we infer that totalsize and
2016 * totalalloc are substitutes.
2018 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
2019 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
2020 ATTR_PACK8(ab
, va
.va_data_size
);
2022 ATTR_PACK8(ab
, va
.va_total_size
);
2024 ab
.actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
2026 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
2027 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
2028 ATTR_PACK8(ab
, va
.va_data_alloc
);
2030 ATTR_PACK8(ab
, va
.va_total_alloc
);
2032 ab
.actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
2034 /* already got the resource fork size/allocation above */
2035 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
) {
2036 ATTR_PACK8(ab
, rlength
);
2037 ab
.actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
2039 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
2040 ATTR_PACK8(ab
, ralloc
);
2041 ab
.actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
2046 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
2047 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
2048 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), al
.commonattr
, al
.volattr
);
2049 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
2050 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
2053 * In the compatible case, we report the smaller of the required and returned sizes.
2054 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
2055 * of the result buffer, even if we copied less out. The caller knows how big a buffer
2056 * they gave us, so they can always check for truncation themselves.
2058 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
2060 /* Return attribute set output if requested. */
2062 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
2064 /* Only report the attributes that are valid */
2065 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
2066 ab
.actual
.dirattr
&= ab
.valid
.dirattr
;
2067 ab
.actual
.fileattr
&= ab
.valid
.fileattr
;
2069 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
2072 /* Only actually copyout as much out as the user buffer can hold */
2073 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
2077 kfree(va
.va_name
, MAXPATHLEN
);
2079 kfree(fullpathptr
, MAXPATHLEN
);
2081 vnode_putname(vname
);
2082 if (ab
.base
!= NULL
)
2083 FREE(ab
.base
, M_TEMP
);
2084 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
2085 kauth_acl_free(va
.va_acl
);
2087 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
2092 fgetattrlist(proc_t p
, struct fgetattrlist_args
*uap
, __unused
int32_t *retval
)
2094 struct vfs_context
*ctx
;
2097 struct getattrlist_args ap
;
2099 ctx
= vfs_context_current();
2102 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2105 if ((error
= vnode_getwithref(vp
)) != 0) {
2111 ap
.alist
= uap
->alist
;
2112 ap
.attributeBuffer
= uap
->attributeBuffer
;
2113 ap
.bufferSize
= uap
->bufferSize
;
2114 ap
.options
= uap
->options
;
2116 /* Default to using the vnode's name. */
2117 error
= getattrlist_internal(vp
, &ap
, NULL
, p
, ctx
);
2127 getattrlist(proc_t p
, struct getattrlist_args
*uap
, __unused
int32_t *retval
)
2129 struct vfs_context
*ctx
;
2130 struct nameidata nd
;
2135 ctx
= vfs_context_current();
2141 nameiflags
= NOTRIGGER
| AUDITVNPATH1
;
2142 if (!(uap
->options
& FSOPT_NOFOLLOW
))
2143 nameiflags
|= FOLLOW
;
2144 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2146 if ((error
= namei(&nd
)) != 0) {
2147 /* vp is still uninitialized */
2152 /* Pass along our componentname to getattrlist_internal */
2153 error
= getattrlist_internal(vp
, uap
, &(nd
.ni_cnd
), p
, ctx
);
2155 /* Retain the namei reference until the getattrlist completes. */
2164 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
2166 /* make sure we have enough source data */
2167 if ((*cursor
) + size
> end
)
2170 bcopy(*cursor
, buf
, size
);
2175 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
2176 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
2177 #define ATTR_UNPACK_TIME(v, is64) \
2180 struct user64_timespec us; \
2182 v.tv_sec = us.tv_sec; \
2183 v.tv_nsec = us.tv_nsec; \
2185 struct user32_timespec us; \
2187 v.tv_sec = us.tv_sec; \
2188 v.tv_nsec = us.tv_nsec; \
2197 setattrlist_internal(vnode_t vp
, struct setattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
2200 struct vnode_attr va
;
2201 struct attrreference ar
;
2202 kauth_action_t action
;
2203 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
2204 int proc_is64
, error
;
2206 kauth_filesec_t rfsec
;
2212 proc_is64
= proc_is64bit(p
);
2216 * Fetch the attribute set and validate.
2218 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
2220 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
2225 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
2226 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
2227 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
2230 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
2231 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
2235 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
2239 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
2240 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
2241 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
2242 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
2244 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
2250 * If the caller's bitmaps indicate that there are no attributes to set,
2251 * then exit early. In particular, we want to avoid the MALLOC below
2252 * since the caller's bufferSize could be zero, and MALLOC of zero bytes
2253 * returns a NULL pointer, which would cause setattrlist to return ENOMEM.
2255 if (al
.commonattr
== 0 &&
2256 (al
.volattr
& ~ATTR_VOL_INFO
) == 0 &&
2265 * Make the naive assumption that the caller has supplied a reasonable buffer
2266 * size. We could be more careful by pulling in the fixed-size region, checking
2267 * the attrref structures, then pulling in the variable section.
2268 * We need to reconsider this for handling large ACLs, as they should probably be
2269 * brought directly into a buffer. Multiple copyins will make this slower though.
2271 * We could also map the user buffer if it is larger than some sensible mimimum.
2273 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
2274 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
2278 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
2279 if (user_buf
== NULL
) {
2280 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
2284 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
2285 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
2288 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
2291 error
= mac_vnode_check_setattrlist(ctx
, vp
, &al
);
2297 * Unpack the argument buffer.
2300 bufend
= cursor
+ uap
->bufferSize
;
2303 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
2304 ATTR_UNPACK(va
.va_encoding
);
2305 VATTR_SET_ACTIVE(&va
, va_encoding
);
2307 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
2308 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
2309 VATTR_SET_ACTIVE(&va
, va_create_time
);
2311 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
2312 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
2313 VATTR_SET_ACTIVE(&va
, va_modify_time
);
2315 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
2316 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
2317 VATTR_SET_ACTIVE(&va
, va_change_time
);
2319 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
2320 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
2321 VATTR_SET_ACTIVE(&va
, va_access_time
);
2323 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
2324 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
2325 VATTR_SET_ACTIVE(&va
, va_backup_time
);
2327 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
2328 if ((cursor
+ 32) > bufend
) {
2330 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
2336 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
2337 ATTR_UNPACK(va
.va_uid
);
2338 VATTR_SET_ACTIVE(&va
, va_uid
);
2340 if (al
.commonattr
& ATTR_CMN_GRPID
) {
2341 ATTR_UNPACK(va
.va_gid
);
2342 VATTR_SET_ACTIVE(&va
, va_gid
);
2344 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
2345 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
2346 VATTR_SET_ACTIVE(&va
, va_mode
);
2348 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
2349 ATTR_UNPACK(va
.va_flags
);
2350 VATTR_SET_ACTIVE(&va
, va_flags
);
2352 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
2355 * We are (for now) passed a kauth_filesec_t, but all we want from
2360 if (ar
.attr_dataoffset
< 0) {
2361 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied", ar
.attr_dataoffset
);
2366 cp
+= ar
.attr_dataoffset
;
2367 rfsec
= (kauth_filesec_t
)cp
;
2368 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) || /* no space for acl */
2369 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
2370 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
2371 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
2373 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
2376 nace
= rfsec
->fsec_entrycount
;
2377 if (nace
== KAUTH_FILESEC_NOACL
)
2379 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2381 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
2384 nace
= rfsec
->fsec_acl
.acl_entrycount
;
2385 if (nace
== KAUTH_FILESEC_NOACL
) {
2387 VATTR_SET(&va
, va_acl
, NULL
);
2390 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2392 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
2395 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
2398 if (al
.commonattr
& ATTR_CMN_UUID
) {
2399 ATTR_UNPACK(va
.va_uuuid
);
2400 VATTR_SET_ACTIVE(&va
, va_uuuid
);
2402 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
2403 ATTR_UNPACK(va
.va_guuid
);
2404 VATTR_SET_ACTIVE(&va
, va_guuid
);
2408 if (al
.volattr
& ATTR_VOL_INFO
) {
2409 if (al
.volattr
& ATTR_VOL_NAME
) {
2412 /* attr_length cannot be 0! */
2413 if ((ar
.attr_dataoffset
< 0) || (ar
.attr_length
== 0)) {
2414 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad offset supplied (2) ", ar
.attr_dataoffset
);
2419 volname
+= ar
.attr_dataoffset
;
2420 if ((volname
+ ar
.attr_length
) > bufend
) {
2422 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
2425 /* guarantee NUL termination */
2426 volname
[ar
.attr_length
- 1] = 0;
2431 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
2432 /* XXX does it actually make any sense to change this? */
2434 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
2439 * Validate and authorize.
2442 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) {
2443 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
2447 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
2448 * and will be auth'ed by the FS.
2450 if (fndrinfo
!= NULL
) {
2451 if (al
.volattr
& ATTR_VOL_INFO
) {
2452 if (vp
->v_tag
!= VT_HFS
) {
2457 action
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
2461 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2462 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
2467 * When we're setting both the access mask and the finder info, then
2468 * check if were about to remove write access for the owner. Since
2469 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
2470 * to consider their ordering.
2472 * If were about to remove write access for the owner we'll set the
2473 * Finder Info here before vnode_setattr. Otherwise we'll set it
2474 * after vnode_setattr since it may be adding owner write access.
2476 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
2477 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
2478 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2481 fndrinfo
= NULL
; /* it was set here so skip setting below */
2485 * Write the attributes if we have any.
2487 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, ctx
)) != 0)) {
2488 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
2493 * Write the Finder Info if we have any.
2495 if (fndrinfo
!= NULL
) {
2496 if (al
.volattr
& ATTR_VOL_INFO
) {
2497 if (vp
->v_tag
== VT_HFS
) {
2498 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
);
2502 /* XXX should never get here */
2504 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2510 * Set the volume name, if we have one
2512 if (volname
!= NULL
)
2518 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
2519 VFSATTR_WANTED(&vs
, f_vol_name
);
2522 error
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
);
2527 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
2528 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
2532 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
2534 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
2539 /* all done and successful */
2542 if (user_buf
!= NULL
)
2543 FREE(user_buf
, M_TEMP
);
2544 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);
2549 setattrlist(proc_t p
, struct setattrlist_args
*uap
, __unused
int32_t *retval
)
2551 struct vfs_context
*ctx
;
2552 struct nameidata nd
;
2557 ctx
= vfs_context_current();
2562 nameiflags
= AUDITVNPATH1
;
2563 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
2564 nameiflags
|= FOLLOW
;
2565 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2566 if ((error
= namei(&nd
)) != 0)
2571 error
= setattrlist_internal(vp
, uap
, p
, ctx
);
2579 fsetattrlist(proc_t p
, struct fsetattrlist_args
*uap
, __unused
int32_t *retval
)
2581 struct vfs_context
*ctx
;
2584 struct setattrlist_args ap
;
2586 ctx
= vfs_context_current();
2588 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2591 if ((error
= vnode_getwithref(vp
)) != 0) {
2597 ap
.alist
= uap
->alist
;
2598 ap
.attributeBuffer
= uap
->attributeBuffer
;
2599 ap
.bufferSize
= uap
->bufferSize
;
2600 ap
.options
= uap
->options
;
2602 error
= setattrlist_internal(vp
, &ap
, p
, ctx
);