quota_oldfiles.c revision 1.2 1 1.2 dholland /* $NetBSD: quota_oldfiles.c,v 1.2 2012/01/09 15:45:19 dholland Exp $ */
2 1.1 dholland
3 1.1 dholland /*
4 1.1 dholland * Copyright (c) 1980, 1990, 1993
5 1.1 dholland * The Regents of the University of California. All rights reserved.
6 1.1 dholland *
7 1.1 dholland * This code is derived from software contributed to Berkeley by
8 1.1 dholland * Robert Elz at The University of Melbourne.
9 1.1 dholland *
10 1.1 dholland * Redistribution and use in source and binary forms, with or without
11 1.1 dholland * modification, are permitted provided that the following conditions
12 1.1 dholland * are met:
13 1.1 dholland * 1. Redistributions of source code must retain the above copyright
14 1.1 dholland * notice, this list of conditions and the following disclaimer.
15 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 dholland * notice, this list of conditions and the following disclaimer in the
17 1.1 dholland * documentation and/or other materials provided with the distribution.
18 1.1 dholland * 3. Neither the name of the University nor the names of its contributors
19 1.1 dholland * may be used to endorse or promote products derived from this software
20 1.1 dholland * without specific prior written permission.
21 1.1 dholland *
22 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 dholland * SUCH DAMAGE.
33 1.1 dholland */
34 1.1 dholland
35 1.1 dholland #include <sys/types.h>
36 1.1 dholland #include <sys/stat.h>
37 1.1 dholland #include <stdio.h>
38 1.1 dholland #include <stdlib.h>
39 1.1 dholland #include <string.h>
40 1.1 dholland #include <unistd.h>
41 1.1 dholland #include <fcntl.h>
42 1.1 dholland #include <limits.h>
43 1.1 dholland #include <fstab.h>
44 1.1 dholland #include <errno.h>
45 1.1 dholland #include <err.h>
46 1.1 dholland
47 1.1 dholland #include <ufs/ufs/quota1.h>
48 1.1 dholland
49 1.1 dholland #include <quota.h>
50 1.1 dholland #include "quotapvt.h"
51 1.1 dholland
52 1.1 dholland struct oldfiles_quotacursor {
53 1.1 dholland unsigned oqc_doingusers;
54 1.1 dholland unsigned oqc_doinggroups;
55 1.1 dholland
56 1.1 dholland unsigned oqc_numusers;
57 1.1 dholland unsigned oqc_numgroups;
58 1.1 dholland
59 1.1 dholland unsigned oqc_didusers;
60 1.1 dholland unsigned oqc_didgroups;
61 1.1 dholland unsigned oqc_diddefault;
62 1.1 dholland unsigned oqc_pos;
63 1.1 dholland unsigned oqc_didblocks;
64 1.1 dholland };
65 1.1 dholland
66 1.1 dholland static uint64_t
67 1.2 dholland dqblk_getlimit(uint32_t val)
68 1.1 dholland {
69 1.1 dholland if (val == 0) {
70 1.1 dholland return QUOTA_NOLIMIT;
71 1.1 dholland } else {
72 1.1 dholland return val - 1;
73 1.1 dholland }
74 1.1 dholland }
75 1.1 dholland
76 1.2 dholland static uint32_t
77 1.2 dholland dqblk_setlimit(uint64_t val)
78 1.2 dholland {
79 1.2 dholland if (val == QUOTA_NOLIMIT && val >= 0xffffffffUL) {
80 1.2 dholland return 0;
81 1.2 dholland } else {
82 1.2 dholland return (uint32_t)val + 1;
83 1.2 dholland }
84 1.2 dholland }
85 1.2 dholland
86 1.1 dholland static void
87 1.1 dholland dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
88 1.1 dholland {
89 1.2 dholland qv->qv_hardlimit = dqblk_getlimit(dq->dqb_bhardlimit);
90 1.2 dholland qv->qv_softlimit = dqblk_getlimit(dq->dqb_bsoftlimit);
91 1.1 dholland qv->qv_usage = dq->dqb_curblocks;
92 1.1 dholland qv->qv_expiretime = dq->dqb_btime;
93 1.1 dholland qv->qv_grace = QUOTA_NOTIME;
94 1.1 dholland }
95 1.1 dholland
96 1.1 dholland static void
97 1.1 dholland dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
98 1.1 dholland {
99 1.2 dholland qv->qv_hardlimit = dqblk_getlimit(dq->dqb_ihardlimit);
100 1.2 dholland qv->qv_softlimit = dqblk_getlimit(dq->dqb_isoftlimit);
101 1.1 dholland qv->qv_usage = dq->dqb_curinodes;
102 1.1 dholland qv->qv_expiretime = dq->dqb_itime;
103 1.1 dholland qv->qv_grace = QUOTA_NOTIME;
104 1.1 dholland }
105 1.1 dholland
106 1.2 dholland static void
107 1.2 dholland dqblk_putblocks(const struct quotaval *qv, struct dqblk *dq)
108 1.2 dholland {
109 1.2 dholland dq->dqb_bhardlimit = dqblk_setlimit(qv->qv_hardlimit);
110 1.2 dholland dq->dqb_bsoftlimit = dqblk_setlimit(qv->qv_softlimit);
111 1.2 dholland dq->dqb_curblocks = qv->qv_usage;
112 1.2 dholland dq->dqb_btime = qv->qv_expiretime;
113 1.2 dholland /* ignore qv->qv_grace */
114 1.2 dholland }
115 1.2 dholland
116 1.2 dholland static void
117 1.2 dholland dqblk_putfiles(const struct quotaval *qv, struct dqblk *dq)
118 1.2 dholland {
119 1.2 dholland dq->dqb_ihardlimit = dqblk_setlimit(qv->qv_hardlimit);
120 1.2 dholland dq->dqb_isoftlimit = dqblk_setlimit(qv->qv_softlimit);
121 1.2 dholland dq->dqb_curinodes = qv->qv_usage;
122 1.2 dholland dq->dqb_itime = qv->qv_expiretime;
123 1.2 dholland /* ignore qv->qv_grace */
124 1.2 dholland }
125 1.2 dholland
126 1.1 dholland static int
127 1.1 dholland __quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
128 1.1 dholland {
129 1.1 dholland int fd;
130 1.1 dholland
131 1.1 dholland fd = open(path, O_RDWR);
132 1.1 dholland if (fd < 0 && (errno == EACCES || errno == EROFS)) {
133 1.1 dholland fd = open(path, O_RDONLY);
134 1.1 dholland if (fd < 0) {
135 1.1 dholland return -1;
136 1.1 dholland }
137 1.1 dholland }
138 1.1 dholland *fd_ret = fd;
139 1.1 dholland return 0;
140 1.1 dholland }
141 1.1 dholland
142 1.1 dholland int
143 1.1 dholland __quota_oldfiles_initialize(struct quotahandle *qh)
144 1.1 dholland {
145 1.1 dholland static const char *const names[] = INITQFNAMES;
146 1.1 dholland
147 1.1 dholland struct fstab *fs;
148 1.1 dholland char buf[sizeof(fs->fs_mntops)];
149 1.1 dholland char *opt, *state, *s;
150 1.1 dholland char path[PATH_MAX];
151 1.1 dholland const char *userquotafile, *groupquotafile;
152 1.1 dholland int hasuserquota, hasgroupquota;
153 1.1 dholland
154 1.1 dholland if (qh->qh_hasoldfiles) {
155 1.1 dholland /* already initialized */
156 1.1 dholland return 0;
157 1.1 dholland }
158 1.1 dholland
159 1.1 dholland /*
160 1.1 dholland * Find the fstab entry.
161 1.1 dholland *
162 1.1 dholland * XXX: should be able to handle not just ffs quota1 files but
163 1.1 dholland * also lfs and even ext2fs.
164 1.1 dholland */
165 1.1 dholland setfsent();
166 1.1 dholland while ((fs = getfsent()) != NULL) {
167 1.1 dholland if (!strcmp(fs->fs_vfstype, "ffs") &&
168 1.1 dholland !strcmp(fs->fs_file, qh->qh_mountpoint)) {
169 1.1 dholland break;
170 1.1 dholland }
171 1.1 dholland }
172 1.1 dholland endfsent();
173 1.1 dholland
174 1.1 dholland if (fs == NULL) {
175 1.1 dholland warnx("%s not found in fstab", qh->qh_mountpoint);
176 1.1 dholland errno = ENXIO;
177 1.1 dholland return -1;
178 1.1 dholland }
179 1.1 dholland
180 1.1 dholland /*
181 1.1 dholland * Inspect the mount options to find the quota files.
182 1.1 dholland * XXX this info should be gotten from the kernel.
183 1.1 dholland *
184 1.1 dholland * The options are:
185 1.1 dholland * userquota[=path] enable user quotas
186 1.1 dholland * groupquota[=path] enable group quotas
187 1.1 dholland */
188 1.1 dholland hasuserquota = hasgroupquota = 0;
189 1.1 dholland userquotafile = groupquotafile = NULL;
190 1.1 dholland strlcpy(buf, fs->fs_mntops, sizeof(buf));
191 1.1 dholland for (opt = strtok_r(buf, ",", &state);
192 1.1 dholland opt != NULL;
193 1.1 dholland opt = strtok_r(NULL, ",", &state)) {
194 1.1 dholland s = strchr(opt, '=');
195 1.1 dholland if (s != NULL) {
196 1.1 dholland *(s++) = '\0';
197 1.1 dholland }
198 1.1 dholland if (!strcmp(opt, "userquota")) {
199 1.1 dholland hasuserquota = 1;
200 1.1 dholland if (s != NULL) {
201 1.1 dholland userquotafile = s;
202 1.1 dholland }
203 1.1 dholland } else if (!strcmp(opt, "groupquota")) {
204 1.1 dholland hasgroupquota = 1;
205 1.1 dholland if (s != NULL) {
206 1.1 dholland groupquotafile = s;
207 1.1 dholland }
208 1.1 dholland }
209 1.1 dholland }
210 1.1 dholland
211 1.1 dholland if (!hasuserquota && !hasgroupquota) {
212 1.1 dholland errno = ENXIO;
213 1.1 dholland return -1;
214 1.1 dholland }
215 1.1 dholland
216 1.1 dholland if (hasuserquota) {
217 1.1 dholland if (userquotafile == NULL) {
218 1.1 dholland (void)snprintf(path, sizeof(path), "%s/%s.%s",
219 1.1 dholland fs->fs_file,
220 1.1 dholland QUOTAFILENAME, names[USRQUOTA]);
221 1.1 dholland userquotafile = path;
222 1.1 dholland }
223 1.1 dholland if (__quota_oldfiles_open(qh, userquotafile,
224 1.1 dholland &qh->qh_userfile)) {
225 1.1 dholland return -1;
226 1.1 dholland }
227 1.1 dholland }
228 1.1 dholland if (hasgroupquota) {
229 1.1 dholland if (groupquotafile == NULL) {
230 1.1 dholland (void)snprintf(path, sizeof(path), "%s/%s.%s",
231 1.1 dholland fs->fs_file,
232 1.1 dholland QUOTAFILENAME, names[GRPQUOTA]);
233 1.1 dholland groupquotafile = path;
234 1.1 dholland }
235 1.1 dholland if (__quota_oldfiles_open(qh, groupquotafile,
236 1.1 dholland &qh->qh_groupfile)) {
237 1.1 dholland return -1;
238 1.1 dholland }
239 1.1 dholland }
240 1.1 dholland
241 1.1 dholland qh->qh_hasoldfiles = 1;
242 1.1 dholland
243 1.1 dholland return 0;
244 1.1 dholland }
245 1.1 dholland
246 1.1 dholland const char *
247 1.1 dholland __quota_oldfiles_getimplname(struct quotahandle *qh)
248 1.1 dholland {
249 1.1 dholland return "ffs quota1 direct file access";
250 1.1 dholland }
251 1.1 dholland
252 1.1 dholland static int
253 1.1 dholland __quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
254 1.1 dholland struct quotaval *qv, int *isallzero)
255 1.1 dholland {
256 1.1 dholland int file;
257 1.1 dholland off_t pos;
258 1.1 dholland struct dqblk dq;
259 1.1 dholland ssize_t result;
260 1.1 dholland
261 1.1 dholland switch (qk->qk_idtype) {
262 1.1 dholland case QUOTA_IDTYPE_USER:
263 1.1 dholland file = qh->qh_userfile;
264 1.1 dholland break;
265 1.1 dholland case QUOTA_IDTYPE_GROUP:
266 1.1 dholland file = qh->qh_groupfile;
267 1.1 dholland break;
268 1.1 dholland default:
269 1.1 dholland errno = EINVAL;
270 1.1 dholland return -1;
271 1.1 dholland }
272 1.1 dholland
273 1.1 dholland if (qk->qk_id == QUOTA_DEFAULTID) {
274 1.1 dholland pos = 0;
275 1.1 dholland } else {
276 1.1 dholland pos = qk->qk_id * sizeof(struct dqblk);
277 1.1 dholland }
278 1.1 dholland
279 1.1 dholland result = pread(file, &dq, sizeof(dq), pos);
280 1.1 dholland if (result < 0) {
281 1.1 dholland return -1;
282 1.2 dholland } else if (result == 0) {
283 1.2 dholland /* Past EOF; no quota info on file for this ID */
284 1.2 dholland errno = ENOENT;
285 1.2 dholland return -1;
286 1.2 dholland } else if ((size_t)result != sizeof(dq)) {
287 1.1 dholland errno = EFTYPE;
288 1.1 dholland return -1;
289 1.1 dholland }
290 1.1 dholland
291 1.1 dholland switch (qk->qk_objtype) {
292 1.1 dholland case QUOTA_OBJTYPE_BLOCKS:
293 1.1 dholland dqblk_getblocks(&dq, qv);
294 1.1 dholland break;
295 1.1 dholland case QUOTA_OBJTYPE_FILES:
296 1.1 dholland dqblk_getfiles(&dq, qv);
297 1.1 dholland break;
298 1.1 dholland default:
299 1.1 dholland errno = EINVAL;
300 1.1 dholland return -1;
301 1.1 dholland }
302 1.1 dholland
303 1.1 dholland if (qk->qk_id == QUOTA_DEFAULTID) {
304 1.1 dholland qv->qv_usage = 0;
305 1.1 dholland qv->qv_grace = qv->qv_expiretime;
306 1.1 dholland qv->qv_expiretime = QUOTA_NOTIME;
307 1.1 dholland } else if (qk->qk_id == 0) {
308 1.1 dholland qv->qv_hardlimit = 0;
309 1.1 dholland qv->qv_softlimit = 0;
310 1.1 dholland qv->qv_expiretime = QUOTA_NOTIME;
311 1.1 dholland qv->qv_grace = QUOTA_NOTIME;
312 1.1 dholland }
313 1.1 dholland
314 1.1 dholland if (isallzero != NULL) {
315 1.1 dholland if (dq.dqb_bhardlimit == 0 &&
316 1.1 dholland dq.dqb_bsoftlimit == 0 &&
317 1.1 dholland dq.dqb_curblocks == 0 &&
318 1.1 dholland dq.dqb_ihardlimit == 0 &&
319 1.1 dholland dq.dqb_isoftlimit == 0 &&
320 1.1 dholland dq.dqb_curinodes == 0 &&
321 1.1 dholland dq.dqb_btime == 0 &&
322 1.1 dholland dq.dqb_itime == 0) {
323 1.1 dholland *isallzero = 1;
324 1.1 dholland } else {
325 1.1 dholland *isallzero = 0;
326 1.1 dholland }
327 1.1 dholland }
328 1.1 dholland
329 1.1 dholland return 0;
330 1.1 dholland }
331 1.1 dholland
332 1.2 dholland static int
333 1.2 dholland __quota_oldfiles_doput(struct quotahandle *qh, const struct quotakey *qk,
334 1.2 dholland const struct quotaval *qv)
335 1.2 dholland {
336 1.2 dholland int file;
337 1.2 dholland off_t pos;
338 1.2 dholland struct quotaval qv2;
339 1.2 dholland struct dqblk dq;
340 1.2 dholland ssize_t result;
341 1.2 dholland
342 1.2 dholland switch (qk->qk_idtype) {
343 1.2 dholland case QUOTA_IDTYPE_USER:
344 1.2 dholland file = qh->qh_userfile;
345 1.2 dholland break;
346 1.2 dholland case QUOTA_IDTYPE_GROUP:
347 1.2 dholland file = qh->qh_groupfile;
348 1.2 dholland break;
349 1.2 dholland default:
350 1.2 dholland errno = EINVAL;
351 1.2 dholland return -1;
352 1.2 dholland }
353 1.2 dholland
354 1.2 dholland if (qk->qk_id == QUOTA_DEFAULTID) {
355 1.2 dholland pos = 0;
356 1.2 dholland } else {
357 1.2 dholland pos = qk->qk_id * sizeof(struct dqblk);
358 1.2 dholland }
359 1.2 dholland
360 1.2 dholland result = pread(file, &dq, sizeof(dq), pos);
361 1.2 dholland if (result < 0) {
362 1.2 dholland return -1;
363 1.2 dholland } else if (result == 0) {
364 1.2 dholland /* Past EOF; fill in a blank dq to start from */
365 1.2 dholland dq.dqb_bhardlimit = 0;
366 1.2 dholland dq.dqb_bsoftlimit = 0;
367 1.2 dholland dq.dqb_curblocks = 0;
368 1.2 dholland dq.dqb_ihardlimit = 0;
369 1.2 dholland dq.dqb_isoftlimit = 0;
370 1.2 dholland dq.dqb_curinodes = 0;
371 1.2 dholland dq.dqb_btime = 0;
372 1.2 dholland dq.dqb_itime = 0;
373 1.2 dholland } else if ((size_t)result != sizeof(dq)) {
374 1.2 dholland errno = EFTYPE;
375 1.2 dholland return -1;
376 1.2 dholland }
377 1.2 dholland
378 1.2 dholland switch (qk->qk_objtype) {
379 1.2 dholland case QUOTA_OBJTYPE_BLOCKS:
380 1.2 dholland dqblk_getblocks(&dq, &qv2);
381 1.2 dholland break;
382 1.2 dholland case QUOTA_OBJTYPE_FILES:
383 1.2 dholland dqblk_getfiles(&dq, &qv2);
384 1.2 dholland break;
385 1.2 dholland default:
386 1.2 dholland errno = EINVAL;
387 1.2 dholland return -1;
388 1.2 dholland }
389 1.2 dholland
390 1.2 dholland if (qk->qk_id == QUOTA_DEFAULTID) {
391 1.2 dholland qv2.qv_hardlimit = qv->qv_hardlimit;
392 1.2 dholland qv2.qv_softlimit = qv->qv_softlimit;
393 1.2 dholland /* leave qv2.qv_usage unchanged */
394 1.2 dholland qv2.qv_expiretime = qv->qv_grace;
395 1.2 dholland /* skip qv2.qv_grace */
396 1.2 dholland
397 1.2 dholland /* ignore qv->qv_usage */
398 1.2 dholland /* ignore qv->qv_expiretime */
399 1.2 dholland } else if (qk->qk_id == 0) {
400 1.2 dholland /* leave qv2.qv_hardlimit unchanged */
401 1.2 dholland /* leave qv2.qv_softlimit unchanged */
402 1.2 dholland qv2.qv_usage = qv->qv_usage;
403 1.2 dholland /* leave qv2.qv_expiretime unchanged */
404 1.2 dholland /* skip qv2.qv_grace */
405 1.2 dholland
406 1.2 dholland /* ignore qv->qv_hardlimit */
407 1.2 dholland /* ignore qv->qv_softlimit */
408 1.2 dholland /* ignore qv->qv_expiretime */
409 1.2 dholland /* ignore qv->qv_grace */
410 1.2 dholland } else {
411 1.2 dholland qv2 = *qv;
412 1.2 dholland }
413 1.2 dholland
414 1.2 dholland switch (qk->qk_objtype) {
415 1.2 dholland case QUOTA_OBJTYPE_BLOCKS:
416 1.2 dholland dqblk_putblocks(&qv2, &dq);
417 1.2 dholland break;
418 1.2 dholland case QUOTA_OBJTYPE_FILES:
419 1.2 dholland dqblk_putfiles(&qv2, &dq);
420 1.2 dholland break;
421 1.2 dholland default:
422 1.2 dholland errno = EINVAL;
423 1.2 dholland return -1;
424 1.2 dholland }
425 1.2 dholland
426 1.2 dholland result = pwrite(file, &dq, sizeof(dq), pos);
427 1.2 dholland if (result < 0) {
428 1.2 dholland return -1;
429 1.2 dholland } else if ((size_t)result != sizeof(dq)) {
430 1.2 dholland /* ? */
431 1.2 dholland errno = EFTYPE;
432 1.2 dholland return -1;
433 1.2 dholland }
434 1.2 dholland
435 1.2 dholland return 0;
436 1.2 dholland }
437 1.2 dholland
438 1.1 dholland int
439 1.1 dholland __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
440 1.1 dholland struct quotaval *qv)
441 1.1 dholland {
442 1.1 dholland return __quota_oldfiles_doget(qh, qk, qv, NULL);
443 1.1 dholland }
444 1.1 dholland
445 1.2 dholland int
446 1.2 dholland __quota_oldfiles_put(struct quotahandle *qh, const struct quotakey *qk,
447 1.2 dholland const struct quotaval *qv)
448 1.2 dholland {
449 1.2 dholland return __quota_oldfiles_doput(qh, qk, qv);
450 1.2 dholland }
451 1.2 dholland
452 1.2 dholland int
453 1.2 dholland __quota_oldfiles_delete(struct quotahandle *qh, const struct quotakey *qk)
454 1.2 dholland {
455 1.2 dholland struct quotaval qv;
456 1.2 dholland
457 1.2 dholland quotaval_clear(&qv);
458 1.2 dholland return __quota_oldfiles_doput(qh, qk, &qv);
459 1.2 dholland }
460 1.2 dholland
461 1.1 dholland struct oldfiles_quotacursor *
462 1.1 dholland __quota_oldfiles_cursor_create(struct quotahandle *qh)
463 1.1 dholland {
464 1.1 dholland struct oldfiles_quotacursor *oqc;
465 1.1 dholland struct stat st;
466 1.1 dholland int serrno;
467 1.1 dholland
468 1.1 dholland oqc = malloc(sizeof(*oqc));
469 1.1 dholland if (oqc == NULL) {
470 1.1 dholland return NULL;
471 1.1 dholland }
472 1.1 dholland
473 1.1 dholland oqc->oqc_didusers = 0;
474 1.1 dholland oqc->oqc_didgroups = 0;
475 1.1 dholland oqc->oqc_diddefault = 0;
476 1.1 dholland oqc->oqc_pos = 0;
477 1.1 dholland oqc->oqc_didblocks = 0;
478 1.1 dholland
479 1.1 dholland if (qh->qh_userfile >= 0) {
480 1.1 dholland oqc->oqc_doingusers = 1;
481 1.1 dholland } else {
482 1.1 dholland oqc->oqc_doingusers = 0;
483 1.1 dholland oqc->oqc_didusers = 1;
484 1.1 dholland }
485 1.1 dholland
486 1.1 dholland if (qh->qh_groupfile >= 0) {
487 1.1 dholland oqc->oqc_doinggroups = 1;
488 1.1 dholland } else {
489 1.1 dholland oqc->oqc_doinggroups = 0;
490 1.1 dholland oqc->oqc_didgroups = 1;
491 1.1 dholland }
492 1.1 dholland
493 1.1 dholland if (fstat(qh->qh_userfile, &st) < 0) {
494 1.1 dholland serrno = errno;
495 1.1 dholland free(oqc);
496 1.1 dholland errno = serrno;
497 1.1 dholland return NULL;
498 1.1 dholland }
499 1.1 dholland oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
500 1.1 dholland
501 1.1 dholland if (fstat(qh->qh_groupfile, &st) < 0) {
502 1.1 dholland serrno = errno;
503 1.1 dholland free(oqc);
504 1.1 dholland errno = serrno;
505 1.1 dholland return NULL;
506 1.1 dholland }
507 1.1 dholland oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
508 1.1 dholland
509 1.1 dholland return oqc;
510 1.1 dholland }
511 1.1 dholland
512 1.1 dholland void
513 1.1 dholland __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
514 1.1 dholland {
515 1.1 dholland free(oqc);
516 1.1 dholland }
517 1.1 dholland
518 1.1 dholland int
519 1.1 dholland __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
520 1.1 dholland unsigned idtype)
521 1.1 dholland {
522 1.1 dholland switch (idtype) {
523 1.1 dholland case QUOTA_IDTYPE_USER:
524 1.1 dholland oqc->oqc_doingusers = 0;
525 1.1 dholland oqc->oqc_didusers = 1;
526 1.1 dholland break;
527 1.1 dholland case QUOTA_IDTYPE_GROUP:
528 1.1 dholland oqc->oqc_doinggroups = 0;
529 1.1 dholland oqc->oqc_didgroups = 1;
530 1.1 dholland break;
531 1.1 dholland default:
532 1.1 dholland errno = EINVAL;
533 1.1 dholland return -1;
534 1.1 dholland }
535 1.1 dholland return 0;
536 1.1 dholland }
537 1.1 dholland
538 1.1 dholland int
539 1.1 dholland __quota_oldfiles_cursor_get(struct quotahandle *qh,
540 1.1 dholland struct oldfiles_quotacursor *oqc,
541 1.1 dholland struct quotakey *key, struct quotaval *val)
542 1.1 dholland {
543 1.1 dholland unsigned maxpos;
544 1.1 dholland int isallzero;
545 1.1 dholland
546 1.1 dholland /* in case one of the sizes is zero */
547 1.1 dholland if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
548 1.1 dholland oqc->oqc_didusers = 1;
549 1.1 dholland }
550 1.1 dholland if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
551 1.1 dholland oqc->oqc_didgroups = 1;
552 1.1 dholland }
553 1.1 dholland
554 1.1 dholland again:
555 1.1 dholland /*
556 1.1 dholland * Figure out what to get
557 1.1 dholland */
558 1.1 dholland
559 1.1 dholland if (!oqc->oqc_didusers) {
560 1.1 dholland key->qk_idtype = QUOTA_IDTYPE_USER;
561 1.1 dholland maxpos = oqc->oqc_numusers;
562 1.1 dholland } else if (!oqc->oqc_didgroups) {
563 1.1 dholland key->qk_idtype = QUOTA_IDTYPE_GROUP;
564 1.1 dholland maxpos = oqc->oqc_numgroups;
565 1.1 dholland } else {
566 1.1 dholland errno = ENOENT;
567 1.1 dholland return -1;
568 1.1 dholland }
569 1.1 dholland
570 1.1 dholland if (!oqc->oqc_diddefault) {
571 1.1 dholland key->qk_id = QUOTA_DEFAULTID;
572 1.1 dholland } else {
573 1.1 dholland key->qk_id = oqc->oqc_pos;
574 1.1 dholland }
575 1.1 dholland
576 1.1 dholland if (!oqc->oqc_didblocks) {
577 1.1 dholland key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
578 1.1 dholland } else {
579 1.1 dholland key->qk_objtype = QUOTA_OBJTYPE_FILES;
580 1.1 dholland }
581 1.1 dholland
582 1.1 dholland /*
583 1.1 dholland * Get it
584 1.1 dholland */
585 1.1 dholland
586 1.1 dholland if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
587 1.1 dholland return -1;
588 1.1 dholland }
589 1.1 dholland
590 1.1 dholland /*
591 1.1 dholland * Advance the cursor
592 1.1 dholland */
593 1.1 dholland if (!oqc->oqc_didblocks) {
594 1.1 dholland oqc->oqc_didblocks = 1;
595 1.1 dholland } else {
596 1.1 dholland oqc->oqc_didblocks = 0;
597 1.1 dholland if (!oqc->oqc_diddefault) {
598 1.1 dholland oqc->oqc_diddefault = 1;
599 1.1 dholland } else {
600 1.1 dholland oqc->oqc_pos++;
601 1.1 dholland if (oqc->oqc_pos >= maxpos) {
602 1.1 dholland oqc->oqc_pos = 0;
603 1.1 dholland oqc->oqc_diddefault = 0;
604 1.1 dholland if (!oqc->oqc_didusers) {
605 1.1 dholland oqc->oqc_didusers = 1;
606 1.1 dholland } else {
607 1.1 dholland oqc->oqc_didgroups = 1;
608 1.1 dholland }
609 1.1 dholland }
610 1.1 dholland }
611 1.1 dholland }
612 1.1 dholland
613 1.1 dholland /*
614 1.1 dholland * If we got an all-zero dqblk (e.g. from the middle of a hole
615 1.1 dholland * in the quota file) don't bother returning it to the caller.
616 1.1 dholland *
617 1.1 dholland * ...unless we're at the end of the data, to avoid going past
618 1.1 dholland * the end and generating a spurious failure. There's no
619 1.1 dholland * reasonable way to make _atend detect empty entries at the
620 1.1 dholland * end of the quota files.
621 1.1 dholland */
622 1.1 dholland if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
623 1.1 dholland goto again;
624 1.1 dholland }
625 1.1 dholland return 0;
626 1.1 dholland }
627 1.1 dholland
628 1.1 dholland int
629 1.1 dholland __quota_oldfiles_cursor_getn(struct quotahandle *qh,
630 1.1 dholland struct oldfiles_quotacursor *oqc,
631 1.1 dholland struct quotakey *keys, struct quotaval *vals,
632 1.1 dholland unsigned maxnum)
633 1.1 dholland {
634 1.1 dholland unsigned i;
635 1.1 dholland
636 1.1 dholland if (maxnum > INT_MAX) {
637 1.1 dholland /* joker, eh? */
638 1.1 dholland errno = EINVAL;
639 1.1 dholland return -1;
640 1.1 dholland }
641 1.1 dholland
642 1.1 dholland for (i=0; i<maxnum; i++) {
643 1.1 dholland if (__quota_oldfiles_cursor_atend(oqc)) {
644 1.1 dholland break;
645 1.1 dholland }
646 1.1 dholland if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
647 1.1 dholland if (i > 0) {
648 1.1 dholland /*
649 1.1 dholland * Succeed witih what we have so far;
650 1.1 dholland * the next attempt will hit the same
651 1.1 dholland * error again.
652 1.1 dholland */
653 1.1 dholland break;
654 1.1 dholland }
655 1.1 dholland return -1;
656 1.1 dholland }
657 1.1 dholland }
658 1.1 dholland return i;
659 1.1 dholland
660 1.1 dholland }
661 1.1 dholland
662 1.1 dholland int
663 1.1 dholland __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
664 1.1 dholland {
665 1.1 dholland /* in case one of the sizes is zero */
666 1.1 dholland if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
667 1.1 dholland oqc->oqc_didusers = 1;
668 1.1 dholland }
669 1.1 dholland if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
670 1.1 dholland oqc->oqc_didgroups = 1;
671 1.1 dholland }
672 1.1 dholland
673 1.1 dholland return oqc->oqc_didusers && oqc->oqc_didgroups;
674 1.1 dholland }
675 1.1 dholland
676 1.1 dholland int
677 1.1 dholland __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
678 1.1 dholland {
679 1.1 dholland oqc->oqc_didusers = 0;
680 1.1 dholland oqc->oqc_didgroups = 0;
681 1.1 dholland oqc->oqc_diddefault = 0;
682 1.1 dholland oqc->oqc_pos = 0;
683 1.1 dholland oqc->oqc_didblocks = 0;
684 1.1 dholland return 0;
685 1.1 dholland }
686