implementation of mbox folder with unique messages numbers
[claws.git] / src / maillock.c
1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2002 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * $Id $
34  */
35
36 #include "maillock.h"
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <time.h>
45
46 /* ********************************************************************** */
47
48 /* lock primitives */
49
50 /* the lock code is modified from the dot lock file code from mail.local.c */
51
52 /*
53                              SENDMAIL LICENSE
54
55 The following license terms and conditions apply, unless a different
56 license is obtained from Sendmail, Inc., 6425 Christie Ave, Fourth Floor,
57 Emeryville, CA 94608, or by electronic mail at license@sendmail.com.
58
59 License Terms:
60
61 Use, Modification and Redistribution (including distribution of any
62 modified or derived work) in source and binary forms is permitted only if
63 each of the following conditions is met:
64
65 1. Redistributions qualify as "freeware" or "Open Source Software" under
66    one of the following terms:
67
68    (a) Redistributions are made at no charge beyond the reasonable cost of
69        materials and delivery.
70
71    (b) Redistributions are accompanied by a copy of the Source Code or by an
72        irrevocable offer to provide a copy of the Source Code for up to three
73        years at the cost of materials and delivery.  Such redistributions
74        must allow further use, modification, and redistribution of the Source
75        Code under substantially the same terms as this license.  For the
76        purposes of redistribution "Source Code" means the complete compilable
77        and linkable source code of sendmail including all modifications.
78
79 2. Redistributions of source code must retain the copyright notices as they
80    appear in each source code file, these license terms, and the
81    disclaimer/limitation of liability set forth as paragraph 6 below.
82
83 3. Redistributions in binary form must reproduce the Copyright Notice,
84    these license terms, and the disclaimer/limitation of liability set
85    forth as paragraph 6 below, in the documentation and/or other materials
86    provided with the distribution.  For the purposes of binary distribution
87    the "Copyright Notice" refers to the following language:
88    "Copyright (c) 1998-2002 Sendmail, Inc.  All rights reserved."
89
90 4. Neither the name of Sendmail, Inc. nor the University of California nor
91    the names of their contributors may be used to endorse or promote
92    products derived from this software without specific prior written
93    permission.  The name "sendmail" is a trademark of Sendmail, Inc.
94
95 5. All redistributions must comply with the conditions imposed by the
96    University of California on certain embedded code, whose copyright
97    notice and conditions for redistribution are as follows:
98
99    (a) Copyright (c) 1988, 1993 The Regents of the University of
100        California.  All rights reserved.
101
102    (b) Redistribution and use in source and binary forms, with or without
103        modification, are permitted provided that the following conditions
104        are met:
105
106       (i)   Redistributions of source code must retain the above copyright
107             notice, this list of conditions and the following disclaimer.
108
109       (ii)  Redistributions in binary form must reproduce the above
110             copyright notice, this list of conditions and the following
111             disclaimer in the documentation and/or other materials provided
112             with the distribution.
113
114       (iii) Neither the name of the University nor the names of its
115             contributors may be used to endorse or promote products derived
116             from this software without specific prior written permission.
117
118 6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY
119    SENDMAIL, INC. AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
120    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
121    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
122    NO EVENT SHALL SENDMAIL, INC., THE REGENTS OF THE UNIVERSITY OF
123    CALIFORNIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
124    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
125    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
126    USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
127    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
128    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
129    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
130 */
131
132 /*
133   TODO : lock, prefer fcntl() over flock()
134          AND use dotlock code above
135 */
136
137 #define LOCKTO_RM       300     /* timeout for stale lockfile removal */
138 #define LOCKTO_GLOB     400     /* global timeout for lockfile creation */
139
140 static int lock_common(char * filename, int fd, short locktype)
141 {
142   char lockfilename[PATH_MAX];
143   struct flock lock;
144   /* dot lock file */
145   int statfailed = 0;
146   time_t start;
147   int r;
148   int res;
149
150   lock.l_start = 0;
151   lock.l_len = 0;
152   lock.l_pid = getpid();
153   lock.l_type = locktype;
154   lock.l_whence = SEEK_SET;
155
156   r = fcntl(fd, F_SETLKW, &lock);
157   if (r < 0) {
158     /* WARNING POSIX lock could not be applied */
159   }
160
161   /* dot lock file */
162
163   if (strlen(filename) + 6 > PATH_MAX) {
164     res = -1;
165     goto unlock;
166   }
167
168   snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
169
170   time(&start);
171   while (1) {
172     int fd;
173     struct stat st;
174     time_t now;
175     
176     /* global timeout */
177     time(&now);
178     if (now > start + LOCKTO_GLOB) {
179       res = -1;
180       goto unlock;
181     }
182
183     fd = open(lockfilename, O_WRONLY|O_EXCL|O_CREAT, 0);
184     if (fd >= 0) {
185       /* defeat lock checking programs which test pid */
186       write(fd, "0", 2);
187       close(fd);
188       break;
189     }
190
191     if (stat(lockfilename, &st) < 0) {
192       if (statfailed++ > 5) {
193         res = -1;
194         goto unlock;
195       }
196       continue;
197     }
198     statfailed = 0;
199     time(&now);
200
201     if (now < st.st_ctime + LOCKTO_RM)
202       continue;
203     
204     /* try to remove stale lockfile */
205     if (unlink(lockfilename) < 0) {
206       res = -1;
207       goto unlock;
208     }
209
210     sleep(5);
211   }
212
213   return 0;
214
215  unlock:
216   lock.l_start = 0;
217   lock.l_len = 0;
218   lock.l_pid = getpid();
219   lock.l_type = F_UNLCK;
220   lock.l_whence = SEEK_SET;
221
222   r = fcntl(fd, F_SETLK, &lock);
223   if (r < 0) {
224     /* WARNING POSIX lock could not be applied */
225   }
226  err:
227   return res;
228 }
229
230 static int unlock_common(char * filename, int fd)
231 {
232   char lockfilename[PATH_MAX];
233   struct flock lock;
234   int r;
235
236   if (strlen(filename) + 6 > PATH_MAX)
237     return -1;
238
239   snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
240
241   unlink(lockfilename);
242
243   lock.l_start = 0;
244   lock.l_len = 0;
245   lock.l_pid = getpid();
246   lock.l_type = F_UNLCK;
247   lock.l_whence = SEEK_SET;
248
249   r = fcntl(fd, F_SETLK, &lock);
250   if (r < 0) {
251     /* WARNING POSIX lock could not be applied */
252   }
253
254   return 0;
255 }
256
257 int maillock_read_lock(char * filename, int fd)
258 {
259   return lock_common(filename, fd, F_RDLCK);
260 }
261
262 int maillock_read_unlock(char * filename, int fd)
263 {
264   return unlock_common(filename, fd);
265 }
266
267 int maillock_write_lock(char * filename, int fd)
268 {
269   return lock_common(filename, fd, F_WRLCK);
270 }
271
272 int maillock_write_unlock(char * filename, int fd)
273 {
274   return unlock_common(filename, fd);
275 }