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.
547 if ((tab
->attr
& asp
->commonattr
) &&
548 (tab
->bits
& vap
->va_active
) &&
549 (tab
->bits
& vap
->va_supported
) == 0) {
550 asp
->commonattr
&= ~tab
->attr
;
552 } while ((++tab
)->attr
!= 0);
555 tab
= getattrlist_dir_tab
;
557 if ((tab
->attr
& asp
->dirattr
) &&
558 (tab
->bits
& vap
->va_active
) &&
559 (vap
->va_supported
& tab
->bits
) == 0) {
560 asp
->dirattr
&= ~tab
->attr
;
562 } while ((++tab
)->attr
!= 0);
565 tab
= getattrlist_file_tab
;
567 if ((tab
->attr
& asp
->fileattr
) &&
568 (tab
->bits
& vap
->va_active
) &&
569 (vap
->va_supported
& tab
->bits
) == 0) {
570 asp
->fileattr
&= ~tab
->attr
;
572 } while ((++tab
)->attr
!= 0);
577 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
580 char uio_buf
[UIO_SIZEOF(1)];
583 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
586 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
587 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
592 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
593 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
601 * Find something resembling a terminal component name in the mountedonname for vp
605 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
611 * We're looking for the last sequence of non / characters, but
612 * not including any trailing / characters.
617 for (cp
= mn
; *cp
!= 0; cp
++) {
619 /* start of run of chars */
625 /* end of run of chars */
632 /* need to close run? */
639 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
,
640 vfs_context_t ctx
, int is_64bit
)
643 struct vnode_attr va
;
644 struct _attrlist_buf ab
;
646 ssize_t fixedsize
, varsize
;
647 const char *cnp
= NULL
; /* protected by ATTR_CMN_NAME */
648 ssize_t cnl
= 0; /* protected by ATTR_CMN_NAME */
657 vs
.f_vol_name
= NULL
;
660 /* Check for special packing semantics */
661 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
);
662 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
664 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
669 /* Keep invalid attrs from being uninitialized */
670 bzero(&vs
, sizeof (vs
));
671 /* Generate a valid mask for post processing */
672 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
676 * For now, the vnode must be the root of its filesystem.
677 * To relax this, we need to be able to find the root vnode of a filesystem
678 * from any vnode in the filesystem.
680 if (!vnode_isvroot(vp
)) {
682 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
687 * Set up the vfs_attr structure and call the filesystem.
689 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
690 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
693 if (vs
.f_active
!= 0) {
694 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
695 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
696 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
697 if (vs
.f_vol_name
== NULL
) {
699 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
705 error
= mac_mount_check_getattr(ctx
, mnt
, &vs
);
709 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
710 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
711 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
716 * Did we ask for something the filesystem doesn't support?
718 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
719 /* default value for volume subtype */
720 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
721 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
722 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
725 * If the file system didn't supply f_signature, then
726 * default it to 'BD', which is the generic signature
727 * that most Carbon file systems should return.
729 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
730 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
731 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
733 /* default for block size */
734 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
735 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
736 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
738 /* default value for volume f_attributes */
739 if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
)
740 && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) {
741 vol_attributes_attr_t
*attrp
= &vs
.f_attributes
;
743 attrp
->validattr
.commonattr
= VFS_DFLT_ATTR_CMN
;
744 attrp
->validattr
.volattr
= VFS_DFLT_ATTR_VOL
;
745 attrp
->validattr
.dirattr
= VFS_DFLT_ATTR_DIR
;
746 attrp
->validattr
.fileattr
= VFS_DFLT_ATTR_FILE
;
747 attrp
->validattr
.forkattr
= 0;
749 attrp
->nativeattr
.commonattr
= 0;
750 attrp
->nativeattr
.volattr
= 0;
751 attrp
->nativeattr
.dirattr
= 0;
752 attrp
->nativeattr
.fileattr
= 0;
753 attrp
->nativeattr
.forkattr
= 0;
754 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
);
757 /* default value for volume f_capabilities */
758 if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) {
759 /* getattrlist is always supported now. */
760 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) {
761 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0;
762 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
763 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
764 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
766 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0;
767 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
768 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
769 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
770 VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
);
773 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
774 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
775 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
779 /* check to see if our fixups were enough */
780 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
783 /* Fix up valid mask for post processing */
784 getvolattrlist_fixupattrs(&ab
.valid
, &vs
);
786 /* Force packing of everything asked for */
787 vs
.f_supported
= vs
.f_active
;
789 /* Adjust the requested attributes */
790 getvolattrlist_fixupattrs((attribute_set_t
*)&alp
->commonattr
, &vs
);
801 * Some fields require data from the root vp
803 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
804 VATTR_WANTED(&va
, va_uid
);
805 VATTR_WANTED(&va
, va_gid
);
806 VATTR_WANTED(&va
, va_mode
);
807 VATTR_WANTED(&va
, va_flags
);
808 VATTR_WANTED(&va
, va_encoding
);
810 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
811 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
815 if (VATTR_IS_ACTIVE(&va
, va_encoding
) &&
816 !VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
817 if (!return_valid
|| pack_invalid
)
818 /* use kTextEncodingMacUnicode */
819 VATTR_RETURN(&va
, va_encoding
, 0x7e);
821 /* don't use a default */
822 alp
->commonattr
&= ~ATTR_CMN_SCRIPT
;
827 * Compute variable-size buffer requirements.
830 if (alp
->commonattr
& ATTR_CMN_NAME
) {
831 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
832 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
833 /* special case for boot volume. Use root name when it's
834 * available (which is the volume name) or just the mount on
835 * name of "/". we must do this for binary compatibility with
836 * pre Tiger code. returning nothing for the boot volume name
837 * breaks installers - 3961058
839 cnp
= vnode_getname(vp
);
841 /* just use "/" as name */
842 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
850 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
852 if (alp
->commonattr
& ATTR_CMN_NAME
)
853 varsize
+= roundup(cnl
+ 1, 4);
855 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
856 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
857 if (alp
->volattr
& ATTR_VOL_NAME
) {
858 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
859 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
861 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
862 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
865 * Allocate a target buffer for attribute results.
866 * Note that since we won't ever copy out more than the caller requested,
867 * we never need to allocate more than they offer.
869 ab
.allocated
= imin(uap
->bufferSize
, fixedsize
+ varsize
);
870 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
872 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
875 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
876 if (ab
.base
== NULL
) {
878 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
883 * Pack results into the destination buffer.
885 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
887 ab
.fixedcursor
+= sizeof (attribute_set_t
);
888 bzero(&ab
.actual
, sizeof (ab
.actual
));
890 ab
.varcursor
= ab
.base
+ fixedsize
;
891 ab
.needed
= fixedsize
+ varsize
;
893 /* common attributes **************************************************/
894 if (alp
->commonattr
& ATTR_CMN_NAME
) {
895 attrlist_pack_string(&ab
, cnp
, cnl
);
896 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
898 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
899 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
900 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
902 if (alp
->commonattr
& ATTR_CMN_FSID
) {
903 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
);
904 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
906 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
907 if (!return_valid
|| pack_invalid
)
910 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
911 ATTR_PACK4(ab
, vp
->v_tag
);
912 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
914 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
915 if (!return_valid
|| pack_invalid
) {
916 fsobj_id_t f
= {0, 0};
920 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
921 if (!return_valid
|| pack_invalid
) {
922 fsobj_id_t f
= {0, 0};
926 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
927 if (!return_valid
|| pack_invalid
) {
928 fsobj_id_t f
= {0, 0};
932 /* note that this returns the encoding for the volume name, not the node name */
933 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
934 ATTR_PACK4(ab
, va
.va_encoding
);
935 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
937 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
938 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
);
939 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
941 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
942 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
943 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
945 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
946 if (!return_valid
|| pack_invalid
)
947 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
949 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
950 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
);
951 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
953 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
954 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
);
955 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
957 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
960 * This attribute isn't really Finder Info, at least for HFS.
962 if (vp
->v_tag
== VT_HFS
) {
963 error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
);
965 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
966 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
967 } else if (!return_valid
) {
970 } else if (!return_valid
|| pack_invalid
) {
971 /* XXX we could at least pass out the volume UUID here */
972 bzero(&f
, sizeof(f
));
973 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
976 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
977 ATTR_PACK4(ab
, va
.va_uid
);
978 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
980 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
981 ATTR_PACK4(ab
, va
.va_gid
);
982 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
984 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
985 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
986 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
988 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
989 ATTR_PACK4(ab
, va
.va_flags
);
990 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
992 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
994 if (vnode_isdir(vp
)) {
995 if (vnode_authorize(vp
, NULL
,
996 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
998 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1000 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1003 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1005 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1007 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1012 * Rather than MAC preceding DAC, in this case we want
1013 * the smallest set of permissions granted by both MAC & DAC
1014 * checks. We won't add back any permissions.
1017 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1020 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1023 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1026 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
1027 ATTR_PACK4(ab
, perms
);
1028 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1031 * The following common volume attributes are only
1032 * packed when the pack_invalid mode is enabled.
1037 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
)
1038 attrlist_pack_variable(&ab
, NULL
, 0);
1039 if (alp
->commonattr
& ATTR_CMN_UUID
)
1040 ATTR_PACK(&ab
, kauth_null_guid
);
1041 if (alp
->commonattr
& ATTR_CMN_GRPUUID
)
1042 ATTR_PACK(&ab
, kauth_null_guid
);
1043 if (alp
->commonattr
& ATTR_CMN_FILEID
)
1044 ATTR_PACK8(ab
, fid
);
1045 if (alp
->commonattr
& ATTR_CMN_PARENTID
)
1046 ATTR_PACK8(ab
, fid
);
1049 /* volume attributes **************************************************/
1051 if (alp
->volattr
& ATTR_VOL_FSTYPE
) {
1052 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
1053 ab
.actual
.volattr
|= ATTR_VOL_FSTYPE
;
1055 if (alp
->volattr
& ATTR_VOL_SIGNATURE
) {
1056 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
1057 ab
.actual
.volattr
|= ATTR_VOL_SIGNATURE
;
1059 if (alp
->volattr
& ATTR_VOL_SIZE
) {
1060 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
1061 ab
.actual
.volattr
|= ATTR_VOL_SIZE
;
1063 if (alp
->volattr
& ATTR_VOL_SPACEFREE
) {
1064 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
1065 ab
.actual
.volattr
|= ATTR_VOL_SPACEFREE
;
1067 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
) {
1068 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
1069 ab
.actual
.volattr
|= ATTR_VOL_SPACEAVAIL
;
1071 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
) {
1072 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
1073 ab
.actual
.volattr
|= ATTR_VOL_MINALLOCATION
;
1075 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
) {
1076 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
1077 ab
.actual
.volattr
|= ATTR_VOL_ALLOCATIONCLUMP
;
1079 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
) {
1080 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
1081 ab
.actual
.volattr
|= ATTR_VOL_IOBLOCKSIZE
;
1083 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
) {
1084 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
1085 ab
.actual
.volattr
|= ATTR_VOL_OBJCOUNT
;
1087 if (alp
->volattr
& ATTR_VOL_FILECOUNT
) {
1088 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
1089 ab
.actual
.volattr
|= ATTR_VOL_FILECOUNT
;
1091 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
) {
1092 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
1093 ab
.actual
.volattr
|= ATTR_VOL_DIRCOUNT
;
1095 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
) {
1096 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
1097 ab
.actual
.volattr
|= ATTR_VOL_MAXOBJCOUNT
;
1099 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
) {
1100 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
1101 ab
.actual
.volattr
|= ATTR_VOL_MOUNTPOINT
;
1103 if (alp
->volattr
& ATTR_VOL_NAME
) {
1104 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
1105 ab
.actual
.volattr
|= ATTR_VOL_NAME
;
1107 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
) {
1108 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
1109 ab
.actual
.volattr
|= ATTR_VOL_MOUNTFLAGS
;
1111 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
) {
1112 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
1113 ab
.actual
.volattr
|= ATTR_VOL_MOUNTEDDEVICE
;
1115 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
) {
1116 if (!return_valid
|| pack_invalid
)
1117 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
1119 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
1120 /* fix up volume capabilities */
1121 if (vfs_extendedsecurity(mnt
)) {
1122 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1124 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
1126 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1127 ATTR_PACK(&ab
, vs
.f_capabilities
);
1128 ab
.actual
.volattr
|= ATTR_VOL_CAPABILITIES
;
1130 if (alp
->volattr
& ATTR_VOL_UUID
) {
1131 ATTR_PACK(&ab
, vs
.f_uuid
);
1132 ab
.actual
.volattr
|= ATTR_VOL_UUID
;
1134 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
1135 /* fix up volume attribute information */
1137 vs
.f_attributes
.validattr
.commonattr
|= VFS_DFLT_ATTR_CMN
;
1138 vs
.f_attributes
.validattr
.volattr
|= VFS_DFLT_ATTR_VOL
;
1139 vs
.f_attributes
.validattr
.dirattr
|= VFS_DFLT_ATTR_DIR
;
1140 vs
.f_attributes
.validattr
.fileattr
|= VFS_DFLT_ATTR_FILE
;
1142 if (vfs_extendedsecurity(mnt
)) {
1143 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1145 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1146 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1148 ATTR_PACK(&ab
, vs
.f_attributes
);
1149 ab
.actual
.volattr
|= ATTR_VOL_ATTRIBUTES
;
1153 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1154 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1155 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
1156 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1157 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1160 * In the compatible case, we report the smaller of the required and returned sizes.
1161 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1162 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1163 * they gave us, so they can always check for truncation themselves.
1165 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1167 /* Return attribute set output if requested. */
1169 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1171 /* Only report the attributes that are valid */
1172 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1173 ab
.actual
.volattr
&= ab
.valid
.volattr
;
1175 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1177 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
1180 if (vs
.f_vol_name
!= NULL
)
1181 kfree(vs
.f_vol_name
, MAXPATHLEN
);
1185 if (ab
.base
!= NULL
)
1186 FREE(ab
.base
, M_TEMP
);
1187 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1192 * Obtain attribute information about a filesystem object.
1196 getattrlist_internal(vnode_t vp
, struct getattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
1199 struct vnode_attr va
;
1200 struct _attrlist_buf ab
;
1201 kauth_action_t action
;
1202 ssize_t fixedsize
, varsize
;
1204 const char *vname
= NULL
;
1206 ssize_t fullpathlen
;
1215 proc_is64
= proc_is64bit(p
);
1225 * Fetch the attribute request.
1227 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
1229 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1234 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1235 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1236 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1239 error
= mac_vnode_check_getattrlist(ctx
, vp
, &al
);
1245 * It is legal to request volume or file attributes,
1249 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
1251 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
1254 /* handle volume attribute request */
1255 error
= getvolattrlist(vp
, uap
, &al
, ctx
, proc_is64
);
1259 /* Check for special packing semantics */
1260 return_valid
= (al
.commonattr
& ATTR_CMN_RETURNED_ATTRS
);
1261 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
1263 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
1264 if (!return_valid
|| al
.forkattr
) {
1268 /* Keep invalid attrs from being uninitialized */
1269 bzero(&va
, sizeof (va
));
1270 /* Generate a valid mask for post processing */
1271 bcopy(&al
.commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
1274 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
1275 * will have a valid snapshot that we can work from here.
1281 * Set up the vnode_attr structure and authorise.
1283 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64
, (vtype
== VDIR
))) != 0) {
1284 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
1287 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) {
1288 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
1293 * If we're asking for the full path, allocate a buffer for that.
1295 if (al
.commonattr
& (ATTR_CMN_FULLPATH
)) {
1296 fullpathptr
= (char*) kalloc(MAXPATHLEN
);
1297 if (fullpathptr
== NULL
) {
1299 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
1305 if (va
.va_active
!= 0) {
1307 * If we're going to ask for va_name, allocate a buffer to point it at
1309 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
1310 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
1311 if (va
.va_name
== NULL
) {
1313 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
1319 * Call the filesystem.
1321 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
1322 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1326 /* did we ask for something the filesystem doesn't support? */
1327 if (!VATTR_ALL_SUPPORTED(&va
)) {
1330 * There are a couple of special cases. If we are after object IDs,
1331 * we can make do with va_fileid.
1333 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
| ATTR_CMN_FILEID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
1334 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
1337 * Many filesystems don't know their parent object id.
1338 * If necessary, attempt to derive it from the vnode.
1340 if ((al
.commonattr
& (ATTR_CMN_PAROBJID
| ATTR_CMN_PARENTID
)) &&
1341 !VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1344 if ((dvp
= vnode_getparent(vp
)) != NULLVP
) {
1345 struct vnode_attr lva
;
1348 VATTR_WANTED(&lva
, va_fileid
);
1349 if (vnode_getattr(dvp
, &lva
, ctx
) == 0 &&
1350 VATTR_IS_SUPPORTED(&va
, va_fileid
)) {
1351 va
.va_parentid
= lva
.va_fileid
;
1352 VATTR_SET_SUPPORTED(&va
, va_parentid
);
1358 * And we can report datasize/alloc from total.
1360 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
1361 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
1362 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
1363 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
1366 * If we don't have an encoding, go with UTF-8
1368 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) &&
1369 !VATTR_IS_SUPPORTED(&va
, va_encoding
) && !return_valid
)
1370 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
1373 * If we don't have a name, we'll get one from the vnode or mount point.
1375 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
1376 VATTR_CLEAR_ACTIVE(&va
, va_name
);
1379 /* If va_dirlinkcount isn't supported use a default of 1. */
1380 if ((al
.dirattr
& ATTR_DIR_LINKCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_dirlinkcount
)) {
1381 VATTR_RETURN(&va
, va_dirlinkcount
, 1);
1385 if (!VATTR_ALL_SUPPORTED(&va
)) {
1388 /* Fix up valid mask for post processing */
1389 getattrlist_fixupattrs(&ab
.valid
, &va
);
1391 /* Force packing of everything asked for */
1392 va
.va_supported
= va
.va_active
;
1394 /* Adjust the requested attributes */
1395 getattrlist_fixupattrs((attribute_set_t
*)&al
.commonattr
, &va
);
1406 * Compute variable-space requirements.
1408 varsize
= 0; /* length count */
1410 /* We may need to fix up the name attribute if requested */
1411 if (al
.commonattr
& ATTR_CMN_NAME
) {
1412 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
1413 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
1417 if (vnode_isvroot(vp
)) {
1418 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
1419 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
1420 /* special case for boot volume. Use root name when it's
1421 * available (which is the volume name) or just the mount on
1422 * name of "/". we must do this for binary compatibility with
1423 * pre Tiger code. returning nothing for the boot volume name
1424 * breaks installers - 3961058
1426 cnp
= vname
= vnode_getname(vp
);
1428 /* just use "/" as name */
1429 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
1434 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
1437 cnp
= vname
= vnode_getname(vp
);
1444 varsize
+= roundup(cnl
+ 1, 4);
1448 * Compute the full path to this vnode, if necessary. This attribute is almost certainly
1449 * not supported by any filesystem, so build the path to this vnode at this time.
1451 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1452 int len
= MAXPATHLEN
;
1454 /* call build_path making sure NOT to use the cache-only behavior */
1455 err
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current());
1462 fullpathlen
= strlen(fullpathptr
);
1464 varsize
+= roundup(fullpathlen
+1, 4);
1468 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
1470 * XXX This needs to change at some point; since the blob is opaque in
1471 * user-space this is OK.
1473 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
1474 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
1475 (va
.va_acl
!= NULL
))
1476 varsize
+= roundup(KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
), 4);
1479 * Allocate a target buffer for attribute results.
1481 * Note that we won't ever copy out more than the caller requested, even though
1482 * we might have to allocate more than they offer so that the diagnostic checks
1483 * don't result in a panic if the caller's buffer is too small..
1485 ab
.allocated
= fixedsize
+ varsize
;
1486 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1488 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1491 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1492 if (ab
.base
== NULL
) {
1494 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1498 /* set the S_IFMT bits for the mode */
1499 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1500 switch (vp
->v_type
) {
1502 va
.va_mode
|= S_IFREG
;
1505 va
.va_mode
|= S_IFDIR
;
1508 va
.va_mode
|= S_IFBLK
;
1511 va
.va_mode
|= S_IFCHR
;
1514 va
.va_mode
|= S_IFLNK
;
1517 va
.va_mode
|= S_IFSOCK
;
1520 va
.va_mode
|= S_IFIFO
;
1529 * Pack results into the destination buffer.
1531 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1533 ab
.fixedcursor
+= sizeof (attribute_set_t
);
1534 bzero(&ab
.actual
, sizeof (ab
.actual
));
1536 ab
.varcursor
= ab
.base
+ fixedsize
;
1537 ab
.needed
= ab
.allocated
;
1539 /* common attributes **************************************************/
1540 if (al
.commonattr
& ATTR_CMN_NAME
) {
1541 attrlist_pack_string(&ab
, cnp
, cnl
);
1542 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
1544 if (al
.commonattr
& ATTR_CMN_DEVID
) {
1545 ATTR_PACK4(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1546 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
1548 if (al
.commonattr
& ATTR_CMN_FSID
) {
1549 ATTR_PACK8(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1550 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
1552 if (al
.commonattr
& ATTR_CMN_OBJTYPE
) {
1553 ATTR_PACK4(ab
, vtype
);
1554 ab
.actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1556 if (al
.commonattr
& ATTR_CMN_OBJTAG
) {
1557 ATTR_PACK4(ab
, vp
->v_tag
);
1558 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1560 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1563 * Carbon can't deal with us reporting the target ID
1564 * for links. So we ask the filesystem to give us the
1565 * source ID as well, and if it gives us one, we use
1568 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1569 f
.fid_objno
= va
.va_linkid
;
1571 f
.fid_objno
= va
.va_fileid
;
1573 f
.fid_generation
= 0;
1575 ab
.actual
.commonattr
|= ATTR_CMN_OBJID
;
1577 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1580 * Carbon can't deal with us reporting the target ID
1581 * for links. So we ask the filesystem to give us the
1582 * source ID as well, and if it gives us one, we use
1585 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1586 f
.fid_objno
= va
.va_linkid
;
1588 f
.fid_objno
= va
.va_fileid
;
1590 f
.fid_generation
= 0;
1592 ab
.actual
.commonattr
|= ATTR_CMN_OBJPERMANENTID
;
1594 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1597 f
.fid_objno
= va
.va_parentid
; /* could be lossy here! */
1598 f
.fid_generation
= 0;
1600 ab
.actual
.commonattr
|= ATTR_CMN_PAROBJID
;
1602 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1603 if (VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
1604 ATTR_PACK4(ab
, va
.va_encoding
);
1605 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1606 } else if (!return_valid
|| pack_invalid
) {
1607 ATTR_PACK4(ab
, 0x7e);
1610 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1611 ATTR_PACK_TIME(ab
, va
.va_create_time
, proc_is64
);
1612 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1614 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1615 ATTR_PACK_TIME(ab
, va
.va_modify_time
, proc_is64
);
1616 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1618 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1619 ATTR_PACK_TIME(ab
, va
.va_change_time
, proc_is64
);
1620 ab
.actual
.commonattr
|= ATTR_CMN_CHGTIME
;
1622 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1623 ATTR_PACK_TIME(ab
, va
.va_access_time
, proc_is64
);
1624 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1626 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1627 ATTR_PACK_TIME(ab
, va
.va_backup_time
, proc_is64
);
1628 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1631 * They are requesting user access, we should obtain this before getting
1632 * the finder info. For some network file systems this is a performance
1635 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1636 if (vtype
== VDIR
) {
1637 if (vnode_authorize(vp
, NULL
,
1638 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1640 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1642 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1645 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1647 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1649 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1654 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1657 char uio_buf
[UIO_SIZEOF(1)];
1659 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1660 uio_buf
, sizeof(uio_buf
))) == NULL
) {
1664 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1665 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
,
1666 &fisize
, XATTR_NOSECURITY
, ctx
);
1669 * Default to zeros if its not available,
1670 * unless ATTR_CMN_RETURNED_ATTRS was requested.
1673 (!return_valid
|| pack_invalid
) &&
1674 ((error
== ENOATTR
) || (error
== ENOENT
) ||
1675 (error
== ENOTSUP
) || (error
== EPERM
))) {
1676 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1677 bzero(ab
.fixedcursor
, 32);
1681 ab
.fixedcursor
+= 32;
1682 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1683 } else if (!return_valid
) {
1684 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1688 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1689 ATTR_PACK4(ab
, va
.va_uid
);
1690 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1692 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1693 ATTR_PACK4(ab
, va
.va_gid
);
1694 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1696 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1697 ATTR_PACK4(ab
, va
.va_mode
);
1698 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1700 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1701 ATTR_PACK4(ab
, va
.va_flags
);
1702 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1704 /* We already obtain the user access, so just fill in the buffer here */
1705 if (al
.commonattr
& ATTR_CMN_USERACCESS
) {
1708 * Rather than MAC preceding DAC, in this case we want
1709 * the smallest set of permissions granted by both MAC & DAC
1710 * checks. We won't add back any permissions.
1713 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1716 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1719 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1722 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1723 ATTR_PACK4(ab
, perms
);
1724 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1726 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1727 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1728 struct kauth_filesec fsec
;
1730 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1732 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1733 fsec
.fsec_owner
= kauth_null_guid
;
1734 fsec
.fsec_group
= kauth_null_guid
;
1735 attrlist_pack_variable2(&ab
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1736 ab
.actual
.commonattr
|= ATTR_CMN_EXTENDED_SECURITY
;
1737 } else if (!return_valid
|| pack_invalid
) {
1738 attrlist_pack_variable(&ab
, NULL
, 0);
1741 if (al
.commonattr
& ATTR_CMN_UUID
) {
1742 if (VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1743 ATTR_PACK(&ab
, va
.va_uuuid
);
1744 ab
.actual
.commonattr
|= ATTR_CMN_UUID
;
1745 } else if (!return_valid
|| pack_invalid
) {
1746 ATTR_PACK(&ab
, kauth_null_guid
);
1749 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1750 if (VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1751 ATTR_PACK(&ab
, va
.va_guuid
);
1752 ab
.actual
.commonattr
|= ATTR_CMN_GRPUUID
;
1753 } else if (!return_valid
|| pack_invalid
) {
1754 ATTR_PACK(&ab
, kauth_null_guid
);
1757 if (al
.commonattr
& ATTR_CMN_FILEID
) {
1758 ATTR_PACK8(ab
, va
.va_fileid
);
1759 ab
.actual
.commonattr
|= ATTR_CMN_FILEID
;
1761 if (al
.commonattr
& ATTR_CMN_PARENTID
) {
1762 ATTR_PACK8(ab
, va
.va_parentid
);
1763 ab
.actual
.commonattr
|= ATTR_CMN_PARENTID
;
1766 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1767 attrlist_pack_string (&ab
, fullpathptr
, fullpathlen
);
1768 ab
.actual
.commonattr
|= ATTR_CMN_FULLPATH
;
1771 if (al
.commonattr
& ATTR_CMN_ADDEDTIME
) {
1772 ATTR_PACK_TIME(ab
, va
.va_addedtime
, proc_is64
);
1773 ab
.actual
.commonattr
|= ATTR_CMN_ADDEDTIME
;
1776 /* directory attributes *********************************************/
1777 if (al
.dirattr
&& (vtype
== VDIR
)) {
1778 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) { /* full count of entries */
1779 ATTR_PACK4(ab
, (uint32_t)va
.va_dirlinkcount
);
1780 ab
.actual
.dirattr
|= ATTR_DIR_LINKCOUNT
;
1782 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) {
1783 ATTR_PACK4(ab
, (uint32_t)va
.va_nchildren
);
1784 ab
.actual
.dirattr
|= ATTR_DIR_ENTRYCOUNT
;
1786 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
) {
1789 mntstat
= (vp
->v_flag
& VROOT
) ? DIR_MNTSTATUS_MNTPOINT
: 0;
1792 * Report back on active vnode triggers
1793 * that can directly trigger a mount
1795 if (vp
->v_resolve
&&
1796 !(vp
->v_resolve
->vr_flags
& VNT_NO_DIRECT_MOUNT
)) {
1797 mntstat
|= DIR_MNTSTATUS_TRIGGER
;
1800 ATTR_PACK4(ab
, mntstat
);
1801 ab
.actual
.dirattr
|= ATTR_DIR_MOUNTSTATUS
;
1805 /* file attributes **************************************************/
1806 if (al
.fileattr
&& (vtype
!= VDIR
)) {
1809 uint64_t rlength
= 0;
1810 uint64_t ralloc
= 0;
1812 * Pre-fetch the rsrc attributes now so we only get them once.
1813 * Fetch the resource fork size/allocation via xattr interface
1815 if (al
.fileattr
& (ATTR_FILE_TOTALSIZE
| ATTR_FILE_ALLOCSIZE
| ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1816 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, ctx
)) != 0) {
1817 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)|| (error
== EACCES
)) {
1826 if (al
.fileattr
& (ATTR_FILE_RSRCALLOCSIZE
| ATTR_FILE_ALLOCSIZE
)) {
1827 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1831 ralloc
= roundup(rsize
, blksize
);
1835 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
) {
1836 ATTR_PACK4(ab
, (uint32_t)va
.va_nlink
);
1837 ab
.actual
.fileattr
|= ATTR_FILE_LINKCOUNT
;
1840 * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes:
1841 * We infer that if the filesystem does not support va_data_size or va_data_alloc
1842 * it must not know about alternate forks. So when we need to gather
1843 * the total size or total alloc, it's OK to substitute the total size for
1844 * the data size below. This is because it is likely a flat filesystem and we must
1845 * be using AD files to store the rsrc fork and EAs.
1847 * Additionally, note that getattrlist is barred from being called on
1848 * resource fork paths. (Search for CN_ALLOWRSRCFORK). So if the filesystem does
1849 * support va_data_size, it is guaranteed to represent the data fork's size. This
1850 * is an important distinction to make because when we call vnode_getattr on
1851 * an HFS resource fork vnode, to get the size, it will vend out the resource
1852 * fork's size (it only gets the size of the passed-in vnode).
1854 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
) {
1855 uint64_t totalsize
= rlength
;
1857 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1858 totalsize
+= va
.va_data_size
;
1860 totalsize
+= va
.va_total_size
;
1863 ATTR_PACK8(ab
, totalsize
);
1864 ab
.actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
1866 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
) {
1867 uint64_t totalalloc
= ralloc
;
1870 * If data_alloc is supported, then it must represent the
1873 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1874 totalalloc
+= va
.va_data_alloc
;
1877 totalalloc
+= va
.va_total_alloc
;
1880 ATTR_PACK8(ab
, totalalloc
);
1881 ab
.actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
1883 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
) {
1884 ATTR_PACK4(ab
, va
.va_iosize
);
1885 ab
.actual
.fileattr
|= ATTR_FILE_IOBLOCKSIZE
;
1887 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
) {
1888 if (!return_valid
|| pack_invalid
) {
1889 ATTR_PACK4(ab
, 0); /* this value is deprecated */
1890 ab
.actual
.fileattr
|= ATTR_FILE_CLUMPSIZE
;
1893 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1896 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1897 if (vp
->v_specinfo
!= NULL
)
1898 dev
= vp
->v_specinfo
->si_rdev
;
1904 ATTR_PACK4(ab
, dev
);
1905 ab
.actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
1909 * If the filesystem does not support datalength
1910 * or dataallocsize, then we infer that totalsize and
1911 * totalalloc are substitutes.
1913 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
1914 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1915 ATTR_PACK8(ab
, va
.va_data_size
);
1917 ATTR_PACK8(ab
, va
.va_total_size
);
1919 ab
.actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
1921 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
1922 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1923 ATTR_PACK8(ab
, va
.va_data_alloc
);
1925 ATTR_PACK8(ab
, va
.va_total_alloc
);
1927 ab
.actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
1929 /* already got the resource fork size/allocation above */
1930 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
) {
1931 ATTR_PACK8(ab
, rlength
);
1932 ab
.actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
1934 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
1935 ATTR_PACK8(ab
, ralloc
);
1936 ab
.actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
1941 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1942 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1943 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), al
.commonattr
, al
.volattr
);
1944 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1945 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1948 * In the compatible case, we report the smaller of the required and returned sizes.
1949 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1950 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1951 * they gave us, so they can always check for truncation themselves.
1953 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1955 /* Return attribute set output if requested. */
1957 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1959 /* Only report the attributes that are valid */
1960 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1961 ab
.actual
.dirattr
&= ab
.valid
.dirattr
;
1962 ab
.actual
.fileattr
&= ab
.valid
.fileattr
;
1964 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1967 /* Only actually copyout as much out as the user buffer can hold */
1968 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
1972 kfree(va
.va_name
, MAXPATHLEN
);
1974 kfree(fullpathptr
, MAXPATHLEN
);
1976 vnode_putname(vname
);
1977 if (ab
.base
!= NULL
)
1978 FREE(ab
.base
, M_TEMP
);
1979 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
1980 kauth_acl_free(va
.va_acl
);
1982 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1987 fgetattrlist(proc_t p
, struct fgetattrlist_args
*uap
, __unused
int32_t *retval
)
1989 struct vfs_context
*ctx
;
1992 struct getattrlist_args ap
;
1994 ctx
= vfs_context_current();
1997 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2000 if ((error
= vnode_getwithref(vp
)) != 0) {
2006 ap
.alist
= uap
->alist
;
2007 ap
.attributeBuffer
= uap
->attributeBuffer
;
2008 ap
.bufferSize
= uap
->bufferSize
;
2009 ap
.options
= uap
->options
;
2011 error
= getattrlist_internal(vp
, &ap
, p
, ctx
);
2021 getattrlist(proc_t p
, struct getattrlist_args
*uap
, __unused
int32_t *retval
)
2023 struct vfs_context
*ctx
;
2024 struct nameidata nd
;
2029 ctx
= vfs_context_current();
2035 nameiflags
= NOTRIGGER
| AUDITVNPATH1
;
2036 if (!(uap
->options
& FSOPT_NOFOLLOW
))
2037 nameiflags
|= FOLLOW
;
2038 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2040 if ((error
= namei(&nd
)) != 0)
2045 error
= getattrlist_internal(vp
, uap
, p
, ctx
);
2053 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
2055 /* make sure we have enough source data */
2056 if ((*cursor
) + size
> end
)
2059 bcopy(*cursor
, buf
, size
);
2064 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
2065 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
2066 #define ATTR_UNPACK_TIME(v, is64) \
2069 struct user64_timespec us; \
2071 v.tv_sec = us.tv_sec; \
2072 v.tv_nsec = us.tv_nsec; \
2074 struct user32_timespec us; \
2076 v.tv_sec = us.tv_sec; \
2077 v.tv_nsec = us.tv_nsec; \
2086 setattrlist_internal(vnode_t vp
, struct setattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
2089 struct vnode_attr va
;
2090 struct attrreference ar
;
2091 kauth_action_t action
;
2092 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
2093 int proc_is64
, error
;
2095 kauth_filesec_t rfsec
;
2101 proc_is64
= proc_is64bit(p
);
2105 * Fetch the attribute set and validate.
2107 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
2109 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
2114 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
2115 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
2116 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
2119 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
2120 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
2124 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
2128 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
2129 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
2130 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
2131 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
2133 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
2139 * If the caller's bitmaps indicate that there are no attributes to set,
2140 * then exit early. In particular, we want to avoid the MALLOC below
2141 * since the caller's bufferSize could be zero, and MALLOC of zero bytes
2142 * returns a NULL pointer, which would cause setattrlist to return ENOMEM.
2144 if (al
.commonattr
== 0 &&
2145 (al
.volattr
& ~ATTR_VOL_INFO
) == 0 &&
2154 * Make the naive assumption that the caller has supplied a reasonable buffer
2155 * size. We could be more careful by pulling in the fixed-size region, checking
2156 * the attrref structures, then pulling in the variable section.
2157 * We need to reconsider this for handling large ACLs, as they should probably be
2158 * brought directly into a buffer. Multiple copyins will make this slower though.
2160 * We could also map the user buffer if it is larger than some sensible mimimum.
2162 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
2163 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
2167 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
2168 if (user_buf
== NULL
) {
2169 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
2173 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
2174 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
2177 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
2180 error
= mac_vnode_check_setattrlist(ctx
, vp
, &al
);
2186 * Unpack the argument buffer.
2189 bufend
= cursor
+ uap
->bufferSize
;
2192 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
2193 ATTR_UNPACK(va
.va_encoding
);
2194 VATTR_SET_ACTIVE(&va
, va_encoding
);
2196 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
2197 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
2198 VATTR_SET_ACTIVE(&va
, va_create_time
);
2200 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
2201 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
2202 VATTR_SET_ACTIVE(&va
, va_modify_time
);
2204 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
2205 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
2206 VATTR_SET_ACTIVE(&va
, va_change_time
);
2208 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
2209 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
2210 VATTR_SET_ACTIVE(&va
, va_access_time
);
2212 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
2213 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
2214 VATTR_SET_ACTIVE(&va
, va_backup_time
);
2216 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
2217 if ((cursor
+ 32) > bufend
) {
2219 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
2225 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
2226 ATTR_UNPACK(va
.va_uid
);
2227 VATTR_SET_ACTIVE(&va
, va_uid
);
2229 if (al
.commonattr
& ATTR_CMN_GRPID
) {
2230 ATTR_UNPACK(va
.va_gid
);
2231 VATTR_SET_ACTIVE(&va
, va_gid
);
2233 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
2234 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
2235 VATTR_SET_ACTIVE(&va
, va_mode
);
2237 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
2238 ATTR_UNPACK(va
.va_flags
);
2239 VATTR_SET_ACTIVE(&va
, va_flags
);
2241 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
2244 * We are (for now) passed a kauth_filesec_t, but all we want from
2249 cp
+= ar
.attr_dataoffset
;
2250 rfsec
= (kauth_filesec_t
)cp
;
2251 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) || /* no space for acl */
2252 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
2253 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
2254 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
2256 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
2259 nace
= rfsec
->fsec_entrycount
;
2260 if (nace
== KAUTH_FILESEC_NOACL
)
2262 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2264 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
2267 nace
= rfsec
->fsec_acl
.acl_entrycount
;
2268 if (nace
== KAUTH_FILESEC_NOACL
) {
2270 VATTR_SET(&va
, va_acl
, NULL
);
2273 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2275 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
2278 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
2281 if (al
.commonattr
& ATTR_CMN_UUID
) {
2282 ATTR_UNPACK(va
.va_uuuid
);
2283 VATTR_SET_ACTIVE(&va
, va_uuuid
);
2285 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
2286 ATTR_UNPACK(va
.va_guuid
);
2287 VATTR_SET_ACTIVE(&va
, va_guuid
);
2291 if (al
.volattr
& ATTR_VOL_INFO
) {
2292 if (al
.volattr
& ATTR_VOL_NAME
) {
2295 volname
+= ar
.attr_dataoffset
;
2296 if ((volname
+ ar
.attr_length
) > bufend
) {
2298 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
2301 /* guarantee NUL termination */
2302 volname
[ar
.attr_length
- 1] = 0;
2307 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
2308 /* XXX does it actually make any sense to change this? */
2310 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
2315 * Validate and authorize.
2318 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) {
2319 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
2323 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
2324 * and will be auth'ed by the FS.
2326 if (fndrinfo
!= NULL
) {
2327 if (al
.volattr
& ATTR_VOL_INFO
) {
2328 if (vp
->v_tag
!= VT_HFS
) {
2333 action
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
2337 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2338 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
2343 * When we're setting both the access mask and the finder info, then
2344 * check if were about to remove write access for the owner. Since
2345 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
2346 * to consider their ordering.
2348 * If were about to remove write access for the owner we'll set the
2349 * Finder Info here before vnode_setattr. Otherwise we'll set it
2350 * after vnode_setattr since it may be adding owner write access.
2352 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
2353 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
2354 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2357 fndrinfo
= NULL
; /* it was set here so skip setting below */
2361 * Write the attributes if we have any.
2363 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, ctx
)) != 0)) {
2364 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
2369 * Write the Finder Info if we have any.
2371 if (fndrinfo
!= NULL
) {
2372 if (al
.volattr
& ATTR_VOL_INFO
) {
2373 if (vp
->v_tag
== VT_HFS
) {
2374 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
);
2378 /* XXX should never get here */
2380 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2386 * Set the volume name, if we have one
2388 if (volname
!= NULL
)
2394 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
2395 VFSATTR_WANTED(&vs
, f_vol_name
);
2398 error
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
);
2403 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
2404 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
2408 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
2410 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
2415 /* all done and successful */
2418 if (user_buf
!= NULL
)
2419 FREE(user_buf
, M_TEMP
);
2420 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);
2425 setattrlist(proc_t p
, struct setattrlist_args
*uap
, __unused
int32_t *retval
)
2427 struct vfs_context
*ctx
;
2428 struct nameidata nd
;
2433 ctx
= vfs_context_current();
2438 nameiflags
= AUDITVNPATH1
;
2439 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
2440 nameiflags
|= FOLLOW
;
2441 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
2442 if ((error
= namei(&nd
)) != 0)
2447 error
= setattrlist_internal(vp
, uap
, p
, ctx
);
2455 fsetattrlist(proc_t p
, struct fsetattrlist_args
*uap
, __unused
int32_t *retval
)
2457 struct vfs_context
*ctx
;
2460 struct setattrlist_args ap
;
2462 ctx
= vfs_context_current();
2464 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2467 if ((error
= vnode_getwithref(vp
)) != 0) {
2473 ap
.alist
= uap
->alist
;
2474 ap
.attributeBuffer
= uap
->attributeBuffer
;
2475 ap
.bufferSize
= uap
->bufferSize
;
2476 ap
.options
= uap
->options
;
2478 error
= setattrlist_internal(vp
, &ap
, p
, ctx
);