From owner-svn-src-projects@FreeBSD.ORG Mon Dec 28 22:44:20 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3C58A106568B; Mon, 28 Dec 2009 22:44:20 +0000 (UTC) (envelope-from mckusick@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2C2EE8FC08; Mon, 28 Dec 2009 22:44:20 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nBSMiKkO003435; Mon, 28 Dec 2009 22:44:20 GMT (envelope-from mckusick@svn.freebsd.org) Received: (from mckusick@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nBSMiKxY003431; Mon, 28 Dec 2009 22:44:20 GMT (envelope-from mckusick@svn.freebsd.org) Message-Id: <200912282244.nBSMiKxY003431@svn.freebsd.org> From: Kirk McKusick Date: Mon, 28 Dec 2009 22:44:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201144 - projects/quota64/lib/libutil X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Dec 2009 22:44:20 -0000 Author: mckusick Date: Mon Dec 28 22:44:19 2009 New Revision: 201144 URL: http://svn.freebsd.org/changeset/base/201144 Log: Add and document the quota_convert function which converts between the old 32-bit and the new 64-bit formats. Modified: projects/quota64/lib/libutil/libutil.h projects/quota64/lib/libutil/quotafile.3 projects/quota64/lib/libutil/quotafile.c Modified: projects/quota64/lib/libutil/libutil.h ============================================================================== --- projects/quota64/lib/libutil/libutil.h Mon Dec 28 22:15:11 2009 (r201143) +++ projects/quota64/lib/libutil/libutil.h Mon Dec 28 22:44:19 2009 (r201144) @@ -154,6 +154,7 @@ int quota_check_path(const struct quotaf 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 Modified: projects/quota64/lib/libutil/quotafile.3 ============================================================================== --- projects/quota64/lib/libutil/quotafile.3 Mon Dec 28 22:15:11 2009 (r201143) +++ projects/quota64/lib/libutil/quotafile.3 Mon Dec 28 22:44:19 2009 (r201144) @@ -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 Modified: projects/quota64/lib/libutil/quotafile.c ============================================================================== --- projects/quota64/lib/libutil/quotafile.c Mon Dec 28 22:15:11 2009 (r201143) +++ projects/quota64/lib/libutil/quotafile.c Mon Dec 28 22:44:19 2009 (r201144) @@ -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, } /* 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); +}