filemodes.c 6.78 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#include "clar_libgit2.h"
#include "buffer.h"
#include "posix.h"
#include "index.h"

static git_repository *g_repo = NULL;

void test_index_filemodes__initialize(void)
{
	g_repo = cl_git_sandbox_init("filemodes");
}

void test_index_filemodes__cleanup(void)
{
	cl_git_sandbox_cleanup();
}

void test_index_filemodes__read(void)
{
	git_index *index;
	unsigned int i;
	static bool expected[6] = { 0, 1, 0, 1, 0, 1 };

	cl_git_pass(git_repository_index(&index, g_repo));
	cl_assert_equal_i(6, git_index_entrycount(index));

	for (i = 0; i < 6; ++i) {
		git_index_entry *entry = git_index_get(index, i);
		cl_assert(entry != NULL);
		cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]);
	}

	git_index_free(index);
}

static void replace_file_with_mode(
	const char *filename, const char *backup, unsigned int create_mode)
{
	git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT;

	cl_git_pass(git_buf_joinpath(&path, "filemodes", filename));
	cl_git_pass(git_buf_printf(&content, "%s as %08u (%d)",
		filename, create_mode, rand()));

	cl_git_pass(p_rename(path.ptr, backup));
	cl_git_write2file(
		path.ptr, content.ptr, O_WRONLY|O_CREAT|O_TRUNC, create_mode);

	git_buf_free(&path);
	git_buf_free(&content);
}

static void add_and_check_mode(
	git_index *index, const char *filename, unsigned int expect_mode)
{
	int pos;
	git_index_entry *entry;

	cl_git_pass(git_index_add(index, filename, 0));

	pos = git_index_find(index, filename);
	cl_assert(pos >= 0);

	entry = git_index_get(index, pos);
	cl_assert(entry->mode == expect_mode);
}

static void append_and_check_mode(
	git_index *index, const char *filename, unsigned int expect_mode)
{
	unsigned int before, after;
	git_index_entry *entry;

	before = git_index_entrycount(index);

	cl_git_pass(git_index_append(index, filename, 0));

	after = git_index_entrycount(index);
	cl_assert_equal_i(before + 1, after);

	/* bypass git_index_get since that resorts the index */
	entry = (git_index_entry *)git_vector_get(&index->entries, after - 1);

	cl_assert_equal_s(entry->path, filename);
	cl_assert(expect_mode == entry->mode);
}

void test_index_filemodes__untrusted(void)
{
	git_config *cfg;
	git_index *index;
	bool can_filemode = cl_is_chmod_supported();

	cl_git_pass(git_repository_config(&cfg, g_repo));
	cl_git_pass(git_config_set_bool(cfg, "core.filemode", false));
	git_config_free(cfg);

	cl_git_pass(git_repository_index(&index, g_repo));
	cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) != 0);

	/* 1 - add 0644 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
nulltoken committed
103
	add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
104 105 106

	/* 2 - add 0644 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
nulltoken committed
107
	add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
108 109 110

	/* 3 - add 0755 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
nulltoken committed
111
	add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
112 113 114

	/* 4 - add 0755 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
nulltoken committed
115
	add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
116 117 118

	/* 5 - append 0644 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.2", 0644);
nulltoken committed
119
	append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
120 121 122

	/* 6 - append 0644 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.2", 0644);
nulltoken committed
123
	append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
124 125 126

	/* 7 - append 0755 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.3", 0755);
nulltoken committed
127
	append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
128 129 130

	/* 8 - append 0755 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.3", 0755);
nulltoken committed
131
	append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
132 133 134 135

	/*  9 - add new 0644 -> expect 0644 */
	cl_git_write2file("filemodes/new_off", "blah",
		O_WRONLY | O_CREAT | O_TRUNC, 0644);
nulltoken committed
136
	add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
137 138 139 140 141 142 143 144

	/* this test won't give predictable results on a platform
	 * that doesn't support filemodes correctly, so skip it.
	 */
	if (can_filemode) {
		/* 10 - add 0755 -> expect 0755 */
		cl_git_write2file("filemodes/new_on", "blah",
			O_WRONLY | O_CREAT | O_TRUNC, 0755);
nulltoken committed
145
		add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	}

	git_index_free(index);
}

void test_index_filemodes__trusted(void)
{
	git_config *cfg;
	git_index *index;

	/* Only run these tests on platforms where I can actually
	 * chmod a file and get the stat results I expect!
	 */
	if (!cl_is_chmod_supported())
		return;

	cl_git_pass(git_repository_config(&cfg, g_repo));
	cl_git_pass(git_config_set_bool(cfg, "core.filemode", true));
	git_config_free(cfg);

	cl_git_pass(git_repository_index(&index, g_repo));
	cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) == 0);

	/* 1 - add 0644 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
nulltoken committed
171
	add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
172 173 174

	/* 2 - add 0644 over existing 0755 -> expect 0644 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
nulltoken committed
175
	add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
176 177 178

	/* 3 - add 0755 over existing 0644 -> expect 0755 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
nulltoken committed
179
	add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
180 181 182

	/* 4 - add 0755 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
nulltoken committed
183
	add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
184 185 186

	/* 5 - append 0644 over existing 0644 -> expect 0644 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.2", 0644);
nulltoken committed
187
	append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
188 189 190

	/* 6 - append 0644 over existing 0755 -> expect 0644 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.2", 0644);
nulltoken committed
191
	append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
192 193 194

	/* 7 - append 0755 over existing 0644 -> expect 0755 */
	replace_file_with_mode("exec_off", "filemodes/exec_off.3", 0755);
nulltoken committed
195
	append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
196 197 198

	/* 8 - append 0755 over existing 0755 -> expect 0755 */
	replace_file_with_mode("exec_on", "filemodes/exec_on.3", 0755);
nulltoken committed
199
	append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
200 201 202 203

	/*  9 - add new 0644 -> expect 0644 */
	cl_git_write2file("filemodes/new_off", "blah",
		O_WRONLY | O_CREAT | O_TRUNC, 0644);
nulltoken committed
204
	add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
205 206 207 208

	/* 10 - add 0755 -> expect 0755 */
	cl_git_write2file("filemodes/new_on", "blah",
		O_WRONLY | O_CREAT | O_TRUNC, 0755);
nulltoken committed
209
	add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
210 211 212

	git_index_free(index);
}