]> git.proxmox.com Git - libgit2.git/blob - tests/index/filemodes.c
1ab8a9a7ff74ba2c0e6358578e6bcb6b9a3efeaa
[libgit2.git] / tests / index / filemodes.c
1 #include "clar_libgit2.h"
2 #include "posix.h"
3 #include "index.h"
4
5 static git_repository *g_repo = NULL;
6
7 void test_index_filemodes__initialize(void)
8 {
9 g_repo = cl_git_sandbox_init("filemodes");
10 }
11
12 void test_index_filemodes__cleanup(void)
13 {
14 cl_git_sandbox_cleanup();
15 }
16
17 void test_index_filemodes__read(void)
18 {
19 git_index *index;
20 unsigned int i;
21 static bool expected[6] = { 0, 1, 0, 1, 0, 1 };
22
23 cl_git_pass(git_repository_index(&index, g_repo));
24 cl_assert_equal_i(6, (int)git_index_entrycount(index));
25
26 for (i = 0; i < 6; ++i) {
27 const git_index_entry *entry = git_index_get_byindex(index, i);
28 cl_assert(entry != NULL);
29 cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]);
30 }
31
32 git_index_free(index);
33 }
34
35 static void replace_file_with_mode(
36 const char *filename, const char *backup, unsigned int create_mode)
37 {
38 git_str path = GIT_STR_INIT, content = GIT_STR_INIT;
39
40 cl_git_pass(git_str_joinpath(&path, "filemodes", filename));
41 cl_git_pass(git_str_printf(&content, "%s as %08u (%d)",
42 filename, create_mode, rand()));
43
44 cl_git_pass(p_rename(path.ptr, backup));
45 cl_git_write2file(
46 path.ptr, content.ptr, content.size,
47 O_WRONLY|O_CREAT|O_TRUNC, create_mode);
48
49 git_str_dispose(&path);
50 git_str_dispose(&content);
51 }
52
53 #define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__func__,__LINE__)
54
55 static void add_and_check_mode_(
56 git_index *index, const char *filename, unsigned int expect_mode,
57 const char *file, const char *func, int line)
58 {
59 size_t pos;
60 const git_index_entry *entry;
61
62 cl_git_pass(git_index_add_bypath(index, filename));
63
64 clar__assert(!git_index_find(&pos, index, filename),
65 file, func, line, "Cannot find index entry", NULL, 1);
66
67 entry = git_index_get_byindex(index, pos);
68
69 clar__assert_equal(file, func, line, "Expected mode does not match index",
70 1, "%07o", (unsigned int)entry->mode, (unsigned int)expect_mode);
71 }
72
73 void test_index_filemodes__untrusted(void)
74 {
75 git_index *index;
76
77 cl_repo_set_bool(g_repo, "core.filemode", false);
78
79 cl_git_pass(git_repository_index(&index, g_repo));
80 cl_assert((git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0);
81
82 /* 1 - add 0644 over existing 0644 -> expect 0644 */
83 replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
84 add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
85
86 /* 2 - add 0644 over existing 0755 -> expect 0755 */
87 replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
88 add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
89
90 /* 3 - add 0755 over existing 0644 -> expect 0644 */
91 replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
92 add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
93
94 /* 4 - add 0755 over existing 0755 -> expect 0755 */
95 replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
96 add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
97
98 /* 5 - add new 0644 -> expect 0644 */
99 cl_git_write2file("filemodes/new_off", "blah", 0,
100 O_WRONLY | O_CREAT | O_TRUNC, 0644);
101 add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
102
103 /* 6 - add new 0755 -> expect 0644 if core.filemode == false */
104 cl_git_write2file("filemodes/new_on", "blah", 0,
105 O_WRONLY | O_CREAT | O_TRUNC, 0755);
106 add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB);
107
108 git_index_free(index);
109 }
110
111 void test_index_filemodes__trusted(void)
112 {
113 git_index *index;
114
115 /* Only run these tests on platforms where I can actually
116 * chmod a file and get the stat results I expect!
117 */
118 if (!cl_is_chmod_supported())
119 return;
120
121 cl_repo_set_bool(g_repo, "core.filemode", true);
122
123 cl_git_pass(git_repository_index(&index, g_repo));
124 cl_assert((git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE) == 0);
125
126 /* 1 - add 0644 over existing 0644 -> expect 0644 */
127 replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
128 add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
129
130 /* 2 - add 0644 over existing 0755 -> expect 0644 */
131 replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
132 add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
133
134 /* 3 - add 0755 over existing 0644 -> expect 0755 */
135 replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
136 add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
137
138 /* 4 - add 0755 over existing 0755 -> expect 0755 */
139 replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
140 add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
141
142 /* 5 - add new 0644 -> expect 0644 */
143 cl_git_write2file("filemodes/new_off", "blah", 0,
144 O_WRONLY | O_CREAT | O_TRUNC, 0644);
145 add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
146
147 /* 6 - add 0755 -> expect 0755 */
148 cl_git_write2file("filemodes/new_on", "blah", 0,
149 O_WRONLY | O_CREAT | O_TRUNC, 0755);
150 add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
151
152 git_index_free(index);
153 }
154
155 #define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__func__,__LINE__)
156
157 static void add_entry_and_check_mode_(
158 git_index *index, bool from_file, git_filemode_t mode,
159 const char *file, const char *func, int line)
160 {
161 size_t pos;
162 const git_index_entry* entry;
163 git_index_entry new_entry;
164
165 /* If old_filename exists, we copy that to the new file, and test
166 * git_index_add(), otherwise create a new entry testing git_index_add_from_buffer
167 */
168 if (from_file)
169 {
170 clar__assert(!git_index_find(&pos, index, "exec_off"),
171 file, func, line, "Cannot find original index entry", NULL, 1);
172
173 entry = git_index_get_byindex(index, pos);
174
175 memcpy(&new_entry, entry, sizeof(new_entry));
176 }
177 else
178 memset(&new_entry, 0x0, sizeof(git_index_entry));
179
180 new_entry.path = "filemodes/explicit_test";
181 new_entry.mode = mode;
182
183 if (from_file)
184 {
185 clar__assert(!git_index_add(index, &new_entry),
186 file, func, line, "Cannot add index entry", NULL, 1);
187 }
188 else
189 {
190 const char *content = "hey there\n";
191 clar__assert(!git_index_add_from_buffer(index, &new_entry, content, strlen(content)),
192 file, func, line, "Cannot add index entry from buffer", NULL, 1);
193 }
194
195 clar__assert(!git_index_find(&pos, index, "filemodes/explicit_test"),
196 file, func, line, "Cannot find new index entry", NULL, 1);
197
198 entry = git_index_get_byindex(index, pos);
199
200 clar__assert_equal(file, func, line, "Expected mode does not match index",
201 1, "%07o", (unsigned int)entry->mode, (unsigned int)mode);
202 }
203
204 void test_index_filemodes__explicit(void)
205 {
206 git_index *index;
207
208 /* These tests should run and work everywhere, as the filemode is
209 * given explicitly to git_index_add or git_index_add_from_buffer
210 */
211 cl_repo_set_bool(g_repo, "core.filemode", false);
212
213 cl_git_pass(git_repository_index(&index, g_repo));
214
215 /* Each of these tests keeps overwriting the same file in the index. */
216 /* 1 - add new 0644 entry */
217 add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
218
219 /* 2 - add 0755 entry over existing 0644 */
220 add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB_EXECUTABLE);
221
222 /* 3 - add 0644 entry over existing 0755 */
223 add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
224
225 /* 4 - add 0755 buffer entry over existing 0644 */
226 add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB_EXECUTABLE);
227
228 /* 5 - add 0644 buffer entry over existing 0755 */
229 add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB);
230
231 git_index_free(index);
232 }
233
234 void test_index_filemodes__invalid(void)
235 {
236 git_index *index;
237 git_index_entry entry;
238 const git_index_entry *dummy;
239
240 cl_git_pass(git_repository_index(&index, g_repo));
241
242 /* add a dummy file so that we have a valid id */
243 cl_git_mkfile("./filemodes/dummy-file.txt", "new-file\n");
244 cl_git_pass(git_index_add_bypath(index, "dummy-file.txt"));
245 cl_assert((dummy = git_index_get_bypath(index, "dummy-file.txt", 0)));
246
247 GIT_INDEX_ENTRY_STAGE_SET(&entry, 0);
248 entry.path = "foo";
249 entry.mode = GIT_OBJECT_BLOB;
250 git_oid_cpy(&entry.id, &dummy->id);
251 cl_git_fail(git_index_add(index, &entry));
252
253 entry.mode = GIT_FILEMODE_BLOB;
254 cl_git_pass(git_index_add(index, &entry));
255
256 git_index_free(index);
257 }
258
259 void test_index_filemodes__frombuffer_requires_files(void)
260 {
261 git_index *index;
262 git_index_entry new_entry;
263 const git_index_entry *ret_entry;
264 const char *content = "hey there\n";
265
266 memset(&new_entry, 0, sizeof(new_entry));
267 cl_git_pass(git_repository_index(&index, g_repo));
268
269 /* regular blob */
270 new_entry.path = "dummy-file.txt";
271 new_entry.mode = GIT_FILEMODE_BLOB;
272
273 cl_git_pass(git_index_add_from_buffer(index,
274 &new_entry, content, strlen(content)));
275
276 cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
277 cl_assert_equal_s("dummy-file.txt", ret_entry->path);
278 cl_assert_equal_i(GIT_FILEMODE_BLOB, ret_entry->mode);
279
280 /* executable blob */
281 new_entry.path = "dummy-file.txt";
282 new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
283
284 cl_git_pass(git_index_add_from_buffer(index,
285 &new_entry, content, strlen(content)));
286
287 cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
288 cl_assert_equal_s("dummy-file.txt", ret_entry->path);
289 cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, ret_entry->mode);
290
291 /* links are also acceptable */
292 new_entry.path = "dummy-link.txt";
293 new_entry.mode = GIT_FILEMODE_LINK;
294
295 cl_git_pass(git_index_add_from_buffer(index,
296 &new_entry, content, strlen(content)));
297
298 cl_assert((ret_entry = git_index_get_bypath(index, "dummy-link.txt", 0)));
299 cl_assert_equal_s("dummy-link.txt", ret_entry->path);
300 cl_assert_equal_i(GIT_FILEMODE_LINK, ret_entry->mode);
301
302 /* trees are rejected */
303 new_entry.path = "invalid_mode.txt";
304 new_entry.mode = GIT_FILEMODE_TREE;
305
306 cl_git_fail(git_index_add_from_buffer(index,
307 &new_entry, content, strlen(content)));
308 cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
309
310 /* submodules are rejected */
311 new_entry.path = "invalid_mode.txt";
312 new_entry.mode = GIT_FILEMODE_COMMIT;
313
314 cl_git_fail(git_index_add_from_buffer(index,
315 &new_entry, content, strlen(content)));
316 cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
317
318 git_index_free(index);
319 }