Implement fallback direct access to quota1-type quota files.
Uses (mostly) code from repquota. Add some missing pieces that weren't in repquota. Use the direct file access code for cursors if proplib reports the quota version is 1.
This commit is contained in:
parent
59bb0b8307
commit
8d70e807c3
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.4 2012/01/09 15:29:55 dholland Exp $
|
||||
# $NetBSD: Makefile,v 1.5 2012/01/09 15:41:58 dholland Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
@ -20,5 +20,6 @@ SRCS+= quota_get.c quota_put.c quota_delete.c
|
|||
SRCS+= quota_cursor.c
|
||||
SRCS+= quota_proplib.c
|
||||
SRCS+= quota_nfs.c
|
||||
SRCS+= quota_oldfiles.c
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: quota_cursor.c,v 1.2 2012/01/09 15:40:10 dholland Exp $ */
|
||||
/* $NetBSD: quota_cursor.c,v 1.3 2012/01/09 15:41:58 dholland Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: quota_cursor.c,v 1.2 2012/01/09 15:40:10 dholland Exp $");
|
||||
__RCSID("$NetBSD: quota_cursor.c,v 1.3 2012/01/09 15:41:58 dholland Exp $");
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
@ -41,6 +41,7 @@ struct quotacursor *
|
|||
quota_opencursor(struct quotahandle *qh)
|
||||
{
|
||||
struct quotacursor *qc;
|
||||
int8_t version;
|
||||
int serrno;
|
||||
|
||||
if (qh->qh_isnfs) {
|
||||
|
@ -48,19 +49,45 @@ quota_opencursor(struct quotahandle *qh)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (__quota_proplib_getversion(qh, &version)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the time being at least the version 1 kernel code
|
||||
* cannot do cursors.
|
||||
*/
|
||||
if (version == 1 && !qh->qh_hasoldfiles) {
|
||||
if (__quota_oldfiles_initialize(qh)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
qc = malloc(sizeof(*qc));
|
||||
if (qc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qc->qc_qh = qh;
|
||||
qc->u.qc_proplib = __quota_proplib_cursor_create();
|
||||
|
||||
if (qc->u.qc_proplib == NULL) {
|
||||
serrno = errno;
|
||||
free(qc);
|
||||
errno = serrno;
|
||||
return NULL;
|
||||
if (version == 1) {
|
||||
qc->qc_type = QC_OLDFILES;
|
||||
qc->u.qc_oldfiles = __quota_oldfiles_cursor_create(qh);
|
||||
if (qc->u.qc_oldfiles == NULL) {
|
||||
serrno = errno;
|
||||
free(qc);
|
||||
errno = serrno;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
qc->qc_type = QC_PROPLIB;
|
||||
qc->u.qc_proplib = __quota_proplib_cursor_create();
|
||||
if (qc->u.qc_proplib == NULL) {
|
||||
serrno = errno;
|
||||
free(qc);
|
||||
errno = serrno;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return qc;
|
||||
}
|
||||
|
@ -68,22 +95,47 @@ quota_opencursor(struct quotahandle *qh)
|
|||
void
|
||||
quotacursor_close(struct quotacursor *qc)
|
||||
{
|
||||
__quota_proplib_cursor_destroy(qc->u.qc_proplib);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
__quota_proplib_cursor_destroy(qc->u.qc_proplib);
|
||||
break;
|
||||
case QC_OLDFILES:
|
||||
__quota_oldfiles_cursor_destroy(qc->u.qc_oldfiles);
|
||||
break;
|
||||
}
|
||||
free(qc);
|
||||
}
|
||||
|
||||
int
|
||||
quotacursor_skipidtype(struct quotacursor *qc, unsigned idtype)
|
||||
{
|
||||
return __quota_proplib_cursor_skipidtype(qc->u.qc_proplib, idtype);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
return __quota_proplib_cursor_skipidtype(qc->u.qc_proplib,
|
||||
idtype);
|
||||
case QC_OLDFILES:
|
||||
return __quota_oldfiles_cursor_skipidtype(qc->u.qc_oldfiles,
|
||||
idtype);
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
quotacursor_get(struct quotacursor *qc,
|
||||
struct quotakey *qk_ret, struct quotaval *qv_ret)
|
||||
{
|
||||
return __quota_proplib_cursor_get(qc->qc_qh, qc->u.qc_proplib,
|
||||
qk_ret, qv_ret);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
return __quota_proplib_cursor_get(qc->qc_qh, qc->u.qc_proplib,
|
||||
qk_ret, qv_ret);
|
||||
case QC_OLDFILES:
|
||||
return __quota_oldfiles_cursor_get(qc->qc_qh,
|
||||
qc->u.qc_oldfiles,
|
||||
qk_ret, qv_ret);
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -91,19 +143,42 @@ quotacursor_getn(struct quotacursor *qc,
|
|||
struct quotakey *keys, struct quotaval *vals,
|
||||
unsigned maxnum)
|
||||
{
|
||||
return __quota_proplib_cursor_getn(qc->qc_qh, qc->u.qc_proplib,
|
||||
keys, vals, maxnum);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
return __quota_proplib_cursor_getn(qc->qc_qh, qc->u.qc_proplib,
|
||||
keys, vals, maxnum);
|
||||
case QC_OLDFILES:
|
||||
return __quota_oldfiles_cursor_getn(qc->qc_qh,
|
||||
qc->u.qc_oldfiles,
|
||||
keys, vals, maxnum);
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
quotacursor_atend(struct quotacursor *qc)
|
||||
{
|
||||
return __quota_proplib_cursor_atend(qc->qc_qh,
|
||||
qc->u.qc_proplib);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
return __quota_proplib_cursor_atend(qc->qc_qh,
|
||||
qc->u.qc_proplib);
|
||||
case QC_OLDFILES:
|
||||
return __quota_oldfiles_cursor_atend(qc->u.qc_oldfiles);
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
quotacursor_rewind(struct quotacursor *qc)
|
||||
{
|
||||
return __quota_proplib_cursor_rewind(qc->u.qc_proplib);
|
||||
switch (qc->qc_type) {
|
||||
case QC_PROPLIB:
|
||||
return __quota_proplib_cursor_rewind(qc->u.qc_proplib);
|
||||
case QC_OLDFILES:
|
||||
return __quota_oldfiles_cursor_rewind(qc->u.qc_oldfiles);
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,530 @@
|
|||
/* $NetBSD: quota_oldfiles.c,v 1.1 2012/01/09 15:41:58 dholland Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Robert Elz at The University of Melbourne.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <fstab.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
|
||||
#include <ufs/ufs/quota1.h>
|
||||
|
||||
#include <quota.h>
|
||||
#include "quotapvt.h"
|
||||
|
||||
struct oldfiles_quotacursor {
|
||||
unsigned oqc_doingusers;
|
||||
unsigned oqc_doinggroups;
|
||||
|
||||
unsigned oqc_numusers;
|
||||
unsigned oqc_numgroups;
|
||||
|
||||
unsigned oqc_didusers;
|
||||
unsigned oqc_didgroups;
|
||||
unsigned oqc_diddefault;
|
||||
unsigned oqc_pos;
|
||||
unsigned oqc_didblocks;
|
||||
};
|
||||
|
||||
static uint64_t
|
||||
dqblk_limit(uint32_t val)
|
||||
{
|
||||
if (val == 0) {
|
||||
return QUOTA_NOLIMIT;
|
||||
} else {
|
||||
return val - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
|
||||
{
|
||||
qv->qv_hardlimit = dqblk_limit(dq->dqb_bhardlimit);
|
||||
qv->qv_softlimit = dqblk_limit(dq->dqb_bsoftlimit);
|
||||
qv->qv_usage = dq->dqb_curblocks;
|
||||
qv->qv_expiretime = dq->dqb_btime;
|
||||
qv->qv_grace = QUOTA_NOTIME;
|
||||
}
|
||||
|
||||
static void
|
||||
dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
|
||||
{
|
||||
qv->qv_hardlimit = dqblk_limit(dq->dqb_ihardlimit);
|
||||
qv->qv_softlimit = dqblk_limit(dq->dqb_isoftlimit);
|
||||
qv->qv_usage = dq->dqb_curinodes;
|
||||
qv->qv_expiretime = dq->dqb_itime;
|
||||
qv->qv_grace = QUOTA_NOTIME;
|
||||
}
|
||||
|
||||
static int
|
||||
__quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0 && (errno == EACCES || errno == EROFS)) {
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*fd_ret = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_initialize(struct quotahandle *qh)
|
||||
{
|
||||
static const char *const names[] = INITQFNAMES;
|
||||
|
||||
struct fstab *fs;
|
||||
char buf[sizeof(fs->fs_mntops)];
|
||||
char *opt, *state, *s;
|
||||
char path[PATH_MAX];
|
||||
const char *userquotafile, *groupquotafile;
|
||||
int hasuserquota, hasgroupquota;
|
||||
|
||||
if (qh->qh_hasoldfiles) {
|
||||
/* already initialized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the fstab entry.
|
||||
*
|
||||
* XXX: should be able to handle not just ffs quota1 files but
|
||||
* also lfs and even ext2fs.
|
||||
*/
|
||||
setfsent();
|
||||
while ((fs = getfsent()) != NULL) {
|
||||
if (!strcmp(fs->fs_vfstype, "ffs") &&
|
||||
!strcmp(fs->fs_file, qh->qh_mountpoint)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
endfsent();
|
||||
|
||||
if (fs == NULL) {
|
||||
warnx("%s not found in fstab", qh->qh_mountpoint);
|
||||
errno = ENXIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect the mount options to find the quota files.
|
||||
* XXX this info should be gotten from the kernel.
|
||||
*
|
||||
* The options are:
|
||||
* userquota[=path] enable user quotas
|
||||
* groupquota[=path] enable group quotas
|
||||
*/
|
||||
hasuserquota = hasgroupquota = 0;
|
||||
userquotafile = groupquotafile = NULL;
|
||||
strlcpy(buf, fs->fs_mntops, sizeof(buf));
|
||||
for (opt = strtok_r(buf, ",", &state);
|
||||
opt != NULL;
|
||||
opt = strtok_r(NULL, ",", &state)) {
|
||||
s = strchr(opt, '=');
|
||||
if (s != NULL) {
|
||||
*(s++) = '\0';
|
||||
}
|
||||
if (!strcmp(opt, "userquota")) {
|
||||
hasuserquota = 1;
|
||||
if (s != NULL) {
|
||||
userquotafile = s;
|
||||
}
|
||||
} else if (!strcmp(opt, "groupquota")) {
|
||||
hasgroupquota = 1;
|
||||
if (s != NULL) {
|
||||
groupquotafile = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasuserquota && !hasgroupquota) {
|
||||
errno = ENXIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hasuserquota) {
|
||||
if (userquotafile == NULL) {
|
||||
(void)snprintf(path, sizeof(path), "%s/%s.%s",
|
||||
fs->fs_file,
|
||||
QUOTAFILENAME, names[USRQUOTA]);
|
||||
userquotafile = path;
|
||||
}
|
||||
if (__quota_oldfiles_open(qh, userquotafile,
|
||||
&qh->qh_userfile)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (hasgroupquota) {
|
||||
if (groupquotafile == NULL) {
|
||||
(void)snprintf(path, sizeof(path), "%s/%s.%s",
|
||||
fs->fs_file,
|
||||
QUOTAFILENAME, names[GRPQUOTA]);
|
||||
groupquotafile = path;
|
||||
}
|
||||
if (__quota_oldfiles_open(qh, groupquotafile,
|
||||
&qh->qh_groupfile)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
qh->qh_hasoldfiles = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
__quota_oldfiles_getimplname(struct quotahandle *qh)
|
||||
{
|
||||
return "ffs quota1 direct file access";
|
||||
}
|
||||
|
||||
static int
|
||||
__quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
|
||||
struct quotaval *qv, int *isallzero)
|
||||
{
|
||||
int file;
|
||||
off_t pos;
|
||||
struct dqblk dq;
|
||||
ssize_t result;
|
||||
|
||||
switch (qk->qk_idtype) {
|
||||
case QUOTA_IDTYPE_USER:
|
||||
file = qh->qh_userfile;
|
||||
break;
|
||||
case QUOTA_IDTYPE_GROUP:
|
||||
file = qh->qh_groupfile;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qk->qk_id == QUOTA_DEFAULTID) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = qk->qk_id * sizeof(struct dqblk);
|
||||
}
|
||||
|
||||
result = pread(file, &dq, sizeof(dq), pos);
|
||||
if (result < 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((size_t)result != sizeof(dq)) {
|
||||
errno = EFTYPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (qk->qk_objtype) {
|
||||
case QUOTA_OBJTYPE_BLOCKS:
|
||||
dqblk_getblocks(&dq, qv);
|
||||
break;
|
||||
case QUOTA_OBJTYPE_FILES:
|
||||
dqblk_getfiles(&dq, qv);
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qk->qk_id == QUOTA_DEFAULTID) {
|
||||
qv->qv_usage = 0;
|
||||
qv->qv_grace = qv->qv_expiretime;
|
||||
qv->qv_expiretime = QUOTA_NOTIME;
|
||||
} else if (qk->qk_id == 0) {
|
||||
qv->qv_hardlimit = 0;
|
||||
qv->qv_softlimit = 0;
|
||||
qv->qv_expiretime = QUOTA_NOTIME;
|
||||
qv->qv_grace = QUOTA_NOTIME;
|
||||
}
|
||||
|
||||
if (isallzero != NULL) {
|
||||
if (dq.dqb_bhardlimit == 0 &&
|
||||
dq.dqb_bsoftlimit == 0 &&
|
||||
dq.dqb_curblocks == 0 &&
|
||||
dq.dqb_ihardlimit == 0 &&
|
||||
dq.dqb_isoftlimit == 0 &&
|
||||
dq.dqb_curinodes == 0 &&
|
||||
dq.dqb_btime == 0 &&
|
||||
dq.dqb_itime == 0) {
|
||||
*isallzero = 1;
|
||||
} else {
|
||||
*isallzero = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
|
||||
struct quotaval *qv)
|
||||
{
|
||||
return __quota_oldfiles_doget(qh, qk, qv, NULL);
|
||||
}
|
||||
|
||||
struct oldfiles_quotacursor *
|
||||
__quota_oldfiles_cursor_create(struct quotahandle *qh)
|
||||
{
|
||||
struct oldfiles_quotacursor *oqc;
|
||||
struct stat st;
|
||||
int serrno;
|
||||
|
||||
oqc = malloc(sizeof(*oqc));
|
||||
if (oqc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oqc->oqc_didusers = 0;
|
||||
oqc->oqc_didgroups = 0;
|
||||
oqc->oqc_diddefault = 0;
|
||||
oqc->oqc_pos = 0;
|
||||
oqc->oqc_didblocks = 0;
|
||||
|
||||
if (qh->qh_userfile >= 0) {
|
||||
oqc->oqc_doingusers = 1;
|
||||
} else {
|
||||
oqc->oqc_doingusers = 0;
|
||||
oqc->oqc_didusers = 1;
|
||||
}
|
||||
|
||||
if (qh->qh_groupfile >= 0) {
|
||||
oqc->oqc_doinggroups = 1;
|
||||
} else {
|
||||
oqc->oqc_doinggroups = 0;
|
||||
oqc->oqc_didgroups = 1;
|
||||
}
|
||||
|
||||
if (fstat(qh->qh_userfile, &st) < 0) {
|
||||
serrno = errno;
|
||||
free(oqc);
|
||||
errno = serrno;
|
||||
return NULL;
|
||||
}
|
||||
oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
|
||||
|
||||
if (fstat(qh->qh_groupfile, &st) < 0) {
|
||||
serrno = errno;
|
||||
free(oqc);
|
||||
errno = serrno;
|
||||
return NULL;
|
||||
}
|
||||
oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
|
||||
|
||||
return oqc;
|
||||
}
|
||||
|
||||
void
|
||||
__quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
|
||||
{
|
||||
free(oqc);
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
|
||||
unsigned idtype)
|
||||
{
|
||||
switch (idtype) {
|
||||
case QUOTA_IDTYPE_USER:
|
||||
oqc->oqc_doingusers = 0;
|
||||
oqc->oqc_didusers = 1;
|
||||
break;
|
||||
case QUOTA_IDTYPE_GROUP:
|
||||
oqc->oqc_doinggroups = 0;
|
||||
oqc->oqc_didgroups = 1;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_cursor_get(struct quotahandle *qh,
|
||||
struct oldfiles_quotacursor *oqc,
|
||||
struct quotakey *key, struct quotaval *val)
|
||||
{
|
||||
unsigned maxpos;
|
||||
int isallzero;
|
||||
|
||||
/* in case one of the sizes is zero */
|
||||
if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
|
||||
oqc->oqc_didusers = 1;
|
||||
}
|
||||
if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
|
||||
oqc->oqc_didgroups = 1;
|
||||
}
|
||||
|
||||
again:
|
||||
/*
|
||||
* Figure out what to get
|
||||
*/
|
||||
|
||||
if (!oqc->oqc_didusers) {
|
||||
key->qk_idtype = QUOTA_IDTYPE_USER;
|
||||
maxpos = oqc->oqc_numusers;
|
||||
} else if (!oqc->oqc_didgroups) {
|
||||
key->qk_idtype = QUOTA_IDTYPE_GROUP;
|
||||
maxpos = oqc->oqc_numgroups;
|
||||
} else {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!oqc->oqc_diddefault) {
|
||||
key->qk_id = QUOTA_DEFAULTID;
|
||||
} else {
|
||||
key->qk_id = oqc->oqc_pos;
|
||||
}
|
||||
|
||||
if (!oqc->oqc_didblocks) {
|
||||
key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
|
||||
} else {
|
||||
key->qk_objtype = QUOTA_OBJTYPE_FILES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get it
|
||||
*/
|
||||
|
||||
if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance the cursor
|
||||
*/
|
||||
if (!oqc->oqc_didblocks) {
|
||||
oqc->oqc_didblocks = 1;
|
||||
} else {
|
||||
oqc->oqc_didblocks = 0;
|
||||
if (!oqc->oqc_diddefault) {
|
||||
oqc->oqc_diddefault = 1;
|
||||
} else {
|
||||
oqc->oqc_pos++;
|
||||
if (oqc->oqc_pos >= maxpos) {
|
||||
oqc->oqc_pos = 0;
|
||||
oqc->oqc_diddefault = 0;
|
||||
if (!oqc->oqc_didusers) {
|
||||
oqc->oqc_didusers = 1;
|
||||
} else {
|
||||
oqc->oqc_didgroups = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got an all-zero dqblk (e.g. from the middle of a hole
|
||||
* in the quota file) don't bother returning it to the caller.
|
||||
*
|
||||
* ...unless we're at the end of the data, to avoid going past
|
||||
* the end and generating a spurious failure. There's no
|
||||
* reasonable way to make _atend detect empty entries at the
|
||||
* end of the quota files.
|
||||
*/
|
||||
if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
|
||||
goto again;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_cursor_getn(struct quotahandle *qh,
|
||||
struct oldfiles_quotacursor *oqc,
|
||||
struct quotakey *keys, struct quotaval *vals,
|
||||
unsigned maxnum)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (maxnum > INT_MAX) {
|
||||
/* joker, eh? */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i<maxnum; i++) {
|
||||
if (__quota_oldfiles_cursor_atend(oqc)) {
|
||||
break;
|
||||
}
|
||||
if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
|
||||
if (i > 0) {
|
||||
/*
|
||||
* Succeed witih what we have so far;
|
||||
* the next attempt will hit the same
|
||||
* error again.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
|
||||
{
|
||||
/* in case one of the sizes is zero */
|
||||
if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
|
||||
oqc->oqc_didusers = 1;
|
||||
}
|
||||
if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
|
||||
oqc->oqc_didgroups = 1;
|
||||
}
|
||||
|
||||
return oqc->oqc_didusers && oqc->oqc_didgroups;
|
||||
}
|
||||
|
||||
int
|
||||
__quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
|
||||
{
|
||||
oqc->oqc_didusers = 0;
|
||||
oqc->oqc_didgroups = 0;
|
||||
oqc->oqc_diddefault = 0;
|
||||
oqc->oqc_pos = 0;
|
||||
oqc->oqc_didblocks = 0;
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: quota_open.c,v 1.3 2012/01/09 15:29:56 dholland Exp $ */
|
||||
/* $NetBSD: quota_open.c,v 1.4 2012/01/09 15:41:58 dholland Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
|
@ -29,12 +29,13 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: quota_open.c,v 1.3 2012/01/09 15:29:56 dholland Exp $");
|
||||
__RCSID("$NetBSD: quota_open.c,v 1.4 2012/01/09 15:41:58 dholland Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <quota.h>
|
||||
|
@ -101,6 +102,10 @@ quota_open(const char *path)
|
|||
|
||||
qh->qh_isnfs = isnfs;
|
||||
|
||||
qh->qh_hasoldfiles = 0;
|
||||
qh->qh_userfile = -1;
|
||||
qh->qh_groupfile = -1;
|
||||
|
||||
return qh;
|
||||
}
|
||||
|
||||
|
@ -119,6 +124,12 @@ quota_getmountdevice(struct quotahandle *qh)
|
|||
void
|
||||
quota_close(struct quotahandle *qh)
|
||||
{
|
||||
if (qh->qh_userfile >= 0) {
|
||||
close(qh->qh_userfile);
|
||||
}
|
||||
if (qh->qh_groupfile >= 0) {
|
||||
close(qh->qh_groupfile);
|
||||
}
|
||||
free(qh->qh_mountdevice);
|
||||
free(qh->qh_mountpoint);
|
||||
free(qh);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: quota_proplib.c,v 1.4 2012/01/09 15:40:10 dholland Exp $ */
|
||||
/* $NetBSD: quota_proplib.c,v 1.5 2012/01/09 15:41:58 dholland Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2011 Manuel Bouyer
|
||||
* All rights reserved.
|
||||
|
@ -26,7 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: quota_proplib.c,v 1.4 2012/01/09 15:40:10 dholland Exp $");
|
||||
__RCSID("$NetBSD: quota_proplib.c,v 1.5 2012/01/09 15:41:58 dholland Exp $");
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -55,7 +55,7 @@ struct proplib_quotacursor {
|
|||
unsigned didblocks;
|
||||
};
|
||||
|
||||
static int
|
||||
int
|
||||
__quota_proplib_getversion(struct quotahandle *qh, int8_t *version_ret)
|
||||
{
|
||||
const char *idtype;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: quotapvt.h,v 1.5 2012/01/09 15:40:10 dholland Exp $ */
|
||||
/* $NetBSD: quotapvt.h,v 1.6 2012/01/09 15:41:59 dholland Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
|
@ -32,18 +32,27 @@ struct quotahandle {
|
|||
char *qh_mountpoint;
|
||||
char *qh_mountdevice;
|
||||
int qh_isnfs;
|
||||
char spare[14*sizeof(char *) + 15 * sizeof(int)];
|
||||
|
||||
/* these are used only by quota_oldfiles */
|
||||
int qh_hasoldfiles;
|
||||
int qh_userfile;
|
||||
int qh_groupfile;
|
||||
|
||||
char spare[14*sizeof(char *) + 12 * sizeof(int)];
|
||||
};
|
||||
|
||||
struct quotacursor {
|
||||
struct quotahandle *qc_qh;
|
||||
enum { QC_PROPLIB, QC_OLDFILES } qc_type;
|
||||
union {
|
||||
struct proplib_quotacursor *qc_proplib;
|
||||
struct oldfiles_quotacursor *qc_oldfiles;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/* proplib kernel interface */
|
||||
int __quota_proplib_getversion(struct quotahandle *qh, int8_t *version_ret);
|
||||
const char *__quota_proplib_getimplname(struct quotahandle *);
|
||||
int __quota_proplib_get(struct quotahandle *qh, const struct quotakey *qk,
|
||||
struct quotaval *qv);
|
||||
|
@ -68,6 +77,27 @@ int __quota_nfs_get(struct quotahandle *qh, const struct quotakey *qk,
|
|||
struct quotaval *qv);
|
||||
|
||||
|
||||
/* direct interface to old (quota1-type) files */
|
||||
int __quota_oldfiles_initialize(struct quotahandle *qh);
|
||||
const char *__quota_oldfiles_getimplname(struct quotahandle *);
|
||||
int __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
|
||||
struct quotaval *qv);
|
||||
struct oldfiles_quotacursor *
|
||||
__quota_oldfiles_cursor_create(struct quotahandle *);
|
||||
void __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *);
|
||||
int __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *,
|
||||
unsigned idtype);
|
||||
int __quota_oldfiles_cursor_get(struct quotahandle *,
|
||||
struct oldfiles_quotacursor *,
|
||||
struct quotakey *, struct quotaval *);
|
||||
int __quota_oldfiles_cursor_getn(struct quotahandle *,
|
||||
struct oldfiles_quotacursor *,
|
||||
struct quotakey *, struct quotaval *,
|
||||
unsigned);
|
||||
int __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *);
|
||||
int __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *);
|
||||
|
||||
|
||||
/* compat for old library */
|
||||
int __quota_getquota(const char *path, struct quotaval *qv, uid_t id,
|
||||
const char *class);
|
||||
|
|
Loading…
Reference in New Issue