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