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 57staticVOLATILE_LIST_HEAD(tempfile_list); 58 59static voidremove_tempfiles(int in_signal_handler) 60{ 61 pid_t me =getpid(); 62volatilestruct volatile_list_head *pos; 63 64list_for_each(pos, &tempfile_list) { 65struct tempfile *p =list_entry(pos,struct tempfile, list); 66 67if(!is_tempfile_active(p) || p->owner != me) 68continue; 69 70if(p->fd >=0) 71close(p->fd); 72 73if(in_signal_handler) 74unlink(p->filename.buf); 75else 76unlink_or_warn(p->filename.buf); 77 78 p->active =0; 79} 80} 81 82static voidremove_tempfiles_on_exit(void) 83{ 84remove_tempfiles(0); 85} 86 87static voidremove_tempfiles_on_signal(int signo) 88{ 89remove_tempfiles(1); 90sigchain_pop(signo); 91raise(signo); 92} 93 94static struct tempfile *new_tempfile(void) 95{ 96struct tempfile *tempfile =xmalloc(sizeof(*tempfile)); 97 tempfile->fd = -1; 98 tempfile->fp = NULL; 99 tempfile->active =0; 100 tempfile->owner =0; 101INIT_LIST_HEAD(&tempfile->list); 102strbuf_init(&tempfile->filename,0); 103return tempfile; 104} 105 106static voidactivate_tempfile(struct tempfile *tempfile) 107{ 108static int initialized; 109 110if(is_tempfile_active(tempfile)) 111BUG("activate_tempfile called for active object"); 112 113if(!initialized) { 114sigchain_push_common(remove_tempfiles_on_signal); 115atexit(remove_tempfiles_on_exit); 116 initialized =1; 117} 118 119volatile_list_add(&tempfile->list, &tempfile_list); 120 tempfile->owner =getpid(); 121 tempfile->active =1; 122} 123 124static voiddeactivate_tempfile(struct tempfile *tempfile) 125{ 126 tempfile->active =0; 127strbuf_release(&tempfile->filename); 128volatile_list_del(&tempfile->list); 129free(tempfile); 130} 131 132/* Make sure errno contains a meaningful value on error */ 133struct tempfile *create_tempfile(const char*path) 134{ 135struct tempfile *tempfile =new_tempfile(); 136 137strbuf_add_absolute_path(&tempfile->filename, path); 138 tempfile->fd =open(tempfile->filename.buf, 139 O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC,0666); 140if(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); 144if(tempfile->fd <0) { 145deactivate_tempfile(tempfile); 146return NULL; 147} 148activate_tempfile(tempfile); 149if(adjust_shared_perm(tempfile->filename.buf)) { 150int save_errno = errno; 151error("cannot fix permission bits on%s", tempfile->filename.buf); 152delete_tempfile(&tempfile); 153 errno = save_errno; 154return NULL; 155} 156 157return tempfile; 158} 159 160struct tempfile *register_tempfile(const char*path) 161{ 162struct tempfile *tempfile =new_tempfile(); 163strbuf_add_absolute_path(&tempfile->filename, path); 164activate_tempfile(tempfile); 165return tempfile; 166} 167 168struct tempfile *mks_tempfile_sm(const char*template,int suffixlen,int mode) 169{ 170struct tempfile *tempfile =new_tempfile(); 171 172strbuf_add_absolute_path(&tempfile->filename,template); 173 tempfile->fd =git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode); 174if(tempfile->fd <0) { 175deactivate_tempfile(tempfile); 176return NULL; 177} 178activate_tempfile(tempfile); 179return tempfile; 180} 181 182struct tempfile *mks_tempfile_tsm(const char*template,int suffixlen,int mode) 183{ 184struct tempfile *tempfile =new_tempfile(); 185const char*tmpdir; 186 187 tmpdir =getenv("TMPDIR"); 188if(!tmpdir) 189 tmpdir ="/tmp"; 190 191strbuf_addf(&tempfile->filename,"%s/%s", tmpdir,template); 192 tempfile->fd =git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode); 193if(tempfile->fd <0) { 194deactivate_tempfile(tempfile); 195return NULL; 196} 197activate_tempfile(tempfile); 198return tempfile; 199} 200 201struct tempfile *xmks_tempfile_m(const char*template,int mode) 202{ 203struct tempfile *tempfile; 204struct strbuf full_template = STRBUF_INIT; 205 206strbuf_add_absolute_path(&full_template,template); 207 tempfile =mks_tempfile_m(full_template.buf, mode); 208if(!tempfile) 209die_errno("Unable to create temporary file '%s'", 210 full_template.buf); 211 212strbuf_release(&full_template); 213return tempfile; 214} 215 216FILE*fdopen_tempfile(struct tempfile *tempfile,const char*mode) 217{ 218if(!is_tempfile_active(tempfile)) 219BUG("fdopen_tempfile() called for inactive object"); 220if(tempfile->fp) 221BUG("fdopen_tempfile() called for open object"); 222 223 tempfile->fp =fdopen(tempfile->fd, mode); 224return tempfile->fp; 225} 226 227const char*get_tempfile_path(struct tempfile *tempfile) 228{ 229if(!is_tempfile_active(tempfile)) 230BUG("get_tempfile_path() called for inactive object"); 231return tempfile->filename.buf; 232} 233 234intget_tempfile_fd(struct tempfile *tempfile) 235{ 236if(!is_tempfile_active(tempfile)) 237BUG("get_tempfile_fd() called for inactive object"); 238return tempfile->fd; 239} 240 241FILE*get_tempfile_fp(struct tempfile *tempfile) 242{ 243if(!is_tempfile_active(tempfile)) 244BUG("get_tempfile_fp() called for inactive object"); 245return tempfile->fp; 246} 247 248intclose_tempfile_gently(struct tempfile *tempfile) 249{ 250int fd; 251FILE*fp; 252int err; 253 254if(!is_tempfile_active(tempfile) || tempfile->fd <0) 255return0; 256 257 fd = tempfile->fd; 258 fp = tempfile->fp; 259 tempfile->fd = -1; 260if(fp) { 261 tempfile->fp = NULL; 262if(ferror(fp)) { 263 err = -1; 264if(!fclose(fp)) 265 errno = EIO; 266}else{ 267 err =fclose(fp); 268} 269}else{ 270 err =close(fd); 271} 272 273return err ? -1:0; 274} 275 276intreopen_tempfile(struct tempfile *tempfile) 277{ 278if(!is_tempfile_active(tempfile)) 279BUG("reopen_tempfile called for an inactive object"); 280if(0<= tempfile->fd) 281BUG("reopen_tempfile called for an open object"); 282 tempfile->fd =open(tempfile->filename.buf, O_WRONLY); 283return tempfile->fd; 284} 285 286intrename_tempfile(struct tempfile **tempfile_p,const char*path) 287{ 288struct tempfile *tempfile = *tempfile_p; 289 290if(!is_tempfile_active(tempfile)) 291BUG("rename_tempfile called for inactive object"); 292 293if(close_tempfile_gently(tempfile)) { 294delete_tempfile(tempfile_p); 295return-1; 296} 297 298if(rename(tempfile->filename.buf, path)) { 299int save_errno = errno; 300delete_tempfile(tempfile_p); 301 errno = save_errno; 302return-1; 303} 304 305deactivate_tempfile(tempfile); 306*tempfile_p = NULL; 307return0; 308} 309 310voiddelete_tempfile(struct tempfile **tempfile_p) 311{ 312struct tempfile *tempfile = *tempfile_p; 313 314if(!is_tempfile_active(tempfile)) 315return; 316 317close_tempfile_gently(tempfile); 318unlink_or_warn(tempfile->filename.buf); 319deactivate_tempfile(tempfile); 320*tempfile_p = NULL; 321}