int repo_read_index(struct repository *repo) { if (!repo->index) repo->index = xcalloc(1, sizeof(*repo->index)); return read_index_from(repo->index, repo->index_file, repo->gitdir); }
static int print_index (SeafRepo *repo) { char *index_file; struct index_state istate; index_file = g_build_path (PATH_SEPERATOR, SEAF_DIR, "index", repo->id, NULL); memset (&istate, 0, sizeof(istate)); if (read_index_from (&istate, index_file) < 0) { fprintf (stderr, "Corrupt index file %s\n", index_file); return -1; } printf ("Index timestamp: %d\n", istate.timestamp.sec); int i; struct cache_entry *ce; char id[41]; printf ("Totally %u entries in index.\n", istate.cache_nr); for (i = 0; i < istate.cache_nr; ++i) { ce = istate.cache[i]; rawdata_to_hex (ce->sha1, id, 20); printf ("%s\t%s\t%o\t%d\t%d\n", ce->name, id, ce->ce_mode, ce->ce_ctime.sec, ce->ce_mtime.sec); } return 0; }
static int real_merge (SeafRepo *repo, SeafCommit *head, CloneTask *task) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; char *root_id = NULL; int clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { seaf_warning ("Failed to load index.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = task->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = head->creator_name; opts.remote_head = head->commit_id; /* Don't need to check locked files on windows. */ opts.force_merge = TRUE; if (repo->encrypted) { opts.crypt = seafile_crypt_new (repo->enc_version, repo->enc_key, repo->enc_iv); } /* Merge the downloaded branch with the current worktree contents. * EMPTY_SHA1 represents an empty common ancestor tree. */ merge_recursive (&opts, task->root_id, head->root_id, EMPTY_SHA1, &clean, &root_id); g_free (root_id); if (update_index (&istate, index_path) < 0) { seaf_warning ("Failed to update index.\n"); return -1; } /* We only update the worktree and index, but don't commit. * The next auto-commit cycle will check and do that for us. */ discard_index (&istate); g_free (opts.crypt); clear_merge_options (&opts); return 0; }
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix) { int entries, was_valid, newfd; struct lock_file *lock_file; /* * We can't free this memory, it becomes part of a linked list * parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR); entries = read_index_from(index_state, index_path); if (entries < 0) return WRITE_TREE_UNREADABLE_INDEX; if (flags & WRITE_TREE_IGNORE_CACHE_TREE) cache_tree_free(&index_state->cache_tree); if (!index_state->cache_tree) index_state->cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(index_state->cache_tree); if (!was_valid) { if (cache_tree_update(index_state, flags) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { if (!write_locked_index(index_state, lock_file, COMMIT_LOCK)) newfd = -1; } /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller * ends up using the old index with unupdated cache-tree part * it misses the work we did here, but that is just a * performance penalty and not a big deal. */ } if (prefix) { struct cache_tree *subtree; subtree = cache_tree_find(index_state->cache_tree, prefix); if (!subtree) return WRITE_TREE_PREFIX_ERROR; hashcpy(sha1, subtree->sha1); } else hashcpy(sha1, index_state->cache_tree->sha1); if (0 <= newfd) rollback_lock_file(lock_file); return 0; }
int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix) { int entries, was_valid; struct lock_file lock_file = LOCK_INIT; int ret = 0; hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR); entries = read_index_from(index_state, index_path, get_git_dir()); if (entries < 0) { ret = WRITE_TREE_UNREADABLE_INDEX; goto out; } if (flags & WRITE_TREE_IGNORE_CACHE_TREE) cache_tree_free(&index_state->cache_tree); if (!index_state->cache_tree) index_state->cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(index_state->cache_tree); if (!was_valid) { if (cache_tree_update(index_state, flags) < 0) { ret = WRITE_TREE_UNMERGED_INDEX; goto out; } write_locked_index(index_state, &lock_file, COMMIT_LOCK); /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller * ends up using the old index with unupdated cache-tree part * it misses the work we did here, but that is just a * performance penalty and not a big deal. */ } if (prefix) { struct cache_tree *subtree; subtree = cache_tree_find(index_state->cache_tree, prefix); if (!subtree) { ret = WRITE_TREE_PREFIX_ERROR; goto out; } oidcpy(oid, &subtree->oid); } else oidcpy(oid, &index_state->cache_tree->oid); out: rollback_lock_file(&lock_file); return ret; }
/* * Get the new blocks that need to be checked out if we ff to @remote. */ static int get_new_blocks_ff (SeafRepo *repo, SeafCommit *head, SeafCommit *remote, BlockList **bl) { SeafRepoManager *mgr = repo->manager; char index_path[SEAF_PATH_MAX]; struct tree_desc trees[2]; struct unpack_trees_options topts; struct index_state istate; int ret = 0; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("Failed to load index.\n"); return -1; } fill_tree_descriptor (&trees[0], head->root_id); fill_tree_descriptor (&trees[1], remote->root_id); memset(&topts, 0, sizeof(topts)); topts.base = repo->worktree; topts.head_idx = -1; topts.src_index = &istate; topts.update = 1; topts.merge = 1; topts.fn = twoway_merge; /* unpack_trees() doesn't update index or worktree. */ if (unpack_trees (2, trees, &topts) < 0) { g_warning ("Failed to ff to commit %s.\n", remote->commit_id); ret = -1; goto out; } *bl = block_list_new (); collect_new_blocks_from_index (&topts.result, *bl); out: tree_desc_free (&trees[0]); tree_desc_free (&trees[1]); discard_index (&istate); discard_index (&topts.result); return ret; }
static int validate_repo_index(SeafRepo *repo) { if (!repo) return -1; g_message("Checking for index\n"); char index_path[SEAF_PATH_MAX]; struct index_state istate; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", seaf->repo_mgr->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("[ERROR] Failed to validate index for repo %s\n", repo->id); return -1; } return 0; }
static void validate_no_submodules(const struct worktree *wt) { struct index_state istate = { NULL }; int i, found_submodules = 0; if (read_index_from(&istate, worktree_git_path(wt, "index"), get_worktree_git_dir(wt)) > 0) { for (i = 0; i < istate.cache_nr; i++) { struct cache_entry *ce = istate.cache[i]; if (S_ISGITLINK(ce->ce_mode)) { found_submodules = 1; break; } } } discard_index(&istate); if (found_submodules) die(_("working trees containing submodules cannot be moved or removed")); }
/* * Get the new blocks that need to be checked out if we do a real merge. */ static int get_new_blocks_merge (SeafRepo *repo, SeafCommit *head, SeafCommit *remote, SeafCommit *common, BlockList **bl) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; int ret, clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("Failed to load index.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = repo->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = remote->creator_name; opts.collect_blocks_only = TRUE; *bl = block_list_new(); opts.bl = *bl; ret = merge_recursive (&opts, head->root_id, remote->root_id, common->root_id, &clean, NULL); clear_merge_options (&opts); discard_index (&istate); return ret; }
static int fast_forward_checkout (SeafRepo *repo, SeafCommit *head, CloneTask *task) { SeafRepoManager *mgr = repo->manager; char index_path[SEAF_PATH_MAX]; struct tree_desc trees[2]; struct unpack_trees_options topts; struct index_state istate; int ret = 0; if (strcmp (head->root_id, task->root_id) == 0) return 0; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { seaf_warning ("Failed to load index.\n"); return -1; } repo->index_corrupted = FALSE; fill_tree_descriptor (&trees[0], task->root_id); fill_tree_descriptor (&trees[1], head->root_id); memset(&topts, 0, sizeof(topts)); topts.base = task->worktree; topts.head_idx = -1; topts.src_index = &istate; topts.update = 1; topts.merge = 1; topts.fn = twoway_merge; if (repo->encrypted) { topts.crypt = seafile_crypt_new (repo->enc_version, repo->enc_key, repo->enc_iv); } if (unpack_trees (2, trees, &topts) < 0) { seaf_warning ("Failed to merge commit %s with work tree.\n", head->commit_id); ret = -1; goto out; } if (update_worktree (&topts, FALSE, head->commit_id, head->creator_name, NULL) < 0) { seaf_warning ("Failed to update worktree.\n"); ret = -1; goto out; } discard_index (&istate); istate = topts.result; if (update_index (&istate, index_path) < 0) { seaf_warning ("Failed to update index.\n"); } out: tree_desc_free (&trees[0]); tree_desc_free (&trees[1]); g_free (topts.crypt); discard_index (&istate); return ret; }
static int do_real_merge (SeafRepo *repo, SeafBranch *head_branch, SeafCommit *head, SeafBranch *remote_branch, SeafCommit *remote, SeafCommit *common, gboolean recover_merge, char **error) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; char *root_id = NULL; SeafCommit *merged; int ret = 0, clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("Failed to load index.\n"); *error = g_strdup ("Internal error.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = repo->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = remote->creator_name; opts.remote_head = remote->commit_id; opts.recover_merge = recover_merge; if (repo->encrypted) { opts.crypt = seafile_crypt_new (repo->enc_version, repo->enc_key, repo->enc_iv); } ret = merge_recursive (&opts, head->root_id, remote->root_id, common->root_id, &clean, &root_id); if (ret < 0) goto out; if (update_index (&istate, index_path) < 0) { *error = g_strdup ("Internal error.\n"); ret = -1; goto out; } if (clean) { merged = seaf_commit_new (NULL, repo->id, root_id, repo->email ? repo->email : seaf->session->base.user_name, seaf->session->base.id, "Auto merge by seafile system", 0); merged->parent_id = g_strdup(head->commit_id); merged->second_parent_id = g_strdup(remote->commit_id); seaf_repo_to_commit (repo, merged); if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged) < 0) { seaf_commit_unref (merged); *error = g_strdup ("Internal error.\n"); ret = -1; goto out; } seaf_branch_set_commit (head_branch, merged->commit_id); seaf_branch_manager_update_branch (seaf->branch_mgr, head_branch); g_debug ("Auto merged.\n"); seaf_commit_unref (merged); } else { ret = -1; g_debug ("Auto merge failed.\n"); } out: if (root_id) g_free (root_id); g_free (opts.crypt); clear_merge_options (&opts); discard_index (&istate); return ret; }