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 */
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainenstruct fs_api_module_register fs_api_module_register = { 0 };
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenstatic void fs_classes_init(void);
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)
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,
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenvoid fs_class_register(const struct fs *fs_class)
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainenstatic void fs_classes_deinit(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_classes_init(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic const struct fs *fs_class_find(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainenstatic const char *fs_driver_module_name(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen t_strdup_printf("fs_%s", fs_driver_module_name(driver));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module = module_dir_find(fs_modules, module_name);
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen "fs_class_%s", fs_driver_module_name(driver)));
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenint fs_init(const char *driver, const char *args,
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen for (i = 0; i < FS_OP_COUNT; i++)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen struct array module_contexts_arr = fs->module_contexts.arr;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
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));
db6fe1b4c478231f9b63cca9069e2ab8fc70da2eTimo Sirainen for (i = 0; i < FS_OP_COUNT; i++)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file = fs->v.file_init(fs, path, mode_flags & FS_OPEN_MODE_MASK,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
ef064b29e237d6093727e18f997f680881567771Timo Sirainen (void)fs_write_stream_abort(file, &file->copy_output);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenenum fs_properties fs_get_properties(struct fs *fs)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen p_array_init(&file->metadata, file->metadata_pool, 8);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_default_set_metadata(struct fs_file *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);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.set_metadata != NULL) T_BEGIN {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void fs_file_timing_start(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&file->timing_start[op], NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenfs_timing_end(struct timing *timing, const struct timeval *start_tv)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenvoid fs_file_timing_end(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing || file->timing_start[op].tv_sec == 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_timing_end(file->fs->stats.timings[op], &file->timing_start[op]);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->fs, "Metadata not supported by backend");
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = file->fs->v.get_metadata(file, metadata_r);
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainenint fs_lookup_metadata(struct fs_file *file, const char *key,
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const char **value_r)
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen return file->fs->v.get_path == NULL ? file->path :
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenfs_set_verror(struct fs *fs, const char *fmt, va_list args)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return "BUG: Unknown fs error";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_last_error(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenbool fs_prefetch(struct fs_file *file, uoff_t length)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen const unsigned char *data;
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 if (ret < 0 && file->pending_read_input->stream_errno != 0) {
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_error(file->pending_read_input));
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read(struct fs_file *file, void *buf, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement read(), but we can do it with
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const unsigned char *data;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct istream *input2 = i_stream_create_fs_stats(input, file);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* need to make the stream seekable */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = i_stream_create_seekable_path(inputs, max_buffer_size,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_set_name(input, i_stream_get_name(inputs[0]));
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) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if ((ret = o_stream_send(output, data, size)) < 0) {
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(file->fs, "fs_write(%s) failed: %s",
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write(struct fs_file *file, const void *data, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement write(), but we can do it with
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct ostream *fs_write_stream(struct fs_file *file)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenstatic int fs_write_stream_finish_int(struct fs_file *file, bool success)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen ret = file->fs->v.write_stream_finish(file, success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen /* write didn't finish yet. this shouldn't happen if we
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen indicated a failure. */
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen fs_set_error(file->fs, "write(%s) failed: %s",
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, success);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, TRUE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_write_stream_abort(struct fs_file *file, struct ostream **output)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen (void)fs_write_stream_finish_int(file, FALSE);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenvoid fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest = i_malloc(method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen memcpy(file->write_digest, digest, method->digest_size);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_set_async_callback(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_async_callback(file, callback, context);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen /* recursion not allowed */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen /* fallback to stat() */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen /* we're going to be counting this as read+write, so remove the
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen copy_count we just added */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(src == NULL || src == dest->copy_src);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(dest->fs, "write(%s) failed: %s",
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo Sirainen if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_copy(struct fs_file *src, struct fs_file *dest)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen i_assert((flags & FS_ITER_FLAG_OBJECTIDS) == 0 ||
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen (fs_get_properties(fs) & FS_PROPERTY_OBJECTIDS) != 0);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen const char *ret;
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 */
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenvoid fs_iter_set_async_callback(struct fs_iter *iter,
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainenconst struct fs_stats *fs_get_stats(struct fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_error(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_critical(struct fs *fs, const char *fmt, ...)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen i_error("fs-%s: %s", fs->name, fs_last_error(fs));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(fs, "Asynchronous operation in progress");