/* * Copyright (c) 2002 Apple Computer, 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 #include #include #include #include "quotacheck.h" /* * Query is based on uid */ #define QQ_COMMON (ATTR_CMN_OWNERID) struct quota_query { u_int32_t qq_len; uid_t qq_uid; }; /* * Desired atttributes for quota checking */ #define QA_COMMON (ATTR_CMN_OBJTYPE | ATTR_CMN_OWNERID | ATTR_CMN_GRPID) #define QA_FILE (ATTR_FILE_ALLOCSIZE) #define QA_DIR (0) struct quota_attr { u_int32_t qa_attrlen; fsobj_type_t qa_type; uid_t qa_uid; gid_t qa_gid; off_t qa_bytes; }; #define ITEMS_PER_SEARCH 2500 void collectdata(const char*, struct quotaname *); /* * Scan an HFS filesystem to check quota(s) present on it. */ int chkquota_hfs(fsname, mntpt, qnp) char *fsname, *mntpt; register struct quotaname *qnp; { int errs = 0; sync(); collectdata(mntpt, qnp); if (qnp->flags & HASUSR) errs = update(mntpt, qnp->usrqfname, USRQUOTA); if (qnp->flags & HASGRP) errs = update(mntpt, qnp->grpqfname, GRPQUOTA); return (errs); } void collectdata(const char* path, struct quotaname *qnp) { struct fssearchblock searchblk = {0}; struct attrlist attrlist = {0}; struct searchstate state; struct quota_attr *qap; struct quota_query query; u_long nummatches; u_int options; int i; int result; int vntype; off_t filebytes; register struct fileusage *fup; qap = malloc(ITEMS_PER_SEARCH * sizeof(struct quota_attr)); if (qap == NULL) err(1, "%s", strerror(errno)); options = SRCHFS_START |SRCHFS_MATCHDIRS | SRCHFS_MATCHFILES; /* Search for items with uid != 0 */ query.qq_len = sizeof(struct quota_query); query.qq_uid = 0; options |= SRCHFS_NEGATEPARAMS | SRCHFS_SKIPLINKS; searchblk.searchattrs.bitmapcount = ATTR_BIT_MAP_COUNT; searchblk.searchattrs.commonattr = QQ_COMMON; searchblk.searchparams1 = &query; searchblk.searchparams2 = &query; searchblk.sizeofsearchparams1 = sizeof(query); searchblk.sizeofsearchparams2 = sizeof(query); /* Ask for type, uid, gid and file bytes */ searchblk.returnattrs = &attrlist; attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; attrlist.commonattr = QA_COMMON; attrlist.dirattr = QA_DIR; attrlist.fileattr = QA_FILE; /* Collect 2,500 items at a time (~60K) */ searchblk.returnbuffer = qap; searchblk.returnbuffersize = ITEMS_PER_SEARCH * sizeof(struct quota_attr); searchblk.maxmatches = ITEMS_PER_SEARCH; for (;;) { nummatches = 0; result = searchfs(path, &searchblk, &nummatches, 0, options, &state); if (result && errno != EAGAIN && errno != EBUSY) { fprintf(stderr, "%d \n", errno); err(1, "searchfs %s", strerror(errno)); } if (result == 0 && nummatches == 0) break; /* all done */ options &= ~SRCHFS_START; for (i = 0; i < nummatches; ++i) { vntype = qap[i].qa_type; filebytes = (vntype == VDIR) ? 0 : qap[i].qa_bytes; if (qnp->flags & HASGRP) { fup = addid(qap[i].qa_gid, GRPQUOTA); fup->fu_curinodes++; if (vntype == VREG || vntype == VDIR || vntype == VLNK) fup->fu_curbytes += filebytes; } if (qnp->flags & HASUSR) { fup = addid(qap[i].qa_uid, USRQUOTA); fup->fu_curinodes++; if (vntype == VREG || vntype == VDIR || vntype == VLNK) fup->fu_curbytes += filebytes; } } } free(qap); }