Coverage Report

Created: 2026-09-03 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-fs/fs-api.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "array.h"
5
#include "module-dir.h"
6
#include "llist.h"
7
#include "str.h"
8
#include "hash-method.h"
9
#include "istream.h"
10
#include "istream-seekable.h"
11
#include "ostream.h"
12
#include "stats-dist.h"
13
#include "time-util.h"
14
#include "settings.h"
15
#include "istream-fs-stats.h"
16
#include "fs-api-private.h"
17
18
static bool fs_settings_check(void *_set, pool_t pool, const char **error_r);
19
20
#undef DEF
21
#define DEF(type, name) \
22
  SETTING_DEFINE_STRUCT_##type(#name, name, struct fs_settings)
23
static const struct setting_define fs_setting_defines[] = {
24
  DEF(STR, fs_name),
25
  DEF(STR, fs_driver),
26
  { .type = SET_FILTER_ARRAY, .key = "fs",
27
    .offset = offsetof(struct fs_settings, fs),
28
    .filter_array_field_name = "fs_name", },
29
30
  SETTING_DEFINE_LIST_END
31
};
32
static const struct fs_settings fs_default_settings = {
33
  .fs_name = "",
34
  .fs_driver = "",
35
  .fs = ARRAY_INIT,
36
};
37
const struct setting_parser_info fs_setting_parser_info = {
38
  .name = "fs",
39
40
  .defines = fs_setting_defines,
41
  .defaults = &fs_default_settings,
42
43
  .struct_size = sizeof(struct fs_settings),
44
  .pool_offset1 = 1 + offsetof(struct fs_settings, pool),
45
46
  .check_func = fs_settings_check,
47
};
48
49
static struct event_category event_category_fs = {
50
  .name = "fs"
51
};
52
53
struct fs_api_module_register fs_api_module_register = { 0 };
54
55
static struct module *fs_modules = NULL;
56
static ARRAY(const struct fs *) fs_classes;
57
58
static void fs_classes_init(void);
59
60
static struct event *fs_create_event(struct fs *fs, struct event *parent)
61
0
{
62
0
  struct event *event;
63
64
0
  event = event_create(parent);
65
0
  event_add_category(event, &event_category_fs);
66
0
  event_set_append_log_prefix(event,
67
0
    t_strdup_printf("fs-%s: ", fs->name));
68
0
  return event;
69
0
}
70
71
void fs_class_register(const struct fs *fs_class)
72
0
{
73
0
  if (!array_is_created(&fs_classes))
74
0
    fs_classes_init();
75
0
  array_push_back(&fs_classes, &fs_class);
76
0
}
77
78
void fs_class_unregister(const struct fs *fs_class)
79
0
{
80
0
  const struct fs *const *p;
81
82
0
  array_foreach(&fs_classes, p) {
83
0
    if (*p == fs_class) {
84
0
      array_delete(&fs_classes,
85
0
             array_foreach_idx(&fs_classes, p), 1);
86
0
      return;
87
0
    }
88
0
  }
89
0
  i_panic("fs_class_unregister(): Class %s not found", fs_class->name);
90
0
}
91
92
static void fs_classes_deinit(void)
93
0
{
94
0
  array_free(&fs_classes);
95
0
}
96
97
static void fs_classes_init(void)
98
0
{
99
0
  i_array_init(&fs_classes, 8);
100
0
  fs_class_register(&fs_class_dict);
101
0
  fs_class_register(&fs_class_posix);
102
0
  fs_class_register(&fs_class_randomfail);
103
0
  fs_class_register(&fs_class_metawrap);
104
0
  fs_class_register(&fs_class_sis);
105
0
  fs_class_register(&fs_class_sis_queue);
106
0
  fs_class_register(&fs_class_test);
107
0
  lib_atexit_priority(fs_classes_deinit, LIB_ATEXIT_PRIORITY_LOW);
108
0
}
109
110
static const struct fs *fs_class_find(const char *driver)
111
0
{
112
0
  const struct fs *class;
113
114
0
  if (!array_is_created(&fs_classes))
115
0
    fs_classes_init();
116
117
0
  array_foreach_elem(&fs_classes, class) {
118
0
    if (strcmp(class->name, driver) == 0)
119
0
      return class;
120
0
  }
121
0
  return NULL;
122
0
}
123
124
static void fs_class_deinit_modules(void)
125
0
{
126
0
  module_dir_unload(&fs_modules);
127
0
}
128
129
static const char *fs_driver_module_name(const char *driver)
130
0
{
131
0
  return t_str_replace(driver, '-', '_');
132
0
}
133
134
static void fs_class_try_load_plugin(const char *driver)
135
0
{
136
0
  const char *module_names[] = {
137
0
    t_strdup_printf("fs_%s", fs_driver_module_name(driver)),
138
0
    NULL
139
0
  };
140
0
  struct module *module;
141
0
  struct module_dir_load_settings mod_set;
142
0
  const struct fs *fs_class;
143
144
0
  i_zero(&mod_set);
145
0
  mod_set.abi_version = DOVECOT_ABI_VERSION;
146
0
  mod_set.ignore_missing = TRUE;
147
148
0
  fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
149
0
               module_names, &mod_set);
150
0
  module_dir_init(fs_modules);
151
152
0
  module = module_dir_find(fs_modules, module_names[0]);
153
0
  fs_class = module == NULL ? NULL :
154
0
    module_get_symbol(module, t_strdup_printf(
155
0
      "fs_class_%s", fs_driver_module_name(driver)));
156
0
  if (fs_class != NULL)
157
0
    fs_class_register(fs_class);
158
159
0
  lib_atexit(fs_class_deinit_modules);
160
0
}
161
162
static int
163
fs_alloc(const char *driver, struct event *event_parent,
164
   const struct fs_parameters *params,
165
   struct fs **fs_r, const char **error_r)
166
0
{
167
0
  const struct fs *fs_class;
168
0
  struct fs *fs;
169
0
  const char *temp_dir, *temp_file_prefix;
170
171
0
  fs_class = fs_class_find(driver);
172
0
  if (fs_class == NULL) {
173
0
    T_BEGIN {
174
0
      fs_class_try_load_plugin(driver);
175
0
    } T_END;
176
0
    fs_class = fs_class_find(driver);
177
0
  }
178
0
  if (fs_class == NULL) {
179
0
    *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
180
0
    return -1;
181
0
  }
182
183
0
  fs = fs_class->v.alloc();
184
0
  fs->refcount = 1;
185
0
  fs->enable_timing = params->enable_timing;
186
0
  fs->username = i_strdup(params->username);
187
0
  fs->session_id = i_strdup(params->session_id);
188
0
  i_array_init(&fs->module_contexts, 5);
189
0
  fs->event = fs_create_event(fs, event_parent);
190
0
  event_set_ptr(fs->event, FS_EVENT_FIELD_FS, fs);
191
192
0
  temp_dir = params->temp_dir != NULL ? params->temp_dir : "/tmp";
193
0
  temp_file_prefix = params->temp_file_prefix != NULL ?
194
0
    params->temp_file_prefix : ".temp.dovecot";
195
0
  fs->temp_path_prefix = i_strconcat(temp_dir, "/", temp_file_prefix, NULL);
196
197
0
  *fs_r = fs;
198
0
  return 0;
199
0
}
200
201
static bool fs_settings_check(void *_set, pool_t pool ATTR_UNUSED,
202
            const char **error_r ATTR_UNUSED)
