~ubuntu-branches/ubuntu/trusty/dovecot/trusty-updates

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (1.15.3) (96.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20140108093549-814nkqdcxfbvgktg
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) 2010-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2010-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "module-dir.h"
4
6
#include "str.h"
 
7
#include "hash-method.h"
 
8
#include "istream.h"
 
9
#include "istream-seekable.h"
 
10
#include "ostream.h"
5
11
#include "fs-api-private.h"
6
12
 
7
 
static struct fs *fs_classes[] = {
8
 
        &fs_class_posix,
9
 
        &fs_class_sis,
10
 
        &fs_class_sis_queue
11
 
};
 
13
static struct module *fs_modules = NULL;
 
14
static ARRAY(const struct fs *) fs_classes;
12
15
 
13
 
static struct fs *
 
16
static int
14
17
fs_alloc(const struct fs *fs_class, const char *args,
15
 
         const struct fs_settings *set)
 
18
         const struct fs_settings *set, struct fs **fs_r, const char **error_r)
16
19
{
17
20
        struct fs *fs;
 
21
        int ret;
18
22
 
19
 
        fs = fs_class->v.init(args, set);
 
23
        fs = fs_class->v.alloc();
20
24
        fs->last_error = str_new(default_pool, 64);
21
 
        return fs;
22
 
}
23
 
 
24
 
struct fs *fs_init(const char *driver, const char *args,
25
 
                   const struct fs_settings *set)
26
 
{
27
 
        unsigned int i;
28
 
 
29
 
        for (i = 0; i < N_ELEMENTS(fs_classes); i++) {
30
 
                if (strcmp(fs_classes[i]->name, driver) == 0)
31
 
                        return fs_alloc(fs_classes[i], args, set);
32
 
        }
33
 
        i_fatal("Unknown fs driver: %s", driver);
 
25
 
 
26
        T_BEGIN {
 
27
                ret = fs_class->v.init(fs, args, set);
 
28
        } T_END;
 
29
        if (ret < 0) {
 
30
                /* a bit kludgy way to allow data stack frame usage in normal
 
31
                   conditions but still be able to return error message from
 
32
                   data stack. */
 
33
                *error_r = t_strdup_printf("%s: %s", fs_class->name,
 
34
                                           fs_last_error(fs));
 
35
                fs_deinit(&fs);
 
36
                return -1;
 
37
        }
 
38
        *fs_r = fs;
 
39
        return 0;
 
40
}
 
41
 
 
42
static void fs_class_register(const struct fs *fs_class)
 
43
{
 
44
        array_append(&fs_classes, &fs_class, 1);
 
45
}
 
46
 
 
47
static void fs_classes_deinit(void)
 
48
{
 
49
        array_free(&fs_classes);
 
50
}
 
51
 
 
52
static void fs_classes_init(void)
 
53
{
 
54
        i_array_init(&fs_classes, 8);
 
55
        fs_class_register(&fs_class_posix);
 
56
        fs_class_register(&fs_class_metawrap);
 
57
        fs_class_register(&fs_class_sis);
 
58
        fs_class_register(&fs_class_sis_queue);
 
59
        lib_atexit(fs_classes_deinit);
 
60
}
 
61
 
 
62
static const struct fs *fs_class_find(const char *driver)
 
63
{
 
64
        const struct fs *const *classp;
 
65
 
 
66
        if (!array_is_created(&fs_classes))
 
67
                fs_classes_init();
 
68
 
 
69
        array_foreach(&fs_classes, classp) {
 
70
                if (strcmp((*classp)->name, driver) == 0)
 
71
                        return *classp;
 
72
        }
 
73
        return NULL;
 
74
}
 
75
 
 
76
static void fs_class_deinit_modules(void)
 
77
{
 
78
        module_dir_unload(&fs_modules);
 
79
}
 
80
 
 
81
static void fs_class_try_load_plugin(const char *driver)
 
82
{
 
83
        const char *module_name = t_strdup_printf("fs_%s", driver);
 
84
        struct module *module;
 
85
        struct module_dir_load_settings mod_set;
 
86
        const struct fs *fs_class;
 
87
 
 
88
        memset(&mod_set, 0, sizeof(mod_set));
 
89
        mod_set.abi_version = DOVECOT_ABI_VERSION;
 
90
        mod_set.ignore_missing = TRUE;
 
91
 
 
92
        fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
 
93
                                             module_name, &mod_set);
 
