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 voidprepare_tempfile_object(struct tempfile *tempfile) 95{ 96 tempfile->fd = -1; 97 tempfile->fp = NULL; 98 tempfile->active =0; 99 tempfile->owner =0; 100INIT_LIST_HEAD(&tempfile->list); 101strbuf_init(&tempfile->filename,0); 102} 103 104static voidactivate_tempfile(struct tempfile *tempfile) 105{ 106static int initialized; 107 108if(is_tempfile_active(tempfile)) 109BUG("activate_tempfile called for active object"); 110 111if(!initialized) { 112sigchain_push_common(remove_tempfiles_on_signal); 113atexit(remove_tempfiles_on_exit); 114 initialized =1; 115} 116 117volatile_list_add(&tempfile->list, &tempfile_list); 118 tempfile->owner =getpid(); 119 tempfile->active =1; 120} 121 122static voiddeactivate_tempfile(struct tempfile *tempfile) 123{ 124 tempfile->active =0; 125strbuf_release(&tempfile->filename); 126volatile_list_del(&tempfile->list); 127} 128 129/* Make sure errno contains a meaningful value on error */ 130intcreate_tempfile(struct tempfile *tempfile,const char*path) 131{ 132prepare_tempfile_object(tempfile); 133 134strbuf_add_absolute_path(&tempfile->filename, path); 135 tempfile->fd =open(tempfile->filename.buf, 136 O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC,0666); 137if(O_CLOEXEC && tempfile->fd <0&& errno == EINVAL) 138/* Try again w/o O_CLOEXEC: the kernel might not support it */ 139 tempfile->fd =open(tempfile->filename.buf, 140 O_RDWR | O_CREAT | O_EXCL,0666); 141if(tempfile->fd <0) { 142deactivate_tempfile(tempfile); 143return-1; 144} 145activate_tempfile(tempfile); 146if(adjust_shared_perm(tempfile->filename.buf)) { 147int save_errno = errno; 148error("cannot fix permission bits on%s", tempfile->filename.buf); 149delete_tempfile(tempfile); 150 errno = save_errno; 151return-1; 152} 153return tempfile->fd; 154} 155 156voidregister_tempfile(struct tempfile *tempfile,const char*path) 157{ 158prepare_tempfile_object(tempfile); 159strbuf_add_absolute_path(&tempfile->filename, path); 160activate_tempfile(tempfile); 161} 162 163intmks_tempfile_sm(struct tempfile *tempfile, 164const char*template,int suffixlen,int mode) 165{ 166prepare_tempfile_object(tempfile); 167 168strbuf_add_absolute_path(&tempfile->filename,template); 169 tempfile->fd =git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode); 170if(tempfile->fd <0) { 171deactivate_tempfile(tempfile); 172return-1; 173} 174activate_tempfile(tempfile); 175return tempfile->fd; 176} 177 178intmks_tempfile_tsm(struct tempfile *tempfile, 179const char*template,int suffixlen,int mode) 180{ 181const char*tmpdir; 182 183prepare_tempfile_object(tempfile); 184 185 tmpdir =getenv("TMPDIR"); 186if(!tmpdir) 187 tmpdir ="/tmp"; 188 189strbuf_addf(&tempfile->filename,"%s/%s", tmpdir,template); 190 tempfile->fd =git_mkstemps_mode(tempfile->filename.buf, suffixlen, mode); 191if(tempfile->fd <0) { 192deactivate_tempfile(tempfile); 193return-1; 194} 195activate_tempfile(tempfile); 196return tempfile->fd; 197} 198 199intxmks_tempfile_m(struct tempfile *tempfile,const char*template,int mode) 200{ 201int fd; 202struct strbuf full_template = STRBUF_INIT; 203 204strbuf_add_absolute_path(&full_template,template); 205 fd =mks_tempfile_m(tempfile, full_template.buf, mode); 206if(fd <0) 207die_errno("Unable to create temporary file '%s'", 208 full_template.buf); 209 210strbuf_release(&full_template); 211return fd; 212} 213 214FILE*fdopen_tempfile(struct tempfile *tempfile,const char*mode) 215{ 216if(!is_tempfile_active(tempfile)) 217BUG("fdopen_tempfile() called for inactive object"); 218if(tempfile->fp) 219BUG("fdopen_tempfile() called for open object"); 220 221 tempfile->fp =fdopen(tempfile->fd, mode); 222return tempfile->fp; 223} 224 225const char*get_tempfile_path(struct tempfile *tempfile) 226{ 227if(!is_tempfile_active(tempfile)) 228BUG("get_tempfile_path() called for inactive object"); 229return tempfile->filename.buf; 230} 231 232intget_tempfile_fd(struct tempfile *tempfile) 233{ 234if(!is_tempfile_active(tempfile)) 235BUG("get_tempfile_fd() called for inactive object"); 236return tempfile->fd; 237} 238 239FILE*get_tempfile_fp(struct tempfile *tempfile) 240{ 241if(!is_tempfile_active(tempfile)) 242BUG("get_tempfile_fp() called for inactive object"); 243return tempfile->fp; 244} 245 246intclose_tempfile_gently(struct tempfile *tempfile) 247{ 248int fd; 249FILE*fp; 250int err; 251 252if(!is_tempfile_active(tempfile) || tempfile->fd <0) 253return0; 254 255 fd = tempfile->fd; 256 fp = tempfile->fp; 257 tempfile->fd = -1; 258if(fp) { 259 tempfile->fp = NULL; 260if(ferror(fp)) { 261 err = -1; 262if(!fclose(fp)) 263 errno = EIO; 264}else{ 265 err =fclose(fp); 266} 267}else{ 268 err =close(fd); 269} 270 271return err ? -1:0; 272} 273 274intreopen_tempfile(struct tempfile *tempfile) 275{ 276if(!is_tempfile_active(tempfile)) 277BUG("reopen_tempfile called for an inactive object"); 278if(0<= tempfile->fd) 279BUG("reopen_tempfile called for an open object"); 280 tempfile->fd =open(tempfile->filename.buf, O_WRONLY); 281return tempfile->fd; 282} 283 284intrename_tempfile(struct tempfile *tempfile,const char*path) 285{ 286if(!is_tempfile_active(tempfile)) 287BUG("rename_tempfile called for inactive object"); 288 289if(close_tempfile_gently(tempfile)) { 290delete_tempfile(tempfile); 291return-1; 292} 293 294if(rename(tempfile->filename.buf, path)) { 295int save_errno = errno; 296delete_tempfile(tempfile); 297 errno = save_errno; 298return-1; 299} 300 301deactivate_tempfile(tempfile); 302return0; 303} 304 305voiddelete_tempfile(struct tempfile *tempfile) 306{ 307if(!is_tempfile_active(tempfile)) 308return; 309 310close_tempfile_gently(tempfile); 311unlink_or_warn(tempfile->filename.buf); 312deactivate_tempfile(tempfile); 313}