xref: /xnu-11417.140.69/libsyscall/wrappers/statfs_ext.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * Copyright (c) 2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <strings.h>
28 #include <sys/attr.h>
29 #include <sys/param.h>
30 #include <sys/mount.h>
31 
32 static int
__statfs_ext_default(const char * path,int fd,struct statfs * buf)33 __statfs_ext_default(const char *path, int fd, struct statfs *buf)
34 {
35 	int ret = 0;
36 
37 	if (path) {
38 		ret = statfs(path, buf);
39 	} else {
40 		ret = fstatfs(fd, buf);
41 	}
42 
43 	return ret;
44 }
45 
46 static int
__statfs_ext_noblock(const char * path,int fd,struct statfs * buf)47 __statfs_ext_noblock(const char *path, int fd, struct statfs *buf)
48 {
49 	int ret = 0;
50 	char *ptr;
51 
52 	struct {
53 		uint32_t        size;
54 		attribute_set_t f_attrs;
55 		fsid_t          f_fsid;
56 		uint32_t        f_type;
57 		attrreference_t f_mntonname;
58 		uint32_t        f_flags;
59 		attrreference_t f_mntfromname;
60 		uint32_t        f_flags_ext;
61 		attrreference_t f_fstypename;
62 		uint32_t        f_fssubtype;
63 		uid_t           f_owner;
64 		char            f_mntonname_buf[MAXPATHLEN];
65 		char            f_mntfromname_buf[MAXPATHLEN];
66 		char            f_fstypename_buf[MFSTYPENAMELEN];
67 	} __attribute__((aligned(4), packed)) *attrbuf;
68 
69 	struct attrlist al = {
70 		.bitmapcount = ATTR_BIT_MAP_COUNT,
71 		.commonattr = ATTR_CMN_FSID | ATTR_CMN_RETURNED_ATTRS,
72 		.volattr =  ATTR_VOL_INFO | ATTR_VOL_FSTYPE | ATTR_VOL_MOUNTPOINT |
73 	    ATTR_VOL_MOUNTFLAGS | ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_FSTYPENAME |
74 	    ATTR_VOL_FSSUBTYPE | ATTR_VOL_MOUNTEXTFLAGS | ATTR_VOL_OWNER,
75 	};
76 
77 	attrbuf = malloc(sizeof(*attrbuf));
78 	if (attrbuf == NULL) {
79 		errno = ENOMEM;
80 		return -1;
81 	}
82 	bzero(attrbuf, sizeof(*attrbuf));
83 
84 	if (path) {
85 		ret = getattrlist(path, &al, attrbuf, sizeof(*attrbuf), FSOPT_NOFOLLOW | FSOPT_RETURN_REALDEV);
86 	} else {
87 		ret = fgetattrlist(fd, &al, attrbuf, sizeof(*attrbuf), FSOPT_RETURN_REALDEV);
88 	}
89 
90 	if (ret < 0) {
91 		goto out;
92 	}
93 
94 	/* Update user structure */
95 	if (attrbuf->f_attrs.commonattr & ATTR_CMN_FSID) {
96 		buf->f_fsid = attrbuf->f_fsid;
97 	}
98 	if (attrbuf->f_attrs.volattr & ATTR_VOL_OWNER) {
99 		buf->f_owner = attrbuf->f_owner;
100 	}
101 	if (attrbuf->f_attrs.volattr & ATTR_VOL_FSTYPE) {
102 		buf->f_type = attrbuf->f_type;
103 	}
104 	if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTFLAGS) {
105 		buf->f_flags = attrbuf->f_flags;
106 	}
107 	if (attrbuf->f_attrs.volattr & ATTR_VOL_FSSUBTYPE) {
108 		buf->f_fssubtype = attrbuf->f_fssubtype;
109 	}
110 	if (attrbuf->f_attrs.volattr & ATTR_VOL_FSTYPENAME) {
111 		ptr = (char *)&attrbuf->f_fstypename + attrbuf->f_fstypename.attr_dataoffset;
112 		strlcpy(buf->f_fstypename, ptr, sizeof(buf->f_fstypename));
113 	}
114 	if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTPOINT) {
115 		ptr = (char *)&attrbuf->f_mntonname + attrbuf->f_mntonname.attr_dataoffset;
116 		strlcpy(buf->f_mntonname, ptr, sizeof(buf->f_mntonname));
117 	}
118 	if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTEDDEVICE) {
119 		ptr = (char *)&attrbuf->f_mntfromname + attrbuf->f_mntfromname.attr_dataoffset;
120 		strlcpy(buf->f_mntfromname, ptr, sizeof(buf->f_mntfromname));
121 	}
122 	if (attrbuf->f_attrs.volattr & ATTR_VOL_MOUNTEXTFLAGS) {
123 		buf->f_flags_ext = attrbuf->f_flags_ext;
124 	}
125 
126 out:
127 	free(attrbuf);
128 	return ret;
129 }
130 
131 static int
__statfs_ext_impl(const char * path,int fd,struct statfs * buf,int flags)132 __statfs_ext_impl(const char *path, int fd, struct statfs *buf, int flags)
133 {
134 	int ret = 0;
135 
136 	bzero(buf, sizeof(struct statfs));
137 
138 	/* Check for invalid flags */
139 	if (flags & ~(STATFS_EXT_NOBLOCK)) {
140 		errno = EINVAL;
141 		return -1;
142 	}
143 
144 	/* Simply wrap statfs() or fstatfs() if no option is provided */
145 	if (flags == 0) {
146 		return __statfs_ext_default(path, fd, buf);
147 	}
148 
149 	/* Retrieve filesystem statistics with extended options */
150 	if (flags & STATFS_EXT_NOBLOCK) {
151 		ret = __statfs_ext_noblock(path, fd, buf);
152 	}
153 
154 	return ret;
155 }
156 
157 int
fstatfs_ext(int fd,struct statfs * buf,int flags)158 fstatfs_ext(int fd, struct statfs *buf, int flags)
159 {
160 	/* fstatfs() sanity checks */
161 	if (fd < 0) {
162 		errno = EBADF;
163 		return -1;
164 	}
165 	if (buf == NULL) {
166 		errno = EFAULT;
167 		return -1;
168 	}
169 
170 	return __statfs_ext_impl(NULL, fd, buf, flags);
171 }
172 
173 int
statfs_ext(const char * path,struct statfs * buf,int flags)174 statfs_ext(const char *path, struct statfs *buf, int flags)
175 {
176 	/* statfs() sanity checks */
177 	if (path == NULL) {
178 		errno = EFAULT;
179 		return -1;
180 	}
181 	if (buf == NULL) {
182 		errno = EFAULT;
183 		return -1;
184 	}
185 
186 	return __statfs_ext_impl(path, -1, buf, flags);
187 }
188