94
        module_dir_init(fs_modules);
 
95
 
 
96
        module = module_dir_find(fs_modules, module_name);
 
97
        fs_class = module == NULL ? NULL :
 
98
                module_get_symbol(module, t_strdup_printf("fs_class_%s", driver));
 
99
        if (fs_class != NULL)
 
100
                fs_class_register(fs_class);
 
101
 
 
102
        lib_atexit(fs_class_deinit_modules);
 
103
}
 
104
 
 
105
int fs_init(const char *driver, const char *args,
 
106
            const struct fs_settings *set,
 
107
            struct fs **fs_r, const char **error_r)
 
108
{
 
109
        const struct fs *fs_class;
 
110
        const char *temp_file_prefix;
 
111
 
 
112
        fs_class = fs_class_find(driver);
 
113
        if (fs_class == NULL) {
 
114
                T_BEGIN {
 
115
                        fs_class_try_load_plugin(driver);
 
116
                } T_END;
 
117
                fs_class = fs_class_find(driver);
 
118
        }
 
119
        if (fs_class == NULL) {
 
120
                *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
 
121
                return -1;
 
122
        }
 
123
        if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
 
124
                return -1;
 
125
 
 
126
        temp_file_prefix = set->temp_file_prefix != NULL ?
 
127
                set->temp_file_prefix : ".temp.dovecot";
 
128
        (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
 
129
                                                temp_file_prefix, NULL);
 
130
        return 0;
34
131
}
35
132
 
36
133
void fs_deinit(struct fs **_fs)
37
134
{
38
135
        struct fs *fs = *_fs;
 
136
        string_t *last_error = fs->last_error;
39
137
 
40
138
        *_fs = NULL;
41
139
 
44
142
                        fs->name, fs->files_open_count);
45
143
        }
46
144
 
47
 
        str_free(&fs->last_error);
 
145
        i_free(fs->temp_path_prefix);
48
146
        fs->v.deinit(fs);
49
 
}
50
 
 
51
 
int fs_open(struct fs *fs, const char *path, int mode_flags,
52
 
            struct fs_file **file_r)
53
 
{
54
 
        int ret;
 
147
        str_free(&last_error);
 
148
}
 
149
 
 
150
const char *fs_get_root_driver(struct fs *fs)
 
151
{
 
152
        while (fs->parent != NULL)
 
153
                fs = fs->parent;
 
154
        return fs->name;
 
155
}
 
156
 
 
157
struct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
 
158
{
 
159
        struct fs_file *file;
 
160
 
 
161
        i_assert(path != NULL);
 
162
        i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
 
163
                 (mode_flags & FS_OPEN_FLAG_ASYNC) != 0);
55
164
 
56
165
        T_BEGIN {
57
 
                ret = fs->v.open(fs, path, mode_flags & FS_OPEN_MODE_MASK,
58
 
                                 mode_flags & ~FS_OPEN_MODE_MASK, file_r);
 
166
                file = fs->v.file_init(fs, path, mode_flags & FS_OPEN_MODE_MASK,
 
167
                                       mode_flags & ~FS_OPEN_MODE_MASK);
59
168
        } T_END;
60
 
        if (ret == 0)
61
 
                fs->files_open_count++;
62
 
        return ret;
 
169
        file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
 
170
        fs->files_open_count++;
 
171
        return file;
63
172
}
64
173
 
65
 
void fs_close(struct fs_file **_file)
 
174
void fs_file_deinit(struct fs_file **_file)
66
175
{
67
176
        struct fs_file *file = *_file;
 
177
        pool_t metadata_pool = file->metadata_pool;
68
178
 
69
179
        i_assert(file->fs->files_open_count > 0);
70
180
 
71
181
        *_file = NULL;
72
182
 
 
183
        fs_file_close(file);
 
184
 
73
185
        file->fs->files_open_count--;
74
 
        file->fs->v.close(file);
 
186
        T_BEGIN {
 
187
                file->fs->v.file_deinit(file);
 
188
        } T_END;
 
189
 
 
190
        if (metadata_pool != NULL)
 
191
                pool_unref(&metadata_pool);
 
192
}
 
193
 
 
194
void fs_file_close(struct fs_file *file)
 
195
{
 
196
        if (file->pending_read_input != NULL)
 
197
                i_stream_unref(&file->pending_read_input);
 
198
        if (file->seekable_input != NULL)
 
199
                i_stream_unref(&file->seekable_input);
 
200
 
 
201
        if (file->copy_input != NULL) {
 
202
                i_stream_unref(&file->copy_input);
 
203
                (void)fs_write_stream_abort(file, &file->copy_output);
 
204
        }
 
205
        i_free_and_null(file->write_digest);
 
206
        if (file->fs->v.file_close != NULL) T_BEGIN {
 
207
                file->fs->v.file_close(file);
 
208
        } T_END;
 
209
}
 
210
 
 
211
enum fs_properties fs_get_properties(struct fs *fs)
 
212
{
 
213
        return fs->v.get_properties(fs);
 
214
}
 
215
 
 
216
void fs_metadata_init(struct fs_file *file)
 
217
{
 
218
        if (file->metadata_pool == NULL) {
 
219
                file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
 
220
                p_array_init(&file->metadata, file->metadata_pool, 8);
 
221
        }
 
222
}
 
223
 
 
224
void fs_default_set_metadata(struct fs_file *file,
 
225
                             const char *key, const char *value)
 
226
{
 
227
        struct fs_metadata *metadata;
 
228
 
 
229
        fs_metadata_init(file);
 
230
        metadata = array_append_space(&file->metadata);
 
231
        metadata->key = p_strdup(file->metadata_pool, key);
 
232
        metadata->value = p_strdup(file->metadata_pool, value);
 
233
}
 
234
 
 
235
void fs_set_metadata(struct fs_file *file, const char *key, const char *value)
 
236
{
 
237
        if (file->fs->v.set_metadata != NULL) T_BEGIN {
 
238
                file->fs->v.set_metadata(file, key, value);
 
239
        } T_END;
 
240
}
 
241
 
 
242
int fs_get_metadata(struct fs_file *file,
 
243
                    const ARRAY_TYPE(fs_metadata) **metadata_r)
 
244
{
 
245
        if (file->fs->v.get_metadata == NULL) {
 
246
                fs_set_error(file->fs, "Metadata not supported by backend");
 
247
                return -1;
 
248
        }
 
249
        return file->fs->v.get_metadata(file, metadata_r);
75
250
}
76
251
 
77
252
const char *fs_file_path(struct fs_file *file)
78
253
{
79
 
        return file->path;
 
254
        return file->fs->v.get_path == NULL ? file->path :
 
255
                file->fs->v.get_path(file);
 
256
}
 
257
 
 
258
struct fs *fs_file_fs(struct fs_file *file)
 
259
{
 
260
        return file->fs;
 
261
}
 
262
 
 
263
static void ATTR_FORMAT(2, 0)
 
264
fs_set_verror(struct fs *fs, const char *fmt, va_list args)
 
265
{
 
266
        /* the error is always kept in the parentmost fs */
 
267
        if (fs->parent != NULL)
 
268
                fs_set_verror(fs->parent, fmt, args);
 
269
        else {
 
270
                str_truncate(fs->last_error, 0);
 
271
                str_vprintfa(fs->last_error, fmt, args);
 
272
        }
80
273
}
81
274
 
82
275
const char *fs_last_error(struct fs *fs)
83
276
{
 
277
        /* the error is always kept in the parentmost fs */
 
278
        if (fs->parent != NULL)
 
279
                return fs_last_error(fs->parent);
 
280
 
84
281
        if (str_len(fs->last_error) == 0)
85
282
                return "BUG: Unknown fs error";
86
283
        return str_c(fs->last_error);
91
288
        return fs_last_error(file->fs);
92
289
}
93
290
 
 
291
bool fs_prefetch(struct fs_file *file, uoff_t length)
 
292
{
 
293
        bool ret;
 
294
 
 
295
        T_BEGIN {
 
296
                ret = file->fs->v.prefetch(file, length);
 
297
        } T_END;
 
298
        return ret;
 
299
}
 
300
 
 
301
ssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
 
