shallow: automatically clean up shallow tempfiles

We sometimes write tempfiles of the form "shallow_XXXXXX" during fetch/push operations with shallow repositories. Under normal circumstances, we clean up the result when we are done. However, we do no take steps to clean up after ourselves when we exit due to die() or signal death. This patch teaches the tempfile creation code to register handlers to clean up after ourselves. To handle this, we change the ownership semantics of the filename returned by setup_temporary_shallow. It now keeps a copy of the filename itself, and returns only a const pointer to it. We can also do away with explicit tempfile removal in the callers. They all exit not long after finishing with the file, so they can rely on the auto-cleanup, simplifying the code. Note that we keep things simple and maintain only a single filename to be cleaned. This is sufficient for the current caller, but we future-proof it with a die("BUG"). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Feb 27, 2014 at 06:25 UTC 0179c945fce361c56b465e8a3f0fdf0962a816a1
5 files changed +40 -37
builtin/receive-pack.c
+4 -12
@@ -828,14 +828,10 @@ static void execute_commands(struct command *commands,
828 }
829 }
830
831 - if (shallow_update) {
832 - if (!checked_connectivity)
833 - error("BUG: run 'git fsck' for safety.\n"
834 - "If there are errors, try to remove "
835 - "the reported refs above");
836 - if (alt_shallow_file && *alt_shallow_file)
837 - unlink(alt_shallow_file);
838 - }
831 + if (shallow_update && !checked_connectivity)
832 + error("BUG: run 'git fsck' for safety.\n"
833 + "If there are errors, try to remove "
834 + "the reported refs above");
835 }
836
837 static struct command *read_head_info(struct sha1_array *shallow)
@@ -1087,10 +1083,6 @@ static void update_shallow_info(struct command *commands,
1083 cmd->skip_update = 1;
1084 }
1085 }
1090 - if (alt_shallow_file && *alt_shallow_file) {
1091 - unlink(alt_shallow_file);
1092 - alt_shallow_file = NULL;
1093 - }
1086 free(ref_status);
1087 }
1088
commit.h
+1 -1
@@ -209,7 +209,7 @@ extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
209 extern void setup_alternate_shallow(struct lock_file *shallow_lock,
210 const char **alternate_shallow_file,
211 const struct sha1_array *extra);
212 -extern char *setup_temporary_shallow(const struct sha1_array *extra);
212 +extern const char *setup_temporary_shallow(const struct sha1_array *extra);
213 extern void advertise_shallow_grafts(int);
214
215 struct shallow_info {
fetch-pack.c
-11
@@ -947,17 +947,6 @@ static void update_shallow(struct fetch_pack_args *args,
947 if (!si->shallow || !si->shallow->nr)
948 return;
949
950 - if (alternate_shallow_file) {
951 - /*
952 - * The temporary shallow file is only useful for
953 - * index-pack and unpack-objects because it may
954 - * contain more roots than we want. Delete it.
955 - */
956 - if (*alternate_shallow_file)
957 - unlink(alternate_shallow_file);
958 - free((char *)alternate_shallow_file);
959 - }
960 -
950 if (args->cloning) {
951 /*
952 * remote is shallow, but this is a clone, there are
shallow.c
+34 -7
@@ -8,6 +8,7 @@
8 #include "diff.h"
9 #include "revision.h"
10 #include "commit-slab.h"
11 +#include "sigchain.h"
12
13 static int is_shallow = -1;
14 static struct stat_validity shallow_stat;
@@ -206,27 +207,53 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
207 return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
208 }
209
209 -char *setup_temporary_shallow(const struct sha1_array *extra)
210 +static struct strbuf temporary_shallow = STRBUF_INIT;
211 +
212 +static void remove_temporary_shallow(void)
213 +{
214 + if (temporary_shallow.len) {
215 + unlink_or_warn(temporary_shallow.buf);
216 + strbuf_reset(&temporary_shallow);
217 + }
218 +}
219 +
220 +static void remove_temporary_shallow_on_signal(int signo)
221 +{
222 + remove_temporary_shallow();
223 + sigchain_pop(signo);
224 + raise(signo);
225 +}
226 +
227 +const char *setup_temporary_shallow(const struct sha1_array *extra)
228 {
229 + static int installed_handler;
230 struct strbuf sb = STRBUF_INIT;
231 int fd;
232
233 + if (temporary_shallow.len)
234 + die("BUG: attempt to create two temporary shallow files");
235 +
236 if (write_shallow_commits(&sb, 0, extra)) {
215 - struct strbuf path = STRBUF_INIT;
216 - strbuf_addstr(&path, git_path("shallow_XXXXXX"));
217 - fd = xmkstemp(path.buf);
237 + strbuf_addstr(&temporary_shallow, git_path("shallow_XXXXXX"));
238 + fd = xmkstemp(temporary_shallow.buf);
239 +
240 + if (!installed_handler) {
241 + atexit(remove_temporary_shallow);
242 + sigchain_push_common(remove_temporary_shallow_on_signal);
243 + }
244 +
245 if (write_in_full(fd, sb.buf, sb.len) != sb.len)
246 die_errno("failed to write to %s",
220 - path.buf);
247 + temporary_shallow.buf);
248 close(fd);
249 strbuf_release(&sb);
223 - return strbuf_detach(&path, NULL);
250 + return temporary_shallow.buf;
251 }
252 /*
253 * is_repository_shallow() sees empty string as "no shallow
254 * file".
255 */
229 - return xstrdup("");
256 + return temporary_shallow.buf;
257 }
258
259 void setup_alternate_shallow(struct lock_file *shallow_lock,
upload-pack.c
+1 -6
@@ -81,7 +81,7 @@ static void create_pack_file(void)
81 const char *argv[12];
82 int i, arg = 0;
83 FILE *pipe_fd;
84 - char *shallow_file = NULL;
84 + const char *shallow_file = NULL;
85
86 if (shallow_nr) {
87 shallow_file = setup_temporary_shallow(NULL);
@@ -242,11 +242,6 @@ static void create_pack_file(void)
242 error("git upload-pack: git-pack-objects died with error.");
243 goto fail;
244 }
245 - if (shallow_file) {
246 - if (*shallow_file)
247 - unlink(shallow_file);
248 - free(shallow_file);
249 - }
245
246 /* flush the data */
247 if (0 <= buffered) {