~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib-fs/fs-metawrap.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "str.h"
 
6
#include "strescape.h"
 
7
#include "istream.h"
 
8
#include "istream-private.h"
 
9
#include "istream-metawrap.h"
 
10
#include "ostream.h"
 
11
#include "ostream-metawrap.h"
 
12
#include "fs-api-private.h"
 
13
 
 
14
#define MAX_METADATA_LINE_LEN 8192
 
15
 
 
16
struct metawrap_fs {
 
17
        struct fs fs;
 
18
        bool wrap_metadata;
 
19
};
 
20
 
 
21
struct metawrap_fs_file {
 
22
        struct fs_file 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;
 
28
        bool metadata_read;
 
29
};
 
30
 
 
31
static struct fs *fs_metawrap_alloc(void)
 
32
{
 
33
        struct metawrap_fs *fs;
 
34
 
 
35
        fs = i_new(struct metawrap_fs, 1);
 
36
        fs->fs = fs_class_metawrap;
 
37
        return &fs->fs;
 
38
}
 
39
 
 
40
static int
 
41
fs_metawrap_init(struct fs *_fs, const char *args, const
 
42
                 struct fs_settings *set)
 
43
{
 
44
        struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
 
45
        const char *parent_name, *parent_args, *error;
 
46
 
 
47
        if (*args == '\0') {
 
48
                fs_set_error(_fs, "Parent filesystem not given as parameter");
 
49
                return -1;
 
50
        }
 
51
 
 
52
        parent_args = strchr(args, ':');
 
53
        if (parent_args == NULL) {
 
54
                parent_name = args;
 
55
                parent_args = "";
 
56
        } else {
 
57
                parent_name = t_strdup_until(args, parent_args);
 
58
                parent_args++;
 
59
        }
 
60
        if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
 
61
                fs_set_error(_fs, "%s: %s", parent_name, error);
 
62
                return -1;
 
63
        }
 
64
        if ((fs_get_properties(_fs->parent) & FS_PROPERTY_METADATA) == 0)
 
65
                fs->wrap_metadata = TRUE;
 
66
        return 0;
 
67
}
 
68
 
 
69
static void fs_metawrap_deinit(struct fs *_fs)
 
70
{
 
71
        struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
 
72
 
 
73
        if (_fs->parent != NULL)
 
74
                fs_deinit(&_fs->parent);
 
75
        i_free(fs);
 
76
}
 
77
 
 
78
static enum fs_properties fs_metawrap_get_properties(struct fs *_fs)
 
79
{
 
80
        const struct metawrap_fs *fs = (const struct metawrap_fs *)_fs;
 
81
        enum fs_properties props;
 
82
 
 
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;
 
88
        }
 
89
        return props;
 
90
}
 
91
 
 
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)
 
95
{
 
96
        struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
 
97
        struct metawrap_fs_file *file;
 
98
 
 
99
        file = i_new(struct metawrap_fs_file, 1);
 
100
        file->file.fs = _fs;
 
101
        file->file.path = i_strdup(path);
 
102
        file->fs = fs;
 
103
        file->open_mode = mode;
 
104
 
 
105
        /* avoid unnecessarily creating two seekable streams */
 
106
        flags &= ~FS_OPEN_FLAG_SEEKABLE;
 
107
 
 
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 |
 
114
                                                FS_OPEN_FLAG_ASYNC);
 
115
        } else {
 
116
                file->super_read = file->super;
 
117
        }
 
118
        fs_metadata_init(&file->file);
 
119
        return &file->file;
 
120
}
 
121
 
 
122
static void fs_metawrap_file_deinit(struct fs_file *_file)
 
123
{
 
124
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
125
 
 
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);
 
130
        i_free(file);
 
131
}
 
132
 
 
133
static void fs_metawrap_file_close(struct fs_file *_file)
 
134
{
 
135
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
136
 
 
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);
 
143
}
 
144
 
 
145
static const char *fs_metawrap_file_get_path(struct fs_file *_file)
 
146
{
 
147
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
148
 
 
149
        return fs_file_path(file->super);
 
150
}
 
151
 
 
152
static void
 
153
fs_metawrap_set_async_callback(struct fs_file *_file,
 
154
                               fs_file_async_callback_t *callback,
 
155
                               void *context)
 
156
{
 
157
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
158
 
 
159
        fs_file_set_async_callback(file->super, callback, context);
 
160
}
 