302
{
 
303
        const unsigned char *data;
 
304
        size_t data_size;
 
305
        ssize_t ret;
 
306
 
 
307
        i_assert(size > 0);
 
308
 
 
309
        if (file->pending_read_input == NULL)
 
310
                file->pending_read_input = fs_read_stream(file, size+1);
 
311
        ret = i_stream_read_data(file->pending_read_input,
 
312
                                 &data, &data_size, size-1);
 
313
        if (ret == 0) {
 
314
                fs_set_error_async(file->fs);
 
315
                return -1;
 
316
        }
 
317
        if (ret < 0 && file->pending_read_input->stream_errno != 0) {
 
318
                fs_set_error(file->fs, "read(%s) failed: %m",
 
319
                             i_stream_get_name(file->pending_read_input));
 
320
        } else {
 
321
                ret = I_MIN(size, data_size);
 
322
                memcpy(buf, data, ret);
 
323
        }
 
324
        i_stream_unref(&file->pending_read_input);
 
325
        return ret;
 
326
}
 
327
 
94
328
ssize_t fs_read(struct fs_file *file, void *buf, size_t size)
95
329
{
96
 
        return file->fs->v.read(file, buf, size);
 
330
        int ret;
 
331
 
 
332
        if (file->fs->v.read != NULL) {
 
333
                T_BEGIN {
 
334
                        ret = file->fs->v.read(file, buf, size);
 
335
                } T_END;
 
336
                return ret;
 
337
        }
 
338
 
 
339
        /* backend didn't bother to implement read(), but we can do it with
 
340
           streams. */
 
341
        return fs_read_via_stream(file, buf, size);
97
342
}
98
343
 
99
344
struct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
100
345
{
101
 
        return file->fs->v.read_stream(file, max_buffer_size);
 
346
        struct istream *input, *inputs[2];
 
347
        const unsigned char *data;
 
348
        size_t size;
 
349
        ssize_t ret;
 
350
        bool want_seekable = FALSE;
 
351
 
 
352
        if (file->seekable_input != NULL) {
 
353
                i_stream_seek(file->seekable_input, 0);
 
354
                i_stream_ref(file->seekable_input);
 
355
                return file->seekable_input;
 
356
        }
 
357
        T_BEGIN {
 
358
                input = file->fs->v.read_stream(file, max_buffer_size);
 
359
        } T_END;
 
360
        if (input->stream_errno != 0) {
 
361
                /* read failed already */
 
362
                return input;
 
363
        }
 
364
 
 
365
        if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
 
366
                want_seekable = TRUE;
 
367
        else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
 
368
                want_seekable = TRUE;
 
369
 
 
370
        if (want_seekable && !input->seekable) {
 
371
                /* need to make the stream seekable */
 
372
                inputs[0] = input;
 
373
                inputs[1] = NULL;
 
374
                input = i_stream_create_seekable_path(inputs, max_buffer_size,
 
375
                                                file->fs->temp_path_prefix);
 
376
                i_stream_set_name(input, i_stream_get_name(inputs[0]));
 
377
                i_stream_unref(&inputs[0]);
 
378
 
 
379
                file->seekable_input = input;
 
380
                i_stream_ref(file->seekable_input);
 
381
        }
 
382
        if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
 
383
                /* read the whole input stream before returning */
 
384
                while ((ret = i_stream_read_data(input, &data, &size, 0)) >= 0) {
 
385
                        i_stream_skip(input, size);
 
386
                        if (ret == 0) {
 
387
                                if (fs_wait_async(file->fs) < 0) {
 
388
                                        input->stream_errno = errno;
 
389
                                        input->eof = TRUE;
 
390
                                        break;
 
391
                                }
 
392
                        }
 
393
                }
 
394
                i_stream_seek(input, 0);
 
395
        }
 
396
        return input;
 
397
}
 
398
 
 
399
int fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
 
