2 * Copyright (c) 1995-2008 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_RETURNED_ATTRS
, 0, sizeof(attribute_set_t
), 0},
402 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
403 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_dirlinkcount
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
404 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
405 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
408 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
409 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
410 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
411 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
412 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
413 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
414 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
415 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
416 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
417 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
422 * The following are attributes that VFS can derive.
424 * A majority of them are the same attributes that are required for stat(2) and statfs(2).
426 #define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
427 ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
428 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
429 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
430 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
431 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
432 ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
434 #define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
435 ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
436 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
437 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
438 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
439 ATTR_CMN_FNDRINFO | \
440 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
441 ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
442 ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
443 ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS)
445 #define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
447 #define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
448 ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
449 ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
450 ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
451 ATTR_FILE_RSRCALLOCSIZE)
454 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vnode_attr
*vap
,
455 ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
)
457 attrgroup_t recognised
;
461 /* is this attribute set? */
462 if (tab
->attr
& attrs
) {
463 recognised
|= tab
->attr
;
464 vap
->va_active
|= tab
->bits
;
465 if (tab
->size
== ATTR_TIME_SIZE
) {
467 *sizep
+= sizeof(struct user64_timespec
);
469 *sizep
+= sizeof(struct user32_timespec
);
474 *actionp
|= tab
->action
;
475 if (attrs
== recognised
)
476 break; /* all done, get out */
478 } while ((++tab
)->attr
!= 0);
480 /* check to make sure that we recognised all of the passed-in attributes */
481 if (attrs
& ~recognised
)
487 * Given the attributes listed in alp, configure vap to request
488 * the data from a filesystem.
491 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
)
496 * Parse the above tables.
498 *sizep
= sizeof(uint32_t); /* length count */
500 if (alp
->commonattr
&&
501 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
503 if (isdir
&& alp
->dirattr
&&
504 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
506 if (!isdir
&& alp
->fileattr
&&
507 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
514 * Given the attributes listed in asp and those supported
515 * in the vap, fixup the asp attributes to reflect any
516 * missing attributes from the file system
519 getattrlist_fixupattrs(attribute_set_t
*asp
, struct vnode_attr
*vap
)
521 struct getattrlist_attrtab
*tab
;
523 if (asp
->commonattr
) {
524 tab
= getattrlist_common_tab
;
526 if ((tab
->attr
& asp
->commonattr
) &&
527 (tab
->bits
& vap
->va_active
) &&
528 (tab
->bits
& vap
->va_supported
) == 0) {
529 asp
->commonattr
&= ~tab
->attr
;
531 } while ((++tab
)->attr
!= 0);
534 tab
= getattrlist_dir_tab
;
536 if ((tab
->attr
& asp
->dirattr
) &&
537 (tab
->bits
& vap
->va_active
) &&
538 (vap
->va_supported
& tab
->bits
) == 0) {
539 asp
->dirattr
&= ~tab
->attr
;
541 } while ((++tab
)->attr
!= 0);
544 tab
= getattrlist_file_tab
;
546 if ((tab
->attr
& asp
->fileattr
) &&
547 (tab
->bits
& vap
->va_active
) &&
548 (vap
->va_supported
& tab
->bits
) == 0) {
549 asp
->fileattr
&= ~tab
->attr
;
551 } while ((++tab
)->attr
!= 0);
556 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
559 char uio_buf
[UIO_SIZEOF(1)];
562 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
565 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
566 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
571 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
572 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
580 * Find something resembling a terminal component name in the mountedonname for vp
584 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
590 * We're looking for the last sequence of non / characters, but
591 * not including any trailing / characters.
596 for (cp
= mn
; *cp
!= 0; cp
++) {
598 /* start of run of chars */
604 /* end of run of chars */
611 /* need to close run? */
618 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
,
619 vfs_context_t ctx
, int is_64bit
)
622 struct vnode_attr va
;
623 struct _attrlist_buf ab
;
625 ssize_t fixedsize
, varsize
;
626 const char *cnp
= NULL
; /* protected by ATTR_CMN_NAME */
627 ssize_t cnl
= 0; /* protected by ATTR_CMN_NAME */
636 vs
.f_vol_name
= NULL
;
639 /* Check for special packing semantics */
640 return_valid
= (alp
->commonattr
& ATTR_CMN_RETURNED_ATTRS
);
641 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
643 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
648 /* Keep invalid attrs from being uninitialized */
649 bzero(&vs
, sizeof (vs
));
650 /* Generate a valid mask for post processing */
651 bcopy(&alp
->commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
655 * For now, the vnode must be the root of its filesystem.
656 * To relax this, we need to be able to find the root vnode of a filesystem
657 * from any vnode in the filesystem.
659 if (!vnode_isvroot(vp
)) {
661 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
666 * Set up the vfs_attr structure and call the filesystem.
668 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
669 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
672 if (vs
.f_active
!= 0) {
673 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
674 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
675 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
676 if (vs
.f_vol_name
== NULL
) {
678 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
684 error
= mac_mount_check_getattr(ctx
, mnt
, &vs
);
688 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
689 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
690 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
695 * Did we ask for something the filesystem doesn't support?
697 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
698 /* default value for volume subtype */
699 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
700 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
701 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
704 * If the file system didn't supply f_signature, then
705 * default it to 'BD', which is the generic signature
706 * that most Carbon file systems should return.
708 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
709 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
710 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
712 /* default for block size */
713 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
714 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
715 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
717 /* default value for volume f_attributes */
718 if (VFSATTR_IS_ACTIVE(&vs
, f_attributes
)
719 && !VFSATTR_IS_SUPPORTED(&vs
, f_attributes
)) {
720 vol_attributes_attr_t
*attrp
= &vs
.f_attributes
;
722 attrp
->validattr
.commonattr
= VFS_DFLT_ATTR_CMN
;
723 attrp
->validattr
.volattr
= VFS_DFLT_ATTR_VOL
;
724 attrp
->validattr
.dirattr
= VFS_DFLT_ATTR_DIR
;
725 attrp
->validattr
.fileattr
= VFS_DFLT_ATTR_FILE
;
726 attrp
->validattr
.forkattr
= 0;
728 attrp
->nativeattr
.commonattr
= 0;
729 attrp
->nativeattr
.volattr
= 0;
730 attrp
->nativeattr
.dirattr
= 0;
731 attrp
->nativeattr
.fileattr
= 0;
732 attrp
->nativeattr
.forkattr
= 0;
733 VFSATTR_SET_SUPPORTED(&vs
, f_attributes
);
736 /* default value for volume f_capabilities */
737 if (VFSATTR_IS_ACTIVE(&vs
, f_capabilities
)) {
738 /* getattrlist is always supported now. */
739 if (!VFSATTR_IS_SUPPORTED(&vs
, f_capabilities
)) {
740 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] = 0;
741 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
742 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
743 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
745 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] = 0;
746 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] = VOL_CAP_INT_ATTRLIST
;
747 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
748 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
749 VFSATTR_SET_SUPPORTED(&vs
, f_capabilities
);
752 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
753 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
754 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_ATTRLIST
;
758 /* check to see if our fixups were enough */
759 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
762 /* Fix up valid mask for post processing */
763 getvolattrlist_fixupattrs(&ab
.valid
, &vs
);
765 /* Force packing of everything asked for */
766 vs
.f_supported
= vs
.f_active
;
768 /* Adjust the requested attributes */
769 getvolattrlist_fixupattrs((attribute_set_t
*)&alp
->commonattr
, &vs
);
780 * Some fields require data from the root vp
782 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
783 VATTR_WANTED(&va
, va_uid
);
784 VATTR_WANTED(&va
, va_gid
);
785 VATTR_WANTED(&va
, va_mode
);
786 VATTR_WANTED(&va
, va_flags
);
787 VATTR_WANTED(&va
, va_encoding
);
789 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
790 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
794 if (VATTR_IS_ACTIVE(&va
, va_encoding
) &&
795 !VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
796 if (!return_valid
|| pack_invalid
)
797 /* use kTextEncodingMacUnicode */
798 VATTR_RETURN(&va
, va_encoding
, 0x7e);
800 /* don't use a default */
801 alp
->commonattr
&= ~ATTR_CMN_SCRIPT
;
806 * Compute variable-size buffer requirements.
809 if (alp
->commonattr
& ATTR_CMN_NAME
) {
810 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
811 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
812 /* special case for boot volume. Use root name when it's
813 * available (which is the volume name) or just the mount on
814 * name of "/". we must do this for binary compatibility with
815 * pre Tiger code. returning nothing for the boot volume name
816 * breaks installers - 3961058
818 cnp
= vnode_getname(vp
);
820 /* just use "/" as name */
821 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
829 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
831 if (alp
->commonattr
& ATTR_CMN_NAME
)
832 varsize
+= roundup(cnl
+ 1, 4);
834 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
835 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
836 if (alp
->volattr
& ATTR_VOL_NAME
) {
837 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
838 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
840 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
841 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
844 * Allocate a target buffer for attribute results.
845 * Note that since we won't ever copy out more than the caller requested,
846 * we never need to allocate more than they offer.
848 ab
.allocated
= imin(uap
->bufferSize
, fixedsize
+ varsize
);
849 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
851 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
854 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
855 if (ab
.base
== NULL
) {
857 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
862 * Pack results into the destination buffer.
864 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
866 ab
.fixedcursor
+= sizeof (attribute_set_t
);
867 bzero(&ab
.actual
, sizeof (ab
.actual
));
869 ab
.varcursor
= ab
.base
+ fixedsize
;
870 ab
.needed
= fixedsize
+ varsize
;
872 /* common attributes **************************************************/
873 if (alp
->commonattr
& ATTR_CMN_NAME
) {
874 attrlist_pack_string(&ab
, cnp
, cnl
);
875 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
877 if (alp
->commonattr
& ATTR_CMN_DEVID
) {
878 ATTR_PACK4(ab
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
879 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
881 if (alp
->commonattr
& ATTR_CMN_FSID
) {
882 ATTR_PACK8(ab
, mnt
->mnt_vfsstat
.f_fsid
);
883 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
885 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
) {
886 if (!return_valid
|| pack_invalid
)
889 if (alp
->commonattr
& ATTR_CMN_OBJTAG
) {
890 ATTR_PACK4(ab
, vp
->v_tag
);
891 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
893 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
894 if (!return_valid
|| pack_invalid
) {
895 fsobj_id_t f
= {0, 0};
899 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
900 if (!return_valid
|| pack_invalid
) {
901 fsobj_id_t f
= {0, 0};
905 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
906 if (!return_valid
|| pack_invalid
) {
907 fsobj_id_t f
= {0, 0};
911 /* note that this returns the encoding for the volume name, not the node name */
912 if (alp
->commonattr
& ATTR_CMN_SCRIPT
) {
913 ATTR_PACK4(ab
, va
.va_encoding
);
914 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
916 if (alp
->commonattr
& ATTR_CMN_CRTIME
) {
917 ATTR_PACK_TIME(ab
, vs
.f_create_time
, is_64bit
);
918 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
920 if (alp
->commonattr
& ATTR_CMN_MODTIME
) {
921 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
922 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
924 if (alp
->commonattr
& ATTR_CMN_CHGTIME
) {
925 if (!return_valid
|| pack_invalid
)
926 ATTR_PACK_TIME(ab
, vs
.f_modify_time
, is_64bit
);
928 if (alp
->commonattr
& ATTR_CMN_ACCTIME
) {
929 ATTR_PACK_TIME(ab
, vs
.f_access_time
, is_64bit
);
930 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
932 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
) {
933 ATTR_PACK_TIME(ab
, vs
.f_backup_time
, is_64bit
);
934 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
936 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
939 * This attribute isn't really Finder Info, at least for HFS.
941 if (vp
->v_tag
== VT_HFS
) {
942 error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
);
944 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
945 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
946 } else if (!return_valid
) {
949 } else if (!return_valid
|| pack_invalid
) {
950 /* XXX we could at least pass out the volume UUID here */
951 bzero(&f
, sizeof(f
));
952 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
955 if (alp
->commonattr
& ATTR_CMN_OWNERID
) {
956 ATTR_PACK4(ab
, va
.va_uid
);
957 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
959 if (alp
->commonattr
& ATTR_CMN_GRPID
) {
960 ATTR_PACK4(ab
, va
.va_gid
);
961 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
963 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
) {
964 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
965 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
967 if (alp
->commonattr
& ATTR_CMN_FLAGS
) {
968 ATTR_PACK4(ab
, va
.va_flags
);
969 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
971 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
973 if (vnode_isdir(vp
)) {
974 if (vnode_authorize(vp
, NULL
,
975 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
977 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
979 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
982 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
984 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
986 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
991 * Rather than MAC preceding DAC, in this case we want
992 * the smallest set of permissions granted by both MAC & DAC
993 * checks. We won't add back any permissions.
996 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
999 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1002 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1005 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
1006 ATTR_PACK4(ab
, perms
);
1007 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1010 * The following common volume attributes are only
1011 * packed when the pack_invalid mode is enabled.
1016 if (alp
->commonattr
& ATTR_CMN_EXTENDED_SECURITY
)
1017 attrlist_pack_variable(&ab
, NULL
, 0);
1018 if (alp
->commonattr
& ATTR_CMN_UUID
)
1019 ATTR_PACK(&ab
, kauth_null_guid
);
1020 if (alp
->commonattr
& ATTR_CMN_GRPUUID
)
1021 ATTR_PACK(&ab
, kauth_null_guid
);
1022 if (alp
->commonattr
& ATTR_CMN_FILEID
)
1023 ATTR_PACK8(ab
, fid
);
1024 if (alp
->commonattr
& ATTR_CMN_PARENTID
)
1025 ATTR_PACK8(ab
, fid
);
1028 /* volume attributes **************************************************/
1030 if (alp
->volattr
& ATTR_VOL_FSTYPE
) {
1031 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
1032 ab
.actual
.volattr
|= ATTR_VOL_FSTYPE
;
1034 if (alp
->volattr
& ATTR_VOL_SIGNATURE
) {
1035 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
1036 ab
.actual
.volattr
|= ATTR_VOL_SIGNATURE
;
1038 if (alp
->volattr
& ATTR_VOL_SIZE
) {
1039 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
1040 ab
.actual
.volattr
|= ATTR_VOL_SIZE
;
1042 if (alp
->volattr
& ATTR_VOL_SPACEFREE
) {
1043 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
1044 ab
.actual
.volattr
|= ATTR_VOL_SPACEFREE
;
1046 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
) {
1047 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
1048 ab
.actual
.volattr
|= ATTR_VOL_SPACEAVAIL
;
1050 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
) {
1051 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
1052 ab
.actual
.volattr
|= ATTR_VOL_MINALLOCATION
;
1054 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
) {
1055 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
1056 ab
.actual
.volattr
|= ATTR_VOL_ALLOCATIONCLUMP
;
1058 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
) {
1059 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
1060 ab
.actual
.volattr
|= ATTR_VOL_IOBLOCKSIZE
;
1062 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
) {
1063 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
1064 ab
.actual
.volattr
|= ATTR_VOL_OBJCOUNT
;
1066 if (alp
->volattr
& ATTR_VOL_FILECOUNT
) {
1067 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
1068 ab
.actual
.volattr
|= ATTR_VOL_FILECOUNT
;
1070 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
) {
1071 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
1072 ab
.actual
.volattr
|= ATTR_VOL_DIRCOUNT
;
1074 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
) {
1075 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
1076 ab
.actual
.volattr
|= ATTR_VOL_MAXOBJCOUNT
;
1078 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
) {
1079 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
1080 ab
.actual
.volattr
|= ATTR_VOL_MOUNTPOINT
;
1082 if (alp
->volattr
& ATTR_VOL_NAME
) {
1083 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
1084 ab
.actual
.volattr
|= ATTR_VOL_NAME
;
1086 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
) {
1087 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
1088 ab
.actual
.volattr
|= ATTR_VOL_MOUNTFLAGS
;
1090 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
) {
1091 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
1092 ab
.actual
.volattr
|= ATTR_VOL_MOUNTEDDEVICE
;
1094 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
) {
1095 if (!return_valid
|| pack_invalid
)
1096 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
1098 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
1099 /* fix up volume capabilities */
1100 if (vfs_extendedsecurity(mnt
)) {
1101 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1103 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
1105 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
1106 ATTR_PACK(&ab
, vs
.f_capabilities
);
1107 ab
.actual
.volattr
|= ATTR_VOL_CAPABILITIES
;
1109 if (alp
->volattr
& ATTR_VOL_UUID
) {
1110 ATTR_PACK(&ab
, vs
.f_uuid
);
1112 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
1113 /* fix up volume attribute information */
1115 vs
.f_attributes
.validattr
.commonattr
|= VFS_DFLT_ATTR_CMN
;
1116 vs
.f_attributes
.validattr
.volattr
|= VFS_DFLT_ATTR_VOL
;
1117 vs
.f_attributes
.validattr
.dirattr
|= VFS_DFLT_ATTR_DIR
;
1118 vs
.f_attributes
.validattr
.fileattr
|= VFS_DFLT_ATTR_FILE
;
1120 if (vfs_extendedsecurity(mnt
)) {
1121 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1123 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1124 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
1126 ATTR_PACK(&ab
, vs
.f_attributes
);
1127 ab
.actual
.volattr
|= ATTR_VOL_ATTRIBUTES
;
1131 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1132 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1133 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), alp
->commonattr
, alp
->volattr
);
1134 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1135 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1138 * In the compatible case, we report the smaller of the required and returned sizes.
1139 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1140 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1141 * they gave us, so they can always check for truncation themselves.
1143 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1145 /* Return attribute set output if requested. */
1147 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1149 /* Only report the attributes that are valid */
1150 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1151 ab
.actual
.volattr
&= ab
.valid
.volattr
;
1153 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1155 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
1158 if (vs
.f_vol_name
!= NULL
)
1159 kfree(vs
.f_vol_name
, MAXPATHLEN
);
1163 if (ab
.base
!= NULL
)
1164 FREE(ab
.base
, M_TEMP
);
1165 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1170 * Obtain attribute information about a filesystem object.
1174 getattrlist_internal(vnode_t vp
, struct getattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
1177 struct vnode_attr va
;
1178 struct _attrlist_buf ab
;
1179 kauth_action_t action
;
1180 ssize_t fixedsize
, varsize
;
1182 const char *vname
= NULL
;
1184 ssize_t fullpathlen
;
1192 proc_is64
= proc_is64bit(p
);
1202 * Fetch the attribute request.
1204 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
1206 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1211 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1212 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1213 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1216 error
= mac_vnode_check_getattrlist(ctx
, vp
, &al
);
1222 * It is legal to request volume or file attributes,
1226 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
1228 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
1231 /* handle volume attribute request */
1232 error
= getvolattrlist(vp
, uap
, &al
, ctx
, proc_is64
);
1236 /* Check for special packing semantics */
1237 return_valid
= (al
.commonattr
& ATTR_CMN_RETURNED_ATTRS
);
1238 pack_invalid
= (uap
->options
& FSOPT_PACK_INVAL_ATTRS
);
1240 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
1241 if (!return_valid
|| al
.forkattr
) {
1245 /* Keep invalid attrs from being uninitialized */
1246 bzero(&va
, sizeof (va
));
1247 /* Generate a valid mask for post processing */
1248 bcopy(&al
.commonattr
, &ab
.valid
, sizeof (attribute_set_t
));
1251 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
1252 * will have a valid snapshot that we can work from here.
1258 * Set up the vnode_attr structure and authorise.
1260 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64
, (vtype
== VDIR
))) != 0) {
1261 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
1264 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0) {
1265 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
1270 * If we're asking for the full path, allocate a buffer for that.
1272 if (al
.commonattr
& (ATTR_CMN_FULLPATH
)) {
1273 fullpathptr
= (char*) kalloc(MAXPATHLEN
);
1274 if (fullpathptr
== NULL
) {
1276 VFS_DEBUG(ctx
,vp
, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
1282 if (va
.va_active
!= 0) {
1284 * If we're going to ask for va_name, allocate a buffer to point it at
1286 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
1287 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
1288 if (va
.va_name
== NULL
) {
1290 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
1296 * Call the filesystem.
1298 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
1299 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1303 /* did we ask for something the filesystem doesn't support? */
1304 if (!VATTR_ALL_SUPPORTED(&va
)) {
1307 * There are a couple of special cases. If we are after object IDs,
1308 * we can make do with va_fileid.
1310 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
| ATTR_CMN_FILEID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
1311 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
1314 * Many filesystems don't know their parent object id.
1315 * If necessary, attempt to derive it from the vnode.
1317 if ((al
.commonattr
& (ATTR_CMN_PAROBJID
| ATTR_CMN_PARENTID
)) &&
1318 !VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1321 if ((dvp
= vnode_getparent(vp
)) != NULLVP
) {
1322 struct vnode_attr lva
;
1325 VATTR_WANTED(&lva
, va_fileid
);
1326 if (vnode_getattr(dvp
, &lva
, ctx
) == 0 &&
1327 VATTR_IS_SUPPORTED(&va
, va_fileid
)) {
1328 va
.va_parentid
= lva
.va_fileid
;
1329 VATTR_SET_SUPPORTED(&va
, va_parentid
);
1335 * And we can report datasize/alloc from total.
1337 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
1338 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
1339 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
1340 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
1343 * If we don't have an encoding, go with UTF-8
1345 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) &&
1346 !VATTR_IS_SUPPORTED(&va
, va_encoding
) && !return_valid
)
1347 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
1350 * If we don't have a name, we'll get one from the vnode or mount point.
1352 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
1353 VATTR_CLEAR_ACTIVE(&va
, va_name
);
1356 /* If va_dirlinkcount isn't supported use a default of 1. */
1357 if ((al
.dirattr
& ATTR_DIR_LINKCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_dirlinkcount
)) {
1358 VATTR_RETURN(&va
, va_dirlinkcount
, 1);
1362 if (!VATTR_ALL_SUPPORTED(&va
)) {
1365 /* Fix up valid mask for post processing */
1366 getattrlist_fixupattrs(&ab
.valid
, &va
);
1368 /* Force packing of everything asked for */
1369 va
.va_supported
= va
.va_active
;
1371 /* Adjust the requested attributes */
1372 getattrlist_fixupattrs((attribute_set_t
*)&al
.commonattr
, &va
);
1383 * Compute variable-space requirements.
1385 varsize
= 0; /* length count */
1387 /* We may need to fix up the name attribute if requested */
1388 if (al
.commonattr
& ATTR_CMN_NAME
) {
1389 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
1390 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
1394 if (vnode_isvroot(vp
)) {
1395 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
1396 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
1397 /* special case for boot volume. Use root name when it's
1398 * available (which is the volume name) or just the mount on
1399 * name of "/". we must do this for binary compatibility with
1400 * pre Tiger code. returning nothing for the boot volume name
1401 * breaks installers - 3961058
1403 cnp
= vname
= vnode_getname(vp
);
1405 /* just use "/" as name */
1406 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
1411 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
1414 cnp
= vname
= vnode_getname(vp
);
1421 varsize
+= roundup(cnl
+ 1, 4);
1425 * Compute the full path to this vnode, if necessary. This attribute is almost certainly
1426 * not supported by any filesystem, so build the path to this vnode at this time.
1428 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1429 int len
= MAXPATHLEN
;
1431 /* call build_path making sure NOT to use the cache-only behavior */
1432 err
= build_path(vp
, fullpathptr
, len
, &len
, 0, vfs_context_current());
1439 fullpathlen
= strlen(fullpathptr
);
1441 varsize
+= roundup(fullpathlen
+1, 4);
1445 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
1447 * XXX This needs to change at some point; since the blob is opaque in
1448 * user-space this is OK.
1450 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
1451 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
1452 (va
.va_acl
!= NULL
))
1453 varsize
+= roundup(KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
), 4);
1456 * Allocate a target buffer for attribute results.
1458 * Note that we won't ever copy out more than the caller requested, even though
1459 * we might have to allocate more than they offer so that the diagnostic checks
1460 * don't result in a panic if the caller's buffer is too small..
1462 ab
.allocated
= fixedsize
+ varsize
;
1463 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1465 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1468 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1469 if (ab
.base
== NULL
) {
1471 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1475 /* set the S_IFMT bits for the mode */
1476 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1477 switch (vp
->v_type
) {
1479 va
.va_mode
|= S_IFREG
;
1482 va
.va_mode
|= S_IFDIR
;
1485 va
.va_mode
|= S_IFBLK
;
1488 va
.va_mode
|= S_IFCHR
;
1491 va
.va_mode
|= S_IFLNK
;
1494 va
.va_mode
|= S_IFSOCK
;
1497 va
.va_mode
|= S_IFIFO
;
1506 * Pack results into the destination buffer.
1508 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1510 ab
.fixedcursor
+= sizeof (attribute_set_t
);
1511 bzero(&ab
.actual
, sizeof (ab
.actual
));
1513 ab
.varcursor
= ab
.base
+ fixedsize
;
1514 ab
.needed
= ab
.allocated
;
1516 /* common attributes **************************************************/
1517 if (al
.commonattr
& ATTR_CMN_NAME
) {
1518 attrlist_pack_string(&ab
, cnp
, cnl
);
1519 ab
.actual
.commonattr
|= ATTR_CMN_NAME
;
1521 if (al
.commonattr
& ATTR_CMN_DEVID
) {
1522 ATTR_PACK4(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1523 ab
.actual
.commonattr
|= ATTR_CMN_DEVID
;
1525 if (al
.commonattr
& ATTR_CMN_FSID
) {
1526 ATTR_PACK8(ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1527 ab
.actual
.commonattr
|= ATTR_CMN_FSID
;
1529 if (al
.commonattr
& ATTR_CMN_OBJTYPE
) {
1530 ATTR_PACK4(ab
, vtype
);
1531 ab
.actual
.commonattr
|= ATTR_CMN_OBJTYPE
;
1533 if (al
.commonattr
& ATTR_CMN_OBJTAG
) {
1534 ATTR_PACK4(ab
, vp
->v_tag
);
1535 ab
.actual
.commonattr
|= ATTR_CMN_OBJTAG
;
1537 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1540 * Carbon can't deal with us reporting the target ID
1541 * for links. So we ask the filesystem to give us the
1542 * source ID as well, and if it gives us one, we use
1545 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1546 f
.fid_objno
= va
.va_linkid
;
1548 f
.fid_objno
= va
.va_fileid
;
1550 f
.fid_generation
= 0;
1552 ab
.actual
.commonattr
|= ATTR_CMN_OBJID
;
1554 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1557 * Carbon can't deal with us reporting the target ID
1558 * for links. So we ask the filesystem to give us the
1559 * source ID as well, and if it gives us one, we use
1562 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1563 f
.fid_objno
= va
.va_linkid
;
1565 f
.fid_objno
= va
.va_fileid
;
1567 f
.fid_generation
= 0;
1569 ab
.actual
.commonattr
|= ATTR_CMN_OBJPERMANENTID
;
1571 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1574 f
.fid_objno
= va
.va_parentid
; /* could be lossy here! */
1575 f
.fid_generation
= 0;
1577 ab
.actual
.commonattr
|= ATTR_CMN_PAROBJID
;
1579 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1580 if (VATTR_IS_SUPPORTED(&va
, va_encoding
)) {
1581 ATTR_PACK4(ab
, va
.va_encoding
);
1582 ab
.actual
.commonattr
|= ATTR_CMN_SCRIPT
;
1583 } else if (!return_valid
|| pack_invalid
) {
1584 ATTR_PACK4(ab
, 0x7e);
1587 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1588 ATTR_PACK_TIME(ab
, va
.va_create_time
, proc_is64
);
1589 ab
.actual
.commonattr
|= ATTR_CMN_CRTIME
;
1591 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1592 ATTR_PACK_TIME(ab
, va
.va_modify_time
, proc_is64
);
1593 ab
.actual
.commonattr
|= ATTR_CMN_MODTIME
;
1595 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1596 ATTR_PACK_TIME(ab
, va
.va_change_time
, proc_is64
);
1597 ab
.actual
.commonattr
|= ATTR_CMN_CHGTIME
;
1599 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1600 ATTR_PACK_TIME(ab
, va
.va_access_time
, proc_is64
);
1601 ab
.actual
.commonattr
|= ATTR_CMN_ACCTIME
;
1603 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1604 ATTR_PACK_TIME(ab
, va
.va_backup_time
, proc_is64
);
1605 ab
.actual
.commonattr
|= ATTR_CMN_BKUPTIME
;
1607 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1610 char uio_buf
[UIO_SIZEOF(1)];
1612 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1613 uio_buf
, sizeof(uio_buf
))) == NULL
) {
1617 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1618 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
,
1619 &fisize
, XATTR_NOSECURITY
, ctx
);
1622 * Default to zeros if its not available,
1623 * unless ATTR_CMN_RETURNED_ATTRS was requested.
1626 (!return_valid
|| pack_invalid
) &&
1627 ((error
== ENOATTR
) || (error
== ENOENT
) ||
1628 (error
== ENOTSUP
) || (error
== EPERM
))) {
1629 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1630 bzero(ab
.fixedcursor
, 32);
1634 ab
.fixedcursor
+= 32;
1635 ab
.actual
.commonattr
|= ATTR_CMN_FNDRINFO
;
1636 } else if (!return_valid
) {
1637 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1641 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1642 ATTR_PACK4(ab
, va
.va_uid
);
1643 ab
.actual
.commonattr
|= ATTR_CMN_OWNERID
;
1645 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1646 ATTR_PACK4(ab
, va
.va_gid
);
1647 ab
.actual
.commonattr
|= ATTR_CMN_GRPID
;
1649 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1650 ATTR_PACK4(ab
, va
.va_mode
);
1651 ab
.actual
.commonattr
|= ATTR_CMN_ACCESSMASK
;
1653 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1654 ATTR_PACK4(ab
, va
.va_flags
);
1655 ab
.actual
.commonattr
|= ATTR_CMN_FLAGS
;
1657 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1659 if (vtype
== VDIR
) {
1660 if (vnode_authorize(vp
, NULL
,
1661 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
1663 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
1665 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
1668 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
1670 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
1672 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
1678 * Rather than MAC preceding DAC, in this case we want
1679 * the smallest set of permissions granted by both MAC & DAC
1680 * checks. We won't add back any permissions.
1683 if (mac_vnode_check_access(ctx
, vp
, W_OK
) != 0)
1686 if (mac_vnode_check_access(ctx
, vp
, R_OK
) != 0)
1689 if (mac_vnode_check_access(ctx
, vp
, X_OK
) != 0)
1692 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1693 ATTR_PACK4(ab
, perms
);
1694 ab
.actual
.commonattr
|= ATTR_CMN_USERACCESS
;
1696 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1697 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1698 struct kauth_filesec fsec
;
1700 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1702 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1703 fsec
.fsec_owner
= kauth_null_guid
;
1704 fsec
.fsec_group
= kauth_null_guid
;
1705 attrlist_pack_variable2(&ab
, &fsec
, __offsetof(struct kauth_filesec
, fsec_acl
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1706 ab
.actual
.commonattr
|= ATTR_CMN_EXTENDED_SECURITY
;
1707 } else if (!return_valid
|| pack_invalid
) {
1708 attrlist_pack_variable(&ab
, NULL
, 0);
1711 if (al
.commonattr
& ATTR_CMN_UUID
) {
1712 if (VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1713 ATTR_PACK(&ab
, va
.va_uuuid
);
1714 ab
.actual
.commonattr
|= ATTR_CMN_UUID
;
1715 } else if (!return_valid
|| pack_invalid
) {
1716 ATTR_PACK(&ab
, kauth_null_guid
);
1719 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1720 if (VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1721 ATTR_PACK(&ab
, va
.va_guuid
);
1722 ab
.actual
.commonattr
|= ATTR_CMN_GRPUUID
;
1723 } else if (!return_valid
|| pack_invalid
) {
1724 ATTR_PACK(&ab
, kauth_null_guid
);
1727 if (al
.commonattr
& ATTR_CMN_FILEID
) {
1728 ATTR_PACK8(ab
, va
.va_fileid
);
1729 ab
.actual
.commonattr
|= ATTR_CMN_FILEID
;
1731 if (al
.commonattr
& ATTR_CMN_PARENTID
) {
1732 ATTR_PACK8(ab
, va
.va_parentid
);
1733 ab
.actual
.commonattr
|= ATTR_CMN_PARENTID
;
1736 if (al
.commonattr
& ATTR_CMN_FULLPATH
) {
1737 attrlist_pack_string (&ab
, fullpathptr
, fullpathlen
);
1738 ab
.actual
.commonattr
|= ATTR_CMN_FULLPATH
;
1741 /* directory attributes *********************************************/
1742 if (al
.dirattr
&& (vtype
== VDIR
)) {
1743 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) { /* full count of entries */
1744 ATTR_PACK4(ab
, (uint32_t)va
.va_dirlinkcount
);
1745 ab
.actual
.dirattr
|= ATTR_DIR_LINKCOUNT
;
1747 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) {
1748 ATTR_PACK4(ab
, (uint32_t)va
.va_nchildren
);
1749 ab
.actual
.dirattr
|= ATTR_DIR_ENTRYCOUNT
;
1751 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
) {
1752 ATTR_PACK_CAST(&ab
, uint32_t, (vp
->v_flag
& VROOT
) ?
1753 DIR_MNTSTATUS_MNTPOINT
: 0);
1754 ab
.actual
.dirattr
|= ATTR_DIR_MOUNTSTATUS
;
1758 /* file attributes **************************************************/
1759 if (al
.fileattr
&& (vtype
!= VDIR
)) {
1760 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
) {
1761 ATTR_PACK4(ab
, (uint32_t)va
.va_nlink
);
1762 ab
.actual
.fileattr
|= ATTR_FILE_LINKCOUNT
;
1764 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
) {
1765 ATTR_PACK8(ab
, va
.va_total_size
);
1766 ab
.actual
.fileattr
|= ATTR_FILE_TOTALSIZE
;
1768 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
) {
1769 ATTR_PACK8(ab
, va
.va_total_alloc
);
1770 ab
.actual
.fileattr
|= ATTR_FILE_ALLOCSIZE
;
1772 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
) {
1773 ATTR_PACK4(ab
, va
.va_iosize
);
1774 ab
.actual
.fileattr
|= ATTR_FILE_IOBLOCKSIZE
;
1776 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
) {
1777 if (!return_valid
|| pack_invalid
) {
1778 ATTR_PACK4(ab
, 0); /* this value is deprecated */
1779 ab
.actual
.fileattr
|= ATTR_FILE_CLUMPSIZE
;
1782 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1785 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1786 if (vp
->v_specinfo
!= NULL
)
1787 dev
= vp
->v_specinfo
->si_rdev
;
1793 ATTR_PACK4(ab
, dev
);
1794 ab
.actual
.fileattr
|= ATTR_FILE_DEVTYPE
;
1796 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
1797 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1798 ATTR_PACK8(ab
, va
.va_data_size
);
1800 ATTR_PACK8(ab
, va
.va_total_size
);
1802 ab
.actual
.fileattr
|= ATTR_FILE_DATALENGTH
;
1804 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
1805 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1806 ATTR_PACK8(ab
, va
.va_data_alloc
);
1808 ATTR_PACK8(ab
, va
.va_total_alloc
);
1810 ab
.actual
.fileattr
|= ATTR_FILE_DATAALLOCSIZE
;
1812 /* fetch resource fork size/allocation via xattr interface */
1813 if (al
.fileattr
& (ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1817 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, ctx
)) != 0) {
1818 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)) {
1825 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
) {
1827 ATTR_PACK8(ab
, rlength
);
1828 ab
.actual
.fileattr
|= ATTR_FILE_RSRCLENGTH
;
1830 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
1831 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1834 rlength
= roundup(rsize
, blksize
);
1835 ATTR_PACK8(ab
, rlength
);
1836 ab
.actual
.fileattr
|= ATTR_FILE_RSRCALLOCSIZE
;
1842 if (!return_valid
&& (ab
.fixedcursor
- ab
.base
) != fixedsize
)
1843 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
1844 fixedsize
, (long) (ab
.fixedcursor
- ab
.base
), al
.commonattr
, al
.volattr
);
1845 if (!return_valid
&& ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1846 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab
.varcursor
- ab
.base
), ab
.needed
);
1849 * In the compatible case, we report the smaller of the required and returned sizes.
1850 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1851 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1852 * they gave us, so they can always check for truncation themselves.
1854 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1856 /* Return attribute set output if requested. */
1858 ab
.actual
.commonattr
|= ATTR_CMN_RETURNED_ATTRS
;
1860 /* Only report the attributes that are valid */
1861 ab
.actual
.commonattr
&= ab
.valid
.commonattr
;
1862 ab
.actual
.dirattr
&= ab
.valid
.dirattr
;
1863 ab
.actual
.fileattr
&= ab
.valid
.fileattr
;
1865 bcopy(&ab
.actual
, ab
.base
+ sizeof(uint32_t), sizeof (ab
.actual
));
1868 /* Only actually copyout as much out as the user buffer can hold */
1869 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
1873 kfree(va
.va_name
, MAXPATHLEN
);
1875 kfree(fullpathptr
, MAXPATHLEN
);
1877 vnode_putname(vname
);
1878 if (ab
.base
!= NULL
)
1879 FREE(ab
.base
, M_TEMP
);
1880 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
1881 kauth_acl_free(va
.va_acl
);
1883 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1888 fgetattrlist(proc_t p
, struct fgetattrlist_args
*uap
, __unused
int32_t *retval
)
1890 struct vfs_context
*ctx
;
1893 struct getattrlist_args ap
;
1895 ctx
= vfs_context_current();
1898 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
1901 if ((error
= vnode_getwithref(vp
)) != 0) {
1907 ap
.alist
= uap
->alist
;
1908 ap
.attributeBuffer
= uap
->attributeBuffer
;
1909 ap
.bufferSize
= uap
->bufferSize
;
1910 ap
.options
= uap
->options
;
1912 error
= getattrlist_internal(vp
, &ap
, p
, ctx
);
1922 getattrlist(proc_t p
, struct getattrlist_args
*uap
, __unused
int32_t *retval
)
1924 struct vfs_context
*ctx
;
1925 struct nameidata nd
;
1930 ctx
= vfs_context_current();
1936 nameiflags
= NOTRIGGER
| AUDITVNPATH1
;
1937 if (!(uap
->options
& FSOPT_NOFOLLOW
))
1938 nameiflags
|= FOLLOW
;
1939 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
1941 if ((error
= namei(&nd
)) != 0)
1946 error
= getattrlist_internal(vp
, uap
, p
, ctx
);
1954 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
1956 /* make sure we have enough source data */
1957 if ((*cursor
) + size
> end
)
1960 bcopy(*cursor
, buf
, size
);
1965 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
1966 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
1967 #define ATTR_UNPACK_TIME(v, is64) \
1970 struct user64_timespec us; \
1972 v.tv_sec = us.tv_sec; \
1973 v.tv_nsec = us.tv_nsec; \
1975 struct user32_timespec us; \
1977 v.tv_sec = us.tv_sec; \
1978 v.tv_nsec = us.tv_nsec; \
1987 setattrlist_internal(vnode_t vp
, struct setattrlist_args
*uap
, proc_t p
, vfs_context_t ctx
)
1990 struct vnode_attr va
;
1991 struct attrreference ar
;
1992 kauth_action_t action
;
1993 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
1994 int proc_is64
, error
;
1996 kauth_filesec_t rfsec
;
2002 proc_is64
= proc_is64bit(p
);
2006 * Fetch the attribute set and validate.
2008 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
2010 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
2015 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
2016 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
2017 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
2020 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
2021 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
2025 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
2029 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
2030 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
2031 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
2032 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
2034 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
2040 * Make the naive assumption that the caller has supplied a reasonable buffer
2041 * size. We could be more careful by pulling in the fixed-size region, checking
2042 * the attrref structures, then pulling in the variable section.
2043 * We need to reconsider this for handling large ACLs, as they should probably be
2044 * brought directly into a buffer. Multiple copyins will make this slower though.
2046 * We could also map the user buffer if it is larger than some sensible mimimum.
2048 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
2049 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
2053 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
2054 if (user_buf
== NULL
) {
2055 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
2059 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
2060 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
2063 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
2066 error
= mac_vnode_check_setattrlist(ctx
, vp
, &al
);
2072 * Unpack the argument buffer.
2075 bufend
= cursor
+ uap
->bufferSize
;
2078 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
2079 ATTR_UNPACK(va
.va_encoding
);
2080 VATTR_SET_ACTIVE(&va
, va_encoding
);
2082 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
2083 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
2084 VATTR_SET_ACTIVE(&va
, va_create_time
);
2086 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
2087 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
2088 VATTR_SET_ACTIVE(&va
, va_modify_time
);
2090 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
2091 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
2092 VATTR_SET_ACTIVE(&va
, va_change_time
);
2094 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
2095 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
2096 VATTR_SET_ACTIVE(&va
, va_access_time
);
2098 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
2099 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
2100 VATTR_SET_ACTIVE(&va
, va_backup_time
);
2102 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
2103 if ((cursor
+ 32) > bufend
) {
2105 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
2111 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
2112 ATTR_UNPACK(va
.va_uid
);
2113 VATTR_SET_ACTIVE(&va
, va_uid
);
2115 if (al
.commonattr
& ATTR_CMN_GRPID
) {
2116 ATTR_UNPACK(va
.va_gid
);
2117 VATTR_SET_ACTIVE(&va
, va_gid
);
2119 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
2120 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
2121 VATTR_SET_ACTIVE(&va
, va_mode
);
2123 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
2124 ATTR_UNPACK(va
.va_flags
);
2125 VATTR_SET_ACTIVE(&va
, va_flags
);
2127 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
2130 * We are (for now) passed a kauth_filesec_t, but all we want from
2135 cp
+= ar
.attr_dataoffset
;
2136 rfsec
= (kauth_filesec_t
)cp
;
2137 if (((((char *)rfsec
) + KAUTH_FILESEC_SIZE(0)) > bufend
) || /* no space for acl */
2138 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
2139 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
2140 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
2142 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
2145 nace
= rfsec
->fsec_entrycount
;
2146 if (nace
== KAUTH_FILESEC_NOACL
)
2148 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2150 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
2153 nace
= rfsec
->fsec_acl
.acl_entrycount
;
2154 if (nace
== KAUTH_FILESEC_NOACL
) {
2156 VATTR_SET(&va
, va_acl
, NULL
);
2159 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
2161 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
2164 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
2167 if (al
.commonattr
& ATTR_CMN_UUID
) {
2168 ATTR_UNPACK(va
.va_uuuid
);
2169 VATTR_SET_ACTIVE(&va
, va_uuuid
);
2171 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
2172 ATTR_UNPACK(va
.va_guuid
);
2173 VATTR_SET_ACTIVE(&va
, va_guuid
);
2177 if (al
.volattr
& ATTR_VOL_INFO
) {
2178 if (al
.volattr
& ATTR_VOL_NAME
) {
2181 volname
+= ar
.attr_dataoffset
;
2182 if ((volname
+ ar
.attr_length
) > bufend
) {
2184 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
2187 /* guarantee NUL termination */
2188 volname
[ar
.attr_length
- 1] = 0;
2193 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
2194 /* XXX does it actually make any sense to change this? */
2196 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
2201 * Validate and authorize.
2204 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)) {
2205 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
2209 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
2210 * and will be auth'ed by the FS.
2212 if (fndrinfo
!= NULL
) {
2213 if (al
.volattr
& ATTR_VOL_INFO
) {
2214 if (vp
->v_tag
!= VT_HFS
) {
2219 action
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
2223 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2224 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
2229 * When we're setting both the access mask and the finder info, then
2230 * check if were about to remove write access for the owner. Since
2231 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
2232 * to consider their ordering.
2234 * If were about to remove write access for the owner we'll set the
2235 * Finder Info here before vnode_setattr. Otherwise we'll set it
2236 * after vnode_setattr since it may be adding owner write access.
2238 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
2239 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
2240 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2243 fndrinfo
= NULL
; /* it was set here so skip setting below */
2247 * Write the attributes if we have any.
2249 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, ctx
)) != 0)) {
2250 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
2255 * Write the Finder Info if we have any.
2257 if (fndrinfo
!= NULL
) {
2258 if (al
.volattr
& ATTR_VOL_INFO
) {
2259 if (vp
->v_tag
== VT_HFS
) {
2260 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, ctx
);
2264 /* XXX should never get here */
2266 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, ctx
)) != 0) {
2272 * Set the volume name, if we have one
2274 if (volname
!= NULL
)
2280 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
2281 VFSATTR_WANTED(&vs
, f_vol_name
);
2284 error
= mac_mount_check_setattr(ctx
, vp
->v_mount
, &vs
);
2289 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
2290 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
2294 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
2296 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
2301 /* all done and successful */
2304 if (user_buf
!= NULL
)
2305 FREE(user_buf
, M_TEMP
);
2306 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);
2311 setattrlist(proc_t p
, struct setattrlist_args
*uap
, __unused
int32_t *retval
)
2313 struct vfs_context
*ctx
;
2314 struct nameidata nd
;
2319 ctx
= vfs_context_current();
2325 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
2326 nameiflags
|= FOLLOW
;
2327 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
2328 if ((error
= namei(&nd
)) != 0)
2333 error
= setattrlist_internal(vp
, uap
, p
, ctx
);
2341 fsetattrlist(proc_t p
, struct fsetattrlist_args
*uap
, __unused
int32_t *retval
)
2343 struct vfs_context
*ctx
;
2346 struct setattrlist_args ap
;
2348 ctx
= vfs_context_current();
2350 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
2353 if ((error
= vnode_getwithref(vp
)) != 0) {
2359 ap
.alist
= uap
->alist
;
2360 ap
.attributeBuffer
= uap
->attributeBuffer
;
2361 ap
.bufferSize
= uap
->bufferSize
;
2362 ap
.options
= uap
->options
;
2364 error
= setattrlist_internal(vp
, &ap
, p
, ctx
);