~ubuntu-branches/ubuntu/vivid/dovecot/vivid

« back to all changes in this revision

Viewing changes to src/lib-storage/subscription-file/subscription-file.c

  • Committer: Bazaar Package Importer
  • Author(s): Jaldhar H. Vyas
  • Date: 2005-11-05 23:19:19 UTC
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051105231919-ydujs4y7687fpor2
Tags: upstream-1.0.alpha4
ImportĀ upstreamĀ versionĀ 1.0.alpha4

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
#include "lib.h"
4
4
#include "istream.h"
5
5
#include "ostream.h"
6
 
#include "file-lock.h"
7
 
#include "write-full.h"
8
 
#include "mail-storage.h"
 
6
#include "file-dotlock.h"
 
7
#include "mail-storage-private.h"
9
8
#include "subscription-file.h"
10
9
 
11
10
#include <unistd.h>
12
11
#include <fcntl.h>
13
12
 
14
 
#define SUBSCRIPTION_FILE_NAME ".subscriptions"
15
13
#define MAX_MAILBOX_LENGTH PATH_MAX
16
14
 
 
15
#define SUBSCRIPTION_FILE_LOCK_TIMEOUT 120
 
16
#define SUBSCRIPTION_FILE_CHANGE_TIMEOUT 30
 
17
#define SUBSCRIPTION_FILE_IMMEDIATE_TIMEOUT (5*60)
 
18
 
17
19
struct subsfile_list_context {
18
20
        pool_t pool;
19
21
 
24
26
        int failed;
25
27
};
26
28
 
27
 
static int subsfile_set_syscall_error(struct mail_storage *storage,
28
 
                                      const char *path, const char *function)
 
29
static void subsfile_set_syscall_error(struct mail_storage *storage,
 
30
                                       const char *function, const char *path)
29
31
{
30
32
        i_assert(function != NULL);
31
33
 
32
 
        if (errno == EACCES) {
 
34
        if (errno == EACCES)
33
35
                mail_storage_set_error(storage, "Permission denied");
34
 
                return FALSE;
35
 
        }
36
 
 
37
 
        mail_storage_set_critical(storage,
38
 
                                  "%s failed with subscription file %s: %m",
39
 
                                  function, path);
40
 
        return FALSE;
41
 
}
42
 
 
43
 
static int subscription_open(struct mail_storage *storage, int update,
44
 
                             const char **path)
45
 
{
46
 
        int fd;
47
 
 
48
 
        *path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL);
49
 
 
50
 
        fd = update ? open(*path, O_RDWR | O_CREAT, 0660) :
51
 
                open(*path, O_RDONLY);
52
 
        if (fd == -1) {
53
 
                if (update || errno != ENOENT) {
54
 
                        subsfile_set_syscall_error(storage, "open()", *path);
55
 
                        return -1;
56
 
                }
57
 
 
58
 
                return -1;
59
 
        }
60
 
 
61
 
        /* FIXME: we should work without locking, rename() would be easiest
62
 
           but .lock would work too */
63
 
        if (file_wait_lock(fd, update ? F_WRLCK : F_RDLCK) <= 0) {
64
 
                subsfile_set_syscall_error(storage, "file_wait_lock()", *path);
65
 
                (void)close(fd);
66
 
                return -1;
67
 
        }
68
 
        return fd;
 
36
        else {
 
37
                mail_storage_set_critical(storage,
 
38
                        "%s failed with subscription file %s: %m",
 
39
                        function, path);
 
40
        }
69
41
}
70
42
 