400
{
 
401
        struct ostream *output;
 
402
        ssize_t ret;
 
403
        int err;
 
404
 
 
405
        if (!file->write_pending) {
 
406
                output = fs_write_stream(file);
 
407
                if ((ret = o_stream_send(output, data, size)) < 0) {
 
408
                        err = errno;
 
409
                        fs_set_error(file->fs, "fs_write(%s) failed: %m",
 
410
                                     o_stream_get_name(output));
 
411
                        fs_write_stream_abort(file, &output);
 
412
                        errno = err;
 
413
                        return -1;
 
414
                }
 
415
                i_assert((size_t)ret == size);
 
416
                ret = fs_write_stream_finish(file, &output);
 
417
        } else {
 
418
                ret = fs_write_stream_finish_async(file);
 
419
        }
 
420
        if (ret == 0) {
 
421
                fs_set_error_async(file->fs);
 
422
                file->write_pending = TRUE;
 
423
                return -1;
 
424
        }
 
425
        file->write_pending = FALSE;
 
426
        return ret < 0 ? -1 : 0;
102
427
}
103
428
 
104
429
int fs_write(struct fs_file *file, const void *data, size_t size)
105
430
{
106
 
        return file->fs->v.write(file, data, size);
 
431
        int ret;
 
432
 
 
433
        if (file->fs->v.write != NULL) {
 
434
                T_BEGIN {
 
435
                        ret = file->fs->v.write(file, data, size);
 
436
                } T_END;
 
437
                return ret;
 
438
        }
 
439
 
 
440
        /* backend didn't bother to implement write(), but we can do it with
 
441
           streams. */
 
442
        return fs_write_via_stream(file, data, size);
107
443
}
108
444
 
109
445
struct ostream *fs_write_stream(struct fs_file *file)
110
446
{
111
 
        file->fs->v.write_stream(file);
 
447
        T_BEGIN {
 
448
                file->fs->v.write_stream(file);
 
449
        } T_END;
112
450
        i_assert(file->output != NULL);
113
451
        return file->output;
114
452
}
115
453
 
116
454
int fs_write_stream_finish(struct fs_file *file, struct ostream **output)
117
455
{
118
 
        i_assert(*output == file->output);
 
456
        int ret;
 
457
 
 
458
        i_assert(*output == file->output || *output == NULL);
119
459
 
120
460
        *output = NULL;
121
 
        return file->fs->v.write_stream_finish(file, TRUE);
 
461
        T_BEGIN {
 
462
                ret = file->fs->v.write_stream_finish(file, TRUE);
 
463
        } T_END;
 
464
        return ret;
 
465
}
 
466
 
 
467
int fs_write_stream_finish_async(struct fs_file *file)
 
468
{
 
469
        int ret;
 
470
 
 
471
        T_BEGIN {
 
472
                ret = file->fs->v.write_stream_finish(file, TRUE);
 
473
        } T_END;
 
474
        return ret;
122
475
}
123
476
 
124
477
void fs_write_stream_abort(struct fs_file *file, struct ostream **output)
126
479
        i_assert(*output == file->output);
127
480
 
128
481
        *output = NULL;
129
 
        (void)file->fs->v.write_stream_finish(file, FALSE);
 
482
        T_BEGIN {
 
483
                (void)file->fs->v.write_stream_finish(file, FALSE);
 
484
        } T_END;
 
485
}
 
486
 
 
487
void fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
 
488
                       const void *digest)
 
489
{
 
490
        file->write_digest_method = method;
 
491
 
 
492
        i_free(file->write_digest);
 
493
        file->write_digest = i_malloc(method->digest_size);
 
494
        memcpy(file->write_digest, digest, method->digest_size);
 
495
}
 
496
 
 
497
void fs_file_set_async_callback(struct fs_file *file,
 
498
                                fs_file_async_callback_t *callback,
 
499
                                void *context)
 
500
{
 
501
        if (file->fs->v.set_async_callback != NULL)
 
502
                file->fs->v.set_async_callback(file, callback, context);
 
503
        else
 
504
                callback(context);
 
505
}
 
506
 
 
507
int fs_wait_async(struct fs *fs)
 
508
{
 
509
        int ret;
 
510
 
 
511
        if (fs->v.wait_async == NULL)
 
512
                ret = 0;
 
513
        else T_BEGIN {
 
514
                ret = fs->v.wait_async(fs);
 
515
        } T_END;
 
516
        return ret;
130
517
}
131
518
 