161
 
 
162
static int fs_metawrap_wait_async(struct fs *_fs)
 
163
{
 
164
        return fs_wait_async(_fs->parent);
 
165
}
 
166
 
 
167
static void
 
168
fs_metawrap_set_metadata(struct fs_file *_file, const char *key,
 
169
                         const char *value)
 
170
{
 
171
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
172
 
 
173
        if (!file->fs->wrap_metadata)
 
174
                fs_set_metadata(file->super, key, value);
 
175
        else
 
176
                fs_default_set_metadata(_file, key, value);
 
177
}
 
178
 
 
179
static int
 
180
fs_metawrap_get_metadata(struct fs_file *_file,
 
181
                         const ARRAY_TYPE(fs_metadata) **metadata_r)
 
182
{
 
183
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
184
        char c;
 
185
 
 
186
        if (!file->fs->wrap_metadata)
 
187
                return fs_get_metadata(file->super, metadata_r);
 
188
 
 
189
        if (!file->metadata_read) {
 
190
                if (fs_read(_file, &c, 1) < 0)
 
191
                        return -1;
 
192
        }
 
193
        *metadata_r = &_file->metadata;
 
194
        return 0;
 
195
}
 
196
 
 
197
static bool fs_metawrap_prefetch(struct fs_file *_file, uoff_t length)
 
198
{
 
199
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
200
 
 
201
        if (!file->fs->wrap_metadata)
 
202
                return fs_prefetch(file->super, length);
 
203
        else
 
204
                return fs_prefetch(file->super_read, length);
 
205
}
 
206
 
 
207
static ssize_t fs_metawrap_read(struct fs_file *_file, void *buf, size_t size)
 
208
{
 
209
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
210
 
 
211
        if (!file->fs->wrap_metadata)
 
212
                return fs_read(file->super, buf, size);
 
213
        return fs_read_via_stream(_file, buf, size);
 
214
}
 
215
 
 
216
static void
 
217
fs_metawrap_callback(const char *key, const char *value, void *context)
 
218
{
 
219
        struct metawrap_fs_file *file = context;
 
220
 
 
221
        if (key == NULL) {
 
222
                file->metadata_read = TRUE;
 
223
                return;
 
224
        }
 
225
 
 
226
        T_BEGIN {
 
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);
 
230
        } T_END;
 
231
}
 
232
 
 
233
static struct istream *
 
234
fs_metawrap_read_stream(struct fs_file *_file, size_t max_buffer_size)
 
235
{
 
236
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
237
        struct istream *input;
 
238
 
 
239
        if (!file->fs->wrap_metadata)
 
240
                return fs_read_stream(file->super, max_buffer_size);
 
241
 
 
242
        if (file->input != NULL) {
 
243
                i_stream_ref(file->input);
 
244
                i_stream_seek(file->input, 0);
 
245
                return file->input;
 
246
        }
 
247
 
 
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);
 
253
        return file->input;
 
254
}
 
255
 
 
256
static int fs_metawrap_write(struct fs_file *_file, const void *data, size_t size)
 
257
{
 
258
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
259
 
 
260
        if (!file->fs->wrap_metadata)
 
261
                return fs_write(file->super, data, size);
 
262
        return fs_write_via_stream(_file, data, size);
 
263
}
 
264
 
 
265
static void fs_metawrap_write_metadata(void *context)
 
266
{
 
267
        struct metawrap_fs_file *file = context;
 
268
        const struct fs_metadata *metadata;
 
269
        string_t *str = t_str_new(256);
 
270
        ssize_t ret;
 
271
 
 
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');
 
279
        }
 
280
        str_append_c(str, '\n');
 
281
        ret = o_stream_send(file->file.output, str_data(str), str_len(str));
 
282
        if (ret < 0)
 
283
                o_stream_close(file->file.output);
 
284
        else
 
285
                i_assert((size_t)ret == str_len(str));
 
286
}
 
287
 
 
288
static void fs_metawrap_write_stream(struct fs_file *_file)
 
289
{
 
290
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
291
 
 
292
        i_assert(_file->output == NULL);
 
293
 
 
294
        file->super_output = fs_write_stream(file->super);
 
295
        if (!file->fs->wrap_metadata)
 
296
                _file->output = file->super_output;
 
297
        else {
 
298
                _file->output = o_stream_create_metawrap(file->super_output,
 
299
                        fs_metawrap_write_metadata, file);
 
300
        }
 
301
}
 
