t3201: test multiple branch filter combinations
[git] / tempfile.c
1 /*
2  * State diagram and cleanup
3  * -------------------------
4  *
5  * If the program exits while a temporary file is active, we want to
6  * make sure that we remove it. This is done by remembering the active
7  * temporary files in a linked list, `tempfile_list`. An `atexit(3)`
8  * handler and a signal handler are registered, to clean up any active
9  * temporary files.
10  *
11  * Because the signal handler can run at any time, `tempfile_list` and
12  * the `tempfile` objects that comprise it must be kept in
13  * self-consistent states at all times.
14  *
15  * The possible states of a `tempfile` object are as follows:
16  *
17  * - Uninitialized. In this state the object's `on_list` field must be
18  *   zero but the rest of its contents need not be initialized. As
19  *   soon as the object is used in any way, it is irrevocably
20  *   registered in `tempfile_list`, and `on_list` is set.
21  *
22  * - Active, file open (after `create_tempfile()` or
23  *   `reopen_tempfile()`). In this state:
24  *
25  *   - the temporary file exists
26  *   - `active` is set
27  *   - `filename` holds the filename of the temporary file
28  *   - `fd` holds a file descriptor open for writing to it
29  *   - `fp` holds a pointer to an open `FILE` object if and only if
30  *     `fdopen_tempfile()` has been called on the object
31  *   - `owner` holds the PID of the process that created the file
32  *
33  * - Active, file closed (after `close_tempfile_gently()`). Same
34  *   as the previous state, except that the temporary file is closed,
35  *   `fd` is -1, and `fp` is `NULL`.
36  *
37  * - Inactive (after `delete_tempfile()`, `rename_tempfile()`, or a
38  *   failed attempt to create a temporary file). In this state:
39  *
40  *   - `active` is unset
41  *   - `filename` is empty (usually, though there are transitory
42  *     states in which this condition doesn't hold). Client code should
43  *     *not* rely on the filename being empty in this state.
44  *   - `fd` is -1 and `fp` is `NULL`
45  *   - the object is removed from `tempfile_list` (but could be used again)
46  *
47  * A temporary file is owned by the process that created it. The
48  * `tempfile` has an `owner` field that records the owner's PID. This
49  * field is used to prevent a forked process from deleting a temporary
50  * file created by its parent.
51  */
52
53 #include "cache.h"
54 #include "tempfile.h"
55 #include "sigchain.h"
56
57 static VOLATILE_LIST_HEAD(tempfile_list);
58
59 static void remove_tempfiles(int in_signal_handler)
60 {
61         pid_t me = getpid();
62         volatile struct volatile_list_head *pos;
63
64         list_for_each(pos, &tempfile_list) {
65                 struct tempfile *p = list_entry(pos, struct tempfile, list);
66
67                 if (!is_tempfile_active(p) || p->owner != me)
68                         continue;
69
70                 if (p->fd >= 0)
71                         close(p->fd);
72
73                 if (in_signal_handler)
74                         unlink(p->filename.buf);
75                 else
76                         unlink_or_warn(p->filename.buf);
77
78                 p->active = 0;
79         }
80 }
81
82 static void remove_tempfiles_on_exit(void)
83 {
84         remove_tempfiles(0);
85 }
86
87 static void remove_tempfiles_on_signal(int signo)
88 {
89         remove_tempfiles(1);
90         sigchain_pop(signo);
91         raise(signo);
92 }
93
94 static struct tempfile *new_tempfile(void)
95 {
96         struct tempfile *tempfile = xmalloc(sizeof(*tempfile));
97         tempfile->fd = -1;
98         tempfile->fp = NULL;
99         tempfile->active = 0;
100         tempfile->owner = 0;
101         INIT_LIST_HEAD(&tempfile->list);
102         strbuf_init(&tempfile->filename, 0);
103         return tempfile;
104 }
105
106 static void activate_tempfile(struct tempfile *tempfile)
107 {
108         static int initialized;
109
110         if (is_tempfile_active(tempfile))
111                 BUG("activate_tempfile called for active object");
112
113         if (!initialized) {
114                 sigchain_push_common(remove_tempfiles_on_signal);
115                 atexit(remove_tempfiles_on_exit);
116                 initialized = 1;
117         }
118
119         volatile_list_add(&tempfile->list, &tempfile_list);
120         tempfile->owner = getpid();
121         tempfile->active = 1;
122 }
123
124 static void deactivate_tempfile(struct tempfile *tempfile)
125 {
126         tempfile->active = 0;
127         strbuf_release(&tempfile->filename);
128         volatile_list_del(&tempfile->list);
129         free(tempfile);
130 }
131
132 /* Make sure errno contains a meaningful value on error */
133 struct tempfile *create_tempfile_mode(const char *path, int mode)
134 {
135         struct tempfile *tempfile = new_tempfile();
136
137         strbuf_add_absolute_path(&tempfile->filename, path);
138         tempfile->fd = open(tempfile->filename.buf,
139                             O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
140         if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
141                 /* Try again w/o O_CLOEXEC: the kernel might not support it */
142                 tempfile->fd = open(tempfile->filename.buf,
143                                     O_RDWR | O_CREAT | O_EXCL, mode);
144         if (tempfile->fd < 0) {
145                 deactivate_tempfile(tempfile);
146                 return NULL;
147         }
148         activate_tempfile(tempfile);
149         if (adjust_shared_perm(tempfile->filename.buf)) {
150                 int save_errno = errno;
151                 error("cannot fix permission bits on %s", tempfile->filename.buf);
152                 delete_tempfile(&tempfile);
153                 errno = save_errno;
154                 return NULL;
155         }
156
157         return tempfile;
158 }
159
160 struct tempfile *register_tempfile(const char *path)
161 {
162         struct tempfile *tempfile = new_tempfile();
163         strbuf_add_absolute_path(&tempfile->filename, path);
164         activate_tempfile(tempfile);
165         return tempfile;
166 }
167
168 struct tempfile *mks_tempfile_sm(const char *filename_template, int suffixlen, int mode)
169 {
170         struct tempfile *tempfile = new_tempfile();
171
172         strbuf_add_absolute_path(&tempfile->filename, filename_template);
173         tempfile->fd = git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode);
174         if (tempfile->fd < 0) {
175                 deactivate_tempfile(tempfile);
176                 return NULL;
177         }
178         activate_tempfile(tempfile);
179         return tempfile;
180 }
181
182 struct tempfile *mks_tempfile_tsm(const char *filename_template, int suffixlen, int mode)
183 {
184         struct tempfile *tempfile = new_tempfile();
185         const char *tmpdir;
186
187         tmpdir = getenv("TMPDIR");
188         if (!tmpdir)
189                 tmpdir = "/tmp";
190
191         strbuf_addf(&tempfile->filename, "%s/%s", tmpdir, filename_template);
192         tempfile->fd = git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode);
193         if (tempfile->fd < 0) {
194                 deactivate_tempfile(tempfile);
195                 return NULL;
196         }
197         activate_tempfile(tempfile);
198         return tempfile;
199 }
200
201 struct tempfile *xmks_tempfile_m(const char *filename_template, int mode)
202 {
203         struct tempfile *tempfile;
204         struct strbuf full_template = STRBUF_INIT;
205
206         strbuf_add_absolute_path(&full_template, filename_template);
207         tempfile = mks_tempfile_m(full_template.buf, mode);
208         if (!tempfile)
209                 die_errno("Unable to create temporary file '%s'",
210                           full_template.buf);
211
212         strbuf_release(&full_template);
213         return tempfile;
214 }
215
216 FILE *fdopen_tempfile(struct tempfile *tempfile, const char *mode)
217 {
218         if (!is_tempfile_active(tempfile))
219                 BUG("fdopen_tempfile() called for inactive object");
220         if (tempfile->fp)
221                 BUG("fdopen_tempfile() called for open object");
222
223         tempfile->fp = fdopen(tempfile->fd, mode);
224         return tempfile->fp;
225 }
226
227 const char *get_tempfile_path(struct tempfile *tempfile)
228 {
229         if (!is_tempfile_active(tempfile))
230                 BUG("get_tempfile_path() called for inactive object");
231         return tempfile->filename.buf;
232 }
233
234 int get_tempfile_fd(struct tempfile *tempfile)
235 {
236         if (!is_tempfile_active(tempfile))
237                 BUG("get_tempfile_fd() called for inactive object");
238         return tempfile->fd;
239 }
240
241 FILE *get_tempfile_fp(struct tempfile *tempfile)
242 {
243         if (!is_tempfile_active(tempfile))
244                 BUG("get_tempfile_fp() called for inactive object");
245         return tempfile->fp;
246 }
247
248 int close_tempfile_gently(struct tempfile *tempfile)
249 {
250         int fd;
251         FILE *fp;
252         int err;
253
254         if (!is_tempfile_active(tempfile) || tempfile->fd < 0)
255                 return 0;
256
257         fd = tempfile->fd;
258         fp = tempfile->fp;
259         tempfile->fd = -1;
260         if (fp) {
261                 tempfile->fp = NULL;
262                 if (ferror(fp)) {
263                         err = -1;
264                         if (!fclose(fp))
265                                 errno = EIO;
266                 } else {
267                         err = fclose(fp);
268                 }
269         } else {
270                 err = close(fd);
271         }
272
273         return err ? -1 : 0;
274 }
275
276 int reopen_tempfile(struct tempfile *tempfile)
277 {
278         if (!is_tempfile_active(tempfile))
279                 BUG("reopen_tempfile called for an inactive object");
280         if (0 <= tempfile->fd)
281                 BUG("reopen_tempfile called for an open object");
282         tempfile->fd = open(tempfile->filename.buf, O_WRONLY|O_TRUNC);
283         return tempfile->fd;
284 }
285
286 int rename_tempfile(struct tempfile **tempfile_p, const char *path)
287 {
288         struct tempfile *tempfile = *tempfile_p;
289
290         if (!is_tempfile_active(tempfile))
291                 BUG("rename_tempfile called for inactive object");
292
293         if (close_tempfile_gently(tempfile)) {
294                 delete_tempfile(tempfile_p);
295                 return -1;
296         }
297
298         if (rename(tempfile->filename.buf, path)) {
299                 int save_errno = errno;
300                 delete_tempfile(tempfile_p);
301                 errno = save_errno;
302                 return -1;
303         }
304
305         deactivate_tempfile(tempfile);
306         *tempfile_p = NULL;
307         return 0;
308 }
309
310 void delete_tempfile(struct tempfile **tempfile_p)
311 {
312         struct tempfile *tempfile = *tempfile_p;
313
314         if (!is_tempfile_active(tempfile))
315                 return;
316
317         close_tempfile_gently(tempfile);
318         unlink_or_warn(tempfile->filename.buf);
319         deactivate_tempfile(tempfile);
320         *tempfile_p = NULL;
321 }