/*
- * Copyright (c) 1995-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 1995-2019 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
#include <sys/file_internal.h>
#include <sys/kauth.h>
#include <sys/uio_internal.h>
-#include <sys/malloc.h>
+#include <kern/kalloc.h>
#include <sys/attr.h>
#include <sys/sysproto.h>
#include <sys/xattr.h>
#include <sys/fsevents.h>
-#include <kern/kalloc.h>
+#include <kern/zalloc.h>
#include <miscfs/specfs/specdev.h>
+#include <security/audit/audit.h>
#if CONFIG_MACF
#include <security/mac_framework.h>
#endif
-#define ATTR_TIME_SIZE -1
+#define ATTR_TIME_SIZE -1
+
+static int readdirattr(vnode_t, struct fd_vn_data *, uio_t, struct attrlist *,
+ uint64_t, int *, int *, vfs_context_t ctx) __attribute__((noinline));
+
+static void
+vattr_get_alt_data(vnode_t, struct attrlist *, struct vnode_attr *, int, int,
+ int, vfs_context_t) __attribute__((noinline));
+
+static void get_error_attributes(vnode_t, struct attrlist *, uint64_t, user_addr_t,
+ size_t, int, caddr_t, vfs_context_t) __attribute__((noinline));
+
+static int getvolattrlist(vfs_context_t, vnode_t, struct attrlist *, user_addr_t,
+ size_t, uint64_t, enum uio_seg, int) __attribute__((noinline));
+
+static int get_direntry(vfs_context_t, vnode_t, struct fd_vn_data *, int *,
+ struct direntry **) __attribute__((noinline));
/*
* Structure describing the state of an in-progress attrlist operation.
*/
struct _attrlist_buf {
- char *base;
- char *fixedcursor;
- char *varcursor;
- ssize_t allocated;
+ char *base;
+ char *fixedcursor;
+ char *varcursor;
+ ssize_t allocated;
ssize_t needed;
- attribute_set_t actual;
+ attribute_set_t actual;
attribute_set_t valid;
};
static void
attrlist_pack_fixed(struct _attrlist_buf *ab, void *source, ssize_t count)
{
- /*
+ /*
* Use ssize_t for pointer math purposes,
* since a ssize_t is a signed long
*/
- ssize_t fit;
+ ssize_t fit;
/*
* Compute the amount of remaining space in the attrlist buffer
* based on how much we've used for fixed width fields vs. the
- * start of the attributes.
- *
- * If we've still got room, then 'fit' will contain the amount of
- * remaining space.
- *
- * Note that this math is safe because, in the event that the
+ * start of the attributes.
+ *
+ * If we've still got room, then 'fit' will contain the amount of
+ * remaining space.
+ *
+ * Note that this math is safe because, in the event that the
* fixed-width cursor has moved beyond the end of the buffer,
- * then, the second input into lmin() below will be negative, and
- * we will fail the (fit > 0) check below.
- */
+ * then, the second input into lmin() below will be negative, and
+ * we will fail the (fit > 0) check below.
+ */
fit = lmin(count, ab->allocated - (ab->fixedcursor - ab->base));
if (fit > 0) {
/* Copy in as much as we can */
* Attempt to pack one (or two) variable width attributes into the attrlist
* buffer. If we are trying to pack two variable width attributes, they are treated
* as a single variable-width attribute from the POV of the system call caller.
- *
- * Recall that a variable-width attribute has two components: the fixed-width
+ *
+ * Recall that a variable-width attribute has two components: the fixed-width
* attribute that tells the caller where to look, and the actual variable width data.
*/
static void
-attrlist_pack_variable2(struct _attrlist_buf *ab, const void *source, ssize_t count,
- const void *ext, ssize_t extcount)
+attrlist_pack_variable2(struct _attrlist_buf *ab, const void *source, ssize_t count,
+ const void *ext, ssize_t extcount)
{
/* Use ssize_t's for pointer math ease */
struct attrreference ar;
ssize_t fit;
/*
- * Pack the fixed-width component to the variable object.
+ * Pack the fixed-width component to the variable object.
* Note that we may be able to pack the fixed width attref, but not
* the variable (if there's no room).
*/
- ar.attr_dataoffset = ab->varcursor - ab->fixedcursor;
- ar.attr_length = count + extcount;
+ ar.attr_dataoffset = (int32_t)(ab->varcursor - ab->fixedcursor);
+ ar.attr_length = (u_int32_t)(count + extcount);
attrlist_pack_fixed(ab, &ar, sizeof(ar));
- /*
+ /*
* Use an lmin() to do a signed comparison. We use a signed comparison
* to detect the 'out of memory' conditions as described above in the
* fixed width check above.
*
* Then pack the first variable attribute as space allows. Note that we advance
- * the variable cursor only if we we had some available space.
+ * the variable cursor only if we we had some available space.
*/
fit = lmin(count, ab->allocated - (ab->varcursor - ab->base));
if (fit > 0) {
ab->varcursor = (char *)roundup((uintptr_t)ab->varcursor, 4);
}
-/*
+/*
* Packing a single variable-width attribute is the same as calling the two, but with
* an invalid 2nd attribute.
*/
* allocated buffer space.
*/
static void
-attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count)
+attrlist_pack_string(struct _attrlist_buf *ab, const char *source, size_t count)
{
struct attrreference ar;
ssize_t fit, space;
}
/*
- * Construct the fixed-width attribute that refers to this string.
+ * Construct the fixed-width attribute that refers to this string.
*/
- ar.attr_dataoffset = ab->varcursor - ab->fixedcursor;
- ar.attr_length = count + 1;
+ ar.attr_dataoffset = (int32_t)(ab->varcursor - ab->fixedcursor);
+ ar.attr_length = (u_int32_t)count + 1;
attrlist_pack_fixed(ab, &ar, sizeof(ar));
/*
space = ab->allocated - (ab->varcursor - ab->base);
fit = lmin(count, space);
if (space > 0) {
- int bytes_to_zero;
+ long bytes_to_zero;
- /*
- * If there is space remaining, copy data in, and
+ /*
+ * If there is space remaining, copy data in, and
* accommodate the trailing NUL terminator.
*
* NOTE: if "space" is too small to hold the string and its NUL
* Zero out any additional bytes we might have as a
* result of rounding up.
*/
- bytes_to_zero = min((roundup(fit, 4) - fit),
+ bytes_to_zero = lmin((roundup(fit, 4) - fit),
space - fit);
- if (bytes_to_zero)
+ if (bytes_to_zero) {
bzero(&(ab->varcursor[fit]), bytes_to_zero);
+ }
}
}
- /*
+ /*
* always move in increments of 4 (including the trailing NUL)
*/
- ab->varcursor += roundup((count+1), 4);
-
+ ab->varcursor += roundup((count + 1), 4);
}
#define ATTR_PACK4(AB, V) \
do { \
- if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \
- *(uint32_t *)AB.fixedcursor = V; \
- AB.fixedcursor += 4; \
- } \
+ if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \
+ *(uint32_t *)AB.fixedcursor = V; \
+ AB.fixedcursor += 4; \
+ } \
} while (0)
#define ATTR_PACK8(AB, V) \
do { \
- if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
- *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \
- AB.fixedcursor += 8; \
- } \
+ if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
+ memcpy(AB.fixedcursor, &V, 8); \
+ AB.fixedcursor += 8; \
+ } \
} while (0)
-#define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
-#define ATTR_PACK_CAST(b, t, v) \
- do { \
- t _f = (t)v; \
- ATTR_PACK(b, _f); \
+#define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v))
+#define ATTR_PACK_CAST(b, t, v) \
+ do { \
+ t _f = (t)v; \
+ ATTR_PACK(b, _f); \
} while (0)
-#define ATTR_PACK_TIME(b, v, is64) \
- do { \
- if (is64) { \
- struct user64_timespec us = {v.tv_sec, v.tv_nsec}; \
- ATTR_PACK(&b, us); \
- } else { \
- struct user32_timespec us = {v.tv_sec, v.tv_nsec}; \
- ATTR_PACK(&b, us); \
- } \
+#define ATTR_PACK_TIME(b, v, is64) \
+ do { \
+ if (is64) { \
+ struct user64_timespec us = {.tv_sec = v.tv_sec, .tv_nsec = v.tv_nsec}; \
+ ATTR_PACK(&b, us); \
+ } else { \
+ struct user32_timespec us = {.tv_sec = (user32_time_t)v.tv_sec, .tv_nsec = (user32_long_t)v.tv_nsec}; \
+ ATTR_PACK(&b, us); \
+ } \
} while(0)
* Table-driven setup for all valid common/volume attributes.
*/
struct getvolattrlist_attrtab {
- attrgroup_t attr;
- uint64_t bits;
-#define VFSATTR_BIT(b) (VFSATTR_ ## b)
- ssize_t size;
+ attrgroup_t attr;
+ uint64_t bits;
+#define VFSATTR_BIT(b) (VFSATTR_ ## b)
+ ssize_t size;
};
static struct getvolattrlist_attrtab getvolattrlist_common_tab[] = {
- {ATTR_CMN_NAME, 0, sizeof(struct attrreference)},
- {ATTR_CMN_DEVID, 0, sizeof(dev_t)},
- {ATTR_CMN_FSID, 0, sizeof(fsid_t)},
- {ATTR_CMN_OBJTYPE, 0, sizeof(fsobj_type_t)},
- {ATTR_CMN_OBJTAG, 0, sizeof(fsobj_tag_t)},
- {ATTR_CMN_OBJID, 0, sizeof(fsobj_id_t)},
- {ATTR_CMN_OBJPERMANENTID, 0, sizeof(fsobj_id_t)},
- {ATTR_CMN_PAROBJID, 0, sizeof(fsobj_id_t)},
- {ATTR_CMN_SCRIPT, 0, sizeof(text_encoding_t)},
- {ATTR_CMN_CRTIME, VFSATTR_BIT(f_create_time), ATTR_TIME_SIZE},
- {ATTR_CMN_MODTIME, VFSATTR_BIT(f_modify_time), ATTR_TIME_SIZE},
- {ATTR_CMN_CHGTIME, VFSATTR_BIT(f_modify_time), ATTR_TIME_SIZE},
- {ATTR_CMN_ACCTIME, VFSATTR_BIT(f_access_time), ATTR_TIME_SIZE},
- {ATTR_CMN_BKUPTIME, VFSATTR_BIT(f_backup_time), ATTR_TIME_SIZE},
- {ATTR_CMN_FNDRINFO, 0, 32},
- {ATTR_CMN_OWNERID, 0, sizeof(uid_t)},
- {ATTR_CMN_GRPID, 0, sizeof(gid_t)},
- {ATTR_CMN_ACCESSMASK, 0, sizeof(uint32_t)},
- {ATTR_CMN_FLAGS, 0, sizeof(uint32_t)},
- {ATTR_CMN_USERACCESS, 0, sizeof(uint32_t)},
- {ATTR_CMN_EXTENDED_SECURITY, 0, sizeof(struct attrreference)},
- {ATTR_CMN_UUID, 0, sizeof(guid_t)},
- {ATTR_CMN_GRPUUID, 0, sizeof(guid_t)},
- {ATTR_CMN_FILEID, 0, sizeof(uint64_t)},
- {ATTR_CMN_PARENTID, 0, sizeof(uint64_t)},
- {ATTR_CMN_RETURNED_ATTRS, 0, sizeof(attribute_set_t)},
- {ATTR_CMN_ERROR, 0, sizeof(uint32_t)},
- {0, 0, 0}
+ {.attr = ATTR_CMN_NAME, .bits = 0, .size = sizeof(struct attrreference)},
+ {.attr = ATTR_CMN_DEVID, .bits = 0, .size = sizeof(dev_t)},
+ {.attr = ATTR_CMN_FSID, .bits = 0, .size = sizeof(fsid_t)},
+ {.attr = ATTR_CMN_OBJTYPE, .bits = 0, .size = sizeof(fsobj_type_t)},
+ {.attr = ATTR_CMN_OBJTAG, .bits = 0, .size = sizeof(fsobj_tag_t)},
+ {.attr = ATTR_CMN_OBJID, .bits = 0, .size = sizeof(fsobj_id_t)},
+ {.attr = ATTR_CMN_OBJPERMANENTID, .bits = 0, .size = sizeof(fsobj_id_t)},
+ {.attr = ATTR_CMN_PAROBJID, .bits = 0, .size = sizeof(fsobj_id_t)},
+ {.attr = ATTR_CMN_SCRIPT, .bits = 0, .size = sizeof(text_encoding_t)},
+ {.attr = ATTR_CMN_CRTIME, .bits = VFSATTR_BIT(f_create_time), .size = ATTR_TIME_SIZE},
+ {.attr = ATTR_CMN_MODTIME, .bits = VFSATTR_BIT(f_modify_time), .size = ATTR_TIME_SIZE},
+ {.attr = ATTR_CMN_CHGTIME, .bits = VFSATTR_BIT(f_modify_time), .size = ATTR_TIME_SIZE},
+ {.attr = ATTR_CMN_ACCTIME, .bits = VFSATTR_BIT(f_access_time), .size = ATTR_TIME_SIZE},
+ {.attr = ATTR_CMN_BKUPTIME, .bits = VFSATTR_BIT(f_backup_time), .size = ATTR_TIME_SIZE},
+ {.attr = ATTR_CMN_FNDRINFO, .bits = 0, .size = 32},
+ {.attr = ATTR_CMN_OWNERID, .bits = 0, .size = sizeof(uid_t)},
+ {.attr = ATTR_CMN_GRPID, .bits = 0, .size = sizeof(gid_t)},
+ {.attr = ATTR_CMN_ACCESSMASK, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = ATTR_CMN_FLAGS, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = ATTR_CMN_USERACCESS, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = ATTR_CMN_EXTENDED_SECURITY, .bits = 0, .size = sizeof(struct attrreference)},
+ {.attr = ATTR_CMN_UUID, .bits = 0, .size = sizeof(guid_t)},
+ {.attr = ATTR_CMN_GRPUUID, .bits = 0, .size = sizeof(guid_t)},
+ {.attr = ATTR_CMN_FILEID, .bits = 0, .size = sizeof(uint64_t)},
+ {.attr = ATTR_CMN_PARENTID, .bits = 0, .size = sizeof(uint64_t)},
+ {.attr = ATTR_CMN_RETURNED_ATTRS, .bits = 0, .size = sizeof(attribute_set_t)},
+ {.attr = ATTR_CMN_ERROR, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = 0, .bits = 0, .size = 0}
};
#define ATTR_CMN_VOL_INVALID \
(ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \
ATTR_CMN_FILEID | ATTR_CMN_PARENTID)
static struct getvolattrlist_attrtab getvolattrlist_vol_tab[] = {
- {ATTR_VOL_FSTYPE, 0, sizeof(uint32_t)},
- {ATTR_VOL_SIGNATURE, VFSATTR_BIT(f_signature), sizeof(uint32_t)},
- {ATTR_VOL_SIZE, VFSATTR_BIT(f_blocks), sizeof(off_t)},
- {ATTR_VOL_SPACEFREE, VFSATTR_BIT(f_bfree) | VFSATTR_BIT(f_bsize), sizeof(off_t)},
- {ATTR_VOL_SPACEAVAIL, VFSATTR_BIT(f_bavail) | VFSATTR_BIT(f_bsize), sizeof(off_t)},
- {ATTR_VOL_MINALLOCATION, VFSATTR_BIT(f_bsize), sizeof(off_t)},
- {ATTR_VOL_ALLOCATIONCLUMP, VFSATTR_BIT(f_bsize), sizeof(off_t)},
- {ATTR_VOL_IOBLOCKSIZE, VFSATTR_BIT(f_iosize), sizeof(uint32_t)},
- {ATTR_VOL_OBJCOUNT, VFSATTR_BIT(f_objcount), sizeof(uint32_t)},
- {ATTR_VOL_FILECOUNT, VFSATTR_BIT(f_filecount), sizeof(uint32_t)},
- {ATTR_VOL_DIRCOUNT, VFSATTR_BIT(f_dircount), sizeof(uint32_t)},
- {ATTR_VOL_MAXOBJCOUNT, VFSATTR_BIT(f_maxobjcount), sizeof(uint32_t)},
- {ATTR_VOL_MOUNTPOINT, 0, sizeof(struct attrreference)},
- {ATTR_VOL_NAME, VFSATTR_BIT(f_vol_name), sizeof(struct attrreference)},
- {ATTR_VOL_MOUNTFLAGS, 0, sizeof(uint32_t)},
- {ATTR_VOL_MOUNTEDDEVICE, 0, sizeof(struct attrreference)},
- {ATTR_VOL_ENCODINGSUSED, 0, sizeof(uint64_t)},
- {ATTR_VOL_CAPABILITIES, VFSATTR_BIT(f_capabilities), sizeof(vol_capabilities_attr_t)},
- {ATTR_VOL_UUID, VFSATTR_BIT(f_uuid), sizeof(uuid_t)},
- {ATTR_VOL_ATTRIBUTES, VFSATTR_BIT(f_attributes), sizeof(vol_attributes_attr_t)},
- {ATTR_VOL_INFO, 0, 0},
- {0, 0, 0}
+ {.attr = ATTR_VOL_FSTYPE, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_SIGNATURE, .bits = VFSATTR_BIT(f_signature), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_SIZE, .bits = VFSATTR_BIT(f_blocks) | VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_SPACEFREE, .bits = VFSATTR_BIT(f_bfree) | VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_SPACEAVAIL, .bits = VFSATTR_BIT(f_bavail) | VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_MINALLOCATION, .bits = VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_ALLOCATIONCLUMP, .bits = VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_IOBLOCKSIZE, .bits = VFSATTR_BIT(f_iosize), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_OBJCOUNT, .bits = VFSATTR_BIT(f_objcount), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_FILECOUNT, .bits = VFSATTR_BIT(f_filecount), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_DIRCOUNT, .bits = VFSATTR_BIT(f_dircount), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_MAXOBJCOUNT, .bits = VFSATTR_BIT(f_maxobjcount), .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_MOUNTPOINT, .bits = 0, .size = sizeof(struct attrreference)},
+ {.attr = ATTR_VOL_NAME, .bits = VFSATTR_BIT(f_vol_name), .size = sizeof(struct attrreference)},
+ {.attr = ATTR_VOL_MOUNTFLAGS, .bits = 0, .size = sizeof(uint32_t)},
+ {.attr = ATTR_VOL_MOUNTEDDEVICE, .bits = 0, .size = sizeof(struct attrreference)},
+ {.attr = ATTR_VOL_ENCODINGSUSED, .bits = 0, .size = sizeof(uint64_t)},
+ {.attr = ATTR_VOL_CAPABILITIES, .bits = VFSATTR_BIT(f_capabilities), .size = sizeof(vol_capabilities_attr_t)},
+ {.attr = ATTR_VOL_UUID, .bits = VFSATTR_BIT(f_uuid), .size = sizeof(uuid_t)},
+ {.attr = ATTR_VOL_QUOTA_SIZE, .bits = VFSATTR_BIT(f_quota) | VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_RESERVED_SIZE, .bits = VFSATTR_BIT(f_reserved) | VFSATTR_BIT(f_bsize), .size = sizeof(off_t)},
+ {.attr = ATTR_VOL_ATTRIBUTES, .bits = VFSATTR_BIT(f_attributes), .size = sizeof(vol_attributes_attr_t)},
+ {.attr = ATTR_VOL_INFO, .bits = 0, .size = 0},
+ {.attr = 0, .bits = 0, .size = 0}
};
static int
getvolattrlist_parsetab(struct getvolattrlist_attrtab *tab, attrgroup_t attrs, struct vfs_attr *vsp,
- ssize_t *sizep, int is_64bit)
+ ssize_t *sizep, int is_64bit, unsigned int maxiter)
{
- attrgroup_t recognised;
+ attrgroup_t recognised;
recognised = 0;
do {
*sizep += tab->size;
}
}
- } while ((++tab)->attr != 0);
-
+ } while (((++tab)->attr != 0) && (--maxiter > 0));
+
/* check to make sure that we recognised all of the passed-in attributes */
- if (attrs & ~recognised)
- return(EINVAL);
- return(0);
+ if (attrs & ~recognised) {
+ return EINVAL;
+ }
+ return 0;
}
/*
static int
getvolattrlist_setupvfsattr(struct attrlist *alp, struct vfs_attr *vsp, ssize_t *sizep, int is_64bit)
{
- int error;
+ int error;
+ if (!alp) {
+ return EINVAL;
+ }
/*
* Parse the above tables.
*/
- *sizep = sizeof(uint32_t); /* length count */
+ *sizep = sizeof(uint32_t); /* length count */
if (alp->commonattr) {
if ((alp->commonattr & ATTR_CMN_VOL_INVALID) &&
(alp->commonattr & ATTR_CMN_RETURNED_ATTRS) == 0) {
- return (EINVAL);
+ return EINVAL;
}
if ((error = getvolattrlist_parsetab(getvolattrlist_common_tab,
- alp->commonattr, vsp, sizep,
- is_64bit)) != 0) {
- return(error);
+ alp->commonattr, vsp, sizep,
+ is_64bit,
+ sizeof(getvolattrlist_common_tab) / sizeof(getvolattrlist_common_tab[0]))) != 0) {
+ return error;
}
}
if (alp->volattr &&
- (error = getvolattrlist_parsetab(getvolattrlist_vol_tab, alp->volattr, vsp, sizep, is_64bit)) != 0)
- return(error);
+ (error = getvolattrlist_parsetab(getvolattrlist_vol_tab, alp->volattr, vsp, sizep, is_64bit, sizeof(getvolattrlist_vol_tab) / sizeof(getvolattrlist_vol_tab[0]))) != 0) {
+ return error;
+ }
- return(0);
+ return 0;
}
/*
* Table-driven setup for all valid common/dir/file/fork attributes against files.
*/
struct getattrlist_attrtab {
- attrgroup_t attr;
- uint64_t bits;
-#define VATTR_BIT(b) (VNODE_ATTR_ ## b)
- ssize_t size;
- kauth_action_t action;
+ attrgroup_t attr;
+ uint64_t bits;
+#define VATTR_BIT(b) (VNODE_ATTR_ ## b)
+ ssize_t size;
+ kauth_action_t action;
};
-/*
- * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this
+/*
+ * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this
* information, and we will synthesize it at the VFS level.
*/
static struct getattrlist_attrtab getattrlist_common_tab[] = {
- {ATTR_CMN_NAME, VATTR_BIT(va_name), sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_DEVID, 0, sizeof(dev_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FSID, 0, sizeof(fsid_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJTYPE, 0, sizeof(fsobj_type_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJTAG, 0, sizeof(fsobj_tag_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJPERMANENTID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_PAROBJID, VATTR_BIT(va_parentid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_SCRIPT, VATTR_BIT(va_encoding), sizeof(text_encoding_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_CRTIME, VATTR_BIT(va_create_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_MODTIME, VATTR_BIT(va_modify_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_CHGTIME, VATTR_BIT(va_change_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_ACCTIME, VATTR_BIT(va_access_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_BKUPTIME, VATTR_BIT(va_backup_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FNDRINFO, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OWNERID, VATTR_BIT(va_uid), sizeof(uid_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_GRPID, VATTR_BIT(va_gid), sizeof(gid_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_ACCESSMASK, VATTR_BIT(va_mode), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FLAGS, VATTR_BIT(va_flags), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_GEN_COUNT, VATTR_BIT(va_write_gencount), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_DOCUMENT_ID, VATTR_BIT(va_document_id), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_USERACCESS, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_EXTENDED_SECURITY, VATTR_BIT(va_acl), sizeof(struct attrreference), KAUTH_VNODE_READ_SECURITY},
- {ATTR_CMN_UUID, VATTR_BIT(va_uuuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_GRPUUID, VATTR_BIT(va_guuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FILEID, VATTR_BIT(va_fileid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_PARENTID, VATTR_BIT(va_parentid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FULLPATH, 0, sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_ADDEDTIME, VATTR_BIT(va_addedtime), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_RETURNED_ATTRS, 0, sizeof(attribute_set_t), 0},
- {ATTR_CMN_ERROR, 0, sizeof(uint32_t), 0},
- {ATTR_CMN_DATA_PROTECT_FLAGS, VATTR_BIT(va_dataprotect_class), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {0, 0, 0, 0}
+ {.attr = ATTR_CMN_NAME, .bits = VATTR_BIT(va_name), .size = sizeof(struct attrreference), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_DEVID, .bits = VATTR_BIT(va_fsid), .size = sizeof(dev_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FSID, .bits = VATTR_BIT(va_fsid64), .size = sizeof(fsid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJTYPE, .bits = 0, .size = sizeof(fsobj_type_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJTAG, .bits = 0, .size = sizeof(fsobj_tag_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJID, .bits = VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), .size = sizeof(fsobj_id_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJPERMANENTID, .bits = VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), .size = sizeof(fsobj_id_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_PAROBJID, .bits = VATTR_BIT(va_parentid), .size = sizeof(fsobj_id_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_SCRIPT, .bits = VATTR_BIT(va_encoding), .size = sizeof(text_encoding_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_CRTIME, .bits = VATTR_BIT(va_create_time), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_MODTIME, .bits = VATTR_BIT(va_modify_time), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_CHGTIME, .bits = VATTR_BIT(va_change_time), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_ACCTIME, .bits = VATTR_BIT(va_access_time), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_BKUPTIME, .bits = VATTR_BIT(va_backup_time), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FNDRINFO, .bits = 0, .size = 32, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OWNERID, .bits = VATTR_BIT(va_uid), .size = sizeof(uid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_GRPID, .bits = VATTR_BIT(va_gid), .size = sizeof(gid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_ACCESSMASK, .bits = VATTR_BIT(va_mode), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FLAGS, .bits = VATTR_BIT(va_flags), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_GEN_COUNT, .bits = VATTR_BIT(va_write_gencount), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_DOCUMENT_ID, .bits = VATTR_BIT(va_document_id), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_USERACCESS, .bits = 0, .size = sizeof(uint32_t), .action = 0},
+ {.attr = ATTR_CMN_EXTENDED_SECURITY, .bits = VATTR_BIT(va_acl), .size = sizeof(struct attrreference), .action = KAUTH_VNODE_READ_SECURITY},
+ {.attr = ATTR_CMN_UUID, .bits = VATTR_BIT(va_uuuid), .size = sizeof(guid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_GRPUUID, .bits = VATTR_BIT(va_guuid), .size = sizeof(guid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FILEID, .bits = VATTR_BIT(va_fileid), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_PARENTID, .bits = VATTR_BIT(va_parentid), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FULLPATH, .bits = 0, .size = sizeof(struct attrreference), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_ADDEDTIME, .bits = VATTR_BIT(va_addedtime), .size = ATTR_TIME_SIZE, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_RETURNED_ATTRS, .bits = 0, .size = sizeof(attribute_set_t), .action = 0},
+ {.attr = ATTR_CMN_ERROR, .bits = 0, .size = sizeof(uint32_t), .action = 0},
+ {.attr = ATTR_CMN_DATA_PROTECT_FLAGS, .bits = VATTR_BIT(va_dataprotect_class), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
};
static struct getattrlist_attrtab getattrlist_dir_tab[] = {
- {ATTR_DIR_LINKCOUNT, VATTR_BIT(va_dirlinkcount), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_DIR_ENTRYCOUNT, VATTR_BIT(va_nchildren), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_DIR_MOUNTSTATUS, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {0, 0, 0, 0}
+ {.attr = ATTR_DIR_LINKCOUNT, .bits = VATTR_BIT(va_dirlinkcount), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_DIR_ENTRYCOUNT, .bits = VATTR_BIT(va_nchildren), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_DIR_MOUNTSTATUS, .bits = 0, .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_DIR_ALLOCSIZE, .bits = VATTR_BIT(va_total_alloc) | VATTR_BIT(va_total_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_DIR_IOBLOCKSIZE, .bits = VATTR_BIT(va_iosize), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_DIR_DATALENGTH, .bits = VATTR_BIT(va_total_size) | VATTR_BIT(va_data_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
};
static struct getattrlist_attrtab getattrlist_file_tab[] = {
- {ATTR_FILE_LINKCOUNT, VATTR_BIT(va_nlink), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_TOTALSIZE, VATTR_BIT(va_total_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_ALLOCSIZE, VATTR_BIT(va_total_alloc) | VATTR_BIT(va_total_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_IOBLOCKSIZE, VATTR_BIT(va_iosize), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_DEVTYPE, VATTR_BIT(va_rdev), sizeof(dev_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_DATALENGTH, VATTR_BIT(va_total_size) | VATTR_BIT(va_data_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_DATAALLOCSIZE, VATTR_BIT(va_total_alloc)| VATTR_BIT(va_data_alloc), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_RSRCLENGTH, 0, sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_RSRCALLOCSIZE, 0, sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
- {0, 0, 0, 0}
-};
+ {.attr = ATTR_FILE_LINKCOUNT, .bits = VATTR_BIT(va_nlink), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_TOTALSIZE, .bits = VATTR_BIT(va_total_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_ALLOCSIZE, .bits = VATTR_BIT(va_total_alloc) | VATTR_BIT(va_total_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_IOBLOCKSIZE, .bits = VATTR_BIT(va_iosize), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_CLUMPSIZE, .bits = 0, .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_DEVTYPE, .bits = VATTR_BIT(va_rdev), .size = sizeof(dev_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_DATALENGTH, .bits = VATTR_BIT(va_total_size) | VATTR_BIT(va_data_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_DATAALLOCSIZE, .bits = VATTR_BIT(va_total_alloc) | VATTR_BIT(va_data_alloc), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_RSRCLENGTH, .bits = 0, .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_RSRCALLOCSIZE, .bits = 0, .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
+};
+
+//for forkattr bits repurposed as new common attributes
+static struct getattrlist_attrtab getattrlist_common_extended_tab[] = {
+ {.attr = ATTR_CMNEXT_RELPATH, .bits = 0, .size = sizeof(struct attrreference), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_PRIVATESIZE, .bits = VATTR_BIT(va_private_size), .size = sizeof(off_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_LINKID, .bits = VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_NOFIRMLINKPATH, .bits = 0, .size = sizeof(struct attrreference), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_REALDEVID, .bits = VATTR_BIT(va_devid), .size = sizeof(uint32_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_REALFSID, .bits = VATTR_BIT(va_fsid64), .size = sizeof(fsid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_CLONEID, .bits = VATTR_BIT(va_clone_id), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_EXT_FLAGS, .bits = VATTR_BIT(va_extflags), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMNEXT_RECURSIVE_GENCOUNT, .bits = VATTR_BIT(va_recursive_gencount), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
+};
/*
* This table is for attributes which are only set from the getattrlistbulk(2)
* accounted from the common, file and directory tables.
*/
static struct getattrlist_attrtab getattrlistbulk_common_tab[] = {
- {ATTR_CMN_DEVID, VATTR_BIT(va_devid), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FSID, VATTR_BIT(va_fsid64), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJTYPE, VATTR_BIT(va_objtype), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_OBJTAG, VATTR_BIT(va_objtag), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_USERACCESS, VATTR_BIT(va_user_access), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_CMN_FNDRINFO, VATTR_BIT(va_finderinfo), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {0, 0, 0, 0}
+ {.attr = ATTR_CMN_DEVID, .bits = VATTR_BIT(va_devid), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_FSID, .bits = VATTR_BIT(va_fsid64), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJTYPE, .bits = VATTR_BIT(va_objtype), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_OBJTAG, .bits = VATTR_BIT(va_objtag), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_CMN_USERACCESS, .bits = VATTR_BIT(va_user_access), .size = 0, .action = 0},
+ {.attr = ATTR_CMN_FNDRINFO, .bits = VATTR_BIT(va_finderinfo), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
};
static struct getattrlist_attrtab getattrlistbulk_file_tab[] = {
- {ATTR_FILE_RSRCLENGTH, VATTR_BIT(va_rsrc_length), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {ATTR_FILE_RSRCALLOCSIZE, VATTR_BIT(va_rsrc_alloc), 0, KAUTH_VNODE_READ_ATTRIBUTES},
- {0, 0, 0, 0}
+ {.attr = ATTR_FILE_RSRCLENGTH, .bits = VATTR_BIT(va_rsrc_length), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = ATTR_FILE_RSRCALLOCSIZE, .bits = VATTR_BIT(va_rsrc_alloc), .size = 0, .action = KAUTH_VNODE_READ_ATTRIBUTES},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
+};
+
+static struct getattrlist_attrtab getattrlistbulk_common_extended_tab[] = {
+ /* getattrlist_parsetab() expects > 1 entries */
+ {.attr = 0, .bits = 0, .size = 0, .action = 0},
+ {.attr = 0, .bits = 0, .size = 0, .action = 0}
};
/*
*
* A majority of them are the same attributes that are required for stat(2) and statfs(2).
*/
-#define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
- ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
- ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
- ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
- ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
- ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
- ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
-
-#define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
- ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
- ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
- ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
- ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
- ATTR_CMN_FNDRINFO | \
- ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
- ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
- ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
- ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS | \
- ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT | \
- ATTR_CMN_DATA_PROTECT_FLAGS)
-
-#define VFS_DFLT_ATT_CMN_EXT (ATTR_CMN_EXT_GEN_COUNT | ATTR_CMN_EXT_DOCUMENT_ID |\
- ATTR_CMN_EXT_DATA_PROTECT_FLAGS)
-
-#define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
-
-#define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
- ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
- ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
- ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
- ATTR_FILE_RSRCALLOCSIZE)
+#define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \
+ ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | ATTR_VOL_QUOTA_SIZE | ATTR_VOL_RESERVED_SIZE | \
+ ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
+ ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
+ ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \
+ ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \
+ ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED)
+
+#define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \
+ ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
+ ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \
+ ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \
+ ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
+ ATTR_CMN_FNDRINFO | \
+ ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \
+ ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \
+ ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \
+ ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS | \
+ ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT | \
+ ATTR_CMN_DATA_PROTECT_FLAGS)
+
+#define VFS_DFLT_ATTR_CMN_EXT (ATTR_CMNEXT_PRIVATESIZE | ATTR_CMNEXT_LINKID | \
+ ATTR_CMNEXT_NOFIRMLINKPATH | ATTR_CMNEXT_REALDEVID | \
+ ATTR_CMNEXT_REALFSID | ATTR_CMNEXT_CLONEID | \
+ ATTR_CMNEXT_EXT_FLAGS)
+
+#define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
+
+#define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \
+ ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
+ ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \
+ ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \
+ ATTR_FILE_RSRCALLOCSIZE)
static int
getattrlist_parsetab(struct getattrlist_attrtab *tab, attrgroup_t attrs,
struct vnode_attr *vap, ssize_t *sizep, kauth_action_t *actionp,
- int is_64bit)
+ int is_64bit, unsigned int maxiter)
{
- attrgroup_t recognised;
-
+ attrgroup_t recognised;
recognised = 0;
+ if (!tab) {
+ return EINVAL;
+ }
+
do {
/* is this attribute set? */
if (tab->attr & attrs) {
recognised |= tab->attr;
- if (vap)
+ if (vap) {
vap->va_active |= tab->bits;
+ }
if (sizep) {
if (tab->size == ATTR_TIME_SIZE) {
if (is_64bit) {
*sizep += sizeof(
- struct user64_timespec);
+ struct user64_timespec);
} else {
*sizep += sizeof(
- struct user32_timespec);
+ struct user32_timespec);
}
} else {
*sizep += tab->size;
}
}
- if (actionp)
+ if (actionp) {
*actionp |= tab->action;
- if (attrs == recognised)
+ }
+ if (attrs == recognised) {
break; /* all done, get out */
+ }
}
- } while ((++tab)->attr != 0);
-
+ } while (((++tab)->attr != 0) && (--maxiter > 0));
+
/* check to make sure that we recognised all of the passed-in attributes */
- if (attrs & ~recognised)
- return(EINVAL);
- return(0);
+ if (attrs & ~recognised) {
+ return EINVAL;
+ }
+ return 0;
}
/*
* the data from a filesystem.
*/
static int
-getattrlist_setupvattr(struct attrlist *alp, struct vnode_attr *vap, ssize_t *sizep, kauth_action_t *actionp, int is_64bit, int isdir)
+getattrlist_setupvattr(struct attrlist *alp, struct vnode_attr *vap, ssize_t *sizep, kauth_action_t *actionp, int is_64bit, int isdir, int use_fork)
{
- int error;
+ int error;
/*
* Parse the above tables.
*/
- *sizep = sizeof(uint32_t); /* length count */
+ *sizep = sizeof(uint32_t); /* length count */
*actionp = 0;
if (alp->commonattr &&
- (error = getattrlist_parsetab(getattrlist_common_tab, alp->commonattr, vap, sizep, actionp, is_64bit)) != 0)
- return(error);
+ (error = getattrlist_parsetab(getattrlist_common_tab, alp->commonattr, vap, sizep, actionp, is_64bit, sizeof(getattrlist_common_tab) / sizeof(getattrlist_common_tab[0]))) != 0) {
+ return error;
+ }
if (isdir && alp->dirattr &&
- (error = getattrlist_parsetab(getattrlist_dir_tab, alp->dirattr, vap, sizep, actionp, is_64bit)) != 0)
- return(error);
+ (error = getattrlist_parsetab(getattrlist_dir_tab, alp->dirattr, vap, sizep, actionp, is_64bit, sizeof(getattrlist_dir_tab) / sizeof(getattrlist_dir_tab[0]))) != 0) {
+ return error;
+ }
if (!isdir && alp->fileattr &&
- (error = getattrlist_parsetab(getattrlist_file_tab, alp->fileattr, vap, sizep, actionp, is_64bit)) != 0)
- return(error);
+ (error = getattrlist_parsetab(getattrlist_file_tab, alp->fileattr, vap, sizep, actionp, is_64bit, sizeof(getattrlist_file_tab) / sizeof(getattrlist_file_tab[0]))) != 0) {
+ return error;
+ }
+ if (use_fork && alp->forkattr &&
+ (error = getattrlist_parsetab(getattrlist_common_extended_tab, alp->forkattr, vap, sizep, actionp, is_64bit, sizeof(getattrlist_common_extended_tab) / sizeof(getattrlist_common_extended_tab[0]))) != 0) {
+ return error;
+ }
- return(0);
+ return 0;
}
/*
*/
static int
getattrlist_setupvattr_all(struct attrlist *alp, struct vnode_attr *vap,
- enum vtype obj_type, ssize_t *fixedsize, int is_64bit)
+ enum vtype obj_type, ssize_t *fixedsize, int is_64bit, int use_fork)
{
- int error = 0;
+ int error = 0;
/*
* Parse the above tables.
}
if (alp->commonattr) {
error = getattrlist_parsetab(getattrlist_common_tab,
- alp->commonattr, vap, fixedsize, NULL, is_64bit);
+ alp->commonattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlist_common_tab) / sizeof(getattrlist_common_tab[0]));
if (!error) {
/* Ignore any errrors from the bulk table */
(void)getattrlist_parsetab(getattrlistbulk_common_tab,
- alp->commonattr, vap, fixedsize, NULL, is_64bit);
- /*
- * turn off va_fsid since we will be using only
- * va_fsid64 for ATTR_CMN_FSID.
- */
- VATTR_CLEAR_ACTIVE(vap, va_fsid);
+ alp->commonattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlistbulk_common_tab) / sizeof(getattrlistbulk_common_tab[0]));
}
}
if (!error && (obj_type == VNON || obj_type == VDIR) && alp->dirattr) {
error = getattrlist_parsetab(getattrlist_dir_tab, alp->dirattr,
- vap, fixedsize, NULL, is_64bit);
+ vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlist_dir_tab) / sizeof(getattrlist_dir_tab[0]));
}
if (!error && (obj_type != VDIR) && alp->fileattr) {
error = getattrlist_parsetab(getattrlist_file_tab,
- alp->fileattr, vap, fixedsize, NULL, is_64bit);
+ alp->fileattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlist_file_tab) / sizeof(getattrlist_file_tab[0]));
if (!error) {
/*Ignore any errors from the bulk table */
(void)getattrlist_parsetab(getattrlistbulk_file_tab,
- alp->fileattr, vap, fixedsize, NULL, is_64bit);
+ alp->fileattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlistbulk_file_tab) / sizeof(getattrlistbulk_file_tab[0]));
}
}
- return (error);
+ /* fork attributes are like extended common attributes if enabled*/
+ if (!error && use_fork && alp->forkattr) {
+ error = getattrlist_parsetab(getattrlist_common_extended_tab,
+ alp->forkattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlist_common_extended_tab) / sizeof(getattrlist_common_extended_tab[0]));
+
+ if (!error) {
+ (void)getattrlist_parsetab(getattrlistbulk_common_extended_tab,
+ alp->forkattr, vap, fixedsize, NULL, is_64bit,
+ sizeof(getattrlistbulk_common_extended_tab) / sizeof(getattrlistbulk_common_extended_tab[0]));
+ }
+ }
+
+ return error;
}
int
vfs_setup_vattr_from_attrlist(struct attrlist *alp, struct vnode_attr *vap,
enum vtype obj_vtype, ssize_t *attrs_fixed_sizep, vfs_context_t ctx)
{
- return (getattrlist_setupvattr_all(alp, vap, obj_vtype,
- attrs_fixed_sizep, IS_64BIT_PROCESS(vfs_context_proc(ctx))));
+ VATTR_INIT(vap);
+
+ // the caller passes us no options, we assume the caller wants the new fork
+ // attr behavior, hence the hardcoded 1
+ return getattrlist_setupvattr_all(alp, vap, obj_vtype,
+ attrs_fixed_sizep, IS_64BIT_PROCESS(vfs_context_proc(ctx)), 1);
}
* missing attributes from the file system
*/
static void
-getattrlist_fixupattrs(attribute_set_t *asp, struct vnode_attr *vap)
+getattrlist_fixupattrs(attribute_set_t *asp, struct vnode_attr *vap, int use_fork)
{
struct getattrlist_attrtab *tab;
if (asp->commonattr) {
tab = getattrlist_common_tab;
do {
- /*
+ /*
* This if() statement is slightly confusing. We're trying to
- * iterate through all of the bits listed in the array
+ * iterate through all of the bits listed in the array
* getattr_common_tab, and see if the filesystem was expected
* to support it, and whether or not we need to do anything about this.
- *
+ *
* This array is full of structs that have 4 fields (attr, bits, size, action).
- * The first is used to store the ATTR_CMN_* bit that was being requested
+ * The first is used to store the ATTR_CMN_* bit that was being requested
* from userland. The second stores the VATTR_BIT corresponding to the field
* filled in vnode_attr struct. If it is 0, then we don't typically expect
* the filesystem to fill in this field. The third is the size of the field,
* and the fourth is the type of kauth actions needed.
*
- * So, for all of the ATTR_CMN bits listed in this array, we iterate through
+ * So, for all of the ATTR_CMN bits listed in this array, we iterate through
* them, and check to see if it was both passed down to the filesystem via the
* va_active bitfield, and whether or not we expect it to be emitted from
* the filesystem. If it wasn't supported, then we un-twiddle the bit and move
}
} while ((++tab)->attr != 0);
}
+ if (use_fork && asp->forkattr) {
+ tab = getattrlist_common_extended_tab;
+ do {
+ if ((tab->attr & asp->forkattr) &&
+ (tab->bits & vap->va_active) &&
+ (vap->va_supported & tab->bits) == 0) {
+ asp->forkattr &= ~tab->attr;
+ }
+ } while ((++tab)->attr != 0);
+ }
}
static int
setattrlist_setfinderinfo(vnode_t vp, char *fndrinfo, struct vfs_context *ctx)
{
- uio_t auio;
- char uio_buf[UIO_SIZEOF(1)];
- int error;
+ uio_t auio;
+ char uio_buf[UIO_SIZEOF(1)];
+ int error;
if ((auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_WRITE, uio_buf, sizeof(uio_buf))) == NULL) {
error = ENOMEM;
#if CONFIG_FSE
if (error == 0 && need_fsevent(FSE_FINDER_INFO_CHANGED, vp)) {
- add_fsevent(FSE_FINDER_INFO_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
+ add_fsevent(FSE_FINDER_INFO_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
}
#endif
- return (error);
+ return error;
}
static void
getattrlist_findnamecomp(const char *mn, const char **np, ssize_t *nl)
{
- int counting;
- const char *cp;
+ int counting;
+ const char *cp;
/*
* We're looking for the last sequence of non / characters, but
}
}
/* need to close run? */
- if (counting)
+ if (counting) {
*nl = cp - *np;
+ }
}
static int
getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp,
- user_addr_t attributeBuffer, size_t bufferSize, uint64_t options,
- enum uio_seg segflg, int is_64bit)
+ user_addr_t attributeBuffer, size_t bufferSize, uint64_t options,
+ enum uio_seg segflg, int is_64bit)
{
struct vfs_attr vs;
struct vnode_attr va;
struct _attrlist_buf ab;
- int error;
- ssize_t fixedsize, varsize;
- const char *cnp = NULL; /* protected by ATTR_CMN_NAME */
- ssize_t cnl = 0; /* protected by ATTR_CMN_NAME */
- int release_str = 0;
- mount_t mnt;
- int return_valid;
- int pack_invalid;
+ int error;
+ ssize_t fixedsize, varsize;
+ const char *cnp = NULL; /* protected by ATTR_CMN_NAME */
+ ssize_t cnl = 0; /* protected by ATTR_CMN_NAME */
+ int release_str = 0;
+ mount_t mnt;
+ int return_valid;
+ int pack_invalid;
+ vnode_t root_vp = NULL;
ab.base = NULL;
VATTR_INIT(&va);
vs.f_vol_name = NULL;
mnt = vp->v_mount;
-
+
/* Check for special packing semantics */
return_valid = (alp->commonattr & ATTR_CMN_RETURNED_ATTRS);
pack_invalid = (options & FSOPT_PACK_INVAL_ATTRS);
goto out;
}
/* Keep invalid attrs from being uninitialized */
- bzero(&vs, sizeof (vs));
+ bzero(&vs, sizeof(vs));
/* Generate a valid mask for post processing */
- bcopy(&alp->commonattr, &ab.valid, sizeof (attribute_set_t));
+ bcopy(&alp->commonattr, &ab.valid, sizeof(attribute_set_t));
}
- /*
- * For now, the vnode must be the root of its filesystem.
- * To relax this, we need to be able to find the root vnode of a filesystem
- * from any vnode in the filesystem.
- */
+ /* If we do not have root vnode, look it up and substitute it in */
if (!vnode_isvroot(vp)) {
- error = EINVAL;
- VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem");
- goto out;
+ if (mnt != NULL) {
+ error = VFS_ROOT(mnt, &root_vp, ctx);
+ if (error) {
+ VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: volume attributes requested on non-root vnode, but got an error getting root.");
+ goto out;
+ }
+ vp = root_vp;
+ } else {
+ error = EINVAL;
+ VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: volume attributes requested on non-root vnode, but no backpointer to mount.");
+ goto out;
+ }
}
/*
if (vs.f_active != 0) {
/* If we're going to ask for f_vol_name, allocate a buffer to point it at */
if (VFSATTR_IS_ACTIVE(&vs, f_vol_name)) {
- vs.f_vol_name = (char *) kalloc(MAXPATHLEN);
- if (vs.f_vol_name == NULL) {
- error = ENOMEM;
- VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate f_vol_name buffer");
- goto out;
- }
+ vs.f_vol_name = (char *) zalloc(ZV_NAMEI);
+ vs.f_vol_name[0] = '\0';
}
VFS_DEBUG(ctx, vp, "ATTRLIST - calling to get %016llx with supported %016llx", vs.f_active, vs.f_supported);
if (!VFSATTR_ALL_SUPPORTED(&vs)) {
/* default value for volume subtype */
if (VFSATTR_IS_ACTIVE(&vs, f_fssubtype)
- && !VFSATTR_IS_SUPPORTED(&vs, f_fssubtype))
+ && !VFSATTR_IS_SUPPORTED(&vs, f_fssubtype)) {
VFSATTR_RETURN(&vs, f_fssubtype, 0);
+ }
/*
* If the file system didn't supply f_signature, then
* that most Carbon file systems should return.
*/
if (VFSATTR_IS_ACTIVE(&vs, f_signature)
- && !VFSATTR_IS_SUPPORTED(&vs, f_signature))
+ && !VFSATTR_IS_SUPPORTED(&vs, f_signature)) {
VFSATTR_RETURN(&vs, f_signature, 0x4244);
+ }
/* default for block size */
if (VFSATTR_IS_ACTIVE(&vs, f_bsize)
- && !VFSATTR_IS_SUPPORTED(&vs, f_bsize))
+ && !VFSATTR_IS_SUPPORTED(&vs, f_bsize)) {
VFSATTR_RETURN(&vs, f_bsize, mnt->mnt_devblocksize);
+ }
/* default value for volume f_attributes */
if (VFSATTR_IS_ACTIVE(&vs, f_attributes)
&& !VFSATTR_IS_SUPPORTED(&vs, f_attributes)) {
vol_attributes_attr_t *attrp = &vs.f_attributes;
-
+
attrp->validattr.commonattr = VFS_DFLT_ATTR_CMN;
attrp->validattr.volattr = VFS_DFLT_ATTR_VOL;
attrp->validattr.dirattr = VFS_DFLT_ATTR_DIR;
attrp->validattr.fileattr = VFS_DFLT_ATTR_FILE;
- attrp->validattr.forkattr = 0;
-
+ attrp->validattr.forkattr = VFS_DFLT_ATTR_CMN_EXT;
+
attrp->nativeattr.commonattr = 0;
attrp->nativeattr.volattr = 0;
attrp->nativeattr.dirattr = 0;
vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_ATTRLIST;
vs.f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
vs.f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
-
+
vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] = 0;
vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_ATTRLIST;
vs.f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
vs.f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
VFSATTR_SET_SUPPORTED(&vs, f_capabilities);
- }
- else {
+ } else {
/* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */
vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_ATTRLIST;
vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_ATTRLIST;
if (pack_invalid) {
/* Fix up valid mask for post processing */
getvolattrlist_fixupattrs(&ab.valid, &vs);
-
+
/* Force packing of everything asked for */
vs.f_supported = vs.f_active;
} else {
#endif
if (VATTR_IS_ACTIVE(&va, va_encoding) &&
!VATTR_IS_SUPPORTED(&va, va_encoding)) {
- if (!return_valid || pack_invalid)
+ if (!return_valid || pack_invalid) {
/* use kTextEncodingMacUnicode */
VATTR_RETURN(&va, va_encoding, 0x7e);
- else
+ } else {
/* don't use a default */
alp->commonattr &= ~ATTR_CMN_SCRIPT;
+ }
}
}
varsize = 0;
if (alp->commonattr & ATTR_CMN_NAME) {
if (vp->v_mount->mnt_vfsstat.f_mntonname[1] == 0x00 &&
- vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') {
+ vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') {
/* special case for boot volume. Use root name when it's
* available (which is the volume name) or just the mount on
* name of "/". we must do this for binary compatibility with
if (cnp == NULL) {
/* just use "/" as name */
cnp = &vp->v_mount->mnt_vfsstat.f_mntonname[0];
- }
- else {
+ } else {
release_str = 1;
}
cnl = strlen(cnp);
- }
- else {
+ } else {
getattrlist_findnamecomp(vp->v_mount->mnt_vfsstat.f_mntonname, &cnp, &cnl);
}
- if (alp->commonattr & ATTR_CMN_NAME)
+ if (alp->commonattr & ATTR_CMN_NAME) {
varsize += roundup(cnl + 1, 4);
+ }
}
- if (alp->volattr & ATTR_VOL_MOUNTPOINT)
+ if (alp->volattr & ATTR_VOL_MOUNTPOINT) {
varsize += roundup(strlen(mnt->mnt_vfsstat.f_mntonname) + 1, 4);
+ }
if (alp->volattr & ATTR_VOL_NAME) {
- vs.f_vol_name[MAXPATHLEN-1] = '\0'; /* Ensure nul-termination */
+ vs.f_vol_name[MAXPATHLEN - 1] = '\0'; /* Ensure nul-termination */
varsize += roundup(strlen(vs.f_vol_name) + 1, 4);
}
- if (alp->volattr & ATTR_VOL_MOUNTEDDEVICE)
+ if (alp->volattr & ATTR_VOL_MOUNTEDDEVICE) {
varsize += roundup(strlen(mnt->mnt_vfsstat.f_mntfromname) + 1, 4);
+ }
/*
* Allocate a target buffer for attribute results.
* Note that since we won't ever copy out more than the caller requested,
* we never need to allocate more than they offer.
*/
- ab.allocated = ulmin(bufferSize, fixedsize + varsize);
- if (ab.allocated > ATTR_MAX_BUFFER) {
+ ab.allocated = fixedsize + varsize;
+ if (((size_t)ab.allocated) > ATTR_MAX_BUFFER) {
error = ENOMEM;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER);
goto out;
}
- MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_ZERO | M_WAITOK);
+
+ if (return_valid &&
+ (ab.allocated < (ssize_t)(sizeof(uint32_t) + sizeof(attribute_set_t))) &&
+ !(options & FSOPT_REPORT_FULLSIZE)) {
+ uint32_t num_bytes_valid = sizeof(uint32_t);
+ /*
+ * Not enough to return anything and we don't have to report
+ * how much space is needed. Get out now.
+ * N.B. - We have only been called after having verified that
+ * attributeBuffer is at least sizeof(uint32_t);
+ */
+ if (UIO_SEG_IS_USER_SPACE(segflg)) {
+ error = copyout(&num_bytes_valid,
+ CAST_USER_ADDR_T(attributeBuffer), num_bytes_valid);
+ } else {
+ bcopy(&num_bytes_valid, (void *)attributeBuffer,
+ (size_t)num_bytes_valid);
+ }
+ goto out;
+ }
+
+ ab.base = kheap_alloc(KHEAP_TEMP, ab.allocated, Z_ZERO | Z_WAITOK);
if (ab.base == NULL) {
error = ENOMEM;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab.allocated);
*/
ab.fixedcursor = ab.base + sizeof(uint32_t);
if (return_valid) {
- ab.fixedcursor += sizeof (attribute_set_t);
- bzero(&ab.actual, sizeof (ab.actual));
+ ab.fixedcursor += sizeof(attribute_set_t);
+ bzero(&ab.actual, sizeof(ab.actual));
}
ab.varcursor = ab.base + fixedsize;
ab.needed = fixedsize + varsize;
/* common attributes **************************************************/
+ if (alp->commonattr & ATTR_CMN_ERROR) {
+ ATTR_PACK4(ab, 0);
+ ab.actual.commonattr |= ATTR_CMN_ERROR;
+ }
if (alp->commonattr & ATTR_CMN_NAME) {
attrlist_pack_string(&ab, cnp, cnl);
ab.actual.commonattr |= ATTR_CMN_NAME;
ab.actual.commonattr |= ATTR_CMN_FSID;
}
if (alp->commonattr & ATTR_CMN_OBJTYPE) {
- if (!return_valid || pack_invalid)
+ if (!return_valid || pack_invalid) {
ATTR_PACK4(ab, 0);
+ }
}
if (alp->commonattr & ATTR_CMN_OBJTAG) {
ATTR_PACK4(ab, vp->v_tag);
ab.actual.commonattr |= ATTR_CMN_MODTIME;
}
if (alp->commonattr & ATTR_CMN_CHGTIME) {
- if (!return_valid || pack_invalid)
+ if (!return_valid || pack_invalid) {
ATTR_PACK_TIME(ab, vs.f_modify_time, is_64bit);
+ }
}
if (alp->commonattr & ATTR_CMN_ACCTIME) {
ATTR_PACK_TIME(ab, vs.f_access_time, is_64bit);
ATTR_PACK4(ab, va.va_flags);
ab.actual.commonattr |= ATTR_CMN_FLAGS;
}
- if (alp->commonattr & ATTR_CMN_USERACCESS) { /* XXX this is expensive and also duplicate work */
- uint32_t perms = 0;
+ if (alp->commonattr & ATTR_CMN_USERACCESS) { /* XXX this is expensive and also duplicate work */
+ uint32_t perms = 0;
if (vnode_isdir(vp)) {
if (vnode_authorize(vp, NULL,
- KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD, ctx) == 0)
+ KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD, ctx) == 0) {
perms |= W_OK;
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0)
+ }
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0) {
perms |= R_OK;
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_SEARCH, ctx) == 0)
+ }
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_SEARCH, ctx) == 0) {
perms |= X_OK;
+ }
} else {
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA, ctx) == 0)
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA, ctx) == 0) {
perms |= W_OK;
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0)
+ }
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0) {
perms |= R_OK;
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0)
+ }
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0) {
perms |= X_OK;
+ }
}
#if CONFIG_MACF
- /*
+ /*
* Rather than MAC preceding DAC, in this case we want
* the smallest set of permissions granted by both MAC & DAC
* checks. We won't add back any permissions.
*/
- if (perms & W_OK)
- if (mac_vnode_check_access(ctx, vp, W_OK) != 0)
+ if (perms & W_OK) {
+ if (mac_vnode_check_access(ctx, vp, W_OK) != 0) {
perms &= ~W_OK;
- if (perms & R_OK)
- if (mac_vnode_check_access(ctx, vp, R_OK) != 0)
+ }
+ }
+ if (perms & R_OK) {
+ if (mac_vnode_check_access(ctx, vp, R_OK) != 0) {
perms &= ~R_OK;
- if (perms & X_OK)
- if (mac_vnode_check_access(ctx, vp, X_OK) != 0)
+ }
+ }
+ if (perms & X_OK) {
+ if (mac_vnode_check_access(ctx, vp, X_OK) != 0) {
perms &= ~X_OK;
+ }
+ }
#endif /* MAC */
KAUTH_DEBUG("ATTRLIST - returning user access %x", perms);
ATTR_PACK4(ab, perms);
if (pack_invalid) {
uint64_t fid = 0;
- if (alp->commonattr & ATTR_CMN_EXTENDED_SECURITY)
+ if (alp->commonattr & ATTR_CMN_EXTENDED_SECURITY) {
attrlist_pack_variable(&ab, NULL, 0);
- if (alp->commonattr & ATTR_CMN_UUID)
+ }
+ if (alp->commonattr & ATTR_CMN_UUID) {
ATTR_PACK(&ab, kauth_null_guid);
- if (alp->commonattr & ATTR_CMN_GRPUUID)
+ }
+ if (alp->commonattr & ATTR_CMN_GRPUUID) {
ATTR_PACK(&ab, kauth_null_guid);
- if (alp->commonattr & ATTR_CMN_FILEID)
+ }
+ if (alp->commonattr & ATTR_CMN_FILEID) {
ATTR_PACK8(ab, fid);
- if (alp->commonattr & ATTR_CMN_PARENTID)
+ }
+ if (alp->commonattr & ATTR_CMN_PARENTID) {
ATTR_PACK8(ab, fid);
+ }
}
/* volume attributes **************************************************/
ATTR_PACK_CAST(&ab, uint32_t, vfs_typenum(mnt));
ab.actual.volattr |= ATTR_VOL_FSTYPE;
}
- if (alp->volattr & ATTR_VOL_SIGNATURE) {
- ATTR_PACK_CAST(&ab, uint32_t, vs.f_signature);
+ if (alp->volattr & ATTR_VOL_SIGNATURE) {
+ ATTR_PACK_CAST(&ab, uint32_t, vs.f_signature);
ab.actual.volattr |= ATTR_VOL_SIGNATURE;
}
if (alp->volattr & ATTR_VOL_SIZE) {
ab.actual.volattr |= ATTR_VOL_MINALLOCATION;
}
if (alp->volattr & ATTR_VOL_ALLOCATIONCLUMP) {
- ATTR_PACK_CAST(&ab, off_t, vs.f_bsize); /* not strictly true */
+ ATTR_PACK_CAST(&ab, off_t, vs.f_bsize); /* not strictly true */
ab.actual.volattr |= ATTR_VOL_ALLOCATIONCLUMP;
}
if (alp->volattr & ATTR_VOL_IOBLOCKSIZE) {
ab.actual.volattr |= ATTR_VOL_MOUNTEDDEVICE;
}
if (alp->volattr & ATTR_VOL_ENCODINGSUSED) {
- if (!return_valid || pack_invalid)
+ if (!return_valid || pack_invalid) {
ATTR_PACK_CAST(&ab, uint64_t, ~0LL); /* return all encodings */
+ }
}
if (alp->volattr & ATTR_VOL_CAPABILITIES) {
/* fix up volume capabilities */
vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] &= ~VOL_CAP_INT_EXTENDED_SECURITY;
}
vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_EXTENDED_SECURITY;
+
+ /*
+ * if the filesystem doesn't mark either VOL_CAP_FMT_NO_IMMUTABLE_FILES
+ * or VOL_CAP_FMT_NO_PERMISSIONS as valid, assume they're not supported
+ */
+ if (!(vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_NO_IMMUTABLE_FILES)) {
+ vs.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~VOL_CAP_FMT_NO_IMMUTABLE_FILES;
+ vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
+ }
+
+ if (!(vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_NO_PERMISSIONS)) {
+ vs.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~VOL_CAP_FMT_NO_PERMISSIONS;
+ vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_PERMISSIONS;
+ }
+
+ /*
+ * ATTR_CMN_USERACCESS attribute was previously set by file-system drivers, thus volume capabilitiy
+ * VOL_CAP_INT_USERACCESS was conditionally enabled. ATTR_CMN_USERACCESS is now set inside VFS,
+ * regardless of underlying volume type thus we always set VOL_CAP_INT_USERACCESS.
+ */
+ vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_USERACCESS;
+ vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_USERACCESS;
+
ATTR_PACK(&ab, vs.f_capabilities);
ab.actual.volattr |= ATTR_VOL_CAPABILITIES;
}
ATTR_PACK(&ab, vs.f_uuid);
ab.actual.volattr |= ATTR_VOL_UUID;
}
+ if (alp->volattr & ATTR_VOL_QUOTA_SIZE) {
+ ATTR_PACK_CAST(&ab, off_t, vs.f_bsize * vs.f_quota);
+ ab.actual.volattr |= ATTR_VOL_QUOTA_SIZE;
+ }
+ if (alp->volattr & ATTR_VOL_RESERVED_SIZE) {
+ ATTR_PACK_CAST(&ab, off_t, vs.f_bsize * vs.f_reserved);
+ ab.actual.volattr |= ATTR_VOL_RESERVED_SIZE;
+ }
if (alp->volattr & ATTR_VOL_ATTRIBUTES) {
/* fix up volume attribute information */
ATTR_PACK(&ab, vs.f_attributes);
ab.actual.volattr |= ATTR_VOL_ATTRIBUTES;
}
-
+
/* diagnostic */
- if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize)
+ if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize) {
panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
fixedsize, (long) (ab.fixedcursor - ab.base), alp->commonattr, alp->volattr);
- if (!return_valid && ab.varcursor != (ab.base + ab.needed))
+ }
+ if (!return_valid && ab.varcursor != (ab.base + ab.needed)) {
panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab.varcursor - ab.base), ab.needed);
+ }
/*
* In the compatible case, we report the smaller of the required and returned sizes.
* of the result buffer, even if we copied less out. The caller knows how big a buffer
* they gave us, so they can always check for truncation themselves.
*/
- *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(ab.allocated, ab.needed);
-
+ *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? (uint32_t)ab.needed : (uint32_t)lmin(bufferSize, ab.needed);
+
/* Return attribute set output if requested. */
- if (return_valid) {
+ if (return_valid &&
+ (ab.allocated >= (ssize_t)(sizeof(uint32_t) + sizeof(ab.actual)))) {
ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS;
if (pack_invalid) {
/* Only report the attributes that are valid */
ab.actual.commonattr &= ab.valid.commonattr;
ab.actual.volattr &= ab.valid.volattr;
}
- bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual));
+ bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof(ab.actual));
}
- if (UIO_SEG_IS_USER_SPACE(segflg))
+ if (UIO_SEG_IS_USER_SPACE(segflg)) {
error = copyout(ab.base, CAST_USER_ADDR_T(attributeBuffer),
- ab.allocated);
- else
- bcopy(ab.base, (void *)attributeBuffer, (size_t)ab.allocated);
+ ulmin((uint32_t)bufferSize, (uint32_t)ab.needed));
+ } else {
+ bcopy(ab.base, (void *)attributeBuffer, (size_t)ulmin((uint32_t)bufferSize, (uint32_t)ab.needed));
+ }
out:
- if (vs.f_vol_name != NULL)
- kfree(vs.f_vol_name, MAXPATHLEN);
+ if (vs.f_vol_name != NULL) {
+ zfree(ZV_NAMEI, vs.f_vol_name);
+ }
if (release_str) {
vnode_putname(cnp);
}
- if (ab.base != NULL)
- FREE(ab.base, M_TEMP);
+ kheap_free(KHEAP_TEMP, ab.base, ab.allocated);
VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error);
- return(error);
+
+ if (root_vp != NULL) {
+ vnode_put(root_vp);
+ }
+ return error;
}
/*
* are in ad.
*/
static errno_t
-attr_pack_common(vfs_context_t ctx, struct vnode *vp, struct attrlist *alp,
+attr_pack_common(vfs_context_t ctx, mount_t mp, vnode_t vp, struct attrlist *alp,
struct _attrlist_buf *abp, struct vnode_attr *vap, int proc_is64,
const char *cnp, ssize_t cnl, const char *fullpathptr,
ssize_t fullpathlen, int return_valid, int pack_invalid, int vtype,
int is_bulk)
{
- uint32_t perms = 0;
- int error = 0;
+ uint32_t perms = 0;
+ int error = 0;
if ((alp->commonattr & ATTR_CMN_ERROR) &&
(!return_valid || pack_invalid)) {
abp->actual.commonattr |= ATTR_CMN_NAME;
}
if (alp->commonattr & ATTR_CMN_DEVID) {
- if (vp) {
+ if (mp) { /* caller needs real devid */
+ ATTR_PACK4((*abp),
+ mp->mnt_vfsstat.f_fsid.val[0]);
+ abp->actual.commonattr |= ATTR_CMN_DEVID;
+ } else if (VATTR_IS_ACTIVE(vap, va_fsid) && VATTR_IS_SUPPORTED(vap, va_fsid)) {
+ ATTR_PACK4((*abp), vap->va_fsid);
+ abp->actual.commonattr |= ATTR_CMN_DEVID;
+ } else if (vp) {
ATTR_PACK4((*abp),
vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
abp->actual.commonattr |= ATTR_CMN_DEVID;
}
}
if (alp->commonattr & ATTR_CMN_FSID) {
- if (vp) {
+ if (mp) { /* caller needs real fsid */
ATTR_PACK8((*abp),
- vp->v_mount->mnt_vfsstat.f_fsid);
+ mp->mnt_vfsstat.f_fsid);
abp->actual.commonattr |= ATTR_CMN_FSID;
} else if (VATTR_IS_SUPPORTED(vap, va_fsid64)) {
ATTR_PACK8((*abp), vap->va_fsid64);
abp->actual.commonattr |= ATTR_CMN_FSID;
+ } else if (vp) {
+ ATTR_PACK8((*abp),
+ vp->v_mount->mnt_vfsstat.f_fsid);
+ abp->actual.commonattr |= ATTR_CMN_FSID;
} else if (!return_valid || pack_invalid) {
fsid_t fsid = {{0}};
-
ATTR_PACK8((*abp), fsid);
}
}
*/
if (vap->va_vaflags & VA_64BITOBJIDS) {
if (VATTR_IS_SUPPORTED(vap, va_linkid)) {
- ATTR_PACK8((*abp), vap->va_linkid);
+ ATTR_PACK8((*abp), vap->va_linkid);
} else {
- ATTR_PACK8((*abp), vap->va_fileid);
+ ATTR_PACK8((*abp), vap->va_fileid);
}
} else {
fsobj_id_t f;
*/
if (vap->va_vaflags & VA_64BITOBJIDS) {
if (VATTR_IS_SUPPORTED(vap, va_linkid)) {
- ATTR_PACK8((*abp), vap->va_linkid);
+ ATTR_PACK8((*abp), vap->va_linkid);
} else {
- ATTR_PACK8((*abp), vap->va_fileid);
+ ATTR_PACK8((*abp), vap->va_fileid);
}
} else {
fsobj_id_t f;
abp->actual.commonattr |= ATTR_CMN_PAROBJID;
}
if (alp->commonattr & ATTR_CMN_SCRIPT) {
- if (VATTR_IS_SUPPORTED(vap, va_encoding)) {
+ if (VATTR_IS_SUPPORTED(vap, va_encoding)) {
ATTR_PACK4((*abp), vap->va_encoding);
abp->actual.commonattr |= ATTR_CMN_SCRIPT;
} else if (!return_valid || pack_invalid) {
abp->actual.commonattr |= ATTR_CMN_BKUPTIME;
}
/*
- * They are requesting user access, we should obtain this before getting
+ * They are requesting user access, we should obtain this before getting
* the finder info. For some network file systems this is a performance
* improvement.
*/
- if (alp->commonattr & ATTR_CMN_USERACCESS) { /* this is expensive */
+ if (alp->commonattr & ATTR_CMN_USERACCESS) { /* this is expensive */
if (vp && !is_bulk) {
if (vtype == VDIR) {
if (vnode_authorize(vp, NULL,
KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE |
KAUTH_VNODE_ADD_SUBDIRECTORY |
- KAUTH_VNODE_DELETE_CHILD, ctx) == 0)
+ KAUTH_VNODE_DELETE_CHILD, ctx) == 0) {
perms |= W_OK;
+ }
if (vnode_authorize(vp, NULL,
KAUTH_VNODE_ACCESS |
- KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0)
+ KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0) {
perms |= R_OK;
+ }
if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS |
- KAUTH_VNODE_SEARCH, ctx) == 0)
+ KAUTH_VNODE_SEARCH, ctx) == 0) {
perms |= X_OK;
+ }
} else {
if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS |
- KAUTH_VNODE_WRITE_DATA, ctx) == 0)
+ KAUTH_VNODE_WRITE_DATA, ctx) == 0) {
perms |= W_OK;
+ }
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0)
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0) {
perms |= R_OK;
- if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0)
+ }
+ if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0) {
perms |= X_OK;
+ }
}
} else if (is_bulk &&
VATTR_IS_SUPPORTED(vap, va_user_access)) {
}
}
if (alp->commonattr & ATTR_CMN_FNDRINFO) {
- size_t fisize = 32;
+ size_t fisize = 32;
- error = 0;
+ error = 0;
if (vp && !is_bulk) {
- uio_t auio;
- char uio_buf[UIO_SIZEOF(1)];
+ uio_t auio;
+ char uio_buf[UIO_SIZEOF(1)];
if ((auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE,
UIO_READ, uio_buf, sizeof(uio_buf))) == NULL) {
fisize);
/* fisize may be reset to 0 after this call */
error = vn_getxattr(vp, XATTR_FINDERINFO_NAME, auio,
- &fisize, XATTR_NOSECURITY, ctx);
+ &fisize, XATTR_NOSECURITY, ctx);
uio_free(auio);
/*
abp->actual.commonattr |= ATTR_CMN_DOCUMENT_ID;
} else if (!return_valid || pack_invalid) {
ATTR_PACK4((*abp), 0);
- }
+ }
}
/* We already obtain the user access, so just fill in the buffer here */
if (alp->commonattr & ATTR_CMN_USERACCESS) {
* the smallest set of permissions granted by both MAC &
* DAC checks. We won't add back any permissions.
*/
- if (perms & W_OK)
- if (mac_vnode_check_access(ctx, vp, W_OK) != 0)
+ if (perms & W_OK) {
+ if (mac_vnode_check_access(ctx, vp, W_OK) != 0) {
perms &= ~W_OK;
- if (perms & R_OK)
- if (mac_vnode_check_access(ctx, vp, R_OK) != 0)
+ }
+ }
+ if (perms & R_OK) {
+ if (mac_vnode_check_access(ctx, vp, R_OK) != 0) {
perms &= ~R_OK;
- if (perms & X_OK)
- if (mac_vnode_check_access(ctx, vp, X_OK) != 0)
+ }
+ }
+ if (perms & X_OK) {
+ if (mac_vnode_check_access(ctx, vp, X_OK) != 0) {
perms &= ~X_OK;
+ }
+ }
}
#endif /* MAC */
VFS_DEBUG(ctx, vp, "ATTRLIST - granting perms %d", perms);
}
}
if (alp->commonattr & ATTR_CMN_UUID) {
- if (VATTR_IS_SUPPORTED(vap, va_uuuid)) {
+ if (VATTR_IS_SUPPORTED(vap, va_uuuid)) {
ATTR_PACK(abp, vap->va_uuuid);
abp->actual.commonattr |= ATTR_CMN_UUID;
} else if (!return_valid || pack_invalid) {
ATTR_PACK8((*abp), vap->va_parentid);
abp->actual.commonattr |= ATTR_CMN_PARENTID;
}
-
+
if (alp->commonattr & ATTR_CMN_FULLPATH) {
if (vp) {
- attrlist_pack_string (abp, fullpathptr, fullpathlen);
+ attrlist_pack_string(abp, fullpathptr, fullpathlen);
abp->actual.commonattr |= ATTR_CMN_FULLPATH;
}
}
-
+
if (alp->commonattr & ATTR_CMN_ADDEDTIME) {
if (VATTR_IS_SUPPORTED(vap, va_addedtime)) {
ATTR_PACK_TIME((*abp), vap->va_addedtime, proc_is64);
abp->actual.commonattr |= ATTR_CMN_ADDEDTIME;
} else if (!return_valid || pack_invalid) {
- struct timespec zerotime = {0, 0};
+ struct timespec zerotime = {.tv_sec = 0, .tv_nsec = 0};
ATTR_PACK_TIME((*abp), zerotime, proc_is64);
}
}
}
out:
- return (error);
+ return error;
}
static errno_t
attr_pack_dir(struct vnode *vp, struct attrlist *alp, struct _attrlist_buf *abp,
- struct vnode_attr *vap)
+ struct vnode_attr *vap, int return_valid, int pack_invalid)
{
if (alp->dirattr & ATTR_DIR_LINKCOUNT) { /* full count of entries */
ATTR_PACK4((*abp), (uint32_t)vap->va_dirlinkcount);
* on vnode. In either case, the directory should
* be reported as a mount point.
*/
- if ((vp->v_flag & VROOT) || vnode_mountedhere(vp)) {
+ if ((vp->v_flag & VROOT) || vnode_mountedhere(vp)) {
mntstat = DIR_MNTSTATUS_MNTPOINT;
} else {
mntstat = 0;
ATTR_PACK4((*abp), mntstat);
abp->actual.dirattr |= ATTR_DIR_MOUNTSTATUS;
}
+ if (alp->dirattr & ATTR_DIR_ALLOCSIZE) {
+ if (VATTR_IS_SUPPORTED(vap, va_data_alloc)) {
+ ATTR_PACK8((*abp), vap->va_data_alloc);
+ abp->actual.dirattr |= ATTR_DIR_ALLOCSIZE;
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_alloc)) {
+ ATTR_PACK8((*abp), vap->va_total_alloc);
+ abp->actual.dirattr |= ATTR_DIR_ALLOCSIZE;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
+ if (alp->dirattr & ATTR_DIR_IOBLOCKSIZE) {
+ if (VATTR_IS_SUPPORTED(vap, va_iosize)) {
+ ATTR_PACK4((*abp), vap->va_iosize);
+ abp->actual.dirattr |= ATTR_DIR_IOBLOCKSIZE;
+ } else if (!return_valid || pack_invalid) {
+ ATTR_PACK4((*abp), 0);
+ }
+ }
+ /*
+ * If the filesystem does not support datalength
+ * or dataallocsize, then we infer that totalsize and
+ * totalalloc are substitutes.
+ */
+ if (alp->dirattr & ATTR_DIR_DATALENGTH) {
+ if (VATTR_IS_SUPPORTED(vap, va_data_size)) {
+ ATTR_PACK8((*abp), vap->va_data_size);
+ abp->actual.dirattr |= ATTR_DIR_DATALENGTH;
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_size)) {
+ ATTR_PACK8((*abp), vap->va_total_size);
+ abp->actual.dirattr |= ATTR_DIR_DATALENGTH;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
return 0;
}
* attempt is made to retrieve them by calling back into the filesystem.
*/
static errno_t
-attr_pack_file(vfs_context_t ctx, struct vnode *vp, struct attrlist *alp,
+attr_pack_file(vfs_context_t ctx, struct vnode *vp, struct attrlist *alp,
struct _attrlist_buf *abp, struct vnode_attr *vap, int return_valid,
int pack_invalid, int is_bulk)
{
- size_t rsize = 0;
+ size_t rsize = 0;
uint64_t rlength = 0;
uint64_t ralloc = 0;
int error = 0;
if (vp && !is_bulk &&
(alp->fileattr & (ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE |
ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE))) {
-
error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL,
&rsize, XATTR_NOSECURITY, ctx);
if (error) {
if (VATTR_IS_SUPPORTED(vap, va_data_size)) {
totalsize += vap->va_data_size;
- } else {
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_size)) {
totalsize += vap->va_total_size;
}
*/
if (VATTR_IS_SUPPORTED(vap, va_data_alloc)) {
totalalloc += vap->va_data_alloc;
- } else {
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_alloc)) {
totalalloc += vap->va_total_alloc;
}
}
}
if (alp->fileattr & ATTR_FILE_IOBLOCKSIZE) {
- ATTR_PACK4((*abp), vap->va_iosize);
- abp->actual.fileattr |= ATTR_FILE_IOBLOCKSIZE;
+ if (VATTR_IS_SUPPORTED(vap, va_iosize)) {
+ ATTR_PACK4((*abp), vap->va_iosize);
+ abp->actual.fileattr |= ATTR_FILE_IOBLOCKSIZE;
+ } else if (!return_valid || pack_invalid) {
+ ATTR_PACK4((*abp), 0);
+ }
}
if (alp->fileattr & ATTR_FILE_CLUMPSIZE) {
if (!return_valid || pack_invalid) {
if (alp->fileattr & ATTR_FILE_DATALENGTH) {
if (VATTR_IS_SUPPORTED(vap, va_data_size)) {
ATTR_PACK8((*abp), vap->va_data_size);
- } else {
+ abp->actual.fileattr |= ATTR_FILE_DATALENGTH;
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_size)) {
ATTR_PACK8((*abp), vap->va_total_size);
+ abp->actual.fileattr |= ATTR_FILE_DATALENGTH;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
}
- abp->actual.fileattr |= ATTR_FILE_DATALENGTH;
}
if (alp->fileattr & ATTR_FILE_DATAALLOCSIZE) {
if (VATTR_IS_SUPPORTED(vap, va_data_alloc)) {
ATTR_PACK8((*abp), vap->va_data_alloc);
- } else {
+ abp->actual.fileattr |= ATTR_FILE_DATAALLOCSIZE;
+ } else if (VATTR_IS_SUPPORTED(vap, va_total_alloc)) {
ATTR_PACK8((*abp), vap->va_total_alloc);
+ abp->actual.fileattr |= ATTR_FILE_DATAALLOCSIZE;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
}
- abp->actual.fileattr |= ATTR_FILE_DATAALLOCSIZE;
}
/* already got the resource fork size/allocation above */
if (alp->fileattr & ATTR_FILE_RSRCLENGTH) {
ATTR_PACK8((*abp), zero_val);
}
}
-out:
- return (error);
+out:
+ return error;
+}
+
+/*
+ * Pack FORKATTR attributes into a user buffer.
+ * alp is a pointer to the bitmap of attributes required.
+ * abp is the state of the attribute filling operation.
+ * The attribute data (along with some other fields that are required
+ * are in ad.
+ */
+static errno_t
+attr_pack_common_extended(mount_t mp, struct vnode *vp, struct attrlist *alp,
+ struct _attrlist_buf *abp, const char *relpathptr, ssize_t relpathlen,
+ const char *REALpathptr, ssize_t REALpathlen,
+ struct vnode_attr *vap, int return_valid, int pack_invalid)
+{
+ if (vp && (alp->forkattr & ATTR_CMNEXT_RELPATH)) {
+ attrlist_pack_string(abp, relpathptr, relpathlen);
+ abp->actual.forkattr |= ATTR_CMNEXT_RELPATH;
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_PRIVATESIZE) {
+ if (VATTR_IS_SUPPORTED(vap, va_private_size)) {
+ ATTR_PACK8((*abp), vap->va_private_size);
+ abp->actual.forkattr |= ATTR_CMNEXT_PRIVATESIZE;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_LINKID) {
+ uint64_t linkid;
+
+ if (VATTR_IS_SUPPORTED(vap, va_linkid)) {
+ linkid = vap->va_linkid;
+ } else {
+ linkid = vap->va_fileid;
+ }
+
+ ATTR_PACK8((*abp), linkid);
+ abp->actual.forkattr |= ATTR_CMNEXT_LINKID;
+ }
+
+ if (vp && (alp->forkattr & ATTR_CMNEXT_NOFIRMLINKPATH)) {
+ attrlist_pack_string(abp, REALpathptr, REALpathlen);
+ abp->actual.forkattr |= ATTR_CMNEXT_NOFIRMLINKPATH;
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_REALDEVID) {
+ if (mp) {
+ ATTR_PACK4((*abp),
+ mp->mnt_vfsstat.f_fsid.val[0]);
+ abp->actual.forkattr |= ATTR_CMNEXT_REALDEVID;
+ } else if (vp) {
+ ATTR_PACK4((*abp),
+ vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
+ abp->actual.forkattr |= ATTR_CMNEXT_REALDEVID;
+ } else if (VATTR_IS_SUPPORTED(vap, va_fsid)) {
+ ATTR_PACK4((*abp), vap->va_fsid);
+ abp->actual.forkattr |= ATTR_CMN_DEVID;
+ } else if (!return_valid || pack_invalid) {
+ ATTR_PACK4((*abp), 0);
+ }
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_REALFSID) {
+ if (mp) {
+ ATTR_PACK8((*abp),
+ mp->mnt_vfsstat.f_fsid);
+ abp->actual.forkattr |= ATTR_CMNEXT_REALFSID;
+ } else if (vp) {
+ ATTR_PACK8((*abp),
+ vp->v_mount->mnt_vfsstat.f_fsid);
+ abp->actual.forkattr |= ATTR_CMNEXT_REALFSID;
+ } else if (VATTR_IS_SUPPORTED(vap, va_fsid64)) {
+ ATTR_PACK8((*abp), vap->va_fsid64);
+ abp->actual.forkattr |= ATTR_CMN_FSID;
+ } else if (!return_valid || pack_invalid) {
+ fsid_t fsid = {{0}};
+
+ ATTR_PACK8((*abp), fsid);
+ }
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_CLONEID) {
+ if (VATTR_IS_SUPPORTED(vap, va_clone_id)) {
+ ATTR_PACK8((*abp), vap->va_clone_id);
+ abp->actual.forkattr |= ATTR_CMNEXT_CLONEID;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_EXT_FLAGS) {
+ if (VATTR_IS_SUPPORTED(vap, va_extflags)) {
+ ATTR_PACK8((*abp), vap->va_extflags);
+ abp->actual.forkattr |= ATTR_CMNEXT_EXT_FLAGS;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
+
+ if (alp->forkattr & ATTR_CMNEXT_RECURSIVE_GENCOUNT) {
+ if (VATTR_IS_SUPPORTED(vap, va_recursive_gencount)) {
+ ATTR_PACK8((*abp), vap->va_recursive_gencount);
+ abp->actual.forkattr |= ATTR_CMNEXT_RECURSIVE_GENCOUNT;
+ } else if (!return_valid || pack_invalid) {
+ uint64_t zero_val = 0;
+ ATTR_PACK8((*abp), zero_val);
+ }
+ }
+
+ return 0;
}
static void
vattr_get_alt_data(vnode_t vp, struct attrlist *alp, struct vnode_attr *vap,
- int return_valid, int is_bulk, vfs_context_t ctx)
+ int return_valid, int is_bulk,
+#if !CONFIG_FIRMLINKS
+ __unused
+#endif
+ int is_realdev, vfs_context_t ctx)
{
/*
* There are a couple of special cases.
/* forget we wanted this */
VATTR_CLEAR_ACTIVE(vap, va_linkid);
}
-
+
+ /*
+ * A filesystem may not support va_fsid64. If it is not available, then we'll
+ * synthesize it from the mount.
+ */
+ if ((alp->commonattr & ATTR_CMN_FSID) && !VATTR_IS_SUPPORTED(vap, va_fsid64)) {
+ VATTR_CLEAR_ACTIVE(vap, va_fsid64);
+ }
+
+ /* Same for fsid */
+ if ((alp->commonattr & ATTR_CMN_FSID) && !VATTR_IS_SUPPORTED(vap, va_fsid)) {
+ VATTR_CLEAR_ACTIVE(vap, va_fsid);
+ }
+
+ /* We request the fsid64 for the devid */
+ if ((alp->commonattr & ATTR_CMN_DEVID) && !VATTR_IS_SUPPORTED(vap, va_fsid)) {
+ VATTR_CLEAR_ACTIVE(vap, va_fsid);
+ }
+
+
/*
* Many filesystems don't know their parent object id.
* If necessary, attempt to derive it from the vnode.
*/
- if ((alp->commonattr & (ATTR_CMN_PAROBJID | ATTR_CMN_PARENTID)) &&
- !VATTR_IS_SUPPORTED(vap, va_parentid) && vp && !is_bulk) {
- vnode_t dvp;
+ if ((alp->commonattr & (ATTR_CMN_PAROBJID | ATTR_CMN_PARENTID)) && vp) {
+ vnode_t dvp;
- if ((dvp = vnode_getparent(vp)) != NULLVP) {
+#if CONFIG_FIRMLINKS
+ /* If this is a firmlink target, we get the fileid of the firmlink parent. */
+ if (!is_realdev && (vp->v_flag & VFMLINKTARGET) && ((dvp = vp->v_fmlink) != NULL) && (vnode_get(dvp) == 0)) {
struct vnode_attr lva;
VATTR_INIT(&lva);
- VATTR_WANTED(&lva, va_fileid);
+ VATTR_WANTED(&lva, va_parentid);
+ VATTR_WANTED(&lva, va_fsid);
if (vnode_getattr(dvp, &lva, ctx) == 0 &&
- VATTR_IS_SUPPORTED(vap, va_fileid)) {
- vap->va_parentid = lva.va_fileid;
+ VATTR_IS_SUPPORTED(&lva, va_parentid) &&
+ VATTR_IS_SUPPORTED(&lva, va_fsid) &&
+ (lva.va_fsid == (uint32_t)vp->v_mount->mnt_vfsstat.f_fsid.val[0])) {
+ vap->va_parentid = lva.va_parentid;
VATTR_SET_SUPPORTED(vap, va_parentid);
}
vnode_put(dvp);
+ } else
+#endif /* CONFIG_FIRMLINKS */
+ if (!VATTR_IS_SUPPORTED(vap, va_parentid) && !is_bulk) {
+ if ((dvp = vnode_getparent(vp)) != NULLVP) {
+ struct vnode_attr lva;
+
+ VATTR_INIT(&lva);
+ VATTR_WANTED(&lva, va_fileid);
+ if (vnode_getattr(dvp, &lva, ctx) == 0 &&
+ VATTR_IS_SUPPORTED(vap, va_fileid)) {
+ vap->va_parentid = lva.va_fileid;
+ VATTR_SET_SUPPORTED(vap, va_parentid);
+ }
+ vnode_put(dvp);
+ }
}
}
+
/*
* And we can report datasize/alloc from total.
*/
}
}
+struct _attrlist_paths {
+ char *fullpathptr;
+ ssize_t *fullpathlenp;
+ char *relpathptr;
+ ssize_t *relpathlenp;
+ char *REALpathptr;
+ ssize_t *REALpathlenp;
+};
+
static errno_t
calc_varsize(vnode_t vp, struct attrlist *alp, struct vnode_attr *vap,
- ssize_t *varsizep, char *fullpathptr, ssize_t *fullpathlenp,
- const char **vnamep, const char **cnpp, ssize_t *cnlp)
+ ssize_t *varsizep, struct _attrlist_paths *pathsp, const char **vnamep,
+ const char **cnpp, ssize_t *cnlp)
{
int error = 0;
/* We may need to fix up the name attribute if requested */
if (alp->commonattr & ATTR_CMN_NAME) {
if (VATTR_IS_SUPPORTED(vap, va_name)) {
- vap->va_name[MAXPATHLEN-1] = '\0'; /* Ensure nul-termination */
+ vap->va_name[MAXPATHLEN - 1] = '\0'; /* Ensure nul-termination */
*cnpp = vap->va_name;
*cnlp = strlen(*cnpp);
} else if (vp) {
/* Filesystem did not support getting the name */
if (vnode_isvroot(vp)) {
if (vp->v_mount->mnt_vfsstat.f_mntonname[1] == 0x00 &&
- vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') {
+ vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') {
/* special case for boot volume. Use root name when it's
* available (which is the volume name) or just the mount on
* name of "/". we must do this for binary compatibility with
*cnpp = &vp->v_mount->mnt_vfsstat.f_mntonname[0];
}
*cnlp = strlen(*cnpp);
- }
- else {
+ } else {
getattrlist_findnamecomp(vp->v_mount->mnt_vfsstat.f_mntonname, cnpp, cnlp);
}
- }
- else {
+ } else {
*cnpp = *vnamep = vnode_getname(vp);
*cnlp = 0;
if (*cnpp != NULL) {
*varsizep += roundup(*cnlp + 1, 4);
}
- /*
+ /*
* Compute the full path to this vnode, if necessary. This attribute is almost certainly
* not supported by any filesystem, so build the path to this vnode at this time.
*/
int err;
/* call build_path making sure NOT to use the cache-only behavior */
- err = build_path(vp, fullpathptr, len, &len, 0, vfs_context_current());
+ err = build_path(vp, pathsp->fullpathptr, len, &len, 0, vfs_context_current());
+ if (err) {
+ error = err;
+ goto out;
+ }
+ if (pathsp->fullpathptr) {
+ *(pathsp->fullpathlenp) = strlen(pathsp->fullpathptr);
+ } else {
+ *(pathsp->fullpathlenp) = 0;
+ }
+ *varsizep += roundup(((*(pathsp->fullpathlenp)) + 1), 4);
+ }
+
+ /*
+ * Compute this vnode's volume relative path.
+ */
+ if (vp && (alp->forkattr & ATTR_CMNEXT_RELPATH)) {
+ int len;
+ int err;
+
+ /* call build_path making sure NOT to use the cache-only behavior */
+ err = build_path(vp, pathsp->relpathptr, MAXPATHLEN, &len, BUILDPATH_VOLUME_RELATIVE, vfs_context_current());
if (err) {
error = err;
goto out;
}
- *fullpathlenp = 0;
- if (fullpathptr){
- *fullpathlenp = strlen(fullpathptr);
+
+ //`len' includes trailing null
+ *(pathsp->relpathlenp) = len - 1;
+ *varsizep += roundup(len, 4);
+ }
+
+ /*
+ * Compute this vnode's real (firmlink free) path.
+ */
+ if (vp && (alp->forkattr & ATTR_CMNEXT_NOFIRMLINKPATH)) {
+ int len;
+ int err;
+
+ /* call build_path making sure NOT to use the cache-only behavior */
+ err = build_path(vp, pathsp->REALpathptr, MAXPATHLEN, &len, BUILDPATH_NO_FIRMLINK, vfs_context_current());
+ if (err) {
+ error = err;
+ goto out;
}
- *varsizep += roundup(((*fullpathlenp) + 1), 4);
+
+ //`len' includes trailing null
+ *(pathsp->REALpathlenp) = len - 1;
+ *varsizep += roundup(len, 4);
}
/*
* user-space this is OK.
*/
if ((alp->commonattr & ATTR_CMN_EXTENDED_SECURITY) &&
- VATTR_IS_SUPPORTED(vap, va_acl) &&
- (vap->va_acl != NULL)) {
-
- /*
+ VATTR_IS_SUPPORTED(vap, va_acl) &&
+ (vap->va_acl != NULL)) {
+ /*
* Since we have a kauth_acl_t (not a kauth_filesec_t), we have to check against
* KAUTH_FILESEC_NOACL ourselves
- */
+ */
if (vap->va_acl->acl_entrycount == KAUTH_FILESEC_NOACL) {
*varsizep += roundup((KAUTH_FILESEC_SIZE(0)), 4);
- }
- else {
- *varsizep += roundup ((KAUTH_FILESEC_SIZE(vap->va_acl->acl_entrycount)), 4);
+ } else {
+ *varsizep += roundup((KAUTH_FILESEC_SIZE(vap->va_acl->acl_entrycount)), 4);
}
}
out:
- return (error);
+ return error;
}
static errno_t
-vfs_attr_pack_internal(vnode_t vp, uio_t auio, struct attrlist *alp,
+vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp,
uint64_t options, struct vnode_attr *vap, __unused void *fndesc,
vfs_context_t ctx, int is_bulk, enum vtype vtype, ssize_t fixedsize)
{
struct _attrlist_buf ab;
+ struct _attrlist_paths apaths = {.fullpathptr = NULL, .fullpathlenp = NULL,
+ .relpathptr = NULL, .relpathlenp = NULL,
+ .REALpathptr = NULL, .REALpathlenp = NULL};
ssize_t buf_size;
size_t copy_size;
- ssize_t varsize;
+ ssize_t varsize;
const char *vname = NULL;
const char *cnp;
ssize_t cnl;
char *fullpathptr;
- ssize_t fullpathlen;
+ ssize_t fullpathlen;
+ char *relpathptr;
+ ssize_t relpathlen;
+ char *REALpathptr;
+ ssize_t REALpathlen;
int error;
int proc_is64;
int return_valid;
int pack_invalid;
+ int is_realdev;
int alloc_local_buf;
+ const int use_fork = options & FSOPT_ATTR_CMN_EXTENDED;
proc_is64 = proc_is64bit(vfs_context_proc(ctx));
ab.base = NULL;
cnl = 0;
fullpathptr = NULL;
fullpathlen = 0;
+ relpathptr = NULL;
+ relpathlen = 0;
+ REALpathptr = NULL;
+ REALpathlen = 0;
error = 0;
alloc_local_buf = 0;
buf_size = (ssize_t)uio_resid(auio);
- if ((buf_size <= 0) || (uio_iovcnt(auio) > 1))
- return (EINVAL);
+ if ((buf_size <= 0) || (uio_iovcnt(auio) > 1)) {
+ return EINVAL;
+ }
copy_size = 0;
/* Check for special packing semantics */
return_valid = (alp->commonattr & ATTR_CMN_RETURNED_ATTRS) ? 1 : 0;
pack_invalid = (options & FSOPT_PACK_INVAL_ATTRS) ? 1 : 0;
+ is_realdev = options & FSOPT_RETURN_REALDEV ? 1 : 0;
if (pack_invalid) {
/* Generate a valid mask for post processing */
- bcopy(&(alp->commonattr), &ab.valid, sizeof (attribute_set_t));
+ bcopy(&(alp->commonattr), &ab.valid, sizeof(attribute_set_t));
}
/* did we ask for something the filesystem doesn't support? */
- if (vap->va_active && !VATTR_ALL_SUPPORTED(vap)) {
- vattr_get_alt_data(vp, alp, vap, return_valid, is_bulk,
+ if (vap->va_active &&
+ (!VATTR_ALL_SUPPORTED(vap)
+#if CONFIG_FIRMLINKS
+ /* For firmlink targets we have to overide what the FS returned for parentid */
+ ||
+ (!is_realdev && vp && (vp->v_flag & VFMLINKTARGET) && vp->v_fmlink &&
+ (alp->commonattr & (ATTR_CMN_PAROBJID | ATTR_CMN_PARENTID)))
+#endif
+ )) {
+ // this disables the selectors that were not supported by the filesystem
+ vattr_get_alt_data(vp, alp, vap, return_valid, is_bulk, is_realdev,
ctx);
/* check again */
if (!VATTR_ALL_SUPPORTED(vap)) {
if (return_valid && pack_invalid) {
/* Fix up valid mask for post processing */
- getattrlist_fixupattrs(&ab.valid, vap);
-
+ getattrlist_fixupattrs(&ab.valid, vap, use_fork);
+
/* Force packing of everything asked for */
vap->va_supported = vap->va_active;
} else if (return_valid) {
/* Adjust the requested attributes */
getattrlist_fixupattrs(
- (attribute_set_t *)&(alp->commonattr), vap);
+ (attribute_set_t *)&(alp->commonattr), vap, use_fork);
} else {
error = EINVAL;
}
}
- if (error)
+ if (error) {
goto out;
+ }
}
+ //if a path is requested, allocate a temporary buffer to build it
if (vp && (alp->commonattr & (ATTR_CMN_FULLPATH))) {
- fullpathptr = (char*) kalloc(MAXPATHLEN);
- if (fullpathptr == NULL) {
- error = ENOMEM;
- VFS_DEBUG(ctx,vp, "ATTRLIST - ERROR: cannot allocate fullpath buffer");
- goto out;
+ fullpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO);
+ apaths.fullpathptr = fullpathptr;
+ apaths.fullpathlenp = &fullpathlen;
+ }
+
+ // only interpret fork attributes if they're used as new common attributes
+ if (vp && use_fork) {
+ if (alp->forkattr & (ATTR_CMNEXT_RELPATH)) {
+ relpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO);
+ apaths.relpathptr = relpathptr;
+ apaths.relpathlenp = &relpathlen;
+ }
+
+ if (alp->forkattr & (ATTR_CMNEXT_NOFIRMLINKPATH)) {
+ REALpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO);
+ apaths.REALpathptr = REALpathptr;
+ apaths.REALpathlenp = &REALpathlen;
}
- bzero(fullpathptr, MAXPATHLEN);
}
/*
* Compute variable-space requirements.
*/
- error = calc_varsize(vp, alp, vap, &varsize, fullpathptr, &fullpathlen,
- &vname, &cnp, &cnl);
- if (error)
+ error = calc_varsize(vp, alp, vap, &varsize, &apaths, &vname, &cnp, &cnl);
+ if (error) {
goto out;
+ }
/*
* Allocate a target buffer for attribute results.
*
* Note that we won't ever copy out more than the caller requested, even though
* we might have to allocate more than they offer so that the diagnostic checks
- * don't result in a panic if the caller's buffer is too small..
+ * don't result in a panic if the caller's buffer is too small.
*/
ab.allocated = fixedsize + varsize;
/* Cast 'allocated' to an unsigned to verify allocation size */
- if ( ((size_t)ab.allocated) > ATTR_MAX_BUFFER) {
+ if (((size_t)ab.allocated) > ATTR_MAX_BUFFER) {
error = ENOMEM;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER);
goto out;
newlen = (ab.allocated + 7) & ~0x07;
/* Align only if enough space for alignment */
- if (newlen <= (uint32_t)buf_size)
+ if (newlen <= (uint32_t)buf_size) {
ab.allocated = newlen;
+ }
}
}
* and big enough.
*/
if (uio_isuserspace(auio) || (buf_size < ab.allocated)) {
- MALLOC(ab.base, char *, ab.allocated, M_TEMP,
- M_ZERO | M_WAITOK);
+ ab.base = kheap_alloc(KHEAP_TEMP, ab.allocated, Z_ZERO | Z_WAITOK);
alloc_local_buf = 1;
} else {
/*
*/
ab.fixedcursor = ab.base + sizeof(uint32_t);
if (return_valid) {
- ab.fixedcursor += sizeof (attribute_set_t);
- bzero(&ab.actual, sizeof (ab.actual));
+ ab.fixedcursor += sizeof(attribute_set_t);
+ bzero(&ab.actual, sizeof(ab.actual));
}
ab.varcursor = ab.base + fixedsize;
ab.needed = ab.allocated;
/* common attributes ************************************************/
- error = attr_pack_common(ctx, vp, alp, &ab, vap, proc_is64, cnp, cnl,
- fullpathptr, fullpathlen, return_valid, pack_invalid, vtype, is_bulk);
+ error = attr_pack_common(ctx, (options & FSOPT_RETURN_REALDEV ? mp : NULL),
+ vp, alp, &ab, vap, proc_is64, cnp, cnl, fullpathptr, fullpathlen,
+ return_valid, pack_invalid, vtype, is_bulk);
/* directory attributes *********************************************/
if (!error && alp->dirattr && (vtype == VDIR)) {
- error = attr_pack_dir(vp, alp, &ab, vap);
+ error = attr_pack_dir(vp, alp, &ab, vap, return_valid, pack_invalid);
}
/* file attributes **************************************************/
pack_invalid, is_bulk);
}
- if (error)
+ /* common extended attributes *****************************************/
+ if (!error && use_fork) {
+ error = attr_pack_common_extended(mp, vp, alp, &ab, relpathptr, relpathlen,
+ REALpathptr, REALpathlen, vap, return_valid, pack_invalid);
+ }
+
+ if (error) {
goto out;
-
+ }
+
/* diagnostic */
- if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize)
+ if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize) {
panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x",
fixedsize, (long) (ab.fixedcursor - ab.base), alp->commonattr, alp->volattr);
- if (!return_valid && ab.varcursor != (ab.base + ab.needed))
+ }
+ if (!return_valid && ab.varcursor != (ab.base + ab.needed)) {
panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab.varcursor - ab.base), ab.needed);
+ }
/*
* In the compatible case, we report the smaller of the required and returned sizes.
* of the result buffer, even if we copied less out. The caller knows how big a buffer
* they gave us, so they can always check for truncation themselves.
*/
- *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(ab.allocated, ab.needed);
+ *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? (uint32_t)ab.needed : (uint32_t)lmin(ab.allocated, ab.needed);
/* Return attribute set output if requested. */
if (return_valid) {
ab.actual.dirattr &= ab.valid.dirattr;
ab.actual.fileattr &= ab.valid.fileattr;
}
- bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual));
+ bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof(ab.actual));
}
- copy_size = imin(buf_size, ab.allocated);
+ copy_size = lmin(buf_size, ab.allocated);
/* Only actually copyout as much out as the user buffer can hold */
if (alloc_local_buf) {
- error = uiomove(ab.base, copy_size, auio);
+ error = uiomove(ab.base, (int)copy_size, auio);
} else {
off_t orig_offset = uio_offset(auio);
}
out:
- if (vname)
+ if (vname) {
vnode_putname(vname);
- if (fullpathptr)
- kfree(fullpathptr, MAXPATHLEN);
- if (ab.base != NULL && alloc_local_buf)
- FREE(ab.base, M_TEMP);
- return (error);
+ }
+ if (fullpathptr) {
+ zfree(ZV_NAMEI, fullpathptr);
+ }
+ if (relpathptr) {
+ zfree(ZV_NAMEI, relpathptr);
+ }
+ if (REALpathptr) {
+ zfree(ZV_NAMEI, REALpathptr);
+ }
+ if (alloc_local_buf) {
+ kheap_free(KHEAP_TEMP, ab.base, ab.allocated);
+ }
+ return error;
}
errno_t
-vfs_attr_pack(vnode_t vp, uio_t uio, struct attrlist *alp, uint64_t options,
+vfs_attr_pack_ext(mount_t mp, vnode_t vp, uio_t uio, struct attrlist *alp, uint64_t options,
struct vnode_attr *vap, __unused void *fndesc, vfs_context_t ctx)
{
int error;
struct attrlist orig_al;
enum vtype v_type;
- if (vp)
+ if (vp) {
v_type = vnode_vtype(vp);
- else
+ } else {
v_type = vap->va_objtype;
+ }
orig_al = *alp;
orig_active = vap->va_active;
vap->va_active = 0;
error = getattrlist_setupvattr_all(alp, vap, v_type, &fixedsize,
- proc_is64bit(vfs_context_proc(ctx)));
+ proc_is64bit(vfs_context_proc(ctx)), options & FSOPT_ATTR_CMN_EXTENDED);
if (error) {
VFS_DEBUG(ctx, vp,
goto out;
}
- error = vfs_attr_pack_internal(vp, uio, alp,
- options|FSOPT_REPORT_FULLSIZE, vap, NULL, ctx, 1, v_type,
+ error = vfs_attr_pack_internal(mp, vp, uio, alp,
+ options | FSOPT_REPORT_FULLSIZE, vap, NULL, ctx, 1, v_type,
fixedsize);
VATTR_CLEAR_SUPPORTED_ALL(vap);
vap->va_active = orig_active;
*alp = orig_al;
out:
- return (error);
+ return error;
+}
+
+errno_t
+vfs_attr_pack(vnode_t vp, uio_t uio, struct attrlist *alp, uint64_t options,
+ struct vnode_attr *vap, __unused void *fndesc, vfs_context_t ctx)
+{
+ return vfs_attr_pack_ext(NULL, vp, uio, alp, options, vap, fndesc, ctx);
}
/*
* name obtained from some authoritative source (eg. readdir vnop); where
* filesystems' getattr vnops do not support ATTR_CMN_NAME, the alt_name will be
* used as the ATTR_CMN_NAME attribute returned in vnode_attr.va_name.
- *
+ *
*/
static int
getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp,
user_addr_t attributeBuffer, size_t bufferSize, uint64_t options,
- enum uio_seg segflg, char* alt_name, struct ucred *file_cred)
+ enum uio_seg segflg, char* authoritative_name, struct ucred *file_cred)
{
- struct vnode_attr va;
- kauth_action_t action;
- ssize_t fixedsize;
- char *va_name;
- int proc_is64;
- int error;
- int return_valid;
- int pack_invalid;
- int vtype = 0;
- uio_t auio;
- char uio_buf[ UIO_SIZEOF(1)];
+ struct vnode_attr *va;
+ kauth_action_t action;
+ ssize_t fixedsize;
+ char *va_name;
+ int proc_is64;
+ int error;
+ int return_valid;
+ int pack_invalid;
+ int vtype = 0;
+ uio_t auio;
+ char uio_buf[UIO_SIZEOF(1)];
+ // must be true for fork attributes to be used as new common attributes
+ const int use_fork = (options & FSOPT_ATTR_CMN_EXTENDED) != 0;
+
+ if (bufferSize < sizeof(uint32_t)) {
+ return ERANGE;
+ }
proc_is64 = proc_is64bit(vfs_context_proc(ctx));
if (segflg == UIO_USERSPACE) {
- if (proc_is64)
+ if (proc_is64) {
segflg = UIO_USERSPACE64;
- else
+ } else {
segflg = UIO_USERSPACE32;
+ }
}
auio = uio_createwithbuffer(1, 0, segflg, UIO_READ,
- &uio_buf[0], sizeof(uio_buf));
+ &uio_buf[0], sizeof(uio_buf));
uio_addiov(auio, attributeBuffer, bufferSize);
- VATTR_INIT(&va);
+ va = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), Z_WAITOK);
+ VATTR_INIT(va);
va_name = NULL;
if (alp->bitmapcount != ATTR_BIT_MAP_COUNT) {
}
VFS_DEBUG(ctx, vp, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
- vp, p->p_comm, alp->commonattr, alp->volattr, alp->fileattr, alp->dirattr, alp->forkattr,
+ vp, vfs_context_proc(ctx)->p_comm, alp->commonattr, alp->volattr, alp->fileattr, alp->dirattr, alp->forkattr,
(options & FSOPT_NOFOLLOW) ? "no":"", vp->v_name);
#if CONFIG_MACF
error = mac_vnode_check_getattrlist(ctx, vp, alp);
- if (error)
+ if (error) {
goto out;
+ }
#endif /* MAC */
/*
- * It is legal to request volume or file attributes,
- * but not both.
+ * It is legal to request volume or file attributes, but not both.
+ *
+ * 26903449 fork attributes can also be requested, but only if they're
+ * interpreted as new, common attributes
*/
if (alp->volattr) {
- if (alp->fileattr || alp->dirattr || alp->forkattr) {
+ if (alp->fileattr || alp->dirattr || (alp->forkattr && !use_fork)) {
error = EINVAL;
- VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes");
+ VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: mixed volume/file/directory attributes");
goto out;
}
/* handle volume attribute request */
error = getvolattrlist(ctx, vp, alp, attributeBuffer,
- bufferSize, options, segflg, proc_is64);
+ bufferSize, options, segflg, proc_is64);
goto out;
}
goto out;
}
+ /* common extended attributes require FSOPT_ATTR_CMN_EXTENDED option */
+ if (!(use_fork) && (alp->forkattr & ATTR_CMNEXT_VALIDMASK)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /* FSOPT_ATTR_CMN_EXTENDED requires forkattrs are not referenced */
+ if ((options & FSOPT_ATTR_CMN_EXTENDED) && (alp->forkattr & (ATTR_FORK_VALIDMASK))) {
+ error = EINVAL;
+ goto out;
+ }
+
/* Check for special packing semantics */
return_valid = (alp->commonattr & ATTR_CMN_RETURNED_ATTRS) ? 1 : 0;
pack_invalid = (options & FSOPT_PACK_INVAL_ATTRS) ? 1 : 0;
if (pack_invalid) {
/* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */
- if (!return_valid || alp->forkattr) {
+ if (!return_valid || (alp->forkattr && !use_fork)) {
error = EINVAL;
goto out;
}
/* Keep invalid attrs from being uninitialized */
- bzero(&va, sizeof (va));
+ bzero(va, sizeof(*va));
}
/* Pick up the vnode type. If the FS is bad and changes vnode types on us, we
/*
* Set up the vnode_attr structure and authorise.
*/
- if ((error = getattrlist_setupvattr(alp, &va, &fixedsize, &action, proc_is64, (vtype == VDIR))) != 0) {
+ if ((error = getattrlist_setupvattr(alp, va, &fixedsize, &action, proc_is64, (vtype == VDIR), use_fork)) != 0) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setup for request failed");
goto out;
}
}
- if (va.va_active != 0) {
- uint64_t va_active = va.va_active;
+ if (va->va_active != 0) {
+ uint64_t va_active = va->va_active;
/*
* If we're going to ask for va_name, allocate a buffer to point it at
*/
- if (VATTR_IS_ACTIVE(&va, va_name)) {
- MALLOC_ZONE(va_name, char *, MAXPATHLEN, M_NAMEI,
- M_WAITOK);
- if (va_name == NULL) {
- error = ENOMEM;
- VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate va_name buffer");
- goto out;
+ if (VATTR_IS_ACTIVE(va, va_name)) {
+ va_name = zalloc(ZV_NAMEI);
+ /*
+ * If we have an authoritative_name, prefer that name.
+ *
+ * N.B. Since authoritative_name implies this is coming from getattrlistbulk,
+ * we know the name is authoritative. For /dev/fd, we want to use the file
+ * descriptor as the name not the underlying name of the associate vnode in a
+ * particular file system.
+ */
+ if (authoritative_name) {
+ /* Don't ask the file system */
+ VATTR_CLEAR_ACTIVE(va, va_name);
+ strlcpy(va_name, authoritative_name, MAXPATHLEN);
}
}
- va.va_name = va_name;
+ va->va_name = authoritative_name ? NULL : va_name;
+
+ if (options & FSOPT_RETURN_REALDEV) {
+ va->va_vaflags |= VA_REALFSID;
+ }
/*
* Call the filesystem.
*/
- if ((error = vnode_getattr(vp, &va, ctx)) != 0) {
+ if ((error = vnode_getattr(vp, va, ctx)) != 0) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: filesystem returned %d", error);
goto out;
}
* opportunity to change the values of attributes
* retrieved.
*/
- error = mac_vnode_check_getattr(ctx, file_cred, vp, &va);
+ error = mac_vnode_check_getattr(ctx, file_cred, vp, va);
if (error) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: MAC framework returned %d", error);
goto out;
(void)file_cred;
#endif
- /*
- * If ATTR_CMN_NAME is not supported by filesystem and the
- * caller has provided a name, use that.
+ /*
+ * It we ask for the name, i.e., vname is non null and
+ * we have an authoritative name, then reset va_name is
+ * active and if needed set va_name is supported.
+ *
* A (buggy) filesystem may change fields which belong
* to us. We try to deal with that here as well.
*/
- va.va_active = va_active;
- if (alt_name && va_name &&
- !(VATTR_IS_SUPPORTED(&va, va_name))) {
- strlcpy(va_name, alt_name, MAXPATHLEN);
- VATTR_SET_SUPPORTED(&va, va_name);
+ va->va_active = va_active;
+ if (authoritative_name && va_name) {
+ VATTR_SET_ACTIVE(va, va_name);
+ if (!(VATTR_IS_SUPPORTED(va, va_name))) {
+ VATTR_SET_SUPPORTED(va, va_name);
+ }
}
- va.va_name = va_name;
+ va->va_name = va_name;
}
-
- error = vfs_attr_pack_internal(vp, auio, alp, options, &va, NULL, ctx,
+
+ error = vfs_attr_pack_internal(vp->v_mount, vp, auio, alp, options, va, NULL, ctx,
0, vtype, fixedsize);
out:
- if (va_name)
- FREE_ZONE(va_name, MAXPATHLEN, M_NAMEI);
- if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL))
- kauth_acl_free(va.va_acl);
+ if (va_name) {
+ zfree(ZV_NAMEI, va_name);
+ }
+ if (VATTR_IS_SUPPORTED(va, va_acl) && (va->va_acl != NULL)) {
+ kauth_acl_free(va->va_acl);
+ }
+ kheap_free(KHEAP_TEMP, va, sizeof(struct vnode_attr));
VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error);
- return(error);
+ return error;
}
int
fp = NULL;
error = 0;
- if ((error = file_vnode(uap->fd, &vp)) != 0)
- return (error);
+ if ((error = fp_get_ftype(p, uap->fd, DTYPE_VNODE, EINVAL, &fp)) != 0) {
+ return error;
+ }
+ vp = (struct vnode *)fp->fp_glob->fg_data;
- if ((error = fp_lookup(p, uap->fd, &fp, 0)) != 0 ||
- (error = vnode_getwithref(vp)) != 0)
+ if ((error = vnode_getwithref(vp)) != 0) {
goto out;
+ }
/*
* Fetch the attribute request.
*/
error = copyin(uap->alist, &al, sizeof(al));
- if (error)
- goto out;
+ if (error) {
+ goto out_vnode_put;
+ }
/* Default to using the vnode's name. */
error = getattrlist_internal(ctx, vp, &al, uap->attributeBuffer,
- uap->bufferSize, uap->options,
- (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : \
- UIO_USERSPACE32), NULL,
- fp->f_fglob->fg_cred);
+ uap->bufferSize, uap->options,
+ (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : \
+ UIO_USERSPACE32), NULL,
+ fp->fp_glob->fg_cred);
+out_vnode_put:
+ vnode_put(vp);
out:
- if (fp)
- fp_drop(p, uap->fd, fp, 0);
- if (vp)
- vnode_put(vp);
- file_drop(uap->fd);
+ fp_drop(p, uap->fd, fp, 0);
return error;
}
/*
* Look up the file.
*/
- if (!(options & FSOPT_NOFOLLOW))
+ if (!(options & FSOPT_NOFOLLOW)) {
nameiflags |= FOLLOW;
+ }
nameiflags |= AUDITVNPATH1;
NDINIT(&nd, LOOKUP, OP_GETATTR, nameiflags, pathsegflg,
error = nameiat(&nd, fd);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
vp = nd.ni_vp;
error = getattrlist_internal(ctx, vp, alp, attributeBuffer,
bufferSize, options, segflg, NULL, NOCRED);
-
+
/* Retain the namei reference until the getattrlist completes. */
nameidone(&nd);
vnode_put(vp);
- return (error);
+ return error;
}
int
* Fetch the attribute request.
*/
error = copyin(uap->alist, &al, sizeof(al));
- if (error)
+ if (error) {
return error;
+ }
- return (getattrlistat_internal(vfs_context_current(),
- CAST_USER_ADDR_T(uap->path), &al,
- CAST_USER_ADDR_T(uap->attributeBuffer), uap->bufferSize,
- (uint64_t)uap->options, segflg, segflg, AT_FDCWD));
+ return getattrlistat_internal(vfs_context_current(),
+ CAST_USER_ADDR_T(uap->path), &al,
+ CAST_USER_ADDR_T(uap->attributeBuffer), uap->bufferSize,
+ (uint64_t)uap->options, segflg, segflg, AT_FDCWD);
}
int
* Fetch the attribute request.
*/
error = copyin(uap->alist, &al, sizeof(al));
- if (error)
+ if (error) {
return error;
+ }
- return (getattrlistat_internal(vfs_context_current(),
- CAST_USER_ADDR_T(uap->path), &al,
- CAST_USER_ADDR_T(uap->attributeBuffer), uap->bufferSize,
- (uint64_t)uap->options, segflg, segflg, uap->fd));
+ return getattrlistat_internal(vfs_context_current(),
+ CAST_USER_ADDR_T(uap->path), &al,
+ CAST_USER_ADDR_T(uap->attributeBuffer), uap->bufferSize,
+ (uint64_t)uap->options, segflg, segflg, uap->fd);
}
/*
if (fvd->fv_eofflag) {
*eofflagp = 1;
if (fvd->fv_buf) {
- FREE(fvd->fv_buf, M_FD_DIRBUF);
+ kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz);
fvd->fv_buf = NULL;
}
return 0;
* not copied out to user space.
*/
if (!fvd->fv_buf) {
- MALLOC(fvd->fv_buf, caddr_t, rdirbufsiz, M_FD_DIRBUF, M_WAITOK);
+ fvd->fv_buf = kheap_alloc(KHEAP_DATA_BUFFERS, rdirbufsiz, Z_WAITOK);
+ fvd->fv_bufallocsiz = rdirbufsiz;
fvd->fv_bufdone = 0;
}
/* Save offsets */
fvd->fv_soff = fvd->fv_eoff;
fvd->fv_eoff = uio_offset(rdir_uio);
- /* Save eofflag state but don't return EOF for this time.*/
+ /* Save eofflag state but don't return EOF for this time.*/
fvd->fv_eofflag = eofflag;
eofflag = 0;
- /* Reset buffer parameters */
+ /* Reset buffer parameters */
fvd->fv_bufsiz = rdirbufused;
fvd->fv_bufdone = 0;
bzero(fvd->fv_buf + rdirbufused, rdirbufsiz - rdirbufused);
- /* Cache allocation size the Filesystem responded to */
- fvd->fv_bufallocsiz = rdirbufsiz;
} else if (!eofflag && (rdirbufsiz < FV_DIRBUF_MAX_SIZ)) {
/*
* Some Filesystems have higher requirements for the
* from VNOP_READDIR is ignored until at least FV_DIRBUF_MAX_SIZ
* has been attempted.
*/
- FREE(fvd->fv_buf, M_FD_DIRBUF);
- fvd->fv_buf = NULL;
+ kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz);
rdirbufsiz = 2 * rdirbufsiz;
fvd->fv_bufallocsiz = 0;
goto retry_alloc;
* time to free up directory entry buffer.
*/
if ((error || eofflag) && fvd->fv_buf) {
- FREE(fvd->fv_buf, M_FD_DIRBUF);
- fvd->fv_buf = NULL;
+ kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz);
+ if (error) {
+ fvd->fv_bufallocsiz = 0;
+ }
}
*eofflagp = eofflag;
- return (error);
+ return error;
}
/*
if (!fvd->fv_bufsiz) {
error = refill_fd_direntries(ctx, dvp, fvd, &eofflag);
if (error) {
- return (error);
+ return error;
}
if (eofflag) {
*eofflagp = eofflag;
- return (error);
+ return error;
}
}
*dpp = (struct direntry *)(fvd->fv_buf + fvd->fv_bufdone);
- return (error);
+ return error;
}
/*
{
size_t fsiz, vsiz;
struct _attrlist_buf ab;
- int namelen;
+ size_t namelen;
kauth_action_t action;
struct attrlist al;
int needs_error_attr = (alp->commonattr & ATTR_CMN_ERROR);
fsiz = 0;
(void)getattrlist_setupvattr(&al, NULL, (ssize_t *)&fsiz,
&action, proc_is64bit(vfs_context_proc(ctx)),
- (vnode_vtype(vp) == VDIR));
+ (vnode_vtype(vp) == VDIR), (options & FSOPT_ATTR_CMN_EXTENDED));
namelen = strlen(namebuf);
vsiz = namelen + 1;
ab.needed = fsiz + vsiz;
/* Fill in the size needed */
- *((uint32_t *)ab.base) = ab.needed;
+ *((uint32_t *)ab.base) = (uint32_t)ab.needed;
if (ab.needed > (ssize_t)kern_attr_buf_siz) {
goto out;
}
* Initialise the value for ATTR_CMN_RETURNED_ATTRS and leave space
* Leave space for filling in its value here at the end.
*/
- bzero(&ab.actual, sizeof (ab.actual));
- ab.fixedcursor += sizeof (attribute_set_t);
+ bzero(&ab.actual, sizeof(ab.actual));
+ ab.fixedcursor += sizeof(attribute_set_t);
ab.allocated = ab.needed;
* ATTR_CMN_NAME.
*/
ab.actual.commonattr |= ATTR_CMN_NAME | ATTR_CMN_RETURNED_ATTRS;
- bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual));
+ bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof(ab.actual));
out:
return;
}
*eofflagp = 0;
if (uio_iovcnt(auio) > 1) {
- return (EINVAL);
+ return EINVAL;
}
/*
kern_attr_buf_siz = ATTR_MAX_BUFFER;
} else if (kern_attr_buf_siz == 0) {
/* Nothing to do */
- return (error);
+ return error;
}
- MALLOC(kern_attr_buf, caddr_t, kern_attr_buf_siz, M_TEMP, M_WAITOK);
+ kern_attr_buf = kheap_alloc(KHEAP_TEMP, kern_attr_buf_siz, Z_WAITOK);
while (uio_resid(auio) > (user_ssize_t)MIN_BUF_SIZE_REQUIRED) {
struct direntry *dp;
*/
if (dp->d_name[dp->d_namlen] != '\0') {
if (!max_path_name_buf) {
- MALLOC(max_path_name_buf, caddr_t, MAXPATHLEN,
- M_TEMP, M_WAITOK);
+ max_path_name_buf = zalloc_flags(ZV_NAMEI, Z_WAITOK);
}
bcopy(dp->d_name, max_path_name_buf, dp->d_namlen);
max_path_name_buf[dp->d_namlen] = '\0';
/*
* We have an iocount on the directory already.
- *
+ *
* Note that we supply NOCROSSMOUNT to the namei call as we attempt to acquire
* a vnode for this particular entry. This is because the native call will
* (likely) attempt to emit attributes based on its own metadata in order to avoid
* creating vnodes where posssible. If the native call is not going to walk
* up the vnode mounted-on chain in order to find the top-most mount point, then we
- * should not either in this emulated readdir+getattrlist() approach. We
+ * should not either in this emulated readdir+getattrlist() approach. We
* will be responsible for setting DIR_MNTSTATUS_MNTPOINT on that directory that
- * contains a mount point.
+ * contains a mount point.
*/
- NDINIT(&nd, LOOKUP, OP_GETATTR, (AUDITVNPATH1 | USEDVP | NOCROSSMOUNT),
+ NDINIT(&nd, LOOKUP, OP_GETATTR, (AUDITVNPATH1 | USEDVP | NOCROSSMOUNT),
UIO_SYSSPACE, CAST_USER_ADDR_T(name_buffer), ctx);
nd.ni_dvp = dvp;
error = getattrlist_internal(ctx, vp, &al,
CAST_USER_ADDR_T(kern_attr_buf), kern_attr_buf_siz,
- options | FSOPT_REPORT_FULLSIZE, UIO_SYSSPACE,
+ options | FSOPT_REPORT_FULLSIZE, UIO_SYSSPACE,
CAST_DOWN_EXPLICIT(char *, name_buffer),
NOCRED);
entlen += pad_bytes;
}
*((uint32_t *)kern_attr_buf) = (uint32_t)entlen;
- error = uiomove(kern_attr_buf, min(entlen, kern_attr_buf_siz),
+ error = uiomove(kern_attr_buf, min((int)entlen, (int)kern_attr_buf_siz),
auio);
if (error) {
}
if (max_path_name_buf) {
- FREE(max_path_name_buf, M_TEMP);
+ zfree(ZV_NAMEI, max_path_name_buf);
}
/*
* At this point, kern_attr_buf is always allocated
*/
- FREE(kern_attr_buf, M_TEMP);
+ kheap_free(KHEAP_TEMP, kern_attr_buf, kern_attr_buf_siz);
/*
* Always set the offset to the last succesful offset
*/
uio_setoffset(auio, fvd->fv_eoff);
- return (error);
+ return error;
}
+/* common attributes that only require KAUTH_VNODE_LIST_DIRECTORY */
+#define LIST_DIR_ATTRS (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE | \
+ ATTR_CMN_FILEID | ATTR_CMN_RETURNED_ATTRS | \
+ ATTR_CMN_ERROR)
+
/*
- *int getattrlistbulk(int dirfd, struct attrlist *alist, void *attributeBuffer,
+ * int getattrlistbulk(int dirfd, struct attrlist *alist, void *attributeBuffer,
* size_t bufferSize, uint64_t options)
*
* Gets directory entries alongwith their attributes in the same way
getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval)
{
struct attrlist al;
- vnode_t dvp;
+ vnode_t dvp = NULLVP;
struct fileproc *fp;
struct fd_vn_data *fvdata;
vfs_context_t ctx;
+ uthread_t ut;
enum uio_seg segflg;
int count;
uio_t auio = NULL;
- char uio_buf[ UIO_SIZEOF(1) ];
+ char uio_buf[UIO_SIZEOF(1)];
kauth_action_t action;
int eofflag;
uint64_t options;
*retval = 0;
error = fp_getfvp(p, uap->dirfd, &fp, &dvp);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
count = 0;
fvdata = NULL;
eofflag = 0;
ctx = vfs_context_current();
+ ut = get_bsdthread_info(current_thread());
segflg = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
- if ((fp->f_fglob->fg_flag & FREAD) == 0) {
+ if ((fp->fp_glob->fg_flag & FREAD) == 0) {
/*
- AUDIT_ARG(vnpath_withref, dvp, ARG_VNODE1);
- */
+ * AUDIT_ARG(vnpath_withref, dvp, ARG_VNODE1);
+ */
error = EBADF;
+ dvp = NULLVP;
goto out;
}
if (uap->options & FSOPT_LIST_SNAPSHOT) {
vnode_t snapdvp;
- if (!vfs_context_issuser(ctx)) {
- error = EPERM;
- goto out;
- }
-
if (!vnode_isvroot(dvp)) {
error = EINVAL;
goto out;
/* switch directory to snapshot directory */
error = vnode_get_snapdir(dvp, &snapdvp, ctx);
- if (error)
+ if (error) {
goto out;
+ }
vnode_put(dvp);
dvp = snapdvp;
}
#if CONFIG_MACF
error = mac_file_check_change_offset(vfs_context_ucred(ctx),
- fp->f_fglob);
- if (error)
+ fp->fp_glob);
+ if (error) {
goto out;
+ }
#endif
/*
* XXX : Audit Support
- *AUDIT_ARG(vnpath, dvp, ARG_VNODE1);
+ * AUDIT_ARG(vnpath, dvp, ARG_VNODE1);
*/
options = uap->options | FSOPT_ATTR_CMN_EXTENDED;
#endif /* MAC */
/*
- * If the only item requested is file names, we can let that past with
- * just LIST_DIRECTORY. If they want any other attributes, that means
- * they need SEARCH as well.
+ * Requested attributes that are available in the direntry struct, with the addition
+ * of ATTR_CMN_RETURNED_ATTRS and ATTR_CMN_ERROR, can be let past with just LIST_DIRECTORY.
+ * Any other requested attributes require SEARCH as well.
*/
action = KAUTH_VNODE_LIST_DIRECTORY;
- if ((al.commonattr & ~ATTR_CMN_NAME) || al.fileattr || al.dirattr)
+ if ((al.commonattr & ~LIST_DIR_ATTRS) || al.fileattr || al.dirattr) {
action |= KAUTH_VNODE_SEARCH;
-
+ }
+
error = vnode_authorize(dvp, NULL, action, ctx);
if (error) {
goto out;
}
- fvdata = (struct fd_vn_data *)fp->f_fglob->fg_vn_data;
+ fvdata = (struct fd_vn_data *)fp->fp_glob->fg_vn_data;
if (!fvdata) {
panic("Directory expected to have fg_vn_data");
}
* traversal needs to be restarted (Any existing state in the
* directory buffer is removed as well).
*/
- if (!fp->f_fglob->fg_offset) {
+ if (!fp->fp_glob->fg_offset) {
fvdata->fv_offset = 0;
- if (fvdata->fv_buf)
- FREE(fvdata->fv_buf, M_FD_DIRBUF);
- fvdata->fv_buf = NULL;
+ kheap_free(KHEAP_DATA_BUFFERS, fvdata->fv_buf,
+ fvdata->fv_bufallocsiz);
fvdata->fv_bufsiz = 0;
fvdata->fv_bufdone = 0;
fvdata->fv_soff = 0;
(ATTR_CMN_UUID | ATTR_CMN_GRPUUID | ATTR_CMN_EXTENDED_SECURITY)) ||
!(al.commonattr & ATTR_CMN_OBJTYPE)) {
error = ENOTSUP;
- } else {
- struct vnode_attr va;
+ } else {
+ struct vnode_attr *va;
char *va_name;
if (fvdata->fv_eofflag && !fvdata->fv_buf) {
eofflag = 0;
count = 0;
- VATTR_INIT(&va);
- MALLOC(va_name, char *, MAXPATHLEN, M_TEMP,
- M_WAITOK | M_ZERO);
- va.va_name = va_name;
+ va = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), Z_WAITOK);
- (void)getattrlist_setupvattr_all(&al, &va, VNON, NULL,
- IS_64BIT_PROCESS(p));
+ VATTR_INIT(va);
+ va_name = zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO);
+ va->va_name = va_name;
- error = VNOP_GETATTRLISTBULK(dvp, &al, &va, auio, NULL,
+ (void)getattrlist_setupvattr_all(&al, va, VNON, NULL,
+ IS_64BIT_PROCESS(p), (uap->options & FSOPT_ATTR_CMN_EXTENDED));
+
+ /*
+ * Set UT_KERN_RAGE_VNODES to cause all vnodes created by the
+ * filesystem to be rapidly aged.
+ */
+ ut->uu_flag |= UT_KERN_RAGE_VNODES;
+ error = VNOP_GETATTRLISTBULK(dvp, &al, va, auio, NULL,
options, &eofflag, &count, ctx);
+ ut->uu_flag &= ~UT_KERN_RAGE_VNODES;
- FREE(va_name, M_TEMP);
+ zfree(ZV_NAMEI, va_name);
+ kheap_free(KHEAP_TEMP, va, sizeof(struct vnode_attr));
/*
* cache state of eofflag.
eofflag = 0;
count = 0;
+ ut->uu_flag |= UT_KERN_RAGE_VNODES;
error = readdirattr(dvp, fvdata, auio, &al, options,
&count, &eofflag, ctx);
+ ut->uu_flag &= ~UT_KERN_RAGE_VNODES;
}
if (count) {
fvdata->fv_offset = uio_offset(auio);
- fp->f_fglob->fg_offset = fvdata->fv_offset;
+ fp->fp_glob->fg_offset = fvdata->fv_offset;
*retval = count;
error = 0;
} else if (!error && !eofflag) {
file_drop(uap->dirfd);
- return (error);
+ return error;
}
static int
attrlist_unpack_fixed(char **cursor, char *end, void *buf, ssize_t size)
{
/* make sure we have enough source data */
- if ((*cursor) + size > end)
- return(EINVAL);
+ if ((*cursor) + size > end) {
+ return EINVAL;
+ }
bcopy(*cursor, buf, size);
*cursor += size;
- return(0);
+ return 0;
}
-#define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
-#define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0)
-#define ATTR_UNPACK_TIME(v, is64) \
- do { \
- if (is64) { \
- struct user64_timespec us; \
- ATTR_UNPACK(us); \
- v.tv_sec = us.tv_sec; \
- v.tv_nsec = us.tv_nsec; \
- } else { \
- struct user32_timespec us; \
- ATTR_UNPACK(us); \
- v.tv_sec = us.tv_sec; \
- v.tv_nsec = us.tv_nsec; \
- } \
+#define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0);
+#define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = (typeof(v))_f;} while(0)
+#define ATTR_UNPACK_TIME(v, is64) \
+ do { \
+ if (is64) { \
+ struct user64_timespec us; \
+ ATTR_UNPACK(us); \
+ v.tv_sec = (unsigned long)us.tv_sec; \
+ v.tv_nsec = (long)us.tv_nsec; \
+ } else { \
+ struct user32_timespec us; \
+ ATTR_UNPACK(us); \
+ v.tv_sec = us.tv_sec; \
+ v.tv_nsec = us.tv_nsec; \
+ } \
} while(0)
struct attrlist al;
struct vnode_attr va;
struct attrreference ar;
- kauth_action_t action;
- char *user_buf, *cursor, *bufend, *fndrinfo, *cp, *volname;
- int proc_is64, error;
- uint32_t nace;
+ kauth_action_t action;
+ char *user_buf, *cursor, *bufend, *fndrinfo, *cp, *volname;
+ int proc_is64, error;
+ uint32_t nace;
kauth_filesec_t rfsec;
user_buf = NULL;
error = 0;
proc_is64 = proc_is64bit(p);
VATTR_INIT(&va);
-
+
/*
* Fetch the attribute set and validate.
*/
- if ((error = copyin(uap->alist, (caddr_t) &al, sizeof (al))))
+ if ((error = copyin(uap->alist, (caddr_t) &al, sizeof(al)))) {
goto out;
+ }
if (al.bitmapcount != ATTR_BIT_MAP_COUNT) {
error = EINVAL;
goto out;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
VFS_DEBUG(ctx, vp, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
vp, p->p_comm, al.commonattr, al.volattr, al.fileattr, al.dirattr, al.forkattr,
(uap->options & FSOPT_NOFOLLOW) ? "no":"", vp->v_name);
/*
* If the caller's bitmaps indicate that there are no attributes to set,
- * then exit early. In particular, we want to avoid the MALLOC below
- * since the caller's bufferSize could be zero, and MALLOC of zero bytes
- * returns a NULL pointer, which would cause setattrlist to return ENOMEM.
+ * then exit early.
*/
if (al.commonattr == 0 &&
- (al.volattr & ~ATTR_VOL_INFO) == 0 &&
- al.dirattr == 0 &&
- al.fileattr == 0 &&
- al.forkattr == 0) {
+ (al.volattr & ~ATTR_VOL_INFO) == 0 &&
+ al.dirattr == 0 &&
+ al.fileattr == 0 &&
+ al.forkattr == 0) {
error = 0;
goto out;
}
-
+
/*
* Make the naive assumption that the caller has supplied a reasonable buffer
* size. We could be more careful by pulling in the fixed-size region, checking
error = ENOMEM;
goto out;
}
- MALLOC(user_buf, char *, uap->bufferSize, M_TEMP, M_WAITOK);
+ user_buf = kheap_alloc(KHEAP_DATA_BUFFERS, uap->bufferSize, Z_WAITOK);
if (user_buf == NULL) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap->bufferSize);
error = ENOMEM;
#if CONFIG_MACF
error = mac_vnode_check_setattrlist(ctx, vp, &al);
- if (error)
+ if (error) {
goto out;
+ }
#endif /* MAC */
/*
ATTR_UNPACK(va.va_flags);
VATTR_SET_ACTIVE(&va, va_flags);
#if CONFIG_MACF
- if ((error = mac_vnode_check_setflags(ctx, vp, va.va_flags)) != 0)
+ if ((error = mac_vnode_check_setflags(ctx, vp, va.va_flags)) != 0) {
goto out;
+ }
#endif
}
if (al.commonattr & ATTR_CMN_EXTENDED_SECURITY) {
-
/*
* We are (for now) passed a kauth_filesec_t, but all we want from
* it is the ACL.
cp += ar.attr_dataoffset;
rfsec = (kauth_filesec_t)cp;
- if (((((char *)rfsec) + KAUTH_FILESEC_SIZE(0)) > bufend) || /* no space for acl */
+ if (((((char *)rfsec) + KAUTH_FILESEC_SIZE(0)) > bufend) || /* no space for acl */
(rfsec->fsec_magic != KAUTH_FILESEC_MAGIC) || /* bad magic */
(KAUTH_FILESEC_COPYSIZE(rfsec) != ar.attr_length) || /* size does not match */
- ((cp + KAUTH_FILESEC_COPYSIZE(rfsec)) > bufend)) { /* ACEs overrun buffer */
+ ((cp + KAUTH_FILESEC_COPYSIZE(rfsec)) > bufend)) { /* ACEs overrun buffer */
error = EINVAL;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad ACL supplied", ar.attr_length);
goto out;
}
nace = rfsec->fsec_entrycount;
- if (nace == KAUTH_FILESEC_NOACL)
+ if (nace == KAUTH_FILESEC_NOACL) {
nace = 0;
- if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */
+ }
+ if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */
error = EINVAL;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad ACL supplied");
goto out;
/* deleting ACL */
VATTR_SET(&va, va_acl, NULL);
} else {
-
- if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */
+ if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */
error = EINVAL;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: supplied ACL is too large");
goto out;
ATTR_UNPACK(va.va_guuid);
VATTR_SET_ACTIVE(&va, va_guuid);
}
+ if (al.commonattr & ATTR_CMN_ADDEDTIME) {
+ ATTR_UNPACK_TIME(va.va_addedtime, proc_is64);
+ VATTR_SET_ACTIVE(&va, va_addedtime);
+ }
+ /* Support setattrlist of data protection class */
+ if (al.commonattr & ATTR_CMN_DATA_PROTECT_FLAGS) {
+ ATTR_UNPACK(va.va_dataprotect_class);
+ VATTR_SET_ACTIVE(&va, va_dataprotect_class);
+ }
/* volume */
if (al.volattr & ATTR_VOL_INFO) {
if (al.volattr & ATTR_VOL_NAME) {
volname = cursor;
- ATTR_UNPACK(ar);
+ ATTR_UNPACK(ar);
/* attr_length cannot be 0! */
if ((ar.attr_dataoffset < 0) || (ar.attr_length == 0) ||
- (ar.attr_length > uap->bufferSize) ||
- (uap->bufferSize - ar.attr_length < (unsigned)ar.attr_dataoffset)) {
+ (ar.attr_length > uap->bufferSize) ||
+ (uap->bufferSize - ar.attr_length < (unsigned)ar.attr_dataoffset)) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad offset supplied (2) ", ar.attr_dataoffset);
error = EINVAL;
goto out;
#if CONFIG_MACF
mac_vnode_notify_setattrlist(ctx, vp, &al);
- if (VATTR_IS_ACTIVE(&va, va_flags))
+ if (VATTR_IS_ACTIVE(&va, va_flags)) {
mac_vnode_notify_setflags(ctx, vp, va.va_flags);
+ }
#endif
/*
if (vp->v_tag == VT_HFS) {
#define HFS_SET_BOOT_INFO (FCNTL_FS_SPECIFIC_BASE + 0x00005)
error = VNOP_IOCTL(vp, HFS_SET_BOOT_INFO, (caddr_t)fndrinfo, 0, ctx);
- if (error != 0)
+ if (error != 0) {
goto out;
+ }
} else {
/* XXX should never get here */
}
}
}
- /*
+ /*
* Set the volume name, if we have one
*/
- if (volname != NULL)
- {
+ if (volname != NULL) {
struct vfs_attr vs;
-
+
VFSATTR_INIT(&vs);
-
- vs.f_vol_name = volname; /* References the setattrlist buffer directly */
+
+ vs.f_vol_name = volname; /* References the setattrlist buffer directly */
VFSATTR_WANTED(&vs, f_vol_name);
-
+
#if CONFIG_MACF
error = mac_mount_check_setattr(ctx, vp->v_mount, &vs);
- if (error != 0)
+ if (error != 0) {
goto out;
+ }
#endif
if ((error = vfs_setattr(vp->v_mount, &vs, ctx)) != 0) {
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setting volume name failed");
goto out;
}
-
+
if (!VFSATTR_ALL_SUPPORTED(&vs)) {
error = EINVAL;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not set volume name");
}
/* all done and successful */
-
+
out:
- if (user_buf != NULL)
- FREE(user_buf, M_TEMP);
+ kheap_free(KHEAP_DATA_BUFFERS, user_buf, uap->bufferSize);
VFS_DEBUG(ctx, vp, "ATTRLIST - set returning %d", error);
- return(error);
+ return error;
}
int
{
struct vfs_context *ctx;
struct nameidata nd;
- vnode_t vp = NULL;
- u_long nameiflags;
+ vnode_t vp = NULL;
+ uint32_t nameiflags;
int error = 0;
ctx = vfs_context_current();
* Look up the file.
*/
nameiflags = AUDITVNPATH1;
- if ((uap->options & FSOPT_NOFOLLOW) == 0)
+ if ((uap->options & FSOPT_NOFOLLOW) == 0) {
nameiflags |= FOLLOW;
+ }
NDINIT(&nd, LOOKUP, OP_SETATTR, nameiflags, UIO_USERSPACE, uap->path, ctx);
- if ((error = namei(&nd)) != 0)
+ if ((error = namei(&nd)) != 0) {
goto out;
+ }
vp = nd.ni_vp;
nameidone(&nd);
error = setattrlist_internal(vp, uap, p, ctx);
out:
- if (vp != NULL)
+ if (vp != NULL) {
+ vnode_put(vp);
+ }
+ return error;
+}
+
+int
+setattrlistat(proc_t p, struct setattrlistat_args *uap, __unused int32_t *retval)
+{
+ struct setattrlist_args ap;
+ struct vfs_context *ctx;
+ struct nameidata nd;
+ vnode_t vp = NULLVP;
+ uint32_t nameiflags;
+ int error;
+
+ ctx = vfs_context_current();
+
+ AUDIT_ARG(fd, uap->fd);
+ /*
+ * Look up the file.
+ */
+ nameiflags = AUDITVNPATH1;
+ if (!(uap->options & FSOPT_NOFOLLOW)) {
+ nameiflags |= FOLLOW;
+ }
+ NDINIT(&nd, LOOKUP, OP_SETATTR, nameiflags, UIO_USERSPACE, uap->path, ctx);
+ if ((error = nameiat(&nd, uap->fd)) != 0) {
+ goto out;
+ }
+ vp = nd.ni_vp;
+ nameidone(&nd);
+
+ ap.path = 0;
+ ap.alist = uap->alist;
+ ap.attributeBuffer = uap->attributeBuffer;
+ ap.bufferSize = uap->bufferSize;
+ ap.options = uap->options;
+
+ error = setattrlist_internal(vp, &ap, p, ctx);
+out:
+ if (vp) {
vnode_put(vp);
+ }
return error;
}
fsetattrlist(proc_t p, struct fsetattrlist_args *uap, __unused int32_t *retval)
{
struct vfs_context *ctx;
- vnode_t vp = NULL;
- int error;
+ vnode_t vp = NULL;
+ int error;
struct setattrlist_args ap;
ctx = vfs_context_current();
- if ((error = file_vnode(uap->fd, &vp)) != 0)
- return (error);
+ if ((error = file_vnode(uap->fd, &vp)) != 0) {
+ return error;
+ }
if ((error = vnode_getwithref(vp)) != 0) {
file_drop(uap->fd);
- return(error);
+ return error;
}
ap.path = 0;
error = setattrlist_internal(vp, &ap, p, ctx);
file_drop(uap->fd);
- if (vp != NULL)
+ if (vp != NULL) {
vnode_put(vp);
+ }
return error;
}
-