tempfile: release deactivated strbufs instead of resetting
[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 left registered in the `tempfile_list`, and
46  *     `on_list` is set.
47  *
48  * A temporary file is owned by the process that created it. The
49  * `tempfile` has an `owner` field that records the owner's PID. This
50  * field is used to prevent a forked process from deleting a temporary
51  * file created by its parent.
52  */
53
54 #include "cache.h"
55 #include "tempfile.h"
56 #include "sigchain.h"
57
58 static struct tempfile *volatile tempfile_list;
59
60 static void remove_tempfiles(int in_signal_handler)
61 {
62         pid_t me = getpid();
63         struct tempfile *volatile p;
64
65         for (p = tempfile_list; p; p = p->next) {
66                 if (!is_tempfile_active(p) || p->owner != me)
67                         continue;
68
69                 if (p->fd >= 0)
70                         close(p->fd);
71
72                 if (in_signal_handler)
73                         unlink(p->filename.buf);
74                 else
75                         unlink_or_warn(p->filename.buf);
76
77                 p->active = 0;
78         }
79 }
80
81 static void remove_tempfiles_on_exit(void)
82 {
83         remove_tempfiles(0);
84 }
85
86 static void remove_tempfiles_on_signal(int signo)
87 {
88         remove_tempfiles(1);
89         sigchain_pop(signo);
90         raise(signo);
91 }
92
93 /*
94  * Initialize *tempfile if necessary and add it to tempfile_list.
95  */
96 static void prepare_tempfile_object(struct tempfile *tempfile)
97 {
98         if (!tempfile_list) {
99                 /* One-time initialization */
100                 sigchain_push_common(remove_tempfiles_on_signal);
101                 atexit(remove_tempfiles_on_exit);
102         }
103
104         if (is_tempfile_active(tempfile))
105                 BUG("prepare_tempfile_object called for active object");
106         if (!tempfile->on_list) {
107                 /* Initialize *tempfile and add it to tempfile_list: */
108                 tempfile->fd = -1;
109                 tempfile->fp = NULL;
110                 tempfile->active = 0;
111                 tempfile->owner = 0;
112                 strbuf_init(&tempfile->filename, 0);
113                 tempfile->next = tempfile_list;
114                 tempfile_list = tempfile;
115                 tempfile->on_list = 1;
116         } else if (tempfile->filename.len) {
117                 /* This shouldn't happen, but better safe than sorry. */
118                 BUG("prepare_tempfile_object called for improperly-reset object");
119         }
120 }
121
122 static void activate_tempfile(struct tempfile *tempfile)
123 {
124         tempfile->owner = getpid();
125         tempfile->active = 1;
126 }
127
128 static void deactivate_tempfile(struct tempfile *tempfile)
129 {
130         tempfile->active = 0;
131         strbuf_release(&tempfile->filename);
132 }
133
134 /* Make sure errno contains a meaningful value on error */
135 int create_tempfile(struct tempfile *tempfile, const char *path)
136 {
137         prepare_tempfile_object(tempfile);
138
139         strbuf_add_absolute_path(&tempfile->filename, path);
140         tempfile->fd = open(tempfile->filename.buf,
141                             O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
142         if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
143                 /* Try again w/o O_CLOEXEC: the kernel might not support it */
144                 tempfile->fd = open(tempfile->filename.buf,
145                                     O_RDWR | O_CREAT | O_EXCL, 0666);
146         if (tempfile->fd < 0) {
147                 deactivate_tempfile(tempfile);
148                 return -1;
149         }
150         activate_tempfile(tempfile);
151         if (adjust_shared_perm(tempfile->filename.buf)) {
152                 int save_errno = errno;
153                 error("cannot fix permission bits on %s", tempfile->filename.buf);
154                 delete_tempfile(tempfile);
155                 errno = save_errno;
156                 return -1;
157         }
158         return tempfile->fd;
159 }
160
161 void register_tempfile(struct tempfile *tempfile, const char *path)
162 {
163         prepare_tempfile_object(tempfile);
164         strbuf_add_absolute_path(&tempfile->filename, path);
165         activate_tempfile(tempfile);
166 }
167
168 int mks_tempfile_sm(struct tempfile *tempfile,
169                     const char *template, int suffixlen, int mode)
170 {
171         prepare_tempfile_object(tempfile);
172
173         strbuf_add_absolute_path(&tempfile->filename, template);
174         tempfile->fd = git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode);
175         if (tempfile->fd < 0) {
176                 deactivate_tempfile(tempfile);
177                 return -1;
178         }
179         activate_tempfile(tempfile);
180         return tempfile->fd;
181 }
182
183 int mks_tempfile_tsm(struct tempfile *tempfile,
184                      const char *template, int suffixlen, int mode)
185 {
186         const char *tmpdir;
187
188         prepare_tempfile_object(tempfile);
189
190         tmpdir = getenv("TMPDIR");
191         if (!tmpdir)
192                 tmpdir = "/tmp";
193
194         strbuf_addf(&tempfile->filename, "%s/%s", tmpdir, template);
195         tempfile->fd = git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode);
196         if (tempfile->fd < 0) {
197                 deactivate_tempfile(tempfile);
198                 return -1;
199         }
200         activate_tempfile(tempfile);
201         return tempfile->fd;
202 }
203
204 int xmks_tempfile_m(struct tempfile *tempfile, const char *template, int mode)
205 {
206         int fd;
207         struct strbuf full_template = STRBUF_INIT;
208
209         strbuf_add_absolute_path(&full_template, template);
210         fd = mks_tempfile_m(tempfile, full_template.buf, mode);
211         if (fd < 0)
212                 die_errno("Unable to create temporary file '%s'",
213                           full_template.buf);
214
215         strbuf_release(&full_template);
216         return fd;
217 }
218
219 FILE *fdopen_tempfile(struct tempfile *tempfile, const char *mode)
220 {
221         if (!is_tempfile_active(tempfile))
222                 BUG("fdopen_tempfile() called for inactive object");
223         if (tempfile->fp)
224                 BUG("fdopen_tempfile() called for open object");
225
226         tempfile->fp = fdopen(tempfile->fd, mode);
227         return tempfile->fp;
228 }
229
230 const char *get_tempfile_path(struct tempfile *tempfile)
231 {
232         if (!is_tempfile_active(tempfile))
233                 BUG("get_tempfile_path() called for inactive object");
234         return tempfile->filename.buf;
235 }
236
237 int get_tempfile_fd(struct tempfile *tempfile)
238 {
239         if (!is_tempfile_active(tempfile))
240                 BUG("get_tempfile_fd() called for inactive object");
241         return tempfile->fd;
242 }
243
244 FILE *get_tempfile_fp(struct tempfile *tempfile)
245 {
246         if (!is_tempfile_active(tempfile))
247                 BUG("get_tempfile_fp() called for inactive object");
248         return tempfile->fp;
249 }
250
251 int close_tempfile_gently(struct tempfile *tempfile)
252 {
253         int fd;
254         FILE *fp;
255         int err;
256
257         if (!is_tempfile_active(tempfile) || tempfile->fd < 0)
258                 return 0;
259
260         fd = tempfile->fd;
261         fp = tempfile->fp;
262         tempfile->fd = -1;
263         if (fp) {
264                 tempfile->fp = NULL;
265                 if (ferror(fp)) {
266                         err = -1;
267                         if (!fclose(fp))
268                                 errno = EIO;
269                 } else {
270                         err = fclose(fp);
271                 }
272         } else {
273                 err = close(fd);
274         }
275
276         return err ? -1 : 0;
277 }
278
279 int reopen_tempfile(struct tempfile *tempfile)
280 {
281         if (!is_tempfile_active(tempfile))
282                 BUG("reopen_tempfile called for an inactive object");
283         if (0 <= tempfile->fd)
284                 BUG("reopen_tempfile called for an open object");
285         tempfile->fd = open(tempfile->filename.buf, O_WRONLY);
286         return tempfile->fd;
287 }
288
289 int rename_tempfile(struct tempfile *tempfile, const char *path)
290 {
291         if (!is_tempfile_active(tempfile))
292                 BUG("rename_tempfile called for inactive object");
293
294         if (close_tempfile_gently(tempfile)) {
295                 delete_tempfile(tempfile);
296                 return -1;
297         }
298
299         if (rename(tempfile->filename.buf, path)) {
300                 int save_errno = errno;
301                 delete_tempfile(tempfile);
302                 errno = save_errno;
303                 return -1;
304         }
305
306         deactivate_tempfile(tempfile);
307         return 0;
308 }
309
310 void delete_tempfile(struct tempfile *tempfile)
311 {
312         if (!is_tempfile_active(tempfile))
313                 return;
314
315         close_tempfile_gently(tempfile);
316         unlink_or_warn(tempfile->filename.buf);
317         deactivate_tempfile(tempfile);
318 }