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

« back to all changes in this revision

Viewing changes to src/lib-storage/index/maildir/maildir-storage.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) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "ioloop.h"
17
17
 
18
18
#define MAILDIR_LIST_CONTEXT(obj) \
19
19
        MODULE_CONTEXT(obj, maildir_mailbox_list_module)
 
20
#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
20
21
 
21
22
struct maildir_mailbox_list_context {
22
23
        union mailbox_list_module_context module_ctx;
60
61
                /* put the temp files into tmp/ directory preferrably */
61
62
                storage->temp_prefix = p_strconcat(_storage->pool, "tmp/",
62
63
                                                   storage->temp_prefix, NULL);
63
 
                dir = mailbox_list_get_path(list, NULL,
64
 
                                            MAILBOX_LIST_PATH_TYPE_DIR);
 
64
                dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR);
65
65
        } else {
66
66
                /* control dir should also be writable */
67
 
                dir = mailbox_list_get_path(list, NULL,
68
 
                                            MAILBOX_LIST_PATH_TYPE_CONTROL);
 
67
                dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL);
69
68
        }
70
69
        _storage->temp_path_prefix = p_strconcat(_storage->pool, dir, "/",
71
70
                                                 storage->temp_prefix, NULL);
97
96
 
98
97
        /* we'll need to figure out the maildir location ourself.
99
98
           It's ~/Maildir unless we are chrooted. */
100
 
        if (mail_user_get_home(ns->owner, &home) > 0) {
 
99
        if (ns->owner != NULL &&
 
100
            mail_user_get_home(ns->owner, &home) > 0) {
101
101
                path = t_strconcat(home, "/Maildir", NULL);
102
102
                if (access(path, R_OK|W_OK|X_OK) == 0) {
103
103
                        if (debug)
155
155
}
156
156
 
157
157
static int
158
 
mkdir_verify(struct mail_storage *storage, struct mail_namespace *ns,
159
 
             const char *dir, mode_t mode, gid_t gid, const char *gid_origin,
160
 
             bool verify)
 
158
mkdir_verify(struct mailbox *box, const char *dir, bool verify)
161
159
{
 
160
        const struct mailbox_permissions *perm;
162
161
        struct stat st;
163
162
 
164
163
        if (verify) {
166
165
                        return 0;
167
166
 
168
167
                if (errno != ENOENT) {
169
 
                        mail_storage_set_critical(storage,
 
168
                        mail_storage_set_critical(box->storage,
170
169
                                                  "stat(%s) failed: %m", dir);
171
170
                        return -1;
172
171
                }
173
172
        }
174
173
 
175
 
        if (mkdir_parents_chgrp(dir, mode, gid, gid_origin) == 0)
 
174
        perm = mailbox_get_permissions(box);
 
175
        if (mkdir_parents_chgrp(dir, perm->dir_create_mode,
 
176
                                perm->file_create_gid,
 
177
                                perm->file_create_gid_origin) == 0)
176
178
                return 0;
177
179
 
178
180
        if (errno == EEXIST) {
179
181
                if (verify)
180
182
                        return 0;
181
 
                mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
 
183
                mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
182
184
                                       "Mailbox already exists");
183
185
        } else if (errno == ENOENT) {
184
 
                mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
 
186
                mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
185
187
                        "Mailbox was deleted while it was being created");
186
188
        } else if (errno == EACCES) {
187
 
                if (ns->type == NAMESPACE_SHARED) {
 
189
                if (box->list->ns->type == MAIL_NAMESPACE_TYPE_SHARED) {
188
190
                        /* shared namespace, don't log permission errors */
189
 
                        mail_storage_set_error(storage, MAIL_ERROR_PERM,
 
191
                        mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
190
192
                                               MAIL_ERRSTR_NO_PERMISSION);
191
193
                        return -1;
192
194
                }
193
 
                mail_storage_set_critical(storage, "%s",
 
195
                mail_storage_set_critical(box->storage, "%s",
194
196
                        mail_error_create_eacces_msg("mkdir", dir));
195
197
        } else {
196
 
                mail_storage_set_critical(storage,
 
198
                mail_storage_set_critical(box->storage,
197
199
                                          "mkdir(%s) failed: %m", dir);
198
200
        }
199
201
        return -1;
224
226
        } else if (st.st_atime > st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
225
227
                /* the directory should be empty. we won't do anything
226
228
                   until ctime changes. */
227
 
        } else if (st.st_atime < ioloop_time - interval) {
 
229
        } else if (st.st_atime < ioloop_time - (time_t)interval) {
228
230
                /* time to scan */
229
231
                (void)unlink_old_files(path, "",
230
232
                                       ioloop_time - MAILDIR_TMP_DELETE_SECS);
233
235
}
234
236
 
235
237
/* create or fix maildir, ignore if it already exists */
236
 
static int create_maildir(struct mailbox *box, bool verify)
 
238
static int create_maildir_subdirs(struct mailbox *box, bool verify)
237
239
{
238
 
        const struct mailbox_permissions *perm = mailbox_get_permissions(box);
239
 
        const char *path;
 
240
        const char *path, *box_path;
240
241
        unsigned int i;
241
242
        enum mail_error error;
242
243
        int ret = 0;
243
244
 
 
245
        if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
 
246
                                &box_path) < 0)
 
247
                return -1;
 
248
 
244
249
        for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
245
 
                path = t_strconcat(mailbox_get_path(box), "/",
246
 
                                   maildir_subdirs[i], NULL);
247
 
                if (mkdir_verify(box->storage, box->list->ns, path,
248
 
                                 perm->dir_create_mode, perm->file_create_gid,
249
 
                                 perm->file_create_gid_origin, verify) < 0) {
 
250
                path = t_strconcat(box_path, "/", maildir_subdirs[i], NULL);
 
251
                if (mkdir_verify(box, path, verify) < 0) {
250
252
                        error = mailbox_get_last_mail_error(box);
251
253
                        if (error != MAIL_ERROR_EXISTS)
252
254
                                return -1;
279
281
        mbox->box.mail_vfuncs = &maildir_mail_vfuncs;
280
282
        mbox->maildir_list_index_ext_id = (uint32_t)-1;
281
283
 
282
 
        index_storage_mailbox_alloc(&mbox->box, vname, flags,
283
 
                                    MAILDIR_INDEX_PREFIX);
 
284
        index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
284
285
 
285
286
        mbox->storage = (struct maildir_storage *)storage;
286
287
        return &mbox->box;
350
351
        if (ret < 0)
351
352
                return -1;
352
353
 
353
 
        /* tmp/ directory doesn't exist. does the maildir? */
354
 
        root_dir = mailbox_list_get_path(box->list, NULL,
355
 
                                         MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
354
        /* tmp/ directory doesn't exist. does the maildir? autocreate missing
 
355
           dirs only with Maildir++ and imapdir layouts. */
 
356
        if (strcmp(box->list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) != 0 &&
 
357
            strcmp(box->list->name, MAILBOX_LIST_NAME_IMAPDIR) != 0) {
 
358
                mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
 
359
                        T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
 
360
                return -1;
 
361
        }
 
362
        root_dir = mailbox_list_get_root_forced(box->list,
 
363
                                                MAILBOX_LIST_PATH_TYPE_MAILBOX);
356
364
        if (strcmp(box_path, root_dir) == 0) {
357
365
                /* root directory. either INBOX or some other namespace root */
358
366
                errno = ENOENT;
359
367
        } else if (stat(box_path, &st) == 0) {
360
368
                /* yes, we'll need to create the missing dirs */
361
 
                if (create_maildir(box, TRUE) < 0)
 
369
                if (create_maildir_subdirs(box, TRUE) < 0)
362
370
                        return -1;
363
371
 
364
372
                return maildir_mailbox_open_existing(box);
366
374
 
367
375
        if (errno == ENOENT || errno == ENAMETOOLONG) {
368
376
                mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
369
 
                        T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name));
 
377
                        T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
370
378
                return -1;
371
379
        } else {
372
380
                mail_storage_set_critical(box->storage,
380
388
        const struct mailbox_permissions *perm = mailbox_get_permissions(box);
381
389
        const char *path;
382
390
        mode_t old_mask;
383
 
        int fd;
 
391
        int fd, ret;
 
392
 
 
393
        ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
 
394
                                  &path);
 
395
        if (ret < 0)
 
396
                return -1;
 
397
        i_assert(ret > 0);
384
398
 
385
399
        old_mask = umask(0);
386
 
        path = t_strconcat(mailbox_get_path(box), "/dovecot-shared", NULL);
 
400
        path = t_strconcat(path, "/dovecot-shared", NULL);
387
401
        fd = open(path, O_WRONLY | O_CREAT, perm->file_create_mode);
388
402
        umask(old_mask);
389
403
 
404
418
                                "fchown(%s) failed: %m", path);
405
419
                }
406
420
        }
407
 
        (void)close(fd);
 
421
        i_close_fd(&fd);
408
422
        return 0;
409
423
}
410
424
 
413
427
{
414
428
        struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
415
429
        struct maildir_uidlist *uidlist;
416
 
        int ret;
 
430
        bool locked = FALSE;
 
431
        int ret = 0;
417
432
 
418
433
        if (!box->opened) {
419
434
                if (mailbox_open(box) < 0)
421
436
        }
422
437
        uidlist = mbox->uidlist;
423
438
 
424
 
        if (maildir_uidlist_lock(uidlist) <= 0)
425
 
                return -1;
 
439
        if (update->uid_validity != 0 || update->min_next_uid != 0 ||
 
440
            !guid_128_is_empty(update->mailbox_guid)) {
 
441
                if (maildir_uidlist_lock(uidlist) <= 0)
 
442
                        return -1;
426
443
 
427
 
        if (!guid_128_is_empty(update->mailbox_guid))
428
 
                maildir_uidlist_set_mailbox_guid(uidlist, update->mailbox_guid);
429
 
        if (update->uid_validity != 0)
430
 
                maildir_uidlist_set_uid_validity(uidlist, update->uid_validity);
431
 
        if (update->min_next_uid != 0) {
432
 
                maildir_uidlist_set_next_uid(uidlist, update->min_next_uid,
433
 
                                             FALSE);
 
444
                locked = TRUE;
 
445
                if (!guid_128_is_empty(update->mailbox_guid))
 
446
                        maildir_uidlist_set_mailbox_guid(uidlist, update->mailbox_guid);
 
447
                if (update->uid_validity != 0)
 
448
                        maildir_uidlist_set_uid_validity(uidlist, update->uid_validity);
 
449
                if (update->min_next_uid != 0) {
 
450
                        maildir_uidlist_set_next_uid(uidlist, update->min_next_uid,
 
451
                                                     FALSE);
 
452
                }
 
453
                ret = maildir_uidlist_update(uidlist);
434
454
        }
435
 
        ret = maildir_uidlist_update(uidlist);
436
455
        if (ret == 0)
437
456
                ret = index_storage_mailbox_update(box, update);
438
 
        maildir_uidlist_unlock(uidlist);
 
457
        if (locked)
 
458
                maildir_uidlist_unlock(uidlist);
439
459
        return ret;
440
460
}
441
461
 
 
462
static int maildir_create_maildirfolder_file(struct mailbox *box)
 
463
{
 
464
        const struct mailbox_permissions *perm;
 
465
        const char *path;
 
466
        mode_t old_mask;
 
467
        int fd;
 
468
 
 
469
        /* Maildir++ spec wants that maildirfolder named file is created for
 
470
           all subfolders. Do this only with Maildir++ layout. */
 
471
        if (strcmp(box->list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) != 0)
 
472
                return 0;
 
473
        perm = mailbox_get_permissions(box);
 
474
 
 
475
        path = t_strconcat(mailbox_get_path(box),
 
476
                           "/"MAILDIR_SUBFOLDER_FILENAME, NULL);
 
477
        old_mask = umask(0);
 
478
        fd = open(path, O_CREAT | O_WRONLY, perm->file_create_mode);
 
479
        umask(old_mask);
 
480
        if (fd != -1) {
 
481
                /* ok */
 
482
        } else if (errno == ENOENT) {
 
483
                mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
 
484
                        "Mailbox was deleted while it was being created");
 
485
                return -1;
 
486
        } else {
 
487
                mail_storage_set_critical(box->storage,
 
488
                        "open(%s, O_CREAT) failed: %m", path);
 
489
                return -1;
 
490
        }
 
491
 
 
492
        if (perm->file_create_gid != (gid_t)-1) {
 
493
                if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) {
 
494
                        /* ok */
 
495
                } else if (errno == EPERM) {
 
496
                        mail_storage_set_critical(box->storage, "%s",
 
497
                                eperm_error_get_chgrp("fchown", path,
 
498
                                                      perm->file_create_gid,
 
499
                                                      perm->file_create_gid_origin));
 
500
                } else {
 
501
                        mail_storage_set_critical(box->storage,
 
502
                                "fchown(%s) failed: %m", path);
 
503
                }
 
504
        }
 
505
        i_close_fd(&fd);
 
506
        return 0;
 
507
}
 
508
 
442
509
static int
443
510
maildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
444
511
                       bool directory)
447
514
        struct stat st;
448
515
        int ret;
449
516
 
450
 
        if (directory &&
451
 
            (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
452
 
                return 0;
453
 
 
454
 
        ret = maildir_check_tmp(box->storage, mailbox_get_path(box));
455
 
        if (ret > 0) {
456
 
                mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
457
 
                                       "Mailbox already exists");
458
 
                return -1;
459
 
        }
460
 
        if (ret < 0)
461
 
                return -1;
462
 
 
463
 
        if (create_maildir(box, FALSE) < 0)
464
 
                return -1;
465
 
 
 
517
        if ((ret = index_storage_mailbox_create(box, directory)) <= 0)
 
518
                return ret;
 
519
        ret = 0;
 
520
        /* the maildir is created now. finish the creation as best as we can */
 
521
        if (create_maildir_subdirs(box, FALSE) < 0)
 
522
                ret = -1;
 
523
        if (maildir_create_maildirfolder_file(box) < 0)
 
524
                ret = -1;
466
525
        /* if dovecot-shared exists in the root dir, copy it to newly
467
526
           created mailboxes */
468
 
        root_dir = mailbox_list_get_path(box->list, NULL,
469
 
                                         MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
527
        root_dir = mailbox_list_get_root_forced(box->list,
 
528
                                                MAILBOX_LIST_PATH_TYPE_MAILBOX);
470
529
        shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
471
530
        if (stat(shared_path, &st) == 0) {
472
531
                if (maildir_create_shared(box) < 0)
473
 
                        return -1;
474
 
        }
475
 
 
476
 
        return update == NULL ? 0 : maildir_mailbox_update(box, update);
 
532
                        ret = -1;
 
533
        }
 
534
        if (update != NULL) {
 
535
                if (maildir_mailbox_update(box, update) < 0)
 
536
                        ret = -1;
 
537
        }
 
538
        return ret;
477
539
}
478
540
 
