1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
8
#include "istream-private.h"
9
#include "istream-metawrap.h"
11
#include "ostream-metawrap.h"
12
#include "fs-api-private.h"
14
#define MAX_METADATA_LINE_LEN 8192
21
struct metawrap_fs_file {
23
struct metawrap_fs *fs;
24
struct fs_file *super, *super_read;
25
enum fs_open_mode open_mode;
26
struct istream *input;
27
struct ostream *super_output;
31
static struct fs *fs_metawrap_alloc(void)
33
struct metawrap_fs *fs;
35
fs = i_new(struct metawrap_fs, 1);
36
fs->fs = fs_class_metawrap;
41
fs_metawrap_init(struct fs *_fs, const char *args, const
42
struct fs_settings *set)
44
struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
45
const char *parent_name, *parent_args, *error;
48
fs_set_error(_fs, "Parent filesystem not given as parameter");
52
parent_args = strchr(args, ':');
53
if (parent_args == NULL) {
57
parent_name = t_strdup_until(args, parent_args);
60
if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
61
fs_set_error(_fs, "%s: %s", parent_name, error);
64
if ((fs_get_properties(_fs->parent) & FS_PROPERTY_METADATA) == 0)
65
fs->wrap_metadata = TRUE;
69
static void fs_metawrap_deinit(struct fs *_fs)
71
struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
73
if (_fs->parent != NULL)
74
fs_deinit(&_fs->parent);
78
static enum fs_properties fs_metawrap_get_properties(struct fs *_fs)
80
const struct metawrap_fs *fs = (const struct metawrap_fs *)_fs;
81
enum fs_properties props;
83
props = fs_get_properties(_fs->parent);
84
if (fs->wrap_metadata) {
85
/* we don't have a quick stat() to see the file's size,
86
because of the metadata header */
87
props &= ~FS_PROPERTY_STAT;
92
static struct fs_file *
93
fs_metawrap_file_init(struct fs *_fs, const char *path,
94
enum fs_open_mode mode, enum fs_open_flags flags)
96
struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
97
struct metawrap_fs_file *file;
99
file = i_new(struct metawrap_fs_file, 1);
101
file->file.path = i_strdup(path);
103
file->open_mode = mode;
105
/* avoid unnecessarily creating two seekable streams */
106
flags &= ~FS_OPEN_FLAG_SEEKABLE;
108
file->super = fs_file_init(_fs->parent, path, mode | flags);
109
if (file->fs->wrap_metadata && mode == FS_OPEN_MODE_READONLY &&
110
(flags & FS_OPEN_FLAG_ASYNC) == 0) {
111
/* use async stream for super, so fs_read_stream() won't create
112
another seekable stream unneededly */
113
file->super_read = fs_file_init(_fs->parent, path, mode | flags |
116
file->super_read = file->super;
118
fs_metadata_init(&file->file);
122
static void fs_metawrap_file_deinit(struct fs_file *_file)
124
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
126
if (file->super_read != file->super && file->super_read != NULL)
127
fs_file_deinit(&file->super_read);
128
fs_file_deinit(&file->super);
129
i_free(file->file.path);
133
static void fs_metawrap_file_close(struct fs_file *_file)
135
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
137
if (file->input != NULL)
138
i_stream_unref(&file->input);
139
if (file->super_read != NULL)
140
fs_file_close(file->super_read);
141
if (file->super != NULL)
142
fs_file_close(file->super);
145
static const char *fs_metawrap_file_get_path(struct fs_file *_file)
147
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
149
return fs_file_path(file->super);
153
fs_metawrap_set_async_callback(struct fs_file *_file,
154
fs_file_async_callback_t *callback,
157
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
159
fs_file_set_async_callback(file->super, callback, context);
162
static int fs_metawrap_wait_async(struct fs *_fs)
164
return fs_wait_async(_fs->parent);
168
fs_metawrap_set_metadata(struct fs_file *_file, const char *key,
171
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
173
if (!file->fs->wrap_metadata)
174
fs_set_metadata(file->super, key, value);
176
fs_default_set_metadata(_file, key, value);
180
fs_metawrap_get_metadata(struct fs_file *_file,
181
const ARRAY_TYPE(fs_metadata) **metadata_r)
183
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
186
if (!file->fs->wrap_metadata)
187
return fs_get_metadata(file->super, metadata_r);
189
if (!file->metadata_read) {
190
if (fs_read(_file, &c, 1) < 0)
193
*metadata_r = &_file->metadata;
197
static bool fs_metawrap_prefetch(struct fs_file *_file, uoff_t length)
199
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
201
if (!file->fs->wrap_metadata)
202
return fs_prefetch(file->super, length);
204
return fs_prefetch(file->super_read, length);
207
static ssize_t fs_metawrap_read(struct fs_file *_file, void *buf, size_t size)
209
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
211
if (!file->fs->wrap_metadata)
212
return fs_read(file->super, buf, size);
213
return fs_read_via_stream(_file, buf, size);
217
fs_metawrap_callback(const char *key, const char *value, void *context)
219
struct metawrap_fs_file *file = context;
222
file->metadata_read = TRUE;
227
key = str_tabunescape(t_strdup_noconst(key));
228
value = str_tabunescape(t_strdup_noconst(value));
229
fs_default_set_metadata(&file->file, key, value);
233
static struct istream *
234
fs_metawrap_read_stream(struct fs_file *_file, size_t max_buffer_size)
236
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
237
struct istream *input;
239
if (!file->fs->wrap_metadata)
240
return fs_read_stream(file->super, max_buffer_size);
242
if (file->input != NULL) {
243
i_stream_ref(file->input);
244
i_stream_seek(file->input, 0);
248
input = fs_read_stream(file->super_read,
249
I_MAX(max_buffer_size, MAX_METADATA_LINE_LEN));
250
file->input = i_stream_create_metawrap(input, fs_metawrap_callback, file);
251
i_stream_unref(&input);
252
i_stream_ref(file->input);
256
static int fs_metawrap_write(struct fs_file *_file, const void *data, size_t size)
258
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
260
if (!file->fs->wrap_metadata)
261
return fs_write(file->super, data, size);
262
return fs_write_via_stream(_file, data, size);
265
static void fs_metawrap_write_metadata(void *context)
267
struct metawrap_fs_file *file = context;
268
const struct fs_metadata *metadata;
269
string_t *str = t_str_new(256);
272
/* FIXME: if fs_set_metadata() is called later the changes are
273
ignored. we'd need to write via temporary file then. */
274
array_foreach(&file->file.metadata, metadata) {
275
str_append_tabescaped(str, metadata->key);
276
str_append_c(str, ':');
277
str_append_tabescaped(str, metadata->value);
278
str_append_c(str, '\n');
280
str_append_c(str, '\n');
281
ret = o_stream_send(file->file.output, str_data(str), str_len(str));
283
o_stream_close(file->file.output);
285
i_assert((size_t)ret == str_len(str));
288
static void fs_metawrap_write_stream(struct fs_file *_file)
290
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
292
i_assert(_file->output == NULL);
294
file->super_output = fs_write_stream(file->super);
295
if (!file->fs->wrap_metadata)
296
_file->output = file->super_output;
298
_file->output = o_stream_create_metawrap(file->super_output,
299
fs_metawrap_write_metadata, file);
303
static int fs_metawrap_write_stream_finish(struct fs_file *_file, bool success)
305
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
308
if (_file->output != NULL) {
309
if (_file->output->closed)
311
if (_file->output == file->super_output)
312
_file->output = NULL;
314
o_stream_unref(&_file->output);
318
fs_write_stream_abort(file->super, &file->super_output);
321
ret = fs_write_stream_finish(file->super, &file->super_output);
327
fs_metawrap_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
329
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
331
return fs_lock(file->super, secs, lock_r);
334
static void fs_metawrap_unlock(struct fs_lock *_lock ATTR_UNUSED)
339
static int fs_metawrap_exists(struct fs_file *_file)
341
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
343
return fs_exists(file->super);
346
static int fs_metawrap_stat(struct fs_file *_file, struct stat *st_r)
348
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
349
struct istream *input;
353
if (!file->fs->wrap_metadata)
354
return fs_stat(file->super, st_r);
355
input = fs_read_stream(_file, IO_BLOCK_SIZE);
356
if ((ret = i_stream_get_size(input, TRUE, &input_size)) < 0) {
357
fs_set_error(_file->fs, "i_stream_get_size(%s) failed: %m",
358
fs_file_path(_file));
359
i_stream_unref(&input);
362
i_stream_unref(&input);
364
fs_set_error_async(_file->fs);
368
if (fs_stat(file->super, st_r) < 0) {
369
i_assert(errno != EAGAIN); /* read should have caught this */
372
st_r->st_size = input_size;
376
static int fs_metawrap_copy(struct fs_file *_src, struct fs_file *_dest)
378
struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
379
struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
381
if (!dest->fs->wrap_metadata) {
383
return fs_copy(src->super, dest->super);
385
return fs_copy_finish_async(dest->super);
387
return fs_default_copy(_src, _dest);
390
static int fs_metawrap_rename(struct fs_file *_src, struct fs_file *_dest)
392
struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
393
struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
395
return fs_rename(src->super, dest->super);
398
static int fs_metawrap_delete(struct fs_file *_file)
400
struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
402
return fs_delete(file->super);
405
static struct fs_iter *
406
fs_metawrap_iter_init(struct fs *_fs, const char *path,
407
enum fs_iter_flags flags)
409
return fs_iter_init(_fs->parent, path, flags);
412
const struct fs fs_class_metawrap = {
418
fs_metawrap_get_properties,
419
fs_metawrap_file_init,
420
fs_metawrap_file_deinit,
421
fs_metawrap_file_close,
422
fs_metawrap_file_get_path,
423
fs_metawrap_set_async_callback,
424
fs_metawrap_wait_async,
425
fs_metawrap_set_metadata,
426
fs_metawrap_get_metadata,
427
fs_metawrap_prefetch,
429
fs_metawrap_read_stream,
431
fs_metawrap_write_stream,
432
fs_metawrap_write_stream_finish,
440
fs_metawrap_iter_init,