Mercurial > dovecot > core-2.2
annotate src/lib-storage/subscription-file/subscription-file.c @ 29:e9375147c0cb HEAD
Added write_full() which is a simple wrapper around write() meant for
writing into files.
When there's too much deleted data in index files, they're now compressed
when the index is being opened.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 26 Aug 2002 02:46:59 +0300 |
parents | 82b7de533f98 |
children | 4223b9ed0c80 |
rev | line source |
---|---|
0 | 1 /* Copyright (C) 2002 Timo Sirainen */ |
2 | |
3 /* ugly code here - text files are annoying to manage */ | |
4 | |
5 #include "lib.h" | |
6 #include "mmap-util.h" | |
29
e9375147c0cb
Added write_full() which is a simple wrapper around write() meant for
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
7 #include "write-full.h" |
0 | 8 #include "imap-match.h" |
9 #include "mail-storage.h" | |
10 #include "subscription-file.h" | |
11 | |
12 #include <unistd.h> | |
13 #include <fcntl.h> | |
14 | |
15 #define SUBSCRIPTION_FILE_NAME ".subscriptions" | |
16 | |
17 static int lock_file(int fd, int type) | |
18 { | |
19 struct flock fl; | |
20 | |
21 /* lock whole file */ | |
22 fl.l_type = type; | |
23 fl.l_whence = SEEK_SET; | |
24 fl.l_start = 0; | |
25 fl.l_len = 0; | |
26 | |
27 while (fcntl(fd, F_SETLKW, &fl) == -1) { | |
28 if (errno != EINTR) | |
29 return FALSE; | |
30 } | |
31 | |
32 return TRUE; | |
33 } | |
34 | |
35 static int subscription_open(MailStorage *storage, int update, | |
36 const char **path, void **mmap_base, | |
37 size_t *mmap_length) | |
38 { | |
39 int fd; | |
40 | |
41 *path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL); | |
42 | |
43 fd = update ? open(*path, O_RDWR | O_CREAT, 0660) : | |
44 open(*path, O_RDONLY); | |
45 if (fd == -1) { | |
46 if (update || errno != ENOENT) { | |
47 mail_storage_set_critical(storage, "Can't open " | |
48 "subscription file %s: %m", | |
49 *path); | |
50 } | |
51 return -1; | |
52 } | |
53 | |
54 if (!lock_file(fd, update ? F_WRLCK : F_RDLCK)) { | |
55 mail_storage_set_critical(storage, "fcntl() failed for " | |
56 "subscription file %s: %m", *path); | |
57 (void)close(fd); | |
58 return -1; | |
59 } | |
60 | |
61 *mmap_base = update ? mmap_rw_file(fd, mmap_length) : | |
62 mmap_ro_file(fd, mmap_length); | |
63 if (*mmap_base == MAP_FAILED) { | |
64 *mmap_base = NULL; | |
65 mail_storage_set_critical(storage, "mmap() failed for " | |
66 "subscription file %s: %m", *path); | |
67 (void)close(fd); | |
68 return -1; | |
69 } | |
70 | |
71 (void)madvise(*mmap_base, *mmap_length, MADV_SEQUENTIAL); | |
72 return fd; | |
73 } | |
74 | |
75 static int subscription_append(MailStorage *storage, int fd, const char *name, | |
76 unsigned int len, int prefix_lf, | |
77 const char *path) | |
78 { | |
79 char *buf; | |
80 | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
81 if (lseek(fd, 0, SEEK_END) == -1) { |
0 | 82 mail_storage_set_critical(storage, "lseek() failed for " |
83 "subscription file %s: %m", path); | |
84 return FALSE; | |
85 } | |
86 | |
87 buf = t_buffer_get(len+2); | |
88 buf[0] = '\n'; | |
89 memcpy(buf+1, name, len); | |
90 buf[len+1] = '\n'; | |
91 | |
92 if (prefix_lf) | |
93 len += 2; | |
94 else { | |
95 buf++; | |
96 len++; | |
97 } | |
98 | |
29
e9375147c0cb
Added write_full() which is a simple wrapper around write() meant for
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
99 if (write_full(fd, buf, len) < 0) { |
0 | 100 mail_storage_set_critical(storage, "write() failed for " |
101 "subscription file %s: %m", path); | |
102 return FALSE; | |
103 } | |
104 | |
105 return TRUE; | |
106 } | |
107 | |
108 int subsfile_set_subscribed(MailStorage *storage, const char *name, int set) | |
109 { | |
110 void *mmap_base; | |
111 size_t mmap_length; | |
112 const char *path; | |
113 char *subscriptions, *end, *p; | |
114 unsigned int namelen, afterlen, removelen; | |
115 int fd, failed, prefix_lf; | |
116 | |
117 if (strcasecmp(name, "INBOX") == 0) | |
118 name = "INBOX"; | |
119 | |
120 fd = subscription_open(storage, TRUE, &path, &mmap_base, &mmap_length); | |
121 if (fd == -1) | |
122 return FALSE; | |
123 | |
124 namelen = strlen(name); | |
125 | |
126 subscriptions = mmap_base; | |
127 if (subscriptions == NULL) | |
128 p = NULL; | |
129 else { | |
130 end = subscriptions + mmap_length; | |
131 for (p = subscriptions; p != end; p++) { | |
132 if (*p == *name && p+namelen <= end && | |
133 strncmp(p, name, namelen) == 0) { | |
134 /* make sure beginning and end matches too */ | |
135 if ((p == subscriptions || p[-1] == '\n') && | |
136 (p+namelen == end || p[namelen] == '\n')) | |
137 break; | |
138 } | |
139 } | |
140 | |
141 if (p == end) | |
142 p = NULL; | |
143 } | |
144 | |
145 failed = FALSE; | |
146 if (p != NULL && !set) { | |
147 /* remove it */ | |
148 afterlen = mmap_length - (unsigned int) (p - subscriptions); | |
149 removelen = namelen < afterlen ? namelen+1 : namelen; | |
150 | |
151 if (removelen < afterlen) | |
152 memmove(p, p+removelen, afterlen-removelen); | |
153 | |
154 if (ftruncate(fd, (off_t) (mmap_length - removelen)) == -1) { | |
155 mail_storage_set_critical(storage, "ftruncate() " | |
156 "failed for subscription " | |
157 "file %s: %m", path); | |
158 failed = TRUE; | |
159 } | |
160 } else if (p == NULL && set) { | |
161 /* append it */ | |
162 prefix_lf = mmap_length > 0 && | |
163 subscriptions[mmap_length-1] != '\n'; | |
164 if (!subscription_append(storage, fd, name, namelen, | |
165 prefix_lf, path)) | |
166 failed = TRUE; | |
167 } | |
168 | |
169 if (mmap_base != NULL && munmap(mmap_base, mmap_length) == -1) { | |
170 mail_storage_set_critical(storage, "munmap() failed for " | |
171 "subscription file %s: %m", path); | |
172 failed = TRUE; | |
173 } | |
174 | |
175 if (close(fd) == -1) { | |
176 mail_storage_set_critical(storage, "close() failed for " | |
177 "subscription file %s: %m", path); | |
178 failed = TRUE; | |
179 } | |
180 return !failed; | |
181 } | |
182 | |
183 int subsfile_foreach(MailStorage *storage, const char *mask, | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
5
diff
changeset
|
184 SubsFileForeachFunc func, void *context) |
0 | 185 { |
186 const ImapMatchGlob *glob; | |
187 const char *path, *start, *end, *p, *line; | |
188 void *mmap_base; | |
189 size_t mmap_length; | |
190 int fd, ret; | |
191 | |
192 fd = subscription_open(storage, FALSE, &path, &mmap_base, &mmap_length); | |
193 if (fd == -1) | |
194 return -1; | |
195 | |
196 glob = imap_match_init(mask, TRUE, storage->hierarchy_sep); | |
197 | |
198 start = mmap_base; end = start + mmap_length; ret = 1; | |
199 while (ret) { | |
200 t_push(); | |
201 | |
202 for (p = start; p != end; p++) { | |
203 if (*p == '\n') | |
204 break; | |
205 } | |
206 | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
207 line = t_strdup_until(start, p); |
0 | 208 if (line != NULL && *line != '\0' && |
209 imap_match(glob, line, 0, NULL) >= 0) | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
5
diff
changeset
|
210 ret = func(storage, line, context); |
0 | 211 t_pop(); |
212 | |
213 if (p == end) | |
214 break; | |
215 start = p+1; | |
216 } | |
217 | |
218 (void)close(fd); | |
219 return ret; | |
220 } |