302
 
 
303
static int fs_metawrap_write_stream_finish(struct fs_file *_file, bool success)
 
304
{
 
305
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
306
        int ret;
 
307
 
 
308
        if (_file->output != NULL) {
 
309
                if (_file->output->closed)
 
310
                        success = FALSE;
 
311
                if (_file->output == file->super_output)
 
312
                        _file->output = NULL;
 
313
                else
 
314
                        o_stream_unref(&_file->output);
 
315
        }
 
316
 
 
317
        if (!success) {
 
318
                fs_write_stream_abort(file->super, &file->super_output);
 
319
                ret = -1;
 
320
        } else {
 
321
                ret = fs_write_stream_finish(file->super, &file->super_output);
 
322
        }
 
323
        return ret;
 
324
}
 
325
 
 
326
static int
 
327
fs_metawrap_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
 
328
{
 
329
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
330
 
 
331
        return fs_lock(file->super, secs, lock_r);
 
332
}
 
333
 
 
334
static void fs_metawrap_unlock(struct fs_lock *_lock ATTR_UNUSED)
 
335
{
 
336
        i_unreached();
 
337
}
 
338
 
 
339
static int fs_metawrap_exists(struct fs_file *_file)
 
340
{
 
341
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
342
 
 
343
        return fs_exists(file->super);
 
344
}
 
345
 
 
346
static int fs_metawrap_stat(struct fs_file *_file, struct stat *st_r)
 
347
{
 
348
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
349
        struct istream *input;
 
350
        uoff_t input_size;
 
351
        ssize_t ret;
 
352
 
 
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);
 
360
                return -1;
 
361
        }
 
362
        i_stream_unref(&input);
 
363
        if (ret == 0) {
 
364
                fs_set_error_async(_file->fs);
 
365
                return -1;
 
366
        }
 
367
 
 
368
        if (fs_stat(file->super, st_r) < 0) {
 
369
                i_assert(errno != EAGAIN); /* read should have caught this */
 
370
                return -1;
 
371
        }
 
372
        st_r->st_size = input_size;
 
373
        return 0;
 
374
}
 
375
 
 
376
static int fs_metawrap_copy(struct fs_file *_src, struct fs_file *_dest)
 
377
{
 
378
        struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
 
379
        struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
 
380
 
 
381
        if (!dest->fs->wrap_metadata) {
 
382
                if (_src != NULL)
 
383
                        return fs_copy(src->super, dest->super);
 
384
                else
 
385
                        return fs_copy_finish_async(dest->super);
 
386
        }
 
387
        return fs_default_copy(_src, _dest);
 
388
}
 
389
 
 
390
static int fs_metawrap_rename(struct fs_file *_src, struct fs_file *_dest)
 
391
{
 
392
        struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
 
393
        struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
 
394
 
 
395
        return fs_rename(src->super, dest->super);
 
396
}
 
397
 
 
398
static int fs_metawrap_delete(struct fs_file *_file)
 
399
{
 
400
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
401
 
 
402
        return fs_delete(file->super);
 
403
}
 
404
 
 
405
static struct fs_iter *
 
406
fs_metawrap_iter_init(struct fs *_fs, const char *path,
 
407
                          enum fs_iter_flags flags)
 
408
{
 
409
        return fs_iter_init(_fs->parent, path, flags);
 
410
}
 
411
 
 
412
const struct fs fs_class_metawrap = {
 
413
        .name = "metawrap",
 
414
        .v = {
 
415
                fs_metawrap_alloc,
 
416
                fs_metawrap_init,
 
417
                fs_metawrap_deinit,
 
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,
 
428
                fs_metawrap_read,
 
429
                fs_metawrap_read_stream,
 
430
                fs_metawrap_write,
 
431
                fs_metawrap_write_stream,
 
432
                fs_metawrap_write_stream_finish,
 
433
                fs_metawrap_lock,
 
434
                fs_metawrap_unlock,
 
435
                fs_metawrap_exists,
 
436
                fs_metawrap_stat,
 
437
                fs_metawrap_copy,
 
438
                fs_metawrap_rename,
 
439
                fs_metawrap_delete,
 
440
                fs_metawrap_iter_init,
 
441
                NULL,
 
442
                NULL
 
443
        }
 
444
};