THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
8.3KB

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