+/*
+ * hfs_quotacheck - checks quotas mountwide for a hypothetical situation. It probes
+ * the quota data structures to see if adding an inode would be allowed or not. If it
+ * will be allowed, the change is made. Otherwise, it reports an error back out so the
+ * caller will know not to proceed with inode allocation in the HFS Catalog.
+ *
+ * Note that this function ONLY tests for addition of inodes, not subtraction.
+ */
+int hfs_quotacheck(hfsmp, change, uid, gid, cred)
+ struct hfsmount *hfsmp;
+ int change;
+ uid_t uid;
+ gid_t gid;
+ kauth_cred_t cred;
+{
+ struct dquot *dq = NULL;
+ struct proc *p;
+ int error = 0;
+ int i;
+ id_t id = uid;
+
+ p = current_proc();
+ if (!IS_VALID_CRED(cred)) {
+ /* This use of proc_ucred() is safe because kernproc credential never changes */
+ cred = proc_ucred(kernproc);
+ }
+
+ if (suser(cred, NULL) || proc_forcequota(p)) {
+ for (i = 0; i < MAXQUOTAS; i++) {
+ /* Select if user or group id should be used */
+ if (i == USRQUOTA)
+ id = uid;
+ else if (i == GRPQUOTA)
+ id = gid;
+
+ error = dqget(id, &hfsmp->hfs_qfiles[i], i, &dq);
+ if (error && (error != EINVAL))
+ break;
+
+ error = 0;
+ if (dq == NODQUOT)
+ continue;
+
+ /* Check quota information */
+ error = hfs_isiqchg_allowed(dq, hfsmp, change, cred, i, id);
+ if (error) {
+ dqrele(dq);
+ break;
+ }
+
+ dqlock(dq);
+ /* Update quota information */
+ dq->dq_curinodes += change;
+ dqunlock(dq);
+ dqrele(dq);
+ }
+ }
+
+ return error;
+}
+
+