Cross Reference: /dovecot/src/lib-fs/fs-api.c
fs-api.c revision db6fe1b4c478231f9b63cca9069e2ab8fc70da2e
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
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen#include "array.h"
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen#include "module-dir.h"
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen#include "llist.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen#include "hash-method.h"
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen#include "istream.h"
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen#include "istream-seekable.h"
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen#include "ostream.h"
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen#include "timing.h"
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen#include "time-util.h"
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen#include "istream-fs-stats.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "fs-api-private.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainenstruct fs_api_module_register fs_api_module_register = { 0 };
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic struct module *fs_modules = NULL;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic ARRAY(const struct fs *) fs_classes;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenstatic void fs_classes_init(void);
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_alloc(const struct fs *fs_class, const char *args,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const struct fs_settings *set, struct fs **fs_r, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs *fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs = fs_class->v.alloc();
70f202ae74b6981ced5776a69b1070274313c6c8Timo Sirainen fs->refcount = 1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->last_error = str_new(default_pool, 64);
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen i_array_init(&fs->module_contexts, 5);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen ret = fs_class->v.init(fs, args, set);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen } T_END;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (ret < 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen /* a bit kludgy way to allow data stack frame usage in normal
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen conditions but still be able to return error message from
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen data stack. */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *error_r = t_strdup_printf("%s: %s", fs_class->name,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_last_error(fs));
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs_unref(&fs);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen fs->username = i_strdup(set->username);
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen fs->session_id = i_strdup(set->session_id);
463072825056eabcbed7aaa943c98655ce173ce5Timo Sirainen *fs_r = fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenvoid fs_class_register(const struct fs *fs_class)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainen if (!array_is_created(&fs_classes))
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainen fs_classes_init();
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen array_append(&fs_classes, &fs_class, 1);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainenstatic void fs_classes_deinit(void)
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen{
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen array_free(&fs_classes);
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen}
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_classes_init(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen i_array_init(&fs_classes, 8);
6c0d8dc7cad70a336b01bd1978b3eee84a63b3b7Timo Sirainen fs_class_register(&fs_class_dict);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_posix);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_class_register(&fs_class_randomfail);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_class_register(&fs_class_metawrap);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_sis);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_sis_queue);
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen lib_atexit(fs_classes_deinit);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic const struct fs *fs_class_find(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *const *classp;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (!array_is_created(&fs_classes))
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_classes_init();
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen array_foreach(&fs_classes, classp) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (strcmp((*classp)->name, driver) == 0)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return *classp;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen }
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return NULL;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_deinit_modules(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_dir_unload(&fs_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainenstatic const char *fs_driver_module_name(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen{
e0593474ae2d8b1d4ec8c70c4fd84ea2bfede75aTimo Sirainen return t_str_replace(driver, '-', '_');
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen}
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen const char *module_name =
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen t_strdup_printf("fs_%s", fs_driver_module_name(driver));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module *module;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module_dir_load_settings mod_set;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *fs_class;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen memset(&mod_set, 0, sizeof(mod_set));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen mod_set.abi_version = DOVECOT_ABI_VERSION;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen mod_set.ignore_missing = TRUE;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_name, &mod_set);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_dir_init(fs_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module = module_dir_find(fs_modules, module_name);
898e99166f46b4f37ae45fe5594ed952b5befe6dTimo Sirainen fs_class = module == NULL ? NULL :
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen module_get_symbol(module, t_strdup_printf(
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen "fs_class_%s", fs_driver_module_name(driver)));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class != NULL)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(fs_class);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen lib_atexit(fs_class_deinit_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenint fs_init(const char *driver, const char *args,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const struct fs_settings *set,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen struct fs **fs_r, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *fs_class;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const char *temp_file_prefix;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class = fs_class_find(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class == NULL) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen T_BEGIN {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_try_load_plugin(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen } T_END;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class = fs_class_find(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen }
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class == NULL) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return -1;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen for (i = 0; i < FS_OP_COUNT; i++)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen (*fs_r)->stats.timings[i] = timing_init();
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen set->temp_file_prefix : ".temp.dovecot";
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix, NULL);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_deinit(struct fs **fs)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen{
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs_unref(fs);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen}
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_ref(struct fs *fs)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen{
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen i_assert(fs->refcount > 0);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs->refcount++;
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen}
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_unref(struct fs **_fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs *fs = *_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen string_t *last_error = fs->last_error;
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen struct array module_contexts_arr = fs->module_contexts.arr;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen i_assert(fs->refcount > 0);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_fs = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen if (--fs->refcount > 0)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen return;
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs->files_open_count > 0) {
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen i_panic("fs-%s: %u files still open (first = %s)",
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen fs->name, fs->files_open_count, fs_file_path(fs->files));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen i_assert(fs->files == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen i_free(fs->username);
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen i_free(fs->session_id);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_free(fs->temp_path_prefix);
db6fe1b4c478231f9b63cca9069e2ab8fc70da2eTimo Sirainen for (i = 0; i < FS_OP_COUNT; i++)
db6fe1b4c478231f9b63cca9069e2ab8fc70da2eTimo Sirainen timing_deinit(&fs->stats.timings[i]);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen fs->v.deinit(fs);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen array_free_i(&module_contexts_arr);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen str_free(&last_error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainenstruct fs *fs_get_parent(struct fs *fs)
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen{
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen return fs->parent;
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen}
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainenconst char *fs_get_driver(struct fs *fs)
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen{
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen return fs->name;
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen}
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainenconst char *fs_get_root_driver(struct fs *fs)
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen{
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen while (fs->parent != NULL)
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen fs = fs->parent;
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen return fs->name;
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen}
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_file *file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(path != NULL);
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen (mode_flags & FS_OPEN_FLAG_ASYNC) != 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file = fs->v.file_init(fs, path, mode_flags & FS_OPEN_MODE_MASK,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen mode_flags & ~FS_OPEN_MODE_MASK);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->files_open_count++;
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen DLLIST_PREPEND(&fs->files, file);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_deinit(struct fs_file **_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_file *file = *_file;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen pool_t metadata_pool = file->metadata_pool;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(file->fs->files_open_count > 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_file = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen fs_file_close(file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen DLLIST_REMOVE(&file->fs->files, file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->files_open_count--;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen T_BEGIN {
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->v.file_deinit(file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen } T_END;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen if (metadata_pool != NULL)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen pool_unref(&metadata_pool);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen}
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainenvoid fs_file_close(struct fs_file *file)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen{
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->pending_read_input != NULL)
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->pending_read_input);
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen if (file->seekable_input != NULL)
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen i_stream_unref(&file->seekable_input);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->copy_input != NULL) {
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->copy_input);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen (void)fs_write_stream_abort(file, &file->copy_output);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen }
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen i_free_and_null(file->write_digest);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen if (file->fs->v.file_close != NULL) T_BEGIN {
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->v.file_close(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenenum fs_properties fs_get_properties(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return fs->v.get_properties(fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_metadata_init(struct fs_file *file)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (file->metadata_pool == NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen p_array_init(&file->metadata, file->metadata_pool, 8);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_default_set_metadata(struct fs_file *file,
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen const char *key, const char *value)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen struct fs_metadata *metadata;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_metadata_init(file);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata = array_append_space(&file->metadata);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->key = p_strdup(file->metadata_pool, key);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->value = p_strdup(file->metadata_pool, value);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.set_metadata != NULL) T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_metadata(file, key, value);
392538eef147981f6d818cd14cabc94cf8049d8eTimo Sirainen file->metadata_changed = TRUE;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void fs_file_timing_start(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen return;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (file->timing_start[op].tv_sec == 0) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&file->timing_start[op], NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenfs_timing_end(struct timing *timing, const struct timeval *start_tv)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct timeval now;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen long long diff;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&now, NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen diff = timeval_diff_usecs(&now, start_tv);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (diff > 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen timing_add_usecs(timing, diff);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenvoid fs_file_timing_end(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing || file->timing_start[op].tv_sec == 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen return;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_timing_end(file->fs->stats.timings[op], &file->timing_start[op]);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen file->timing_start[op].tv_sec = 0;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_get_metadata(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const ARRAY_TYPE(fs_metadata) **metadata_r)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen int ret;
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fs->v.get_metadata == NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->fs, "Metadata not supported by backend");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted &&
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted) {
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->lookup_metadata_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.lookup_metadata_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_METADATA);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = file->fs->v.get_metadata(file, metadata_r);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_METADATA);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainenint fs_lookup_metadata(struct fs_file *file, const char *key,
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const char **value_r)
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen{
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const ARRAY_TYPE(fs_metadata) *metadata;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const struct fs_metadata *md;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen if (fs_get_metadata(file, &metadata) < 0)
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen return -1;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen array_foreach(metadata, md) {
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen if (strcmp(md->key, key) == 0) {
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen *value_r = md->value;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen return 1;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen }
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen }
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen *value_r = NULL;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen return 0;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen}
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_path(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen return file->fs->v.get_path == NULL ? file->path :
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen file->fs->v.get_path(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenstruct fs *fs_file_fs(struct fs_file *file)
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen{
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen return file->fs;
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen}
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenstatic void ATTR_FORMAT(2, 0)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenfs_set_verror(struct fs *fs, const char *fmt, va_list args)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen{
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen if (fs->parent != NULL)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs->parent, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen else {
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen str_truncate(fs->last_error, 0);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen str_vprintfa(fs->last_error, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen }
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen}
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_last_error(struct fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen if (fs->parent != NULL)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen return fs_last_error(fs->parent);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (str_len(fs->last_error) == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return "BUG: Unknown fs error";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return str_c(fs->last_error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_last_error(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fs_last_error(file->fs);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenbool fs_prefetch(struct fs_file *file, uoff_t length)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen bool ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.prefetch_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_PREFETCH);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.prefetch(file, length);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_PREFETCH);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen const unsigned char *data;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen size_t data_size;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ssize_t ret;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(size > 0);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (file->pending_read_input == NULL)
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen file->pending_read_input = fs_read_stream(file, size+1);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ret = i_stream_read_data(file->pending_read_input,
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen &data, &data_size, size-1);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret == 0) {
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen fs_set_error_async(file->fs);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen return -1;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen }
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret < 0 && file->pending_read_input->stream_errno != 0) {
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(file->fs, "read(%s) failed: %s",
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_name(file->pending_read_input),
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_error(file->pending_read_input));
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen } else {
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ret = I_MIN(size, data_size);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen memcpy(buf, data, ret);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen }
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen i_stream_unref(&file->pending_read_input);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read(struct fs_file *file, void *buf, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.read_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_READ);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.read != NULL) {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.read(file, buf, size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_READ);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement read(), but we can do it with
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen streams. */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return fs_read_via_stream(file, buf, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen struct istream *input, *inputs[2];
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const unsigned char *data;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen size_t size;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen ssize_t ret;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen bool want_seekable = FALSE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.read_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_READ);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen if (file->seekable_input != NULL) {
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen i_stream_seek(file->seekable_input, 0);
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen i_stream_ref(file->seekable_input);
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen return file->seekable_input;
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (input->stream_errno != 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_READ);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return input;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (file->fs->set.enable_timing) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct istream *input2 = i_stream_create_fs_stats(input, file);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_stream_unref(&input);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen input = input2;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen want_seekable = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen want_seekable = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (want_seekable && !input->seekable) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* need to make the stream seekable */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen inputs[0] = input;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen inputs[1] = NULL;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = i_stream_create_seekable_path(inputs, max_buffer_size,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->fs->temp_path_prefix);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_set_name(input, i_stream_get_name(inputs[0]));
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_unref(&inputs[0]);
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen file->seekable_input = input;
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen i_stream_ref(file->seekable_input);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read the whole input stream before returning */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) >= 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_skip(input, size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (ret == 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_wait_async(file->fs) < 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input->stream_errno = errno;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input->eof = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen break;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_seek(input, 0);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return input;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen struct ostream *output;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ssize_t ret;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen int err;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if (!file->write_pending) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen output = fs_write_stream(file);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if ((ret = o_stream_send(output, data, size)) < 0) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen err = errno;
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(file->fs, "fs_write(%s) failed: %s",
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen o_stream_get_name(output),
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen o_stream_get_error(output));
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_write_stream_abort(file, &output);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen errno = err;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return -1;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen i_assert((size_t)ret == size);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ret = fs_write_stream_finish(file, &output);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen } else {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ret = fs_write_stream_finish_async(file);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if (ret == 0) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_set_error_async(file->fs);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen file->write_pending = TRUE;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return -1;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen file->write_pending = FALSE;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return ret < 0 ? -1 : 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write(struct fs_file *file, const void *data, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.write != NULL) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_WRITE);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.write(file, data, size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
b76b97a5b240ecfdd38d34645caa930d0de2ff27Timo Sirainen file->fs->stats.write_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_WRITE);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement write(), but we can do it with
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen streams. */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return fs_write_via_stream(file, data, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct ostream *fs_write_stream(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.write_count++;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen file->fs->v.write_stream(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(file->output != NULL);
af8e9722500efbba1bb58a96302a71977e1dbe92Timo Sirainen o_stream_cork(file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return file->output;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenstatic int fs_write_stream_finish_int(struct fs_file *file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_WRITE);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen T_BEGIN {
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen ret = file->fs->v.write_stream_finish(file, success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen } T_END;
8f8858ba3f4b14d3f651e091b5790f633e7f9fe5Timo Sirainen if (ret != 0) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_WRITE);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen file->metadata_changed = FALSE;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen } else {
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen /* write didn't finish yet. this shouldn't happen if we
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen indicated a failure. */
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen i_assert(success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen }
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return ret;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen}
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen{
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen bool success = TRUE;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
af8e9722500efbba1bb58a96302a71977e1dbe92Timo Sirainen if (file->output != NULL)
af8e9722500efbba1bb58a96302a71977e1dbe92Timo Sirainen o_stream_uncork(file->output);
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen if (file->output != NULL) {
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen if (o_stream_nfinish(file->output) < 0) {
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen fs_set_error(file->fs, "write(%s) failed: %s",
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen o_stream_get_name(file->output),
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen o_stream_get_error(file->output));
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen success = FALSE;
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen }
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen }
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, success);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, TRUE);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_write_stream_abort(struct fs_file *file, struct ostream **output)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(*output == file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
9750790dae6365365366e6fcaa3ab0c2e76b0507Timo Sirainen if (file->output != NULL)
9750790dae6365365366e6fcaa3ab0c2e76b0507Timo Sirainen o_stream_ignore_last_errors(file->output);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen (void)fs_write_stream_finish_int(file, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenvoid fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen const void *digest)
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen{
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest_method = method;
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen i_free(file->write_digest);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest = i_malloc(method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen memcpy(file->write_digest, digest, method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen}
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_set_async_callback(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file_async_callback_t *callback,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen void *context)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fs->v.set_async_callback != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_async_callback(file, callback, context);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen else
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen callback(context);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainenint fs_wait_async(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen /* recursion not allowed */
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen i_assert(fs->prev_ioloop == NULL);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainen if (fs->v.wait_async == NULL)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = 0;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen else T_BEGIN {
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen fs->prev_ioloop = current_ioloop;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = fs->v.wait_async(fs);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen i_assert(current_ioloop == fs->prev_ioloop);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen fs->prev_ioloop = NULL;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.lock(file, secs, lock_r);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_unlock(struct fs_lock **_lock)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_lock *lock = *_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_lock = NULL;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen lock->file->fs->v.unlock(lock);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_exists(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen struct stat st;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen if (file->fs->v.exists == NULL) {
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen /* fallback to stat() */
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen if (fs_stat(file, &st) == 0)
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen return 1;
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen else
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen return errno == ENOENT ? 0 : -1;
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen }
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.exists_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_EXISTS);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.exists(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_EXISTS);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted &&
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->stat_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.stat_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_STAT);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.stat(file, st_r);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_STAT);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen /* we're going to be counting this as read+write, so remove the
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen copy_count we just added */
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen dest->fs->stats.copy_count--;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_src != NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(src == NULL || src == dest->copy_src);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_output == NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(dest->copy_input == NULL);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo Sirainen if (fs_write_stream_finish_async(dest) <= 0)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = NULL;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return 0;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen } else {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = src;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_output = fs_write_stream(dest);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_input->stream_errno != 0) {
459b43463e1d652e5e2b8274246f1fa5ecf54d32Timo Sirainen errno = dest->copy_input->stream_errno;
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(dest->fs, "read(%s) failed: %s",
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_name(dest->copy_input),
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_error(dest->copy_input));
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen i_stream_unref(&dest->copy_input);
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_output->stream_errno != 0) {
459b43463e1d652e5e2b8274246f1fa5ecf54d32Timo Sirainen errno = dest->copy_output->stream_errno;
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(dest->fs, "write(%s) failed: %s",
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen o_stream_get_name(dest->copy_output),
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen o_stream_get_error(dest->copy_output));
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen i_stream_unref(&dest->copy_input);
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (!dest->copy_input->eof) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_set_error_async(dest->fs);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_stream_unref(&dest->copy_input);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo Sirainen if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = NULL;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return 0;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_copy(struct fs_file *src, struct fs_file *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen dest->fs->stats.copy_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(dest, FS_OP_COPY);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = src->fs->v.copy(src, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_COPY);
392538eef147981f6d818cd14cabc94cf8049d8eTimo Sirainen dest->metadata_changed = FALSE;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_copy_finish_async(struct fs_file *dest)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = dest->fs->v.copy(NULL, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_COPY);
392538eef147981f6d818cd14cabc94cf8049d8eTimo Sirainen dest->metadata_changed = FALSE;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen dest->fs->stats.rename_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(dest, FS_OP_RENAME);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = src->fs->v.rename(src, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_RENAME);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_delete(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.delete_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_DELETE);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.delete_file(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_DELETE);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstruct fs_iter *
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen struct fs_iter *iter;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct timeval now = ioloop_timeval;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen i_assert((flags & FS_ITER_FLAG_OBJECTIDS) == 0 ||
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen (fs_get_properties(fs) & FS_PROPERTY_OBJECTIDS) != 0);
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen fs->stats.iter_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (fs->set.enable_timing) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&now, NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen iter = fs->v.iter_init(fs, path, flags);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iter->start_time = now;
e13e798694ba1b0d0a5cf471600168eeaa8d2af4Timo Sirainen DLLIST_PREPEND(&fs->iters, iter);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return iter;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_iter_deinit(struct fs_iter **_iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_iter *iter = *_iter;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *_iter = NULL;
e13e798694ba1b0d0a5cf471600168eeaa8d2af4Timo Sirainen DLLIST_REMOVE(&iter->fs->iters, iter);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = iter->fs->v.iter_deinit(iter);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenconst char *fs_iter_next(struct fs_iter *iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen const char *ret;
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = iter->fs->v.iter_next(iter);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (iter->start_time.tv_sec != 0 &&
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen (ret != NULL || !fs_iter_have_more(iter))) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* first result returned - count this as the finish time, since
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen we don't want to count the time caller spends on this
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iteration. */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_timing_end(iter->fs->stats.timings[FS_OP_ITER], &iter->start_time);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iter->start_time.tv_sec = 0;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenvoid fs_iter_set_async_callback(struct fs_iter *iter,
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen fs_file_async_callback_t *callback,
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen void *context)
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen{
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen iter->async_callback = callback;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen iter->async_context = context;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen}
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenbool fs_iter_have_more(struct fs_iter *iter)
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen{
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen return iter->async_have_more;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen}
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainenconst struct fs_stats *fs_get_stats(struct fs *fs)
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen{
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen return &fs->stats;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen}
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_error(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_list args;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_start(args, fmt);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs, fmt, args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_end(args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_critical(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_list args;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_start(args, fmt);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen i_error("fs-%s: %s", fs->name, fs_last_error(fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_end(args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_error_async(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(fs, "Asynchronous operation in progress");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen errno = EAGAIN;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}