71
43
static const char *next_line(struct mail_storage *storage, const char *path,
73
45
{
74
46
        const char *line;
75
47
 
 
48
        *failed = FALSE;
 
49
        if (input == NULL)
 
50
                return NULL;
 
51
 
76
52
        while ((line = i_stream_next_line(input)) == NULL) {
77
53
                switch (i_stream_read(input)) {
78
54
                case -1:
79
 
                        *failed = FALSE;
80
55
                        return NULL;
81
56
                case -2:
82
57
                        /* mailbox name too large */
89
64
                }
90
65
        }
91
66
 
92
 
        *failed = FALSE;
93
67
        return line;
94
68
}
95
69
 
96
 
static int stream_cut(struct mail_storage *storage, const char *path,
97
 
                      struct istream *input, uoff_t count)
 
70
int subsfile_set_subscribed(struct mail_storage *storage, const char *path,
 
71
                            const char *temp_prefix, const char *name, int set)
98
72
{
 
73
        struct dotlock_settings dotlock_set;
 
74
        struct dotlock *dotlock;
 
75
        const char *line;
 
76
        struct istream *input;
99
77
        struct ostream *output;
100
 
        int fd, failed;
101
 
 
102
 
        fd = i_stream_get_fd(input);
103
 
        i_assert(fd != -1);
104
 
 
105
 
        output = o_stream_create_file(fd, default_pool, 4096, FALSE);
106
 
        if (o_stream_seek(output, input->start_offset + input->v_offset) < 0) {
107
 
                failed = TRUE;
108
 
                errno = output->stream_errno;
109
 
                subsfile_set_syscall_error(storage, "o_stream_seek()", path);
110
 
        } else {
111
 
                i_stream_skip(input, count);
112
 
                failed = o_stream_send_istream(output, input) < 0;
113
 
                if (failed) {
114
 
                        errno = output->stream_errno;
115
 
                        subsfile_set_syscall_error(storage,
116
 
                                                   "o_stream_send_istream()",
117
 
                                                   path);
118
 
                }
119
 
        }
120
 
 
121
 
        if (!failed) {
122
 
                if (ftruncate(fd, output->offset) < 0) {
123
 
                        subsfile_set_syscall_error(storage, "ftruncate()",
124
 
                                                   path);
125
 
                        failed = TRUE;
126
 
                }
127
 
        }
128
 
 
129
 
        o_stream_unref(output);
130
 
        return !failed;
131
 
}
132
 
 
133
 
int subsfile_set_subscribed(struct mail_storage *storage,
134
 
                            const char *name, int set)
135
 
{
136
 
        const char *path, *line;
137
 
        struct istream *input;
138
 
        uoff_t offset;
139
 
        int fd, failed;
 
78
        int fd_in, fd_out, found, failed = FALSE;
140
79
 
141
80
        if (strcasecmp(name, "INBOX") == 0)
142
81
                name = "INBOX";
143
82
 
144
 
        fd = subscription_open(storage, TRUE, &path);
145
 
        if (fd == -1)
146
 
                return FALSE;
147
 
 
148
 
        input = i_stream_create_file(fd, default_pool,
149
 
                                     MAX_MAILBOX_LENGTH, FALSE);
150
 
        do {
151
 
                offset = input->v_offset;
152
 
                line = next_line(storage, path, input, &failed);
153
 
        } while (line != NULL && strcmp(line, name) != 0);
154
 
 
155
 
        if (!failed) {
156
 
                if (set && line == NULL) {
157
 
                        /* add subscription. we're at EOF so just write it */
158
 
                        lseek(fd, 0, SEEK_END);
159
 
                        write_full(fd, t_strconcat(name, "\n", NULL),
160
 
                                   strlen(name)+1);
161
 
                } else if (!set && line != NULL) {
162
 
                        /* remove subcription. */
163
 
                        uoff_t size = input->v_offset - offset;
164
 
                        i_stream_seek(input, offset);
165
 
                        if (!stream_cut(storage, path, input, size))
166
 
                                failed = TRUE;
167
 
                }
168
 
        }
169
 
 
170
 
        i_stream_unref(input);
171
 
 
172
 
        if (close(fd) < 0) {
173
 
                subsfile_set_syscall_error(storage, "close()", path);
174
 
                failed = TRUE;
175
 
        }
176
 
        return !failed;
 
83
        memset(&dotlock_set, 0, sizeof(dotlock_set));
 
84
        dotlock_set.temp_prefix = temp_prefix;
 
85
        dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT;
 
86
        dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT;
 
87
        dotlock_set.immediate_stale_timeout = SUBSCRIPTION_FILE_IMMEDIATE_TIMEOUT;
 
88
 
 
89
        /* FIXME: set lock notification callback */
 
90
        fd_out = file_dotlock_open(&dotlock_set, path, 0, &dotlock);
 
91
        if (fd_out == -1) {
 
92
                if (errno == EAGAIN) {
 
93
                        mail_storage_set_error(storage,
 
94
                                "Timeout waiting for subscription file lock");
 
95
                } else {
 
96
                        subsfile_set_syscall_error(storage,
 
97
                                                   "file_dotlock_open()", path);
 
98
                }
 
99
                return -1;
 
100
        }
 
101
 
 
102
        fd_in = open(path, O_RDONLY);
 
103
        if (fd_in == -1 && errno != ENOENT) {
 
104
                subsfile_set_syscall_error(storage, "open()", path);
 
105
                (void)file_dotlock_delete(&dotlock);
 
106
                return -1;
 
107
        }
 
108
 
 
109
        input = fd_in == -1 ? NULL :
 
110
                i_stream_create_file(fd_in, default_pool,
 
111
                                     MAX_MAILBOX_LENGTH, TRUE);
 
112
        output = o_stream_create_file(fd_out, default_pool,
 
113
                                      MAX_MAILBOX_LENGTH, FALSE);
 
114
        found = FALSE;
 
115
        while ((line = next_line(storage, path, input, &failed)) != NULL) {
 
116
                if (strcmp(line, name) == 0) {
 
117
                        found = TRUE;
 
118
                        if (!set)
 
119
                                continue;
 
120
                }
 
121
 
 
122
                if (o_stream_send_str(output, line) < 0 ||
 
123
                    o_stream_send(output, "\n", 1) < 0) {
 
124
                        subsfile_set_syscall_error(storage, "write()",
 
125
                                                   path);
 
126
                        failed = TRUE;
 
127
                        break;
 
128
                }
 
129
        }
 
130
 
 
131
        if (!failed && set && !found) {
 
132
                /* append subscription */
 
133
                line = t_strconcat(name, "\n", NULL);
 
134
                if (o_stream_send_str(output, line) < 0) {
 
135
                        subsfile_set_syscall_error(storage, "write()", path);
 
136
                        failed = TRUE;
 
137
                }
 
138
        }
 
139
 
 
140
        if (input != NULL)
 
141
                i_stream_unref(input);
 
142
        o_stream_unref(output);
 
143
 
 
144
        if (failed || (set && found) || (!set && !found)) {
 
145
                if (file_dotlock_delete(&dotlock) < 0) {
 
146
                        subsfile_set_syscall_error(storage,
 
147
                                "file_dotlock_delete()", path);
 
148
                        failed = TRUE;
 
149
                }
 
150
        } else {
 
151
                enum dotlock_replace_flags flags =
 
152
                        DOTLOCK_REPLACE_FLAG_VERIFY_OWNER;
 
153
                if (file_dotlock_replace(&dotlock, flags) < 0) {
 
154
                        subsfile_set_syscall_error(storage,
 
155
                                "file_dotlock_replace()", path);
 
156
                        failed = TRUE;
 
157
                }
 
158
        }
 
159
        return failed ? -1 : 0;
177
160
}
178
161
 
179
162
struct subsfile_list_context *
180
 
subsfile_list_init(struct mail_storage *storage)
 
163
subsfile_list_init(struct mail_storage *storage, const char *path)
181
164
{
182
165
        struct subsfile_list_context *ctx;
183
166
        pool_t pool;
184
 
        const char *path;
185
167
        int fd;
186
168
 
187
 
        fd = subscription_open(storage, FALSE, &path);
188
 
        if (fd == -1 && errno != ENOENT)
 
169
        fd = open(path, O_RDONLY);
 
170
        if (fd == -1 && errno != ENOENT) {
 
171
                subsfile_set_syscall_error(storage, "open()", path);
189
172
                return NULL;
 
173
        }
190
174
 
191
175
        pool = pool_alloconly_create("subsfile_list", MAX_MAILBOX_LENGTH+1024);
192
176
 
208
192
                i_stream_unref(ctx->input);
209
193
        pool_unref(ctx->pool);
210
194
 
211
 
        return !failed;
 
195
        return failed ? -1 : 0;
212
196
}
213
197
 
214
198
const char *subsfile_list_next(struct subsfile_list_context *ctx)