* [PATCH 04/12] Protect index with sparse prefix
@ 2008-07-23 14:56 Nguyễn Thái Ngọc Duy
0 siblings, 0 replies; only message in thread
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:56 UTC (permalink / raw)
To: git
This ensures no one can write to index outside sparse prefix.
Protection is usually applied to the_index only. For more
complicated cases where temporary index is required, thorough
check will be done by check_index_prefix()
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-commit.c | 11 +++++
builtin-ls-files.c | 2 +
builtin-merge-recursive.c | 4 +-
builtin-read-tree.c | 5 ++
cache.h | 1 +
diff-lib.c | 3 +
read-cache.c | 107 ++++++++++++++++++++++++++++++++++++++++++++-
unpack-trees.c | 3 +
unpack-trees.h | 3 +-
9 files changed, 135 insertions(+), 4 deletions(-)
diff --git a/builtin-commit.c b/builtin-commit.c
index 97e64de..f2d301a 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -223,6 +223,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
int fd;
struct string_list partial;
const char **pathspec = NULL;
+ char **saved_sparse_prefix;
if (interactive) {
interactive_add(argc, argv, prefix);
@@ -306,6 +307,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
memset(&partial, 0, sizeof(partial));
partial.strdup_strings = 1;
+
+ /*
+ * this code modifies index but won't write down anything
+ * so it's safe to turn of sparse_prefix protection for a while
+ */
+ saved_sparse_prefix = save_sparse_prefix();
+
if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec))
exit(1);
@@ -313,6 +321,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die("cannot read the index");
+ /* re-enable sparse_prefix again */
+ restore_sparse_prefix(saved_sparse_prefix);
+
fd = hold_locked_index(&index_lock, 1);
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index e8d568e..4d18873 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -606,6 +606,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
*/
if (show_stage || show_unmerged)
die("ls-files --with-tree is incompatible with -s or -u");
+ /* no need to restore as ls-files never writes index */
+ save_sparse_prefix();
overlay_tree_on_cache(with_tree, prefix);
}
show_files(&dir, prefix);
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 43e55bf..7ce015b 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -201,8 +201,10 @@ static int git_merge_trees(int index_only,
memset(&opts, 0, sizeof(opts));
if (index_only)
opts.index_only = 1;
- else
+ else {
opts.update = 1;
+ opts.check_index_prefix = 1;
+ }
opts.merge = 1;
opts.head_idx = 2;
opts.fn = threeway_merge;
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 72a6de3..0883b41 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -218,6 +218,11 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
opts.head_idx = 1;
}
+ if (get_sparse_prefix()) {
+ read_cache();
+ opts.check_index_prefix = 1;
+ }
+
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
parse_tree(tree);
diff --git a/cache.h b/cache.h
index 4687096..f6bbadc 100644
--- a/cache.h
+++ b/cache.h
@@ -331,6 +331,7 @@ extern char **split_prefix(const char *env);
extern char **combine_prefix_list(char **p1, char **p2);
extern void free_prefix_list(char **prefix_list);
extern int outside_prefix_list(char **iprefix, const char *prefix);
+extern int check_index_prefix(const struct index_state *index, int is_merge);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
diff --git a/diff-lib.c b/diff-lib.c
index e7eaff9..2908146 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -73,6 +73,9 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
struct cache_entry *ce = active_cache[i];
int changed;
+ if (index_outside_sparse_prefix(ce->name))
+ continue;
+
if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
break;
diff --git a/read-cache.c b/read-cache.c
index a50a851..4fea40e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -23,6 +23,11 @@
struct index_state the_index;
+static int outside_cache_prefix(const struct index_state *istate, const char *ce_name)
+{
+ return istate == &the_index && index_outside_sparse_prefix(ce_name);
+}
+
static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
{
istate->cache[nr] = ce;
@@ -396,6 +401,8 @@ int remove_index_entry_at(struct index_state *istate, int pos)
{
struct cache_entry *ce = istate->cache[pos];
+ if (outside_cache_prefix(istate, ce->name))
+ die("%s: cannot remove from index outside %s", ce->name, get_sparse_prefix_str());
remove_name_hash(ce);
istate->cache_changed = 1;
istate->cache_nr--;
@@ -410,6 +417,10 @@ int remove_index_entry_at(struct index_state *istate, int pos)
int remove_file_from_index(struct index_state *istate, const char *path)
{
int pos = index_name_pos(istate, path, strlen(path));
+
+ if (outside_cache_prefix(istate, path))
+ die("%s: cannot remove from index from outside %s", path, get_sparse_prefix_str());
+
if (pos < 0)
pos = -pos-1;
cache_tree_invalidate_path(istate->cache_tree, path);
@@ -809,21 +820,43 @@ static int check_file_directory_conflict(struct index_state *istate,
return retval + has_dir_name(istate, ce, pos, ok_to_replace);
}
+/*
+ * ce_compare only considers stuff that will be written to a tree object
+ * or index stages
+ *
+ * On CE_* flags CE_HASHED, CE_UNHASHED and CE_UPTODATE are out because they
+ * are in-core only, will not be written out
+ */
+#define CE_COMPARE_MASK (CE_STATE_MASK | CE_UPTODATE)
+static int ce_compare(const struct cache_entry *ce1, const struct cache_entry *ce2)
+{
+ return ce1->ce_mode == ce2->ce_mode &&
+ ((ce1->ce_flags ^ ce2->ce_flags) & ~CE_COMPARE_MASK) == 0 &&
+ !memcmp(ce1->sha1, ce2->sha1, 20) &&
+ !strcmp(ce1->name, ce2->name);
+}
+
static int add_index_entry_with_check(struct index_state *istate, struct cache_entry *ce, int option)
{
int pos;
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
+ int is_outside = outside_cache_prefix(istate, ce->name);
cache_tree_invalidate_path(istate->cache_tree, ce->name);
pos = index_name_pos(istate, ce->name, ce->ce_flags);
/* existing match? Just replace it. */
if (pos >= 0) {
+ if (is_outside && !ce_compare(istate->cache[pos], ce))
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
replace_index_entry(istate, pos, ce);
return 0;
}
+
+ if (is_outside)
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
pos = -pos-1;
/*
@@ -858,9 +891,11 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
{
int pos;
- if (option & ADD_CACHE_JUST_APPEND)
+ if (option & ADD_CACHE_JUST_APPEND) {
+ if (outside_cache_prefix(istate, ce->name))
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
pos = istate->cache_nr;
- else {
+ } else {
int ret;
ret = add_index_entry_with_check(istate, ce, option);
if (ret <= 0)
@@ -1444,3 +1479,71 @@ int read_index_unmerged(struct index_state *istate)
istate->cache_nr = dst - istate->cache;
return !!last;
}
+
+int check_index_prefix(const struct index_state *index, int is_merge)
+{
+ unsigned i;
+ char **index_prefix = get_sparse_prefix();
+
+ if (!index_prefix)
+ return 1;
+
+ /* Check for unmerged entries first */
+ for (i = 0; i < index->cache_nr; i++) {
+ struct cache_entry *ce = index->cache[i];
+ if (ce_stage(ce) && index_outside_sparse_prefix(ce->name))
+ return 0;
+ }
+
+ /*
+ * if is_merge is true, caller has decided that there
+ * could be changes outside index prefix, return now
+ */
+ if (is_merge)
+ return 1;
+ else {
+ const struct index_state *idx[2];
+ int prefix_i[2];
+ int index_prefix_nr;
+ unsigned entry_i[2];
+
+ idx[0] = &the_index;
+ idx[1] = index;
+ prefix_i[0] = prefix_i[1] = 0;
+ entry_i[0] = entry_i[1] = 0;
+ index_prefix_nr = 0;
+ while (index_prefix[index_prefix_nr])
+ index_prefix_nr++;
+
+ while (entry_i[0] < idx[0]->cache_nr &&
+ entry_i[1] < idx[1]->cache_nr) {
+ /* ignore anything inside index prefix */
+ int what_index;
+ for (what_index = 0; what_index < 2; what_index++) {
+ const struct index_state *idx_p = idx[what_index];
+ const char *prefix = index_prefix[prefix_i[what_index]];
+ unsigned *entry_ip = entry_i+what_index;
+ if (prefix_i[what_index] < index_prefix_nr &&
+ !prefixcmp(idx_p->cache[*entry_ip]->name, prefix)) {
+ while (*entry_ip < idx_p->cache_nr &&
+ !prefixcmp(idx_p->cache[*entry_ip]->name, prefix))
+ entry_ip[0]++;
+ prefix_i[what_index]++;
+ }
+ }
+
+ if (entry_i[0] == idx[0]->cache_nr || entry_i[1] == idx[1]->cache_nr)
+ break;
+
+ /* does not match */
+ if (!ce_compare(idx[0]->cache[entry_i[0]], idx[1]->cache[entry_i[1]]))
+ return 0;
+
+ entry_i[0]++;
+ entry_i[1]++;
+ }
+
+ return entry_i[0] == idx[0]->cache_nr &&
+ entry_i[1] == idx[1]->cache_nr;
+ }
+}
diff --git a/unpack-trees.c b/unpack-trees.c
index cba0aca..0a6723b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -408,6 +408,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->trivial_merges_only && o->nontrivial_merge)
return unpack_failed(o, "Merge requires file-level merging");
+ if (o->check_index_prefix && !check_index_prefix(&o->result, o->merge && !o->prefix))
+ return unpack_failed(o, "Merge outside index prefix");
+
o->src_index = NULL;
ret = check_updates(o) ? (-2) : 0;
if (o->dst_index)
diff --git a/unpack-trees.h b/unpack-trees.h
index 94e5672..a1b46f9 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -26,7 +26,8 @@ struct unpack_trees_options {
verbose_update:1,
aggressive:1,
skip_unmerged:1,
- gently:1;
+ gently:1,
+ check_index_prefix:1;
const char *prefix;
int pos;
struct dir_struct *dir;
--
1.5.5.GIT
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2008-07-23 14:57 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-23 14:56 [PATCH 04/12] Protect index with sparse prefix Nguyễn Thái Ngọc Duy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).