Merge branch 'ns/tmp-objdir'
New interface into the tmp-objdir API to help in-core use of the quarantine feature. * ns/tmp-objdir: tmp-objdir: disable ref updates when replacing the primary odb tmp-objdir: new API for creating temporary writable databases
This commit is contained in:
commit
0dc90d954d
@ -26,10 +26,22 @@ static int prune_tmp_file(const char *fullpath)
|
||||
return error("Could not stat '%s'", fullpath);
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
if (show_only || verbose)
|
||||
printf("Removing stale temporary file %s\n", fullpath);
|
||||
if (!show_only)
|
||||
unlink_or_warn(fullpath);
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (show_only || verbose)
|
||||
printf("Removing stale temporary directory %s\n", fullpath);
|
||||
if (!show_only) {
|
||||
struct strbuf remove_dir_buf = STRBUF_INIT;
|
||||
|
||||
strbuf_addstr(&remove_dir_buf, fullpath);
|
||||
remove_dir_recursively(&remove_dir_buf, 0);
|
||||
strbuf_release(&remove_dir_buf);
|
||||
}
|
||||
} else {
|
||||
if (show_only || verbose)
|
||||
printf("Removing stale temporary file %s\n", fullpath);
|
||||
if (!show_only)
|
||||
unlink_or_warn(fullpath);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2206,7 +2206,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
|
||||
strvec_push(&child.args, alt_shallow_file);
|
||||
}
|
||||
|
||||
tmp_objdir = tmp_objdir_create();
|
||||
tmp_objdir = tmp_objdir_create("incoming");
|
||||
if (!tmp_objdir) {
|
||||
if (err_fd > 0)
|
||||
close(err_fd);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "commit.h"
|
||||
#include "strvec.h"
|
||||
#include "object-store.h"
|
||||
#include "tmp-objdir.h"
|
||||
#include "chdir-notify.h"
|
||||
#include "shallow.h"
|
||||
|
||||
@ -169,6 +170,10 @@ void setup_git_env(const char *git_dir)
|
||||
args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
|
||||
args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
|
||||
args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
|
||||
if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
|
||||
args.disable_ref_updates = 1;
|
||||
}
|
||||
|
||||
repo_set_gitdir(the_repository, git_dir, &args);
|
||||
strvec_clear(&to_free);
|
||||
|
||||
@ -332,10 +337,14 @@ static void update_relative_gitdir(const char *name,
|
||||
void *data)
|
||||
{
|
||||
char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
|
||||
struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
|
||||
|
||||
trace_printf_key(&trace_setup_key,
|
||||
"setup: move $GIT_DIR to '%s'",
|
||||
path);
|
||||
set_git_dir_1(path);
|
||||
if (tmp_objdir)
|
||||
tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
|
||||
free(path);
|
||||
}
|
||||
|
||||
|
@ -680,6 +680,49 @@ void add_to_alternates_memory(const char *reference)
|
||||
'\n', NULL, 0);
|
||||
}
|
||||
|
||||
struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy)
|
||||
{
|
||||
struct object_directory *new_odb;
|
||||
|
||||
/*
|
||||
* Make sure alternates are initialized, or else our entry may be
|
||||
* overwritten when they are.
|
||||
*/
|
||||
prepare_alt_odb(the_repository);
|
||||
|
||||
/*
|
||||
* Make a new primary odb and link the old primary ODB in as an
|
||||
* alternate
|
||||
*/
|
||||
new_odb = xcalloc(1, sizeof(*new_odb));
|
||||
new_odb->path = xstrdup(dir);
|
||||
|
||||
/*
|
||||
* Disable ref updates while a temporary odb is active, since
|
||||
* the objects in the database may roll back.
|
||||
*/
|
||||
new_odb->disable_ref_updates = 1;
|
||||
new_odb->will_destroy = will_destroy;
|
||||
new_odb->next = the_repository->objects->odb;
|
||||
the_repository->objects->odb = new_odb;
|
||||
return new_odb->next;
|
||||
}
|
||||
|
||||
void restore_primary_odb(struct object_directory *restore_odb, const char *old_path)
|
||||
{
|
||||
struct object_directory *cur_odb = the_repository->objects->odb;
|
||||
|
||||
if (strcmp(old_path, cur_odb->path))
|
||||
BUG("expected %s as primary object store; found %s",
|
||||
old_path, cur_odb->path);
|
||||
|
||||
if (cur_odb->next != restore_odb)
|
||||
BUG("we expect the old primary object store to be the first alternate");
|
||||
|
||||
the_repository->objects->odb = restore_odb;
|
||||
free_object_directory(cur_odb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the exact path an alternate is at and returns it. In case of
|
||||
* error NULL is returned and the human readable error is added to `err`
|
||||
@ -1806,8 +1849,11 @@ int hash_object_file(const struct git_hash_algo *algo, const void *buf,
|
||||
/* Finalize a file on disk, and close it. */
|
||||
static void close_loose_object(int fd)
|
||||
{
|
||||
if (fsync_object_files)
|
||||
fsync_or_die(fd, "loose object file");
|
||||
if (!the_repository->objects->odb->will_destroy) {
|
||||
if (fsync_object_files)
|
||||
fsync_or_die(fd, "loose object file");
|
||||
}
|
||||
|
||||
if (close(fd) != 0)
|
||||
die_errno(_("error when closing loose object file"));
|
||||
}
|
||||
|
@ -27,6 +27,18 @@ struct object_directory {
|
||||
uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
|
||||
struct oidtree *loose_objects_cache;
|
||||
|
||||
/*
|
||||
* This is a temporary object store created by the tmp_objdir
|
||||
* facility. Disable ref updates since the objects in the store
|
||||
* might be discarded on rollback.
|
||||
*/
|
||||
int disable_ref_updates;
|
||||
|
||||
/*
|
||||
* This object store is ephemeral, so there is no need to fsync.
|
||||
*/
|
||||
int will_destroy;
|
||||
|
||||
/*
|
||||
* Path to the alternative object store. If this is a relative path,
|
||||
* it is relative to the current working directory.
|
||||
@ -58,6 +70,17 @@ void add_to_alternates_file(const char *dir);
|
||||
*/
|
||||
void add_to_alternates_memory(const char *dir);
|
||||
|
||||
/*
|
||||
* Replace the current writable object directory with the specified temporary
|
||||
* object directory; returns the former primary object directory.
|
||||
*/
|
||||
struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
|
||||
|
||||
/*
|
||||
* Restore a previous ODB replaced by set_temporary_main_odb.
|
||||
*/
|
||||
void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
|
||||
|
||||
/*
|
||||
* Populate and return the loose object cache array corresponding to the
|
||||
* given object ID.
|
||||
@ -68,6 +91,9 @@ struct oidtree *odb_loose_cache(struct object_directory *odb,
|
||||
/* Empty the loose object cache for the specified object directory. */
|
||||
void odb_clear_loose_cache(struct object_directory *odb);
|
||||
|
||||
/* Clear and free the specified object directory */
|
||||
void free_object_directory(struct object_directory *odb);
|
||||
|
||||
struct packed_git {
|
||||
struct hashmap_entry packmap_ent;
|
||||
struct packed_git *next;
|
||||
|
2
object.c
2
object.c
@ -513,7 +513,7 @@ struct raw_object_store *raw_object_store_new(void)
|
||||
return o;
|
||||
}
|
||||
|
||||
static void free_object_directory(struct object_directory *odb)
|
||||
void free_object_directory(struct object_directory *odb)
|
||||
{
|
||||
free(odb->path);
|
||||
odb_clear_loose_cache(odb);
|
||||
|
2
refs.c
2
refs.c
@ -2145,7 +2145,7 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
|
||||
break;
|
||||
}
|
||||
|
||||
if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
|
||||
if (refs->repo->objects->odb->disable_ref_updates) {
|
||||
strbuf_addstr(err,
|
||||
_("ref updates forbidden inside quarantine environment"));
|
||||
return -1;
|
||||
|
@ -82,6 +82,8 @@ void repo_set_gitdir(struct repository *repo,
|
||||
expand_base_dir(&repo->objects->odb->path, o->object_dir,
|
||||
repo->commondir, "objects");
|
||||
|
||||
repo->objects->odb->disable_ref_updates = o->disable_ref_updates;
|
||||
|
||||
free(repo->objects->alternate_db);
|
||||
repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
|
||||
expand_base_dir(&repo->graft_file, o->graft_file,
|
||||
|
@ -162,6 +162,7 @@ struct set_gitdir_args {
|
||||
const char *graft_file;
|
||||
const char *index_file;
|
||||
const char *alternate_db;
|
||||
int disable_ref_updates;
|
||||
};
|
||||
|
||||
void repo_set_gitdir(struct repository *repo, const char *root,
|
||||
|
55
tmp-objdir.c
55
tmp-objdir.c
@ -1,5 +1,6 @@
|
||||
#include "cache.h"
|
||||
#include "tmp-objdir.h"
|
||||
#include "chdir-notify.h"
|
||||
#include "dir.h"
|
||||
#include "sigchain.h"
|
||||
#include "string-list.h"
|
||||
@ -11,6 +12,8 @@
|
||||
struct tmp_objdir {
|
||||
struct strbuf path;
|
||||
struct strvec env;
|
||||
struct object_directory *prev_odb;
|
||||
int will_destroy;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -38,6 +41,9 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
|
||||
if (t == the_tmp_objdir)
|
||||
the_tmp_objdir = NULL;
|
||||
|
||||
if (!on_signal && t->prev_odb)
|
||||
restore_primary_odb(t->prev_odb, t->path.buf);
|
||||
|
||||
/*
|
||||
* This may use malloc via strbuf_grow(), but we should
|
||||
* have pre-grown t->path sufficiently so that this
|
||||
@ -52,6 +58,7 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
|
||||
*/
|
||||
if (!on_signal)
|
||||
tmp_objdir_free(t);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -121,7 +128,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,11 +136,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);
|
||||
strvec_init(&t->env);
|
||||
|
||||
strbuf_addf(&t->path, "%s/incoming-XXXXXX", get_object_directory());
|
||||
/*
|
||||
* 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_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix);
|
||||
|
||||
/*
|
||||
* Grow the strbuf beyond any filename we expect to be placed in it.
|
||||
@ -269,6 +281,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());
|
||||
|
||||
@ -292,3 +311,33 @@ 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);
|
||||
}
|
||||
|
29
tmp-objdir.h
29
tmp-objdir.h
@ -10,7 +10,7 @@
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* struct tmp_objdir *t = tmp_objdir_create();
|
||||
* struct tmp_objdir *t = tmp_objdir_create("incoming");
|
||||
* if (!run_command_v_opt_cd_env(cmd, 0, NULL, tmp_objdir_env(t)) &&
|
||||
* !tmp_objdir_migrate(t))
|
||||
* printf("success!\n");
|
||||
@ -22,9 +22,10 @@
|
||||
struct tmp_objdir;
|
||||
|
||||
/*
|
||||
* Create a new temporary object directory; returns NULL on failure.
|
||||
* Create a new temporary object directory with the specified prefix;
|
||||
* returns NULL on failure.
|
||||
*/
|
||||
struct tmp_objdir *tmp_objdir_create(void);
|
||||
struct tmp_objdir *tmp_objdir_create(const char *prefix);
|
||||
|
||||
/*
|
||||
* Return a list of environment strings, suitable for use with
|
||||
@ -51,4 +52,26 @@ int tmp_objdir_destroy(struct tmp_objdir *);
|
||||
*/
|
||||
void tmp_objdir_add_as_alternate(const struct tmp_objdir *);
|
||||
|
||||
/*
|
||||
* Replaces the writable object store in the current process with the temporary
|
||||
* object directory and makes the former main object store an alternate.
|
||||
* If will_destroy is nonzero, the object directory may not be migrated.
|
||||
*/
|
||||
void tmp_objdir_replace_primary_odb(struct tmp_objdir *, int will_destroy);
|
||||
|
||||
/*
|
||||
* If the primary object database was replaced by a temporary object directory,
|
||||
* restore it to its original value while keeping the directory contents around.
|
||||
* Returns NULL if the primary object database was not replaced.
|
||||
*/
|
||||
struct tmp_objdir *tmp_objdir_unapply_primary_odb(void);
|
||||
|
||||
/*
|
||||
* Reapplies the former primary temporary object database, after potentially
|
||||
* changing its relative path.
|
||||
*/
|
||||
void tmp_objdir_reapply_primary_odb(struct tmp_objdir *, const char *old_cwd,
|
||||
const char *new_cwd);
|
||||
|
||||
|
||||
#endif /* TMP_OBJDIR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user