Cross Reference: /dovecot/src/plugins/quota/quota-maildir.c
quota-maildir.c revision 8da095519878426b012058e6f331a669f327f47f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2006-2007 Dovecot authors, see the included COPYING file */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "lib.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "array.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "ioloop.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "nfs-workarounds.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "file-dotlock.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "read-full.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "write-full.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "str.h"
677e22747b82bf15b339e31d1d0106d62bf806daTimo Sirainen#include "maildir-storage.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include "quota-private.h"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include <stdio.h>
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include <stdlib.h>
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include <dirent.h>
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#include <sys/stat.h>
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#define MAILDIRSIZE_FILENAME "maildirsize"
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen#define MAILDIRSIZE_STALE_SECS (60*15)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstruct maildir_quota_root {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct quota_root root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *maildirsize_path;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen uint64_t message_bytes_limit;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen uint64_t message_count_limit;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen uint64_t total_bytes;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen uint64_t total_count;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int fd;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen time_t recalc_last_stamp;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen unsigned int limits_initialized:1;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen unsigned int master_message_limits:1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen};
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstruct maildir_list_context {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_storage *storage;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_list_iterate_context *iter;
61e84692827b6a64912343f515c984853021483aTimo Sirainen const struct mailbox_info *info;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen string_t *path;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int state;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen};
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_maildir;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainenstruct dotlock_settings dotlock_settings = {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen MEMBER(temp_prefix) NULL,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen MEMBER(lock_suffix) NULL,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen MEMBER(timeout) 0,
8da095519878426b012058e6f331a669f327f47fTimo Sirainen MEMBER(stale_timeout) 30
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen};
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildir_sum_dir(const char *dir, uint64_t *total_bytes,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t *total_count)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen DIR *dirp;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct dirent *dp;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen string_t *path;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen const char *p;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen size_t len;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen uoff_t num;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen dirp = opendir(dir);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (dirp == NULL) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno == ENOENT || errno == ESTALE)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("opendir(%s) failed: %m", dir);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen path = t_str_new(256);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append(path, dir);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append_c(path, '/');
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen len = str_len(path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen while ((dp = readdir(dirp)) != NULL) {
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen if (dp->d_name[0] == '.' &&
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen (dp->d_name[1] == '\0' || dp->d_name[1] == '.'))
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen continue;
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen p = strstr(dp->d_name, ",S=");
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen num = (uoff_t)-1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (p != NULL) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* ,S=nnnn[:,] */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen p += 3;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen for (num = 0; *p >= '0' && *p <= '9'; p++)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen num = num * 10 + (*p - '0');
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (*p != ':' && *p != '\0' && *p != ',') {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* not in expected format, fallback to stat() */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen num = (uoff_t)-1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen } else {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *total_bytes += num;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *total_count += 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (num == (uoff_t)-1) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct stat st;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_truncate(path, len);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append(path, dp->d_name);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (stat(str_c(path), &st) == 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *total_bytes += st.st_size;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *total_count += 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen } else if (errno != ENOENT && errno != ESTALE) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("stat(%s) failed: %m", str_c(path));
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (closedir(dirp) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("closedir(%s) failed: %m", dir);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic struct maildir_list_context *
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildir_list_init(struct mail_storage *storage)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_list_context *ctx;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx = i_new(struct maildir_list_context, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->storage = storage;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx->path = str_new(default_pool, 512);
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen ctx->iter = mailbox_list_iter_init(mail_storage_get_list(storage), "*",
18ffea71d9beeec3cc1d400f751926ee72807f62Timo Sirainen MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ctx;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic const char *
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildir_list_next(struct maildir_list_context *ctx, time_t *mtime_r)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct stat st;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen const char *path;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen bool is_file;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen for (;;) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (ctx->state == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->info = mailbox_list_iter_next(ctx->iter);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ctx->info == NULL)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return NULL;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_push();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path = mail_storage_get_mailbox_path(ctx->storage,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->info->name,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &is_file);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_truncate(ctx->path, 0);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append(ctx->path, path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append(ctx->path, ctx->state == 0 ? "/new" : "/cur");
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (++ctx->state == 2)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx->state = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (stat(str_c(ctx->path), &st) == 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen break;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* ignore if the directory got lost, stale or if it was
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen actually a file and not a directory */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno != ENOENT && errno != ESTALE && errno != ENOTDIR) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("stat(%s) failed: %m", str_c(ctx->path));
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx->state = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *mtime_r = st.st_size;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return str_c(ctx->path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int maildir_list_deinit(struct maildir_list_context *ctx)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int ret = mailbox_list_iter_deinit(&ctx->iter);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_free(&ctx->path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen i_free(ctx);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildirs_check_have_changed(struct mail_storage *storage, time_t latest_mtime)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_list_context *ctx;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen time_t mtime;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx = maildir_list_init(storage);
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen while (maildir_list_next(ctx, &mtime) != NULL) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (mtime > latest_mtime) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen break;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (maildir_list_deinit(ctx) < 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_write(struct maildir_quota_root *root, const char *path)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct dotlock *dotlock;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen string_t *str;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int fd;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen i_assert(root->fd == -1);
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen dotlock_settings.use_excl_lock = getenv("DOTLOCK_USE_EXCL") != NULL;
8da095519878426b012058e6f331a669f327f47fTimo Sirainen dotlock_settings.nfs_flush = getenv("MAIL_NFS_STORAGE") != NULL;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen fd = file_dotlock_open(&dotlock_settings, path,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (fd == -1) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno == EAGAIN) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* someone's just in the middle of updating it */
25b0229f40dc59d0b3f31e01b7afc57304bead5cTimo Sirainen return 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("file_dotlock_open(%s) failed: %m", path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str = t_str_new(128);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (root->message_bytes_limit != (uint64_t)-1) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen str_printfa(str, "%lluS",
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (unsigned long long)root->message_bytes_limit);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (root->message_count_limit != (uint64_t)-1) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (str_len(str) > 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_append_c(str, ',');
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen str_printfa(str, "%lluC",
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (unsigned long long)root->message_count_limit);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen str_printfa(str, "\n%llu %llu\n",
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (unsigned long long)root->total_bytes,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (unsigned long long)root->total_count);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("write_full(%s) failed: %m", path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen file_dotlock_delete(&dotlock);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen /* keep the fd open since we might want to update it later */
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen if (file_dotlock_replace(&dotlock,
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("file_dotlock_replace(%s) failed: %m", path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen root->fd = fd;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void maildirsize_recalculate_init(struct maildir_quota_root *root)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->total_bytes = root->total_count = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->recalc_last_stamp = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_recalculate_storage(struct maildir_quota_root *root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *storage)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_list_context *ctx;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *dir;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen time_t mtime;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ctx = maildir_list_init(storage);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen while ((dir = maildir_list_next(ctx, &mtime)) != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (mtime > root->recalc_last_stamp)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->recalc_last_stamp = mtime;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_push();
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (maildir_sum_dir(dir, &root->total_bytes,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &root->total_count) < 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (maildir_list_deinit(ctx) < 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic void maildirsize_rebuild_later(struct maildir_quota_root *root)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (!root->master_message_limits) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* FIXME: can't unlink(), because the limits would be lost. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (unlink(root->maildirsize_path) < 0 &&
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen errno != ENOENT && errno != ESTALE)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_error("unlink(%s) failed: %m", root->maildirsize_path);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_recalculate_finish(struct maildir_quota_root *root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (ret == 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* maildir didn't change, we can write the maildirsize file */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = maildirsize_write(root, root->maildirsize_path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (ret != 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen maildirsize_rebuild_later(root);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_recalculate(struct maildir_quota_root *root)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *const *storages;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen maildirsize_recalculate_init(root);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* count mails from all storages */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen storages = array_get(&root->root.quota->storages, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (maildirsize_recalculate_storage(root, storages[i]) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* check if any of the directories have changed */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = maildirs_check_have_changed(storages[i],
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->recalc_last_stamp);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret != 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return maildirsize_recalculate_finish(root, ret);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenstatic bool
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenmaildir_parse_limit(const char *str, uint64_t *bytes_r, uint64_t *count_r)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen const char *const *limit;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen unsigned long long value;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen char *pos;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen bool ret = TRUE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen *bytes_r = (uint64_t)-1;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen *count_r = (uint64_t)-1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* 0 values mean unlimited */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen for (limit = t_strsplit(str, ","); *limit != NULL; limit++) {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen value = strtoull(*limit, &pos, 10);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (pos[0] != '\0' && pos[1] == '\0') {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen switch (pos[0]) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen case 'C':
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (value != 0)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen *count_r = value;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen break;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen case 'S':
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (value != 0)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen *bytes_r = value;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen break;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen default:
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen ret = FALSE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen break;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen } else {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen ret = FALSE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen return ret;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen}
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenstatic int maildirsize_parse(struct maildir_quota_root *root,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen int fd, const char *const *lines)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen{
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint64_t message_bytes_limit, message_count_limit;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen long long bytes_diff, total_bytes;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen int count_diff, total_count;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen unsigned int line_count = 0;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (*lines == NULL)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen return -1;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* first line contains the limits */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen (void)maildir_parse_limit(lines[0], &message_bytes_limit,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen &message_count_limit);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen if (!root->master_message_limits) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen /* we don't know the limits, use whatever the file says */
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen root->message_bytes_limit = message_bytes_limit;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen root->message_count_limit = message_count_limit;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen } else if (root->message_bytes_limit != message_bytes_limit ||
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen root->message_count_limit != message_count_limit) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen /* we know the limits and they've changed.
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen the file must be rewritten. */
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen return 0;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen }
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen if (*lines == NULL) {
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen /* no quota lines. rebuild it. */
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen return 0;
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen }
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* rest of the lines contains <bytes> <count> diffs */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen total_bytes = 0; total_count = 0;
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen for (lines++; *lines != NULL; lines++, line_count++) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (sscanf(*lines, "%lld %d", &bytes_diff, &count_diff) != 2)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen total_bytes += bytes_diff;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen total_count += count_diff;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* we end always with LF, which shows up as empty last line. there
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen should be no other empty lines */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (lines[1] != NULL)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (total_bytes < 0 || total_count < 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* corrupted */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if ((uint64_t)total_bytes > root->message_bytes_limit ||
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (uint64_t)total_count > root->message_count_limit) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* we're over quota. don't trust these values if the file
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen contains more than the initial summary line, or if the file
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen is older than 15 minutes. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct stat st;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (line_count > 1)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (fstat(fd, &st) < 0 ||
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen st.st_mtime < ioloop_time - MAILDIRSIZE_STALE_SECS)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->total_bytes = (uint64_t)total_bytes;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->total_count = (uint64_t)total_count;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_read(struct maildir_quota_root *root)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen char buf[5120+1];
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen unsigned int i, size;
5f24517ae602ca828bc7e197913f51d55d79c9bcTimo Sirainen int fd, ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_push();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (root->fd != -1) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (close(root->fd) < 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("close(%s) failed: %m", root->maildirsize_path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->fd = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fd = nfs_safe_open(root->maildirsize_path, O_RDWR | O_APPEND);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (fd == -1) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno == ENOENT)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen else {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("open(%s) failed: %m", root->maildirsize_path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
4c5272b168b4d71a95a08d48cc5b29cd7b27f193Timo Sirainen /* @UNSAFE */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen size = 0;
4c5272b168b4d71a95a08d48cc5b29cd7b27f193Timo Sirainen while (size < sizeof(buf)-1 &&
4c5272b168b4d71a95a08d48cc5b29cd7b27f193Timo Sirainen (ret = read(fd, buf + size, sizeof(buf)-1 - size)) != 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (ret < 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno == ESTALE)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("read(%s) failed: %m", root->maildirsize_path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen size += ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
4c5272b168b4d71a95a08d48cc5b29cd7b27f193Timo Sirainen if (ret < 0 || size >= sizeof(buf)-1) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* error / recalculation needed. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen (void)close(fd);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret < 0 ? -1 : 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* file is smaller than 5120 bytes, which means we can use it */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->total_bytes = root->total_count = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen /* skip the last line if there's no LF at the end. Remove the last LF
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen so we don't get one empty line in the strsplit. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen while (size > 0 && buf[size-1] != '\n') size--;
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen if (size > 0) size--;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen buf[size] = '\0';
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen /* If there are any NUL bytes, the file is broken. */
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen for (i = 0; i < size; i++) {
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen if (buf[i] == '\0')
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen break;
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen }
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen if (i == size &&
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen maildirsize_parse(root, fd, t_strsplit(buf, "\n")) > 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->fd = fd;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen } else {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* broken file / need recalculation */
aa9c91ee2fcf0ee65d82d0cdc4a58ab1a7002c26Timo Sirainen (void)close(fd);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->fd = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainenstatic void maildirquota_init_limits(struct maildir_quota_root *root)
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen{
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen root->limits_initialized = TRUE;
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen if (root->root.default_rule.bytes_limit != 0 ||
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen root->root.default_rule.count_limit != 0) {
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen root->master_message_limits = TRUE;
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen root->message_bytes_limit = root->root.default_rule.bytes_limit;
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen root->message_count_limit = root->root.default_rule.count_limit;
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen }
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen}
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirquota_refresh(struct maildir_quota_root *root)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen if (!root->limits_initialized) {
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen maildirquota_init_limits(root);
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen if (root->maildirsize_path == NULL) {
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen i_warning("quota maildir: No maildir storages, "
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen "ignoring quota.");
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen return 0;
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen }
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen } else {
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen if (root->maildirsize_path == NULL)
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen return 0;
9d254c7c7b715d7fe1206e9b228e9c5b23b99f28Timo Sirainen }
c73bb576f140e1c1aae57fd607d02b418afe2c3fTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = maildirsize_read(root);
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen if (ret == 0) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen if (root->message_bytes_limit == (uint64_t)-1 &&
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen root->message_count_limit == (uint64_t)-1) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen /* no quota */
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen return 0;
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen }
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = maildirsize_recalculate(root);
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret < 0 ? -1 : 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int maildirsize_update(struct maildir_quota_root *root,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int count_diff, int64_t bytes_diff)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen const char *str;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen int ret = 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
0461b5dfd1ac6b5ae49a2f1ab6ffdc2e5e2ee7c2Timo Sirainen if (count_diff == 0 && bytes_diff == 0)
0461b5dfd1ac6b5ae49a2f1ab6ffdc2e5e2ee7c2Timo Sirainen return 0;
0461b5dfd1ac6b5ae49a2f1ab6ffdc2e5e2ee7c2Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_push();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* We rely on O_APPEND working in here. That isn't NFS-safe, but it
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen isn't necessarily that bad because the file is recreated once in
a8fcd55e88550ebb905249825bdb1eec7b9667ffTimo Sirainen a while, and sooner if corruption causes calculations to go
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen over quota. This is also how Maildir++ spec specifies it should be
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen done.. */
0461b5dfd1ac6b5ae49a2f1ab6ffdc2e5e2ee7c2Timo Sirainen str = t_strdup_printf("%lld %d\n", (long long)bytes_diff, count_diff);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (write_full(root->fd, str, strlen(str)) < 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen ret = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno == ESTALE) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* deleted/replaced already, ignore */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("write_full(%s) failed: %m",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->maildirsize_path);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_pop();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return ret;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_root *maildir_quota_alloc(void)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root = i_new(struct maildir_quota_root, 1);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->fd = -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->message_bytes_limit = (uint64_t)-1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen root->message_count_limit = (uint64_t)-1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return &root->root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic void maildir_quota_deinit(struct quota_root *_root)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
6ce34c7a2462412af024a0320911a3fe1c04b264Timo Sirainen if (root->fd != -1)
6ce34c7a2462412af024a0320911a3fe1c04b264Timo Sirainen (void)close(root->fd);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen i_free(root);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenstatic bool
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenmaildir_quota_parse_rule(struct quota_root *root ATTR_UNUSED,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen struct quota_rule *rule,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen const char *str, const char **error_r)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen{
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint64_t bytes, count;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (!maildir_parse_limit(str, &bytes, &count)) {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen *error_r = "Invalid Maildir++ quota rule";
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen return FALSE;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen }
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen rule->bytes_limit = bytes;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen rule->count_limit = count;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen return TRUE;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen}
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmaildir_quota_root_storage_added(struct quota_root *_root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *storage)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *control_dir;
677e22747b82bf15b339e31d1d0106d62bf806daTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (root->maildirsize_path != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen control_dir = mail_storage_get_mailbox_control_dir(storage, "");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->maildirsize_path =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p_strconcat(_root->pool, control_dir,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "/"MAILDIRSIZE_FILENAME, NULL);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic void
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmaildir_quota_storage_added(struct quota *quota,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *_storage)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct maildir_storage *storage =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (struct maildir_storage *)_storage;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root **roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(_storage->name, "maildir") != 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get_modifiable(&quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (roots[i]->backend.name == quota_backend_maildir.name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen maildir_quota_root_storage_added(roots[i], _storage);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* For newly generated filenames add ,S=size. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen storage->save_size_in_filename = TRUE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic const char *const *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenmaildir_quota_root_get_resources(struct quota_root *root ATTR_UNUSED)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen static const char *resources_both[] = {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen QUOTA_NAME_MESSAGES,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen NULL
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen };
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return resources_both;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildir_quota_get_resource(struct quota_root *_root, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen uint64_t *value_r, uint64_t *limit ATTR_UNUSED)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (maildirquota_refresh(root) < 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen return -1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen *value_r = root->total_bytes;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen *value_r = root->total_count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen return 0;
8b10d65deb01f351172408ab9540413d60d5fe3bTimo Sirainen return 1;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmaildir_quota_update(struct quota_root *_root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_transaction_context *ctx)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (struct maildir_quota_root *) _root;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (root->fd == -1 || ctx->recalculate ||
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen maildirsize_update(root, ctx->count_used, ctx->bytes_used) < 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen maildirsize_rebuild_later(root);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstruct quota_backend quota_backend_maildir = {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen "maildir",
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen maildir_quota_alloc,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen NULL,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen maildir_quota_deinit,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen maildir_quota_parse_rule,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen maildir_quota_storage_added,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen maildir_quota_root_get_resources,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen maildir_quota_get_resource,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen maildir_quota_update
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen};