]> git.notmuchmail.org Git - notmuch/blob - contrib/notmuch-deliver/src/maildircreate.c
74030f413c86b178412cba13eb4b05c06b28647c
[notmuch] / contrib / notmuch-deliver / src / maildircreate.c
1 /*
2 ** Copyright 1998 - 2003 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5
6 #include        "maildircreate.h"
7 #include        "maildirmisc.h"
8 #include        <sys/types.h>
9 #if     HAVE_SYS_STAT_H
10 #include        <sys/stat.h>
11 #endif
12
13 #if TIME_WITH_SYS_TIME
14 #include        <sys/time.h>
15 #include        <time.h>
16 #else
17 #if HAVE_SYS_TIME_H
18 #include        <sys/time.h>
19 #else
20 #include        <time.h>
21 #endif
22 #endif
23 #if     HAVE_SYS_STAT_H
24 #include        <sys/stat.h>
25 #endif
26
27 #if     HAVE_UNISTD_H
28 #include        <unistd.h>
29 #endif
30 #include        <string.h>
31 #include        <errno.h>
32 #include        <stdio.h>
33 #include        <stdlib.h>
34 #include        <fcntl.h>
35 #include        "numlib/numlib.h"
36
37
38 static const char rcsid[]="$Id: maildircreate.c,v 1.6 2003/01/26 04:07:03 mrsam Exp $";
39
40 FILE *maildir_tmpcreate_fp(struct maildir_tmpcreate_info *info)
41 {
42         int fd=maildir_tmpcreate_fd(info);
43         FILE *fp;
44
45         if (fd < 0)
46                 return NULL;
47
48         fp=fdopen(fd, "w+");
49
50         if (fp == NULL)
51         {
52                 close(fd);
53                 return NULL;
54         }
55
56         return fp;
57 }
58
59 static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info);
60
61 #define KEEPTRYING      (60 * 60)
62 #define SLEEPFOR        3
63
64 int maildir_tmpcreate_fd(struct maildir_tmpcreate_info *info)
65 {
66         int i;
67
68         if (!info->doordie)
69                 return (maildir_tmpcreate_fd_do(info));
70
71         for (i=0; i<KEEPTRYING / SLEEPFOR; i++)
72         {
73                 int fd=maildir_tmpcreate_fd_do(info);
74
75                 if (fd >= 0 || errno != EAGAIN)
76                         return fd;
77
78                 sleep(SLEEPFOR);
79         }
80
81         return -1;
82 }
83
84 static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info)
85 {
86         const char *maildir=info->maildir;
87         const char *uniq=info->uniq;
88         const char *hostname=info->hostname;
89
90         char hostname_buf[256];
91         char time_buf[NUMBUFSIZE];
92         char usec_buf[NUMBUFSIZE];
93         char pid_buf[NUMBUFSIZE];
94         char len_buf[NUMBUFSIZE+3];
95         char dev_buf[NUMBUFSIZE];
96         char ino_buf[NUMBUFSIZE];
97         struct timeval tv;
98
99         struct stat stat_buf;
100         int fd;
101
102         if (!maildir)
103                 maildir=".";
104         if (!uniq)
105                 uniq="";
106
107         if (!hostname || !*hostname)
108         {
109                 hostname_buf[sizeof(hostname_buf)-1]=0;
110                 if (gethostname(hostname_buf, sizeof(hostname_buf)-1) < 0)
111                         strcpy(hostname_buf, "localhost");
112                 hostname=hostname_buf;
113         }
114
115         gettimeofday(&tv, NULL);
116
117         libmail_str_time_t(tv.tv_sec, time_buf);
118         libmail_str_time_t(tv.tv_usec, usec_buf);
119         libmail_str_pid_t(getpid(), pid_buf);
120         len_buf[0]=0;
121         if (info->msgsize > 0)
122         {
123                 strcpy(len_buf, ",S=");
124                 libmail_str_size_t(info->msgsize, len_buf+3);
125         }
126
127         if (info->tmpname)
128                 free(info->tmpname);
129
130         info->tmpname=malloc(strlen(maildir)+strlen(uniq)+
131                              strlen(hostname)+strlen(time_buf)+
132                              strlen(usec_buf)+
133                              strlen(pid_buf)+strlen(len_buf)+100);
134
135         if (!info->tmpname)
136         {
137                 maildir_tmpcreate_free(info);
138                 return -1;
139         }
140
141         strcpy(info->tmpname, maildir);
142         strcat(info->tmpname, "/tmp/");
143         strcat(info->tmpname, time_buf);
144         strcat(info->tmpname, ".M");
145         strcat(info->tmpname, usec_buf);
146         strcat(info->tmpname, "P");
147         strcat(info->tmpname, pid_buf);
148
149         if (*uniq)
150                 strcat(strcat(info->tmpname, "_"), uniq);
151         strcat(info->tmpname, ".");
152         strcat(info->tmpname, hostname);
153         strcat(info->tmpname, len_buf);
154
155         if (stat( info->tmpname, &stat_buf) == 0)
156         {
157                 maildir_tmpcreate_free(info);
158                 errno=EAGAIN;
159                 return -1;
160         }
161
162         if (errno != ENOENT)
163         {
164                 maildir_tmpcreate_free(info);
165                 if (errno == EAGAIN)
166                         errno=EIO;
167                 return -1;
168         }
169
170         if ((fd=maildir_safeopen_stat(info->tmpname, O_CREAT|O_RDWR|O_TRUNC,
171                                       info->openmode, &stat_buf)) < 0)
172         {
173                 maildir_tmpcreate_free(info);
174                 return -1;
175         }
176
177         libmail_strh_dev_t(stat_buf.st_dev, dev_buf);
178         libmail_strh_ino_t(stat_buf.st_ino, ino_buf);
179
180         if (info->newname)
181                 free(info->newname);
182
183         info->newname=malloc(strlen(info->tmpname)+strlen(ino_buf)+
184                              strlen(dev_buf)+3);
185
186         if (!info->newname)
187         {
188                 maildir_tmpcreate_free(info);
189                 unlink(info->tmpname);
190                 close(fd);
191                 if (errno == EAGAIN)
192                         errno=EIO;
193                 return -1;
194         }
195
196         strcpy(info->newname, maildir);
197         strcat(info->newname, "/new/");
198         strcat(info->newname, time_buf);
199         strcat(info->newname, ".M");
200         strcat(info->newname, usec_buf);
201         strcat(info->newname, "P");
202         strcat(info->newname, pid_buf);
203         strcat(info->newname, "V");
204         strcat(info->newname, dev_buf);
205         strcat(info->newname, "I");
206         strcat(info->newname, ino_buf);
207         if (*uniq)
208                 strcat(strcat(info->newname, "_"), uniq);
209         strcat(info->newname, ".");
210         strcat(info->newname, hostname);
211         strcat(info->newname, len_buf);
212
213         return fd;
214 }
215
216 void maildir_tmpcreate_free(struct maildir_tmpcreate_info *info)
217 {
218         if (info->tmpname)
219                 free(info->tmpname);
220         info->tmpname=NULL;
221
222         if (info->newname)
223                 free(info->newname);
224         info->newname=NULL;
225 }
226
227 int maildir_movetmpnew(const char *tmpname, const char *newname)
228 {
229         if (link(tmpname, newname) == 0)
230         {
231                 unlink(tmpname);
232                 return 0;
233         }
234
235         if (errno != EXDEV)
236                 return -1;
237
238         /* AFS? */
239
240         return rename(tmpname, newname);
241 }