/* * Copyright (c) 2024 Apple Inc. All rights reserved. * * @APPLE_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 * compliance with the License. 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include static int __statfs_ext_default(const char *path, int fd, struct statfs *buf) { int ret = 0; if (path) { ret = statfs(path, buf); } else { ret = fstatfs(fd, buf); } return ret; } static int __statfs_ext_noblock(const char *path, int fd, struct statfs *buf) { int ret = 0; char *ptr; struct { uint32_t size; attribute_set_t f_attrs; fsid_t f_fsid; uint32_t f_type; attrreference_t f_mntonname; uint32_t f_flags; attrreference_t f_mntfromname; uint32_t f_flags_ext; attrreference_t f_fstypename; uint32_t f_fssubtype; uid_t f_owner; char f_mntonname_buf[MAXPATHLEN]; char f_mntfromname_buf[MAXPATHLEN]; char f_fstypename_buf[MFSTYPENAMELEN]; } __attribute__((aligned(4), packed)) *attrbuf; struct attrlist al = { .bitmapcount = ATTR_BIT_MAP_COUNT, .commonattr = ATTR_CMN_FSID | ATTR_CMN_RETURNED_ATTRS, .volattr = ATTR_VOL_INFO | ATTR_VOL_FSTYPE | ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_FSTYPENAME | ATTR_VOL_FSSUBTYPE | ATTR_VOL_MOUNTEXTFLAGS | ATTR_VOL_OWNER, }; attrbuf = malloc(sizeof(*attrbuf)); if (attrbuf == NULL) { errno = ENOMEM; return -1; } bzero(attrbuf, sizeof(*attrbuf)); if (path) { ret = getattrlist(path, &al, attrbuf, sizeof(*attrbuf), FSOPT_NOFOLLOW | FSOPT_RETURN_REALDEV); } else { ret = fgetattrlist(fd, &al, attrbuf, sizeof(*attrbuf), FSOPT_RETURN_REALDEV); } if (ret < 0) { goto out; } /* Update user structure */ if (attrbuf->f_attrs.commonattr & ATTR_CMN_FSID) { buf->f_fsid = attrbuf->f_fsid; } if (attrbuf->f_attrs.volattr & ATTR_VOL_OWNER) { buf->f_owner = attrbuf->f_owner; } if (attrbuf->f_attrs.volattr & ATTR_VOL_FSTYPE) { buf->f_type = attrbuf->f_type; } if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTFLAGS) { buf->f_flags = attrbuf->f_flags; } if (attrbuf->f_attrs.volattr & ATTR_VOL_FSSUBTYPE) { buf->f_fssubtype = attrbuf->f_fssubtype; } if (attrbuf->f_attrs.volattr & ATTR_VOL_FSTYPENAME) { ptr = (char *)&attrbuf->f_fstypename + attrbuf->f_fstypename.attr_dataoffset; strlcpy(buf->f_fstypename, ptr, sizeof(buf->f_fstypename)); } if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTPOINT) { ptr = (char *)&attrbuf->f_mntonname + attrbuf->f_mntonname.attr_dataoffset; strlcpy(buf->f_mntonname, ptr, sizeof(buf->f_mntonname)); } if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTEDDEVICE) { ptr = (char *)&attrbuf->f_mntfromname + attrbuf->f_mntfromname.attr_dataoffset; strlcpy(buf->f_mntfromname, ptr, sizeof(buf->f_mntfromname)); } if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTEXTFLAGS) { buf->f_flags_ext = attrbuf->f_flags_ext; } out: free(attrbuf); return ret; } static int __statfs_ext_impl(const char *path, int fd, struct statfs *buf, int flags) { int ret = 0; bzero(buf, sizeof(struct statfs)); /* Check for invalid flags */ if (flags & ~(STATFS_EXT_NOBLOCK)) { errno = EINVAL; return -1; } /* Retrieve filesystem statistics with extended options */ if (flags & STATFS_EXT_NOBLOCK) { ret = __statfs_ext_noblock(path, fd, buf); } /* * Fall back to statfs()/fstatfs() if: * 1. No options are provided. * 2. __statfs_ext_noblock() returns EINVAL. */ if ((flags == 0) || (ret == -1 && errno == EINVAL)) { ret = __statfs_ext_default(path, fd, buf); } return ret; } int fstatfs_ext(int fd, struct statfs *buf, int flags) { /* fstatfs() sanity checks */ if (fd < 0) { errno = EBADF; return -1; } if (buf == NULL) { errno = EFAULT; return -1; } return __statfs_ext_impl(NULL, fd, buf, flags); } int statfs_ext(const char *path, struct statfs *buf, int flags) { /* statfs() sanity checks */ if (path == NULL) { errno = EFAULT; return -1; } if (buf == NULL) { errno = EFAULT; return -1; } return __statfs_ext_impl(path, -1, buf, flags); }