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)
30
32
i_assert(function != NULL);
32
if (errno == EACCES) {
33
35
mail_storage_set_error(storage, "Permission denied");
37
mail_storage_set_critical(storage,
38
"%s failed with subscription file %s: %m",
43
static int subscription_open(struct mail_storage *storage, int update,
48
*path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL);
50
fd = update ? open(*path, O_RDWR | O_CREAT, 0660) :
51
open(*path, O_RDONLY);
53
if (update || errno != ENOENT) {
54
subsfile_set_syscall_error(storage, "open()", *path);
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);
37
mail_storage_set_critical(storage,
38
"%s failed with subscription file %s: %m",
71
43
static const char *next_line(struct mail_storage *storage, const char *path,
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)
73
struct dotlock_settings dotlock_set;
74
struct dotlock *dotlock;
76
struct istream *input;
99
77
struct ostream *output;
102
fd = i_stream_get_fd(input);
105
output = o_stream_create_file(fd, default_pool, 4096, FALSE);
106
if (o_stream_seek(output, input->start_offset + input->v_offset) < 0) {
108
errno = output->stream_errno;
109
subsfile_set_syscall_error(storage, "o_stream_seek()", path);
111
i_stream_skip(input, count);
112
failed = o_stream_send_istream(output, input) < 0;
114
errno = output->stream_errno;
115
subsfile_set_syscall_error(storage,
116
"o_stream_send_istream()",
122
if (ftruncate(fd, output->offset) < 0) {
123
subsfile_set_syscall_error(storage, "ftruncate()",
129
o_stream_unref(output);
133
int subsfile_set_subscribed(struct mail_storage *storage,
134
const char *name, int set)
136
const char *path, *line;
137
struct istream *input;
78
int fd_in, fd_out, found, failed = FALSE;
141
80
if (strcasecmp(name, "INBOX") == 0)
144
fd = subscription_open(storage, TRUE, &path);
148
input = i_stream_create_file(fd, default_pool,
149
MAX_MAILBOX_LENGTH, FALSE);
151
offset = input->v_offset;
152
line = next_line(storage, path, input, &failed);
153
} while (line != NULL && strcmp(line, name) != 0);
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),
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))
170
i_stream_unref(input);
173
subsfile_set_syscall_error(storage, "close()", path);
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;
89
/* FIXME: set lock notification callback */
90
fd_out = file_dotlock_open(&dotlock_set, path, 0, &dotlock);
92
if (errno == EAGAIN) {
93
mail_storage_set_error(storage,
94
"Timeout waiting for subscription file lock");
96
subsfile_set_syscall_error(storage,
97
"file_dotlock_open()", path);
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);
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);
115
while ((line = next_line(storage, path, input, &failed)) != NULL) {
116
if (strcmp(line, name) == 0) {
122
if (o_stream_send_str(output, line) < 0 ||
123
o_stream_send(output, "\n", 1) < 0) {
124
subsfile_set_syscall_error(storage, "write()",
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);
141
i_stream_unref(input);
142
o_stream_unref(output);
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);
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);
159
return failed ? -1 : 0;
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)
182
165
struct subsfile_list_context *ctx;
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);
191
175
pool = pool_alloconly_create("subsfile_list", MAX_MAILBOX_LENGTH+1024);