|
1 # HG changeset patch |
|
2 # Parent 5037ac63d7aece4b5e96e26bace1ab4b7e791804 |
|
3 |
|
4 diff -r 5037ac63d7ae Local/Makefile |
|
5 --- a/Local/Makefile Sat Feb 19 13:42:16 2011 +0100 |
|
6 +++ b/Local/Makefile Sun Feb 20 23:37:25 2011 +0100 |
|
7 @@ -1,4 +1,5 @@ |
|
8 # $Cambridge: exim/src/src/EDITME,v 1.27 2010/06/12 15:21:25 jetmore Exp $ |
|
9 +EXTRALIBS_EXIM=-lrt |
|
10 |
|
11 ################################################## |
|
12 # The Exim mail transport agent # |
|
13 diff -r 5037ac63d7ae src/transports/appendfile.c |
|
14 --- a/src/transports/appendfile.c Sat Feb 19 13:42:16 2011 +0100 |
|
15 +++ b/src/transports/appendfile.c Sun Feb 20 23:37:25 2011 +0100 |
|
16 @@ -13,6 +13,7 @@ |
|
17 |
|
18 #ifdef SUPPORT_MAILDIR |
|
19 #include "tf_maildir.h" |
|
20 +extern int lockfd; /* from tf_maildir */ // hs12 |
|
21 #endif |
|
22 |
|
23 |
|
24 @@ -278,8 +279,8 @@ |
|
25 gid = gid; |
|
26 |
|
27 if (ob->expand_maildir_use_size_file) |
|
28 - ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, |
|
29 - US"`maildir_use_size_file` in transport", tblock->name); |
|
30 + ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, |
|
31 + US"`maildir_use_size_file` in transport", tblock->name); |
|
32 |
|
33 /* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size, |
|
34 mailbox_filecount */ |
|
35 @@ -841,7 +842,7 @@ |
|
36 sigalrm_seen set if there has been a timeout |
|
37 */ |
|
38 |
|
39 -static int |
|
40 +int |
|
41 apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock, |
|
42 int flocktime) |
|
43 { |
|
44 @@ -887,7 +888,6 @@ |
|
45 |
|
46 |
|
47 |
|
48 - |
|
49 #ifdef SUPPORT_MBX |
|
50 /************************************************* |
|
51 * Copy message into MBX mailbox * |
|
52 @@ -2416,18 +2416,32 @@ |
|
53 { |
|
54 off_t size; |
|
55 int filecount; |
|
56 + uschar *excuse; |
|
57 + |
|
58 + struct timespec t0, t1; |
|
59 + clock_gettime(CLOCK_REALTIME, &t0); |
|
60 |
|
61 maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex, |
|
62 - &size, &filecount); |
|
63 + &size, &filecount, &excuse); |
|
64 |
|
65 if (maildirsize_fd == -1) |
|
66 { |
|
67 addr->basic_errno = errno; |
|
68 - addr->message = string_sprintf("while opening or reading " |
|
69 - "%s/maildirsize", check_path); |
|
70 + //addr->message = string_sprintf("%s", excuse); |
|
71 + addr->message = excuse; |
|
72 return FALSE; |
|
73 } |
|
74 |
|
75 + |
|
76 + clock_gettime(CLOCK_REALTIME, &t1); |
|
77 + t1.tv_sec -= t0.tv_sec; |
|
78 + t1.tv_nsec -= t0.tv_nsec; |
|
79 + if (t1.tv_nsec < 0) { t1.tv_sec--; t1.tv_nsec *= -1; } |
|
80 + DEBUG(D_transport) { |
|
81 + if (t1.tv_sec >= 1) debug_printf("%s/maildirsize was locked for %d.09ld seconds\n", |
|
82 + check_path, t1.tv_sec, t1.tv_nsec); |
|
83 + } |
|
84 + |
|
85 if (mailbox_size < 0) mailbox_size = size; |
|
86 if (mailbox_filecount < 0) mailbox_filecount = filecount; |
|
87 } |
|
88 @@ -3125,6 +3139,8 @@ |
|
89 uschar *renamename = newname; |
|
90 fd = -1; |
|
91 |
|
92 + if (lockfd >= 0) (void)apply_lock(lockfd, F_RDLCK, 1, 120, 0, 0); // hs12 |
|
93 + |
|
94 DEBUG(D_transport) debug_printf("renaming temporary file\n"); |
|
95 |
|
96 /* If there is no rename name set, we are in a non-maildir, non-mailstore |
|
97 @@ -3245,6 +3261,7 @@ |
|
98 filename = dataname = NULL; /* Prevents attempt to unlink at end */ |
|
99 } |
|
100 } /* maildir or mailstore */ |
|
101 + |
|
102 } /* successful write + close */ |
|
103 } /* isdirectory */ |
|
104 } /* write success */ |
|
105 @@ -3280,6 +3297,11 @@ |
|
106 detected, in order to get the file closed and the lock file tidied away. */ |
|
107 |
|
108 RETURN: |
|
109 +if (lockfd >= 0) |
|
110 + { |
|
111 + (void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0); // hs12 |
|
112 + (void)close(lockfd); |
|
113 + } |
|
114 |
|
115 #ifdef SUPPORT_MBX |
|
116 if (mbx_lockfd >= 0) |
|
117 diff -r 5037ac63d7ae src/transports/appendfile.h |
|
118 --- a/src/transports/appendfile.h Sat Feb 19 13:42:16 2011 +0100 |
|
119 +++ b/src/transports/appendfile.h Sun Feb 20 23:37:25 2011 +0100 |
|
120 @@ -95,5 +95,8 @@ |
|
121 /* Function that is shared with tf_maildir.c */ |
|
122 |
|
123 extern off_t check_dir_size(uschar *, int *, const pcre *); |
|
124 +extern int apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock, |
|
125 + int flocktime); |
|
126 + |
|
127 |
|
128 /* End of transports/appendfile.h */ |
|
129 diff -r 5037ac63d7ae src/transports/tf_maildir.c |
|
130 --- a/src/transports/tf_maildir.c Sat Feb 19 13:42:16 2011 +0100 |
|
131 +++ b/src/transports/tf_maildir.c Sun Feb 20 23:37:25 2011 +0100 |
|
132 @@ -367,13 +367,16 @@ |
|
133 |
|
134 Returns: >=0 a file descriptor for an open maildirsize file |
|
135 -1 there was an error opening or accessing the file |
|
136 + or locking |
|
137 -2 the file was removed because of a race |
|
138 */ |
|
139 |
|
140 +int lockfd = -1; // hs12 |
|
141 + |
|
142 int |
|
143 maildir_ensure_sizefile(uschar *path, appendfile_transport_options_block *ob, |
|
144 const pcre *regex, const pcre *dir_regex, off_t *returned_size, |
|
145 - int *returned_filecount) |
|
146 + int *returned_filecount, uschar **excuse) |
|
147 { |
|
148 int count, fd; |
|
149 off_t cached_quota = 0; |
|
150 @@ -381,25 +384,80 @@ |
|
151 int filecount = 0; |
|
152 int linecount = 0; |
|
153 off_t size = 0; |
|
154 -uschar *filename; |
|
155 +uschar *filename, *lockname, *hitchname; |
|
156 uschar buffer[MAX_FILE_SIZE]; |
|
157 uschar *ptr = buffer; |
|
158 uschar *endptr; |
|
159 |
|
160 +filename = string_sprintf("%s/maildirsize", path); |
|
161 +lockname = string_sprintf("%s.lock", filename); |
|
162 +hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname, |
|
163 + (unsigned int)(time(NULL)), (unsigned int)getpid()); |
|
164 + |
|
165 +/* Try to create a lock file. Here we should copy the loop from appendfile.c, |
|
166 +since our approach is quite simplified */ |
|
167 +lockfd = Uopen(lockname, O_CREAT|O_RDWR, ob->mode ? ob->mode : 0600); |
|
168 +if (lockfd < 0) |
|
169 + { |
|
170 + if (errno != ENOENT) |
|
171 + { |
|
172 + *excuse = string_sprintf("open %s", lockname); |
|
173 + return -1; |
|
174 + } |
|
175 + |
|
176 + lockfd = Uopen(hitchname, O_WRONLY|O_CREAT|O_EXCL, ob->mode ? ob->mode : 0600); |
|
177 + if (lockfd < 0) |
|
178 + { |
|
179 + *excuse = string_sprintf("open %s", hitchname); |
|
180 + return -1; |
|
181 + } |
|
182 + if (link(hitchname, lockname) < 0) |
|
183 + { |
|
184 + int save_errno = errno; |
|
185 + (void)unlink(hitchname); |
|
186 + errno = save_errno; |
|
187 + if (errno != EEXIST) |
|
188 + { |
|
189 + *excuse = string_sprintf("link %s -> %s", hitchname, lockname); |
|
190 + return -1; |
|
191 + } |
|
192 + (void)close(lockfd); |
|
193 + lockfd = Uopen(lockname, O_WRONLY, ob->mode ? ob->mode : 0600); |
|
194 + if (lockfd < 0) |
|
195 + { |
|
196 + *excuse = string_sprintf("open %s", lockname); |
|
197 + return -1; |
|
198 + } |
|
199 + } |
|
200 + (void)unlink(hitchname); |
|
201 + } |
|
202 + |
|
203 + |
|
204 +/* Before doing anything here we try to open and lock the maildirsize.lock |
|
205 +file. This should prevent/avoid races and parallel recalculations. We |
|
206 +need to do this on an extra lockfile, since the maildirsize file itself |
|
207 +gets renamed during the recalculation. */ |
|
208 + |
|
209 +if (lockfd >= 0) |
|
210 +(void)apply_lock(lockfd, F_WRLCK, 1, 120, 0, 0); // hs12 |
|
211 +if (sigalrm_seen) |
|
212 + { |
|
213 + *excuse = string_sprintf("timeout locking %s", lockname); |
|
214 + return -1; |
|
215 + } |
|
216 +DEBUG(D_transport) debug_printf("locked (WR) %s\n", lockname); |
|
217 + |
|
218 /* Try a few times to open or create the file, in case another process is doing |
|
219 the same thing. */ |
|
220 |
|
221 -filename = string_sprintf("%s/maildirsize", path); |
|
222 - |
|
223 DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path); |
|
224 fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600); |
|
225 -if (fd < 0) |
|
226 - { |
|
227 +if (fd < 0) { |
|
228 if (errno != ENOENT) return -1; |
|
229 DEBUG(D_transport) |
|
230 debug_printf("%s does not exist: recalculating\n", filename); |
|
231 goto RECALCULATE; |
|
232 - } |
|
233 +} |
|
234 |
|
235 /* The file has been successfully opened. Check that the cached quota value is |
|
236 still correct, and that the size of the file is still small enough. If so, |
|
237 @@ -588,8 +646,10 @@ |
|
238 } |
|
239 } |
|
240 |
|
241 + DEBUG(D_transport) debug_printf("releasing lock\n"); |
|
242 + (void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0); |
|
243 + |
|
244 /* Return the sizes and the file descriptor, if any */ |
|
245 - |
|
246 DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT |
|
247 " filecount=%d\n", size, filecount); |
|
248 *returned_size = size; |
|
249 diff -r 5037ac63d7ae src/transports/tf_maildir.h |
|
250 --- a/src/transports/tf_maildir.h Sat Feb 19 13:42:16 2011 +0100 |
|
251 +++ b/src/transports/tf_maildir.h Sun Feb 20 23:37:25 2011 +0100 |
|
252 @@ -16,7 +16,7 @@ |
|
253 uschar *); |
|
254 extern int maildir_ensure_sizefile(uschar *, |
|
255 appendfile_transport_options_block *, const pcre *, |
|
256 - const pcre *, off_t *, int *); |
|
257 + const pcre *, off_t *, int *, uschar **); |
|
258 extern void maildir_record_length(int, int); |
|
259 |
|
260 /* End of tf_maildir.h */ |