Commit 14997dc5 by Russell Belfer

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.
parent 5173ea92
......@@ -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.
......
......@@ -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);
......
......@@ -116,4 +116,3 @@ const git_error *giterr_last(void)
{
return GIT_GLOBAL->last_error;
}
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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(
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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) {
......
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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"));
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
}
......@@ -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)
......
......@@ -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)
......
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment