summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/diff.c4
-rw-r--r--src/index.c88
-rw-r--r--src/index.h5
-rw-r--r--src/repository.c3
4 files changed, 80 insertions, 20 deletions
diff --git a/src/diff.c b/src/diff.c
index 02b89b46e..bc8708e33 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -456,10 +456,10 @@ static int maybe_modified(
if (!diff_path_matches_pathspec(diff, oitem->path))
return 0;
- /* on platforms with no symlinks, promote plain files to symlinks */
+ /* on platforms with no symlinks, preserve mode of existing symlinks */
if (S_ISLNK(omode) && S_ISREG(nmode) &&
!(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS))
- nmode = GIT_MODE_TYPE(omode) | (nmode & GIT_MODE_PERMS_MASK);
+ nmode = omode;
/* on platforms with no execmode, just preserve old mode */
if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) &&
diff --git a/src/index.c b/src/index.c
index f1ae9a710..3fedcd27a 100644
--- a/src/index.c
+++ b/src/index.c
@@ -15,6 +15,7 @@
#include "hash.h"
#include "git2/odb.h"
#include "git2/blob.h"
+#include "git2/config.h"
#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
#define short_entry_size(len) entry_size(struct entry_short, len)
@@ -124,11 +125,27 @@ static unsigned int index_create_mode(unsigned int mode)
{
if (S_ISLNK(mode))
return S_IFLNK;
+
if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
return (S_IFLNK | S_IFDIR);
+
return S_IFREG | ((mode & 0100) ? 0755 : 0644);
}
+static unsigned int index_merge_mode(
+ git_index *index, git_index_entry *existing, unsigned int mode)
+{
+ if (index->no_symlinks && S_ISREG(mode) &&
+ existing && S_ISLNK(existing->mode))
+ return existing->mode;
+
+ if (index->distrust_filemode && S_ISREG(mode))
+ return (existing && S_ISREG(existing->mode)) ?
+ existing->mode : index_create_mode(0666);
+
+ return index_create_mode(mode);
+}
+
int git_index_open(git_index **index_out, const char *index_path)
{
git_index *index;
@@ -208,6 +225,45 @@ void git_index_clear(git_index *index)
index->tree = NULL;
}
+int git_index_set_caps(git_index *index, unsigned int caps)
+{
+ assert(index);
+
+ if (caps == GIT_INDEXCAP_FROM_OWNER) {
+ git_config *cfg;
+ int val;
+
+ if (INDEX_OWNER(index) == NULL ||
+ git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0)
+ {
+ giterr_set(GITERR_INDEX,
+ "Cannot get repository config to set index caps");
+ return -1;
+ }
+
+ if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
+ index->ignore_case = (val != 0);
+ if (git_config_get_bool(&val, cfg, "core.filemode") == 0)
+ index->distrust_filemode = (val == 0);
+ if (git_config_get_bool(&val, cfg, "core.symlinks") == 0)
+ index->no_symlinks = (val != 0);
+ }
+ else {
+ index->ignore_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);
+ index->distrust_filemode = ((caps & GIT_INDEXCAP_NO_FILEMODE) != 0);
+ index->no_symlinks = ((caps & GIT_INDEXCAP_NO_SYMLINKS) != 0);
+ }
+
+ return 0;
+}
+
+unsigned int git_index_caps(const git_index *index)
+{
+ return ((index->ignore_case ? GIT_INDEXCAP_IGNORE_CASE : 0) |
+ (index->distrust_filemode ? GIT_INDEXCAP_NO_FILEMODE : 0) |
+ (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0));
+}
+
int git_index_read(git_index *index)
{
int error, updated;
@@ -383,7 +439,7 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
{
size_t path_length;
int position;
- git_index_entry **entry_array;
+ git_index_entry **existing = NULL;
assert(index && entry && entry->path != NULL);
@@ -397,28 +453,24 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
else
entry->flags |= GIT_IDXENTRY_NAMEMASK;;
- /*
- * replacing is not requested: just insert entry at the end;
- * the index is no longer sorted
- */
- if (!replace)
- return git_vector_insert(&index->entries, entry);
-
/* look if an entry with this path already exists */
- position = git_index_find(index, entry->path);
+ if ((position = git_index_find(index, entry->path)) >= 0) {
+ existing = (git_index_entry **)&index->entries.contents[position];
- /*
- * if no entry exists add the entry at the end;
- * the index is no longer sorted
+ /* update filemode to existing values if stat is not trusted */
+ entry->mode = index_merge_mode(index, *existing, entry->mode);
+ }
+
+ /* if replacing is not requested or no existing entry exists, just
+ * insert entry at the end; the index is no longer sorted
*/
- if (position == GIT_ENOTFOUND)
+ if (!replace || !existing)
return git_vector_insert(&index->entries, entry);
/* exists, replace it */
- entry_array = (git_index_entry **) index->entries.contents;
- git__free(entry_array[position]->path);
- git__free(entry_array[position]);
- entry_array[position] = entry;
+ git__free((*existing)->path);
+ git__free(*existing);
+ *existing = entry;
return 0;
}
@@ -475,7 +527,7 @@ int git_index_add2(git_index *index, const git_index_entry *source_entry)
int git_index_append2(git_index *index, const git_index_entry *source_entry)
{
- return index_add2(index, source_entry, 1);
+ return index_add2(index, source_entry, 0);
}
int git_index_remove(git_index *index, int position)
diff --git a/src/index.h b/src/index.h
index 8515f4fcb..a57da5386 100644
--- a/src/index.h
+++ b/src/index.h
@@ -26,6 +26,11 @@ struct git_index {
git_vector entries;
unsigned int on_disk:1;
+
+ unsigned int ignore_case:1;
+ unsigned int distrust_filemode:1;
+ unsigned int no_symlinks:1;
+
git_tree_cache *tree;
git_vector unmerged;
diff --git a/src/repository.c b/src/repository.c
index 4e467e689..4806215e8 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -573,6 +573,9 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
return -1;
GIT_REFCOUNT_OWN(repo->_index, repo);
+
+ if (git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER) < 0)
+ return -1;
}
*out = repo->_index;