2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/namei.h>
26 #include <sys/kernel.h>
28 #include <sys/vnode_internal.h>
29 #include <sys/mount_internal.h>
30 #include <sys/proc_internal.h>
31 #include <sys/kauth.h>
32 #include <sys/uio_internal.h>
33 #include <sys/malloc.h>
35 #include <sys/sysproto.h>
36 #include <sys/xattr.h>
37 #include <sys/fsevents.h>
38 #include <kern/kalloc.h>
39 #include <miscfs/specfs/specdev.h>
42 #define ATTR_TIME_SIZE -1
45 * Structure describing the state of an in-progress attrlist operation.
47 struct _attrlist_buf
{
57 * Pack (count) bytes from (source) into (buf).
60 attrlist_pack_fixed(struct _attrlist_buf
*ab
, void *source
, ssize_t count
)
64 /* how much room left in the buffer? */
65 fit
= imin(count
, ab
->allocated
- (ab
->fixedcursor
- ab
->base
));
67 bcopy(source
, ab
->fixedcursor
, fit
);
69 /* always move in increments of 4 */
70 ab
->fixedcursor
+= roundup(count
, 4);
73 attrlist_pack_variable2(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
, const void *ext
, ssize_t extcount
)
75 struct attrreference ar
;
78 /* pack the reference to the variable object */
79 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
80 ar
.attr_length
= count
+ extcount
;
81 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
83 /* calculate space and pack the variable object */
84 fit
= imin(count
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
87 bcopy(source
, ab
->varcursor
, fit
);
90 fit
= imin(extcount
, ab
->allocated
- (ab
->varcursor
- ab
->base
));
93 bcopy(ext
, ab
->varcursor
, fit
);
96 /* always move in increments of 4 */
97 ab
->varcursor
= (char *)roundup((uintptr_t)ab
->varcursor
, 4);
100 attrlist_pack_variable(struct _attrlist_buf
*ab
, const void *source
, ssize_t count
)
102 attrlist_pack_variable2(ab
, source
, count
, NULL
, 0);
105 attrlist_pack_string(struct _attrlist_buf
*ab
, const char *source
, ssize_t count
)
107 struct attrreference ar
;
112 * Supplied count is character count of string text, excluding trailing nul
113 * which we always supply here.
115 if (source
== NULL
) {
117 } else if (count
== 0) {
118 count
= strlen(source
);
122 * Make the reference and pack it.
123 * Note that this is entirely independent of how much we get into
126 ar
.attr_dataoffset
= ab
->varcursor
- ab
->fixedcursor
;
127 ar
.attr_length
= count
+ 1;
128 attrlist_pack_fixed(ab
, &ar
, sizeof(ar
));
130 /* calculate how much of the string text we can copy, and do that */
131 space
= ab
->allocated
- (ab
->varcursor
- ab
->base
);
132 fit
= imin(count
, space
);
134 bcopy(source
, ab
->varcursor
, fit
);
135 /* is there room for our trailing nul? */
137 ab
->varcursor
[fit
] = '\0';
139 /* always move in increments of 4 */
140 ab
->varcursor
+= roundup(count
+ 1, 4);
143 #define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
144 #define ATTR_PACK_CAST(b, t, v) \
150 #define ATTR_PACK_TIME(b, v, is64) \
153 struct user_timespec us = {v.tv_sec, v.tv_nsec}; \
162 * Table-driven setup for all valid common/volume attributes.
164 struct getvolattrlist_attrtab
{
167 #define VFSATTR_BIT(b) (VFSATTR_ ## b)
170 static struct getvolattrlist_attrtab getvolattrlist_common_tab
[] = {
171 {ATTR_CMN_NAME
, 0, sizeof(struct attrreference
)},
172 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
)},
173 {ATTR_CMN_FSID
, 0, sizeof(fsid_t
)},
174 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
)},
175 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
)},
176 {ATTR_CMN_OBJID
, 0, sizeof(fsobj_id_t
)},
177 {ATTR_CMN_OBJPERMANENTID
, 0, sizeof(fsobj_id_t
)},
178 {ATTR_CMN_PAROBJID
, 0, sizeof(fsobj_id_t
)},
179 {ATTR_CMN_SCRIPT
, 0, sizeof(text_encoding_t
)},
180 {ATTR_CMN_CRTIME
, VFSATTR_BIT(f_create_time
), ATTR_TIME_SIZE
},
181 {ATTR_CMN_MODTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
182 {ATTR_CMN_CHGTIME
, VFSATTR_BIT(f_modify_time
), ATTR_TIME_SIZE
},
183 {ATTR_CMN_ACCTIME
, VFSATTR_BIT(f_access_time
), ATTR_TIME_SIZE
},
184 {ATTR_CMN_BKUPTIME
, VFSATTR_BIT(f_backup_time
), ATTR_TIME_SIZE
},
185 {ATTR_CMN_FNDRINFO
, 0, 32},
186 {ATTR_CMN_OWNERID
, 0, sizeof(uid_t
)},
187 {ATTR_CMN_GRPID
, 0, sizeof(gid_t
)},
188 {ATTR_CMN_ACCESSMASK
, 0, sizeof(uint32_t)},
189 {ATTR_CMN_FLAGS
, 0, sizeof(uint32_t)},
190 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t)},
194 static struct getvolattrlist_attrtab getvolattrlist_vol_tab
[] = {
195 {ATTR_VOL_FSTYPE
, 0, sizeof(uint32_t)},
196 {ATTR_VOL_SIGNATURE
, VFSATTR_BIT(f_signature
), sizeof(uint32_t)},
197 {ATTR_VOL_SIZE
, VFSATTR_BIT(f_blocks
), sizeof(off_t
)},
198 {ATTR_VOL_SPACEFREE
, VFSATTR_BIT(f_bfree
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
199 {ATTR_VOL_SPACEAVAIL
, VFSATTR_BIT(f_bavail
) | VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
200 {ATTR_VOL_MINALLOCATION
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
201 {ATTR_VOL_ALLOCATIONCLUMP
, VFSATTR_BIT(f_bsize
), sizeof(off_t
)},
202 {ATTR_VOL_IOBLOCKSIZE
, VFSATTR_BIT(f_iosize
), sizeof(uint32_t)},
203 {ATTR_VOL_OBJCOUNT
, VFSATTR_BIT(f_objcount
), sizeof(uint32_t)},
204 {ATTR_VOL_FILECOUNT
, VFSATTR_BIT(f_filecount
), sizeof(uint32_t)},
205 {ATTR_VOL_DIRCOUNT
, VFSATTR_BIT(f_dircount
), sizeof(uint32_t)},
206 {ATTR_VOL_MAXOBJCOUNT
, VFSATTR_BIT(f_maxobjcount
), sizeof(uint32_t)},
207 {ATTR_VOL_MOUNTPOINT
, 0, sizeof(struct attrreference
)},
208 {ATTR_VOL_NAME
, VFSATTR_BIT(f_vol_name
), sizeof(struct attrreference
)},
209 {ATTR_VOL_MOUNTFLAGS
, 0, sizeof(uint32_t)},
210 {ATTR_VOL_MOUNTEDDEVICE
, 0, sizeof(struct attrreference
)},
211 {ATTR_VOL_ENCODINGSUSED
, 0, sizeof(uint64_t)},
212 {ATTR_VOL_CAPABILITIES
, VFSATTR_BIT(f_capabilities
), sizeof(vol_capabilities_attr_t
)},
213 {ATTR_VOL_ATTRIBUTES
, VFSATTR_BIT(f_attributes
), sizeof(vol_attributes_attr_t
)},
214 {ATTR_VOL_INFO
, 0, 0},
219 getvolattrlist_parsetab(struct getvolattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vfs_attr
*vsp
,
220 ssize_t
*sizep
, int is_64bit
)
222 attrgroup_t recognised
;
226 /* is this attribute set? */
227 if (tab
->attr
& attrs
) {
228 recognised
|= tab
->attr
;
229 vsp
->f_active
|= tab
->bits
;
230 if (tab
->size
== ATTR_TIME_SIZE
) {
232 *sizep
+= sizeof(struct user_timespec
);
234 *sizep
+= sizeof(struct timespec
);
240 } while ((++tab
)->attr
!= 0);
242 /* check to make sure that we recognised all of the passed-in attributes */
243 if (attrs
& ~recognised
)
249 * Given the attributes listed in alp, configure vap to request
250 * the data from a filesystem.
253 getvolattrlist_setupvfsattr(struct attrlist
*alp
, struct vfs_attr
*vsp
, ssize_t
*sizep
, int is_64bit
)
258 * Parse the above tables.
260 *sizep
= sizeof(uint32_t); /* length count */
261 if (alp
->commonattr
&&
262 (error
= getvolattrlist_parsetab(getvolattrlist_common_tab
, alp
->commonattr
, vsp
, sizep
, is_64bit
)) != 0)
265 (error
= getvolattrlist_parsetab(getvolattrlist_vol_tab
, alp
->volattr
, vsp
, sizep
, is_64bit
)) != 0)
272 * Table-driven setup for all valid common/dir/file/fork attributes against files.
274 struct getattrlist_attrtab
{
277 #define VATTR_BIT(b) (VNODE_ATTR_ ## b)
279 kauth_action_t action
;
281 static struct getattrlist_attrtab getattrlist_common_tab
[] = {
282 {ATTR_CMN_NAME
, VATTR_BIT(va_name
), sizeof(struct attrreference
), KAUTH_VNODE_READ_ATTRIBUTES
},
283 {ATTR_CMN_DEVID
, 0, sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
284 {ATTR_CMN_FSID
, VATTR_BIT(va_fsid
), sizeof(fsid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
285 {ATTR_CMN_OBJTYPE
, 0, sizeof(fsobj_type_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
286 {ATTR_CMN_OBJTAG
, 0, sizeof(fsobj_tag_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
287 {ATTR_CMN_OBJID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
288 {ATTR_CMN_OBJPERMANENTID
, VATTR_BIT(va_fileid
) | VATTR_BIT(va_linkid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
289 {ATTR_CMN_PAROBJID
, VATTR_BIT(va_parentid
), sizeof(fsobj_id_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
290 {ATTR_CMN_SCRIPT
, VATTR_BIT(va_encoding
), sizeof(text_encoding_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
291 {ATTR_CMN_CRTIME
, VATTR_BIT(va_create_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
292 {ATTR_CMN_MODTIME
, VATTR_BIT(va_modify_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
293 {ATTR_CMN_CHGTIME
, VATTR_BIT(va_change_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
294 {ATTR_CMN_ACCTIME
, VATTR_BIT(va_access_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
295 {ATTR_CMN_BKUPTIME
, VATTR_BIT(va_backup_time
), ATTR_TIME_SIZE
, KAUTH_VNODE_READ_ATTRIBUTES
},
296 {ATTR_CMN_FNDRINFO
, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES
},
297 {ATTR_CMN_OWNERID
, VATTR_BIT(va_uid
), sizeof(uid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
298 {ATTR_CMN_GRPID
, VATTR_BIT(va_gid
), sizeof(gid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
299 {ATTR_CMN_ACCESSMASK
, VATTR_BIT(va_mode
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
300 {ATTR_CMN_FLAGS
, VATTR_BIT(va_flags
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
301 {ATTR_CMN_USERACCESS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
302 {ATTR_CMN_EXTENDED_SECURITY
, VATTR_BIT(va_acl
), sizeof(struct attrreference
), KAUTH_VNODE_READ_SECURITY
},
303 {ATTR_CMN_UUID
, VATTR_BIT(va_uuuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
304 {ATTR_CMN_GRPUUID
, VATTR_BIT(va_guuid
), sizeof(guid_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
307 static struct getattrlist_attrtab getattrlist_dir_tab
[] = {
308 {ATTR_DIR_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
309 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nchildren
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
310 /* ATTR_DIR_ENTRYCOUNT falls back to va_nlink-2 if va_nchildren isn't supported, so request va_nlink just in case */
311 {ATTR_DIR_ENTRYCOUNT
, VATTR_BIT(va_nlink
), 0, KAUTH_VNODE_READ_ATTRIBUTES
},
312 {ATTR_DIR_MOUNTSTATUS
, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
315 static struct getattrlist_attrtab getattrlist_file_tab
[] = {
316 {ATTR_FILE_LINKCOUNT
, VATTR_BIT(va_nlink
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
317 {ATTR_FILE_TOTALSIZE
, VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
318 {ATTR_FILE_ALLOCSIZE
, VATTR_BIT(va_total_alloc
) | VATTR_BIT(va_total_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
319 {ATTR_FILE_IOBLOCKSIZE
, VATTR_BIT(va_iosize
), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES
},
320 {ATTR_FILE_DEVTYPE
, VATTR_BIT(va_rdev
), sizeof(dev_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
321 {ATTR_FILE_DATALENGTH
, VATTR_BIT(va_total_size
) | VATTR_BIT(va_data_size
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
322 {ATTR_FILE_DATAALLOCSIZE
, VATTR_BIT(va_total_alloc
)| VATTR_BIT(va_data_alloc
), sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
323 {ATTR_FILE_RSRCLENGTH
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
324 {ATTR_FILE_RSRCALLOCSIZE
, 0, sizeof(off_t
), KAUTH_VNODE_READ_ATTRIBUTES
},
329 getattrlist_parsetab(struct getattrlist_attrtab
*tab
, attrgroup_t attrs
, struct vnode_attr
*vap
,
330 ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
)
332 attrgroup_t recognised
;
336 /* is this attribute set? */
337 if (tab
->attr
& attrs
) {
338 recognised
|= tab
->attr
;
339 vap
->va_active
|= tab
->bits
;
340 if (tab
->size
== ATTR_TIME_SIZE
) {
342 *sizep
+= sizeof(struct user_timespec
);
344 *sizep
+= sizeof(struct timespec
);
349 *actionp
|= tab
->action
;
351 } while ((++tab
)->attr
!= 0);
353 /* check to make sure that we recognised all of the passed-in attributes */
354 if (attrs
& ~recognised
)
360 * Given the attributes listed in alp, configure vap to request
361 * the data from a filesystem.
364 getattrlist_setupvattr(struct attrlist
*alp
, struct vnode_attr
*vap
, ssize_t
*sizep
, kauth_action_t
*actionp
, int is_64bit
, int isdir
)
369 * Parse the above tables.
371 *sizep
= sizeof(uint32_t); /* length count */
373 if (alp
->commonattr
&&
374 (error
= getattrlist_parsetab(getattrlist_common_tab
, alp
->commonattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
376 if (isdir
&& alp
->dirattr
&&
377 (error
= getattrlist_parsetab(getattrlist_dir_tab
, alp
->dirattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
379 if (!isdir
&& alp
->fileattr
&&
380 (error
= getattrlist_parsetab(getattrlist_file_tab
, alp
->fileattr
, vap
, sizep
, actionp
, is_64bit
)) != 0)
387 setattrlist_setfinderinfo(vnode_t vp
, char *fndrinfo
, struct vfs_context
*ctx
)
390 char uio_buf
[UIO_SIZEOF(1)];
393 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_WRITE
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
396 uio_addiov(auio
, CAST_USER_ADDR_T(fndrinfo
), 32);
397 error
= vn_setxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, XATTR_NOSECURITY
, ctx
);
401 if (error
== 0 && need_fsevent(FSE_FINDER_INFO_CHANGED
, vp
)) {
402 add_fsevent(FSE_FINDER_INFO_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
410 * Find something resembling a terminal component name in the mountedonname for vp
414 getattrlist_findnamecomp(const char *mn
, const char **np
, ssize_t
*nl
)
420 * We're looking for the last sequence of non / characters, but
421 * not including any trailing / characters.
426 for (cp
= mn
; *cp
!= 0; cp
++) {
428 /* start of run of chars */
434 /* end of run of chars */
441 /* need to close run? */
448 getvolattrlist(vnode_t vp
, struct getattrlist_args
*uap
, struct attrlist
*alp
, vfs_context_t ctx
, int is_64bit
)
451 struct vnode_attr va
;
452 struct _attrlist_buf ab
;
454 ssize_t fixedsize
, varsize
;
462 vs
.f_vol_name
= NULL
;
467 * For now, the vnode must be the root of its filesystem.
468 * To relax this, we need to be able to find the root vnode of a filesystem
469 * from any vnode in the filesystem.
471 if (!vnode_isvroot(vp
)) {
473 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
478 * Set up the vfs_attr structure and call the filesystem.
480 if ((error
= getvolattrlist_setupvfsattr(alp
, &vs
, &fixedsize
, is_64bit
)) != 0) {
481 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
484 if (vs
.f_active
!= 0) {
485 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */
486 if (VFSATTR_IS_ACTIVE(&vs
, f_vol_name
)) {
487 vs
.f_vol_name
= (char *) kalloc(MAXPATHLEN
);
488 if (vs
.f_vol_name
== NULL
) {
490 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
495 VFS_DEBUG(ctx
, vp
, "ATTRLIST - calling to get %016llx with supported %016llx", vs
.f_active
, vs
.f_supported
);
496 if ((error
= vfs_getattr(mnt
, &vs
, ctx
)) != 0) {
497 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
502 * Did we ask for something the filesystem doesn't support?
504 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
505 /* default value for volume subtype */
506 if (VFSATTR_IS_ACTIVE(&vs
, f_fssubtype
)
507 && !VFSATTR_IS_SUPPORTED(&vs
, f_fssubtype
))
508 VFSATTR_RETURN(&vs
, f_fssubtype
, 0);
511 * If the file system didn't supply f_signature, then
512 * default it to 'BD', which is the generic signature
513 * that most Carbon file systems should return.
515 if (VFSATTR_IS_ACTIVE(&vs
, f_signature
)
516 && !VFSATTR_IS_SUPPORTED(&vs
, f_signature
))
517 VFSATTR_RETURN(&vs
, f_signature
, 0x4244);
519 /* default for block size */
520 if (VFSATTR_IS_ACTIVE(&vs
, f_bsize
)
521 && !VFSATTR_IS_SUPPORTED(&vs
, f_bsize
))
522 VFSATTR_RETURN(&vs
, f_bsize
, mnt
->mnt_devblocksize
);
524 /* check to see if our fixups were enough */
525 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
527 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not get all requested volume attributes");
528 VFS_DEBUG(ctx
, vp
, "ATTRLIST - wanted %016llx got %016llx missing %016llx",
529 vs
.f_active
, vs
.f_supported
, vs
.f_active
& ~vs
.f_supported
);
536 * Some fields require data from the root vp
538 if (alp
->commonattr
& (ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
| ATTR_CMN_FLAGS
| ATTR_CMN_SCRIPT
)) {
539 VATTR_WANTED(&va
, va_uid
);
540 VATTR_WANTED(&va
, va_gid
);
541 VATTR_WANTED(&va
, va_mode
);
542 VATTR_WANTED(&va
, va_flags
);
543 VATTR_WANTED(&va
, va_encoding
);
545 if ((error
= vnode_getattr(vp
, &va
, ctx
)) != 0) {
546 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp
);
550 if (VATTR_IS_ACTIVE(&va
, va_encoding
) && !VATTR_IS_SUPPORTED(&va
, va_encoding
))
551 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
555 * Compute variable-size buffer requirements.
558 if (alp
->commonattr
& ATTR_CMN_NAME
) {
559 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
560 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
561 /* special case for boot volume. Use root name when it's
562 * available (which is the volume name) or just the mount on
563 * name of "/". we must do this for binary compatibility with
564 * pre Tiger code. returning nothing for the boot volume name
565 * breaks installers - 3961058
567 cnp
= vnode_getname(vp
);
569 /* just use "/" as name */
570 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
575 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
577 if (alp
->commonattr
& ATTR_CMN_NAME
)
578 varsize
+= roundup(cnl
+ 1, 4);
580 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
581 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntonname
) + 1, 4);
582 if (alp
->volattr
& ATTR_VOL_NAME
) {
583 vs
.f_vol_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
584 varsize
+= roundup(strlen(vs
.f_vol_name
) + 1, 4);
586 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
587 varsize
+= roundup(strlen(mnt
->mnt_vfsstat
.f_mntfromname
) + 1, 4);
590 * Allocate a target buffer for attribute results.
591 * Note that since we won't ever copy out more than the caller requested,
592 * we never need to allocate more than they offer.
594 ab
.allocated
= imin(uap
->bufferSize
, fixedsize
+ varsize
);
595 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
597 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
600 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
601 if (ab
.base
== NULL
) {
603 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
608 * Pack results into the destination buffer.
610 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
611 ab
.varcursor
= ab
.base
+ fixedsize
;
612 ab
.needed
= fixedsize
+ varsize
;
614 /* common attributes **************************************************/
615 if (alp
->commonattr
& ATTR_CMN_NAME
)
616 attrlist_pack_string(&ab
, cnp
, cnl
);
617 if (alp
->commonattr
& ATTR_CMN_DEVID
)
618 ATTR_PACK_CAST(&ab
, dev_t
, mnt
->mnt_vfsstat
.f_fsid
.val
[0]);
619 if (alp
->commonattr
& ATTR_CMN_FSID
)
620 ATTR_PACK(&ab
, mnt
->mnt_vfsstat
.f_fsid
);
621 if (alp
->commonattr
& ATTR_CMN_OBJTYPE
)
622 ATTR_PACK_CAST(&ab
, fsobj_type_t
, 0);
623 if (alp
->commonattr
& ATTR_CMN_OBJTAG
)
624 ATTR_PACK_CAST(&ab
, fsobj_tag_t
, vp
->v_tag
);
625 if (alp
->commonattr
& ATTR_CMN_OBJID
) {
626 fsobj_id_t f
= {0, 0};
629 if (alp
->commonattr
& ATTR_CMN_OBJPERMANENTID
) {
630 fsobj_id_t f
= {0, 0};
633 if (alp
->commonattr
& ATTR_CMN_PAROBJID
) {
634 fsobj_id_t f
= {0, 0};
637 /* note that this returns the encoding for the volume name, not the node name */
638 if (alp
->commonattr
& ATTR_CMN_SCRIPT
)
639 ATTR_PACK_CAST(&ab
, text_encoding_t
, va
.va_encoding
);
640 if (alp
->commonattr
& ATTR_CMN_CRTIME
)
641 ATTR_PACK_TIME(&ab
, vs
.f_create_time
, is_64bit
);
642 if (alp
->commonattr
& ATTR_CMN_MODTIME
)
643 ATTR_PACK_TIME(&ab
, vs
.f_modify_time
, is_64bit
);
644 if (alp
->commonattr
& ATTR_CMN_CHGTIME
)
645 ATTR_PACK_TIME(&ab
, vs
.f_modify_time
, is_64bit
);
646 if (alp
->commonattr
& ATTR_CMN_ACCTIME
)
647 ATTR_PACK_TIME(&ab
, vs
.f_access_time
, is_64bit
);
648 if (alp
->commonattr
& ATTR_CMN_BKUPTIME
)
649 ATTR_PACK_TIME(&ab
, vs
.f_backup_time
, is_64bit
);
650 if (alp
->commonattr
& ATTR_CMN_FNDRINFO
) {
653 * This attribute isn't really Finder Info, at least for HFS.
655 if (vp
->v_tag
== VT_HFS
) {
656 if ((error
= VNOP_IOCTL(vp
, HFS_GET_BOOT_INFO
, (caddr_t
)&f
, 0, ctx
)) != 0)
659 /* XXX we could at least pass out the volume UUID here */
660 bzero(&f
, sizeof(f
));
662 attrlist_pack_fixed(&ab
, f
, sizeof(f
));
664 if (alp
->commonattr
& ATTR_CMN_OWNERID
)
665 ATTR_PACK(&ab
, va
.va_uid
);
666 if (alp
->commonattr
& ATTR_CMN_GRPID
)
667 ATTR_PACK(&ab
, va
.va_gid
);
668 if (alp
->commonattr
& ATTR_CMN_ACCESSMASK
)
669 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
670 if (alp
->commonattr
& ATTR_CMN_FLAGS
)
671 ATTR_PACK(&ab
, va
.va_flags
);
672 if (alp
->commonattr
& ATTR_CMN_USERACCESS
) { /* XXX this is expensive and also duplicate work */
674 if (vnode_isdir(vp
)) {
675 if (vnode_authorize(vp
, NULL
,
676 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, ctx
) == 0)
678 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, ctx
) == 0)
680 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, ctx
) == 0)
683 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, ctx
) == 0)
685 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, ctx
) == 0)
687 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, ctx
) == 0)
690 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms
);
691 ATTR_PACK(&ab
, perms
);
694 /* volume attributes **************************************************/
696 if (alp
->volattr
& ATTR_VOL_FSTYPE
)
697 ATTR_PACK_CAST(&ab
, uint32_t, vfs_typenum(mnt
));
698 if (alp
->volattr
& ATTR_VOL_SIGNATURE
)
699 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_signature
);
700 if (alp
->volattr
& ATTR_VOL_SIZE
)
701 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_blocks
);
702 if (alp
->volattr
& ATTR_VOL_SPACEFREE
)
703 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bfree
);
704 if (alp
->volattr
& ATTR_VOL_SPACEAVAIL
)
705 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
* vs
.f_bavail
);
706 if (alp
->volattr
& ATTR_VOL_MINALLOCATION
)
707 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
);
708 if (alp
->volattr
& ATTR_VOL_ALLOCATIONCLUMP
)
709 ATTR_PACK_CAST(&ab
, off_t
, vs
.f_bsize
); /* not strictly true */
710 if (alp
->volattr
& ATTR_VOL_IOBLOCKSIZE
)
711 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_iosize
);
712 if (alp
->volattr
& ATTR_VOL_OBJCOUNT
)
713 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_objcount
);
714 if (alp
->volattr
& ATTR_VOL_FILECOUNT
)
715 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_filecount
);
716 if (alp
->volattr
& ATTR_VOL_DIRCOUNT
)
717 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_dircount
);
718 if (alp
->volattr
& ATTR_VOL_MAXOBJCOUNT
)
719 ATTR_PACK_CAST(&ab
, uint32_t, vs
.f_maxobjcount
);
720 if (alp
->volattr
& ATTR_VOL_MOUNTPOINT
)
721 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntonname
, 0);
722 if (alp
->volattr
& ATTR_VOL_NAME
)
723 attrlist_pack_string(&ab
, vs
.f_vol_name
, 0);
724 if (alp
->volattr
& ATTR_VOL_MOUNTFLAGS
)
725 ATTR_PACK_CAST(&ab
, uint32_t, mnt
->mnt_flag
);
726 if (alp
->volattr
& ATTR_VOL_MOUNTEDDEVICE
)
727 attrlist_pack_string(&ab
, mnt
->mnt_vfsstat
.f_mntfromname
, 0);
728 if (alp
->volattr
& ATTR_VOL_ENCODINGSUSED
)
729 ATTR_PACK_CAST(&ab
, uint64_t, ~0LL); /* return all encodings */
730 if (alp
->volattr
& ATTR_VOL_CAPABILITIES
) {
731 /* fix up volume capabilities */
732 if (vfs_extendedsecurity(mnt
)) {
733 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
735 vs
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] &= ~VOL_CAP_INT_EXTENDED_SECURITY
;
737 vs
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] |= VOL_CAP_INT_EXTENDED_SECURITY
;
738 ATTR_PACK(&ab
, vs
.f_capabilities
);
740 if (alp
->volattr
& ATTR_VOL_ATTRIBUTES
) {
741 /* fix up volume attribute information */
742 if (vfs_extendedsecurity(mnt
)) {
743 vs
.f_attributes
.validattr
.commonattr
|= (ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
745 vs
.f_attributes
.validattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
746 vs
.f_attributes
.nativeattr
.commonattr
&= ~(ATTR_CMN_EXTENDED_SECURITY
| ATTR_CMN_UUID
| ATTR_CMN_GRPUUID
);
748 ATTR_PACK(&ab
, vs
.f_attributes
);
752 if ((ab
.fixedcursor
- ab
.base
) != fixedsize
)
753 panic("packed field size mismatch; allocated %d but packed %d for common %08x vol %08x",
754 fixedsize
, ab
.fixedcursor
- ab
.base
, alp
->commonattr
, alp
->volattr
);
755 if (ab
.varcursor
!= (ab
.base
+ ab
.needed
))
756 panic("packed variable field size mismatch; used %d but expected %d", ab
.varcursor
- ab
.base
, ab
.needed
);
759 * In the compatible case, we report the smaller of the required and returned sizes.
760 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
761 * of the result buffer, even if we copied less out. The caller knows how big a buffer
762 * they gave us, so they can always check for truncation themselves.
764 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
766 error
= copyout(ab
.base
, uap
->attributeBuffer
, ab
.allocated
);
769 if (vs
.f_vol_name
!= NULL
)
770 kfree(vs
.f_vol_name
, MAXPATHLEN
);
772 FREE(ab
.base
, M_TEMP
);
773 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
778 * Obtain attribute information about a filesystem object.
781 getattrlist(struct proc
*p
, struct getattrlist_args
*uap
, __unused register_t
*retval
)
784 struct vnode_attr va
;
785 struct vfs_context context
, *ctx
;
787 struct _attrlist_buf ab
;
790 kauth_action_t action
;
791 ssize_t fixedsize
, varsize
;
798 context
.vc_ucred
= kauth_cred_get();
811 nameiflags
= AUDITVNPATH1
;
812 if (!(uap
->options
& FSOPT_NOFOLLOW
))
813 nameiflags
|= FOLLOW
;
814 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
816 if ((error
= namei(&nd
)) != 0)
822 * Fetch the attribute request.
824 if ((error
= copyin(uap
->alist
, &al
, sizeof(al
))) != 0)
826 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
831 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
832 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
833 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
836 * It is legal to request volume or file attributes,
840 if (al
.fileattr
|| al
.dirattr
|| al
.forkattr
) {
842 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
845 /* handle volume attribute request */
846 error
= getvolattrlist(vp
, uap
, &al
, &context
, proc_is64bit(p
));
851 * Set up the vnode_attr structure and authorise.
853 if ((error
= getattrlist_setupvattr(&al
, &va
, &fixedsize
, &action
, proc_is64bit(p
), vnode_isdir(vp
))) != 0) {
854 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setup for request failed");
857 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0) {
858 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorisation failed/denied");
862 if (va
.va_active
!= 0) {
864 * If we're going to ask for va_name, allocate a buffer to point it at
866 if (VATTR_IS_ACTIVE(&va
, va_name
)) {
867 va
.va_name
= (char *) kalloc(MAXPATHLEN
);
868 if (va
.va_name
== NULL
) {
870 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: cannot allocate va_name buffer");
876 * Call the filesystem.
878 if ((error
= vnode_getattr(vp
, &va
, &context
)) != 0) {
879 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
883 /* did we ask for something the filesystem doesn't support? */
884 if (!VATTR_ALL_SUPPORTED(&va
)) {
887 * There are a couple of special cases. If we are after object IDs,
888 * we can make do with va_fileid.
890 if ((al
.commonattr
& (ATTR_CMN_OBJID
| ATTR_CMN_OBJPERMANENTID
)) && !VATTR_IS_SUPPORTED(&va
, va_linkid
))
891 VATTR_CLEAR_ACTIVE(&va
, va_linkid
); /* forget we wanted this */
893 * Many (most?) filesystems don't know their parent object id. We can get it the
896 if ((al
.commonattr
& ATTR_CMN_PAROBJID
) && !VATTR_IS_SUPPORTED(&va
, va_parentid
))
897 VATTR_CLEAR_ACTIVE(&va
, va_parentid
);
899 * And we can report datasize/alloc from total.
901 if ((al
.fileattr
& ATTR_FILE_DATALENGTH
) && !VATTR_IS_SUPPORTED(&va
, va_data_size
))
902 VATTR_CLEAR_ACTIVE(&va
, va_data_size
);
903 if ((al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) && !VATTR_IS_SUPPORTED(&va
, va_data_alloc
))
904 VATTR_CLEAR_ACTIVE(&va
, va_data_alloc
);
907 * If we don't have an encoding, go with UTF-8
909 if ((al
.commonattr
& ATTR_CMN_SCRIPT
) && !VATTR_IS_SUPPORTED(&va
, va_encoding
))
910 VATTR_RETURN(&va
, va_encoding
, 0x7e /* kTextEncodingMacUnicode */);
913 * If we don't have a name, we'll get one from the vnode or mount point.
915 if ((al
.commonattr
& ATTR_CMN_NAME
) && !VATTR_IS_SUPPORTED(&va
, va_name
)) {
916 VATTR_CLEAR_ACTIVE(&va
, va_name
);
920 * We used to return va_nlink-2 for ATTR_DIR_ENTRYCOUNT. The va_nchildren
921 * field is preferred, but we'll fall back to va_nlink-2 for compatibility
922 * with file systems which haven't adopted va_nchildren. Note: the "- 2"
923 * reflects the "." and ".." entries which are reported via POSIX APIs, but
924 * not via Carbon (since they don't in fact exist in HFS).
926 if ((al
.dirattr
& ATTR_DIR_ENTRYCOUNT
) && !VATTR_IS_SUPPORTED(&va
, va_nchildren
) &&
927 VATTR_IS_SUPPORTED(&va
, va_nlink
)) {
928 VATTR_RETURN(&va
, va_nchildren
, va
.va_nlink
- 2);
932 if (!VATTR_ALL_SUPPORTED(&va
)) {
934 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not get all requested file attributes");
935 VFS_DEBUG(ctx
, vp
, "ATTRLIST - have %016llx wanted %016llx missing %016llx",
936 va
.va_supported
, va
.va_active
, va
.va_active
& ~va
.va_supported
);
943 * Compute variable-space requirements.
945 varsize
= 0; /* length count */
946 if (al
.commonattr
& ATTR_CMN_NAME
) {
947 if (VATTR_IS_SUPPORTED(&va
, va_name
)) {
948 va
.va_name
[MAXPATHLEN
-1] = '\0'; /* Ensure nul-termination */
952 if (vnode_isvroot(vp
)) {
953 if (vp
->v_mount
->mnt_vfsstat
.f_mntonname
[1] == 0x00 &&
954 vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0] == '/') {
955 /* special case for boot volume. Use root name when it's
956 * available (which is the volume name) or just the mount on
957 * name of "/". we must do this for binary compatibility with
958 * pre Tiger code. returning nothing for the boot volume name
959 * breaks installers - 3961058
961 cnp
= vname
= vnode_getname(vp
);
963 /* just use "/" as name */
964 cnp
= &vp
->v_mount
->mnt_vfsstat
.f_mntonname
[0];
969 getattrlist_findnamecomp(vp
->v_mount
->mnt_vfsstat
.f_mntonname
, &cnp
, &cnl
);
972 cnp
= vname
= vnode_getname(vp
);
979 varsize
+= roundup(cnl
+ 1, 4);
983 * We have a kauth_acl_t but we will be returning a kauth_filesec_t.
985 * XXX This needs to change at some point; since the blob is opaque in
986 * user-space this is OK.
988 if ((al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) &&
989 VATTR_IS_SUPPORTED(&va
, va_acl
) &&
991 varsize
+= roundup(KAUTH_FILESEC_SIZE(va
.va_acl
->acl_entrycount
), 4);
994 * Allocate a target buffer for attribute results.
996 * Note that we won't ever copy out more than the caller requested, even though
997 * we might have to allocate more than they offer do that the diagnostic checks
998 * don't result in a panic if the caller's buffer is too small..
1000 ab
.allocated
= fixedsize
+ varsize
;
1001 if (ab
.allocated
> ATTR_MAX_BUFFER
) {
1003 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab
.allocated
, ATTR_MAX_BUFFER
);
1006 MALLOC(ab
.base
, char *, ab
.allocated
, M_TEMP
, M_WAITOK
);
1007 if (ab
.base
== NULL
) {
1009 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab
.allocated
);
1014 * Pack results into the destination buffer.
1016 ab
.fixedcursor
= ab
.base
+ sizeof(uint32_t);
1017 ab
.varcursor
= ab
.base
+ fixedsize
;
1018 ab
.needed
= ab
.allocated
;
1020 /* common attributes **************************************************/
1021 if (al
.commonattr
& ATTR_CMN_NAME
)
1022 attrlist_pack_string(&ab
, cnp
, cnl
);
1023 if (al
.commonattr
& ATTR_CMN_DEVID
)
1024 ATTR_PACK_CAST(&ab
, dev_t
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1025 if (al
.commonattr
& ATTR_CMN_FSID
)
1026 ATTR_PACK(&ab
, vp
->v_mount
->mnt_vfsstat
.f_fsid
);
1027 if (al
.commonattr
& ATTR_CMN_OBJTYPE
)
1028 ATTR_PACK_CAST(&ab
, fsobj_type_t
, vp
->v_type
);
1029 if (al
.commonattr
& ATTR_CMN_OBJTAG
)
1030 ATTR_PACK_CAST(&ab
, fsobj_tag_t
, vp
->v_tag
);
1031 if (al
.commonattr
& ATTR_CMN_OBJID
) {
1034 * Carbon can't deal with us reporting the target ID
1035 * for links. So we ask the filesystem to give us the
1036 * source ID as well, and if it gives us one, we use
1039 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1040 f
.fid_objno
= va
.va_linkid
;
1042 f
.fid_objno
= va
.va_fileid
;
1044 f
.fid_generation
= 0;
1047 if (al
.commonattr
& ATTR_CMN_OBJPERMANENTID
) {
1050 * Carbon can't deal with us reporting the target ID
1051 * for links. So we ask the filesystem to give us the
1052 * source ID as well, and if it gives us one, we use
1055 if (VATTR_IS_SUPPORTED(&va
, va_linkid
)) {
1056 f
.fid_objno
= va
.va_linkid
;
1058 f
.fid_objno
= va
.va_fileid
;
1060 f
.fid_generation
= 0;
1063 if (al
.commonattr
& ATTR_CMN_PAROBJID
) {
1066 * If the filesystem doesn't know the parent ID, we can
1067 * try to get it via v->v_parent. Don't need to worry
1068 * about links here, as we dont allow hardlinks to
1071 if (VATTR_IS_SUPPORTED(&va
, va_parentid
)) {
1072 f
.fid_objno
= va
.va_parentid
;
1074 struct vnode_attr lva
;
1077 pvp
= vnode_getparent(vp
);
1079 if (pvp
== NULLVP
) {
1084 VATTR_WANTED(&lva
, va_fileid
);
1085 error
= vnode_getattr(pvp
, &lva
, &context
);
1090 f
.fid_objno
= lva
.va_fileid
;
1092 f
.fid_generation
= 0;
1095 if (al
.commonattr
& ATTR_CMN_SCRIPT
)
1096 ATTR_PACK_CAST(&ab
, text_encoding_t
, va
.va_encoding
);
1097 if (al
.commonattr
& ATTR_CMN_CRTIME
)
1098 ATTR_PACK_TIME(&ab
, va
.va_create_time
, proc_is64bit(p
));
1099 if (al
.commonattr
& ATTR_CMN_MODTIME
)
1100 ATTR_PACK_TIME(&ab
, va
.va_modify_time
, proc_is64bit(p
));
1101 if (al
.commonattr
& ATTR_CMN_CHGTIME
)
1102 ATTR_PACK_TIME(&ab
, va
.va_change_time
, proc_is64bit(p
));
1103 if (al
.commonattr
& ATTR_CMN_ACCTIME
)
1104 ATTR_PACK_TIME(&ab
, va
.va_access_time
, proc_is64bit(p
));
1105 if (al
.commonattr
& ATTR_CMN_BKUPTIME
)
1106 ATTR_PACK_TIME(&ab
, va
.va_backup_time
, proc_is64bit(p
));
1107 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1110 char uio_buf
[UIO_SIZEOF(1)];
1112 fisize
= imin(32, ab
.allocated
- (ab
.fixedcursor
- ab
.base
));
1114 if ((auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
, uio_buf
, sizeof(uio_buf
))) == NULL
) {
1118 uio_addiov(auio
, CAST_USER_ADDR_T(ab
.fixedcursor
), fisize
);
1119 error
= vn_getxattr(vp
, XATTR_FINDERINFO_NAME
, auio
, &fisize
, XATTR_NOSECURITY
, &context
);
1123 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)) {
1124 VFS_DEBUG(ctx
, vp
, "ATTRLIST - No system.finderinfo attribute, returning zeroes");
1125 bzero(ab
.fixedcursor
, 32);
1128 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: reading system.finderinfo attribute");
1133 VFS_DEBUG(ctx
, vp
, "ATTRLIST - no room in caller buffer for FINDERINFO");
1135 ab
.fixedcursor
+= 32;
1137 if (al
.commonattr
& ATTR_CMN_OWNERID
)
1138 ATTR_PACK(&ab
, va
.va_uid
);
1139 if (al
.commonattr
& ATTR_CMN_GRPID
)
1140 ATTR_PACK(&ab
, va
.va_gid
);
1141 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
)
1142 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_mode
);
1143 if (al
.commonattr
& ATTR_CMN_FLAGS
)
1144 ATTR_PACK(&ab
, va
.va_flags
);
1145 if (al
.commonattr
& ATTR_CMN_USERACCESS
) { /* this is expensive */
1147 if (vnode_isdir(vp
)) {
1148 if (vnode_authorize(vp
, NULL
,
1149 KAUTH_VNODE_ACCESS
| KAUTH_VNODE_ADD_FILE
| KAUTH_VNODE_ADD_SUBDIRECTORY
| KAUTH_VNODE_DELETE_CHILD
, &context
) == 0)
1151 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_LIST_DIRECTORY
, &context
) == 0)
1153 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_SEARCH
, &context
) == 0)
1156 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_WRITE_DATA
, &context
) == 0)
1158 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_READ_DATA
, &context
) == 0)
1160 if (vnode_authorize(vp
, NULL
, KAUTH_VNODE_ACCESS
| KAUTH_VNODE_EXECUTE
, &context
) == 0)
1163 VFS_DEBUG(ctx
, vp
, "ATTRLIST - granting perms %d", perms
);
1164 ATTR_PACK(&ab
, perms
);
1166 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1167 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
)) {
1168 struct kauth_filesec fsec
;
1170 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl.
1172 fsec
.fsec_magic
= KAUTH_FILESEC_MAGIC
;
1173 fsec
.fsec_owner
= kauth_null_guid
;
1174 fsec
.fsec_group
= kauth_null_guid
;
1175 attrlist_pack_variable2(&ab
, &fsec
, ((char *)&fsec
.fsec_acl
- (char *)&fsec
), va
.va_acl
, KAUTH_ACL_COPYSIZE(va
.va_acl
));
1177 attrlist_pack_variable(&ab
, NULL
, 0);
1180 if (al
.commonattr
& ATTR_CMN_UUID
) {
1181 if (!VATTR_IS_SUPPORTED(&va
, va_uuuid
)) {
1182 ATTR_PACK(&ab
, kauth_null_guid
);
1184 ATTR_PACK(&ab
, va
.va_uuuid
);
1187 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1188 if (!VATTR_IS_SUPPORTED(&va
, va_guuid
)) {
1189 ATTR_PACK(&ab
, kauth_null_guid
);
1191 ATTR_PACK(&ab
, va
.va_guuid
);
1195 /* directory attributes **************************************************/
1196 if (vnode_isdir(vp
)) {
1197 if (al
.dirattr
& ATTR_DIR_LINKCOUNT
) /* full count of entries */
1198 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nlink
);
1199 if (al
.dirattr
& ATTR_DIR_ENTRYCOUNT
)
1200 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nchildren
);
1201 if (al
.dirattr
& ATTR_DIR_MOUNTSTATUS
)
1202 ATTR_PACK_CAST(&ab
, uint32_t, (vp
->v_flag
& VROOT
) ? DIR_MNTSTATUS_MNTPOINT
: 0);
1205 /* file attributes **************************************************/
1206 if (!vnode_isdir(vp
)) {
1207 if (al
.fileattr
& ATTR_FILE_LINKCOUNT
)
1208 ATTR_PACK_CAST(&ab
, uint32_t, va
.va_nlink
);
1209 if (al
.fileattr
& ATTR_FILE_TOTALSIZE
)
1210 ATTR_PACK(&ab
, va
.va_total_size
);
1211 if (al
.fileattr
& ATTR_FILE_ALLOCSIZE
)
1212 ATTR_PACK(&ab
, va
.va_total_alloc
);
1213 if (al
.fileattr
& ATTR_FILE_IOBLOCKSIZE
)
1214 ATTR_PACK(&ab
, va
.va_iosize
);
1215 if (al
.fileattr
& ATTR_FILE_CLUMPSIZE
)
1216 ATTR_PACK_CAST(&ab
, uint32_t, 0); /* XXX value is deprecated */
1217 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1218 if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1219 ATTR_PACK(&ab
, vp
->v_specinfo
->si_rdev
);
1221 ATTR_PACK_CAST(&ab
, uint32_t, 0);
1224 if (al
.fileattr
& ATTR_FILE_DATALENGTH
) {
1225 if (VATTR_IS_SUPPORTED(&va
, va_data_size
)) {
1226 ATTR_PACK(&ab
, va
.va_data_size
);
1228 ATTR_PACK(&ab
, va
.va_total_size
);
1231 if (al
.fileattr
& ATTR_FILE_DATAALLOCSIZE
) {
1232 if (VATTR_IS_SUPPORTED(&va
, va_data_alloc
)) {
1233 ATTR_PACK(&ab
, va
.va_data_alloc
);
1235 ATTR_PACK(&ab
, va
.va_total_alloc
);
1238 /* fetch resource fork size/allocation via xattr interface */
1239 if (al
.fileattr
& (ATTR_FILE_RSRCLENGTH
| ATTR_FILE_RSRCALLOCSIZE
)) {
1241 if ((error
= vn_getxattr(vp
, XATTR_RESOURCEFORK_NAME
, NULL
, &rsize
, XATTR_NOSECURITY
, &context
)) != 0) {
1242 if ((error
== ENOENT
) || (error
== ENOATTR
) || (error
== ENOTSUP
) || (error
== EPERM
)) {
1249 if (al
.fileattr
& ATTR_FILE_RSRCLENGTH
)
1250 ATTR_PACK_CAST(&ab
, off_t
, rsize
);
1251 if (al
.fileattr
& ATTR_FILE_RSRCALLOCSIZE
) {
1252 uint32_t blksize
= vp
->v_mount
->mnt_vfsstat
.f_bsize
;
1255 ATTR_PACK_CAST(&ab
, off_t
, (roundup(rsize
, blksize
)));
1261 if ((ab
.fixedcursor
- ab
.base
) != fixedsize
)
1262 panic("packed field size mismatch; allocated %d but packed %d for common %08x vol %08x",
1263 fixedsize
, ab
.fixedcursor
- ab
.base
, al
.commonattr
, al
.volattr
);
1264 if (ab
.varcursor
!= (ab
.base
+ ab
.needed
))
1265 panic("packed variable field size mismatch; used %d but expected %d", ab
.varcursor
- ab
.base
, ab
.needed
);
1268 * In the compatible case, we report the smaller of the required and returned sizes.
1269 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size
1270 * of the result buffer, even if we copied less out. The caller knows how big a buffer
1271 * they gave us, so they can always check for truncation themselves.
1273 *(uint32_t *)ab
.base
= (uap
->options
& FSOPT_REPORT_FULLSIZE
) ? ab
.needed
: imin(ab
.allocated
, ab
.needed
);
1275 /* Only actually copyout as much out as the user buffer can hold */
1276 error
= copyout(ab
.base
, uap
->attributeBuffer
, imin(uap
->bufferSize
, ab
.allocated
));
1280 kfree(va
.va_name
, MAXPATHLEN
);
1282 vnode_putname(vname
);
1285 if (ab
.base
!= NULL
)
1286 FREE(ab
.base
, M_TEMP
);
1287 if (VATTR_IS_SUPPORTED(&va
, va_acl
) && (va
.va_acl
!= NULL
))
1288 kauth_acl_free(va
.va_acl
);
1290 VFS_DEBUG(ctx
, vp
, "ATTRLIST - returning %d", error
);
1295 attrlist_unpack_fixed(char **cursor
, char *end
, void *buf
, ssize_t size
)
1297 /* make sure we have enough source data */
1298 if ((*cursor
) + size
> end
)
1301 bcopy(*cursor
, buf
, size
);
1306 #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
1307 #define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
1308 #define ATTR_UNPACK_TIME(v, is64) \
1311 struct user_timespec us; \
1313 v.tv_sec = us.tv_sec; \
1314 v.tv_nsec = us.tv_nsec; \
1325 setattrlist(struct proc
*p
, register struct setattrlist_args
*uap
, __unused register_t
*retval
)
1328 struct vfs_context context
, *ctx
;
1329 struct vnode_attr va
;
1330 struct attrreference ar
;
1331 struct nameidata nd
;
1334 kauth_action_t action
;
1335 char *user_buf
, *cursor
, *bufend
, *fndrinfo
, *cp
, *volname
;
1336 int proc_is64
, error
;
1338 kauth_filesec_t rfsec
;
1340 context
.vc_proc
= p
;
1341 context
.vc_ucred
= kauth_cred_get();
1348 proc_is64
= proc_is64bit(p
);
1356 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0)
1357 nameiflags
|= FOLLOW
;
1358 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, &context
);
1359 if ((error
= namei(&nd
)) != 0)
1365 * Fetch the attribute set and validate.
1367 if ((error
= copyin(uap
->alist
, (caddr_t
) &al
, sizeof (al
))))
1369 if (al
.bitmapcount
!= ATTR_BIT_MAP_COUNT
) {
1374 VFS_DEBUG(ctx
, vp
, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
1375 vp
, p
->p_comm
, al
.commonattr
, al
.volattr
, al
.fileattr
, al
.dirattr
, al
.forkattr
,
1376 (uap
->options
& FSOPT_NOFOLLOW
) ? "no":"", vp
->v_name
);
1379 if ((al
.volattr
& ~ATTR_VOL_SETMASK
) ||
1380 (al
.commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
1384 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid volume attributes");
1388 if ((al
.commonattr
& ~ATTR_CMN_SETMASK
) ||
1389 (al
.fileattr
& ~ATTR_FILE_SETMASK
) ||
1390 (al
.dirattr
& ~ATTR_DIR_SETMASK
) ||
1391 (al
.forkattr
& ~ATTR_FORK_SETMASK
)) {
1393 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes");
1399 * Make the naive assumption that the caller has supplied a reasonable buffer
1400 * size. We could be more careful by pulling in the fixed-size region, checking
1401 * the attrref structures, then pulling in the variable section.
1402 * We need to reconsider this for handling large ACLs, as they should probably be
1403 * brought directly into a buffer. Multiple copyins will make this slower though.
1405 * We could also map the user buffer if it is larger than some sensible mimimum.
1407 if (uap
->bufferSize
> ATTR_MAX_BUFFER
) {
1408 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer size %d too large", uap
->bufferSize
);
1412 MALLOC(user_buf
, char *, uap
->bufferSize
, M_TEMP
, M_WAITOK
);
1413 if (user_buf
== NULL
) {
1414 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap
->bufferSize
);
1418 if ((error
= copyin(uap
->attributeBuffer
, user_buf
, uap
->bufferSize
)) != 0) {
1419 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: buffer copyin failed");
1422 VFS_DEBUG(ctx
, vp
, "ATTRLIST - copied in %d bytes of user attributes to %p", uap
->bufferSize
, user_buf
);
1425 * Unpack the argument buffer.
1428 bufend
= cursor
+ uap
->bufferSize
;
1431 if (al
.commonattr
& ATTR_CMN_SCRIPT
) {
1432 ATTR_UNPACK(va
.va_encoding
);
1433 VATTR_SET_ACTIVE(&va
, va_encoding
);
1435 if (al
.commonattr
& ATTR_CMN_CRTIME
) {
1436 ATTR_UNPACK_TIME(va
.va_create_time
, proc_is64
);
1437 VATTR_SET_ACTIVE(&va
, va_create_time
);
1439 if (al
.commonattr
& ATTR_CMN_MODTIME
) {
1440 ATTR_UNPACK_TIME(va
.va_modify_time
, proc_is64
);
1441 VATTR_SET_ACTIVE(&va
, va_modify_time
);
1443 if (al
.commonattr
& ATTR_CMN_CHGTIME
) {
1444 ATTR_UNPACK_TIME(va
.va_change_time
, proc_is64
);
1445 VATTR_SET_ACTIVE(&va
, va_change_time
);
1447 if (al
.commonattr
& ATTR_CMN_ACCTIME
) {
1448 ATTR_UNPACK_TIME(va
.va_access_time
, proc_is64
);
1449 VATTR_SET_ACTIVE(&va
, va_access_time
);
1451 if (al
.commonattr
& ATTR_CMN_BKUPTIME
) {
1452 ATTR_UNPACK_TIME(va
.va_backup_time
, proc_is64
);
1453 VATTR_SET_ACTIVE(&va
, va_backup_time
);
1455 if (al
.commonattr
& ATTR_CMN_FNDRINFO
) {
1456 if ((cursor
+ 32) > bufend
) {
1458 VFS_DEBUG(ctx
, vp
, "ATTRLIST - not enough data supplied for FINDERINFO");
1464 if (al
.commonattr
& ATTR_CMN_OWNERID
) {
1465 ATTR_UNPACK(va
.va_uid
);
1466 VATTR_SET_ACTIVE(&va
, va_uid
);
1468 if (al
.commonattr
& ATTR_CMN_GRPID
) {
1469 ATTR_UNPACK(va
.va_gid
);
1470 VATTR_SET_ACTIVE(&va
, va_gid
);
1472 if (al
.commonattr
& ATTR_CMN_ACCESSMASK
) {
1473 ATTR_UNPACK_CAST(uint32_t, va
.va_mode
);
1474 VATTR_SET_ACTIVE(&va
, va_mode
);
1476 if (al
.commonattr
& ATTR_CMN_FLAGS
) {
1477 ATTR_UNPACK(va
.va_flags
);
1478 VATTR_SET_ACTIVE(&va
, va_flags
);
1480 if (al
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) {
1483 * We are (for now) passed a kauth_filesec_t, but all we want from
1488 cp
+= ar
.attr_dataoffset
;
1489 rfsec
= (kauth_filesec_t
)cp
;
1490 if (((char *)(rfsec
+ 1) > bufend
) || /* no space for acl */
1491 (rfsec
->fsec_magic
!= KAUTH_FILESEC_MAGIC
) || /* bad magic */
1492 (KAUTH_FILESEC_COPYSIZE(rfsec
) != ar
.attr_length
) || /* size does not match */
1493 ((cp
+ KAUTH_FILESEC_COPYSIZE(rfsec
)) > bufend
)) { /* ACEs overrun buffer */
1495 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied", ar
.attr_length
);
1498 nace
= rfsec
->fsec_entrycount
;
1499 if (nace
== KAUTH_FILESEC_NOACL
)
1501 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
1503 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: bad ACL supplied");
1506 nace
= rfsec
->fsec_acl
.acl_entrycount
;
1507 if (nace
== KAUTH_FILESEC_NOACL
) {
1509 VATTR_SET(&va
, va_acl
, NULL
);
1512 if (nace
> KAUTH_ACL_MAX_ENTRIES
) { /* ACL size invalid */
1514 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: supplied ACL is too large");
1517 VATTR_SET(&va
, va_acl
, &rfsec
->fsec_acl
);
1520 if (al
.commonattr
& ATTR_CMN_UUID
) {
1521 ATTR_UNPACK(va
.va_uuuid
);
1522 VATTR_SET_ACTIVE(&va
, va_uuuid
);
1524 if (al
.commonattr
& ATTR_CMN_GRPUUID
) {
1525 ATTR_UNPACK(va
.va_guuid
);
1526 VATTR_SET_ACTIVE(&va
, va_guuid
);
1530 if (al
.volattr
& ATTR_VOL_INFO
) {
1531 if (al
.volattr
& ATTR_VOL_NAME
) {
1534 volname
+= ar
.attr_dataoffset
;
1535 if ((volname
+ ar
.attr_length
) > bufend
) {
1537 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: volume name too big for caller buffer");
1540 /* guarantee NUL termination */
1541 volname
[ar
.attr_length
- 1] = 0;
1546 if (al
.fileattr
& ATTR_FILE_DEVTYPE
) {
1547 /* XXX does it actually make any sense to change this? */
1549 VFS_DEBUG(ctx
, vp
, "ATTRLIST - XXX device type change not implemented");
1554 * Validate and authorize.
1557 if ((va
.va_active
!= 0LL) && ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)) {
1558 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: attribute changes refused: %d", error
);
1562 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data,
1563 * and will be auth'ed by the FS.
1565 if (fndrinfo
!= NULL
) {
1566 if (al
.volattr
& ATTR_VOL_INFO
) {
1567 if (vp
->v_tag
!= VT_HFS
) {
1572 action
|= KAUTH_VNODE_WRITE_ATTRIBUTES
;
1576 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
1577 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: authorization failed");
1582 * When we're setting both the access mask and the finder info, then
1583 * check if were about to remove write access for the owner. Since
1584 * vnode_setattr and vn_setxattr invoke two separate vnops, we need
1585 * to consider their ordering.
1587 * If were about to remove write access for the owner we'll set the
1588 * Finder Info here before vnode_setattr. Otherwise we'll set it
1589 * after vnode_setattr since it may be adding owner write access.
1591 if ((fndrinfo
!= NULL
) && !(al
.volattr
& ATTR_VOL_INFO
) &&
1592 (al
.commonattr
& ATTR_CMN_ACCESSMASK
) && !(va
.va_mode
& S_IWUSR
)) {
1593 if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, &context
)) != 0) {
1596 fndrinfo
= NULL
; /* it was set here so skip setting below */
1600 * Write the attributes if we have any.
1602 if ((va
.va_active
!= 0LL) && ((error
= vnode_setattr(vp
, &va
, &context
)) != 0)) {
1603 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: filesystem returned %d", error
);
1608 * Write the Finder Info if we have any.
1610 if (fndrinfo
!= NULL
) {
1611 if (al
.volattr
& ATTR_VOL_INFO
) {
1612 if (vp
->v_tag
== VT_HFS
) {
1613 error
= VNOP_IOCTL(vp
, HFS_SET_BOOT_INFO
, (caddr_t
)fndrinfo
, 0, &context
);
1617 /* XXX should never get here */
1619 } else if ((error
= setattrlist_setfinderinfo(vp
, fndrinfo
, &context
)) != 0) {
1625 * Set the volume name, if we have one
1627 if (volname
!= NULL
)
1633 vs
.f_vol_name
= volname
; /* References the setattrlist buffer directly */
1634 VFSATTR_WANTED(&vs
, f_vol_name
);
1636 if ((error
= vfs_setattr(vp
->v_mount
, &vs
, ctx
)) != 0) {
1637 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: setting volume name failed");
1641 if (!VFSATTR_ALL_SUPPORTED(&vs
)) {
1643 VFS_DEBUG(ctx
, vp
, "ATTRLIST - ERROR: could not set volume name");
1648 /* all done and successful */
1653 if (user_buf
!= NULL
)
1654 FREE(user_buf
, M_TEMP
);
1655 VFS_DEBUG(ctx
, vp
, "ATTRLIST - set returning %d", error
);