203
0
{
204
0
  struct fs_settings *set = _set;
205
206
0
  if (set->fs_driver[0] == '\0' && set->fs_name[0] != '\0') {
207
    /* default an empty fs_driver to fs_name, so it's possible to
208
       configure simply: fs driver { .. }, but to still allow the
209
       same driver to be used multiple times if necessary. */
210
0
    set->fs_driver = set->fs_name;
211
0
  }
212
0
  return TRUE;
213
0
}
214
215
static int fs_init(struct event *event,
216
       const struct fs_parameters *params,
217
       const ARRAY_TYPE(const_string) *fs_list,
218
       unsigned int fs_list_idx,
219
       unsigned int *init_fs_last_list_idx,
220
       struct fs **fs_r, const char **error_r)
221
0
{
222
0
  const struct fs_settings *fs_set;
223
0
  struct fs *fs;
224
0
  const char *fs_name, *error;
225
0
  int ret;
226
227
0
  fs_name = array_idx_elem(fs_list, fs_list_idx);
228
0
  if (settings_get_filter(event, "fs", fs_name, &fs_setting_parser_info,
229
0
        0, &fs_set, error_r) < 0)
230
0
    return -1;
231
232
0
  if (fs_set->fs_driver[0] == '\0') {
233
0
    *error_r = "fs_driver is empty";
234
0
    settings_free(fs_set);
235
0
    return -1;
236
0
  }
237
238
0
  event_add_str(event, "fs", fs_name);
239
0
  settings_event_add_list_filter_name(event, "fs", fs_name);
240
241
0
  ret = fs_alloc(fs_set->fs_driver, event, params, &fs, error_r);
242
0
  settings_free(fs_set);
243
0
  if (ret < 0)
244
0
    return -1;
245
246
0
  fs->init_fs_list = fs_list;
247
0
  fs->init_fs_list_idx = fs_list_idx;
248
0
  fs->init_fs_last_list_idx = init_fs_last_list_idx;
249
0
  *init_fs_last_list_idx = fs_list_idx;
250
0
  T_BEGIN {
251
0
    ret = fs->v.init(fs, params, &error);
252
0
  } T_END_PASS_STR_IF(ret < 0, &error);
253
0
  if (ret < 0) {
254
0
    *error_r = t_strdup_printf("%s: %s", fs->name, error);
255
0
    fs_unref(&fs);
256
0
    return -1;
257
0
  }
258
  /* fs's parent event points to the fs parent's event. This is normally
259
     wanted. However, we don't want the parent fs's settings to be read
260
     for this fs. We don't expect settings to be read anymore after
261
     init(). Drop settings_filter_name so if settings are attempted to be
262
     read later on, it will be obvious enough that it's not using any
263
     fs settings. */
264
0
  event_set_ptr(event, SETTINGS_EVENT_FILTER_NAME, NULL);
265
0
  fs->init_fs_list = NULL;
266
0
  *fs_r = fs;
267
0
  return 0;
268
0
}
269
270
int fs_init_auto(struct event *event, const struct fs_parameters *params,
271
     struct fs **fs_r, const char **error_r)
272
0
{
273
0
  const struct fs_settings *fs_set;
274
0
  struct fs *fs;
275
0
  unsigned int last_list_idx;
276
0
  int ret;
277
278
0
  if (settings_get(event, &fs_setting_parser_info, 0,
279
0
       &fs_set, error_r) < 0)
280
0
    return -1;
281
0
  if (array_is_empty(&fs_set->fs)) {
282
0
    settings_free(fs_set);
283
0
    *error_r = "fs { .. } named list filter is missing";
284
0
    return 0;
285
0
  }
286
287
0
  event = event_create(event);
288
0
  ret = fs_init(event, params, &fs_set->fs, 0,
289
0
          &last_list_idx, &fs, error_r);
290
0
  event_unref(&event);
291
292
0
  if (ret == 0 && last_list_idx + 1 < array_count(&fs_set->fs)) {
293
0
    const char *fs_name_last =
294
0
      array_idx_elem(&fs_set->fs, last_list_idx);
295
0
    const char *fs_name_extra =
296
0
      array_idx_elem(&fs_set->fs, last_list_idx + 1);
297
0
    *error_r = t_strdup_printf(
298
0
      "Extra fs %s { .. } named list filter - "
299
0
      "the parent fs %s { .. } doesn't support a child fs",
300
0
      fs_name_extra, fs_name_last);
301
0
    settings_free(fs_set);
302
0
    fs_unref(&fs);
303
0
    return -1;
304
0
  }
305
0
  settings_free(fs_set);
306
0
  if (ret < 0)
307
0
    return -1;
308
0
  *fs_r = fs;
309
0
  return 1;
310
0
}
311
312
int fs_init_parent(struct fs *fs, const struct fs_parameters *params,
313
       const char **error_r)
314
0
{
315
0
  if (fs->init_fs_list_idx + 1 >= array_count(fs->init_fs_list)) {
316
0
    *error_r = "Next fs { .. } named list filter is missing";
317
0
    return -1;
318
0
  }
319
320
  /* Remove the parent fs's settings_filter_name while initializing a
321
     child fs, so the parent settings won't be attempted to be read. */
322
0
  char *old_filter = event_get_ptr(event_get_parent(fs->event),
323
0
           SETTINGS_EVENT_FILTER_NAME);
324
0
  event_set_ptr(event_get_parent(fs->event),
325
0
          SETTINGS_EVENT_FILTER_NAME, NULL);
326
327
0
  struct event *event = event_create(fs->event);
328
  /* Drop the parent "fs-name: " prefix */
329
0
  event_drop_parent_log_prefixes(event, 1);
330
0
  int ret = fs_init(event, params,
331
0
        fs->init_fs_list, fs->init_fs_list_idx + 1,
332
0
        fs->init_fs_last_list_idx,
333
0
        &fs->parent, error_r);
334
0
  event_unref(&event);
335
  /* Restore the old settings_filter_name, since the caller's init()
336
     could still need it. */
337
0
  event_set_ptr(event_get_parent(fs->event),
338
0
          SETTINGS_EVENT_FILTER_NAME, old_filter);
339
0
  return ret;
340
0
}
341
342
void fs_deinit(struct fs **fs)
343
0
{
344
0
  fs_unref(fs);
345
0
}
346
347
void fs_ref(struct fs *fs)
348
0
{
349
0
  i_assert(fs->refcount > 0);
350
351
0
  fs->refcount++;
352
0
}
353
354
void fs_unref(struct fs **_fs)
355
0
{
356
0
  struct fs *fs = *_fs;
357
0
  struct array module_contexts_arr;
358
0
  unsigned int i;
359
360
0
  if (fs == NULL)
361
0
    return;
362
363
0
  module_contexts_arr = fs->module_contexts.arr;
364
365
0
  i_assert(fs->refcount > 0);
366
367
0
  *_fs = NULL;
368
369
0
  if (--fs->refcount > 0)
370
0
    return;
371
372
0
  if (fs->files_open_count > 0) {
373
0
    i_panic("fs-%s: %u files still open (first = %s)",
374
0
      fs->name, fs->files_open_count, fs_file_path(fs->files));
375
0
  }
376
0
  i_assert(fs->files == NULL);
377
378
0
  if (fs->v.deinit != NULL)
379
0
    fs->v.deinit(fs);
380
381
0
  fs_deinit(&fs->parent);
382
0
  event_unref(&fs->event);
383
0
  i_free(fs->username);
384
0
  i_free(fs->session_id);
385
0
  i_free(fs->temp_path_prefix);
386
0
  for (i = 0; i < FS_OP_COUNT; i++) {
387
0
    if (fs->stats.timings[i] != NULL)
388
0
      stats_dist_deinit(&fs->stats.timings[i]);
389
0
  }
390
0
  T_BEGIN {
391
0
    fs->v.free(fs);
392
0
  } T_END;
393
0
  array_free_i(&module_contexts_arr);
394
0
}
395
396
struct fs *fs_get_parent(struct fs *fs)
397
0
{
398
0
  return fs->parent;
399
0
}
400
401
const char *fs_get_driver(struct fs *fs)
402
0
{
403
0
  return fs->name;
404
0
}
405
406
struct fs *fs_get_root_fs(struct fs *fs)
407
0
{
408
0
  while (fs->parent != NULL)
409
0
    fs = fs->parent;
410
0
  return fs;
411
0
}
412
413
const char *fs_get_root_driver(struct fs *fs)
414
0
{
415
0
  return fs_get_root_fs(fs)->name;
416
0
}
417
418
struct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
419
0
{
420
0
  return fs_file_init_with_event(fs, fs->event, path, mode_flags);
421
0
}
422
423
struct fs_file *fs_file_init_with_event(struct fs *fs, struct event *event,
424
          const char *path, int mode_flags)
425
0
{
426
0
  struct fs_file *file;
427
428
0
  i_assert(path != NULL);
429
0
  i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
430
0
     (mode_flags & FS_OPEN_FLAG_ASYNC) != 0);
431
432
0
  T_BEGIN {
433
0
    file = fs->v.file_alloc();
434
0
    file->fs = fs;
435
0
    file->flags = mode_flags & ENUM_NEGATE(FS_OPEN_MODE_MASK);
436
0
    file->event = fs_create_event(fs, event);
437
0
    event_set_ptr(file->event, FS_EVENT_FIELD_FS, fs);
438
0
    event_set_ptr(file->event, FS_EVENT_FIELD_FILE, file);
439
0
    fs->v.file_init(file, path, mode_flags & FS_OPEN_MODE_MASK,
440
0
        mode_flags & ENUM_NEGATE(FS_OPEN_MODE_MASK));
441
0
  } T_END;
442
443
0
  fs->files_open_count++;
444
0
  DLLIST_PREPEND(&fs->files, file);
445
446
0
  fs_set_metadata(file, FS_METADATA_ORIG_PATH, path);
447
0
  return file;
448
0
}
449
450
void fs_file_deinit(struct fs_file **_file)
451
0
{
452
0
  struct fs_file *file = *_file;
453
454
0
  if (file == NULL)
455
0
    return;
456
457
0
  i_assert(file->fs->files_open_count > 0);
458
459
0
  *_file = NULL;
460
461
0
  fs_file_close(file);
462
463
0
  DLLIST_REMOVE(&file->fs->files, file);
464
0
  file->fs->files_open_count--;
465
0
  T_BEGIN {
466
0
    file->fs->v.file_deinit(file);
467
0
  } T_END;
468
0
}
469
470
bool fs_file_equals(struct fs_file *file1, struct fs_file *file2)
471
0
{
472
0
  while (file1->parent != NULL)
473
0
    file1 = file1->parent;
474
0
  while (file2->parent != NULL)
475
0
    file2 = file2->parent;
476
477
0
  if (strcmp(file1->fs->name, file2->fs->name) != 0)
478
0
    return FALSE;
479
0
  if (file1->fs->v.file_equals == NULL)
480
0
    return FALSE;
481
0
  i_assert(file1->fs->v.file_equals == file2->fs->v.file_equals);
482
0
  return file1->fs->v.file_equals(file1, file2);
483
0
}
484
485
void fs_file_free(struct fs_file *file)
486
0
{
487
0
  if (file->last_error_changed) {
488
    /* fs_set_error() used without ever accessing it via
489
       fs_file_last_error(). Log it to make sure it's not lost.
490
       Note that the errors are always set only to the file at
491
       the root of the parent hierarchy. */
492
0
    e_error(file->event, "%s (in file %s deinit)",
493
0
      file->last_error, fs_file_path(file));
494
0
  }
495
496
0
  fs_file_deinit(&file->parent);
497
0
  event_unref(&file->event);
498
0
  pool_unref(&file->metadata_pool);
499
0
  i_free(file->last_error);
500
0
}
501
502
void fs_file_set_flags(struct fs_file *file,
503
           enum fs_open_flags add_flags,
504
           enum fs_open_flags remove_flags)
505
0
{
506
0
  file->flags |= add_flags;
507
0
  file->flags &= ENUM_NEGATE(remove_flags);
508
509
0
  if (file->parent != NULL)
510
0
    fs_file_set_flags(file->parent, add_flags, remove_flags);
511
0
}
512
513
void fs_file_close(struct fs_file *file)
514
0
{
515
0
  if (file == NULL)
516
0
    return;
517
518
0
  i_assert(!file->writing_stream);
519
0
  i_assert(file->output == NULL);
520
521
0
  if (file->pending_read_input != NULL)
522
0
    i_stream_unref(&file->pending_read_input);
523
0
  if (file->seekable_input != NULL)
524
0
    i_stream_unref(&file->seekable_input);
525
526
0
  if (file->copy_input != NULL) {
527
0
    i_stream_unref(&file->copy_input);
528
0
    fs_write_stream_abort_error(file, &file->copy_output, "fs_file_close(%s)",
529
0
              o_stream_get_name(file->copy_output));
530
0
  }
531
0
  i_free_and_null(file->write_digest);
532
0
  if (file->fs->v.file_close != NULL) T_BEGIN {
533
0
    file->fs->v.file_close(file);
534
0
  } T_END;
535
536
  /* check this only after closing, because some of the fs backends keep
537
     the istream internally open and don't call the destroy-callback
538
     until after file_close() */
539
0
  i_assert(!file->istream_open);
540
0
}
541
542
enum fs_properties fs_get_properties(struct fs *fs)
543
0
{
544
0
  return fs->v.get_properties(fs);
545
0
}
546
547
void fs_metadata_init(struct fs_file *file)
548
0
{
549
0
  if (file->metadata_pool == NULL) {
550
0
    i_assert(!array_is_created(&file->metadata));
551
0
    file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
552
0
    p_array_init(&file->metadata, file->metadata_pool, 8);
553
0
  }
554
0
}
555
556
void fs_metadata_init_or_clear(struct fs_file *file)
557
0
{
558
0
  if (file->metadata_pool == NULL)
559
0
    fs_metadata_init(file);
560
0
  else T_BEGIN {
561
0
    const struct fs_metadata *md;
562
0
    ARRAY_TYPE(fs_metadata) internal_metadata;
563
564
0
    t_array_init(&internal_metadata, 4);
565
0
    array_foreach(&file->metadata, md) {
566
0
      if (strncmp(md->key, FS_METADATA_INTERNAL_PREFIX,
567
0
            strlen(FS_METADATA_INTERNAL_PREFIX)) == 0)
568
0
        array_push_back(&internal_metadata, md);
569
0
    }
570
0
    array_clear(&file->metadata);
571
0
    array_append_array(&file->metadata, &internal_metadata);
572
0
  } T_END;
573
0
}
574
575
static struct fs_metadata *
576
fs_metadata_find_md(const ARRAY_TYPE(fs_metadata) *metadata,
577
        const char *key)
578
0
{
579
0
  struct fs_metadata *md;
580
581
0
  array_foreach_modifiable(metadata, md) {
582
0
    if (strcmp(md->key, key) == 0)
583
0
      return md;
584
0
  }
585
0
  return NULL;
586
0
}
587
588
void fs_default_set_metadata(struct fs_file *file,
589
           const char *key, const char *value)
590
0
{
591
0
  struct fs_metadata *metadata;
592
593
0
  fs_metadata_init(file);
594
0
  metadata = fs_metadata_find_md(&file->metadata, key);
595
0
  if (metadata == NULL) {
596
0
    metadata = array_append_space(&file->metadata);
597
0
    metadata->key = p_strdup(file->metadata_pool, key);
598
0
  }
599
0
  metadata->value = p_strdup(file->metadata_pool, value);
600
0
}
601
602
const char *fs_metadata_find(const ARRAY_TYPE(fs_metadata) *metadata,
603
           const char *key)
604
0
{
605
0
  const struct fs_metadata *md;
606
607
0
  if (!array_is_created(metadata))
608
0
    return NULL;
609
610
0
  md = fs_metadata_find_md(metadata, key);
611
0
  return md == NULL ? NULL : md->value;
612
0
}
613
614
void fs_set_metadata(struct fs_file *file, const char *key, const char *value)
615
0
{
616
0
  i_assert(key != NULL);
617
0
  i_assert(value != NULL);
618
0
  i_assert(strchr(key, '_') == NULL);
619
620
0
  if (file->fs->v.set_metadata != NULL) T_BEGIN {
621
0
    file->fs->v.set_metadata(file, key, value);
622
0
    if (strncmp(key, FS_METADATA_INTERNAL_PREFIX,
623
0
          strlen(FS_METADATA_INTERNAL_PREFIX)) == 0) {
624
      /* internal metadata change, which isn't stored. */
625
0
    } else {
626
0
      file->metadata_changed = TRUE;
627
0
    }
628
0
  } T_END;
629
0
}
630
631
static void fs_file_timing_start(struct fs_file *file, enum fs_op op)
632
0
{
633
0
  if (!file->fs->enable_timing)
634
0
    return;
635
0
  if (file->timing_start[op].tv_sec == 0)
636
0
    i_gettimeofday(&file->timing_start[op]);
637
0
}
638
639
static void
640
fs_timing_end(struct stats_dist **timing, const struct timeval *start_tv)
641
0
{
642
0
  struct timeval now;
643
0
  long long diff;
644
645
0
  i_gettimeofday(&now);
646
647
0
  diff = timeval_diff_usecs(&now, start_tv);
648
0
  if (diff > 0) {
649
0
    if (*timing == NULL)
650
0
      *timing = stats_dist_init();
651
0
    stats_dist_add(*timing, diff);
652
0
  }
653
0
}
654
655
void fs_file_timing_end(struct fs_file *file, enum fs_op op)
656
0
{
657
0
  if (!file->fs->enable_timing || file->timing_start[op].tv_sec == 0)
658
0
    return;
659
660
0
  fs_timing_end(&file->fs->stats.timings[op], &file->timing_start[op]);
661
  /* don't count this again */
662
0
  file->timing_start[op].tv_sec = 0;
663
0
}
664
665
int fs_get_metadata_full(struct fs_file *file,
666
       enum fs_get_metadata_flags flags,
667
       const ARRAY_TYPE(fs_metadata) **metadata_r)
668
0
{
669
0
  int ret;
670
671
0
  if (file->fs->v.get_metadata == NULL) {
672
0
    if (array_is_created(&file->metadata)) {
673
      /* Return internal metadata. */
674
0
      *metadata_r = &file->metadata;
675
0
      return 0;
676
0
    }
677
0
    fs_set_error(file->event, ENOTSUP, "Metadata not supported by backend");
678
0
    return -1;
679
0
  }
680
0
  if (!file->read_or_prefetch_counted &&
681
0
      !file->lookup_metadata_counted) {
682
0
    if ((flags & FS_GET_METADATA_FLAG_LOADED_ONLY) == 0) {
683
0
      file->lookup_metadata_counted = TRUE;
684
0
      file->fs->stats.lookup_metadata_count++;
685
0
    }
686
0
    fs_file_timing_start(file, FS_OP_METADATA);
687
0
  }
688
0
  T_BEGIN {
689
0
    ret = file->fs->v.get_metadata(file, flags, metadata_r);
690
0
  } T_END;
691
0
  if (!(ret < 0 && errno == EAGAIN))
692
0
    fs_file_timing_end(file, FS_OP_METADATA);
693
0
  return ret;
694
0
}
695
696
int fs_get_metadata(struct fs_file *file,
697
        const ARRAY_TYPE(fs_metadata) **metadata_r)
698
0
{
699
0
  return fs_get_metadata_full(file, 0, metadata_r);
700
0
}
701
702
int fs_lookup_metadata(struct fs_file *file, const char *key,
703
           const char **value_r)
704
0
{
705
0
  const ARRAY_TYPE(fs_metadata) *metadata;
706
707
0
  if (fs_get_metadata(file, &metadata) < 0)
708
0
    return -1;
709
0
  *value_r = fs_metadata_find(metadata, key);
710
0
  return *value_r != NULL ? 1 : 0;
711
0
}
712
713
const char *fs_lookup_loaded_metadata(struct fs_file *file, const char *key)
714
0
{
715
0
  const ARRAY_TYPE(fs_metadata) *metadata;
716
717
0
  if (fs_get_metadata_full(file, FS_GET_METADATA_FLAG_LOADED_ONLY, &metadata) < 0)
718
0
    i_panic("FS_GET_METADATA_FLAG_LOADED_ONLY lookup can't fail");
719
0
  return fs_metadata_find(metadata, key);
720
0
}
721
722
const char *fs_file_path(struct fs_file *file)
723
0
{
724
0
  return file->fs->v.get_path == NULL ? file->path :
725
0
    file->fs->v.get_path(file);
726
0
}
727
728
struct fs *fs_file_fs(struct fs_file *file)
729
0
{
730
0
  return file->fs;
731
0
}
732
733
struct event *fs_file_event(struct fs_file *file)
734
0
{
735
0
  return file->event;
736
0
}
737
738
static struct fs_file *fs_file_get_error_file(struct fs_file *file)
739
0
{
740
  /* the error is always kept in the parent-most file */
741
0
  while (file->parent != NULL)
742
0
    file = file->parent;
743
0
  return file;
744
0
}
745
746
static void ATTR_FORMAT(2, 0)
747
fs_set_verror(struct event *event, const char *fmt, va_list args)
748
0
{
749
0
  struct event *fs_event = event;
750
0
  struct fs_file *file;
751
0
  struct fs_iter *iter;
752
753
  /* NOTE: the event might be a passthrough event. We must log it exactly
754
     once so it gets freed. */
755
756
  /* figure out if the error is for a file or iter */
757
0
  while ((file = event_get_ptr(fs_event, FS_EVENT_FIELD_FILE)) == NULL &&
758
0
         (iter = event_get_ptr(fs_event, FS_EVENT_FIELD_ITER)) == NULL) {
759
0
    fs_event = event_get_parent(fs_event);
760
0
    i_assert(fs_event != NULL);
761
0
  }
762
763
0
  char *new_error = i_strdup_vprintf(fmt, args);
764
  /* Don't flood the debug log with "Asynchronous operation in progress"
765
     messages. They tell nothing useful. */
766
0
  if (errno != EAGAIN)
767
0
    e_debug(event, "%s", new_error);
768
0
  else
769
0
    event_send_abort(event);
770
771
  /* free old error after strdup in case args point to the old error */
772
0
  if (file != NULL) {
773
0
    file = fs_file_get_error_file(file);
774
0
    char *old_error = file->last_error;
775
776
0
    if (old_error == NULL) {
777
0
      i_assert(!file->last_error_changed);
778
0
    } else if (strcmp(old_error, new_error) == 0) {
779
      /* identical error - ignore */
780
0
    } else if (file->last_error_changed) {
781
      /* multiple fs_set_error() calls used without
782
         fs_file_last_error() in the middle. */
783
0
      e_error(file->event, "%s (overwriting error for file %s)",
784
0
        old_error, fs_file_path(file));
785
0
    }
786
0
    if (errno == EAGAIN || errno == ENOENT || errno == EEXIST ||
787
0
        errno == ENOTEMPTY) {
788
      /* These are (or can be) expected errors - don't log
789
         them if they have a missing fs_file_last_error()
790
         call */
791
0
      file->last_error_changed = FALSE;
792
0
    } else {
793
0
      file->last_error_changed = TRUE;
794
0
    }
795
796
0
    i_free(file->last_error);
797
0
    file->last_error = new_error;
798
0
  } else {
799
0
    i_assert(iter != NULL);
800
0
    if (iter->last_error != NULL &&
801
0
        strcmp(iter->last_error, new_error) == 0) {
802
      /* identical error - ignore */
803
0
    } else if (iter->last_error != NULL) {
804
      /* multiple fs_set_error() calls before the iter
805
         finishes */
806
0
      e_error(iter->fs->event, "%s (overwriting error for file %s)",
807
0
        iter->last_error, iter->path);
808
0
    }
809
0
    i_free(iter->last_error);
810
0
    iter->last_error = new_error;
811
0
  }
812
0
}
813
814
const char *fs_file_last_error(struct fs_file *file)
815
0
{
816
0
  struct fs_file *error_file = fs_file_get_error_file(file);
817
818
0
  error_file->last_error_changed = FALSE;
819
0
  if (error_file->last_error == NULL)
820
0
    return "BUG: Unknown file error";
821
0
  return error_file->last_error;
822
0
}
823
824
bool fs_prefetch(struct fs_file *file, uoff_t length)
825
0
{
826
0
  bool ret;
827
828
0
  if (!file->read_or_prefetch_counted) {
829
0
    file->read_or_prefetch_counted = TRUE;
830
0
    file->fs->stats.prefetch_count++;
831
0
    fs_file_timing_start(file, FS_OP_PREFETCH);
832
0
  }
833
0
  T_BEGIN {
834
0
    ret = file->fs->v.prefetch(file, length);
835
0
  } T_END;
836
0
  fs_file_timing_end(file, FS_OP_PREFETCH);
837
0
  return ret;
838
0
}
839
840
ssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
841
0
{
842
0
  const unsigned char *data;
843
0
  size_t data_size;
844
0
  ssize_t ret;
845
846
0
  i_assert(size > 0);
847
848
0
  if (file->pending_read_input == NULL)
849
0
    file->pending_read_input = fs_read_stream(file, size+1);
850
0
  ret = i_stream_read_bytes(file->pending_read_input, &data,
851
0
          &data_size, size);
852
0
  if (ret == 0) {
853
0
    fs_file_set_error_async(file);
854
0
    return -1;
855
0
  }
856
0
  if (ret < 0 && file->pending_read_input->stream_errno != 0) {
857
0
    fs_set_error(file->event,
858
0
           file->pending_read_input->stream_errno,
859
0
           "read(%s) failed: %s",
860
0
           i_stream_get_name(file->pending_read_input),
861
0
           i_stream_get_error(file->pending_read_input));
862
0
  } else {
863
0
    ret = I_MIN(size, data_size);
864
0
    if (ret > 0)
865
0
      memcpy(buf, data, ret);
866
0
  }
867
0
  i_stream_unref(&file->pending_read_input);
868
0
  return ret;
869
0
}
870
871
ssize_t fs_read(struct fs_file *file, void *buf, size_t size)
872
0
{
873
0
  int ret;
874
875
0
  if (!file->read_or_prefetch_counted) {
876
0
    file->read_or_prefetch_counted = TRUE;
877
0
    file->fs->stats.read_count++;
878
0
    fs_file_timing_start(file, FS_OP_READ);
879
0
  }
880
881
0
  if (file->fs->v.read != NULL) {
882
0
    T_BEGIN {
883
0
      ret = file->fs->v.read(file, buf, size);
884
0
    } T_END;
885
0
    if (!(ret < 0 && errno == EAGAIN))
886
0
      fs_file_timing_end(file, FS_OP_READ);
887
0
    return ret;
888
0
  }
889
890
  /* backend didn't bother to implement read(), but we can do it with
891
     streams. */
892
0
  return fs_read_via_stream(file, buf, size);
893
0
}
894
895
static void fs_file_istream_destroyed(struct fs_file *file)
896
0
{
897
0
  i_assert(file->istream_open);
898
899
0
  file->istream_open = FALSE;
900
0
}
901
902
struct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
903
0
{
904
0
  struct istream *input, *inputs[2];
905
0
  const unsigned char *data;
906
0
  size_t size;
907
0
  ssize_t ret;
908
0
  bool want_seekable = FALSE;
909
910
0
  if (!file->read_or_prefetch_counted) {
911
0
    file->read_or_prefetch_counted = TRUE;
912
0
    file->fs->stats.read_count++;
913
0
    fs_file_timing_start(file, FS_OP_READ);
914
0
  }
915
916
0
  if (file->seekable_input != NULL) {
917
    /* allow multiple open streams, each in a different position */
918
0
    input = i_stream_create_limit(file->seekable_input, UOFF_T_MAX);
919
0
    i_stream_seek(input, 0);
920
0
    return input;
921
0
  }
922
0
  i_assert(!file->istream_open);
923
0
  T_BEGIN {
924
0
    input = file->fs->v.read_stream(file, max_buffer_size);
925
0
  } T_END;
926
0
  if (input->stream_errno != 0) {
927
    /* read failed already */
928
0
    fs_file_timing_end(file, FS_OP_READ);
929
0
    return input;
930
0
  }
931
0
  if (file->fs->enable_timing) {
932
0
    struct istream *input2 = i_stream_create_fs_stats(input, file);
933
934
0
    i_stream_unref(&input);
935
0
    input = input2;
936
0
  }
937
938
0
  if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
939
0
    want_seekable = TRUE;
940
0
  else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
941
0
    want_seekable = TRUE;
942
943
0
  if (want_seekable && !input->seekable) {
944
    /* need to make the stream seekable */
945
0
    inputs[0] = input;
946
0
    inputs[1] = NULL;
947
0
    input = i_stream_create_seekable_path(inputs, max_buffer_size,
948
0
            file->fs->temp_path_prefix);
949
0
    i_stream_set_name(input, i_stream_get_name(inputs[0]));
950
0
    i_stream_unref(&inputs[0]);
951
0
  }
952
0
  file->seekable_input = input;
953
0
  i_stream_ref(file->seekable_input);
954
955
0
  if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
956
    /* read the whole input stream before returning */
957
0
    while ((ret = i_stream_read_more(input, &data, &size)) >= 0) {
958
0
      i_stream_skip(input, size);
959
0
      if (ret == 0)
960
0
        fs_wait_async(file->fs);
961
0
    }
962
0
    i_stream_seek(input, 0);
963
0
  }
964
0
  file->istream_open = TRUE;
965
0
  i_stream_add_destroy_callback(input, fs_file_istream_destroyed, file);
966
0
  return input;
967
0
}
968
969
int fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
970
0
{
971
0
  struct ostream *output;
972
0
  ssize_t ret;
973
0
  int err;
974
975
0
  if (!file->write_pending) {
976
0
    output = fs_write_stream(file);
977
0
    if ((ret = o_stream_send(output, data, size)) < 0) {
978
0
      err = errno;
979
0
      fs_write_stream_abort_error(file, &output, "fs_write(%s) failed: %s",
980
0
                o_stream_get_name(output),
981
0
                o_stream_get_error(output));
982
0
      errno = err;
983
0
      return -1;
984
0
    }
985
0
    i_assert((size_t)ret == size);
986
0
    ret = fs_write_stream_finish(file, &output);
987
0
  } else {
988
0
    ret = fs_write_stream_finish_async(file);
989
0
  }
990
0
  if (ret == 0) {
991
0
    fs_file_set_error_async(file);
992
0
    file->write_pending = TRUE;
993
0
    return -1;
994
0
  }
995
0
  file->write_pending = FALSE;
996
0
  return ret < 0 ? -1 : 0;
997
0
}
998
999
int fs_write(struct fs_file *file, const void *data, size_t size)
1000
0
{
1001
0
  int ret;
1002
1003
0
  if (file->fs->v.write != NULL) {
1004
0
    fs_file_timing_start(file, FS_OP_WRITE);
1005
0
    T_BEGIN {
1006
0
      ret = file->fs->v.write(file, data, size);
1007
0
    } T_END;
1008
0
    if (!(ret < 0 && errno == EAGAIN)) {
1009
0
      file->fs->stats.write_count++;
1010
0
      file->fs->stats.write_bytes += size;
1011
0
      fs_file_timing_end(file, FS_OP_WRITE);
1012
0
    }
1013
0
    return ret;
1014
0
  }
1015
1016
  /* backend didn't bother to implement write(), but we can do it with
1017
     streams. */
1018
0
  return fs_write_via_stream(file, data, size);
1019
0
}
1020
1021
struct ostream *fs_write_stream(struct fs_file *file)
1022
0
{
1023
0
  i_assert(!file->writing_stream);
1024
0
  i_assert(file->output == NULL);
1025
1026
0
  file->writing_stream = TRUE;
1027
0
  file->fs->stats.write_count++;
1028
0
  T_BEGIN {
1029
0
    file->fs->v.write_stream(file);
1030
0
  } T_END;
1031
0
  i_assert(file->output != NULL);
1032
0
  o_stream_cork(file->output);
1033
0
  return file->output;
1034
0
}
1035
1036
static int fs_write_stream_finish_int(struct fs_file *file, bool success)
1037
0
{
1038
0
  int ret;
1039
1040
0
  i_assert(file->writing_stream);
1041
1042
0
  fs_file_timing_start(file, FS_OP_WRITE);
1043
0
  T_BEGIN {
1044
0
    ret = file->fs->v.write_stream_finish(file, success);
1045
0
  } T_END;
1046
0
  if (ret != 0) {
1047
0
    fs_file_timing_end(file, FS_OP_WRITE);
1048
0
    file->metadata_changed = FALSE;
1049
0
  } else {
1050
    /* write didn't finish yet. this shouldn't happen if we
1051
       indicated a failure. */
1052
0
    i_assert(success);
1053
0
  }
1054
0
  if (ret != 0) {
1055
0
    i_assert(file->output == NULL);
1056
0
    file->writing_stream = FALSE;
1057
0
  }
1058
0
  return ret;
1059
0
}
1060
1061
int fs_write_stream_finish(struct fs_file *file, struct ostream **output)
1062
0
{
1063
0
  bool success = TRUE;
1064
0
  int ret;
1065
1066
0
  i_assert(*output == file->output || *output == NULL);
1067
0
  i_assert(output != &file->output);
1068
1069
0
  *output = NULL;
1070
0
  if (file->output != NULL) {
1071
0
    o_stream_uncork(file->output);
1072
0
    if ((ret = o_stream_finish(file->output)) <= 0) {
1073
0
      i_assert(ret < 0);
1074
0
      fs_set_error(file->event, file->output->stream_errno,
1075
0
             "write(%s) failed: %s",
1076
0
             o_stream_get_name(file->output),
1077
0
             o_stream_get_error(file->output));
1078
0
      success = FALSE;
1079
0
    }
1080
0
    file->fs->stats.write_bytes += file->output->offset;
1081
0
  }
1082
0
  return fs_write_stream_finish_int(file, success);
1083
0
}
1084
1085
int fs_write_stream_finish_async(struct fs_file *file)
1086
0
{
1087
0
  return fs_write_stream_finish_int(file, TRUE);
1088
0
}
1089
1090
/* Accepts both a caller-owned pointer (e.g. &output where output is a local
1091
 * variable) and &file->output itself. */
1092
static void fs_write_stream_abort(struct fs_file *file, struct ostream **output)
1093
0
{
1094
0
  int ret;
1095
0
  bool is_file_output = (output == &file->output);
1096
1097
0
  i_assert(*output == file->output);
1098
0
  i_assert(file->output != NULL);
1099
1100
0
  if (!is_file_output)
1101
0
    *output = NULL;
1102
1103
0
  o_stream_abort(file->output);
1104
  /* make sure we don't have an old error lying around */
1105
0
  ret = fs_write_stream_finish_int(file, FALSE);
1106
1107
0
  if (is_file_output)
1108
0
    *output = NULL;
1109
1110
0
  i_assert(ret != 0);
1111
0
}
1112
1113
void fs_write_stream_abort_error(struct fs_file *file, struct ostream **output, const char *error_fmt, ...)
1114
0
{
1115
0
  va_list args;
1116
0
  va_start(args, error_fmt);
1117
0
  fs_set_verror(file->event, error_fmt, args);
1118
  /* the error shouldn't be automatically logged if
1119
     fs_file_last_error() is no longer used */
1120
0
  fs_file_get_error_file(file)->last_error_changed = FALSE;
1121
0
  fs_write_stream_abort(file, output);
1122
0
  va_end(args);
1123
0
}
1124
1125
void fs_write_stream_abort_parent(struct fs_file *file, struct ostream **output)
1126
0
{
1127
0
  i_assert(file->parent != NULL);
1128
0
  i_assert(fs_file_last_error(file->parent) != NULL);
1129
0
  fs_write_stream_abort(file->parent, output);
1130
0
}
1131
1132
void fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
1133
           const void *digest)
1134
0
{
1135
0
  file->write_digest_method = method;
1136
1137
0
  i_free(file->write_digest);
1138
0
  file->write_digest = i_malloc(method->digest_size);
1139
0
  memcpy(file->write_digest, digest, method->digest_size);
1140
0
}
1141
1142
#undef fs_file_set_async_callback
1143
void fs_file_set_async_callback(struct fs_file *file,
1144
        fs_file_async_callback_t *callback,
1145
        void *context)
1146
0
{
1147
0
  if (file->fs->v.set_async_callback != NULL)
1148
0
    file->fs->v.set_async_callback(file, callback, context);
1149
0
  else
1150
0
    callback(context);
1151
0
}
1152
1153
void fs_wait_async(struct fs *fs)
1154
0
{
1155
  /* recursion not allowed */
1156
0
  i_assert(fs->prev_ioloop == NULL);
1157
1158
0
  if (fs->v.wait_async != NULL) T_BEGIN {
1159
0
    fs->prev_ioloop = current_ioloop;
1160
0
    fs->v.wait_async(fs);
1161
0
    i_assert(current_ioloop == fs->prev_ioloop);
1162
0
    fs->prev_ioloop = NULL;
1163
0
  } T_END;
1164
0
}
1165
1166
bool fs_switch_ioloop(struct fs *fs)
1167
0
{
1168
0
  bool ret = FALSE;
1169
1170
0
  if (fs->v.switch_ioloop != NULL) {
1171
0
    T_BEGIN {
1172
0
      ret = fs->v.switch_ioloop(fs);
1173
0
    } T_END;
1174
0
  } else if (fs->parent != NULL) {
1175
0
    ret = fs_switch_ioloop(fs->parent);
1176
0
  }
1177
0
  return ret;
1178
0
}
1179
1180
int fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
1181
0
{
1182
0
  int ret;
1183
1184
0
  T_BEGIN {
1185
0
    ret = file->fs->v.lock(file, secs, lock_r);
1186
0
  } T_END;
1187
0
  return ret;
1188
0
}
1189
1190
void fs_unlock(struct fs_lock **_lock)
1191
0
{
1192
0
  struct fs_lock *lock = *_lock;
1193
1194
0
  if (lock == NULL)
1195
0
    return;
1196
1197
0
  *_lock = NULL;
1198
0
  T_BEGIN {
1199
0
    lock->file->fs->v.unlock(lock);
1200
0
  } T_END;
1201
0
}
1202
1203
int fs_exists(struct fs_file *file)
1204
0
{
1205
0
  struct stat st;
1206
0
  int ret;
1207
1208
0
  if (file->fs->v.exists == NULL) {
1209
    /* fallback to stat() */
1210
0
    if (fs_stat(file, &st) == 0)
1211
0
      return 1;
1212
0
    else
1213
0
      return errno == ENOENT ? 0 : -1;
1214
0
  }
1215
0
  fs_file_timing_start(file, FS_OP_EXISTS);
1216
0
  T_BEGIN {
1217
0
    ret = file->fs->v.exists(file);
1218
0
  } T_END;
1219
0
  if (!(ret < 0 && errno == EAGAIN)) {
1220
0
    file->fs->stats.exists_count++;
1221
0
    fs_file_timing_end(file, FS_OP_EXISTS);
1222
0
  }
1223
0
  return ret;
1224
0
}
1225
1226
int fs_stat(struct fs_file *file, struct stat *st_r)
1227
0
{
1228
0
  int ret;
1229
1230
0
  if (file->fs->v.stat == NULL) {
1231
0
    fs_set_error(file->event, ENOTSUP, "fs_stat() not supported");
1232
0
    return -1;
1233
0
  }
1234
1235
0
  if (!file->read_or_prefetch_counted &&
1236
0
      !file->lookup_metadata_counted && !file->stat_counted) {
1237
0
    file->stat_counted = TRUE;
1238
0
    file->fs->stats.stat_count++;
1239
0
    fs_file_timing_start(file, FS_OP_STAT);
1240
0
  }
1241
0
  T_BEGIN {
1242
0
    ret = file->fs->v.stat(file, st_r);
1243
0
  } T_END;
1244
0
  if (!(ret < 0 && errno == EAGAIN))
1245
0
    fs_file_timing_end(file, FS_OP_STAT);
1246
0
  return ret;
1247
0
}
1248
1249
int fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r)
1250
0
{
1251
0
  int ret;
1252
1253
0
  if (file->fs->v.get_nlinks == NULL) {
1254
0
    struct stat st;
1255
1256
0
    if (fs_stat(file, &st) < 0)
1257
0
      return -1;
1258
0
    *nlinks_r = st.st_nlink;
1259
0
    return 0;
1260
0
  }
1261
1262
0
  if (!file->read_or_prefetch_counted &&
1263
0
      !file->lookup_metadata_counted && !file->stat_counted) {
1264
0
    file->stat_counted = TRUE;
1265
0
    file->fs->stats.stat_count++;
1266
0
    fs_file_timing_start(file, FS_OP_STAT);
1267
0
  }
1268
0
  T_BEGIN {
1269
0
    ret = file->fs->v.get_nlinks(file, nlinks_r);
1270
0
  } T_END;
1271
0
  if (!(ret < 0 && errno == EAGAIN))
1272
0
    fs_file_timing_end(file, FS_OP_STAT);
1273
0
  return ret;
1274
0
}
1275
1276
int fs_default_copy(struct fs_file *src, struct fs_file *dest)
1277
0
{
1278
0
  int tmp_errno;
1279
  /* we're going to be counting this as read+write, so don't update
1280
     copy_count */
1281
0
  dest->copy_counted = TRUE;
1282
1283
0
  if (dest->copy_src != NULL) {
1284
0
    i_assert(src == NULL || src == dest->copy_src);
1285
0
    if (dest->copy_output == NULL) {
1286
0
      i_assert(dest->copy_input == NULL);
1287
0
      if (fs_write_stream_finish_async(dest) <= 0)
1288
0
        return -1;
1289
0
      dest->copy_src = NULL;
1290
0
      return 0;
1291
0
    }
1292
0
  } else {
1293
0
    dest->copy_src = src;
1294
0
    dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
1295
0
    dest->copy_output = fs_write_stream(dest);
1296
0
  }
1297
0
  switch (o_stream_send_istream(dest->copy_output, dest->copy_input)) {
1298
0
  case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
1299
0
    break;
1300
0
  case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
1301
0
  case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
1302
0
    fs_file_set_error_async(dest);
1303
0
    return -1;
1304
0
  case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
1305
0
    fs_write_stream_abort_error(dest, &dest->copy_output,
1306
0
              "read(%s) failed: %s",
1307
0
              i_stream_get_name(dest->copy_input),
1308
0
              i_stream_get_error(dest->copy_input));
1309
0
    errno = dest->copy_input->stream_errno;
1310
0
    i_stream_unref(&dest->copy_input);
1311
0
    return -1;
1312
0
  case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
1313
    /* errno might not survive abort error */
1314
0
    tmp_errno = dest->copy_output->stream_errno;
1315
0
    fs_write_stream_abort_error(dest, &dest->copy_output,
1316
0
              "write(%s) failed: %s",
1317
0
              o_stream_get_name(dest->copy_output),
1318
0
              o_stream_get_error(dest->copy_output));
1319
0
    errno = tmp_errno;
1320
0
    i_stream_unref(&dest->copy_input);
1321
0
    return -1;
1322
0
  }
1323
0
  i_stream_unref(&dest->copy_input);
1324
0
  if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
1325
0
    return -1;
1326
0
  dest->copy_src = NULL;
1327
0
  return 0;
1328
0
}
1329
1330
int fs_copy(struct fs_file *src, struct fs_file *dest)
1331
0
{
1332
0
  int ret;
1333
1334
0
  i_assert(src->fs == dest->fs);
1335
1336
0
  if (src->fs->v.copy == NULL) {
1337
0
    fs_set_error(src->event, ENOTSUP, "fs_copy() not supported");
1338
0
    return -1;
1339
0
  }
1340
1341
0
  fs_file_timing_start(dest, FS_OP_COPY);
1342
0
  T_BEGIN {
1343
0
    ret = src->fs->v.copy(src, dest);
1344
0
  } T_END;
1345
0
  if (!(ret < 0 && errno == EAGAIN)) {
1346
0
    fs_file_timing_end(dest, FS_OP_COPY);
1347
0
    if (dest->copy_counted)
1348
0
      dest->copy_counted = FALSE;
1349
0
    else
1350
0
      dest->fs->stats.copy_count++;
1351
0
    dest->metadata_changed = FALSE;
1352
0
  }
1353
0
  return ret;
1354
0
}
1355
1356
int fs_copy_finish_async(struct fs_file *dest)
1357
0
{
1358
0
  int ret;
1359
1360
0
  T_BEGIN {
1361
0
    ret = dest->fs->v.copy(NULL, dest);
1362
0
  } T_END;
1363
0
  if (!(ret < 0 && errno == EAGAIN)) {
1364
0
    fs_file_timing_end(dest, FS_OP_COPY);
1365
0
    if (dest->copy_counted)
1366
0
      dest->copy_counted = FALSE;
1367
0
    else
1368
0
      dest->fs->stats.copy_count++;
1369
0
    dest->metadata_changed = FALSE;
1370
0
  }
1371
0
  return ret;
1372
0
}
1373
1374
int fs_rename(struct fs_file *src, struct fs_file *dest)
1375
0
{
1376
0
  int ret;
1377
1378
0
  i_assert(src->fs == dest->fs);
1379
1380
0
  fs_file_timing_start(dest, FS_OP_RENAME);
1381
0
  T_BEGIN {
1382
0
    ret = src->fs->v.rename(src, dest);
1383
0
  } T_END;
1384
0
  if (!(ret < 0 && errno == EAGAIN)) {
1385
0
    dest->fs->stats.rename_count++;
1386
0
    fs_file_timing_end(dest, FS_OP_RENAME);
1387
0
  }
1388
0
  return ret;
1389
0
}
1390
1391
int fs_delete(struct fs_file *file)
1392
0
{
1393
0
  int ret;
1394
1395
0
  fs_file_timing_start(file, FS_OP_DELETE);
1396
0
  T_BEGIN {
1397
0
    ret = file->fs->v.delete_file(file);
1398
0
  } T_END;
1399
0
  if (!(ret < 0 && errno == EAGAIN)) {
1400
0
    file->fs->stats.delete_count++;
1401
0
    fs_file_timing_end(file, FS_OP_DELETE);
1402
0
  }
1403
0
  return ret;
1404
0
}
1405
1406
struct fs_iter *
1407
fs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
1408
0
{
1409
0
  return fs_iter_init_with_event(fs, fs->event, path, flags);
1410
0
}
1411
1412
struct fs_iter *
1413
fs_iter_init_with_event(struct fs *fs, struct event *event,
1414
      const char *path, enum fs_iter_flags flags)
