Home | History | Annotate | Line # | Download | only in libquota
quota_oldfiles.c revision 1.9.36.1
      1  1.9.36.1    martin /*	$NetBSD: quota_oldfiles.c,v 1.9.36.1 2022/04/27 16:53:32 martin Exp $	*/
      2       1.1  dholland 
      3       1.1  dholland /*
      4       1.1  dholland  * Copyright (c) 1980, 1990, 1993
      5       1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      6       1.1  dholland  *
      7       1.1  dholland  * This code is derived from software contributed to Berkeley by
      8       1.1  dholland  * Robert Elz at The University of Melbourne.
      9       1.1  dholland  *
     10       1.1  dholland  * Redistribution and use in source and binary forms, with or without
     11       1.1  dholland  * modification, are permitted provided that the following conditions
     12       1.1  dholland  * are met:
     13       1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     14       1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     15       1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  dholland  *    documentation and/or other materials provided with the distribution.
     18       1.1  dholland  * 3. Neither the name of the University nor the names of its contributors
     19       1.1  dholland  *    may be used to endorse or promote products derived from this software
     20       1.1  dholland  *    without specific prior written permission.
     21       1.1  dholland  *
     22       1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23       1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24       1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25       1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26       1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27       1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28       1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29       1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30       1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31       1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32       1.1  dholland  * SUCH DAMAGE.
     33       1.1  dholland  */
     34       1.1  dholland 
     35       1.8  dholland #include <sys/cdefs.h>
     36  1.9.36.1    martin __RCSID("$NetBSD: quota_oldfiles.c,v 1.9.36.1 2022/04/27 16:53:32 martin Exp $");
     37       1.8  dholland 
     38       1.1  dholland #include <sys/types.h>
     39       1.1  dholland #include <sys/stat.h>
     40       1.1  dholland #include <stdio.h>
     41       1.1  dholland #include <stdlib.h>
     42       1.1  dholland #include <string.h>
     43       1.1  dholland #include <unistd.h>
     44       1.1  dholland #include <fcntl.h>
     45       1.1  dholland #include <limits.h>
     46       1.1  dholland #include <fstab.h>
     47       1.1  dholland #include <errno.h>
     48       1.1  dholland #include <err.h>
     49       1.1  dholland 
     50       1.1  dholland #include <ufs/ufs/quota1.h>
     51       1.1  dholland 
     52       1.1  dholland #include <quota.h>
     53       1.1  dholland #include "quotapvt.h"
     54       1.1  dholland 
     55       1.3  dholland struct oldfiles_fstabentry {
     56       1.3  dholland 	char *ofe_mountpoint;
     57       1.3  dholland 	int ofe_hasuserquota;
     58       1.3  dholland 	int ofe_hasgroupquota;
     59       1.3  dholland 	char *ofe_userquotafile;
     60       1.3  dholland 	char *ofe_groupquotafile;
     61       1.3  dholland };
     62       1.3  dholland 
     63       1.1  dholland struct oldfiles_quotacursor {
     64       1.1  dholland 	unsigned oqc_doingusers;
     65       1.1  dholland 	unsigned oqc_doinggroups;
     66       1.1  dholland 
     67       1.1  dholland 	unsigned oqc_numusers;
     68       1.1  dholland 	unsigned oqc_numgroups;
     69       1.1  dholland 
     70       1.1  dholland 	unsigned oqc_didusers;
     71       1.1  dholland 	unsigned oqc_didgroups;
     72       1.1  dholland 	unsigned oqc_diddefault;
     73       1.1  dholland 	unsigned oqc_pos;
     74       1.1  dholland 	unsigned oqc_didblocks;
     75       1.1  dholland };
     76       1.1  dholland 
     77       1.3  dholland static struct oldfiles_fstabentry *__quota_oldfiles_fstab;
     78       1.3  dholland static unsigned __quota_oldfiles_numfstab;
     79       1.3  dholland static unsigned __quota_oldfiles_maxfstab;
     80       1.3  dholland static int __quota_oldfiles_fstab_loaded;
     81       1.3  dholland 
     82       1.3  dholland static const struct oldfiles_fstabentry *
     83       1.3  dholland __quota_oldfiles_find_fstabentry(const char *mountpoint)
     84       1.3  dholland {
     85       1.3  dholland 	unsigned i;
     86       1.3  dholland 
     87       1.3  dholland 	for (i = 0; i < __quota_oldfiles_numfstab; i++) {
     88       1.3  dholland 		if (!strcmp(mountpoint,
     89       1.3  dholland 			    __quota_oldfiles_fstab[i].ofe_mountpoint)) {
     90       1.3  dholland 			return &__quota_oldfiles_fstab[i];
     91       1.3  dholland 		}
     92       1.3  dholland 	}
     93       1.3  dholland 	return NULL;
     94       1.3  dholland }
     95       1.3  dholland 
     96       1.3  dholland static int
     97       1.3  dholland __quota_oldfiles_add_fstabentry(struct oldfiles_fstabentry *ofe)
     98       1.3  dholland {
     99       1.3  dholland 	unsigned newmax;
    100       1.3  dholland 	struct oldfiles_fstabentry *newptr;
    101       1.3  dholland 
    102       1.3  dholland 	if (__quota_oldfiles_numfstab + 1 >= __quota_oldfiles_maxfstab) {
    103       1.3  dholland 		if (__quota_oldfiles_maxfstab == 0) {
    104       1.3  dholland 			newmax = 4;
    105       1.3  dholland 		} else {
    106       1.3  dholland 			newmax = __quota_oldfiles_maxfstab * 2;
    107       1.3  dholland 		}
    108       1.3  dholland 		newptr = realloc(__quota_oldfiles_fstab,
    109       1.3  dholland 				 newmax * sizeof(__quota_oldfiles_fstab[0]));
    110       1.3  dholland 		if (newptr == NULL) {
    111       1.3  dholland 			return -1;
    112       1.3  dholland 		}
    113       1.3  dholland 		__quota_oldfiles_maxfstab = newmax;
    114       1.3  dholland 		__quota_oldfiles_fstab = newptr;
    115       1.3  dholland 	}
    116       1.3  dholland 
    117       1.3  dholland 	__quota_oldfiles_fstab[__quota_oldfiles_numfstab++] = *ofe;
    118       1.3  dholland 	return 0;
    119       1.3  dholland }
    120       1.3  dholland 
    121       1.3  dholland static int
    122       1.3  dholland __quota_oldfiles_fill_fstabentry(const struct fstab *fs,
    123       1.3  dholland 				 struct oldfiles_fstabentry *ofe)
    124       1.3  dholland {
    125       1.4  dholland 	char buf[256];
    126       1.3  dholland 	char *opt, *state, *s;
    127       1.3  dholland 	int serrno;
    128       1.3  dholland 	int ret = 0;
    129       1.3  dholland 
    130       1.3  dholland 	/*
    131       1.3  dholland 	 * Inspect the mount options to find the quota files.
    132       1.3  dholland 	 * XXX this info should be gotten from the kernel.
    133       1.3  dholland 	 *
    134       1.3  dholland 	 * The options are:
    135       1.3  dholland 	 *    userquota[=path]          enable user quotas
    136       1.3  dholland 	 *    groupquota[=path]         enable group quotas
    137       1.3  dholland 	 */
    138       1.3  dholland 
    139       1.3  dholland 	ofe->ofe_mountpoint = NULL;
    140       1.3  dholland 	ofe->ofe_hasuserquota = ofe->ofe_hasgroupquota = 0;
    141       1.3  dholland 	ofe->ofe_userquotafile = ofe->ofe_groupquotafile = NULL;
    142       1.3  dholland 
    143       1.3  dholland 	strlcpy(buf, fs->fs_mntops, sizeof(buf));
    144       1.3  dholland 	for (opt = strtok_r(buf, ",", &state);
    145       1.3  dholland 	     opt != NULL;
    146       1.3  dholland 	     opt = strtok_r(NULL, ",", &state)) {
    147       1.3  dholland 		s = strchr(opt, '=');
    148       1.3  dholland 		if (s != NULL) {
    149       1.3  dholland 			*(s++) = '\0';
    150       1.3  dholland 		}
    151       1.3  dholland 		if (!strcmp(opt, "userquota")) {
    152       1.3  dholland 			ret = 1;
    153       1.3  dholland 			ofe->ofe_hasuserquota = 1;
    154       1.3  dholland 			if (s != NULL) {
    155       1.3  dholland 				ofe->ofe_userquotafile = strdup(s);
    156       1.3  dholland 				if (ofe->ofe_userquotafile == NULL) {
    157       1.3  dholland 					goto fail;
    158       1.3  dholland 				}
    159       1.3  dholland 			}
    160       1.3  dholland 		} else if (!strcmp(opt, "groupquota")) {
    161       1.3  dholland 			ret = 1;
    162       1.3  dholland 			ofe->ofe_hasgroupquota = 1;
    163       1.3  dholland 			if (s != NULL) {
    164       1.3  dholland 				ofe->ofe_groupquotafile = strdup(s);
    165       1.3  dholland 				if (ofe->ofe_groupquotafile == NULL) {
    166       1.3  dholland 					goto fail;
    167       1.3  dholland 				}
    168       1.3  dholland 			}
    169       1.3  dholland 		}
    170       1.3  dholland 	}
    171       1.3  dholland 
    172       1.3  dholland 	if (ret == 1) {
    173       1.3  dholland 		ofe->ofe_mountpoint = strdup(fs->fs_file);
    174       1.3  dholland 		if (ofe->ofe_mountpoint == NULL) {
    175       1.3  dholland 			goto fail;
    176       1.3  dholland 		}
    177       1.3  dholland 	}
    178       1.3  dholland 
    179       1.3  dholland 	return ret;
    180       1.3  dholland 
    181       1.3  dholland fail:
    182       1.3  dholland 	serrno = errno;
    183       1.3  dholland 	if (ofe->ofe_mountpoint != NULL) {
    184       1.3  dholland 		free(ofe->ofe_mountpoint);
    185       1.3  dholland 	}
    186       1.3  dholland 	if (ofe->ofe_groupquotafile != NULL) {
    187       1.3  dholland 		free(ofe->ofe_groupquotafile);
    188       1.3  dholland 	}
    189       1.3  dholland 	if (ofe->ofe_userquotafile != NULL) {
    190       1.3  dholland 		free(ofe->ofe_userquotafile);
    191       1.3  dholland 	}
    192       1.3  dholland 	errno = serrno;
    193       1.3  dholland 	return -1;
    194       1.3  dholland }
    195       1.3  dholland 
    196       1.3  dholland void
    197       1.3  dholland __quota_oldfiles_load_fstab(void)
    198       1.3  dholland {
    199       1.3  dholland 	struct oldfiles_fstabentry ofe;
    200       1.3  dholland 	struct fstab *fs;
    201       1.3  dholland 	int result;
    202       1.3  dholland 
    203       1.3  dholland 	if (__quota_oldfiles_fstab_loaded) {
    204       1.3  dholland 		return;
    205       1.3  dholland 	}
    206       1.3  dholland 
    207       1.3  dholland 	/*
    208       1.9     njoly 	 * Check if fstab file exists before trying to parse it.
    209       1.9     njoly 	 * Avoid warnings from {get,set}fsent() if missing.
    210       1.9     njoly 	 */
    211       1.9     njoly 	if (access(_PATH_FSTAB, F_OK) == -1 && errno == ENOENT)
    212       1.9     njoly 		return;
    213       1.9     njoly 
    214       1.9     njoly 	/*
    215       1.3  dholland 	 * XXX: should be able to handle ext2fs quota1 files too
    216       1.3  dholland 	 *
    217       1.3  dholland 	 * XXX: should use getfsent_r(), but there isn't one.
    218       1.3  dholland 	 */
    219       1.3  dholland 	setfsent();
    220       1.3  dholland 	while ((fs = getfsent()) != NULL) {
    221       1.3  dholland 		if (!strcmp(fs->fs_vfstype, "ffs") ||
    222       1.3  dholland 		    !strcmp(fs->fs_vfstype, "lfs")) {
    223       1.3  dholland 			result = __quota_oldfiles_fill_fstabentry(fs, &ofe);
    224       1.3  dholland 			if (result == -1) {
    225       1.3  dholland 				goto failed;
    226       1.3  dholland 			}
    227       1.3  dholland 			if (result == 0) {
    228       1.3  dholland 				continue;
    229       1.3  dholland 			}
    230       1.3  dholland 			if (__quota_oldfiles_add_fstabentry(&ofe)) {
    231       1.3  dholland 				goto failed;
    232       1.3  dholland 			}
    233       1.3  dholland 		}
    234       1.3  dholland 	}
    235       1.3  dholland 	endfsent();
    236       1.3  dholland 	__quota_oldfiles_fstab_loaded = 1;
    237       1.3  dholland 
    238       1.3  dholland 	return;
    239       1.3  dholland failed:
    240       1.3  dholland 	warn("Failed reading fstab");
    241       1.3  dholland 	return;
    242       1.3  dholland }
    243       1.3  dholland 
    244       1.3  dholland int
    245       1.3  dholland __quota_oldfiles_infstab(const char *mountpoint)
    246       1.3  dholland {
    247       1.3  dholland 	return __quota_oldfiles_find_fstabentry(mountpoint) != NULL;
    248       1.3  dholland }
    249       1.3  dholland 
    250       1.5  dholland static void
    251       1.5  dholland __quota_oldfiles_defquotafile(struct quotahandle *qh, int idtype,
    252       1.5  dholland 			      char *buf, size_t maxlen)
    253       1.5  dholland {
    254       1.5  dholland 	static const char *const names[] = INITQFNAMES;
    255       1.5  dholland 
    256       1.5  dholland 	(void)snprintf(buf, maxlen, "%s/%s.%s",
    257       1.5  dholland 		       qh->qh_mountpoint,
    258  1.9.36.1    martin 		       QUOTAFILENAME, names[idtype]);
    259       1.5  dholland }
    260       1.5  dholland 
    261       1.5  dholland const char *
    262       1.5  dholland __quota_oldfiles_getquotafile(struct quotahandle *qh, int idtype,
    263       1.5  dholland 			      char *buf, size_t maxlen)
    264       1.5  dholland {
    265       1.5  dholland 	const struct oldfiles_fstabentry *ofe;
    266       1.5  dholland 	const char *file;
    267       1.5  dholland 
    268       1.5  dholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
    269       1.5  dholland 	if (ofe == NULL) {
    270       1.5  dholland 		errno = ENXIO;
    271       1.5  dholland 		return NULL;
    272       1.5  dholland 	}
    273       1.5  dholland 
    274       1.5  dholland 	switch (idtype) {
    275       1.5  dholland 	    case USRQUOTA:
    276       1.5  dholland 		if (!ofe->ofe_hasuserquota) {
    277       1.5  dholland 			errno = ENXIO;
    278       1.5  dholland 			return NULL;
    279       1.5  dholland 		}
    280       1.5  dholland 		file = ofe->ofe_userquotafile;
    281       1.5  dholland 		break;
    282       1.5  dholland 	    case GRPQUOTA:
    283       1.5  dholland 		if (!ofe->ofe_hasgroupquota) {
    284       1.5  dholland 			errno = ENXIO;
    285       1.5  dholland 			return NULL;
    286       1.5  dholland 		}
    287       1.5  dholland 		file = ofe->ofe_groupquotafile;
    288       1.5  dholland 		break;
    289       1.5  dholland 	    default:
    290       1.5  dholland 		errno = EINVAL;
    291       1.5  dholland 		return NULL;
    292       1.5  dholland 	}
    293       1.5  dholland 
    294       1.5  dholland 	if (file == NULL) {
    295       1.5  dholland 		__quota_oldfiles_defquotafile(qh, idtype, buf, maxlen);
    296       1.5  dholland 		file = buf;
    297       1.5  dholland 	}
    298       1.5  dholland 	return file;
    299       1.5  dholland }
    300       1.5  dholland 
    301       1.1  dholland static uint64_t
    302       1.2  dholland dqblk_getlimit(uint32_t val)
    303       1.1  dholland {
    304       1.1  dholland 	if (val == 0) {
    305       1.1  dholland 		return QUOTA_NOLIMIT;
    306       1.1  dholland 	} else {
    307       1.1  dholland 		return val - 1;
    308       1.1  dholland 	}
    309       1.1  dholland }
    310       1.1  dholland 
    311       1.2  dholland static uint32_t
    312       1.2  dholland dqblk_setlimit(uint64_t val)
    313       1.2  dholland {
    314       1.2  dholland 	if (val == QUOTA_NOLIMIT && val >= 0xffffffffUL) {
    315       1.2  dholland 		return 0;
    316       1.2  dholland 	} else {
    317       1.2  dholland 		return (uint32_t)val + 1;
    318       1.2  dholland 	}
    319       1.2  dholland }
    320       1.2  dholland 
    321       1.1  dholland static void
    322       1.1  dholland dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
    323       1.1  dholland {
    324       1.2  dholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_bhardlimit);
    325       1.2  dholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_bsoftlimit);
    326       1.1  dholland 	qv->qv_usage = dq->dqb_curblocks;
    327       1.1  dholland 	qv->qv_expiretime = dq->dqb_btime;
    328       1.1  dholland 	qv->qv_grace = QUOTA_NOTIME;
    329       1.1  dholland }
    330       1.1  dholland 
    331       1.1  dholland static void
    332       1.1  dholland dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
    333       1.1  dholland {
    334       1.2  dholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_ihardlimit);
    335       1.2  dholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_isoftlimit);
    336       1.1  dholland 	qv->qv_usage = dq->dqb_curinodes;
    337       1.1  dholland 	qv->qv_expiretime = dq->dqb_itime;
    338       1.1  dholland 	qv->qv_grace = QUOTA_NOTIME;
    339       1.1  dholland }
    340       1.1  dholland 
    341       1.2  dholland static void
    342       1.2  dholland dqblk_putblocks(const struct quotaval *qv, struct dqblk *dq)
    343       1.2  dholland {
    344       1.2  dholland 	dq->dqb_bhardlimit = dqblk_setlimit(qv->qv_hardlimit);
    345       1.2  dholland 	dq->dqb_bsoftlimit = dqblk_setlimit(qv->qv_softlimit);
    346       1.2  dholland 	dq->dqb_curblocks = qv->qv_usage;
    347       1.2  dholland 	dq->dqb_btime = qv->qv_expiretime;
    348       1.2  dholland 	/* ignore qv->qv_grace */
    349       1.2  dholland }
    350       1.2  dholland 
    351       1.2  dholland static void
    352       1.2  dholland dqblk_putfiles(const struct quotaval *qv, struct dqblk *dq)
    353       1.2  dholland {
    354       1.2  dholland 	dq->dqb_ihardlimit = dqblk_setlimit(qv->qv_hardlimit);
    355       1.2  dholland 	dq->dqb_isoftlimit = dqblk_setlimit(qv->qv_softlimit);
    356       1.2  dholland 	dq->dqb_curinodes = qv->qv_usage;
    357       1.2  dholland 	dq->dqb_itime = qv->qv_expiretime;
    358       1.2  dholland 	/* ignore qv->qv_grace */
    359       1.2  dholland }
    360       1.2  dholland 
    361       1.1  dholland static int
    362       1.1  dholland __quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
    363       1.1  dholland {
    364       1.1  dholland 	int fd;
    365       1.1  dholland 
    366       1.1  dholland 	fd = open(path, O_RDWR);
    367       1.1  dholland 	if (fd < 0 && (errno == EACCES || errno == EROFS)) {
    368       1.1  dholland 		fd = open(path, O_RDONLY);
    369       1.1  dholland 		if (fd < 0) {
    370       1.1  dholland 			return -1;
    371       1.1  dholland 		}
    372       1.1  dholland 	}
    373       1.1  dholland 	*fd_ret = fd;
    374       1.1  dholland 	return 0;
    375       1.1  dholland }
    376       1.1  dholland 
    377       1.1  dholland int
    378       1.1  dholland __quota_oldfiles_initialize(struct quotahandle *qh)
    379       1.1  dholland {
    380       1.3  dholland 	const struct oldfiles_fstabentry *ofe;
    381       1.1  dholland 	char path[PATH_MAX];
    382       1.1  dholland 	const char *userquotafile, *groupquotafile;
    383       1.1  dholland 
    384       1.3  dholland 	if (qh->qh_oldfilesopen) {
    385       1.1  dholland 		/* already initialized */
    386       1.1  dholland 		return 0;
    387       1.1  dholland 	}
    388       1.1  dholland 
    389       1.1  dholland 	/*
    390       1.1  dholland 	 * Find the fstab entry.
    391       1.1  dholland 	 */
    392       1.3  dholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
    393       1.3  dholland 	if (ofe == NULL) {
    394       1.1  dholland 		warnx("%s not found in fstab", qh->qh_mountpoint);
    395       1.1  dholland 		errno = ENXIO;
    396       1.1  dholland 		return -1;
    397       1.1  dholland 	}
    398       1.1  dholland 
    399       1.3  dholland 	if (!ofe->ofe_hasuserquota && !ofe->ofe_hasgroupquota) {
    400       1.1  dholland 		errno = ENXIO;
    401       1.1  dholland 		return -1;
    402       1.1  dholland 	}
    403       1.1  dholland 
    404       1.3  dholland 	if (ofe->ofe_hasuserquota) {
    405       1.3  dholland 		userquotafile = ofe->ofe_userquotafile;
    406       1.1  dholland 		if (userquotafile == NULL) {
    407       1.5  dholland 			__quota_oldfiles_defquotafile(qh, USRQUOTA,
    408       1.5  dholland 						      path, sizeof(path));
    409       1.1  dholland 			userquotafile = path;
    410       1.1  dholland 		}
    411       1.1  dholland 		if (__quota_oldfiles_open(qh, userquotafile,
    412       1.1  dholland 					  &qh->qh_userfile)) {
    413       1.1  dholland 			return -1;
    414       1.1  dholland 		}
    415       1.1  dholland 	}
    416       1.3  dholland 	if (ofe->ofe_hasgroupquota) {
    417       1.3  dholland 		groupquotafile = ofe->ofe_groupquotafile;
    418       1.1  dholland 		if (groupquotafile == NULL) {
    419       1.5  dholland 			__quota_oldfiles_defquotafile(qh, GRPQUOTA,
    420       1.5  dholland 						      path, sizeof(path));
    421       1.1  dholland 			groupquotafile = path;
    422       1.1  dholland 		}
    423       1.1  dholland 		if (__quota_oldfiles_open(qh, groupquotafile,
    424       1.1  dholland 					  &qh->qh_groupfile)) {
    425       1.1  dholland 			return -1;
    426       1.1  dholland 		}
    427       1.1  dholland 	}
    428       1.1  dholland 
    429       1.3  dholland 	qh->qh_oldfilesopen = 1;
    430       1.1  dholland 
    431       1.1  dholland 	return 0;
    432       1.1  dholland }
    433       1.1  dholland 
    434       1.1  dholland const char *
    435       1.1  dholland __quota_oldfiles_getimplname(struct quotahandle *qh)
    436       1.1  dholland {
    437       1.3  dholland 	return "ufs/ffs quota v1 file access";
    438       1.1  dholland }
    439       1.1  dholland 
    440       1.5  dholland int
    441       1.5  dholland __quota_oldfiles_quotaon(struct quotahandle *qh, int idtype)
    442       1.5  dholland {
    443       1.5  dholland 	int result;
    444       1.5  dholland 
    445       1.5  dholland 	/*
    446       1.5  dholland 	 * If we have the quota files open, close them.
    447       1.5  dholland 	 */
    448       1.5  dholland 
    449       1.5  dholland 	if (qh->qh_oldfilesopen) {
    450       1.5  dholland 		if (qh->qh_userfile >= 0) {
    451       1.5  dholland 			close(qh->qh_userfile);
    452       1.5  dholland 			qh->qh_userfile = -1;
    453       1.5  dholland 		}
    454       1.5  dholland 		if (qh->qh_groupfile >= 0) {
    455       1.5  dholland 			close(qh->qh_groupfile);
    456       1.5  dholland 			qh->qh_groupfile = -1;
    457       1.5  dholland 		}
    458       1.5  dholland 		qh->qh_oldfilesopen = 0;
    459       1.5  dholland 	}
    460       1.5  dholland 
    461       1.5  dholland 	/*
    462       1.5  dholland 	 * Go over to the syscall interface.
    463       1.5  dholland 	 */
    464       1.5  dholland 
    465       1.6  dholland 	result = __quota_kernel_quotaon(qh, idtype);
    466       1.5  dholland 	if (result < 0) {
    467       1.5  dholland 		return -1;
    468       1.5  dholland 	}
    469       1.5  dholland 
    470       1.5  dholland 	/*
    471       1.5  dholland 	 * We succeeded, so all further access should be via the
    472       1.5  dholland 	 * kernel.
    473       1.5  dholland 	 */
    474       1.5  dholland 
    475       1.6  dholland 	qh->qh_mode = QUOTA_MODE_KERNEL;
    476       1.5  dholland 	return 0;
    477       1.5  dholland }
    478       1.5  dholland 
    479       1.1  dholland static int
    480       1.1  dholland __quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
    481       1.1  dholland 		       struct quotaval *qv, int *isallzero)
    482       1.1  dholland {
    483       1.1  dholland 	int file;
    484       1.1  dholland 	off_t pos;
    485       1.1  dholland 	struct dqblk dq;
    486       1.1  dholland 	ssize_t result;
    487       1.1  dholland 
    488       1.3  dholland 	if (!qh->qh_oldfilesopen) {
    489       1.3  dholland 		if (__quota_oldfiles_initialize(qh)) {
    490       1.3  dholland 			return -1;
    491       1.3  dholland 		}
    492       1.3  dholland 	}
    493       1.3  dholland 
    494       1.1  dholland 	switch (qk->qk_idtype) {
    495       1.1  dholland 	    case QUOTA_IDTYPE_USER:
    496       1.1  dholland 		file = qh->qh_userfile;
    497       1.1  dholland 		break;
    498       1.1  dholland 	    case QUOTA_IDTYPE_GROUP:
    499       1.1  dholland 		file = qh->qh_groupfile;
    500       1.1  dholland 		break;
    501       1.1  dholland 	    default:
    502       1.1  dholland 		errno = EINVAL;
    503       1.1  dholland 		return -1;
    504       1.1  dholland 	}
    505       1.1  dholland 
    506       1.1  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    507       1.1  dholland 		pos = 0;
    508       1.1  dholland 	} else {
    509       1.1  dholland 		pos = qk->qk_id * sizeof(struct dqblk);
    510       1.1  dholland 	}
    511       1.1  dholland 
    512       1.1  dholland 	result = pread(file, &dq, sizeof(dq), pos);
    513       1.1  dholland 	if (result < 0) {
    514       1.1  dholland 		return -1;
    515       1.2  dholland 	} else if (result == 0) {
    516       1.2  dholland 		/* Past EOF; no quota info on file for this ID */
    517       1.2  dholland 		errno = ENOENT;
    518       1.2  dholland 		return -1;
    519       1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    520       1.1  dholland 		errno = EFTYPE;
    521       1.1  dholland 		return -1;
    522       1.1  dholland 	}
    523       1.1  dholland 
    524       1.1  dholland 	switch (qk->qk_objtype) {
    525       1.1  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    526       1.1  dholland 		dqblk_getblocks(&dq, qv);
    527       1.1  dholland 		break;
    528       1.1  dholland 	    case QUOTA_OBJTYPE_FILES:
    529       1.1  dholland 		dqblk_getfiles(&dq, qv);
    530       1.1  dholland 		break;
    531       1.1  dholland 	    default:
    532       1.1  dholland 		errno = EINVAL;
    533       1.1  dholland 		return -1;
    534       1.1  dholland 	}
    535       1.1  dholland 
    536       1.1  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    537       1.1  dholland 		qv->qv_usage = 0;
    538       1.1  dholland 		qv->qv_grace = qv->qv_expiretime;
    539       1.1  dholland 		qv->qv_expiretime = QUOTA_NOTIME;
    540       1.1  dholland 	} else if (qk->qk_id == 0) {
    541       1.1  dholland 		qv->qv_hardlimit = 0;
    542       1.1  dholland 		qv->qv_softlimit = 0;
    543       1.1  dholland 		qv->qv_expiretime = QUOTA_NOTIME;
    544       1.1  dholland 		qv->qv_grace = QUOTA_NOTIME;
    545       1.1  dholland 	}
    546       1.1  dholland 
    547       1.1  dholland 	if (isallzero != NULL) {
    548       1.1  dholland 		if (dq.dqb_bhardlimit == 0 &&
    549       1.1  dholland 		    dq.dqb_bsoftlimit == 0 &&
    550       1.1  dholland 		    dq.dqb_curblocks == 0 &&
    551       1.1  dholland 		    dq.dqb_ihardlimit == 0 &&
    552       1.1  dholland 		    dq.dqb_isoftlimit == 0 &&
    553       1.1  dholland 		    dq.dqb_curinodes == 0 &&
    554       1.1  dholland 		    dq.dqb_btime == 0 &&
    555       1.1  dholland 		    dq.dqb_itime == 0) {
    556       1.1  dholland 			*isallzero = 1;
    557       1.1  dholland 		} else {
    558       1.1  dholland 			*isallzero = 0;
    559       1.1  dholland 		}
    560       1.1  dholland 	}
    561       1.1  dholland 
    562       1.1  dholland 	return 0;
    563       1.1  dholland }
    564       1.1  dholland 
    565       1.2  dholland static int
    566       1.2  dholland __quota_oldfiles_doput(struct quotahandle *qh, const struct quotakey *qk,
    567       1.2  dholland 		       const struct quotaval *qv)
    568       1.2  dholland {
    569       1.2  dholland 	int file;
    570       1.2  dholland 	off_t pos;
    571       1.2  dholland 	struct quotaval qv2;
    572       1.2  dholland 	struct dqblk dq;
    573       1.2  dholland 	ssize_t result;
    574       1.2  dholland 
    575       1.3  dholland 	if (!qh->qh_oldfilesopen) {
    576       1.3  dholland 		if (__quota_oldfiles_initialize(qh)) {
    577       1.3  dholland 			return -1;
    578       1.3  dholland 		}
    579       1.3  dholland 	}
    580       1.3  dholland 
    581       1.2  dholland 	switch (qk->qk_idtype) {
    582       1.2  dholland 	    case QUOTA_IDTYPE_USER:
    583       1.2  dholland 		file = qh->qh_userfile;
    584       1.2  dholland 		break;
    585       1.2  dholland 	    case QUOTA_IDTYPE_GROUP:
    586       1.2  dholland 		file = qh->qh_groupfile;
    587       1.2  dholland 		break;
    588       1.2  dholland 	    default:
    589       1.2  dholland 		errno = EINVAL;
    590       1.2  dholland 		return -1;
    591       1.2  dholland 	}
    592       1.2  dholland 
    593       1.2  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    594       1.2  dholland 		pos = 0;
    595       1.2  dholland 	} else {
    596       1.2  dholland 		pos = qk->qk_id * sizeof(struct dqblk);
    597       1.2  dholland 	}
    598       1.2  dholland 
    599       1.2  dholland 	result = pread(file, &dq, sizeof(dq), pos);
    600       1.2  dholland 	if (result < 0) {
    601       1.2  dholland 		return -1;
    602       1.2  dholland 	} else if (result == 0) {
    603       1.2  dholland 		/* Past EOF; fill in a blank dq to start from */
    604       1.2  dholland 		dq.dqb_bhardlimit = 0;
    605       1.2  dholland 		dq.dqb_bsoftlimit = 0;
    606       1.2  dholland 		dq.dqb_curblocks = 0;
    607       1.2  dholland 		dq.dqb_ihardlimit = 0;
    608       1.2  dholland 		dq.dqb_isoftlimit = 0;
    609       1.2  dholland 		dq.dqb_curinodes = 0;
    610       1.2  dholland 		dq.dqb_btime = 0;
    611       1.2  dholland 		dq.dqb_itime = 0;
    612       1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    613       1.2  dholland 		errno = EFTYPE;
    614       1.2  dholland 		return -1;
    615       1.2  dholland 	}
    616       1.2  dholland 
    617       1.2  dholland 	switch (qk->qk_objtype) {
    618       1.2  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    619       1.2  dholland 		dqblk_getblocks(&dq, &qv2);
    620       1.2  dholland 		break;
    621       1.2  dholland 	    case QUOTA_OBJTYPE_FILES:
    622       1.2  dholland 		dqblk_getfiles(&dq, &qv2);
    623       1.2  dholland 		break;
    624       1.2  dholland 	    default:
    625       1.2  dholland 		errno = EINVAL;
    626       1.2  dholland 		return -1;
    627       1.2  dholland 	}
    628       1.2  dholland 
    629       1.2  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    630       1.2  dholland 		qv2.qv_hardlimit = qv->qv_hardlimit;
    631       1.2  dholland 		qv2.qv_softlimit = qv->qv_softlimit;
    632       1.2  dholland 		/* leave qv2.qv_usage unchanged */
    633       1.2  dholland 		qv2.qv_expiretime = qv->qv_grace;
    634       1.2  dholland 		/* skip qv2.qv_grace */
    635       1.2  dholland 
    636       1.2  dholland 		/* ignore qv->qv_usage */
    637       1.2  dholland 		/* ignore qv->qv_expiretime */
    638       1.2  dholland 	} else if (qk->qk_id == 0) {
    639       1.2  dholland 		/* leave qv2.qv_hardlimit unchanged */
    640       1.2  dholland 		/* leave qv2.qv_softlimit unchanged */
    641       1.2  dholland 		qv2.qv_usage = qv->qv_usage;
    642       1.2  dholland 		/* leave qv2.qv_expiretime unchanged */
    643       1.2  dholland 		/* skip qv2.qv_grace */
    644       1.2  dholland 
    645       1.2  dholland 		/* ignore qv->qv_hardlimit */
    646       1.2  dholland 		/* ignore qv->qv_softlimit */
    647       1.2  dholland 		/* ignore qv->qv_expiretime */
    648       1.2  dholland 		/* ignore qv->qv_grace */
    649       1.2  dholland 	} else {
    650       1.2  dholland 		qv2 = *qv;
    651       1.2  dholland 	}
    652       1.2  dholland 
    653       1.2  dholland 	switch (qk->qk_objtype) {
    654       1.2  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    655       1.2  dholland 		dqblk_putblocks(&qv2, &dq);
    656       1.2  dholland 		break;
    657       1.2  dholland 	    case QUOTA_OBJTYPE_FILES:
    658       1.2  dholland 		dqblk_putfiles(&qv2, &dq);
    659       1.2  dholland 		break;
    660       1.2  dholland 	    default:
    661       1.2  dholland 		errno = EINVAL;
    662       1.2  dholland 		return -1;
    663       1.2  dholland 	}
    664       1.2  dholland 
    665       1.2  dholland 	result = pwrite(file, &dq, sizeof(dq), pos);
    666       1.2  dholland 	if (result < 0) {
    667       1.2  dholland 		return -1;
    668       1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    669       1.2  dholland 		/* ? */
    670       1.2  dholland 		errno = EFTYPE;
    671       1.2  dholland 		return -1;
    672       1.2  dholland 	}
    673       1.2  dholland 
    674       1.2  dholland 	return 0;
    675       1.2  dholland }
    676       1.2  dholland 
    677       1.1  dholland int
    678       1.1  dholland __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
    679       1.1  dholland 		     struct quotaval *qv)
    680       1.1  dholland {
    681       1.1  dholland 	return __quota_oldfiles_doget(qh, qk, qv, NULL);
    682       1.1  dholland }
    683       1.1  dholland 
    684       1.2  dholland int
    685       1.2  dholland __quota_oldfiles_put(struct quotahandle *qh, const struct quotakey *qk,
    686       1.2  dholland 		     const struct quotaval *qv)
    687       1.2  dholland {
    688       1.2  dholland 	return __quota_oldfiles_doput(qh, qk, qv);
    689       1.2  dholland }
    690       1.2  dholland 
    691       1.2  dholland int
    692       1.2  dholland __quota_oldfiles_delete(struct quotahandle *qh, const struct quotakey *qk)
    693       1.2  dholland {
    694       1.2  dholland 	struct quotaval qv;
    695       1.2  dholland 
    696       1.2  dholland 	quotaval_clear(&qv);
    697       1.2  dholland 	return __quota_oldfiles_doput(qh, qk, &qv);
    698       1.2  dholland }
    699       1.2  dholland 
    700       1.1  dholland struct oldfiles_quotacursor *
    701       1.1  dholland __quota_oldfiles_cursor_create(struct quotahandle *qh)
    702       1.1  dholland {
    703       1.1  dholland 	struct oldfiles_quotacursor *oqc;
    704       1.1  dholland 	struct stat st;
    705       1.1  dholland 	int serrno;
    706       1.1  dholland 
    707       1.3  dholland 	/* quota_opencursor calls initialize for us, no need to do it here */
    708       1.3  dholland 
    709       1.1  dholland 	oqc = malloc(sizeof(*oqc));
    710       1.1  dholland 	if (oqc == NULL) {
    711       1.1  dholland 		return NULL;
    712       1.1  dholland 	}
    713       1.1  dholland 
    714       1.1  dholland 	oqc->oqc_didusers = 0;
    715       1.1  dholland 	oqc->oqc_didgroups = 0;
    716       1.1  dholland 	oqc->oqc_diddefault = 0;
    717       1.1  dholland 	oqc->oqc_pos = 0;
    718       1.1  dholland 	oqc->oqc_didblocks = 0;
    719       1.1  dholland 
    720       1.1  dholland 	if (qh->qh_userfile >= 0) {
    721       1.1  dholland 		oqc->oqc_doingusers = 1;
    722       1.1  dholland 	} else {
    723       1.1  dholland 		oqc->oqc_doingusers = 0;
    724       1.1  dholland 		oqc->oqc_didusers = 1;
    725       1.1  dholland 	}
    726       1.1  dholland 
    727       1.1  dholland 	if (qh->qh_groupfile >= 0) {
    728       1.1  dholland 		oqc->oqc_doinggroups = 1;
    729       1.1  dholland 	} else {
    730       1.1  dholland 		oqc->oqc_doinggroups = 0;
    731       1.1  dholland 		oqc->oqc_didgroups = 1;
    732       1.1  dholland 	}
    733       1.1  dholland 
    734       1.1  dholland 	if (fstat(qh->qh_userfile, &st) < 0) {
    735       1.1  dholland 		serrno = errno;
    736       1.1  dholland 		free(oqc);
    737       1.1  dholland 		errno = serrno;
    738       1.1  dholland 		return NULL;
    739       1.1  dholland 	}
    740       1.1  dholland 	oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
    741       1.1  dholland 
    742       1.1  dholland 	if (fstat(qh->qh_groupfile, &st) < 0) {
    743       1.1  dholland 		serrno = errno;
    744       1.1  dholland 		free(oqc);
    745       1.1  dholland 		errno = serrno;
    746       1.1  dholland 		return NULL;
    747       1.1  dholland 	}
    748       1.1  dholland 	oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
    749       1.1  dholland 
    750       1.1  dholland 	return oqc;
    751       1.1  dholland }
    752       1.1  dholland 
    753       1.1  dholland void
    754       1.1  dholland __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
    755       1.1  dholland {
    756       1.1  dholland 	free(oqc);
    757       1.1  dholland }
    758       1.1  dholland 
    759       1.1  dholland int
    760       1.1  dholland __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
    761       1.7  dholland 				   int idtype)
    762       1.1  dholland {
    763       1.1  dholland 	switch (idtype) {
    764       1.1  dholland 	    case QUOTA_IDTYPE_USER:
    765       1.1  dholland 		oqc->oqc_doingusers = 0;
    766       1.1  dholland 		oqc->oqc_didusers = 1;
    767       1.1  dholland 		break;
    768       1.1  dholland 	    case QUOTA_IDTYPE_GROUP:
    769       1.1  dholland 		oqc->oqc_doinggroups = 0;
    770       1.1  dholland 		oqc->oqc_didgroups = 1;
    771       1.1  dholland 		break;
    772       1.1  dholland 	    default:
    773       1.1  dholland 		errno = EINVAL;
    774       1.1  dholland 		return -1;
    775       1.1  dholland 	}
    776       1.1  dholland 	return 0;
    777       1.1  dholland }
    778       1.1  dholland 
    779       1.1  dholland int
    780       1.1  dholland __quota_oldfiles_cursor_get(struct quotahandle *qh,
    781       1.1  dholland 			    struct oldfiles_quotacursor *oqc,
    782       1.1  dholland 			    struct quotakey *key, struct quotaval *val)
    783       1.1  dholland {
    784       1.1  dholland 	unsigned maxpos;
    785       1.1  dholland 	int isallzero;
    786       1.1  dholland 
    787       1.1  dholland 	/* in case one of the sizes is zero */
    788       1.1  dholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
    789       1.1  dholland 		oqc->oqc_didusers = 1;
    790       1.1  dholland 	}
    791       1.1  dholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
    792       1.1  dholland 		oqc->oqc_didgroups = 1;
    793       1.1  dholland 	}
    794       1.1  dholland 
    795       1.1  dholland  again:
    796       1.1  dholland 	/*
    797       1.1  dholland 	 * Figure out what to get
    798       1.1  dholland 	 */
    799       1.1  dholland 
    800       1.1  dholland 	if (!oqc->oqc_didusers) {
    801       1.1  dholland 		key->qk_idtype = QUOTA_IDTYPE_USER;
    802       1.1  dholland 		maxpos = oqc->oqc_numusers;
    803       1.1  dholland 	} else if (!oqc->oqc_didgroups) {
    804       1.1  dholland 		key->qk_idtype = QUOTA_IDTYPE_GROUP;
    805       1.1  dholland 		maxpos = oqc->oqc_numgroups;
    806       1.1  dholland 	} else {
    807       1.1  dholland 		errno = ENOENT;
    808       1.1  dholland 		return -1;
    809       1.1  dholland 	}
    810       1.1  dholland 
    811       1.1  dholland 	if (!oqc->oqc_diddefault) {
    812       1.1  dholland 		key->qk_id = QUOTA_DEFAULTID;
    813       1.1  dholland 	} else {
    814       1.1  dholland 		key->qk_id = oqc->oqc_pos;
    815       1.1  dholland 	}
    816       1.1  dholland 
    817       1.1  dholland 	if (!oqc->oqc_didblocks) {
    818       1.1  dholland 		key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
    819       1.1  dholland 	} else {
    820       1.1  dholland 		key->qk_objtype = QUOTA_OBJTYPE_FILES;
    821       1.1  dholland 	}
    822       1.1  dholland 
    823       1.1  dholland 	/*
    824       1.1  dholland 	 * Get it
    825       1.1  dholland 	 */
    826       1.1  dholland 
    827       1.1  dholland 	if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
    828       1.1  dholland 		return -1;
    829       1.1  dholland 	}
    830       1.1  dholland 
    831       1.1  dholland 	/*
    832       1.1  dholland 	 * Advance the cursor
    833       1.1  dholland 	 */
    834       1.1  dholland 	if (!oqc->oqc_didblocks) {
    835       1.1  dholland 		oqc->oqc_didblocks = 1;
    836       1.1  dholland 	} else {
    837       1.1  dholland 		oqc->oqc_didblocks = 0;
    838       1.1  dholland 		if (!oqc->oqc_diddefault) {
    839       1.1  dholland 			oqc->oqc_diddefault = 1;
    840       1.1  dholland 		} else {
    841       1.1  dholland 			oqc->oqc_pos++;
    842       1.1  dholland 			if (oqc->oqc_pos >= maxpos) {
    843       1.1  dholland 				oqc->oqc_pos = 0;
    844       1.1  dholland 				oqc->oqc_diddefault = 0;
    845       1.1  dholland 				if (!oqc->oqc_didusers) {
    846       1.1  dholland 					oqc->oqc_didusers = 1;
    847       1.1  dholland 				} else {
    848       1.1  dholland 					oqc->oqc_didgroups = 1;
    849       1.1  dholland 				}
    850       1.1  dholland 			}
    851       1.1  dholland 		}
    852       1.1  dholland 	}
    853       1.1  dholland 
    854       1.1  dholland 	/*
    855       1.1  dholland 	 * If we got an all-zero dqblk (e.g. from the middle of a hole
    856       1.1  dholland 	 * in the quota file) don't bother returning it to the caller.
    857       1.1  dholland 	 *
    858       1.1  dholland 	 * ...unless we're at the end of the data, to avoid going past
    859       1.1  dholland 	 * the end and generating a spurious failure. There's no
    860       1.1  dholland 	 * reasonable way to make _atend detect empty entries at the
    861       1.1  dholland 	 * end of the quota files.
    862       1.1  dholland 	 */
    863       1.1  dholland 	if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
    864       1.1  dholland 		goto again;
    865       1.1  dholland 	}
    866       1.1  dholland 	return 0;
    867       1.1  dholland }
    868       1.1  dholland 
    869       1.1  dholland int
    870       1.1  dholland __quota_oldfiles_cursor_getn(struct quotahandle *qh,
    871       1.1  dholland 			     struct oldfiles_quotacursor *oqc,
    872       1.1  dholland 			     struct quotakey *keys, struct quotaval *vals,
    873       1.1  dholland 			     unsigned maxnum)
    874       1.1  dholland {
    875       1.1  dholland 	unsigned i;
    876       1.1  dholland 
    877       1.1  dholland 	if (maxnum > INT_MAX) {
    878       1.1  dholland 		/* joker, eh? */
    879       1.1  dholland 		errno = EINVAL;
    880       1.1  dholland 		return -1;
    881       1.1  dholland 	}
    882       1.1  dholland 
    883       1.1  dholland 	for (i=0; i<maxnum; i++) {
    884       1.1  dholland 		if (__quota_oldfiles_cursor_atend(oqc)) {
    885       1.1  dholland 			break;
    886       1.1  dholland 		}
    887       1.1  dholland 		if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
    888       1.1  dholland 			if (i > 0) {
    889       1.1  dholland 				/*
    890       1.1  dholland 				 * Succeed witih what we have so far;
    891       1.1  dholland 				 * the next attempt will hit the same
    892       1.1  dholland 				 * error again.
    893       1.1  dholland 				 */
    894       1.1  dholland 				break;
    895       1.1  dholland 			}
    896       1.1  dholland 			return -1;
    897       1.1  dholland 		}
    898       1.1  dholland 	}
    899       1.1  dholland 	return i;
    900       1.1  dholland 
    901       1.1  dholland }
    902       1.1  dholland 
    903       1.1  dholland int
    904       1.1  dholland __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
    905       1.1  dholland {
    906       1.1  dholland 	/* in case one of the sizes is zero */
    907       1.1  dholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
    908       1.1  dholland 		oqc->oqc_didusers = 1;
    909       1.1  dholland 	}
    910       1.1  dholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
    911       1.1  dholland 		oqc->oqc_didgroups = 1;
    912       1.1  dholland 	}
    913       1.1  dholland 
    914       1.1  dholland 	return oqc->oqc_didusers && oqc->oqc_didgroups;
    915       1.1  dholland }
    916       1.1  dholland 
    917       1.1  dholland int
    918       1.1  dholland __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
    919       1.1  dholland {
    920       1.1  dholland 	oqc->oqc_didusers = 0;
    921       1.1  dholland 	oqc->oqc_didgroups = 0;
    922       1.1  dholland 	oqc->oqc_diddefault = 0;
    923       1.1  dholland 	oqc->oqc_pos = 0;
    924       1.1  dholland 	oqc->oqc_didblocks = 0;
    925       1.1  dholland 	return 0;
    926       1.1  dholland }
    927