Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
e1d27bca
Commit
e1d27bca
authored
9 years ago
by
Edward Thomson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3413 from libgit2/cmn/follow-symlink
filebuf: follow symlinks when creating a lock file
parents
9fd4c9c8
d83b2e9f
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
137 additions
and
3 deletions
+137
-3
CHANGELOG.md
+3
-0
src/filebuf.c
+81
-3
tests/core/filebuf.c
+53
-0
No files found.
CHANGELOG.md
View file @
e1d27bca
...
...
@@ -7,6 +7,9 @@ v0.23 + 1
example
`filter=*`
. Consumers should examine the attributes parameter
of the
`check`
function for details.
*
Symlinks are now followed when locking a file, which can be
necessary when multiple worktrees share a base repository.
### API additions
*
`git_config_lock()`
has been added, which allow for
...
...
This diff is collapsed.
Click to expand it.
src/filebuf.c
View file @
e1d27bca
...
...
@@ -191,6 +191,81 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
return
0
;
}
#define MAX_SYMLINK_DEPTH 5
static
int
resolve_symlink
(
git_buf
*
out
,
const
char
*
path
)
{
int
i
,
error
,
root
;
ssize_t
ret
;
struct
stat
st
;
git_buf
curpath
=
GIT_BUF_INIT
,
target
=
GIT_BUF_INIT
;
if
((
error
=
git_buf_grow
(
&
target
,
GIT_PATH_MAX
+
1
))
<
0
||
(
error
=
git_buf_puts
(
&
curpath
,
path
))
<
0
)
return
error
;
for
(
i
=
0
;
i
<
MAX_SYMLINK_DEPTH
;
i
++
)
{
error
=
p_lstat
(
curpath
.
ptr
,
&
st
);
if
(
error
<
0
&&
errno
==
ENOENT
)
{
error
=
git_buf_puts
(
out
,
curpath
.
ptr
);
goto
cleanup
;
}
if
(
error
<
0
)
{
giterr_set
(
GITERR_OS
,
"failed to stat '%s'"
,
curpath
.
ptr
);
error
=
-
1
;
goto
cleanup
;
}
if
(
!
S_ISLNK
(
st
.
st_mode
))
{
error
=
git_buf_puts
(
out
,
curpath
.
ptr
);
goto
cleanup
;
}
ret
=
p_readlink
(
curpath
.
ptr
,
target
.
ptr
,
GIT_PATH_MAX
);
if
(
ret
<
0
)
{
giterr_set
(
GITERR_OS
,
"failed to read symlink '%s'"
,
curpath
.
ptr
);
error
=
-
1
;
goto
cleanup
;
}
if
(
ret
==
GIT_PATH_MAX
)
{
giterr_set
(
GITERR_INVALID
,
"symlink target too long"
);
error
=
-
1
;
goto
cleanup
;
}
/* readlink(2) won't NUL-terminate for us */
target
.
ptr
[
ret
]
=
'\0'
;
target
.
size
=
ret
;
root
=
git_path_root
(
target
.
ptr
);
if
(
root
>=
0
)
{
if
((
error
=
git_buf_puts
(
&
curpath
,
target
.
ptr
))
<
0
)
goto
cleanup
;
}
else
{
git_buf
dir
=
GIT_BUF_INIT
;
if
((
error
=
git_path_dirname_r
(
&
dir
,
curpath
.
ptr
))
<
0
)
goto
cleanup
;
git_buf_swap
(
&
curpath
,
&
dir
);
git_buf_free
(
&
dir
);
if
((
error
=
git_path_apply_relative
(
&
curpath
,
target
.
ptr
))
<
0
)
goto
cleanup
;
}
}
giterr_set
(
GITERR_INVALID
,
"maximum symlink depth reached"
);
error
=
-
1
;
cleanup
:
git_buf_free
(
&
curpath
);
git_buf_free
(
&
target
);
return
error
;
}
int
git_filebuf_open
(
git_filebuf
*
file
,
const
char
*
path
,
int
flags
,
mode_t
mode
)
{
int
compression
,
error
=
-
1
;
...
...
@@ -265,11 +340,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
file
->
path_lock
=
git_buf_detach
(
&
tmp_path
);
GITERR_CHECK_ALLOC
(
file
->
path_lock
);
}
else
{
path_len
=
strlen
(
path
);
git_buf
resolved_path
=
GIT_BUF_INIT
;
if
((
error
=
resolve_symlink
(
&
resolved_path
,
path
))
<
0
)
goto
cleanup
;
/* Save the original path of the file */
file
->
path_original
=
git__strdup
(
path
)
;
GITERR_CHECK_ALLOC
(
file
->
path_original
);
path_len
=
resolved_path
.
size
;
file
->
path_original
=
git_buf_detach
(
&
resolved_path
);
/* create the locking path by appending ".lock" to the original */
GITERR_CHECK_ALLOC_ADD
(
&
alloc_len
,
path_len
,
GIT_FILELOCK_EXTLENGTH
);
...
...
This diff is collapsed.
Click to expand it.
tests/core/filebuf.c
View file @
e1d27bca
...
...
@@ -151,3 +151,56 @@ void test_core_filebuf__rename_error(void)
cl_assert_equal_i
(
false
,
git_path_exists
(
test_lock
));
}
void
test_core_filebuf__symlink_follow
(
void
)
{
git_filebuf
file
=
GIT_FILEBUF_INIT
;
const
char
*
dir
=
"linkdir"
,
*
source
=
"linkdir/link"
;
#ifdef GIT_WIN32
cl_skip
();
#endif
cl_git_pass
(
p_mkdir
(
dir
,
0777
));
cl_git_pass
(
p_symlink
(
"target"
,
source
));
cl_git_pass
(
git_filebuf_open
(
&
file
,
source
,
0
,
0666
));
cl_git_pass
(
git_filebuf_printf
(
&
file
,
"%s
\n
"
,
"libgit2 rocks"
));
cl_assert_equal_i
(
true
,
git_path_exists
(
"linkdir/target.lock"
));
cl_git_pass
(
git_filebuf_commit
(
&
file
));
cl_assert_equal_i
(
true
,
git_path_exists
(
"linkdir/target"
));
git_filebuf_cleanup
(
&
file
);
/* The second time around, the target file does exist */
cl_git_pass
(
git_filebuf_open
(
&
file
,
source
,
0
,
0666
));
cl_git_pass
(
git_filebuf_printf
(
&
file
,
"%s
\n
"
,
"libgit2 rocks"
));
cl_assert_equal_i
(
true
,
git_path_exists
(
"linkdir/target.lock"
));
cl_git_pass
(
git_filebuf_commit
(
&
file
));
cl_assert_equal_i
(
true
,
git_path_exists
(
"linkdir/target"
));
git_filebuf_cleanup
(
&
file
);
cl_git_pass
(
git_futils_rmdir_r
(
dir
,
NULL
,
GIT_RMDIR_REMOVE_FILES
));
}
void
test_core_filebuf__symlink_depth
(
void
)
{
git_filebuf
file
=
GIT_FILEBUF_INIT
;
const
char
*
dir
=
"linkdir"
,
*
source
=
"linkdir/link"
;
#ifdef GIT_WIN32
cl_skip
();
#endif
cl_git_pass
(
p_mkdir
(
dir
,
0777
));
/* Endless loop */
cl_git_pass
(
p_symlink
(
"link"
,
source
));
cl_git_fail
(
git_filebuf_open
(
&
file
,
source
,
0
,
0666
));
cl_git_pass
(
git_futils_rmdir_r
(
dir
,
NULL
,
GIT_RMDIR_REMOVE_FILES
));
}
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment