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