quotafile.c revision 187914
1/*- 2 * Copyright (c) 2008 Dag-Erling Co��dan Sm��rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: projects/quota64/lib/libutil/quotafile.c 187914 2009-01-30 13:54:03Z des $ 28 */ 29 30#include <sys/types.h> 31#include <sys/endian.h> 32#include <sys/stat.h> 33 34#include <ufs/ufs/quota.h> 35 36#include <errno.h> 37#include <fcntl.h> 38#include <grp.h> 39#include <pwd.h> 40#include <libutil.h> 41#include <stdint.h> 42#include <stdlib.h> 43#include <string.h> 44#include <unistd.h> 45 46struct quotafile { 47 int fd; 48 int type; /* 32 or 64 */ 49}; 50 51struct quotafile * 52quota_open(const char *fn) 53{ 54 struct quotafile *qf; 55 struct dqhdr64 dqh; 56 int serrno; 57 58 if ((qf = calloc(1, sizeof(*qf))) == NULL) 59 return (NULL); 60 if ((qf->fd = open(fn, O_RDWR)) < 0) { 61 serrno = errno; 62 free(qf); 63 errno = serrno; 64 return (NULL); 65 } 66 qf->type = 32; 67 switch (read(qf->fd, &dqh, sizeof(dqh))) { 68 case -1: 69 serrno = errno; 70 close(qf->fd); 71 free(qf); 72 errno = serrno; 73 return (NULL); 74 case sizeof(dqh): 75 if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) { 76 /* no magic, assume 32 bits */ 77 qf->type = 32; 78 return (qf); 79 } 80 if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION || 81 be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) || 82 be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) { 83 /* correct magic, wrong version / lengths */ 84 close(qf->fd); 85 free(qf); 86 errno = EINVAL; 87 return (NULL); 88 } 89 qf->type = 64; 90 return (qf); 91 default: 92 qf->type = 32; 93 return (qf); 94 } 95 /* not reached */ 96} 97 98struct quotafile * 99quota_create(const char *fn) 100{ 101 struct quotafile *qf; 102 struct dqhdr64 dqh; 103 struct group *grp; 104 int serrno; 105 106 if ((qf = calloc(1, sizeof(*qf))) == NULL) 107 return (NULL); 108 if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) { 109 serrno = errno; 110 free(qf); 111 errno = serrno; 112 return (NULL); 113 } 114 qf->type = 64; 115 memset(&dqh, 0, sizeof(dqh)); 116 memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic)); 117 dqh.dqh_version = htobe32(Q_DQHDR64_VERSION); 118 dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64)); 119 dqh.dqh_reclen = htobe32(sizeof(struct dqblk64)); 120 if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) { 121 serrno = errno; 122 unlink(fn); 123 close(qf->fd); 124 free(qf); 125 errno = serrno; 126 return (NULL); 127 } 128 grp = getgrnam(QUOTAGROUP); 129 fchown(qf->fd, 0, grp ? grp->gr_gid : 0); 130 fchmod(qf->fd, 0640); 131 return (qf); 132} 133 134void 135quota_close(struct quotafile *qf) 136{ 137 138 close(qf->fd); 139 free(qf); 140} 141 142static int 143quota_read32(struct quotafile *qf, struct dqblk *dqb, int id) 144{ 145 struct dqblk32 dqb32; 146 off_t off; 147 148 off = id * sizeof(struct dqblk32); 149 if (lseek(qf->fd, off, SEEK_SET) == -1) 150 return (-1); 151 switch (read(qf->fd, &dqb32, sizeof(dqb32))) { 152 case 0: 153 memset(&dqb, 0, sizeof(*dqb)); 154 return (0); 155 case sizeof(dqb32): 156 dqb->dqb_bhardlimit = dqb32.dqb_bhardlimit; 157 dqb->dqb_bsoftlimit = dqb32.dqb_bsoftlimit; 158 dqb->dqb_curblocks = dqb32.dqb_curblocks; 159 dqb->dqb_ihardlimit = dqb32.dqb_ihardlimit; 160 dqb->dqb_isoftlimit = dqb32.dqb_isoftlimit; 161 dqb->dqb_curinodes = dqb32.dqb_curinodes; 162 dqb->dqb_btime = dqb32.dqb_btime; 163 dqb->dqb_itime = dqb32.dqb_itime; 164 return (0); 165 default: 166 return (-1); 167 } 168} 169 170static int 171quota_read64(struct quotafile *qf, struct dqblk *dqb, int id) 172{ 173 struct dqblk64 dqb64; 174 off_t off; 175 176 off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64); 177 if (lseek(qf->fd, off, SEEK_SET) == -1) 178 return (-1); 179 switch (read(qf->fd, &dqb64, sizeof(dqb64))) { 180 case 0: 181 memset(&dqb, 0, sizeof(*dqb)); 182 return (0); 183 case sizeof(dqb64): 184 dqb->dqb_bhardlimit = be64toh(dqb64.dqb_bhardlimit); 185 dqb->dqb_bsoftlimit = be64toh(dqb64.dqb_bsoftlimit); 186 dqb->dqb_curblocks = be64toh(dqb64.dqb_curblocks); 187 dqb->dqb_ihardlimit = be64toh(dqb64.dqb_ihardlimit); 188 dqb->dqb_isoftlimit = be64toh(dqb64.dqb_isoftlimit); 189 dqb->dqb_curinodes = be64toh(dqb64.dqb_curinodes); 190 dqb->dqb_btime = be64toh(dqb64.dqb_btime); 191 dqb->dqb_itime = be64toh(dqb64.dqb_itime); 192 return (0); 193 default: 194 return (-1); 195 } 196} 197 198int 199quota_read(struct quotafile *qf, struct dqblk *dqb, int id) 200{ 201 202 switch (qf->type) { 203 case 32: 204 return quota_read32(qf, dqb, id); 205 case 64: 206 return quota_read64(qf, dqb, id); 207 default: 208 errno = EINVAL; 209 return (-1); 210 } 211 /* not reached */ 212} 213 214#define CLIP32(u64) ((u64) > UINT32_MAX ? UINT32_MAX : (uint32_t)(u64)) 215 216static int 217quota_write32(struct quotafile *qf, const struct dqblk *dqb, int id) 218{ 219 struct dqblk32 dqb32; 220 off_t off; 221 222 dqb32.dqb_bhardlimit = CLIP32(dqb->dqb_bhardlimit); 223 dqb32.dqb_bsoftlimit = CLIP32(dqb->dqb_bsoftlimit); 224 dqb32.dqb_curblocks = CLIP32(dqb->dqb_curblocks); 225 dqb32.dqb_ihardlimit = CLIP32(dqb->dqb_ihardlimit); 226 dqb32.dqb_isoftlimit = CLIP32(dqb->dqb_isoftlimit); 227 dqb32.dqb_curinodes = CLIP32(dqb->dqb_curinodes); 228 dqb32.dqb_btime = CLIP32(dqb->dqb_btime); 229 dqb32.dqb_itime = CLIP32(dqb->dqb_itime); 230 231 off = id * sizeof(struct dqblk32); 232 if (lseek(qf->fd, off, SEEK_SET) == -1) 233 return (-1); 234 return (write(qf->fd, &dqb32, sizeof(dqb32))); 235} 236 237static int 238quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id) 239{ 240 struct dqblk64 dqb64; 241 off_t off; 242 243 dqb64.dqb_bhardlimit = htobe64(dqb->dqb_bhardlimit); 244 dqb64.dqb_bsoftlimit = htobe64(dqb->dqb_bsoftlimit); 245 dqb64.dqb_curblocks = htobe64(dqb->dqb_curblocks); 246 dqb64.dqb_ihardlimit = htobe64(dqb->dqb_ihardlimit); 247 dqb64.dqb_isoftlimit = htobe64(dqb->dqb_isoftlimit); 248 dqb64.dqb_curinodes = htobe64(dqb->dqb_curinodes); 249 dqb64.dqb_btime = htobe64(dqb->dqb_btime); 250 dqb64.dqb_itime = htobe64(dqb->dqb_itime); 251 252 off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64); 253 if (lseek(qf->fd, off, SEEK_SET) == -1) 254 return (-1); 255 return (write(qf->fd, &dqb64, sizeof(dqb64))); 256} 257 258int 259quota_write(struct quotafile *qf, const struct dqblk *dqb, int id) 260{ 261 262 switch (qf->type) { 263 case 32: 264 return quota_write32(qf, dqb, id); 265 case 64: 266 return quota_write64(qf, dqb, id); 267 default: 268 errno = EINVAL; 269 return (-1); 270 } 271 /* not reached */ 272} 273