479
541
static int
552
614
{
553
615
        const char *path;
554
616
 
555
 
        path = mailbox_list_get_path(list, NULL,
556
 
                                     MAILBOX_LIST_PATH_TYPE_CONTROL);
 
617
        path = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL);
557
618
        path = t_strconcat(path, "/"MAILDIR_UIDVALIDITY_FNAME, NULL);
558
619
        return mailbox_uidvalidity_next(list, path);
559
620
}
568
629
                return mbox->_private_flags_mask;
569
630
        mbox->private_flags_mask_set = TRUE;
570
631
 
571
 
        path = mailbox_list_get_path(box->list, NULL,
572
 
                                     MAILBOX_LIST_PATH_TYPE_MAILBOX);
573
 
        path2 = mailbox_list_get_path(box->list, NULL,
574
 
                                      MAILBOX_LIST_PATH_TYPE_INDEX);
575
 
        if (strcmp(path, path2) == 0) {
 
632
        path = mailbox_list_get_root_forced(box->list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
633
        if (box->list->set.index_pvt_dir != NULL) {
 
634
                /* private index directory is set. we'll definitely have
 
635
                   private flags. */
 
636
                mbox->_private_flags_mask = MAIL_SEEN;
 
637
        } else if (!mailbox_list_get_root_path(box->list,
 
638
                                               MAILBOX_LIST_PATH_TYPE_INDEX,
 
639
                                               &path2) ||
 
640
                   strcmp(path, path2) == 0) {
576
641
                /* no separate index directory. we can't have private flags,
577
642
                   so don't even bother checking if dovecot-shared exists */
578
643
        } else {
599
664
 
600
665
struct mail_storage maildir_storage = {
601
666
        .name = MAILDIR_STORAGE_NAME,
602
 
        .class_flags = MAIL_STORAGE_CLASS_FLAG_FILE_PER_MSG,
 
667
        .class_flags = MAIL_STORAGE_CLASS_FLAG_FILE_PER_MSG |
 
668
                MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS |
 
669
                MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_SAVE_GUIDS |
 
670
                MAIL_STORAGE_CLASS_FLAG_BINARY_DATA,
603
671
 
604
672
        .v = {
605
673
                maildir_get_setting_parser_info,
606
674
                maildir_storage_alloc,
607
675
                maildir_storage_create,
608
 
                NULL,
 
676
                index_storage_destroy,
609
677
                maildir_storage_add_list,
610
678
                maildir_storage_get_list_settings,
611
679
                maildir_storage_autodetect,
629
697
                index_storage_get_status,
630
698
                maildir_mailbox_get_metadata,
631
699
                index_storage_set_subscribed,
 
700
                index_storage_attribute_set,
 
701
                index_storage_attribute_get,
 
702
                index_storage_attribute_iter_init,
 
703
                index_storage_attribute_iter_next,
 
704
                index_storage_attribute_iter_deinit,
632
705
                maildir_list_index_has_changed,
633
706
                maildir_list_index_update_sync,
634
707
                maildir_storage_sync_init,