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 57static VOLATILE_LIST_HEAD(tempfile_list); 58 59static 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 82static void remove_tempfiles_on_exit(void) 83{ 84 remove_tempfiles(0); 85} 86 87static void remove_tempfiles_on_signal(int signo) 88{ 89 remove_tempfiles(1); 90 sigchain_pop(signo); 91 raise(signo); 92} 93 94static 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 106static 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 124static 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 */ 133struct tempfile *create_tempfile(const char *path) 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, 0666); 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, 0666); 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 160struct 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 168struct 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 182struct 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 201struct 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 216FILE *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 227const 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 234int 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 241FILE *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 248int 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 276int 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); 283 return tempfile->fd; 284} 285 286int 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 310void 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}