1415
0
{
1416
0
  struct fs_iter *iter;
1417
0
  struct timeval now = ioloop_timeval;
1418
1419
0
  i_assert((flags & FS_ITER_FLAG_OBJECTIDS) == 0 ||
1420
0
     (fs_get_properties(fs) & FS_PROPERTY_OBJECTIDS) != 0);
1421
1422
0
  fs->stats.iter_count++;
1423
0
  if (fs->enable_timing)
1424
0
    i_gettimeofday(&now);
1425
0
  if (fs->v.iter_init == NULL)
1426
0
    iter = i_new(struct fs_iter, 1);
1427
0
  else
1428
0
    iter = fs->v.iter_alloc();
1429
0
  iter->fs = fs;
1430
0
  iter->event = fs_create_event(fs, event);
1431
0
  event_set_ptr(iter->event, FS_EVENT_FIELD_FS, fs);
1432
0
  event_set_ptr(iter->event, FS_EVENT_FIELD_ITER, iter);
1433
0
  if (fs->v.iter_init != NULL) T_BEGIN {
1434
0
    iter->flags = flags;
1435
0
    iter->path = i_strdup(path);
1436
0
    fs->v.iter_init(iter, path, flags);
1437
0
  } T_END;
1438
0
  iter->start_time = now;
1439
0
  DLLIST_PREPEND(&fs->iters, iter);
1440
0
  return iter;
1441
0
}
1442
1443
int fs_iter_deinit(struct fs_iter **_iter, const char **error_r)
1444
0
{
1445
0
  struct fs_iter *iter = *_iter;
1446
0
  struct fs *fs;
1447
0
  struct event *event;
1448
0
  int ret;
1449
1450
0
  if (iter == NULL)
1451
0
    return 0;
1452
1453
0
  fs = iter->fs;
1454
0
  event = iter->event;
1455
1456
0
  *_iter = NULL;
1457
0
  DLLIST_REMOVE(&fs->iters, iter);
1458
1459
0
  if (fs->v.iter_deinit == NULL) {
1460
0
    fs_set_error(event, ENOTSUP, "FS iteration not supported");
1461
0
    ret = -1;
1462
0
  } else T_BEGIN {
1463
0
    ret = iter->fs->v.iter_deinit(iter);
1464
0
  } T_END;
1465
0
  if (ret < 0)
1466
0
    *error_r = t_strdup(iter->last_error);
1467
0
  i_free(iter->last_error);
1468
0
  i_free(iter->path);
1469
0
  i_free(iter);
1470
0
  event_unref(&event);
1471
0
  return ret;
1472
0
}
1473
1474
const char *fs_iter_next(struct fs_iter *iter)
1475
0
{
1476
0
  const char *ret;
1477
1478
0
  if (iter->fs->v.iter_next == NULL)
1479
0
    return NULL;
1480
0
  T_BEGIN {
1481
0
    ret = iter->fs->v.iter_next(iter);
1482
0
  } T_END;
1483
0
  if (iter->start_time.tv_sec != 0 &&
1484
0
      (ret != NULL || !fs_iter_have_more(iter))) {
1485
    /* first result returned - count this as the finish time, since
1486
       we don't want to count the time caller spends on this
1487
       iteration. */
1488
0
    fs_timing_end(&iter->fs->stats.timings[FS_OP_ITER], &iter->start_time);
1489
    /* don't count this again */
1490
0
    iter->start_time.tv_sec = 0;
1491
0
  }
1492
0
  return ret;
1493
0
}
1494
1495
#undef fs_iter_set_async_callback
1496
void fs_iter_set_async_callback(struct fs_iter *iter,
1497
        fs_file_async_callback_t *callback,
1498
        void *context)
1499
0
{
1500
0
  iter->async_callback = callback;
1501
0
  iter->async_context = context;
1502
0
}
1503
1504
bool fs_iter_have_more(struct fs_iter *iter)
1505
0
{
1506
0
  return iter->async_have_more;
1507
0
}
1508
1509
const struct fs_stats *fs_get_stats(struct fs *fs)
1510
0
{
1511
0
  return &fs->stats;
1512
0
}
1513
1514
void fs_set_error(struct event *event, int err, const char *fmt, ...)
1515
0
{
1516
0
  va_list args;
1517
1518
0
  i_assert(err != 0);
1519
1520
0
  errno = err;
1521
0
  va_start(args, fmt);
1522
0
  fs_set_verror(event, fmt, args);
1523
0
  va_end(args);
1524
0
}
1525
1526
void fs_set_error_errno(struct event *event, const char *fmt, ...)
1527
0
{
1528
0
  va_list args;
1529
1530
0
  i_assert(errno != 0);
1531
1532
0
  va_start(args, fmt);
1533
0
  fs_set_verror(event, fmt, args);
1534
0
  va_end(args);
1535
0
}
1536
1537
void fs_file_set_error_async(struct fs_file *file)
1538
0
{
1539
0
  fs_set_error(file->event, EAGAIN, "Asynchronous operation in progress");
1540
0
}
1541
1542
static uint64_t
1543
fs_stats_count_ops(const struct fs_stats *stats, const enum fs_op ops[],
1544
       unsigned int ops_count)
1545
0
{
1546
0
  uint64_t ret = 0;
1547
1548
0
  for (unsigned int i = 0; i < ops_count; i++) {
1549
0
    if (stats->timings[ops[i]] != NULL)
1550
0
      ret += stats_dist_get_sum(stats->timings[ops[i]]);
1551
0
  }
1552
0
  return ret;
1553
0
}
1554
1555
uint64_t fs_stats_get_read_usecs(const struct fs_stats *stats)
1556
0
{
1557
0
  const enum fs_op read_ops[] = {
1558
0
    FS_OP_METADATA, FS_OP_PREFETCH, FS_OP_READ, FS_OP_EXISTS,
1559
0
    FS_OP_STAT, FS_OP_ITER
1560
0
  };
1561
0
  return fs_stats_count_ops(stats, read_ops, N_ELEMENTS(read_ops));
1562
0
}
1563
1564
uint64_t fs_stats_get_write_usecs(const struct fs_stats *stats)
1565
0
{
1566
0
  const enum fs_op write_ops[] = {
1567
0
    FS_OP_WRITE, FS_OP_COPY, FS_OP_DELETE
1568
0
  };
1569
0
  return fs_stats_count_ops(stats, write_ops, N_ELEMENTS(write_ops));
1570
0
}
1571
1572
struct fs_file *
1573
fs_file_init_parent(struct fs_file *parent, const char *path,
1574
        enum fs_open_mode mode, enum fs_open_flags flags)
1575
0
{
1576
0
  return fs_file_init_with_event(parent->fs->parent, parent->event,
1577
0
               path, (int)mode | (int)flags);
1578
0
}
1579
1580
struct fs_iter *
1581
fs_iter_init_parent(struct fs_iter *parent,
1582
        const char *path, enum fs_iter_flags flags)
1583
0
{
1584
0
  return fs_iter_init_with_event(parent->fs->parent, parent->event,
1585
0
               path, flags);
1586
0
}
1587
1588
struct event *fs_get_event(struct fs *fs)
1589
0
{
1590
0
  return fs->event;
1591
0
}