diff options
Diffstat (limited to 'tmp-objdir.c')
| -rw-r--r-- | tmp-objdir.c | 114 |
1 files changed, 69 insertions, 45 deletions
diff --git a/tmp-objdir.c b/tmp-objdir.c index 91c00567f4..2a2012eb6d 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,21 +1,24 @@ #include "cache.h" #include "tmp-objdir.h" +#include "chdir-notify.h" #include "dir.h" #include "sigchain.h" #include "string-list.h" #include "strbuf.h" -#include "argv-array.h" +#include "strvec.h" #include "quote.h" #include "object-store.h" struct tmp_objdir { struct strbuf path; - struct argv_array env; + struct strvec env; + struct object_directory *prev_odb; + int will_destroy; }; /* * Allow only one tmp_objdir at a time in a running process, which simplifies - * our signal/atexit cleanup routines. It's doubtful callers will ever need + * our atexit cleanup routines. It's doubtful callers will ever need * more than one, and we can expand later if so. You can have many such * tmp_objdirs simultaneously in many processes, of course. */ @@ -24,11 +27,11 @@ static struct tmp_objdir *the_tmp_objdir; static void tmp_objdir_free(struct tmp_objdir *t) { strbuf_release(&t->path); - argv_array_clear(&t->env); + strvec_clear(&t->env); free(t); } -static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal) +int tmp_objdir_destroy(struct tmp_objdir *t) { int err; @@ -38,26 +41,14 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal) if (t == the_tmp_objdir) the_tmp_objdir = NULL; - /* - * This may use malloc via strbuf_grow(), but we should - * have pre-grown t->path sufficiently so that this - * doesn't happen in practice. - */ + if (t->prev_odb) + restore_primary_odb(t->prev_odb, t->path.buf); + err = remove_dir_recursively(&t->path, 0); - /* - * When we are cleaning up due to a signal, we won't bother - * freeing memory; it may cause a deadlock if the signal - * arrived while libc's allocator lock is held. - */ - if (!on_signal) - tmp_objdir_free(t); - return err; -} + tmp_objdir_free(t); -int tmp_objdir_destroy(struct tmp_objdir *t) -{ - return tmp_objdir_destroy_1(t, 0); + return err; } static void remove_tmp_objdir(void) @@ -65,11 +56,9 @@ static void remove_tmp_objdir(void) tmp_objdir_destroy(the_tmp_objdir); } -static void remove_tmp_objdir_on_signal(int signo) +void tmp_objdir_discard_objects(struct tmp_objdir *t) { - tmp_objdir_destroy_1(the_tmp_objdir, 1); - sigchain_pop(signo); - raise(signo); + remove_dir_recursively(&t->path, REMOVE_DIR_KEEP_TOPLEVEL); } /* @@ -79,7 +68,7 @@ static void remove_tmp_objdir_on_signal(int signo) * separated by PATH_SEP (which is what separate values in * GIT_ALTERNATE_OBJECT_DIRECTORIES). */ -static void env_append(struct argv_array *env, const char *key, const char *val) +static void env_append(struct strvec *env, const char *key, const char *val) { struct strbuf quoted = STRBUF_INIT; const char *old; @@ -97,16 +86,16 @@ static void env_append(struct argv_array *env, const char *key, const char *val) old = getenv(key); if (!old) - argv_array_pushf(env, "%s=%s", key, val); + strvec_pushf(env, "%s=%s", key, val); else - argv_array_pushf(env, "%s=%s%c%s", key, old, PATH_SEP, val); + strvec_pushf(env, "%s=%s%c%s", key, old, PATH_SEP, val); strbuf_release("ed); } -static void env_replace(struct argv_array *env, const char *key, const char *val) +static void env_replace(struct strvec *env, const char *key, const char *val) { - argv_array_pushf(env, "%s=%s", key, val); + strvec_pushf(env, "%s=%s", key, val); } static int setup_tmp_objdir(const char *root) @@ -121,7 +110,7 @@ static int setup_tmp_objdir(const char *root) return ret; } -struct tmp_objdir *tmp_objdir_create(void) +struct tmp_objdir *tmp_objdir_create(const char *prefix) { static int installed_handlers; struct tmp_objdir *t; @@ -129,19 +118,16 @@ struct tmp_objdir *tmp_objdir_create(void) if (the_tmp_objdir) BUG("only one tmp_objdir can be used at a time"); - t = xmalloc(sizeof(*t)); + t = xcalloc(1, sizeof(*t)); strbuf_init(&t->path, 0); - argv_array_init(&t->env); - - strbuf_addf(&t->path, "%s/incoming-XXXXXX", get_object_directory()); + strvec_init(&t->env); /* - * Grow the strbuf beyond any filename we expect to be placed in it. - * If tmp_objdir_destroy() is called by a signal handler, then - * we should be able to use the strbuf to remove files without - * having to call malloc. + * Use a string starting with tmp_ so that the builtin/prune.c code + * can recognize any stale objdirs left behind by a crash and delete + * them. */ - strbuf_grow(&t->path, 1024); + strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix); if (!mkdtemp(t->path.buf)) { /* free, not destroy, as we never touched the filesystem */ @@ -152,7 +138,6 @@ struct tmp_objdir *tmp_objdir_create(void) the_tmp_objdir = t; if (!installed_handlers) { atexit(remove_tmp_objdir); - sigchain_push_common(remove_tmp_objdir_on_signal); installed_handlers++; } @@ -185,9 +170,11 @@ static int pack_copy_priority(const char *name) return 1; if (ends_with(name, ".pack")) return 2; - if (ends_with(name, ".idx")) + if (ends_with(name, ".rev")) return 3; - return 4; + if (ends_with(name, ".idx")) + return 4; + return 5; } static int pack_copy_cmp(const char *a, const char *b) @@ -267,6 +254,13 @@ int tmp_objdir_migrate(struct tmp_objdir *t) if (!t) return 0; + if (t->prev_odb) { + if (the_repository->objects->odb->will_destroy) + BUG("migrating an ODB that was marked for destruction"); + restore_primary_odb(t->prev_odb, t->path.buf); + t->prev_odb = NULL; + } + strbuf_addbuf(&src, &t->path); strbuf_addstr(&dst, get_object_directory()); @@ -283,10 +277,40 @@ const char **tmp_objdir_env(const struct tmp_objdir *t) { if (!t) return NULL; - return t->env.argv; + return t->env.v; } void tmp_objdir_add_as_alternate(const struct tmp_objdir *t) { add_to_alternates_memory(t->path.buf); } + +void tmp_objdir_replace_primary_odb(struct tmp_objdir *t, int will_destroy) +{ + if (t->prev_odb) + BUG("the primary object database is already replaced"); + t->prev_odb = set_temporary_primary_odb(t->path.buf, will_destroy); + t->will_destroy = will_destroy; +} + +struct tmp_objdir *tmp_objdir_unapply_primary_odb(void) +{ + if (!the_tmp_objdir || !the_tmp_objdir->prev_odb) + return NULL; + + restore_primary_odb(the_tmp_objdir->prev_odb, the_tmp_objdir->path.buf); + the_tmp_objdir->prev_odb = NULL; + return the_tmp_objdir; +} + +void tmp_objdir_reapply_primary_odb(struct tmp_objdir *t, const char *old_cwd, + const char *new_cwd) +{ + char *path; + + path = reparent_relative_path(old_cwd, new_cwd, t->path.buf); + strbuf_reset(&t->path); + strbuf_addstr(&t->path, path); + free(path); + tmp_objdir_replace_primary_odb(t, t->will_destroy); +} |
