]> git.proxmox.com Git - libgit2.git/blame - tests/checkout/nasty.c
New upstream version 1.1.0+dfsg.1
[libgit2.git] / tests / checkout / nasty.c
CommitLineData
a64119e3
ET
1#include "clar_libgit2.h"
2#include "checkout_helpers.h"
3
4#include "git2/checkout.h"
5#include "repository.h"
6#include "buffer.h"
22a2d3d5 7#include "futils.h"
a64119e3
ET
8
9static const char *repo_name = "nasty";
10static git_repository *repo;
11static git_checkout_options checkout_opts;
12
13void test_checkout_nasty__initialize(void)
14{
15 repo = cl_git_sandbox_init(repo_name);
16
17 GIT_INIT_STRUCTURE(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
18 checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
19}
20
21void test_checkout_nasty__cleanup(void)
22{
23 cl_git_sandbox_cleanup();
24}
25
232bc895
ET
26static void test_checkout_passes(const char *refname, const char *filename)
27{
28 git_oid commit_id;
29 git_commit *commit;
30 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
31 git_buf path = GIT_BUF_INIT;
32
33 cl_git_pass(git_buf_joinpath(&path, repo_name, filename));
34
35 cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname));
36 cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
37
38 opts.checkout_strategy = GIT_CHECKOUT_FORCE |
39 GIT_CHECKOUT_DONT_UPDATE_INDEX;
40
41 cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts));
42 cl_assert(!git_path_exists(path.ptr));
43
44 git_commit_free(commit);
ac3d33df 45 git_buf_dispose(&path);
232bc895
ET
46}
47
48static void test_checkout_fails(const char *refname, const char *filename)
a64119e3
ET
49{
50 git_oid commit_id;
51 git_commit *commit;
52 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
53 git_buf path = GIT_BUF_INIT;
54
55 cl_git_pass(git_buf_joinpath(&path, repo_name, filename));
56
57 cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname));
58 cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
59
60 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
61
62 cl_git_fail(git_checkout_tree(repo, (const git_object *)commit, &opts));
63 cl_assert(!git_path_exists(path.ptr));
64
65 git_commit_free(commit);
ac3d33df 66 git_buf_dispose(&path);
a64119e3
ET
67}
68
69/* A tree that contains ".git" as a tree, with a blob inside
70 * (".git/foobar").
71 */
72void test_checkout_nasty__dotgit_tree(void)
73{
74 test_checkout_fails("refs/heads/dotgit_tree", ".git/foobar");
75}
76
77/* A tree that contains ".GIT" as a tree, with a blob inside
78 * (".GIT/foobar").
79 */
80void test_checkout_nasty__dotcapitalgit_tree(void)
81{
82 test_checkout_fails("refs/heads/dotcapitalgit_tree", ".GIT/foobar");
83}
84
85/* A tree that contains a tree ".", with a blob inside ("./foobar").
86 */
87void test_checkout_nasty__dot_tree(void)
88{
89 test_checkout_fails("refs/heads/dot_tree", "foobar");
90}
91
92/* A tree that contains a tree ".", with a tree ".git", with a blob
93 * inside ("./.git/foobar").
94 */
95void test_checkout_nasty__dot_dotgit_tree(void)
96{
97 test_checkout_fails("refs/heads/dot_dotgit_tree", ".git/foobar");
98}
99
100/* A tree that contains a tree, with a tree "..", with a tree ".git", with a
101 * blob inside ("foo/../.git/foobar").
102 */
103void test_checkout_nasty__dotdot_dotgit_tree(void)
104{
105 test_checkout_fails("refs/heads/dotdot_dotgit_tree", ".git/foobar");
106}
107
108/* A tree that contains a tree, with a tree "..", with a blob inside
109 * ("foo/../foobar").
110 */
111void test_checkout_nasty__dotdot_tree(void)
112{
113 test_checkout_fails("refs/heads/dotdot_tree", "foobar");
114}
115
116/* A tree that contains a blob with the rogue name ".git/foobar" */
117void test_checkout_nasty__dotgit_path(void)
118{
119 test_checkout_fails("refs/heads/dotgit_path", ".git/foobar");
120}
121
122/* A tree that contains a blob with the rogue name ".GIT/foobar" */
123void test_checkout_nasty__dotcapitalgit_path(void)
124{
125 test_checkout_fails("refs/heads/dotcapitalgit_path", ".GIT/foobar");
126}
127
128/* A tree that contains a blob with the rogue name "./.git/foobar" */
129void test_checkout_nasty__dot_dotgit_path(void)
130{
131 test_checkout_fails("refs/heads/dot_dotgit_path", ".git/foobar");
132}
133
134/* A tree that contains a blob with the rogue name "./.GIT/foobar" */
135void test_checkout_nasty__dot_dotcapitalgit_path(void)
136{
137 test_checkout_fails("refs/heads/dot_dotcapitalgit_path", ".GIT/foobar");
138}
139
140/* A tree that contains a blob with the rogue name "foo/../.git/foobar" */
141void test_checkout_nasty__dotdot_dotgit_path(void)
142{
143 test_checkout_fails("refs/heads/dotdot_dotgit_path", ".git/foobar");
144}
145
146/* A tree that contains a blob with the rogue name "foo/../.GIT/foobar" */
147void test_checkout_nasty__dotdot_dotcapitalgit_path(void)
148{
149 test_checkout_fails("refs/heads/dotdot_dotcapitalgit_path", ".GIT/foobar");
150}
151
152/* A tree that contains a blob with the rogue name "foo/." */
153void test_checkout_nasty__dot_path(void)
154{
155 test_checkout_fails("refs/heads/dot_path", "./foobar");
156}
157
158/* A tree that contains a blob with the rogue name "foo/." */
159void test_checkout_nasty__dot_path_two(void)
160{
161 test_checkout_fails("refs/heads/dot_path_two", "foo/.");
162}
163
164/* A tree that contains a blob with the rogue name "foo/../foobar" */
165void test_checkout_nasty__dotdot_path(void)
166{
167 test_checkout_fails("refs/heads/dotdot_path", "foobar");
168}
169
170/* A tree that contains an entry with a backslash ".git\foobar" */
171void test_checkout_nasty__dotgit_backslash_path(void)
172{
173#ifdef GIT_WIN32
174 test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
175#endif
176}
177
178/* A tree that contains an entry with a backslash ".GIT\foobar" */
179void test_checkout_nasty__dotcapitalgit_backslash_path(void)
180{
181#ifdef GIT_WIN32
182 test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
183#endif
184}
185
186/* A tree that contains an entry with a backslash ".\.GIT\foobar" */
187void test_checkout_nasty__dot_backslash_dotcapitalgit_path(void)
188{
189#ifdef GIT_WIN32
190 test_checkout_fails("refs/heads/dot_backslash_dotcapitalgit_path", ".GIT/foobar");
191#endif
192}
193
194/* A tree that contains an entry ".git.", because Win32 APIs will drop the
195 * trailing slash.
196 */
197void test_checkout_nasty__dot_git_dot(void)
198{
199#ifdef GIT_WIN32
200 test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
201#endif
202}
203
204/* A tree that contains an entry "git~1", because that is typically the
205 * short name for ".git".
206 */
207void test_checkout_nasty__git_tilde1(void)
208{
a64119e3 209 test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
b6832cbf 210 test_checkout_fails("refs/heads/git_tilde1", "git~1/foobar");
a64119e3
ET
211}
212
213/* A tree that contains an entry "git~2", when we have forced the short
214 * name for ".git" into "GIT~2".
215 */
216void test_checkout_nasty__git_custom_shortname(void)
217{
218#ifdef GIT_WIN32
07c989e9 219 if (!cl_sandbox_supports_8dot3())
5f28ec84
ET
220 clar__skip();
221
a64119e3
ET
222 cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
223 cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
224 cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
5f28ec84 225 test_checkout_fails("refs/heads/git_tilde2", ".git/foobar");
a64119e3
ET
226#endif
227}
228
229/* A tree that contains an entry "git~3", which should be allowed, since
230 * it is not the typical short name ("GIT~1") or the actual short name
231 * ("GIT~2") for ".git".
232 */
233void test_checkout_nasty__only_looks_like_a_git_shortname(void)
234{
235#ifdef GIT_WIN32
236 git_oid commit_id;
237 git_commit *commit;
238 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
239
240 cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
241 cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
242 cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
243
244 cl_git_pass(git_reference_name_to_id(&commit_id, repo, "refs/heads/git_tilde3"));
245 cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
246
247 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
248
249 cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts));
250 cl_assert(git_path_exists("nasty/git~3/foobar"));
251
252 git_commit_free(commit);
253#endif
254}
255
256/* A tree that contains an entry "git:", because Win32 APIs will reject
257 * that as looking too similar to a drive letter.
258 */
259void test_checkout_nasty__dot_git_colon(void)
260{
261#ifdef GIT_WIN32
262 test_checkout_fails("refs/heads/dot_git_colon", ".git/foobar");
263#endif
264}
265
266/* A tree that contains an entry "git:foo", because Win32 APIs will turn
267 * that into ".git".
268 */
269void test_checkout_nasty__dot_git_colon_stuff(void)
270{
271#ifdef GIT_WIN32
272 test_checkout_fails("refs/heads/dot_git_colon_stuff", ".git/foobar");
273#endif
274}
275
b6832cbf
UG
276/* A tree that contains an entry ".git::$INDEX_ALLOCATION" because NTFS
277 * will interpret that as a synonym to ".git", even when mounted via SMB
278 * on macOS.
279 */
280void test_checkout_nasty__dotgit_alternate_data_stream(void)
281{
282 test_checkout_fails("refs/heads/dotgit_alternate_data_stream", ".git/dummy-file");
283 test_checkout_fails("refs/heads/dotgit_alternate_data_stream", ".git::$INDEX_ALLOCATION/dummy-file");
284}
285
11d67b75
ET
286/* Trees that contains entries with a tree ".git" that contain
287 * byte sequences:
288 * { 0xe2, 0x80, 0x8c }
289 * { 0xe2, 0x80, 0x8d }
290 * { 0xe2, 0x80, 0x8e }
291 * { 0xe2, 0x80, 0x8f }
292 * { 0xe2, 0x80, 0xaa }
293 * { 0xe2, 0x80, 0xab }
294 * { 0xe2, 0x80, 0xac }
295 * { 0xe2, 0x80, 0xad }
296 * { 0xe2, 0x81, 0xae }
297 * { 0xe2, 0x81, 0xaa }
298 * { 0xe2, 0x81, 0xab }
299 * { 0xe2, 0x81, 0xac }
300 * { 0xe2, 0x81, 0xad }
301 * { 0xe2, 0x81, 0xae }
302 * { 0xe2, 0x81, 0xaf }
303 * { 0xef, 0xbb, 0xbf }
304 * Because these map to characters that HFS filesystems "ignore". Thus
305 * ".git<U+200C>" will map to ".git".
306 */
307void test_checkout_nasty__dot_git_hfs_ignorable(void)
308{
309#ifdef __APPLE__
310 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_1", ".git/foobar");
311 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_2", ".git/foobar");
312 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_3", ".git/foobar");
313 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_4", ".git/foobar");
314 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_5", ".git/foobar");
315 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_6", ".git/foobar");
316 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_7", ".git/foobar");
317 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_8", ".git/foobar");
318 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_9", ".git/foobar");
319 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_10", ".git/foobar");
320 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_11", ".git/foobar");
321 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_12", ".git/foobar");
322 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_13", ".git/foobar");
323 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_14", ".git/foobar");
324 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_15", ".git/foobar");
325 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
326#endif
327}
ec74b40c
ET
328
329void test_checkout_nasty__honors_core_protecthfs(void)
330{
331 cl_repo_set_bool(repo, "core.protectHFS", true);
332
333 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_1", ".git/foobar");
334 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_2", ".git/foobar");
335 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_3", ".git/foobar");
336 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_4", ".git/foobar");
337 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_5", ".git/foobar");
338 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_6", ".git/foobar");
339 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_7", ".git/foobar");
340 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_8", ".git/foobar");
341 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_9", ".git/foobar");
342 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_10", ".git/foobar");
343 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_11", ".git/foobar");
344 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_12", ".git/foobar");
345 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_13", ".git/foobar");
346 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_14", ".git/foobar");
347 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_15", ".git/foobar");
348 test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
349}
350
351void test_checkout_nasty__honors_core_protectntfs(void)
352{
353 cl_repo_set_bool(repo, "core.protectNTFS", true);
354
355 test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
356 test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
357 test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
358 test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
359}
232bc895
ET
360
361void test_checkout_nasty__symlink1(void)
362{
363 test_checkout_passes("refs/heads/symlink1", ".git/foobar");
364}
365
366void test_checkout_nasty__symlink2(void)
367{
368 test_checkout_passes("refs/heads/symlink2", ".git/foobar");
369}
370
371void test_checkout_nasty__symlink3(void)
372{
373 test_checkout_passes("refs/heads/symlink3", ".git/foobar");
374}
375
4b3ec53c
XL
376void test_checkout_nasty__gitmodules_symlink(void)
377{
378 cl_repo_set_bool(repo, "core.protectHFS", true);
379 test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
380 cl_repo_set_bool(repo, "core.protectHFS", false);
381
382 cl_repo_set_bool(repo, "core.protectNTFS", true);
383 test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
384 cl_repo_set_bool(repo, "core.protectNTFS", false);
385
386 test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
387}