132
519
int fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
133
520
{
134
 
        return file->fs->v.lock(file, secs, lock_r);
 
521
        int ret;
 
522
 
 
523
        T_BEGIN {
 
524
                ret = file->fs->v.lock(file, secs, lock_r);
 
525
        } T_END;
 
526
        return ret;
135
527
}
136
528
 
137
529
void fs_unlock(struct fs_lock **_lock)
139
531
        struct fs_lock *lock = *_lock;
140
532
 
141
533
        *_lock = NULL;
142
 
        lock->file->fs->v.unlock(lock);
143
 
}
144
 
 
145
 
int fs_fdatasync(struct fs_file *file)
146
 
{
147
 
        return file->fs->v.fdatasync(file);
148
 
}
149
 
 
150
 
int fs_exists(struct fs *fs, const char *path)
151
 
{
152
 
        return fs->v.exists(fs, path);
153
 
}
154
 
 
155
 
int fs_stat(struct fs *fs, const char *path, struct stat *st_r)
156
 
{
157
 
        return fs->v.stat(fs, path, st_r);
158
 
}
159
 
 
160
 
int fs_link(struct fs *fs, const char *src, const char *dest)
161
 
{
162
 
        return fs->v.link(fs, src, dest);
163
 
}
164
 
 
165
 
int fs_rename(struct fs *fs, const char *src, const char *dest)
166
 
{
167
 
        return fs->v.rename(fs, src, dest);
168
 
}
169
 
 
170
 
int fs_unlink(struct fs *fs, const char *path)
171
 
{
172
 
        return fs->v.unlink(fs, path);
173
 
}
174
 
 
175
 
int fs_rmdir(struct fs *fs, const char *path)
176
 
{
177
 
        return fs->v.rmdir(fs, path);
 
534
        T_BEGIN {
 
535
                lock->file->fs->v.unlock(lock);
 
536
        } T_END;
 
537
}
 
538
 
 
539
int fs_exists(struct fs_file *file)
 
540
{
 
541
        struct stat st;
 
542
        int ret;
 
543
 
 
544
        if (file->fs->v.exists == NULL) {
 
545
                /* fallback to stat() */
 
546
                if (fs_stat(file, &st) == 0)
 
547
                        return 1;
 
548
                else
 
549
                        return errno == ENOENT ? 0 : -1;
 
550
        }
 
551
        T_BEGIN {
 
552
                ret = file->fs->v.exists(file);
 
553
        } T_END;
 
554
        return ret;
 
555
}
 
556
 
 
557
int fs_stat(struct fs_file *file, struct stat *st_r)
 
558
{
 
559
        int ret;
 
560
 
 
561
        T_BEGIN {
 
562
                ret = file->fs->v.stat(file, st_r);
 
563
        } T_END;
 
564
        return ret;
 
565
}
 
566
 
 
567
int fs_default_copy(struct fs_file *src, struct fs_file *dest)
 
568
{
 
569
        if (dest->copy_src != NULL) {
 
570
                i_assert(src == NULL || src == dest->copy_src);
 
571
                if (dest->copy_output == NULL) {
 
572
                        i_assert(dest->copy_input == NULL);
 
573
                        if (fs_write_stream_finish_async(dest) <= 0)
 
574
                                return -1;
 
575
                        dest->copy_src = NULL;
 
576
                        return 0;
 
577
                }
 
578
        } else {
 
579
                dest->copy_src = src;
 
580
                dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
 
581
                dest->copy_output = fs_write_stream(dest);
 
582
        }
 
583
        while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
 
584
        if (dest->copy_input->stream_errno != 0) {
 
585
                errno = dest->copy_input->stream_errno;
 
586
                fs_set_error(dest->fs, "read(%s) failed: %m",
 
587
                             i_stream_get_name(dest->copy_input));
 
588
                i_stream_unref(&dest->copy_input);
 
589
                fs_write_stream_abort(dest, &dest->copy_output);
 
590
                return -1;
 
591
        }
 
592
        if (dest->copy_output->stream_errno != 0) {
 
593
                errno = dest->copy_output->stream_errno;
 
594
                fs_set_error(dest->fs, "write(%s) failed: %m",
 
595
                             o_stream_get_name(dest->copy_output));
 
596
                i_stream_unref(&dest->copy_input);
 
597
                fs_write_stream_abort(dest, &dest->copy_output);
 
598
                return -1;
 
599
        }
 
600
        if (!dest->copy_input->eof) {
 
601
                fs_set_error_async(dest->fs);
 
602
                return -1;
 
603
        }
 
604
        i_stream_unref(&dest->copy_input);
 
605
        if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
 
606
                return -1;
 
607
        dest->copy_src = NULL;
 
608
        return 0;
 
609
}
 
