]> git.notmuchmail.org Git - notmuch/blob - contrib/notmuch-deliver/maildrop/maildir/maildircreate.c
5efc0afbc158e4147a7933ef8d2ab87bb685cd2a
[notmuch] / contrib / notmuch-deliver / maildrop / maildir / 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
39 FILE *maildir_tmpcreate_fp(struct maildir_tmpcreate_info *info)
40 {
41         int fd=maildir_tmpcreate_fd(info);
42         FILE *fp;
43
44         if (fd < 0)
45                 return NULL;
46
47         fp=fdopen(fd, "w+");
48
49         if (fp == NULL)
50         {
51                 close(fd);
52                 return NULL;
53         }
54
55         return fp;
56 }
57
58 static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info);
59
60 #define KEEPTRYING      (60 * 60)
61 #define SLEEPFOR        3
62
63 int maildir_tmpcreate_fd(struct maildir_tmpcreate_info *info)
64 {
65         int i;
66
67         if (!info->doordie)
68                 return (maildir_tmpcreate_fd_do(info));
69
70         for (i=0; i<KEEPTRYING / SLEEPFOR; i++)
71         {
72                 int fd=maildir_tmpcreate_fd_do(info);
73
74                 if (fd >= 0 || errno != EAGAIN)
75                         return fd;
76
77                 sleep(SLEEPFOR);
78         }
79
80         return -1;
81 }
82
83 static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info)
84 {
85         const char *maildir=info->maildir;
86         const char *uniq=info->uniq;
87         const char *hostname=info->hostname;
88
89         char hostname_buf[256];
90         char time_buf[NUMBUFSIZE];
91         char usec_buf[NUMBUFSIZE];
92         char pid_buf[NUMBUFSIZE];
93         char len_buf[NUMBUFSIZE+3];
94         char dev_buf[NUMBUFSIZE];
95         char ino_buf[NUMBUFSIZE];
96         struct timeval tv;
97
98         struct stat stat_buf;
99         int fd;
100
101         if (!maildir)
102                 maildir=".";
103         if (!uniq)
104                 uniq="";
105
106         if (!hostname || !*hostname)
107         {
108                 hostname_buf[sizeof(hostname_buf)-1]=0;
109                 if (gethostname(hostname_buf, sizeof(hostname_buf)-1) < 0)
110                         strcpy(hostname_buf, "localhost");
111                 hostname=hostname_buf;
112         }
113
114         gettimeofday(&tv, NULL);
115
116         libmail_str_time_t(tv.tv_sec, time_buf);
117         libmail_str_time_t(tv.tv_usec, usec_buf);
118         libmail_str_pid_t(getpid(), pid_buf);
119         len_buf[0]=0;
120         if (info->msgsize > 0)
121         {
122                 strcpy(len_buf, ",S=");
123                 libmail_str_size_t(info->msgsize, len_buf+3);
124         }
125
126         if (info->tmpname)
127                 free(info->tmpname);
128
129         info->tmpname=malloc(strlen(maildir)+strlen(uniq)+
130                              strlen(hostname)+strlen(time_buf)+
131                              strlen(usec_buf)+
132                              strlen(pid_buf)+strlen(len_buf)+100);
133
134         if (!info->tmpname)
135         {
136                 maildir_tmpcreate_free(info);
137                 return -1;
138         }
139
140         strcpy(info->tmpname, maildir);
141         strcat(info->tmpname, "/tmp/");
142         strcat(info->tmpname, time_buf);
143         strcat(info->tmpname, ".M");
144         strcat(info->tmpname, usec_buf);
145         strcat(info->tmpname, "P");
146         strcat(info->tmpname, pid_buf);
147
148         if (*uniq)
149                 strcat(strcat(info->tmpname, "_"), uniq);
150         strcat(info->tmpname, ".");
151         strcat(info->tmpname, hostname);
152         strcat(info->tmpname, len_buf);
153
154         if (stat( info->tmpname, &stat_buf) == 0)
155         {
156                 maildir_tmpcreate_free(info);
157                 errno=EAGAIN;
158                 return -1;
159         }
160
161         if (errno != ENOENT)
162         {
163                 maildir_tmpcreate_free(info);
164                 if (errno == EAGAIN)
165                         errno=EIO;
166                 return -1;
167         }
168
169         if ((fd=maildir_safeopen_stat(info->tmpname, O_CREAT|O_RDWR|O_TRUNC,
170                                       info->openmode, &stat_buf)) < 0)
171         {
172                 maildir_tmpcreate_free(info);
173                 return -1;
174         }
175
176         libmail_strh_dev_t(stat_buf.st_dev, dev_buf);
177         libmail_strh_ino_t(stat_buf.st_ino, ino_buf);
178
179         if (info->newname)
180                 free(info->newname);
181
182         info->newname=malloc(strlen(info->tmpname)+strlen(ino_buf)+
183                              strlen(dev_buf)+3);
184
185         if (!info->newname)
186         {
187                 maildir_tmpcreate_free(info);
188                 unlink(info->tmpname);
189                 close(fd);
190                 if (errno == EAGAIN)
191                         errno=EIO;
192                 return -1;
193         }
194
195         strcpy(info->newname, maildir);
196         strcat(info->newname, "/new/");
197         strcat(info->newname, time_buf);
198         strcat(info->newname, ".M");
199         strcat(info->newname, usec_buf);
200         strcat(info->newname, "P");
201         strcat(info->newname, pid_buf);
202         strcat(info->newname, "V");
203         strcat(info->newname, dev_buf);
204         strcat(info->newname, "I");
205         strcat(info->newname, ino_buf);
206         if (*uniq)
207                 strcat(strcat(info->newname, "_"), uniq);
208         strcat(info->newname, ".");
209         strcat(info->newname, hostname);
210         strcat(info->newname, len_buf);
211
212         return fd;
213 }
214
215 void maildir_tmpcreate_free(struct maildir_tmpcreate_info *info)
216 {
217         if (info->tmpname)
218                 free(info->tmpname);
219         info->tmpname=NULL;
220
221         if (info->newname)
222                 free(info->newname);
223         info->newname=NULL;
224 }
225
226 int maildir_movetmpnew(const char *tmpname, const char *newname)
227 {
228         if (link(tmpname, newname) == 0)
229         {
230                 unlink(tmpname);
231                 return 0;
232         }
233
234         if (errno != EXDEV)
235                 return -1;
236
237         /* AFS? */
238
239         return rename(tmpname, newname);
240 }