Add and document the quota_convert function which converts between the

old 32-bit and the new 64-bit formats.
This commit is contained in:
Kirk McKusick 2009-12-28 22:44:19 +00:00
parent 3af26d4abb
commit aee785babd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/quota64/; revision=201144
3 changed files with 124 additions and 10 deletions

View file

@ -154,6 +154,7 @@ int quota_check_path(const struct quotafile *, const char *path);
int quota_read(struct quotafile *, struct dqblk *, int);
int quota_write_limits(struct quotafile *, struct dqblk *, int);
int quota_write_usage(struct quotafile *, struct dqblk *, int);
int quota_convert(struct quotafile *, int);
#endif
__END_DECLS

View file

@ -1,6 +1,6 @@
.\"-
.\" Copyright (c) 2008 Dag-Erling Coïdan Smørgrav
.\" All rights reserved.
.\" Copyright (c) 2009 Dag-Erling Coïdan Smørgrav and
.\" Marshall Kirk McKusick. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 26, 2009
.Dd December 28, 2009
.Dt QUOTAFILE 3
.Os
.Sh NAME
@ -40,6 +40,7 @@
.Nm quota_qfname
.Nm quota_maxid
.Nm quota_check_path
.Nm quota_convert
.Nd "Manipulate quotas"
.Sh LIBRARY
.Lb libutil
@ -72,6 +73,8 @@
.Fn quota_maxid "const struct quotafile *qf"
.Ft int
.Fn quota_check_path "const struct quotafile *qf" "const char *path"
.Ft int
.Fn quota_convert "struct quotafile *qf" "int wordsize"
.Sh DESCRIPTION
These functions are designed to simplify access to filesystem quotas.
If quotas are active on a filesystem,
@ -219,9 +222,23 @@ If the
argument refers to a symbolic link,
.Fn quota_check_path
will follow it.
.Pp
The
.Fn quota_convert
function converts the quota file associated with its
.Va qf
argument to the data size specified by its
.Va wordsize
argument.
The supported wordsize arguments are 32 for the old 32-bit
quota file format and 64 for the new 64-bit quota file format.
The
.Fn quota_convert
function may only be called to operate on quota files that
are not currently active.
.Sh IMPLEMENTATION NOTES
If the underlying quota file is in the old 32-bit format, limit and
usage values written to the quota file will be clipped to 32 bits.
If the underlying quota file is in or converted to the old 32-bit format,
limit and usage values written to the quota file will be clipped to 32 bits.
.Sh RETURN VALUES
If the filesystem has quotas associated with it,
.Fn quota_open
@ -246,6 +263,7 @@ The
.Fn quota_read ,
.Fn quota_write_limits ,
.Fn quota_write_usage ,
.Fn quota_convert ,
and
.Fn quota_close
functions return zero on success.
@ -259,13 +277,13 @@ to indicate the error.
.Xr quota.group 5
.Sh HISTORY
The
.Nm
.Nm quotafile
functions first appeared in
.Fx 8.0 .
.Fx 8.1 .
.Sh AUTHORS
.An -nosplit
The
.Nm
.Nm quotafile
functions and this manual page were written by
.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org
and

View file

@ -255,9 +255,9 @@ quota_maxid(struct quotafile *qf)
return (0);
switch (qf->wordsize) {
case 32:
return (st.st_size / sizeof(struct dqblk32));
return (st.st_size / sizeof(struct dqblk32) - 1);
case 64:
return (st.st_size / sizeof(struct dqblk64) - 1);
return (st.st_size / sizeof(struct dqblk64) - 2);
default:
return (0);
}
@ -494,3 +494,98 @@ quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
}
/* not reached */
}
/*
* Convert a quota file from one format to another.
*/
int
quota_convert(struct quotafile *qf, int wordsize)
{
struct quotafile *newqf;
struct dqhdr64 dqh;
struct dqblk dqblk;
struct group *grp;
int serrno, maxid, id, fd;
/*
* Quotas must not be active and quotafile must be open
* for reading and writing.
*/
if ((qf->accmode & O_RDWR) != O_RDWR || qf->fd == -1) {
errno = EBADF;
return (-1);
}
if ((wordsize != 32 && wordsize != 64) ||
wordsize == qf->wordsize) {
errno = EINVAL;
return (-1);
}
maxid = quota_maxid(qf);
if ((newqf = calloc(1, sizeof(*qf))) == NULL) {
errno = ENOMEM;
return (-1);
}
*newqf = *qf;
snprintf(newqf->qfname, MAXPATHLEN + 1, "%s_%d.orig", qf->qfname,
qf->wordsize);
if (rename(qf->qfname, newqf->qfname) < 0) {
free(newqf);
return (-1);
}
if ((newqf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
serrno = errno;
goto error;
}
newqf->wordsize = wordsize;
if (wordsize == 64) {
memset(&dqh, 0, sizeof(dqh));
memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
if (write(newqf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
serrno = errno;
goto error;
}
}
grp = getgrnam(QUOTAGROUP);
fchown(newqf->fd, 0, grp ? grp->gr_gid : 0);
fchmod(newqf->fd, 0640);
for (id = 0; id <= maxid; id++) {
if ((quota_read(qf, &dqblk, id)) < 0)
break;
switch (newqf->wordsize) {
case 32:
if ((quota_write32(newqf, &dqblk, id)) < 0)
break;
continue;
case 64:
if ((quota_write64(newqf, &dqblk, id)) < 0)
break;
continue;
default:
errno = EINVAL;
break;
}
}
if (id < maxid) {
serrno = errno;
goto error;
}
/*
* Update the passed in quotafile to reference the new file
* of the converted format size.
*/
fd = qf->fd;
qf->fd = newqf->fd;
newqf->fd = fd;
qf->wordsize = newqf->wordsize;
quota_close(newqf);
return (0);
error:
/* put back the original file */
(void) rename(newqf->qfname, qf->qfname);
quota_close(newqf);
errno = serrno;
return (-1);
}