610
 
 
611
int fs_copy(struct fs_file *src, struct fs_file *dest)
 
612
{
 
613
        int ret;
 
614
 
 
615
        i_assert(src->fs == dest->fs);
 
616
 
 
617
        T_BEGIN {
 
618
                ret = src->fs->v.copy(src, dest);
 
619
        } T_END;
 
620
        return ret;
 
621
}
 
622
 
 
623
int fs_copy_finish_async(struct fs_file *dest)
 
624
{
 
625
        int ret;
 
626
 
 
627
        T_BEGIN {
 
628
                ret = dest->fs->v.copy(NULL, dest);
 
629
        } T_END;
 
630
        return ret;
 
631
}
 
632
 
 
633
int fs_rename(struct fs_file *src, struct fs_file *dest)
 
634
{
 
635
        int ret;
 
636
 
 
637
        i_assert(src->fs == dest->fs);
 
638
 
 
639
        T_BEGIN {
 
640
                ret = src->fs->v.rename(src, dest);
 
641
        } T_END;
 
642
        return ret;
 
643
}
 
644
 
 
645
int fs_delete(struct fs_file *file)
 
646
{
 
647
        int ret;
 
648
 
 
649
        T_BEGIN {
 
650
                ret = file->fs->v.delete_file(file);
 
651
        } T_END;
 
652
        return ret;
 
653
}
 
654
 
 
655
struct fs_iter *
 
656
fs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
 
657
{
 
658
        struct fs_iter *iter;
 
659
 
 
660
        T_BEGIN {
 
661
                iter = fs->v.iter_init(fs, path, flags);
 
662
        } T_END;
 
663
        return iter;
 
664
}
 
665
 
 
666
int fs_iter_deinit(struct fs_iter **_iter)
 
667
{
 
668
        struct fs_iter *iter = *_iter;
 
669
        int ret;
 
670
 
 
671
        *_iter = NULL;
 
672
        T_BEGIN {
 
673
                ret = iter->fs->v.iter_deinit(iter);
 
674
        } T_END;
 
675
        return ret;
 
676
}
 
677
 
 
678
const char *fs_iter_next(struct fs_iter *iter)
 
679
{
 
680
        return iter->fs->v.iter_next(iter);
 
681
}
 
682
 
 
683
void fs_iter_set_async_callback(struct fs_iter *iter,
 
684
                                fs_file_async_callback_t *callback,
 
685
                                void *context)
 
686
{
 
687
        iter->async_callback = callback;
 
688
        iter->async_context = context;
 
689
}
 
690
 
 
691
bool fs_iter_have_more(struct fs_iter *iter)
 
692
{
 
693
        return iter->async_have_more;
178
694
}
179
695
 
180
696
void fs_set_error(struct fs *fs, const char *fmt, ...)
182
698
        va_list args;
183
699
 
184
700
        va_start(args, fmt);
185
 
        str_truncate(fs->last_error, 0);
186
 
        str_vprintfa(fs->last_error, fmt, args);
 
701
        fs_set_verror(fs, fmt, args);
187
702
        va_end(args);
188
703
}
189
704
 
192
707
        va_list args;
193
708
 
194
709
        va_start(args, fmt);
195
 
        str_truncate(fs->last_error, 0);
196
 
        str_vprintfa(fs->last_error, fmt, args);
197
 
        i_error("fs-%s: %s", fs->name, str_c(fs->last_error));
 
710
        fs_set_verror(fs, fmt, args);
 
711
 
 
712
        i_error("fs-%s: %s", fs->name, fs_last_error(fs));
198
713
        va_end(args);
199
714
}
 
715
 
 
716
void fs_set_error_async(struct fs *fs)
 
717
{
 
718
        fs_set_error(fs, "Asynchronous operation in progress");
 
719
        errno = EAGAIN;
 
720
}