OSDN Git Service

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