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:
dholland 2012-01-09 15:41:58 +00:00
parent 59bb0b8307
commit 8d70e807c3
6 changed files with 672 additions and 25 deletions

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);