/src/dovecot/src/lib-fs/fs-sis-queue.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "istream.h" |
6 | | #include "ostream.h" |
7 | | #include "settings.h" |
8 | | #include "fs-sis-common.h" |
9 | | |
10 | | struct fs_sis_queue_settings { |
11 | | pool_t pool; |
12 | | const char *fs_sis_queue_path; |
13 | | }; |
14 | | |
15 | | struct sis_queue_fs { |
16 | | struct fs fs; |
17 | | char *queue_dir; |
18 | | }; |
19 | | |
20 | | struct sis_queue_fs_file { |
21 | | struct fs_file file; |
22 | | struct sis_queue_fs *fs; |
23 | | }; |
24 | | |
25 | 0 | #define SISQUEUE_FS(ptr) container_of((ptr), struct sis_queue_fs, fs) |
26 | 0 | #define SISQUEUE_FILE(ptr) container_of((ptr), struct sis_queue_fs_file, file) |
27 | | |
28 | | #undef DEF |
29 | | #define DEF(type, name) \ |
30 | | SETTING_DEFINE_STRUCT_##type(#name, name, struct fs_sis_queue_settings) |
31 | | static const struct setting_define fs_sis_queue_setting_defines[] = { |
32 | | DEF(STR, fs_sis_queue_path), |
33 | | |
34 | | SETTING_DEFINE_LIST_END |
35 | | }; |
36 | | static const struct fs_sis_queue_settings fs_sis_queue_default_settings = { |
37 | | .fs_sis_queue_path = "", |
38 | | }; |
39 | | |
40 | | const struct setting_parser_info fs_sis_queue_setting_parser_info = { |
41 | | .name = "fs_sis_queue", |
42 | | |
43 | | .defines = fs_sis_queue_setting_defines, |
44 | | .defaults = &fs_sis_queue_default_settings, |
45 | | |
46 | | .struct_size = sizeof(struct fs_sis_queue_settings), |
47 | | .pool_offset1 = 1 + offsetof(struct fs_sis_queue_settings, pool), |
48 | | }; |
49 | | |
50 | | static struct fs *fs_sis_queue_alloc(void) |
51 | 0 | { |
52 | 0 | struct sis_queue_fs *fs; |
53 | |
|
54 | 0 | fs = i_new(struct sis_queue_fs, 1); |
55 | 0 | fs->fs = fs_class_sis_queue; |
56 | 0 | return &fs->fs; |
57 | 0 | } |
58 | | |
59 | | static int |
60 | | fs_sis_queue_init(struct fs *_fs, const struct fs_parameters *params, |
61 | | const char **error_r) |
62 | 0 | { |
63 | 0 | struct sis_queue_fs *fs = SISQUEUE_FS(_fs); |
64 | 0 | const struct fs_sis_queue_settings *set; |
65 | |
|
66 | 0 | if (settings_get(_fs->event, &fs_sis_queue_setting_parser_info, 0, |
67 | 0 | &set, error_r) < 0) |
68 | 0 | return -1; |
69 | 0 | fs->queue_dir = i_strdup(set->fs_sis_queue_path); |
70 | 0 | settings_free(set); |
71 | |
|
72 | 0 | return fs_init_parent(_fs, params, error_r); |
73 | 0 | } |
74 | | |
75 | | static void fs_sis_queue_free(struct fs *_fs) |
76 | 0 | { |
77 | 0 | struct sis_queue_fs *fs = SISQUEUE_FS(_fs); |
78 | |
|
79 | 0 | i_free(fs->queue_dir); |
80 | 0 | i_free(fs); |
81 | 0 | } |
82 | | |
83 | | static struct fs_file *fs_sis_queue_file_alloc(void) |
84 | 0 | { |
85 | 0 | struct sis_queue_fs_file *file = i_new(struct sis_queue_fs_file, 1); |
86 | 0 | return &file->file; |
87 | 0 | } |
88 | | |
89 | | static void |
90 | | fs_sis_queue_file_init(struct fs_file *_file, const char *path, |
91 | | enum fs_open_mode mode, enum fs_open_flags flags) |
92 | 0 | { |
93 | 0 | struct sis_queue_fs_file *file = SISQUEUE_FILE(_file); |
94 | 0 | struct sis_queue_fs *fs = SISQUEUE_FS(_file->fs); |
95 | |
|
96 | 0 | file->file.path = i_strdup(path); |
97 | 0 | file->fs = fs; |
98 | |
|
99 | 0 | if (mode == FS_OPEN_MODE_APPEND) |
100 | 0 | fs_set_error(_file->event, ENOTSUP, "APPEND mode not supported"); |
101 | 0 | else |
102 | 0 | file->file.parent = fs_file_init_parent(_file, path, mode, flags); |
103 | 0 | } |
104 | | |
105 | | static void fs_sis_queue_file_deinit(struct fs_file *_file) |
106 | 0 | { |
107 | 0 | struct sis_queue_fs_file *file = SISQUEUE_FILE(_file); |
108 | |
|
109 | 0 | fs_file_free(_file); |
110 | 0 | i_free(file->file.path); |
111 | 0 | i_free(file); |
112 | 0 | } |
113 | | |
114 | | static void fs_sis_queue_add(struct sis_queue_fs_file *file) |
115 | 0 | { |
116 | 0 | struct sis_queue_fs *fs = SISQUEUE_FS(file->file.fs); |
117 | 0 | struct fs_file *queue_file; |
118 | 0 | const char *fname, *path, *queue_path; |
119 | |
|
120 | 0 | path = fs_file_path(&file->file); |
121 | 0 | fname = strrchr(path, '/'); |
122 | 0 | if (fname != NULL) |
123 | 0 | fname++; |
124 | 0 | else |
125 | 0 | fname = path; |
126 | |
|
127 | 0 | queue_path = t_strdup_printf("%s/%s", fs->queue_dir, fname); |
128 | 0 | queue_file = fs_file_init_parent(&file->file, queue_path, FS_OPEN_MODE_CREATE, 0); |
129 | 0 | if (fs_write(queue_file, "", 0) < 0 && errno != EEXIST) |
130 | 0 | e_error(file->file.event, "%s", fs_file_last_error(queue_file)); |
131 | 0 | fs_file_deinit(&queue_file); |
132 | 0 | } |
133 | | |
134 | | static int fs_sis_queue_write(struct fs_file *_file, const void *data, size_t size) |
135 | 0 | { |
136 | 0 | struct sis_queue_fs_file *file = SISQUEUE_FILE(_file); |
137 | |
|
138 | 0 | if (_file->parent == NULL) |
139 | 0 | return -1; |
140 | 0 | if (fs_write(_file->parent, data, size) < 0) |
141 | 0 | return -1; |
142 | 0 | T_BEGIN { |
143 | 0 | fs_sis_queue_add(file); |
144 | 0 | } T_END; |
145 | 0 | return 0; |
146 | 0 | } |
147 | | |
148 | | static void fs_sis_queue_write_stream(struct fs_file *_file) |
149 | 0 | { |
150 | 0 | i_assert(_file->output == NULL); |
151 | | |
152 | 0 | if (_file->parent == NULL) { |
153 | 0 | _file->output = o_stream_create_error_str(EINVAL, "%s", |
154 | 0 | fs_file_last_error(_file)); |
155 | 0 | } else { |
156 | 0 | _file->output = fs_write_stream(_file->parent); |
157 | 0 | } |
158 | 0 | o_stream_set_name(_file->output, _file->path); |
159 | 0 | } |
160 | | |
161 | | static int fs_sis_queue_write_stream_finish(struct fs_file *_file, bool success) |
162 | 0 | { |
163 | 0 | struct sis_queue_fs_file *file = SISQUEUE_FILE(_file); |
164 | |
|
165 | 0 | if (!success) { |
166 | 0 | if (_file->parent != NULL) |
167 | 0 | fs_write_stream_abort_parent(_file, &_file->output); |
168 | 0 | return -1; |
169 | 0 | } |
170 | | |
171 | 0 | if (fs_write_stream_finish(_file->parent, &_file->output) < 0) |
172 | 0 | return -1; |
173 | 0 | T_BEGIN { |
174 | 0 | fs_sis_queue_add(file); |
175 | 0 | } T_END; |
176 | 0 | return 1; |
177 | 0 | } |
178 | | |
179 | | static int fs_sis_queue_delete(struct fs_file *_file) |
180 | 0 | { |
181 | 0 | T_BEGIN { |
182 | 0 | fs_sis_try_unlink_hash_file(_file, _file->parent); |
183 | 0 | } T_END; |
184 | 0 | return fs_delete(_file->parent); |
185 | 0 | } |
186 | | |
187 | | const struct fs fs_class_sis_queue = { |
188 | | .name = "sis-queue", |
189 | | .v = { |
190 | | .alloc = fs_sis_queue_alloc, |
191 | | .init = fs_sis_queue_init, |
192 | | .deinit = NULL, |
193 | | .free = fs_sis_queue_free, |
194 | | .get_properties = fs_wrapper_get_properties, |
195 | | .file_alloc = fs_sis_queue_file_alloc, |
196 | | .file_init = fs_sis_queue_file_init, |
197 | | .file_deinit = fs_sis_queue_file_deinit, |
198 | | .file_close = fs_wrapper_file_close, |
199 | | .get_path = fs_wrapper_file_get_path, |
200 | | .set_async_callback = fs_wrapper_set_async_callback, |
201 | | .wait_async = fs_wrapper_wait_async, |
202 | | .set_metadata = fs_wrapper_set_metadata, |
203 | | .get_metadata = fs_wrapper_get_metadata, |
204 | | .prefetch = fs_wrapper_prefetch, |
205 | | .read = fs_wrapper_read, |
206 | | .read_stream = fs_wrapper_read_stream, |
207 | | .write = fs_sis_queue_write, |
208 | | .write_stream = fs_sis_queue_write_stream, |
209 | | .write_stream_finish = fs_sis_queue_write_stream_finish, |
210 | | .lock = fs_wrapper_lock, |
211 | | .unlock = fs_wrapper_unlock, |
212 | | .exists = fs_wrapper_exists, |
213 | | .stat = fs_wrapper_stat, |
214 | | .copy = fs_wrapper_copy, |
215 | | .rename = fs_wrapper_rename, |
216 | | .delete_file = fs_sis_queue_delete, |
217 | | .iter_alloc = fs_wrapper_iter_alloc, |
218 | | .iter_init = fs_wrapper_iter_init, |
219 | | .iter_next = NULL, |
220 | | .iter_deinit = NULL, |
221 | | .switch_ioloop = NULL, |
222 | | .get_nlinks = fs_wrapper_get_nlinks, |
223 | | } |
224 | | }; |