Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-10-08 23:45:43 +0400
committerRussell Belfer <rb@github.com>2013-10-08 23:45:43 +0400
commit14997dc5f69e7ceebe502b32087d809a8482bf78 (patch)
treeff245ed60887dc4eddd3b3ea65e7dd215deeeb62
parent5173ea921d4ccbbe7d61ddce9a0920c2e1c82035 (diff)
More filemode cleanups for FAT on MacOS
This cleans up some additional issues. The main change is that on a filesystem that doesn't support mode bits, libgit2 will now create new blobs with GIT_FILEMODE_BLOB always instead of being at the mercy to the filesystem driver to report executable or not. This means that if "core.filemode" lies and claims that filemode is not supported, then we will ignore the executable bit from the filesystem. Previously we would have allowed it. This adds an option to the new git_repository_reset_filesystem to recurse through submodules if desired. There may be other types of APIs that would like a "recurse submodules" option, but this one is particularly useful. This also has a number of cleanups, etc., for related things including trying to give better error messages when problems come up from the filesystem. For example, the FAT filesystem driver on MacOS appears to return errno EINVAL if you attempt to write a filename with invalid UTF-8 in it. We try to capture that with a better error message now.
-rw-r--r--include/git2/repository.h4
-rw-r--r--src/checkout.c3
-rw-r--r--src/errors.c1
-rw-r--r--src/fileops.c85
-rw-r--r--src/index.c8
-rw-r--r--src/index.h2
-rw-r--r--src/iterator.c2
-rw-r--r--src/path.c33
-rw-r--r--src/path.h4
-rw-r--r--src/repository.c185
-rw-r--r--src/submodule.c3
-rw-r--r--src/win32/posix_w32.c4
-rw-r--r--tests-clar/clar_libgit2.c2
-rw-r--r--tests-clar/diff/patch.c4
-rw-r--r--tests-clar/diff/workdir.c11
-rw-r--r--tests-clar/index/addall.c5
-rw-r--r--tests-clar/index/filemodes.c24
-rw-r--r--tests-clar/refs/unicode.c23
-rw-r--r--tests-clar/submodule/lookup.c15
-rw-r--r--tests-clar/submodule/modify.c15
-rw-r--r--tests-clar/submodule/submodule_helpers.c4
21 files changed, 236 insertions, 201 deletions
diff --git a/include/git2/repository.h b/include/git2/repository.h
index 74ab65bf7..28d8400f2 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -299,10 +299,12 @@ GIT_EXTERN(int) git_repository_init_ext(
* properties to compensate for the current filesystem of the repo.
*
* @param repo A repository object
+ * @param recurse_submodules Should submodules be reset recursively
* @returrn 0 on success, < 0 on error
*/
GIT_EXTERN(int) git_repository_reset_filesystem(
- git_repository *repo);
+ git_repository *repo,
+ int recurse_submodules);
/**
* Retrieve and resolve the reference pointed at by HEAD.
diff --git a/src/checkout.c b/src/checkout.c
index 5d741d393..d3f673d40 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -783,7 +783,8 @@ static int checkout_update_index(
memset(&entry, 0, sizeof(entry));
entry.path = (char *)file->path; /* cast to prevent warning */
- git_index_entry__init_from_stat(&entry, st);
+ git_index_entry__init_from_stat(
+ &entry, st, !(git_index_caps(data->index) & GIT_INDEXCAP_NO_FILEMODE));
git_oid_cpy(&entry.oid, &file->oid);
return git_index_add(data->index, &entry);
diff --git a/src/errors.c b/src/errors.c
index e2629f69e..c9d9e4e37 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -116,4 +116,3 @@ const git_error *giterr_last(void)
{
return GIT_GLOBAL->last_error;
}
-
diff --git a/src/fileops.c b/src/fileops.c
index be2e53ca8..63aedc6d0 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -78,11 +78,8 @@ int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, con
int git_futils_open_ro(const char *path)
{
int fd = p_open(path, O_RDONLY);
- if (fd < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
- fd = GIT_ENOTFOUND;
- giterr_set(GITERR_OS, "Failed to open '%s'", path);
- }
+ if (fd < 0)
+ return git_path_set_error(errno, path, "open");
return fd;
}
@@ -138,7 +135,6 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
int git_futils_readbuffer_updated(
git_buf *buf, const char *path, time_t *mtime, size_t *size, int *updated)
{
- int error = 0;
git_file fd;
struct stat st;
bool changed = false;
@@ -148,13 +144,8 @@ int git_futils_readbuffer_updated(
if (updated != NULL)
*updated = 0;
- if (p_stat(path, &st) < 0) {
- error = errno;
- giterr_set(GITERR_OS, "Failed to stat '%s'", path);
- if (error == ENOENT || error == ENOTDIR)
- return GIT_ENOTFOUND;
- return -1;
- }
+ if (p_stat(path, &st) < 0)
+ return git_path_set_error(errno, path, "stat");
if (S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
@@ -441,66 +432,60 @@ static int futils__rm_first_parent(git_buf *path, const char *ceiling)
static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
{
- struct stat st;
futils__rmdir_data *data = opaque;
+ int error = data->error;
+ struct stat st;
- if (data->depth > FUTILS_MAX_DEPTH) {
- data->error =
- futils__error_cannot_rmdir(path->ptr, "directory nesting too deep");
- }
+ if (data->depth > FUTILS_MAX_DEPTH)
+ error = futils__error_cannot_rmdir(
+ path->ptr, "directory nesting too deep");
- else if ((data->error = p_lstat_posixly(path->ptr, &st)) < 0) {
+ else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) {
if (errno == ENOENT)
- data->error = 0;
+ error = 0;
else if (errno == ENOTDIR) {
/* asked to remove a/b/c/d/e and a/b is a normal file */
if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0)
- data->error = futils__rm_first_parent(path, data->base);
+ error = futils__rm_first_parent(path, data->base);
else
futils__error_cannot_rmdir(
path->ptr, "parent is not directory");
}
else
- futils__error_cannot_rmdir(path->ptr, "cannot access");
+ error = git_path_set_error(errno, path->ptr, "rmdir");
}
else if (S_ISDIR(st.st_mode)) {
data->depth++;
- {
- int error =
- git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
- if (error < 0)
- return (error == GIT_EUSER) ? data->error : error;
- }
+ error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
+ if (error < 0)
+ return (error == GIT_EUSER) ? data->error : error;
data->depth--;
if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0)
return data->error;
- data->error = p_rmdir(path->ptr);
-
- if (data->error < 0) {
+ if ((error = p_rmdir(path->ptr)) < 0) {
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
(errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY))
- data->error = 0;
+ error = 0;
else
- futils__error_cannot_rmdir(path->ptr, NULL);
+ error = git_path_set_error(errno, path->ptr, "rmdir");
}
}
else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) {
- data->error = p_unlink(path->ptr);
-
- if (data->error < 0)
- futils__error_cannot_rmdir(path->ptr, "cannot be removed");
+ if (p_unlink(path->ptr) < 0)
+ error = git_path_set_error(errno, path->ptr, "remove");
}
else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0)
- data->error = futils__error_cannot_rmdir(path->ptr, "still present");
+ error = futils__error_cannot_rmdir(path->ptr, "still present");
- return data->error;
+ data->error = error;
+ return error;
}
static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
@@ -523,7 +508,7 @@ static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
giterr_clear();
error = GIT_ITEROVER;
} else {
- futils__error_cannot_rmdir(git_buf_cstr(path), NULL);
+ error = git_path_set_error(errno, git_buf_cstr(path), "rmdir");
}
}
@@ -818,11 +803,8 @@ int git_futils_cp(const char *from, const char *to, mode_t filemode)
return ifd;
if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
- ofd = GIT_ENOTFOUND;
- giterr_set(GITERR_OS, "Failed to open '%s' for writing", to);
p_close(ifd);
- return ofd;
+ return git_path_set_error(errno, to, "open for writing");
}
return cp_by_fd(ifd, ofd, true);
@@ -905,15 +887,14 @@ static int _cp_r_callback(void *ref, git_buf *from)
goto exit;
}
- if (p_lstat(info->to.ptr, &to_st) < 0) {
- if (errno != ENOENT && errno != ENOTDIR) {
- giterr_set(GITERR_OS,
- "Could not access %s while copying files", info->to.ptr);
- error = -1;
- goto exit;
- }
- } else
+ if (!(error = git_path_lstat(info->to.ptr, &to_st)))
exists = true;
+ else if (error != GIT_ENOTFOUND)
+ goto exit;
+ else {
+ giterr_clear();
+ error = 0;
+ }
if ((error = git_path_lstat(from->ptr, &from_st)) < 0)
goto exit;
diff --git a/src/index.c b/src/index.c
index 21a8d31d1..06394e6db 100644
--- a/src/index.c
+++ b/src/index.c
@@ -579,7 +579,8 @@ const git_index_entry *git_index_get_bypath(
return git_index_get_byindex(index, pos);
}
-void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st)
+void git_index_entry__init_from_stat(
+ git_index_entry *entry, struct stat *st, bool trust_mode)
{
entry->ctime.seconds = (git_time_t)st->st_ctime;
entry->mtime.seconds = (git_time_t)st->st_mtime;
@@ -587,7 +588,8 @@ void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st)
/* entry->ctime.nanoseconds = st->st_ctimensec; */
entry->dev = st->st_rdev;
entry->ino = st->st_ino;
- entry->mode = index_create_mode(st->st_mode);
+ entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
+ index_create_mode(0666) : index_create_mode(st->st_mode);
entry->uid = st->st_uid;
entry->gid = st->st_gid;
entry->file_size = st->st_size;
@@ -631,7 +633,7 @@ static int index_entry_init(
entry = git__calloc(1, sizeof(git_index_entry));
GITERR_CHECK_ALLOC(entry);
- git_index_entry__init_from_stat(entry, &st);
+ git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
entry->oid = oid;
entry->path = git__strdup(rel_path);
diff --git a/src/index.h b/src/index.h
index 40577e105..4c448fabf 100644
--- a/src/index.h
+++ b/src/index.h
@@ -48,7 +48,7 @@ struct git_index_conflict_iterator {
};
extern void git_index_entry__init_from_stat(
- git_index_entry *entry, struct stat *st);
+ git_index_entry *entry, struct stat *st, bool trust_mode);
extern size_t git_index__prefix_position(git_index *index, const char *path);
diff --git a/src/iterator.c b/src/iterator.c
index ea6b45e88..c0d7862ff 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1175,7 +1175,7 @@ static int fs_iterator__update_entry(fs_iterator *fi)
return GIT_ITEROVER;
fi->entry.path = ps->path;
- git_index_entry__init_from_stat(&fi->entry, &ps->st);
+ git_index_entry__init_from_stat(&fi->entry, &ps->st, true);
/* need different mode here to keep directories during iteration */
fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode);
diff --git a/src/path.c b/src/path.c
index 27abd062b..d45751cd1 100644
--- a/src/path.c
+++ b/src/path.c
@@ -538,16 +538,35 @@ bool git_path_is_empty_dir(const char *path)
#endif
-int git_path_lstat(const char *path, struct stat *st)
+int git_path_set_error(int errno_value, const char *path, const char *action)
{
- int err = 0;
-
- if (p_lstat(path, st) < 0) {
- err = (errno == ENOENT) ? GIT_ENOTFOUND : -1;
- giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
+ switch (errno_value) {
+ case ENOENT:
+ case ENOTDIR:
+ giterr_set(GITERR_OS, "Could not find '%s' to %s", path, action);
+ return GIT_ENOTFOUND;
+
+ case EINVAL:
+ case ENAMETOOLONG:
+ giterr_set(GITERR_OS, "Invalid path for filesystem '%s'", path);
+ return GIT_EINVALIDSPEC;
+
+ case EEXIST:
+ giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path);
+ return GIT_EEXISTS;
+
+ default:
+ giterr_set(GITERR_OS, "Could not %s '%s'", action, path);
+ return -1;
}
+}
+
+int git_path_lstat(const char *path, struct stat *st)
+{
+ if (p_lstat(path, st) == 0)
+ return 0;
- return err;
+ return git_path_set_error(errno, path, "stat");
}
static bool _check_dir_contents(
diff --git a/src/path.h b/src/path.h
index 2cfd714cd..175756938 100644
--- a/src/path.h
+++ b/src/path.h
@@ -358,6 +358,10 @@ extern int git_path_dirload_with_stat(
const char *end_stat,
git_vector *contents);
+/* translate errno to libgit2 error code and set error message */
+extern int git_path_set_error(
+ int errno_value, const char *path, const char *action);
+
/* check if non-ascii characters are present in filename */
extern bool git_path_has_non_ascii(const char *path, size_t pathlen);
diff --git a/src/repository.c b/src/repository.c
index 52509ffc1..23cafe05a 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -961,80 +961,121 @@ static int create_empty_file(const char *path, mode_t mode)
return 0;
}
-static int repo_init_config(
- git_config *parent,
- const char *repo_dir,
- const char *work_dir,
- uint32_t flags,
- uint32_t mode)
+static int repo_local_config(
+ git_config **out,
+ git_buf *config_dir,
+ git_repository *repo,
+ const char *repo_dir)
{
int error = 0;
- git_buf buf = GIT_BUF_INIT;
- const char *cfg_path = NULL;
- git_config *config = NULL;
- bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
+ git_config *parent;
+ const char *cfg_path;
-#define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\
- if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
- goto cleanup; } while (0)
-
- if (git_buf_joinpath(&buf, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
+ if (git_buf_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
return -1;
- cfg_path = git_buf_cstr(&buf);
+ cfg_path = git_buf_cstr(config_dir);
+ /* make LOCAL config if missing */
if (!git_path_isfile(cfg_path) &&
(error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
- goto cleanup;
+ return error;
- if (!parent)
- error = git_config_open_ondisk(&config, cfg_path);
- else if ((error = git_config_open_level(
- &config, parent, GIT_CONFIG_LEVEL_LOCAL)) < 0)
- {
+ /* if no repo, just open that file directly */
+ if (!repo)
+ return git_config_open_ondisk(out, cfg_path);
+
+ /* otherwise, open parent config and get that level */
+ if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
+ return error;
+
+ if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
giterr_clear();
if (!(error = git_config_add_file_ondisk(
parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false)))
- error = git_config_open_level(
- &config, parent, GIT_CONFIG_LEVEL_LOCAL);
+ error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
}
- if (error < 0)
- goto cleanup;
- if ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0 &&
- (error = check_repositoryformatversion(config)) < 0)
- goto cleanup;
+ git_config_free(parent);
+
+ return error;
+}
+
+static int repo_init_fs_configs(
+ git_config *cfg,
+ const char *cfg_path,
+ const char *repo_dir,
+ const char *work_dir,
+ bool update_ignorecase)
+{
+ int error = 0;
+
+ if (!work_dir)
+ work_dir = repo_dir;
+
+ if ((error = git_config_set_bool(
+ cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
+ return error;
+
+ if (!are_symlinks_supported(work_dir)) {
+ if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
+ return error;
+ } else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
+ giterr_clear();
- SET_REPO_CONFIG(
- bool, "core.bare", is_bare);
- SET_REPO_CONFIG(
- int32, "core.repositoryformatversion", GIT_REPO_VERSION);
- SET_REPO_CONFIG(
- bool, "core.filemode", is_chmod_supported(cfg_path));
+ if (update_ignorecase) {
+ if (is_filesystem_case_insensitive(repo_dir)) {
+ if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
+ return error;
+ } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
+ giterr_clear();
+ }
#ifdef GIT_USE_ICONV
- SET_REPO_CONFIG(
- bool, "core.precomposeunicode",
- does_fs_decompose_unicode_paths(is_bare ? repo_dir : work_dir));
+ if ((error = git_config_set_bool(
+ cfg, "core.precomposeunicode",
+ does_fs_decompose_unicode_paths(work_dir))) < 0)
+ return error;
#endif
- if (!are_symlinks_supported(is_bare ? repo_dir : work_dir))
- SET_REPO_CONFIG(bool, "core.symlinks", false);
+ return 0;
+}
- /* core git does not do this on a reinit, but it is a property of
- * the filesystem, so I think we should...
- */
- if (!(flags & GIT_REPOSITORY_INIT__IS_REINIT) &&
- is_filesystem_case_insensitive(repo_dir))
- SET_REPO_CONFIG(bool, "core.ignorecase", true);
+static int repo_init_config(
+ const char *repo_dir,
+ const char *work_dir,
+ uint32_t flags,
+ uint32_t mode)
+{
+ int error = 0;
+ git_buf cfg_path = GIT_BUF_INIT;
+ git_config *config = NULL;
+ bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
+ bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
+
+ if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
+ goto cleanup;
+
+ if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
+ goto cleanup;
+
+#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
+ if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
+ goto cleanup; } while (0)
+
+ SET_REPO_CONFIG(bool, "core.bare", is_bare);
+ SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
+
+ if ((error = repo_init_fs_configs(
+ config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
+ goto cleanup;
if (!is_bare) {
SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
- if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
+ if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD))
SET_REPO_CONFIG(string, "core.worktree", work_dir);
- }
- else if ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0) {
+ else if (is_reinit) {
if (git_config_delete_entry(config, "core.worktree") < 0)
giterr_clear();
}
@@ -1050,38 +1091,44 @@ static int repo_init_config(
}
cleanup:
- git_buf_free(&buf);
+ git_buf_free(&cfg_path);
git_config_free(config);
return error;
}
-int git_repository_reset_filesystem(git_repository *repo)
+static int repo_reset_submodule_fs(git_submodule *sm, const char *n, void *p)
{
- int error = 0;
- uint32_t flags = 0;
- const char *repo_dir, *work_dir;
- git_config *cfg;
+ git_repository *smrepo = NULL;
+ GIT_UNUSED(n); GIT_UNUSED(p);
- assert(repo);
+ if (git_submodule_open(&smrepo, sm) < 0 ||
+ git_repository_reset_filesystem(smrepo, true) < 0)
+ giterr_clear();
+ git_repository_free(smrepo);
- repo_dir = git_repository_path(repo);
- work_dir = git_repository_workdir(repo);
+ return 0;
+}
- if (git_repository_is_bare(repo))
- flags |= GIT_REPOSITORY_INIT_BARE;
- else if (!git__prefixcmp(repo_dir, work_dir) &&
- !strcmp(repo_dir + strlen(work_dir), DOT_GIT "/"))
- flags |= GIT_REPOSITORY_INIT__NATURAL_WD;
+int git_repository_reset_filesystem(git_repository *repo, int recurse)
+{
+ int error = 0;
+ git_buf path = GIT_BUF_INIT;
+ git_config *config = NULL;
+ const char *repo_dir = git_repository_path(repo);
- if ((error = git_repository_config(&cfg, repo)) < 0)
- return error;
+ if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
+ error = repo_init_fs_configs(
+ config, path.ptr, repo_dir, git_repository_workdir(repo), true);
- error = repo_init_config(cfg, repo_dir, work_dir, flags, 0);
+ git_config_free(config);
+ git_buf_free(&path);
- git_config_free(cfg);
git_repository__cvar_cache_clear(repo);
+ if (!repo->is_bare && recurse)
+ (void)git_submodule_foreach(repo, repo_reset_submodule_fs, NULL);
+
return error;
}
@@ -1473,7 +1520,7 @@ int git_repository_init_ext(
opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
error = repo_init_config(
- NULL, repo_path.ptr, wd_path.ptr, opts->flags, opts->mode);
+ repo_path.ptr, wd_path.ptr, opts->flags, opts->mode);
/* TODO: reinitialize the templates */
}
@@ -1481,7 +1528,7 @@ int git_repository_init_ext(
if (!(error = repo_init_structure(
repo_path.ptr, wd_path.ptr, opts)) &&
!(error = repo_init_config(
- NULL, repo_path.ptr, wd_path.ptr, opts->flags, opts->mode)))
+ repo_path.ptr, wd_path.ptr, opts->flags, opts->mode)))
error = repo_init_create_head(
repo_path.ptr, opts->initial_head);
}
diff --git a/src/submodule.c b/src/submodule.c
index 121383b9c..12ade83fe 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -372,7 +372,8 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
memset(&entry, 0, sizeof(entry));
entry.path = sm->path;
- git_index_entry__init_from_stat(&entry, &st);
+ git_index_entry__init_from_stat(
+ &entry, &st, !(git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE));
/* calling git_submodule_open will have set sm->wd_oid if possible */
if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 2f490529c..18f717b0f 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -125,8 +125,8 @@ static int do_lstat(
errno = ENOENT;
- /* We need POSIX behavior, then ENOTDIR must set when any of the folders in the
- * file path is a regular file,otherwise ENOENT must be set.
+ /* To match POSIX behavior, set ENOTDIR when any of the folders in the
+ * file path is a regular file, otherwise set ENOENT.
*/
if (posix_enotdir) {
/* scan up path until we find an existing item */
diff --git a/tests-clar/clar_libgit2.c b/tests-clar/clar_libgit2.c
index c3abc1f95..82ec5c065 100644
--- a/tests-clar/clar_libgit2.c
+++ b/tests-clar/clar_libgit2.c
@@ -191,7 +191,7 @@ git_repository *cl_git_sandbox_init(const char *sandbox)
cl_git_pass(git_repository_open(&_cl_repo, sandbox));
/* Adjust configs after copying to new filesystem */
- cl_git_pass(git_repository_reset_filesystem(_cl_repo));
+ cl_git_pass(git_repository_reset_filesystem(_cl_repo, 0));
return _cl_repo;
}
diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c
index 7aab8f409..1dbfc9ac5 100644
--- a/tests-clar/diff/patch.c
+++ b/tests-clar/diff/patch.c
@@ -240,7 +240,7 @@ void test_diff_patch__hunks_have_correct_line_numbers(void)
git_repository_set_config(g_repo, cfg);
git_config_free(cfg);
- git_repository_reset_filesystem(g_repo);
+ git_repository_reset_filesystem(g_repo, false);
cl_git_pass(
git_futils_readbuffer(&old_content, "renames/songof7cities.txt"));
@@ -524,7 +524,7 @@ void test_diff_patch__line_counts_with_eofnl(void)
git_repository_set_config(g_repo, cfg);
git_config_free(cfg);
- git_repository_reset_filesystem(g_repo);
+ git_repository_reset_filesystem(g_repo, false);
cl_git_pass(git_futils_readbuffer(&content, "renames/songof7cities.txt"));
diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c
index 6c17b41c6..aeef7b963 100644
--- a/tests-clar/diff/workdir.c
+++ b/tests-clar/diff/workdir.c
@@ -761,16 +761,7 @@ void test_diff_workdir__submodules(void)
git_diff_list *diff = NULL;
diff_expects exp;
- g_repo = cl_git_sandbox_init("submod2");
-
- cl_fixture_sandbox("submod2_target");
- p_rename("submod2_target/.gitted", "submod2_target/.git");
-
- rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
- p_rename("submod2/not/.gitted", "submod2/not/.git");
-
- cl_fixture_cleanup("submod2_target");
+ g_repo = setup_fixture_submod2();
a = resolve_commit_oid_to_tree(g_repo, a_commit);
diff --git a/tests-clar/index/addall.c b/tests-clar/index/addall.c
index f46a1e16c..3b5f5f22d 100644
--- a/tests-clar/index/addall.c
+++ b/tests-clar/index/addall.c
@@ -111,8 +111,9 @@ static void check_stat_data(git_index *index, const char *path, bool match)
cl_assert(st.st_gid == entry->gid);
cl_assert_equal_i_fmt(
GIT_MODE_TYPE(st.st_mode), GIT_MODE_TYPE(entry->mode), "%07o");
- cl_assert_equal_b(
- GIT_PERMS_IS_EXEC(st.st_mode), GIT_PERMS_IS_EXEC(entry->mode));
+ if (cl_is_chmod_supported())
+ cl_assert_equal_b(
+ GIT_PERMS_IS_EXEC(st.st_mode), GIT_PERMS_IS_EXEC(entry->mode));
} else {
/* most things will still match */
cl_assert(st.st_size != entry->file_size);
diff --git a/tests-clar/index/filemodes.c b/tests-clar/index/filemodes.c
index 8cbd6ff3a..013932696 100644
--- a/tests-clar/index/filemodes.c
+++ b/tests-clar/index/filemodes.c
@@ -74,7 +74,6 @@ static void add_and_check_mode_(
void test_index_filemodes__untrusted(void)
{
git_index *index;
- bool can_filemode = cl_is_chmod_supported();
cl_repo_set_bool(g_repo, "core.filemode", false);
@@ -97,20 +96,15 @@ void test_index_filemodes__untrusted(void)
replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
- /* these tests of newly added files won't give predictable results on
- * filesystems without actual filemode support, so skip them.
- */
- if (can_filemode) {
- /* 5 - add new 0644 -> expect 0644 */
- cl_git_write2file("filemodes/new_off", "blah", 0,
- O_WRONLY | O_CREAT | O_TRUNC, 0644);
- add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
-
- /* 6 - add new 0755 -> expect 0755 */
- cl_git_write2file("filemodes/new_on", "blah", 0,
- O_WRONLY | O_CREAT | O_TRUNC, 0755);
- add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
- }
+ /* 5 - add new 0644 -> expect 0644 */
+ cl_git_write2file("filemodes/new_off", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
+
+ /* 6 - add new 0755 -> expect 0644 if core.filemode == false */
+ cl_git_write2file("filemodes/new_on", "blah", 0,
+ O_WRONLY | O_CREAT | O_TRUNC, 0755);
+ add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB);
git_index_free(index);
}
diff --git a/tests-clar/refs/unicode.c b/tests-clar/refs/unicode.c
index 2ec103275..b29c63e2b 100644
--- a/tests-clar/refs/unicode.c
+++ b/tests-clar/refs/unicode.c
@@ -22,23 +22,38 @@ void test_refs_unicode__create_and_lookup(void)
git_reference *ref0, *ref1, *ref2;
git_repository *repo2;
- const char *REFNAME = "refs/heads/" "\305" "ngstr" "\366" "m";
+ const char *REFNAME = "refs/heads/" "\303\205" "ngstr" "\303\266" "m";
+ const char *REFNAME_DECOMPOSED =
+ "refs/heads/" "A" "\314\212" "ngstro" "\314\210" "m";
const char *master = "refs/heads/master";
/* Create the reference */
cl_git_pass(git_reference_lookup(&ref0, repo, master));
cl_git_pass(git_reference_create(&ref1, repo, REFNAME, git_reference_target(ref0), 0));
cl_assert_equal_s(REFNAME, git_reference_name(ref1));
+ git_reference_free(ref0);
/* Lookup the reference in a different instance of the repository */
cl_git_pass(git_repository_open(&repo2, "testrepo.git"));
+
cl_git_pass(git_reference_lookup(&ref2, repo2, REFNAME));
+ cl_assert_equal_i(
+ 0, git_oid_cmp(git_reference_target(ref1), git_reference_target(ref2)));
+ cl_assert_equal_s(REFNAME, git_reference_name(ref2));
+ git_reference_free(ref2);
+
+#if GIT_USE_ICONV
+ /* Lookup reference by decomposed unicode name */
- cl_assert(git_oid_cmp(git_reference_target(ref1), git_reference_target(ref2)) == 0);
+ cl_git_pass(git_reference_lookup(&ref2, repo2, REFNAME_DECOMPOSED));
+ cl_assert_equal_i(
+ 0, git_oid_cmp(git_reference_target(ref1), git_reference_target(ref2)));
cl_assert_equal_s(REFNAME, git_reference_name(ref2));
+ git_reference_free(ref2);
+#endif
+
+ /* Cleanup */
- git_reference_free(ref0);
git_reference_free(ref1);
- git_reference_free(ref2);
git_repository_free(repo2);
}
diff --git a/tests-clar/submodule/lookup.c b/tests-clar/submodule/lookup.c
index b626cdf04..5f320e702 100644
--- a/tests-clar/submodule/lookup.c
+++ b/tests-clar/submodule/lookup.c
@@ -7,20 +7,7 @@ static git_repository *g_repo = NULL;
void test_submodule_lookup__initialize(void)
{
- g_repo = cl_git_sandbox_init("submod2");
-
- cl_fixture_sandbox("submod2_target");
- p_rename("submod2_target/.gitted", "submod2_target/.git");
-
- /* must create submod2_target before rewrite so prettify will work */
- rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
-}
-
-void test_submodule_lookup__cleanup(void)
-{
- cl_git_sandbox_cleanup();
- cl_fixture_cleanup("submod2_target");
+ g_repo = setup_fixture_submod2();
}
void test_submodule_lookup__simple_lookup(void)
diff --git a/tests-clar/submodule/modify.c b/tests-clar/submodule/modify.c
index c0498ce6e..e326287a6 100644
--- a/tests-clar/submodule/modify.c
+++ b/tests-clar/submodule/modify.c
@@ -11,20 +11,7 @@ static git_repository *g_repo = NULL;
void test_submodule_modify__initialize(void)
{
- g_repo = cl_git_sandbox_init("submod2");
-
- cl_fixture_sandbox("submod2_target");
- p_rename("submod2_target/.gitted", "submod2_target/.git");
-
- /* must create submod2_target before rewrite so prettify will work */
- rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
-}
-
-void test_submodule_modify__cleanup(void)
-{
- cl_git_sandbox_cleanup();
- cl_fixture_cleanup("submod2_target");
+ g_repo = setup_fixture_submod2();
}
void test_submodule_modify__add(void)
diff --git a/tests-clar/submodule/submodule_helpers.c b/tests-clar/submodule/submodule_helpers.c
index 3e79c77fd..cc3b7a2e3 100644
--- a/tests-clar/submodule/submodule_helpers.c
+++ b/tests-clar/submodule/submodule_helpers.c
@@ -102,6 +102,8 @@ git_repository *setup_fixture_submodules(void)
cl_set_cleanup(cleanup_fixture_submodules, "testrepo.git");
+ cl_git_pass(git_repository_reset_filesystem(repo, 1));
+
return repo;
}
@@ -118,5 +120,7 @@ git_repository *setup_fixture_submod2(void)
cl_set_cleanup(cleanup_fixture_submodules, "submod2_target");
+ cl_git_pass(git_repository_reset_filesystem(repo, 1));
+
return repo;
}