2 * Copyright (c) 1995-2010 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 * Pack (count) bytes from (source) into (buf).
78 attrlist_pack_fixed(struct _attrlist_buf
*ab
, void *source
, ssize_t count
)
82 /* how much room left in the buffer? */
83 fit
= imin(count
, ab
->allocated
- (ab
->fixedcursor
- ab
->base
));
85 bcopy(source
, ab
->fixedcursor
, fit
);
87 /* always move in increments of 4 */
88 ab
->fixedcursor
+= roundup(count
, 4);
91 attrlist_pack_variable2(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
, const void *ext
, ssize_t extcount
)
93 struct attrreference ar
;
96 /* pack the reference to the variable object */
97 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
98 ar
.attr_length
= count
+ extcount
;
99 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
101 /* calculate space and pack the variable object */
102 fit
= imin(count
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
105 bcopy(source
, ab
->varcursor
, fit
);
106 ab
->varcursor
+= fit
;
108 fit
= imin(extcount
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
111 bcopy(ext
, ab
->varcursor
, fit
);
112 ab
->varcursor
+= fit
;
114 /* always move in increments of 4 */
115 ab
->varcursor
= (char *)roundup((uintptr_t)ab
->varcursor
, 4);
118 attrlist_pack_variable(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
)
120 attrlist_pack_variable2(ab
, source
, count
, NULL
, 0);
123 attrlist_pack_string(struct _attrlist_buf
*ab
, const char *source
, ssize_t count
)
125 struct attrreference ar
;
130 * Supplied count is character count of string text, excluding trailing nul
131 * which we always supply here.
133 if (source
== NULL
) {
135 } else if (count
== 0) {
136 count
= strlen(source
);
140 * Make the reference and pack it.
141 * Note that this is entirely independent of how much we get into
144 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
145 ar
.attr_length
= count
+ 1;
146 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
148 /* calculate how much of the string text we can copy, and do that */
149 space
= ab
->allocated
- (ab
->varcursor
- ab
->base
);
150 fit
= imin(count
, space
);
152 bcopy(source
, ab
->varcursor
, fit
);
153 /* is there room for our trailing nul? */
155 ab
->varcursor
[fit
] = '\0';
157 /* always move in increments of 4 */
158 ab
->varcursor
+= roundup(count
+ 1, 4);
161 #define ATTR_PACK4(AB, V) \
163 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \
164 *(uint32_t *)AB.fixedcursor = V; \
165 AB.fixedcursor += 4; \
169 #define ATTR_PACK8(AB, V) \
171 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
172 *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \
173 AB.fixedcursor += 8; \
177 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
178 #define ATTR_PACK_CAST(b, t, v) \
184 #define ATTR_PACK_TIME(b, v, is64) \
187 struct user64_timespec us = {v.tv_sec, v.tv_nsec}; \
190 struct user32_timespec us = {v.tv_sec, v.tv_nsec}; \
197 * Table-driven setup for all valid common/volume attributes.
199 struct getvolattrlist_attrtab
{
202 #define VFSATTR_BIT(b) (VFSATTR_ ## b)
205 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = {
206 {ATTR_CMN_NAME
, 0, sizeof(struct attrreference
)},
207 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
)},
208 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
)},
209 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
)},
210 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
)},
211 {ATTR_CMN_OBJID
, 0, sizeof(fsobj_id_t
)},
212 {ATTR_CMN_OBJPERMANENTID
, 0, sizeof(fsobj_id_t
)},
213 {ATTR_CMN_PAROBJID
, 0, sizeof(fsobj_id_t
)},
214 {ATTR_CMN_SCRIPT
, 0, sizeof(text_encoding_t
)},
215 {ATTR_CMN_CRTIME
, VFSATTR_BIT(f_create_time
), ATTR_TIME_SIZE
},
216 {ATTR_CMN_MODTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
217 {ATTR_CMN_CHGTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
218 {ATTR_CMN_ACCTIME
, VFSATTR_BIT(f_access_time
), ATTR_TIME_SIZE
},
219 {ATTR_CMN_BKUPTIME
, VFSATTR_BIT(f_backup_time
), ATTR_TIME_SIZE
},
220 {ATTR_CMN_FNDRINFO
, 0, 32},
221 {ATTR_CMN_OWNERID
, 0, sizeof(uid_t
)},
222 {ATTR_CMN_GRPID
, 0, sizeof(gid_t
)},
223 {ATTR_CMN_ACCESSMASK
, 0, sizeof(uint32_t)},
224 {ATTR_CMN_FLAGS
, 0, sizeof(uint32_t)},
225 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t)},
226 {ATTR_CMN_EXTENDED_SECURITY
, 0, sizeof(struct attrreference
)},
227 {ATTR_CMN_UUID
, 0, sizeof(guid_t
)},
228 {ATTR_CMN_GRPUUID
, 0, sizeof(guid_t
)},
229 {ATTR_CMN_FILEID
, 0, sizeof(uint64_t)},
230 {ATTR_CMN_PARENTID
, 0, sizeof(uint64_t)},
231 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
)},
234 #define ATTR_CMN_VOL_INVALID \
235 (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \
236 ATTR_CMN_FILEID | ATTR_CMN_PARENTID)
238 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = {
239 {ATTR_VOL_FSTYPE
, 0, sizeof(uint32_t)},
240 {ATTR_VOL_SIGNATURE
, VFSATTR_BIT(f_signature
), sizeof(uint32_t)},
241 {ATTR_VOL_SIZE
, VFSATTR_BIT(f_blocks
), sizeof(off_t
)},
242 {ATTR_VOL_SPACEFREE
, VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
243 {ATTR_VOL_SPACEAVAIL
, VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
244 {ATTR_VOL_MINALLOCATION
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
245 {ATTR_VOL_ALLOCATIONCLUMP
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
246 {ATTR_VOL_IOBLOCKSIZE
, VFSATTR_BIT(f_iosize
), sizeof(uint32_t)},
247 {ATTR_VOL_OBJCOUNT
, VFSATTR_BIT(f_objcount
), sizeof(uint32_t)},
248 {ATTR_VOL_FILECOUNT
, VFSATTR_BIT(f_filecount
), sizeof(uint32_t)},
249 {ATTR_VOL_DIRCOUNT
, VFSATTR_BIT(f_dircount
), sizeof(uint32_t)},
250 {ATTR_VOL_MAXOBJCOUNT
, VFSATTR_BIT(f_maxobjcount
), sizeof(uint32_t)},
251 {ATTR_VOL_MOUNTPOINT
, 0, sizeof(struct attrreference
)},
252 {ATTR_VOL_NAME
, VFSATTR_BIT(f_vol_name
), sizeof(struct attrreference
)},
253 {ATTR_VOL_MOUNTFLAGS
, 0, sizeof(uint32_t)},
254 {ATTR_VOL_MOUNTEDDEVICE
, 0, sizeof(struct attrreference
)},
255 {ATTR_VOL_ENCODINGSUSED
, 0, sizeof(uint64_t)},
256 {ATTR_VOL_CAPABILITIES
, VFSATTR_BIT(f_capabilities
), sizeof(vol_capabilities_attr_t
)},
257 {ATTR_VOL_UUID
, VFSATTR_BIT(f_uuid
), sizeof(uuid_t
)},
258 {ATTR_VOL_ATTRIBUTES
, VFSATTR_BIT(f_attributes
), sizeof(vol_attributes_attr_t
)},
259 {ATTR_VOL_INFO
, 0, 0},
264 getvolattrlist_parsetab(struct getvolattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vfs_attr
*vsp
,
265 ssize_t
*sizep
, int is_64bit
)
267 attrgroup_t recognised
;
271 /* is this attribute set? */
272 if (tab
->attr
& attrs
) {
273 recognised
|= tab
->attr
;
274 vsp
->f_active
|= tab
->bits
;
275 if (tab
->size
== ATTR_TIME_SIZE
) {
277 *sizep
+= sizeof(struct user64_timespec
);
279 *sizep
+= sizeof(struct user32_timespec
);
285 } while ((++tab
)->attr
!= 0);
287 /* check to make sure that we recognised all of the passed-in attributes */
288 if (attrs
& ~recognised
)
294 * Given the attributes listed in alp, configure vap to request
295 * the data from a filesystem.
298 getvolattrlist_setupvfsattr(struct attrlist
*alp
, struct vfs_attr
*vsp
, ssize_t
*sizep
, int is_64bit
)
303 * Parse the above tables.
305 *sizep
= sizeof(uint32_t); /* length count */
306 if (alp
->commonattr
) {
307 if ((alp
->commonattr
& ATTR_CMN_VOL_INVALID
) &&
308 (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
) == 0) {
311 if ((error
= getvolattrlist_parsetab(getvolattrlist_common_tab
,
312 alp
->commonattr
, vsp
, sizep
,
318 (error
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
)) != 0)
325 * Given the attributes listed in asp and those supported
326 * in the vsp, fixup the asp attributes to reflect any
327 * missing attributes from the file system
330 getvolattrlist_fixupattrs(attribute_set_t
*asp
, struct vfs_attr
*vsp
)
332 struct getvolattrlist_attrtab
*tab
;
334 if (asp
->commonattr
) {
335 tab
= getvolattrlist_common_tab
;
337 if ((tab
->attr
& asp
->commonattr
) &&
339 ((tab
->bits
& vsp
->f_supported
) == 0)) {
340 asp
->commonattr
&= ~tab
->attr
;
342 } while ((++tab
)->attr
!= 0);
345 tab
= getvolattrlist_vol_tab
;
347 if ((tab
->attr
& asp
->volattr
) &&
349 ((tab
->bits
& vsp
->f_supported
) == 0)) {
350 asp
->volattr
&= ~tab
->attr
;
352 } while ((++tab
)->attr
!= 0);
357 * Table-driven setup for all valid common/dir/file/fork attributes against files.
359 struct getattrlist_attrtab
{
362 #define VATTR_BIT(b) (VNODE_ATTR_ ## b)
364 kauth_action_t action
;
368 * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this
369 * information, and we will synthesize it at the VFS level.
371 static struct getattrlist_attrtab getattrlist_common_tab
[] = {
372 {ATTR_CMN_NAME
, VATTR_BIT(va_name
), sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
373 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
374 {ATTR_CMN_FSID
, VATTR_BIT(va_fsid
), sizeof(fsid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
375 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
376 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
377 {ATTR_CMN_OBJID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
378 {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
379 {ATTR_CMN_PAROBJID
, VATTR_BIT(va_parentid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
380 {ATTR_CMN_SCRIPT
, VATTR_BIT(va_encoding
), sizeof(text_encoding_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
381 {ATTR_CMN_CRTIME
, VATTR_BIT(va_create_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
382 {ATTR_CMN_MODTIME
, VATTR_BIT(va_modify_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
383 {ATTR_CMN_CHGTIME
, VATTR_BIT(va_change_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
384 {ATTR_CMN_ACCTIME
, VATTR_BIT(va_access_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
385 {ATTR_CMN_BKUPTIME
, VATTR_BIT(va_backup_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
386 {ATTR_CMN_FNDRINFO
, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES
},
387 {ATTR_CMN_OWNERID
, VATTR_BIT(va_uid
), sizeof(uid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
388 {ATTR_CMN_GRPID
, VATTR_BIT(va_gid
), sizeof(gid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
389 {ATTR_CMN_ACCESSMASK
, VATTR_BIT(va_mode
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
390 {ATTR_CMN_FLAGS
, VATTR_BIT(va_flags
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
391 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
392 {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
), sizeof(struct attrreference
), KAUTH_VNODE_READ_SECURITY
},
393 {ATTR_CMN_UUID
, VATTR_BIT(va_uuuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
394 {ATTR_CMN_GRPUUID
, VATTR_BIT(va_guuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
395 {ATTR_CMN_FILEID
, VATTR_BIT(va_fileid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
396 {ATTR_CMN_PARENTID
, VATTR_BIT(va_parentid
), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES
},
397 {ATTR_CMN_FULLPATH
, 0, sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
398 {ATTR_CMN_ADDEDTIME
, VATTR_BIT(va_addedtime
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
399 {ATTR_CMN_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
), 0},
403 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
404 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_dirlinkcount
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
405 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
406 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
409 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
410 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
411 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
412 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
413 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
414 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
415 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
416 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
417 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
418 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
423 * The following are attributes that VFS can derive.
425 * A majority of them are the same attributes that are required for stat(2) and statfs(2).
427 #define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
428 ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
429 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
430 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
431 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
432 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
433 ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
435 #define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
436 ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
437 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
438 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
439 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
440 ATTR_CMN_FNDRINFO | \
441 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
442 ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
443 ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
444 ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS)
446 #define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
448 #define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
449 ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
450 ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
451 ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
452 ATTR_FILE_RSRCALLOCSIZE)
455 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vnode_attr
*vap
,
456 ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
)
458 attrgroup_t recognised
;
462 /* is this attribute set? */
463 if (tab
->attr
& attrs
) {
464 recognised
|= tab
->attr
;
465 vap
->va_active
|= tab
->bits
;
466 if (tab
->size
== ATTR_TIME_SIZE
) {
468 *sizep
+= sizeof(struct user64_timespec
);
470 *sizep
+= sizeof(struct user32_timespec
);
475 *actionp
|= tab
->action
;
476 if (attrs
== recognised
)
477 break; /* all done, get out */
479 } while ((++tab
)->attr
!= 0);
481 /* check to make sure that we recognised all of the passed-in attributes */
482 if (attrs
& ~recognised
)
488 * Given the attributes listed in alp, configure vap to request
489 * the data from a filesystem.
492 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
)
497 * Parse the above tables.
499 *sizep
= sizeof(uint32_t); /* length count */
501 if (alp
->commonattr
&&
502 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
504 if (isdir
&& alp
->dirattr
&&
505 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
507 if (!isdir
&& alp
->fileattr
&&
508 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
515 * Given the attributes listed in asp and those supported
516 * in the vap, fixup the asp attributes to reflect any
517 * missing attributes from the file system
520 getattrlist_fixupattrs(attribute_set_t
*asp
, struct vnode_attr
*vap
)
522 struct getattrlist_attrtab
*tab
;
524 if (asp
->commonattr
) {
525 tab
= getattrlist_common_tab
;
528 * This if() statement is slightly confusing. We're trying to
529 * iterate through all of the bits listed in the array
530 * getattr_common_tab, and see if the filesystem was expected
531 * to support it, and whether or not we need to do anything about this.
533 * This array is full of structs that have 4 fields (attr, bits, size, action).
534 * The first is used to store the ATTR_CMN_* bit that was being requested
535 * from userland. The second stores the VATTR_BIT corresponding to the field
536 * filled in vnode_attr struct. If it is 0, then we don't typically expect
537 * the filesystem to fill in this field. The third is the size of the field,
538 * and the fourth is the type of kauth actions needed.
540 * So, for all of the ATTR_CMN bits listed in this array, we iterate through
541 * them, and check to see if it was both passed down to the filesystem via the
542 * va_active bitfield, and whether or not we expect it to be emitted from
543 * the filesystem. If it wasn't supported, then we un-twiddle the bit and move
544 * on. This is done so that we can uncheck those bits and re-request
545 * a vnode_getattr from the filesystem again.
548 if ((tab
->attr
& asp
->commonattr
) &&
549 (tab
->bits
& vap
->va_active
) &&
550 (tab
->bits
& vap
->va_supported
) == 0) {
551 asp
->commonattr
&= ~tab
->attr
;
553 } while ((++tab
)->attr
!= 0);
556 tab
= getattrlist_dir_tab
;
558 if ((tab
->attr
& asp
->dirattr
) &&
559 (tab
->bits
& vap
->va_active
) &&
560 (vap
->va_supported
& tab
->bits
) == 0) {
561 asp
->dirattr
&= ~tab
->attr
;
563 } while ((++tab
)->attr
!= 0);
566 tab
= getattrlist_file_tab
;
568 if ((tab
->attr
& asp
->fileattr
) &&
569 (tab
->bits
& vap
->va_active
) &&
570 (vap
->va_supported
& tab
->bits
) == 0) {
571 asp
->fileattr
&= ~tab
->attr
;
573 } while ((++tab
)->attr
!= 0);
578 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
581 char uio_buf
[UIO_SIZEOF(1)];
584 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
587 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
588 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
593 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
594 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
602 * Find something resembling a terminal component name in the mountedonname for vp
606 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
612 * We're looking for the last sequence of non / characters, but
613 * not including any trailing / characters.
618 for (cp
= mn
; *cp
!= 0; cp
++) {
620 /* start of run of chars */
626 /* end of run of chars */
633 /* need to close run? */
640 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
,
641 vfs_context_t ctx
, int is_64bit
)
644 struct vnode_attr va
;
645 struct _attrlist_buf ab
;
647 ssize_t fixedsize
, varsize
;
648 const char *cnp
= NULL
; /* protected by ATTR_CMN_NAME */
649 ssize_t cnl
= 0; /* protected by ATTR_CMN_NAME */
658 vs
.f_vol_name
= NULL
;
661 /* Check for special packing semantics */
662 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
);
663 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
665 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
670 /* Keep invalid attrs from being uninitialized */
671 bzero(&vs
, sizeof (vs
));
672 /* Generate a valid mask for post processing */
673 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
677 * For now, the vnode must be the root of its filesystem.
678 * To relax this, we need to be able to find the root vnode of a filesystem
679 * from any vnode in the filesystem.
681 if (!vnode_isvroot(vp
)) {
683 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
688 * Set up the vfs_attr structure and call the filesystem.
690 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
691 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
694 if (vs
.f_active
!= 0) {
695 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
696 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
697 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
698 if (vs
.f_vol_name
== NULL
) {
700 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
706 error
= mac_mount_check_getattr(ctx
, mnt
, &vs
);
710 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
711 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
712 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
717 * Did we ask for something the filesystem doesn't support?
719 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
720 /* default value for volume subtype */
721 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
722 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
723 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
726 * If the file system didn't supply f_signature, then
727 * default it to 'BD', which is the generic signature
728 * that most Carbon file systems should return.
730 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
731 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
732 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
734 /* default for block size */
735 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
736 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
737 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
739 /* default value for volume f_attributes */
740 if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
)
741 && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) {
742 vol_attributes_attr_t
*attrp
= &vs
.f_attributes
;
744 attrp
->validattr
.commonattr
= VFS_DFLT_ATTR_CMN
;
745 attrp
->validattr
.volattr
= VFS_DFLT_ATTR_VOL
;
746 attrp
->validattr
.dirattr
= VFS_DFLT_ATTR_DIR
;
747 attrp
->validattr
.fileattr
= VFS_DFLT_ATTR_FILE
;
748 attrp
->validattr
.forkattr
= 0;
750 attrp
->nativeattr
.commonattr
= 0;
751 attrp
->nativeattr
.volattr
= 0;
752 attrp
->nativeattr
.dirattr
= 0;
753 attrp
->nativeattr
.fileattr
= 0;
754 attrp
->nativeattr
.forkattr
= 0;
755 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
);
758 /* default value for volume f_capabilities */
759 if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) {
760 /* getattrlist is always supported now. */
761 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) {
762 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0;
763 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
764 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
765 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
767 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0;
768 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
769 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
770 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
771 VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
);
774 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
775 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
776 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
780 /* check to see if our fixups were enough */
781 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
784 /* Fix up valid mask for post processing */
785 getvolattrlist_fixupattrs(&ab
.valid
, &vs
);
787 /* Force packing of everything asked for */
788 vs
.f_supported
= vs
.f_active
;
790 /* Adjust the requested attributes */
791 getvolattrlist_fixupattrs((attribute_set_t
*)&alp
->commonattr
, &vs
);
802 * Some fields require data from the root vp
804 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
805 VATTR_WANTED(&va
, va_uid
);
806 VATTR_WANTED(&va
, va_gid
);
807 VATTR_WANTED(&va
, va_mode
);
808 VATTR_WANTED(&va
, va_flags
);
809 VATTR_WANTED(&va
, va_encoding
);
811 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
812 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
816 if (VATTR_IS_ACTIVE(&va
, va_encoding
) &&
817 !VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
818 if (!return_valid
|| pack_invalid
)
819 /* use kTextEncodingMacUnicode */
820 VATTR_RETURN(&va
, va_encoding
, 0x7e);
822 /* don't use a default */
823 alp
->commonattr
&= ~ATTR_CMN_SCRIPT
;
828 * Compute variable-size buffer requirements.
831 if (alp
->commonattr
& ATTR_CMN_NAME
) {
832 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
833 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
834 /* special case for boot volume. Use root name when it's
835 * available (which is the volume name) or just the mount on
836 * name of "/". we must do this for binary compatibility with
837 * pre Tiger code. returning nothing for the boot volume name
838 * breaks installers - 3961058
840 cnp
= vnode_getname(vp
);
842 /* just use "/" as name */
843 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
851 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
853 if (alp
->commonattr
& ATTR_CMN_NAME
)
854 varsize
+= roundup(cnl
+ 1, 4);
856 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
857 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
858 if (alp
->volattr
& ATTR_VOL_NAME
) {
859 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
860 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
862 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
863 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
866 * Allocate a target buffer for attribute results.
867 * Note that since we won't ever copy out more than the caller requested,
868 * we never need to allocate more than they offer.
870 ab
.allocated
= imin(uap
->bufferSize
, fixedsize
+ varsize
);
871 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
873 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
876 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
877 if (ab
.base
== NULL
) {
879 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
884 * Pack results into the destination buffer.
886 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
888 ab
.fixedcursor
+= sizeof (attribute_set_t
);
889 bzero(&ab
.actual
, sizeof (ab
.actual
));
891 ab
.varcursor
= ab
.base
+ fixedsize
;
892 ab
.needed
= fixedsize
+ varsize
;
894 /* common attributes **************************************************/
895 if (alp
->commonattr
& ATTR_CMN_NAME
) {
896 attrlist_pack_string(&ab
, cnp
, cnl
);
897 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
899 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
900 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
901 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
903 if (alp
->commonattr
& ATTR_CMN_FSID
) {
904 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
);
905 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
907 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
908 if (!return_valid
|| pack_invalid
)
911 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
912 ATTR_PACK4(ab
, vp
->v_tag
);
913 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
915 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
916 if (!return_valid
|| pack_invalid
) {
917 fsobj_id_t f
= {0, 0};
921 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
922 if (!return_valid
|| pack_invalid
) {
923 fsobj_id_t f
= {0, 0};
927 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
928 if (!return_valid
|| pack_invalid
) {
929 fsobj_id_t f
= {0, 0};
933 /* note that this returns the encoding for the volume name, not the node name */
934 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
935 ATTR_PACK4(ab
, va
.va_encoding
);
936 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
938 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
939 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
);
940 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
942 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
943 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
944 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
946 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
947 if (!return_valid
|| pack_invalid
)
948 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
950 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
951 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
);
952 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
954 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
955 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
);
956 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
958 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
961 * This attribute isn't really Finder Info, at least for HFS.
963 if (vp
->v_tag
== VT_HFS
) {
964 error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
);
966 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
967 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
968 } else if (!return_valid
) {
971 } else if (!return_valid
|| pack_invalid
) {
972 /* XXX we could at least pass out the volume UUID here */
973 bzero(&f
, sizeof(f
));
974 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
977 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
978 ATTR_PACK4(ab
, va
.va_uid
);
979 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
981 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
982 ATTR_PACK4(ab
, va
.va_gid
);
983 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
985 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
986 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
987 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
989 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
990 ATTR_PACK4(ab
, va
.va_flags
);
991 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
993 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
995 if (vnode_isdir(vp
)) {
996 if (vnode_authorize(vp
, NULL
,
997 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
999 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1001 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1004 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1006 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1008 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1013 * Rather than MAC preceding DAC, in this case we want
1014 * the smallest set of permissions granted by both MAC & DAC
1015 * checks. We won't add back any permissions.
1018 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1021 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1024 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1027 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
1028 ATTR_PACK4(ab
, perms
);
1029 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1032 * The following common volume attributes are only
1033 * packed when the pack_invalid mode is enabled.
1038 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
)
1039 attrlist_pack_variable(&ab
, NULL
, 0);
1040 if (alp
->commonattr
& ATTR_CMN_UUID
)
1041 ATTR_PACK(&ab
, kauth_null_guid
);
1042 if (alp
->commonattr
& ATTR_CMN_GRPUUID
)
1043 ATTR_PACK(&ab
, kauth_null_guid
);
1044 if (alp
->commonattr
& ATTR_CMN_FILEID
)
1045 ATTR_PACK8(ab
, fid
);
1046 if (alp
->commonattr
& ATTR_CMN_PARENTID
)
1047 ATTR_PACK8(ab
, fid
);
1050 /* volume attributes **************************************************/
1052 if (alp
->volattr
& ATTR_VOL_FSTYPE
) {
1053 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
1054 ab
.actual
.volattr
|= ATTR_VOL_FSTYPE
;
1056 if (alp
->volattr
& ATTR_VOL_SIGNATURE
) {
1057 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
1058 ab
.actual
.volattr
|= ATTR_VOL_SIGNATURE
;
1060 if (alp
->volattr
& ATTR_VOL_SIZE
) {
1061 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
1062 ab
.actual
.volattr
|= ATTR_VOL_SIZE
;
1064 if (alp
->volattr
& ATTR_VOL_SPACEFREE
) {
1065 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
1066 ab
.actual
.volattr
|= ATTR_VOL_SPACEFREE
;
1068 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
) {
1069 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
1070 ab
.actual
.volattr
|= ATTR_VOL_SPACEAVAIL
;
1072 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
) {
1073 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
1074 ab
.actual
.volattr
|= ATTR_VOL_MINALLOCATION
;
1076 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
) {
1077 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
1078 ab
.actual
.volattr
|= ATTR_VOL_ALLOCATIONCLUMP
;
1080 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
) {
1081 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
1082 ab
.actual
.volattr
|= ATTR_VOL_IOBLOCKSIZE
;
1084 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
) {
1085 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
1086 ab
.actual
.volattr
|= ATTR_VOL_OBJCOUNT
;
1088 if (alp
->volattr
& ATTR_VOL_FILECOUNT
) {
1089 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
1090 ab
.actual
.volattr
|= ATTR_VOL_FILECOUNT
;
1092 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
) {
1093 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
1094 ab
.actual
.volattr
|= ATTR_VOL_DIRCOUNT
;
1096 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
) {
1097 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
1098 ab
.actual
.volattr
|= ATTR_VOL_MAXOBJCOUNT
;
1100 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
) {
1101 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
1102 ab
.actual
.volattr
|= ATTR_VOL_MOUNTPOINT
;
1104 if (alp
->volattr
& ATTR_VOL_NAME
) {
1105 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
1106 ab
.actual
.volattr
|= ATTR_VOL_NAME
;
1108 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
) {
1109 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
1110 ab
.actual
.volattr
|= ATTR_VOL_MOUNTFLAGS
;
1112 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
) {
1113 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
1114 ab
.actual
.volattr
|= ATTR_VOL_MOUNTEDDEVICE
;
1116 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
) {
1117 if (!return_valid
|| pack_invalid
)
1118 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
1120 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
1121 /* fix up volume capabilities */
1122 if (vfs_extendedsecurity(mnt
)) {
1123 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1125 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
1127 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1128 ATTR_PACK(&ab
, vs
.f_capabilities
);
1129 ab
.actual
.volattr
|= ATTR_VOL_CAPABILITIES
;
1131 if (alp
->volattr
& ATTR_VOL_UUID
) {
1132 ATTR_PACK(&ab
, vs
.f_uuid
);
1133 ab
.actual
.volattr
|= ATTR_VOL_UUID
;
1135 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
1136 /* fix up volume attribute information */
1138 vs
.f_attributes
.validattr
.commonattr
|= VFS_DFLT_ATTR_CMN
;
1139 vs
.f_attributes
.validattr
.volattr
|= VFS_DFLT_ATTR_VOL
;
1140 vs
.f_attributes
.validattr
.dirattr
|= VFS_DFLT_ATTR_DIR
;
1141 vs
.f_attributes
.validattr
.fileattr
|= VFS_DFLT_ATTR_FILE
;
1143 if (vfs_extendedsecurity(mnt
)) {
1144 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1146 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1147 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1149 ATTR_PACK(&ab
, vs
.f_attributes
);
1150 ab
.actual
.volattr
|= ATTR_VOL_ATTRIBUTES
;
1154 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1155 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1156 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
1157 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1158 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1161 * In the compatible case, we report the smaller of the required and returned sizes.
1162 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1163 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1164 * they gave us, so they can always check for truncation themselves.
1166 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1168 /* Return attribute set output if requested. */
1170 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1172 /* Only report the attributes that are valid */
1173 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1174 ab
.actual
.volattr
&= ab
.valid
.volattr
;
1176 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1178 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
1181 if (vs
.f_vol_name
!= NULL
)
1182 kfree(vs
.f_vol_name
, MAXPATHLEN
);
1186 if (ab
.base
!= NULL
)
1187 FREE(ab
.base
, M_TEMP
);
1188 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1193 * Obtain attribute information about a filesystem object.
1197 getattrlist_internal(vnode_t vp
, struct getattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
1200 struct vnode_attr va
;
1201 struct _attrlist_buf ab
;
1202 kauth_action_t action
;
1203 ssize_t fixedsize
, varsize
;
1205 const char *vname
= NULL
;
1207 ssize_t fullpathlen
;
1216 proc_is64
= proc_is64bit(p
);
1226 * Fetch the attribute request.
1228 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
1230 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1235 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1236 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1237 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1240 error
= mac_vnode_check_getattrlist(ctx
, vp
, &al
);
1246 * It is legal to request volume or file attributes,
1250 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
1252 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
1255 /* handle volume attribute request */
1256 error
= getvolattrlist(vp
, uap
, &al
, ctx
, proc_is64
);
1260 /* Check for special packing semantics */
1261 return_valid
= (al
.commonattr
& ATTR_CMN_RETURNED_ATTRS
);
1262 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
1264 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
1265 if (!return_valid
|| al
.forkattr
) {
1269 /* Keep invalid attrs from being uninitialized */
1270 bzero(&va
, sizeof (va
));
1271 /* Generate a valid mask for post processing */
1272 bcopy(&al
.commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
1275 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
1276 * will have a valid snapshot that we can work from here.
1282 * Set up the vnode_attr structure and authorise.
1284 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64
, (vtype
== VDIR
))) != 0) {
1285 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
1288 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) {
1289 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
1294 * If we're asking for the full path, allocate a buffer for that.
1296 if (al
.commonattr
& (ATTR_CMN_FULLPATH
)) {
1297 fullpathptr
= (char*) kalloc(MAXPATHLEN
);
1298 if (fullpathptr
== NULL
) {
1300 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
1306 if (va
.va_active
!= 0) {
1308 * If we're going to ask for va_name, allocate a buffer to point it at
1310 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
1311 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
1312 if (va
.va_name
== NULL
) {
1314 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
1320 * Call the filesystem.
1322 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
1323 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1327 /* did we ask for something the filesystem doesn't support? */
1328 if (!VATTR_ALL_SUPPORTED(&va
)) {
1331 * There are a couple of special cases. If we are after object IDs,
1332 * we can make do with va_fileid.
1334 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
| ATTR_CMN_FILEID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
1335 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
1338 * Many filesystems don't know their parent object id.
1339 * If necessary, attempt to derive it from the vnode.
1341 if ((al
.commonattr
& (ATTR_CMN_PAROBJID
| ATTR_CMN_PARENTID
)) &&
1342 !VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1345 if ((dvp
= vnode_getparent(vp
)) != NULLVP
) {
1346 struct vnode_attr lva
;
1349 VATTR_WANTED(&lva
, va_fileid
);
1350 if (vnode_getattr(dvp
, &lva
, ctx
) == 0 &&
1351 VATTR_IS_SUPPORTED(&va
, va_fileid
)) {
1352 va
.va_parentid
= lva
.va_fileid
;
1353 VATTR_SET_SUPPORTED(&va
, va_parentid
);
1359 * And we can report datasize/alloc from total.
1361 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
1362 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
1363 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
1364 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
1367 * If we don't have an encoding, go with UTF-8
1369 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) &&
1370 !VATTR_IS_SUPPORTED(&va
, va_encoding
) && !return_valid
)
1371 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
1374 * If we don't have a name, we'll get one from the vnode or mount point.
1376 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
1377 VATTR_CLEAR_ACTIVE(&va
, va_name
);
1380 /* If va_dirlinkcount isn't supported use a default of 1. */
1381 if ((al
.dirattr
& ATTR_DIR_LINKCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_dirlinkcount
)) {
1382 VATTR_RETURN(&va
, va_dirlinkcount
, 1);
1386 if (!VATTR_ALL_SUPPORTED(&va
)) {
1389 /* Fix up valid mask for post processing */
1390 getattrlist_fixupattrs(&ab
.valid
, &va
);
1392 /* Force packing of everything asked for */
1393 va
.va_supported
= va
.va_active
;
1395 /* Adjust the requested attributes */
1396 getattrlist_fixupattrs((attribute_set_t
*)&al
.commonattr
, &va
);
1407 * Compute variable-space requirements.
1409 varsize
= 0; /* length count */
1411 /* We may need to fix up the name attribute if requested */
1412 if (al
.commonattr
& ATTR_CMN_NAME
) {
1413 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
1414 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
1418 if (vnode_isvroot(vp
)) {
1419 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
1420 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
1421 /* special case for boot volume. Use root name when it's
1422 * available (which is the volume name) or just the mount on
1423 * name of "/". we must do this for binary compatibility with
1424 * pre Tiger code. returning nothing for the boot volume name
1425 * breaks installers - 3961058
1427 cnp
= vname
= vnode_getname(vp
);
1429 /* just use "/" as name */
1430 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
1435 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
1438 cnp
= vname
= vnode_getname(vp
);
1445 varsize
+= roundup(cnl
+ 1, 4);
1449 * Compute the full path to this vnode, if necessary. This attribute is almost certainly
1450 * not supported by any filesystem, so build the path to this vnode at this time.
1452 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1453 int len
= MAXPATHLEN
;
1455 /* call build_path making sure NOT to use the cache-only behavior */
1456 err
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current());
1463 fullpathlen
= strlen(fullpathptr
);
1465 varsize
+= roundup(fullpathlen
+1, 4);
1469 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
1471 * XXX This needs to change at some point; since the blob is opaque in
1472 * user-space this is OK.
1474 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
1475 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
1476 (va
.va_acl
!= NULL
))
1477 varsize
+= roundup(KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
), 4);
1480 * Allocate a target buffer for attribute results.
1482 * Note that we won't ever copy out more than the caller requested, even though
1483 * we might have to allocate more than they offer so that the diagnostic checks
1484 * don't result in a panic if the caller's buffer is too small..
1486 ab
.allocated
= fixedsize
+ varsize
;
1487 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1489 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1492 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1493 if (ab
.base
== NULL
) {
1495 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1499 /* set the S_IFMT bits for the mode */
1500 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1501 switch (vp
->v_type
) {
1503 va
.va_mode
|= S_IFREG
;
1506 va
.va_mode
|= S_IFDIR
;
1509 va
.va_mode
|= S_IFBLK
;
1512 va
.va_mode
|= S_IFCHR
;
1515 va
.va_mode
|= S_IFLNK
;
1518 va
.va_mode
|= S_IFSOCK
;
1521 va
.va_mode
|= S_IFIFO
;
1530 * Pack results into the destination buffer.
1532 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1534 ab
.fixedcursor
+= sizeof (attribute_set_t
);
1535 bzero(&ab
.actual
, sizeof (ab
.actual
));
1537 ab
.varcursor
= ab
.base
+ fixedsize
;
1538 ab
.needed
= ab
.allocated
;
1540 /* common attributes **************************************************/
1541 if (al
.commonattr
& ATTR_CMN_NAME
) {
1542 attrlist_pack_string(&ab
, cnp
, cnl
);
1543 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
1545 if (al
.commonattr
& ATTR_CMN_DEVID
) {
1546 ATTR_PACK4(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1547 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
1549 if (al
.commonattr
& ATTR_CMN_FSID
) {
1550 ATTR_PACK8(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1551 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
1553 if (al
.commonattr
& ATTR_CMN_OBJTYPE
) {
1554 ATTR_PACK4(ab
, vtype
);
1555 ab
.actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1557 if (al
.commonattr
& ATTR_CMN_OBJTAG
) {
1558 ATTR_PACK4(ab
, vp
->v_tag
);
1559 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1561 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1564 * Carbon can't deal with us reporting the target ID
1565 * for links. So we ask the filesystem to give us the
1566 * source ID as well, and if it gives us one, we use
1569 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1570 f
.fid_objno
= va
.va_linkid
;
1572 f
.fid_objno
= va
.va_fileid
;
1574 f
.fid_generation
= 0;
1576 ab
.actual
.commonattr
|= ATTR_CMN_OBJID
;
1578 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1581 * Carbon can't deal with us reporting the target ID
1582 * for links. So we ask the filesystem to give us the
1583 * source ID as well, and if it gives us one, we use
1586 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1587 f
.fid_objno
= va
.va_linkid
;
1589 f
.fid_objno
= va
.va_fileid
;
1591 f
.fid_generation
= 0;
1593 ab
.actual
.commonattr
|= ATTR_CMN_OBJPERMANENTID
;
1595 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1598 f
.fid_objno
= va
.va_parentid
; /* could be lossy here! */
1599 f
.fid_generation
= 0;
1601 ab
.actual
.commonattr
|= ATTR_CMN_PAROBJID
;
1603 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1604 if (VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
1605 ATTR_PACK4(ab
, va
.va_encoding
);
1606 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1607 } else if (!return_valid
|| pack_invalid
) {
1608 ATTR_PACK4(ab
, 0x7e);
1611 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1612 ATTR_PACK_TIME(ab
, va
.va_create_time
, proc_is64
);
1613 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1615 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1616 ATTR_PACK_TIME(ab
, va
.va_modify_time
, proc_is64
);
1617 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1619 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1620 ATTR_PACK_TIME(ab
, va
.va_change_time
, proc_is64
);
1621 ab
.actual
.commonattr
|= ATTR_CMN_CHGTIME
;
1623 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1624 ATTR_PACK_TIME(ab
, va
.va_access_time
, proc_is64
);
1625 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1627 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1628 ATTR_PACK_TIME(ab
, va
.va_backup_time
, proc_is64
);
1629 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1632 * They are requesting user access, we should obtain this before getting
1633 * the finder info. For some network file systems this is a performance
1636 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1637 if (vtype
== VDIR
) {
1638 if (vnode_authorize(vp
, NULL
,
1639 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1641 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1643 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1646 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1648 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1650 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1655 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1658 char uio_buf
[UIO_SIZEOF(1)];
1660 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1661 uio_buf
, sizeof(uio_buf
))) == NULL
) {
1665 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1666 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
,
1667 &fisize
, XATTR_NOSECURITY
, ctx
);
1670 * Default to zeros if its not available,
1671 * unless ATTR_CMN_RETURNED_ATTRS was requested.
1674 (!return_valid
|| pack_invalid
) &&
1675 ((error
== ENOATTR
) || (error
== ENOENT
) ||
1676 (error
== ENOTSUP
) || (error
== EPERM
))) {
1677 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1678 bzero(ab
.fixedcursor
, 32);
1682 ab
.fixedcursor
+= 32;
1683 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1684 } else if (!return_valid
) {
1685 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1689 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1690 ATTR_PACK4(ab
, va
.va_uid
);
1691 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1693 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1694 ATTR_PACK4(ab
, va
.va_gid
);
1695 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1697 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1698 ATTR_PACK4(ab
, va
.va_mode
);
1699 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1701 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1702 ATTR_PACK4(ab
, va
.va_flags
);
1703 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1705 /* We already obtain the user access, so just fill in the buffer here */
1706 if (al
.commonattr
& ATTR_CMN_USERACCESS
) {
1709 * Rather than MAC preceding DAC, in this case we want
1710 * the smallest set of permissions granted by both MAC & DAC
1711 * checks. We won't add back any permissions.
1714 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1717 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1720 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1723 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1724 ATTR_PACK4(ab
, perms
);
1725 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1727 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1728 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1729 struct kauth_filesec fsec
;
1731 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1733 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1734 fsec
.fsec_owner
= kauth_null_guid
;
1735 fsec
.fsec_group
= kauth_null_guid
;
1736 attrlist_pack_variable2(&ab
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1737 ab
.actual
.commonattr
|= ATTR_CMN_EXTENDED_SECURITY
;
1738 } else if (!return_valid
|| pack_invalid
) {
1739 attrlist_pack_variable(&ab
, NULL
, 0);
1742 if (al
.commonattr
& ATTR_CMN_UUID
) {
1743 if (VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1744 ATTR_PACK(&ab
, va
.va_uuuid
);
1745 ab
.actual
.commonattr
|= ATTR_CMN_UUID
;
1746 } else if (!return_valid
|| pack_invalid
) {
1747 ATTR_PACK(&ab
, kauth_null_guid
);
1750 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1751 if (VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1752 ATTR_PACK(&ab
, va
.va_guuid
);
1753 ab
.actual
.commonattr
|= ATTR_CMN_GRPUUID
;
1754 } else if (!return_valid
|| pack_invalid
) {
1755 ATTR_PACK(&ab
, kauth_null_guid
);
1758 if (al
.commonattr
& ATTR_CMN_FILEID
) {
1759 ATTR_PACK8(ab
, va
.va_fileid
);
1760 ab
.actual
.commonattr
|= ATTR_CMN_FILEID
;
1762 if (al
.commonattr
& ATTR_CMN_PARENTID
) {
1763 ATTR_PACK8(ab
, va
.va_parentid
);
1764 ab
.actual
.commonattr
|= ATTR_CMN_PARENTID
;
1767 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1768 attrlist_pack_string (&ab
, fullpathptr
, fullpathlen
);
1769 ab
.actual
.commonattr
|= ATTR_CMN_FULLPATH
;
1772 if (al
.commonattr
& ATTR_CMN_ADDEDTIME
) {
1773 ATTR_PACK_TIME(ab
, va
.va_addedtime
, proc_is64
);
1774 ab
.actual
.commonattr
|= ATTR_CMN_ADDEDTIME
;
1778 /* directory attributes *********************************************/
1779 if (al
.dirattr
&& (vtype
== VDIR
)) {
1780 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) { /* full count of entries */
1781 ATTR_PACK4(ab
, (uint32_t)va
.va_dirlinkcount
);
1782 ab
.actual
.dirattr
|= ATTR_DIR_LINKCOUNT
;
1784 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) {
1785 ATTR_PACK4(ab
, (uint32_t)va
.va_nchildren
);
1786 ab
.actual
.dirattr
|= ATTR_DIR_ENTRYCOUNT
;
1788 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
) {
1791 mntstat
= (vp
->v_flag
& VROOT
) ? DIR_MNTSTATUS_MNTPOINT
: 0;
1794 * Report back on active vnode triggers
1795 * that can directly trigger a mount
1797 if (vp
->v_resolve
&&
1798 !(vp
->v_resolve
->vr_flags
& VNT_NO_DIRECT_MOUNT
)) {
1799 mntstat
|= DIR_MNTSTATUS_TRIGGER
;
1802 ATTR_PACK4(ab
, mntstat
);
1803 ab
.actual
.dirattr
|= ATTR_DIR_MOUNTSTATUS
;
1807 /* file attributes **************************************************/
1808 if (al
.fileattr
&& (vtype
!= VDIR
)) {
1811 uint64_t rlength
= 0;
1812 uint64_t ralloc
= 0;
1814 * Pre-fetch the rsrc attributes now so we only get them once.
1815 * Fetch the resource fork size/allocation via xattr interface
1817 if (al
.fileattr
& (ATTR_FILE_TOTALSIZE
| ATTR_FILE_ALLOCSIZE
| ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1818 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, ctx
)) != 0) {
1819 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)|| (error
== EACCES
)) {
1828 if (al
.fileattr
& (ATTR_FILE_RSRCALLOCSIZE
| ATTR_FILE_ALLOCSIZE
)) {
1829 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1833 ralloc
= roundup(rsize
, blksize
);
1837 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
) {
1838 ATTR_PACK4(ab
, (uint32_t)va
.va_nlink
);
1839 ab
.actual
.fileattr
|= ATTR_FILE_LINKCOUNT
;
1842 * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes:
1843 * We infer that if the filesystem does not support va_data_size or va_data_alloc
1844 * it must not know about alternate forks. So when we need to gather
1845 * the total size or total alloc, it's OK to substitute the total size for
1846 * the data size below. This is because it is likely a flat filesystem and we must
1847 * be using AD files to store the rsrc fork and EAs.
1849 * Additionally, note that getattrlist is barred from being called on
1850 * resource fork paths. (Search for CN_ALLOWRSRCFORK). So if the filesystem does
1851 * support va_data_size, it is guaranteed to represent the data fork's size. This
1852 * is an important distinction to make because when we call vnode_getattr on
1853 * an HFS resource fork vnode, to get the size, it will vend out the resource
1854 * fork's size (it only gets the size of the passed-in vnode).
1856 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
) {
1857 uint64_t totalsize
= rlength
;
1859 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1860 totalsize
+= va
.va_data_size
;
1862 totalsize
+= va
.va_total_size
;
1865 ATTR_PACK8(ab
, totalsize
);
1866 ab
.actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
1868 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
) {
1869 uint64_t totalalloc
= ralloc
;
1872 * If data_alloc is supported, then it must represent the
1875 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1876 totalalloc
+= va
.va_data_alloc
;
1879 totalalloc
+= va
.va_total_alloc
;
1882 ATTR_PACK8(ab
, totalalloc
);
1883 ab
.actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
1885 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
) {
1886 ATTR_PACK4(ab
, va
.va_iosize
);
1887 ab
.actual
.fileattr
|= ATTR_FILE_IOBLOCKSIZE
;
1889 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
) {
1890 if (!return_valid
|| pack_invalid
) {
1891 ATTR_PACK4(ab
, 0); /* this value is deprecated */
1892 ab
.actual
.fileattr
|= ATTR_FILE_CLUMPSIZE
;
1895 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1898 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1899 if (vp
->v_specinfo
!= NULL
)
1900 dev
= vp
->v_specinfo
->si_rdev
;
1906 ATTR_PACK4(ab
, dev
);
1907 ab
.actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
1911 * If the filesystem does not support datalength
1912 * or dataallocsize, then we infer that totalsize and
1913 * totalalloc are substitutes.
1915 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
1916 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1917 ATTR_PACK8(ab
, va
.va_data_size
);
1919 ATTR_PACK8(ab
, va
.va_total_size
);
1921 ab
.actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
1923 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
1924 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1925 ATTR_PACK8(ab
, va
.va_data_alloc
);
1927 ATTR_PACK8(ab
, va
.va_total_alloc
);
1929 ab
.actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
1931 /* already got the resource fork size/allocation above */
1932 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
) {
1933 ATTR_PACK8(ab
, rlength
);
1934 ab
.actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
1936 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
1937 ATTR_PACK8(ab
, ralloc
);
1938 ab
.actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
1943 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1944 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1945 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), al
.commonattr
, al
.volattr
);
1946 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1947 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1950 * In the compatible case, we report the smaller of the required and returned sizes.
1951 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1952 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1953 * they gave us, so they can always check for truncation themselves.
1955 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1957 /* Return attribute set output if requested. */
1959 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1961 /* Only report the attributes that are valid */
1962 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1963 ab
.actual
.dirattr
&= ab
.valid
.dirattr
;
1964 ab
.actual
.fileattr
&= ab
.valid
.fileattr
;
1966 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1969 /* Only actually copyout as much out as the user buffer can hold */
1970 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
1974 kfree(va
.va_name
, MAXPATHLEN
);
1976 kfree(fullpathptr
, MAXPATHLEN
);
1978 vnode_putname(vname
);
1979 if (ab
.base
!= NULL
)
1980 FREE(ab
.base
, M_TEMP
);
1981 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
1982 kauth_acl_free(va
.va_acl
);
1984 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1989 fgetattrlist(proc_t p
, struct fgetattrlist_args
*uap
, __unused
int32_t *retval
)
1991 struct vfs_context
*ctx
;
1994 struct getattrlist_args ap
;
1996 ctx
= vfs_context_current();
1999 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2002 if ((error
= vnode_getwithref(vp
)) != 0) {
2008 ap
.alist
= uap
->alist
;
2009 ap
.attributeBuffer
= uap
->attributeBuffer
;
2010 ap
.bufferSize
= uap
->bufferSize
;
2011 ap
.options
= uap
->options
;
2013 error
= getattrlist_internal(vp
, &ap
, p
, ctx
);
2023 getattrlist(proc_t p
, struct getattrlist_args
*uap
, __unused
int32_t *retval
)
2025 struct vfs_context
*ctx
;
2026 struct nameidata nd
;
2031 ctx
= vfs_context_current();
2037 nameiflags
= NOTRIGGER
| AUDITVNPATH1
;
2038 if (!(uap
->options
& FSOPT_NOFOLLOW
))
2039 nameiflags
|= FOLLOW
;
2040 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2042 if ((error
= namei(&nd
)) != 0)
2047 error
= getattrlist_internal(vp
, uap
, p
, ctx
);
2055 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
2057 /* make sure we have enough source data */
2058 if ((*cursor
) + size
> end
)
2061 bcopy(*cursor
, buf
, size
);
2066 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
2067 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
2068 #define ATTR_UNPACK_TIME(v, is64) \
2071 struct user64_timespec us; \
2073 v.tv_sec = us.tv_sec; \
2074 v.tv_nsec = us.tv_nsec; \
2076 struct user32_timespec us; \
2078 v.tv_sec = us.tv_sec; \
2079 v.tv_nsec = us.tv_nsec; \
2088 setattrlist_internal(vnode_t vp
, struct setattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
2091 struct vnode_attr va
;
2092 struct attrreference ar
;
2093 kauth_action_t action
;
2094 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
2095 int proc_is64
, error
;
2097 kauth_filesec_t rfsec
;
2103 proc_is64
= proc_is64bit(p
);
2107 * Fetch the attribute set and validate.
2109 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
2111 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
2116 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
2117 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
2118 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
2121 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
2122 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
2126 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
2130 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
2131 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
2132 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
2133 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
2135 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
2141 * Make the naive assumption that the caller has supplied a reasonable buffer
2142 * size. We could be more careful by pulling in the fixed-size region, checking
2143 * the attrref structures, then pulling in the variable section.
2144 * We need to reconsider this for handling large ACLs, as they should probably be
2145 * brought directly into a buffer. Multiple copyins will make this slower though.
2147 * We could also map the user buffer if it is larger than some sensible mimimum.
2149 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
2150 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
2154 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
2155 if (user_buf
== NULL
) {
2156 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
2160 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
2161 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
2164 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
2167 error
= mac_vnode_check_setattrlist(ctx
, vp
, &al
);
2173 * Unpack the argument buffer.
2176 bufend
= cursor
+ uap
->bufferSize
;
2179 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
2180 ATTR_UNPACK(va
.va_encoding
);
2181 VATTR_SET_ACTIVE(&va
, va_encoding
);
2183 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
2184 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
2185 VATTR_SET_ACTIVE(&va
, va_create_time
);
2187 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
2188 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
2189 VATTR_SET_ACTIVE(&va
, va_modify_time
);
2191 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
2192 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
2193 VATTR_SET_ACTIVE(&va
, va_change_time
);
2195 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
2196 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
2197 VATTR_SET_ACTIVE(&va
, va_access_time
);
2199 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
2200 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
2201 VATTR_SET_ACTIVE(&va
, va_backup_time
);
2203 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
2204 if ((cursor
+ 32) > bufend
) {
2206 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
2212 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
2213 ATTR_UNPACK(va
.va_uid
);
2214 VATTR_SET_ACTIVE(&va
, va_uid
);
2216 if (al
.commonattr
& ATTR_CMN_GRPID
) {
2217 ATTR_UNPACK(va
.va_gid
);
2218 VATTR_SET_ACTIVE(&va
, va_gid
);
2220 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
2221 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
2222 VATTR_SET_ACTIVE(&va
, va_mode
);
2224 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
2225 ATTR_UNPACK(va
.va_flags
);
2226 VATTR_SET_ACTIVE(&va
, va_flags
);
2228 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
2231 * We are (for now) passed a kauth_filesec_t, but all we want from
2236 cp
+= ar
.attr_dataoffset
;
2237 rfsec
= (kauth_filesec_t
)cp
;
2238 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) || /* no space for acl */
2239 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
2240 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
2241 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
2243 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
2246 nace
= rfsec
->fsec_entrycount
;
2247 if (nace
== KAUTH_FILESEC_NOACL
)
2249 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2251 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
2254 nace
= rfsec
->fsec_acl
.acl_entrycount
;
2255 if (nace
== KAUTH_FILESEC_NOACL
) {
2257 VATTR_SET(&va
, va_acl
, NULL
);
2260 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2262 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
2265 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
2268 if (al
.commonattr
& ATTR_CMN_UUID
) {
2269 ATTR_UNPACK(va
.va_uuuid
);
2270 VATTR_SET_ACTIVE(&va
, va_uuuid
);
2272 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
2273 ATTR_UNPACK(va
.va_guuid
);
2274 VATTR_SET_ACTIVE(&va
, va_guuid
);
2278 if (al
.volattr
& ATTR_VOL_INFO
) {
2279 if (al
.volattr
& ATTR_VOL_NAME
) {
2282 volname
+= ar
.attr_dataoffset
;
2283 if ((volname
+ ar
.attr_length
) > bufend
) {
2285 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
2288 /* guarantee NUL termination */
2289 volname
[ar
.attr_length
- 1] = 0;
2294 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
2295 /* XXX does it actually make any sense to change this? */
2297 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
2302 * Validate and authorize.
2305 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) {
2306 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
2310 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
2311 * and will be auth'ed by the FS.
2313 if (fndrinfo
!= NULL
) {
2314 if (al
.volattr
& ATTR_VOL_INFO
) {
2315 if (vp
->v_tag
!= VT_HFS
) {
2320 action
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
2324 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2325 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
2330 * When we're setting both the access mask and the finder info, then
2331 * check if were about to remove write access for the owner. Since
2332 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
2333 * to consider their ordering.
2335 * If were about to remove write access for the owner we'll set the
2336 * Finder Info here before vnode_setattr. Otherwise we'll set it
2337 * after vnode_setattr since it may be adding owner write access.
2339 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
2340 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
2341 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2344 fndrinfo
= NULL
; /* it was set here so skip setting below */
2348 * Write the attributes if we have any.
2350 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, ctx
)) != 0)) {
2351 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
2356 * Write the Finder Info if we have any.
2358 if (fndrinfo
!= NULL
) {
2359 if (al
.volattr
& ATTR_VOL_INFO
) {
2360 if (vp
->v_tag
== VT_HFS
) {
2361 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
);
2365 /* XXX should never get here */
2367 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2373 * Set the volume name, if we have one
2375 if (volname
!= NULL
)
2381 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
2382 VFSATTR_WANTED(&vs
, f_vol_name
);
2385 error
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
);
2390 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
2391 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
2395 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
2397 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
2402 /* all done and successful */
2405 if (user_buf
!= NULL
)
2406 FREE(user_buf
, M_TEMP
);
2407 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);
2412 setattrlist(proc_t p
, struct setattrlist_args
*uap
, __unused
int32_t *retval
)
2414 struct vfs_context
*ctx
;
2415 struct nameidata nd
;
2420 ctx
= vfs_context_current();
2425 nameiflags
= AUDITVNPATH1
;
2426 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
2427 nameiflags
|= FOLLOW
;
2428 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2429 if ((error
= namei(&nd
)) != 0)
2434 error
= setattrlist_internal(vp
, uap
, p
, ctx
);
2442 fsetattrlist(proc_t p
, struct fsetattrlist_args
*uap
, __unused
int32_t *retval
)
2444 struct vfs_context
*ctx
;
2447 struct setattrlist_args ap
;
2449 ctx
= vfs_context_current();
2451 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2454 if ((error
= vnode_getwithref(vp
)) != 0) {
2460 ap
.alist
= uap
->alist
;
2461 ap
.attributeBuffer
= uap
->attributeBuffer
;
2462 ap
.bufferSize
= uap
->bufferSize
;
2463 ap
.options
= uap
->options
;
2465 error
= setattrlist_internal(vp
, &ap
, p
, ctx
);