]> git.proxmox.com Git - libgit2.git/blame - tests/core/link.c
New upstream version 1.1.0+dfsg.1
[libgit2.git] / tests / core / link.c
CommitLineData
65477db1
ET
1#include "clar_libgit2.h"
2#include "posix.h"
3#include "buffer.h"
4#include "path.h"
5
6#ifdef GIT_WIN32
7# include "win32/reparse.h"
8#endif
9
10void test_core_link__cleanup(void)
11{
12#ifdef GIT_WIN32
13 RemoveDirectory("lstat_junction");
14 RemoveDirectory("lstat_dangling");
15 RemoveDirectory("lstat_dangling_dir");
16 RemoveDirectory("lstat_dangling_junction");
17
18 RemoveDirectory("stat_junction");
19 RemoveDirectory("stat_dangling");
20 RemoveDirectory("stat_dangling_dir");
21 RemoveDirectory("stat_dangling_junction");
22#endif
23}
24
25#ifdef GIT_WIN32
6b11eb51 26static bool should_run(void)
65477db1
ET
27{
28 static SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
29 PSID admin_sid;
30 BOOL is_admin;
31
32 cl_win32_pass(AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &admin_sid));
33 cl_win32_pass(CheckTokenMembership(NULL, admin_sid, &is_admin));
34 FreeSid(admin_sid);
35
36 return is_admin ? true : false;
37}
6b11eb51
ET
38#else
39static bool should_run(void)
40{
41 return true;
42}
65477db1
ET
43#endif
44
45static void do_symlink(const char *old, const char *new, int is_dir)
46{
47#ifndef GIT_WIN32
48 GIT_UNUSED(is_dir);
49
50 cl_must_pass(symlink(old, new));
51#else
52 typedef DWORD (WINAPI *create_symlink_func)(LPCTSTR, LPCTSTR, DWORD);
53 HMODULE module;
54 create_symlink_func pCreateSymbolicLink;
55
65477db1 56 cl_assert(module = GetModuleHandle("kernel32"));
22a2d3d5 57 cl_assert(pCreateSymbolicLink = (create_symlink_func)(void *)GetProcAddress(module, "CreateSymbolicLinkA"));
65477db1
ET
58
59 cl_win32_pass(pCreateSymbolicLink(new, old, is_dir));
60#endif
61}
62
63static void do_hardlink(const char *old, const char *new)
64{
65#ifndef GIT_WIN32
66 cl_must_pass(link(old, new));
67#else
68 typedef DWORD (WINAPI *create_hardlink_func)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES);
69 HMODULE module;
70 create_hardlink_func pCreateHardLink;
71
65477db1 72 cl_assert(module = GetModuleHandle("kernel32"));
22a2d3d5 73 cl_assert(pCreateHardLink = (create_hardlink_func)(void *)GetProcAddress(module, "CreateHardLinkA"));
65477db1
ET
74
75 cl_win32_pass(pCreateHardLink(new, old, 0));
76#endif
77}
78
79#ifdef GIT_WIN32
80
81static void do_junction(const char *old, const char *new)
82{
83 GIT_REPARSE_DATA_BUFFER *reparse_buf;
84 HANDLE handle;
85 git_buf unparsed_buf = GIT_BUF_INIT;
86 wchar_t *subst_utf16, *print_utf16;
87 DWORD ioctl_ret;
88 int subst_utf16_len, subst_byte_len, print_utf16_len, print_byte_len, ret;
89 USHORT reparse_buflen;
90 size_t i;
91
92 /* Junction targets must be the unparsed name, starting with \??\, using
93 * backslashes instead of forward, and end in a trailing backslash.
94 * eg: \??\C:\Foo\
95 */
96 git_buf_puts(&unparsed_buf, "\\??\\");
97
98 for (i = 0; i < strlen(old); i++)
99 git_buf_putc(&unparsed_buf, old[i] == '/' ? '\\' : old[i]);
100
101 git_buf_putc(&unparsed_buf, '\\');
102
103 subst_utf16_len = git__utf8_to_16(NULL, 0, git_buf_cstr(&unparsed_buf));
104 subst_byte_len = subst_utf16_len * sizeof(WCHAR);
105
106 print_utf16_len = subst_utf16_len - 4;
107 print_byte_len = subst_byte_len - (4 * sizeof(WCHAR));
108
109 /* The junction must be an empty directory before the junction attribute
110 * can be added.
111 */
112 cl_win32_pass(CreateDirectoryA(new, NULL));
113
114 handle = CreateFileA(new, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
115 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
116 cl_win32_pass(handle != INVALID_HANDLE_VALUE);
117
118 reparse_buflen = (USHORT)(REPARSE_DATA_HEADER_SIZE +
119 REPARSE_DATA_MOUNTPOINT_HEADER_SIZE +
120 subst_byte_len + sizeof(WCHAR) +
121 print_byte_len + sizeof(WCHAR));
122
123 reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
124 cl_assert(reparse_buf);
125
126 subst_utf16 = reparse_buf->MountPointReparseBuffer.PathBuffer;
127 print_utf16 = subst_utf16 + subst_utf16_len + 1;
128
129 ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1,
130 git_buf_cstr(&unparsed_buf));
131 cl_assert_equal_i(subst_utf16_len, ret);
132
133 ret = git__utf8_to_16(print_utf16,
134 print_utf16_len + 1, git_buf_cstr(&unparsed_buf) + 4);
135 cl_assert_equal_i(print_utf16_len, ret);
136
137 reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
138 reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0;
7110000d 139 reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len;
65477db1
ET
140 reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
141 reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len;
142 reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE;
143
144 cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
145 reparse_buf, reparse_buflen, NULL, 0, &ioctl_ret, NULL));
146
147 CloseHandle(handle);
148 LocalFree(reparse_buf);
6b11eb51 149
ac3d33df 150 git_buf_dispose(&unparsed_buf);
65477db1
ET
151}
152
153static void do_custom_reparse(const char *path)
154{
155 REPARSE_GUID_DATA_BUFFER *reparse_buf;
156 HANDLE handle;
157 DWORD ioctl_ret;
158
159 const char *reparse_data = "Reparse points are silly.";
160 size_t reparse_buflen = REPARSE_GUID_DATA_BUFFER_HEADER_SIZE +
161 strlen(reparse_data) + 1;
162
163 reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
164 cl_assert(reparse_buf);
165
166 reparse_buf->ReparseTag = 42;
167 reparse_buf->ReparseDataLength = (WORD)(strlen(reparse_data) + 1);
168
169 reparse_buf->ReparseGuid.Data1 = 0xdeadbeef;
170 reparse_buf->ReparseGuid.Data2 = 0xdead;
171 reparse_buf->ReparseGuid.Data3 = 0xbeef;
172 reparse_buf->ReparseGuid.Data4[0] = 42;
173 reparse_buf->ReparseGuid.Data4[1] = 42;
174 reparse_buf->ReparseGuid.Data4[2] = 42;
175 reparse_buf->ReparseGuid.Data4[3] = 42;
176 reparse_buf->ReparseGuid.Data4[4] = 42;
177 reparse_buf->ReparseGuid.Data4[5] = 42;
178 reparse_buf->ReparseGuid.Data4[6] = 42;
179 reparse_buf->ReparseGuid.Data4[7] = 42;
180 reparse_buf->ReparseGuid.Data4[8] = 42;
181
182 memcpy(reparse_buf->GenericReparseBuffer.DataBuffer,
183 reparse_data, strlen(reparse_data) + 1);
184
185 handle = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
186 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
187 cl_win32_pass(handle != INVALID_HANDLE_VALUE);
188
189 cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
190 reparse_buf,
191 reparse_buf->ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
192 NULL, 0, &ioctl_ret, NULL));
193
194 CloseHandle(handle);
195 LocalFree(reparse_buf);
196}
197
198#endif
199
65477db1
ET
200void test_core_link__stat_regular_file(void)
201{
202 struct stat st;
203
204 cl_git_rewritefile("stat_regfile", "This is a regular file!\n");
205
206 cl_must_pass(p_stat("stat_regfile", &st));
207 cl_assert(S_ISREG(st.st_mode));
208 cl_assert_equal_i(24, st.st_size);
209}
210
211void test_core_link__lstat_regular_file(void)
212{
213 struct stat st;
214
215 cl_git_rewritefile("lstat_regfile", "This is a regular file!\n");
216
217 cl_must_pass(p_stat("lstat_regfile", &st));
218 cl_assert(S_ISREG(st.st_mode));
219 cl_assert_equal_i(24, st.st_size);
220}
221
222void test_core_link__stat_symlink(void)
223{
224 struct stat st;
225
6b11eb51
ET
226 if (!should_run())
227 clar__skip();
228
65477db1
ET
229 cl_git_rewritefile("stat_target", "This is the target of a symbolic link.\n");
230 do_symlink("stat_target", "stat_symlink", 0);
231
232 cl_must_pass(p_stat("stat_target", &st));
233 cl_assert(S_ISREG(st.st_mode));
234 cl_assert_equal_i(39, st.st_size);
235
236 cl_must_pass(p_stat("stat_symlink", &st));
237 cl_assert(S_ISREG(st.st_mode));
238 cl_assert_equal_i(39, st.st_size);
239}
240
241void test_core_link__stat_symlink_directory(void)
242{
243 struct stat st;
244
6b11eb51
ET
245 if (!should_run())
246 clar__skip();
247
65477db1
ET
248 p_mkdir("stat_dirtarget", 0777);
249 do_symlink("stat_dirtarget", "stat_dirlink", 1);
250
251 cl_must_pass(p_stat("stat_dirtarget", &st));
252 cl_assert(S_ISDIR(st.st_mode));
253
254 cl_must_pass(p_stat("stat_dirlink", &st));
255 cl_assert(S_ISDIR(st.st_mode));
256}
257
258void test_core_link__stat_symlink_chain(void)
259{
260 struct stat st;
261
6b11eb51
ET
262 if (!should_run())
263 clar__skip();
264
65477db1
ET
265 cl_git_rewritefile("stat_final_target", "Final target of some symbolic links...\n");
266 do_symlink("stat_final_target", "stat_chain_3", 0);
267 do_symlink("stat_chain_3", "stat_chain_2", 0);
268 do_symlink("stat_chain_2", "stat_chain_1", 0);
269
270 cl_must_pass(p_stat("stat_chain_1", &st));
271 cl_assert(S_ISREG(st.st_mode));
272 cl_assert_equal_i(39, st.st_size);
273}
274
275void test_core_link__stat_dangling_symlink(void)
276{
277 struct stat st;
278
6b11eb51
ET
279 if (!should_run())
280 clar__skip();
281
65477db1
ET
282 do_symlink("stat_nonexistent", "stat_dangling", 0);
283
284 cl_must_fail(p_stat("stat_nonexistent", &st));
285 cl_must_fail(p_stat("stat_dangling", &st));
286}
287
288void test_core_link__stat_dangling_symlink_directory(void)
289{
290 struct stat st;
291
6b11eb51
ET
292 if (!should_run())
293 clar__skip();
294
65477db1
ET
295 do_symlink("stat_nonexistent", "stat_dangling_dir", 1);
296
297 cl_must_fail(p_stat("stat_nonexistent_dir", &st));
298 cl_must_fail(p_stat("stat_dangling", &st));
299}
300
301void test_core_link__lstat_symlink(void)
302{
303 git_buf target_path = GIT_BUF_INIT;
304 struct stat st;
305
6b11eb51
ET
306 if (!should_run())
307 clar__skip();
308
65477db1
ET
309 /* Windows always writes the canonical path as the link target, so
310 * write the full path on all platforms.
311 */
312 git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_target");
313
314 cl_git_rewritefile("lstat_target", "This is the target of a symbolic link.\n");
315 do_symlink(git_buf_cstr(&target_path), "lstat_symlink", 0);
316
317 cl_must_pass(p_lstat("lstat_target", &st));
318 cl_assert(S_ISREG(st.st_mode));
319 cl_assert_equal_i(39, st.st_size);
320
321 cl_must_pass(p_lstat("lstat_symlink", &st));
322 cl_assert(S_ISLNK(st.st_mode));
323 cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
324
ac3d33df 325 git_buf_dispose(&target_path);
65477db1
ET
326}
327
328void test_core_link__lstat_symlink_directory(void)
329{
330 git_buf target_path = GIT_BUF_INIT;
331 struct stat st;
332
6b11eb51
ET
333 if (!should_run())
334 clar__skip();
335
65477db1
ET
336 git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_dirtarget");
337
338 p_mkdir("lstat_dirtarget", 0777);
339 do_symlink(git_buf_cstr(&target_path), "lstat_dirlink", 1);
340
341 cl_must_pass(p_lstat("lstat_dirtarget", &st));
342 cl_assert(S_ISDIR(st.st_mode));
343
344 cl_must_pass(p_lstat("lstat_dirlink", &st));
345 cl_assert(S_ISLNK(st.st_mode));
346 cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
347
ac3d33df 348 git_buf_dispose(&target_path);
65477db1
ET
349}
350
351void test_core_link__lstat_dangling_symlink(void)
352{
353 struct stat st;
354
6b11eb51
ET
355 if (!should_run())
356 clar__skip();
357
65477db1
ET
358 do_symlink("lstat_nonexistent", "lstat_dangling", 0);
359
360 cl_must_fail(p_lstat("lstat_nonexistent", &st));
361
362 cl_must_pass(p_lstat("lstat_dangling", &st));
363 cl_assert(S_ISLNK(st.st_mode));
364 cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
365}
366
367void test_core_link__lstat_dangling_symlink_directory(void)
368{
369 struct stat st;
370
6b11eb51
ET
371 if (!should_run())
372 clar__skip();
373
65477db1
ET
374 do_symlink("lstat_nonexistent", "lstat_dangling_dir", 1);
375
376 cl_must_fail(p_lstat("lstat_nonexistent", &st));
377
378 cl_must_pass(p_lstat("lstat_dangling_dir", &st));
379 cl_assert(S_ISLNK(st.st_mode));
380 cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
381}
382
383void test_core_link__stat_junction(void)
384{
385#ifdef GIT_WIN32
386 git_buf target_path = GIT_BUF_INIT;
387 struct stat st;
388
389 git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_junctarget");
390
391 p_mkdir("stat_junctarget", 0777);
392 do_junction(git_buf_cstr(&target_path), "stat_junction");
393
394 cl_must_pass(p_stat("stat_junctarget", &st));
395 cl_assert(S_ISDIR(st.st_mode));
396
397 cl_must_pass(p_stat("stat_junction", &st));
398 cl_assert(S_ISDIR(st.st_mode));
399
ac3d33df 400 git_buf_dispose(&target_path);
65477db1
ET
401#endif
402}
403
404void test_core_link__stat_dangling_junction(void)
405{
406#ifdef GIT_WIN32
407 git_buf target_path = GIT_BUF_INIT;
408 struct stat st;
409
410 git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_nonexistent_junctarget");
411
412 p_mkdir("stat_nonexistent_junctarget", 0777);
413 do_junction(git_buf_cstr(&target_path), "stat_dangling_junction");
414
415 RemoveDirectory("stat_nonexistent_junctarget");
416
417 cl_must_fail(p_stat("stat_nonexistent_junctarget", &st));
418 cl_must_fail(p_stat("stat_dangling_junction", &st));
419
ac3d33df 420 git_buf_dispose(&target_path);
65477db1
ET
421#endif
422}
423
424void test_core_link__lstat_junction(void)
425{
426#ifdef GIT_WIN32
427 git_buf target_path = GIT_BUF_INIT;
428 struct stat st;
429
430 git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_junctarget");
431
432 p_mkdir("lstat_junctarget", 0777);
433 do_junction(git_buf_cstr(&target_path), "lstat_junction");
434
435 cl_must_pass(p_lstat("lstat_junctarget", &st));
436 cl_assert(S_ISDIR(st.st_mode));
437
438 cl_must_pass(p_lstat("lstat_junction", &st));
439 cl_assert(S_ISLNK(st.st_mode));
440
ac3d33df 441 git_buf_dispose(&target_path);
65477db1
ET
442#endif
443}
444
445void test_core_link__lstat_dangling_junction(void)
446{
447#ifdef GIT_WIN32
448 git_buf target_path = GIT_BUF_INIT;
449 struct stat st;
450
451 git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_nonexistent_junctarget");
452
453 p_mkdir("lstat_nonexistent_junctarget", 0777);
454 do_junction(git_buf_cstr(&target_path), "lstat_dangling_junction");
455
456 RemoveDirectory("lstat_nonexistent_junctarget");
457
458 cl_must_fail(p_lstat("lstat_nonexistent_junctarget", &st));
459
460 cl_must_pass(p_lstat("lstat_dangling_junction", &st));
461 cl_assert(S_ISLNK(st.st_mode));
462 cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
463
ac3d33df 464 git_buf_dispose(&target_path);
65477db1
ET
465#endif
466}
467
468void test_core_link__stat_hardlink(void)
469{
470 struct stat st;
471
6b11eb51
ET
472 if (!should_run())
473 clar__skip();
474
65477db1
ET
475 cl_git_rewritefile("stat_hardlink1", "This file has many names!\n");
476 do_hardlink("stat_hardlink1", "stat_hardlink2");
477
478 cl_must_pass(p_stat("stat_hardlink1", &st));
479 cl_assert(S_ISREG(st.st_mode));
480 cl_assert_equal_i(26, st.st_size);
481
482 cl_must_pass(p_stat("stat_hardlink2", &st));
483 cl_assert(S_ISREG(st.st_mode));
484 cl_assert_equal_i(26, st.st_size);
485}
486
487void test_core_link__lstat_hardlink(void)
488{
489 struct stat st;
490
6b11eb51
ET
491 if (!should_run())
492 clar__skip();
493
65477db1
ET
494 cl_git_rewritefile("lstat_hardlink1", "This file has many names!\n");
495 do_hardlink("lstat_hardlink1", "lstat_hardlink2");
496
497 cl_must_pass(p_lstat("lstat_hardlink1", &st));
498 cl_assert(S_ISREG(st.st_mode));
499 cl_assert_equal_i(26, st.st_size);
500
501 cl_must_pass(p_lstat("lstat_hardlink2", &st));
502 cl_assert(S_ISREG(st.st_mode));
503 cl_assert_equal_i(26, st.st_size);
504}
505
506void test_core_link__stat_reparse_point(void)
507{
508#ifdef GIT_WIN32
509 struct stat st;
510
511 /* Generic reparse points should be treated as regular files, only
512 * symlinks and junctions should be treated as links.
513 */
514
515 cl_git_rewritefile("stat_reparse", "This is a reparse point!\n");
516 do_custom_reparse("stat_reparse");
517
518 cl_must_pass(p_lstat("stat_reparse", &st));
519 cl_assert(S_ISREG(st.st_mode));
520 cl_assert_equal_i(25, st.st_size);
521#endif
522}
523
524void test_core_link__lstat_reparse_point(void)
525{
526#ifdef GIT_WIN32
527 struct stat st;
528
529 cl_git_rewritefile("lstat_reparse", "This is a reparse point!\n");
530 do_custom_reparse("lstat_reparse");
531
532 cl_must_pass(p_lstat("lstat_reparse", &st));
533 cl_assert(S_ISREG(st.st_mode));
534 cl_assert_equal_i(25, st.st_size);
535#endif
536}
537
538void test_core_link__readlink_nonexistent_file(void)
539{
540 char buf[2048];
541
542 cl_must_fail(p_readlink("readlink_nonexistent", buf, 2048));
543 cl_assert_equal_i(ENOENT, errno);
544}
545
546void test_core_link__readlink_normal_file(void)
547{
548 char buf[2048];
549
550 cl_git_rewritefile("readlink_regfile", "This is a regular file!\n");
551 cl_must_fail(p_readlink("readlink_regfile", buf, 2048));
552 cl_assert_equal_i(EINVAL, errno);
553}
554
555void test_core_link__readlink_symlink(void)
556{
557 git_buf target_path = GIT_BUF_INIT;
558 int len;
559 char buf[2048];
560
6b11eb51
ET
561 if (!should_run())
562 clar__skip();
563
65477db1
ET
564 git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_target");
565
566 cl_git_rewritefile("readlink_target", "This is the target of a symlink\n");
567 do_symlink(git_buf_cstr(&target_path), "readlink_link", 0);
568
569 len = p_readlink("readlink_link", buf, 2048);
570 cl_must_pass(len);
571
572 buf[len] = 0;
573
cceae9a2 574 cl_assert_equal_s(git_buf_cstr(&target_path), buf);
65477db1 575
ac3d33df 576 git_buf_dispose(&target_path);
65477db1
ET
577}
578
579void test_core_link__readlink_dangling(void)
580{
581 git_buf target_path = GIT_BUF_INIT;
582 int len;
583 char buf[2048];
584
6b11eb51
ET
585 if (!should_run())
586 clar__skip();
587
65477db1
ET
588 git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_nonexistent");
589
590 do_symlink(git_buf_cstr(&target_path), "readlink_dangling", 0);
591
592 len = p_readlink("readlink_dangling", buf, 2048);
593 cl_must_pass(len);
594
595 buf[len] = 0;
596
cceae9a2 597 cl_assert_equal_s(git_buf_cstr(&target_path), buf);
65477db1 598
ac3d33df 599 git_buf_dispose(&target_path);
65477db1
ET
600}
601
602void test_core_link__readlink_multiple(void)
603{
604 git_buf target_path = GIT_BUF_INIT,
605 path3 = GIT_BUF_INIT, path2 = GIT_BUF_INIT, path1 = GIT_BUF_INIT;
606 int len;
607 char buf[2048];
608
6b11eb51
ET
609 if (!should_run())
610 clar__skip();
611
65477db1
ET
612 git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_final");
613 git_buf_join(&path3, '/', clar_sandbox_path(), "readlink_3");
614 git_buf_join(&path2, '/', clar_sandbox_path(), "readlink_2");
615 git_buf_join(&path1, '/', clar_sandbox_path(), "readlink_1");
616
617 do_symlink(git_buf_cstr(&target_path), git_buf_cstr(&path3), 0);
618 do_symlink(git_buf_cstr(&path3), git_buf_cstr(&path2), 0);
619 do_symlink(git_buf_cstr(&path2), git_buf_cstr(&path1), 0);
620
621 len = p_readlink("readlink_1", buf, 2048);
622 cl_must_pass(len);
623
624 buf[len] = 0;
625
cceae9a2 626 cl_assert_equal_s(git_buf_cstr(&path2), buf);
65477db1 627
ac3d33df
JK
628 git_buf_dispose(&path1);
629 git_buf_dispose(&path2);
630 git_buf_dispose(&path3);
631 git_buf_dispose(&target_path);
65477db1 632}