2 * Copyright (c) 1995-2005 Apple Computer, 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 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/namei.h>
32 #include <sys/kernel.h>
34 #include <sys/vnode_internal.h>
35 #include <sys/mount_internal.h>
36 #include <sys/proc_internal.h>
37 #include <sys/kauth.h>
38 #include <sys/uio_internal.h>
39 #include <sys/malloc.h>
41 #include <sys/sysproto.h>
42 #include <sys/xattr.h>
43 #include <sys/fsevents.h>
44 #include <kern/kalloc.h>
45 #include <miscfs/specfs/specdev.h>
48 #define ATTR_TIME_SIZE -1
51 * Structure describing the state of an in-progress attrlist operation.
53 struct _attrlist_buf
{
63 * Pack (count) bytes from (source) into (buf).
66 attrlist_pack_fixed(struct _attrlist_buf
*ab
, void *source
, ssize_t count
)
70 /* how much room left in the buffer? */
71 fit
= imin(count
, ab
->allocated
- (ab
->fixedcursor
- ab
->base
));
73 bcopy(source
, ab
->fixedcursor
, fit
);
75 /* always move in increments of 4 */
76 ab
->fixedcursor
+= roundup(count
, 4);
79 attrlist_pack_variable2(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
, const void *ext
, ssize_t extcount
)
81 struct attrreference ar
;
84 /* pack the reference to the variable object */
85 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
86 ar
.attr_length
= count
+ extcount
;
87 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
89 /* calculate space and pack the variable object */
90 fit
= imin(count
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
93 bcopy(source
, ab
->varcursor
, fit
);
96 fit
= imin(extcount
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
99 bcopy(ext
, ab
->varcursor
, fit
);
100 ab
->varcursor
+= fit
;
102 /* always move in increments of 4 */
103 ab
->varcursor
= (char *)roundup((uintptr_t)ab
->varcursor
, 4);
106 attrlist_pack_variable(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
)
108 attrlist_pack_variable2(ab
, source
, count
, NULL
, 0);
111 attrlist_pack_string(struct _attrlist_buf
*ab
, const char *source
, ssize_t count
)
113 struct attrreference ar
;
118 * Supplied count is character count of string text, excluding trailing nul
119 * which we always supply here.
121 if (source
== NULL
) {
123 } else if (count
== 0) {
124 count
= strlen(source
);
128 * Make the reference and pack it.
129 * Note that this is entirely independent of how much we get into
132 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
133 ar
.attr_length
= count
+ 1;
134 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
136 /* calculate how much of the string text we can copy, and do that */
137 space
= ab
->allocated
- (ab
->varcursor
- ab
->base
);
138 fit
= imin(count
, space
);
140 bcopy(source
, ab
->varcursor
, fit
);
141 /* is there room for our trailing nul? */
143 ab
->varcursor
[fit
] = '\0';
145 /* always move in increments of 4 */
146 ab
->varcursor
+= roundup(count
+ 1, 4);
149 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
150 #define ATTR_PACK_CAST(b, t, v) \
156 #define ATTR_PACK_TIME(b, v, is64) \
159 struct user_timespec us = {v.tv_sec, v.tv_nsec}; \
168 * Table-driven setup for all valid common/volume attributes.
170 struct getvolattrlist_attrtab
{
173 #define VFSATTR_BIT(b) (VFSATTR_ ## b)
176 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = {
177 {ATTR_CMN_NAME
, 0, sizeof(struct attrreference
)},
178 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
)},
179 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
)},
180 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
)},
181 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
)},
182 {ATTR_CMN_OBJID
, 0, sizeof(fsobj_id_t
)},
183 {ATTR_CMN_OBJPERMANENTID
, 0, sizeof(fsobj_id_t
)},
184 {ATTR_CMN_PAROBJID
, 0, sizeof(fsobj_id_t
)},
185 {ATTR_CMN_SCRIPT
, 0, sizeof(text_encoding_t
)},
186 {ATTR_CMN_CRTIME
, VFSATTR_BIT(f_create_time
), ATTR_TIME_SIZE
},
187 {ATTR_CMN_MODTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
188 {ATTR_CMN_CHGTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
189 {ATTR_CMN_ACCTIME
, VFSATTR_BIT(f_access_time
), ATTR_TIME_SIZE
},
190 {ATTR_CMN_BKUPTIME
, VFSATTR_BIT(f_backup_time
), ATTR_TIME_SIZE
},
191 {ATTR_CMN_FNDRINFO
, 0, 32},
192 {ATTR_CMN_OWNERID
, 0, sizeof(uid_t
)},
193 {ATTR_CMN_GRPID
, 0, sizeof(gid_t
)},
194 {ATTR_CMN_ACCESSMASK
, 0, sizeof(uint32_t)},
195 {ATTR_CMN_FLAGS
, 0, sizeof(uint32_t)},
196 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t)},
200 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = {
201 {ATTR_VOL_FSTYPE
, 0, sizeof(uint32_t)},
202 {ATTR_VOL_SIGNATURE
, VFSATTR_BIT(f_signature
), sizeof(uint32_t)},
203 {ATTR_VOL_SIZE
, VFSATTR_BIT(f_blocks
), sizeof(off_t
)},
204 {ATTR_VOL_SPACEFREE
, VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
205 {ATTR_VOL_SPACEAVAIL
, VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
206 {ATTR_VOL_MINALLOCATION
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
207 {ATTR_VOL_ALLOCATIONCLUMP
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
208 {ATTR_VOL_IOBLOCKSIZE
, VFSATTR_BIT(f_iosize
), sizeof(uint32_t)},
209 {ATTR_VOL_OBJCOUNT
, VFSATTR_BIT(f_objcount
), sizeof(uint32_t)},
210 {ATTR_VOL_FILECOUNT
, VFSATTR_BIT(f_filecount
), sizeof(uint32_t)},
211 {ATTR_VOL_DIRCOUNT
, VFSATTR_BIT(f_dircount
), sizeof(uint32_t)},
212 {ATTR_VOL_MAXOBJCOUNT
, VFSATTR_BIT(f_maxobjcount
), sizeof(uint32_t)},
213 {ATTR_VOL_MOUNTPOINT
, 0, sizeof(struct attrreference
)},
214 {ATTR_VOL_NAME
, VFSATTR_BIT(f_vol_name
), sizeof(struct attrreference
)},
215 {ATTR_VOL_MOUNTFLAGS
, 0, sizeof(uint32_t)},
216 {ATTR_VOL_MOUNTEDDEVICE
, 0, sizeof(struct attrreference
)},
217 {ATTR_VOL_ENCODINGSUSED
, 0, sizeof(uint64_t)},
218 {ATTR_VOL_CAPABILITIES
, VFSATTR_BIT(f_capabilities
), sizeof(vol_capabilities_attr_t
)},
219 {ATTR_VOL_ATTRIBUTES
, VFSATTR_BIT(f_attributes
), sizeof(vol_attributes_attr_t
)},
220 {ATTR_VOL_INFO
, 0, 0},
225 getvolattrlist_parsetab(struct getvolattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vfs_attr
*vsp
,
226 ssize_t
*sizep
, int is_64bit
)
228 attrgroup_t recognised
;
232 /* is this attribute set? */
233 if (tab
->attr
& attrs
) {
234 recognised
|= tab
->attr
;
235 vsp
->f_active
|= tab
->bits
;
236 if (tab
->size
== ATTR_TIME_SIZE
) {
238 *sizep
+= sizeof(struct user_timespec
);
240 *sizep
+= sizeof(struct timespec
);
246 } while ((++tab
)->attr
!= 0);
248 /* check to make sure that we recognised all of the passed-in attributes */
249 if (attrs
& ~recognised
)
255 * Given the attributes listed in alp, configure vap to request
256 * the data from a filesystem.
259 getvolattrlist_setupvfsattr(struct attrlist
*alp
, struct vfs_attr
*vsp
, ssize_t
*sizep
, int is_64bit
)
264 * Parse the above tables.
266 *sizep
= sizeof(uint32_t); /* length count */
267 if (alp
->commonattr
&&
268 (error
= getvolattrlist_parsetab(getvolattrlist_common_tab
, alp
->commonattr
, vsp
, sizep
, is_64bit
)) != 0)
271 (error
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
)) != 0)
278 * Table-driven setup for all valid common/dir/file/fork attributes against files.
280 struct getattrlist_attrtab
{
283 #define VATTR_BIT(b) (VNODE_ATTR_ ## b)
285 kauth_action_t action
;
287 static struct getattrlist_attrtab getattrlist_common_tab
[] = {
288 {ATTR_CMN_NAME
, VATTR_BIT(va_name
), sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
289 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
290 {ATTR_CMN_FSID
, VATTR_BIT(va_fsid
), sizeof(fsid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
291 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
292 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
293 {ATTR_CMN_OBJID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
294 {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
295 {ATTR_CMN_PAROBJID
, VATTR_BIT(va_parentid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
296 {ATTR_CMN_SCRIPT
, VATTR_BIT(va_encoding
), sizeof(text_encoding_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
297 {ATTR_CMN_CRTIME
, VATTR_BIT(va_create_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
298 {ATTR_CMN_MODTIME
, VATTR_BIT(va_modify_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
299 {ATTR_CMN_CHGTIME
, VATTR_BIT(va_change_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
300 {ATTR_CMN_ACCTIME
, VATTR_BIT(va_access_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
301 {ATTR_CMN_BKUPTIME
, VATTR_BIT(va_backup_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
302 {ATTR_CMN_FNDRINFO
, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES
},
303 {ATTR_CMN_OWNERID
, VATTR_BIT(va_uid
), sizeof(uid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
304 {ATTR_CMN_GRPID
, VATTR_BIT(va_gid
), sizeof(gid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
305 {ATTR_CMN_ACCESSMASK
, VATTR_BIT(va_mode
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
306 {ATTR_CMN_FLAGS
, VATTR_BIT(va_flags
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
307 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
308 {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
), sizeof(struct attrreference
), KAUTH_VNODE_READ_SECURITY
},
309 {ATTR_CMN_UUID
, VATTR_BIT(va_uuuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
310 {ATTR_CMN_GRPUUID
, VATTR_BIT(va_guuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
313 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
314 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
315 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
316 /* ATTR_DIR_ENTRYCOUNT falls back to va_nlink-2 if va_nchildren isn't supported, so request va_nlink just in case */
317 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nlink
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
318 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
321 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
322 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
323 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
324 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
325 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
326 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
327 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
328 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
329 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
330 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
335 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vnode_attr
*vap
,
336 ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
)
338 attrgroup_t recognised
;
342 /* is this attribute set? */
343 if (tab
->attr
& attrs
) {
344 recognised
|= tab
->attr
;
345 vap
->va_active
|= tab
->bits
;
346 if (tab
->size
== ATTR_TIME_SIZE
) {
348 *sizep
+= sizeof(struct user_timespec
);
350 *sizep
+= sizeof(struct timespec
);
355 *actionp
|= tab
->action
;
357 } while ((++tab
)->attr
!= 0);
359 /* check to make sure that we recognised all of the passed-in attributes */
360 if (attrs
& ~recognised
)
366 * Given the attributes listed in alp, configure vap to request
367 * the data from a filesystem.
370 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
)
375 * Parse the above tables.
377 *sizep
= sizeof(uint32_t); /* length count */
379 if (alp
->commonattr
&&
380 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
382 if (isdir
&& alp
->dirattr
&&
383 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
385 if (!isdir
&& alp
->fileattr
&&
386 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
393 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
396 char uio_buf
[UIO_SIZEOF(1)];
399 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
402 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
403 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
407 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
408 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
416 * Find something resembling a terminal component name in the mountedonname for vp
420 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
426 * We're looking for the last sequence of non / characters, but
427 * not including any trailing / characters.
432 for (cp
= mn
; *cp
!= 0; cp
++) {
434 /* start of run of chars */
440 /* end of run of chars */
447 /* need to close run? */
454 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
, vfs_context_t ctx
, int is_64bit
)
457 struct vnode_attr va
;
458 struct _attrlist_buf ab
;
460 ssize_t fixedsize
, varsize
;
468 vs
.f_vol_name
= NULL
;
473 * For now, the vnode must be the root of its filesystem.
474 * To relax this, we need to be able to find the root vnode of a filesystem
475 * from any vnode in the filesystem.
477 if (!vnode_isvroot(vp
)) {
479 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
484 * Set up the vfs_attr structure and call the filesystem.
486 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
487 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
490 if (vs
.f_active
!= 0) {
491 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
492 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
493 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
494 if (vs
.f_vol_name
== NULL
) {
496 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
501 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
502 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
503 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
508 * Did we ask for something the filesystem doesn't support?
510 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
511 /* default value for volume subtype */
512 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
513 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
514 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
517 * If the file system didn't supply f_signature, then
518 * default it to 'BD', which is the generic signature
519 * that most Carbon file systems should return.
521 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
522 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
523 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
525 /* default for block size */
526 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
527 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
528 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
530 /* check to see if our fixups were enough */
531 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
533 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not get all requested volume attributes");
534 VFS_DEBUG(ctx
, vp
, "ATTRLIST - wanted %016llx got %016llx missing %016llx",
535 vs
.f_active
, vs
.f_supported
, vs
.f_active
& ~vs
.f_supported
);
542 * Some fields require data from the root vp
544 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
545 VATTR_WANTED(&va
, va_uid
);
546 VATTR_WANTED(&va
, va_gid
);
547 VATTR_WANTED(&va
, va_mode
);
548 VATTR_WANTED(&va
, va_flags
);
549 VATTR_WANTED(&va
, va_encoding
);
551 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
552 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
556 if (VATTR_IS_ACTIVE(&va
, va_encoding
) && !VATTR_IS_SUPPORTED(&va
, va_encoding
))
557 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
561 * Compute variable-size buffer requirements.
564 if (alp
->commonattr
& ATTR_CMN_NAME
) {
565 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
566 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
567 /* special case for boot volume. Use root name when it's
568 * available (which is the volume name) or just the mount on
569 * name of "/". we must do this for binary compatibility with
570 * pre Tiger code. returning nothing for the boot volume name
571 * breaks installers - 3961058
573 cnp
= vnode_getname(vp
);
575 /* just use "/" as name */
576 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
581 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
583 if (alp
->commonattr
& ATTR_CMN_NAME
)
584 varsize
+= roundup(cnl
+ 1, 4);
586 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
587 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
588 if (alp
->volattr
& ATTR_VOL_NAME
) {
589 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
590 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
592 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
593 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
596 * Allocate a target buffer for attribute results.
597 * Note that since we won't ever copy out more than the caller requested,
598 * we never need to allocate more than they offer.
600 ab
.allocated
= imin(uap
->bufferSize
, fixedsize
+ varsize
);
601 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
603 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
606 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
607 if (ab
.base
== NULL
) {
609 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
614 * Pack results into the destination buffer.
616 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
617 ab
.varcursor
= ab
.base
+ fixedsize
;
618 ab
.needed
= fixedsize
+ varsize
;
620 /* common attributes **************************************************/
621 if (alp
->commonattr
& ATTR_CMN_NAME
)
622 attrlist_pack_string(&ab
, cnp
, cnl
);
623 if (alp
->commonattr
& ATTR_CMN_DEVID
)
624 ATTR_PACK_CAST(&ab
, dev_t
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
625 if (alp
->commonattr
& ATTR_CMN_FSID
)
626 ATTR_PACK(&ab
, mnt
->mnt_vfsstat
.f_fsid
);
627 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
)
628 ATTR_PACK_CAST(&ab
, fsobj_type_t
, 0);
629 if (alp
->commonattr
& ATTR_CMN_OBJTAG
)
630 ATTR_PACK_CAST(&ab
, fsobj_tag_t
, vp
->v_tag
);
631 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
632 fsobj_id_t f
= {0, 0};
635 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
636 fsobj_id_t f
= {0, 0};
639 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
640 fsobj_id_t f
= {0, 0};
643 /* note that this returns the encoding for the volume name, not the node name */
644 if (alp
->commonattr
& ATTR_CMN_SCRIPT
)
645 ATTR_PACK_CAST(&ab
, text_encoding_t
, va
.va_encoding
);
646 if (alp
->commonattr
& ATTR_CMN_CRTIME
)
647 ATTR_PACK_TIME(&ab
, vs
.f_create_time
, is_64bit
);
648 if (alp
->commonattr
& ATTR_CMN_MODTIME
)
649 ATTR_PACK_TIME(&ab
, vs
.f_modify_time
, is_64bit
);
650 if (alp
->commonattr
& ATTR_CMN_CHGTIME
)
651 ATTR_PACK_TIME(&ab
, vs
.f_modify_time
, is_64bit
);
652 if (alp
->commonattr
& ATTR_CMN_ACCTIME
)
653 ATTR_PACK_TIME(&ab
, vs
.f_access_time
, is_64bit
);
654 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
)
655 ATTR_PACK_TIME(&ab
, vs
.f_backup_time
, is_64bit
);
656 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
659 * This attribute isn't really Finder Info, at least for HFS.
661 if (vp
->v_tag
== VT_HFS
) {
662 if ((error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
)) != 0)
665 /* XXX we could at least pass out the volume UUID here */
666 bzero(&f
, sizeof(f
));
668 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
670 if (alp
->commonattr
& ATTR_CMN_OWNERID
)
671 ATTR_PACK(&ab
, va
.va_uid
);
672 if (alp
->commonattr
& ATTR_CMN_GRPID
)
673 ATTR_PACK(&ab
, va
.va_gid
);
674 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
)
675 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
676 if (alp
->commonattr
& ATTR_CMN_FLAGS
)
677 ATTR_PACK(&ab
, va
.va_flags
);
678 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
680 if (vnode_isdir(vp
)) {
681 if (vnode_authorize(vp
, NULL
,
682 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
684 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
686 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
689 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
691 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
693 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
696 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
697 ATTR_PACK(&ab
, perms
);
700 /* volume attributes **************************************************/
702 if (alp
->volattr
& ATTR_VOL_FSTYPE
)
703 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
704 if (alp
->volattr
& ATTR_VOL_SIGNATURE
)
705 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
706 if (alp
->volattr
& ATTR_VOL_SIZE
)
707 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
708 if (alp
->volattr
& ATTR_VOL_SPACEFREE
)
709 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
710 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
)
711 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
712 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
)
713 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
714 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
)
715 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
716 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
)
717 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
718 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
)
719 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
720 if (alp
->volattr
& ATTR_VOL_FILECOUNT
)
721 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
722 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
)
723 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
724 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
)
725 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
726 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
727 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
728 if (alp
->volattr
& ATTR_VOL_NAME
)
729 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
730 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
)
731 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
732 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
733 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
734 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
)
735 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
736 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
737 /* fix up volume capabilities */
738 if (vfs_extendedsecurity(mnt
)) {
739 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
741 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
743 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
744 ATTR_PACK(&ab
, vs
.f_capabilities
);
746 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
747 /* fix up volume attribute information */
748 if (vfs_extendedsecurity(mnt
)) {
749 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
751 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
752 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
754 ATTR_PACK(&ab
, vs
.f_attributes
);
758 if ((ab
.fixedcursor
- ab
.base
) != fixedsize
)
759 panic("packed field size mismatch; allocated %d but packed %d for common %08x vol %08x",
760 fixedsize
, ab
.fixedcursor
- ab
.base
, alp
->commonattr
, alp
->volattr
);
761 if (ab
.varcursor
!= (ab
.base
+ ab
.needed
))
762 panic("packed variable field size mismatch; used %d but expected %d", ab
.varcursor
- ab
.base
, ab
.needed
);
765 * In the compatible case, we report the smaller of the required and returned sizes.
766 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
767 * of the result buffer, even if we copied less out. The caller knows how big a buffer
768 * they gave us, so they can always check for truncation themselves.
770 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
772 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
775 if (vs
.f_vol_name
!= NULL
)
776 kfree(vs
.f_vol_name
, MAXPATHLEN
);
778 FREE(ab
.base
, M_TEMP
);
779 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
784 * Obtain attribute information about a filesystem object.
787 getattrlist(struct proc
*p
, struct getattrlist_args
*uap
, __unused register_t
*retval
)
790 struct vnode_attr va
;
791 struct vfs_context context
, *ctx
;
793 struct _attrlist_buf ab
;
796 kauth_action_t action
;
797 ssize_t fixedsize
, varsize
;
804 context
.vc_ucred
= kauth_cred_get();
817 nameiflags
= AUDITVNPATH1
;
818 if (!(uap
->options
& FSOPT_NOFOLLOW
))
819 nameiflags
|= FOLLOW
;
820 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
822 if ((error
= namei(&nd
)) != 0)
828 * Fetch the attribute request.
830 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
832 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
837 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
838 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
839 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
842 * It is legal to request volume or file attributes,
846 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
848 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
851 /* handle volume attribute request */
852 error
= getvolattrlist(vp
, uap
, &al
, &context
, proc_is64bit(p
));
857 * Set up the vnode_attr structure and authorise.
859 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64bit(p
), vnode_isdir(vp
))) != 0) {
860 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
863 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0) {
864 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
868 if (va
.va_active
!= 0) {
870 * If we're going to ask for va_name, allocate a buffer to point it at
872 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
873 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
874 if (va
.va_name
== NULL
) {
876 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
882 * Call the filesystem.
884 if ((error
= vnode_getattr(vp
, &va
, &context
)) != 0) {
885 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
889 /* did we ask for something the filesystem doesn't support? */
890 if (!VATTR_ALL_SUPPORTED(&va
)) {
893 * There are a couple of special cases. If we are after object IDs,
894 * we can make do with va_fileid.
896 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
897 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
899 * Many (most?) filesystems don't know their parent object id. We can get it the
902 if ((al
.commonattr
& ATTR_CMN_PAROBJID
) && !VATTR_IS_SUPPORTED(&va
, va_parentid
))
903 VATTR_CLEAR_ACTIVE(&va
, va_parentid
);
905 * And we can report datasize/alloc from total.
907 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
908 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
909 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
910 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
913 * If we don't have an encoding, go with UTF-8
915 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) && !VATTR_IS_SUPPORTED(&va
, va_encoding
))
916 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
919 * If we don't have a name, we'll get one from the vnode or mount point.
921 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
922 VATTR_CLEAR_ACTIVE(&va
, va_name
);
926 * We used to return va_nlink-2 for ATTR_DIR_ENTRYCOUNT. The va_nchildren
927 * field is preferred, but we'll fall back to va_nlink-2 for compatibility
928 * with file systems which haven't adopted va_nchildren. Note: the "- 2"
929 * reflects the "." and ".." entries which are reported via POSIX APIs, but
930 * not via Carbon (since they don't in fact exist in HFS).
932 if ((al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_nchildren
) &&
933 VATTR_IS_SUPPORTED(&va
, va_nlink
)) {
934 VATTR_RETURN(&va
, va_nchildren
, va
.va_nlink
- 2);
938 if (!VATTR_ALL_SUPPORTED(&va
)) {
940 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not get all requested file attributes");
941 VFS_DEBUG(ctx
, vp
, "ATTRLIST - have %016llx wanted %016llx missing %016llx",
942 va
.va_supported
, va
.va_active
, va
.va_active
& ~va
.va_supported
);
949 * Compute variable-space requirements.
951 varsize
= 0; /* length count */
952 if (al
.commonattr
& ATTR_CMN_NAME
) {
953 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
954 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
958 if (vnode_isvroot(vp
)) {
959 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
960 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
961 /* special case for boot volume. Use root name when it's
962 * available (which is the volume name) or just the mount on
963 * name of "/". we must do this for binary compatibility with
964 * pre Tiger code. returning nothing for the boot volume name
965 * breaks installers - 3961058
967 cnp
= vname
= vnode_getname(vp
);
969 /* just use "/" as name */
970 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
975 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
978 cnp
= vname
= vnode_getname(vp
);
985 varsize
+= roundup(cnl
+ 1, 4);
989 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
991 * XXX This needs to change at some point; since the blob is opaque in
992 * user-space this is OK.
994 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
995 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
997 varsize
+= roundup(KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
), 4);
1000 * Allocate a target buffer for attribute results.
1002 * Note that we won't ever copy out more than the caller requested, even though
1003 * we might have to allocate more than they offer do that the diagnostic checks
1004 * don't result in a panic if the caller's buffer is too small..
1006 ab
.allocated
= fixedsize
+ varsize
;
1007 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1009 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1012 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1013 if (ab
.base
== NULL
) {
1015 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1020 * Pack results into the destination buffer.
1022 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1023 ab
.varcursor
= ab
.base
+ fixedsize
;
1024 ab
.needed
= ab
.allocated
;
1026 /* common attributes **************************************************/
1027 if (al
.commonattr
& ATTR_CMN_NAME
)
1028 attrlist_pack_string(&ab
, cnp
, cnl
);
1029 if (al
.commonattr
& ATTR_CMN_DEVID
)
1030 ATTR_PACK_CAST(&ab
, dev_t
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1031 if (al
.commonattr
& ATTR_CMN_FSID
)
1032 ATTR_PACK(&ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1033 if (al
.commonattr
& ATTR_CMN_OBJTYPE
)
1034 ATTR_PACK_CAST(&ab
, fsobj_type_t
, vp
->v_type
);
1035 if (al
.commonattr
& ATTR_CMN_OBJTAG
)
1036 ATTR_PACK_CAST(&ab
, fsobj_tag_t
, vp
->v_tag
);
1037 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1040 * Carbon can't deal with us reporting the target ID
1041 * for links. So we ask the filesystem to give us the
1042 * source ID as well, and if it gives us one, we use
1045 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1046 f
.fid_objno
= va
.va_linkid
;
1048 f
.fid_objno
= va
.va_fileid
;
1050 f
.fid_generation
= 0;
1053 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1056 * Carbon can't deal with us reporting the target ID
1057 * for links. So we ask the filesystem to give us the
1058 * source ID as well, and if it gives us one, we use
1061 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1062 f
.fid_objno
= va
.va_linkid
;
1064 f
.fid_objno
= va
.va_fileid
;
1066 f
.fid_generation
= 0;
1069 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1072 * If the filesystem doesn't know the parent ID, we can
1073 * try to get it via v->v_parent. Don't need to worry
1074 * about links here, as we dont allow hardlinks to
1077 if (VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1078 f
.fid_objno
= va
.va_parentid
;
1080 struct vnode_attr lva
;
1083 pvp
= vnode_getparent(vp
);
1085 if (pvp
== NULLVP
) {
1090 VATTR_WANTED(&lva
, va_fileid
);
1091 error
= vnode_getattr(pvp
, &lva
, &context
);
1096 f
.fid_objno
= lva
.va_fileid
;
1098 f
.fid_generation
= 0;
1101 if (al
.commonattr
& ATTR_CMN_SCRIPT
)
1102 ATTR_PACK_CAST(&ab
, text_encoding_t
, va
.va_encoding
);
1103 if (al
.commonattr
& ATTR_CMN_CRTIME
)
1104 ATTR_PACK_TIME(&ab
, va
.va_create_time
, proc_is64bit(p
));
1105 if (al
.commonattr
& ATTR_CMN_MODTIME
)
1106 ATTR_PACK_TIME(&ab
, va
.va_modify_time
, proc_is64bit(p
));
1107 if (al
.commonattr
& ATTR_CMN_CHGTIME
)
1108 ATTR_PACK_TIME(&ab
, va
.va_change_time
, proc_is64bit(p
));
1109 if (al
.commonattr
& ATTR_CMN_ACCTIME
)
1110 ATTR_PACK_TIME(&ab
, va
.va_access_time
, proc_is64bit(p
));
1111 if (al
.commonattr
& ATTR_CMN_BKUPTIME
)
1112 ATTR_PACK_TIME(&ab
, va
.va_backup_time
, proc_is64bit(p
));
1113 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1116 char uio_buf
[UIO_SIZEOF(1)];
1118 fisize
= imin(32, ab
.allocated
- (ab
.fixedcursor
- ab
.base
));
1120 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
1124 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1125 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, &fisize
, XATTR_NOSECURITY
, &context
);
1129 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)) {
1130 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1131 bzero(ab
.fixedcursor
, 32);
1134 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1139 VFS_DEBUG(ctx
, vp
, "ATTRLIST - no room in caller buffer for FINDERINFO");
1141 ab
.fixedcursor
+= 32;
1143 if (al
.commonattr
& ATTR_CMN_OWNERID
)
1144 ATTR_PACK(&ab
, va
.va_uid
);
1145 if (al
.commonattr
& ATTR_CMN_GRPID
)
1146 ATTR_PACK(&ab
, va
.va_gid
);
1147 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
)
1148 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
1149 if (al
.commonattr
& ATTR_CMN_FLAGS
)
1150 ATTR_PACK(&ab
, va
.va_flags
);
1151 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1153 if (vnode_isdir(vp
)) {
1154 if (vnode_authorize(vp
, NULL
,
1155 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, &context
) == 0)
1157 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, &context
) == 0)
1159 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, &context
) == 0)
1162 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, &context
) == 0)
1164 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, &context
) == 0)
1166 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, &context
) == 0)
1169 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1170 ATTR_PACK(&ab
, perms
);
1172 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1173 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1174 struct kauth_filesec fsec
;
1176 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1178 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1179 fsec
.fsec_owner
= kauth_null_guid
;
1180 fsec
.fsec_group
= kauth_null_guid
;
1181 attrlist_pack_variable2(&ab
, &fsec
, ((char *)&fsec
.fsec_acl
- (char *)&fsec
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1183 attrlist_pack_variable(&ab
, NULL
, 0);
1186 if (al
.commonattr
& ATTR_CMN_UUID
) {
1187 if (!VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1188 ATTR_PACK(&ab
, kauth_null_guid
);
1190 ATTR_PACK(&ab
, va
.va_uuuid
);
1193 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1194 if (!VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1195 ATTR_PACK(&ab
, kauth_null_guid
);
1197 ATTR_PACK(&ab
, va
.va_guuid
);
1201 /* directory attributes **************************************************/
1202 if (vnode_isdir(vp
)) {
1203 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) /* full count of entries */
1204 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nlink
);
1205 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
)
1206 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nchildren
);
1207 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
)
1208 ATTR_PACK_CAST(&ab
, uint32_t, (vp
->v_flag
& VROOT
) ? DIR_MNTSTATUS_MNTPOINT
: 0);
1211 /* file attributes **************************************************/
1212 if (!vnode_isdir(vp
)) {
1213 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
)
1214 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nlink
);
1215 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
)
1216 ATTR_PACK(&ab
, va
.va_total_size
);
1217 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
)
1218 ATTR_PACK(&ab
, va
.va_total_alloc
);
1219 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
)
1220 ATTR_PACK(&ab
, va
.va_iosize
);
1221 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
)
1222 ATTR_PACK_CAST(&ab
, uint32_t, 0); /* XXX value is deprecated */
1223 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1224 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1225 ATTR_PACK(&ab
, vp
->v_specinfo
->si_rdev
);
1227 ATTR_PACK_CAST(&ab
, uint32_t, 0);
1230 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
1231 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1232 ATTR_PACK(&ab
, va
.va_data_size
);
1234 ATTR_PACK(&ab
, va
.va_total_size
);
1237 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
1238 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1239 ATTR_PACK(&ab
, va
.va_data_alloc
);
1241 ATTR_PACK(&ab
, va
.va_total_alloc
);
1244 /* fetch resource fork size/allocation via xattr interface */
1245 if (al
.fileattr
& (ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1247 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, &context
)) != 0) {
1248 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)) {
1255 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
)
1256 ATTR_PACK_CAST(&ab
, off_t
, rsize
);
1257 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
1258 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1261 ATTR_PACK_CAST(&ab
, off_t
, (roundup(rsize
, blksize
)));
1267 if ((ab
.fixedcursor
- ab
.base
) != fixedsize
)
1268 panic("packed field size mismatch; allocated %d but packed %d for common %08x vol %08x",
1269 fixedsize
, ab
.fixedcursor
- ab
.base
, al
.commonattr
, al
.volattr
);
1270 if (ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1271 panic("packed variable field size mismatch; used %d but expected %d", ab
.varcursor
- ab
.base
, ab
.needed
);
1274 * In the compatible case, we report the smaller of the required and returned sizes.
1275 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1276 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1277 * they gave us, so they can always check for truncation themselves.
1279 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1281 /* Only actually copyout as much out as the user buffer can hold */
1282 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
1286 kfree(va
.va_name
, MAXPATHLEN
);
1288 vnode_putname(vname
);
1291 if (ab
.base
!= NULL
)
1292 FREE(ab
.base
, M_TEMP
);
1293 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
1294 kauth_acl_free(va
.va_acl
);
1296 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1301 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
1303 /* make sure we have enough source data */
1304 if ((*cursor
) + size
> end
)
1307 bcopy(*cursor
, buf
, size
);
1312 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
1313 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
1314 #define ATTR_UNPACK_TIME(v, is64) \
1317 struct user_timespec us; \
1319 v.tv_sec = us.tv_sec; \
1320 v.tv_nsec = us.tv_nsec; \
1331 setattrlist(struct proc
*p
, register struct setattrlist_args
*uap
, __unused register_t
*retval
)
1334 struct vfs_context context
, *ctx
;
1335 struct vnode_attr va
;
1336 struct attrreference ar
;
1337 struct nameidata nd
;
1340 kauth_action_t action
;
1341 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
1342 int proc_is64
, error
;
1344 kauth_filesec_t rfsec
;
1346 context
.vc_proc
= p
;
1347 context
.vc_ucred
= kauth_cred_get();
1354 proc_is64
= proc_is64bit(p
);
1362 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
1363 nameiflags
|= FOLLOW
;
1364 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, &context
);
1365 if ((error
= namei(&nd
)) != 0)
1371 * Fetch the attribute set and validate.
1373 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
1375 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1380 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1381 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1382 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1385 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
1386 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
1390 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
1394 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
1395 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
1396 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
1397 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
1399 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
1405 * Make the naive assumption that the caller has supplied a reasonable buffer
1406 * size. We could be more careful by pulling in the fixed-size region, checking
1407 * the attrref structures, then pulling in the variable section.
1408 * We need to reconsider this for handling large ACLs, as they should probably be
1409 * brought directly into a buffer. Multiple copyins will make this slower though.
1411 * We could also map the user buffer if it is larger than some sensible mimimum.
1413 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
1414 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
1418 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
1419 if (user_buf
== NULL
) {
1420 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
1424 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
1425 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
1428 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
1431 * Unpack the argument buffer.
1434 bufend
= cursor
+ uap
->bufferSize
;
1437 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1438 ATTR_UNPACK(va
.va_encoding
);
1439 VATTR_SET_ACTIVE(&va
, va_encoding
);
1441 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1442 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
1443 VATTR_SET_ACTIVE(&va
, va_create_time
);
1445 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1446 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
1447 VATTR_SET_ACTIVE(&va
, va_modify_time
);
1449 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1450 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
1451 VATTR_SET_ACTIVE(&va
, va_change_time
);
1453 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1454 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
1455 VATTR_SET_ACTIVE(&va
, va_access_time
);
1457 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1458 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
1459 VATTR_SET_ACTIVE(&va
, va_backup_time
);
1461 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1462 if ((cursor
+ 32) > bufend
) {
1464 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
1470 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1471 ATTR_UNPACK(va
.va_uid
);
1472 VATTR_SET_ACTIVE(&va
, va_uid
);
1474 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1475 ATTR_UNPACK(va
.va_gid
);
1476 VATTR_SET_ACTIVE(&va
, va_gid
);
1478 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1479 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
1480 VATTR_SET_ACTIVE(&va
, va_mode
);
1482 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1483 ATTR_UNPACK(va
.va_flags
);
1484 VATTR_SET_ACTIVE(&va
, va_flags
);
1486 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1489 * We are (for now) passed a kauth_filesec_t, but all we want from
1494 cp
+= ar
.attr_dataoffset
;
1495 rfsec
= (kauth_filesec_t
)cp
;
1496 if (((char *)(rfsec
+ 1) > bufend
) || /* no space for acl */
1497 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
1498 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
1499 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
1501 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
1504 nace
= rfsec
->fsec_entrycount
;
1505 if (nace
== KAUTH_FILESEC_NOACL
)
1507 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
1509 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
1512 nace
= rfsec
->fsec_acl
.acl_entrycount
;
1513 if (nace
== KAUTH_FILESEC_NOACL
) {
1515 VATTR_SET(&va
, va_acl
, NULL
);
1518 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
1520 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
1523 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
1526 if (al
.commonattr
& ATTR_CMN_UUID
) {
1527 ATTR_UNPACK(va
.va_uuuid
);
1528 VATTR_SET_ACTIVE(&va
, va_uuuid
);
1530 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1531 ATTR_UNPACK(va
.va_guuid
);
1532 VATTR_SET_ACTIVE(&va
, va_guuid
);
1536 if (al
.volattr
& ATTR_VOL_INFO
) {
1537 if (al
.volattr
& ATTR_VOL_NAME
) {
1540 volname
+= ar
.attr_dataoffset
;
1541 if ((volname
+ ar
.attr_length
) > bufend
) {
1543 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
1546 /* guarantee NUL termination */
1547 volname
[ar
.attr_length
- 1] = 0;
1552 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1553 /* XXX does it actually make any sense to change this? */
1555 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
1560 * Validate and authorize.
1563 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)) {
1564 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
1568 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
1569 * and will be auth'ed by the FS.
1571 if (fndrinfo
!= NULL
) {
1572 if (al
.volattr
& ATTR_VOL_INFO
) {
1573 if (vp
->v_tag
!= VT_HFS
) {
1578 action
|= KAUTH_VNODE_WRITE_ATTRIBUTES
;
1582 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
1583 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
1588 * When we're setting both the access mask and the finder info, then
1589 * check if were about to remove write access for the owner. Since
1590 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
1591 * to consider their ordering.
1593 * If were about to remove write access for the owner we'll set the
1594 * Finder Info here before vnode_setattr. Otherwise we'll set it
1595 * after vnode_setattr since it may be adding owner write access.
1597 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
1598 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
1599 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, &context
)) != 0) {
1602 fndrinfo
= NULL
; /* it was set here so skip setting below */
1606 * Write the attributes if we have any.
1608 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, &context
)) != 0)) {
1609 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1614 * Write the Finder Info if we have any.
1616 if (fndrinfo
!= NULL
) {
1617 if (al
.volattr
& ATTR_VOL_INFO
) {
1618 if (vp
->v_tag
== VT_HFS
) {
1619 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, &context
);
1623 /* XXX should never get here */
1625 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, &context
)) != 0) {
1631 * Set the volume name, if we have one
1633 if (volname
!= NULL
)
1639 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
1640 VFSATTR_WANTED(&vs
, f_vol_name
);
1642 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
1643 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
1647 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
1649 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
1654 /* all done and successful */
1659 if (user_buf
!= NULL
)
1660 FREE(user_buf
, M_TEMP
);
1661 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);