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
d4b953f8
Unverified
Commit
d4b953f8
authored
Jun 02, 2020
by
Edward Thomson
Committed by
GitHub
Jun 02, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5528 from libgit2/ethomson/clar_internal
clar: use internal functions instead of /bin/cp and /bin/rm
parents
849f371e
2a2c5b40
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
191 additions
and
44 deletions
+191
-44
tests/clar/fs.h
+191
-44
No files found.
tests/clar/fs.h
View file @
d4b953f8
/*
* By default, use a read/write loop to copy files on POSIX systems.
* On Linux, use sendfile by default as it's slightly faster. On
* macOS, we avoid fcopyfile by default because it's slightly slower.
*/
#undef USE_FCOPYFILE
#define USE_SENDFILE 1
#ifdef _WIN32
#ifdef _WIN32
#define RM_RETRY_COUNT 5
#define RM_RETRY_COUNT 5
...
@@ -254,74 +262,213 @@ cl_fs_cleanup(void)
...
@@ -254,74 +262,213 @@ cl_fs_cleanup(void)
#include <errno.h>
#include <errno.h>
#include <string.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__linux__)
# include <sys/sendfile.h>
#endif
static
int
#if defined(__APPLE__) || defined(__FreeBSD__)
shell_out
(
char
*
const
argv
[])
# include <copyfile.h>
#endif
static
void
basename_r
(
const
char
**
out
,
int
*
out_len
,
const
char
*
in
)
{
{
int
status
,
piderr
;
size_t
in_len
=
strlen
(
in
),
start_pos
;
pid_t
pid
;
for
(
in_len
=
strlen
(
in
);
in_len
;
in_len
--
)
{
if
(
in
[
in_len
-
1
]
!=
'/'
)
break
;
}
for
(
start_pos
=
in_len
;
start_pos
;
start_pos
--
)
{
if
(
in
[
start_pos
-
1
]
==
'/'
)
break
;
}
pid
=
fork
(
);
cl_assert
(
in_len
-
start_pos
<
INT_MAX
);
if
(
pid
<
0
)
{
if
(
in_len
-
start_pos
>
0
)
{
fprintf
(
stderr
,
*
out
=
&
in
[
start_pos
];
"System error: `fork()` call failed (%d) - %s
\n
"
,
*
out_len
=
(
in_len
-
start_pos
);
errno
,
strerror
(
errno
));
}
else
{
exit
(
-
1
);
*
out
=
"/"
;
*
out_len
=
1
;
}
}
}
static
char
*
joinpath
(
const
char
*
dir
,
const
char
*
base
,
int
base_len
)
{
char
*
out
;
int
len
;
if
(
pid
==
0
)
{
if
(
base_len
==
-
1
)
{
execv
(
argv
[
0
],
argv
);
size_t
bl
=
strlen
(
base
);
cl_assert
(
bl
<
INT_MAX
);
base_len
=
(
int
)
bl
;
}
}
do
{
len
=
strlen
(
dir
)
+
base_len
+
2
;
piderr
=
waitpid
(
pid
,
&
status
,
WUNTRACED
);
cl_assert
(
len
>
0
);
}
while
(
piderr
<
0
&&
(
errno
==
EAGAIN
||
errno
==
EINTR
));
cl_assert
(
out
=
malloc
(
len
));
cl_assert
(
snprintf
(
out
,
len
,
"%s/%.*s"
,
dir
,
base_len
,
base
)
<
len
);
return
out
;
}
static
void
fs_copydir_helper
(
const
char
*
source
,
const
char
*
dest
,
int
dest_mode
)
{
DIR
*
source_dir
;
struct
dirent
*
d
;
mkdir
(
dest
,
dest_mode
);
cl_assert_
(
source_dir
=
opendir
(
source
),
"Could not open source dir"
);
while
((
d
=
(
errno
=
0
,
readdir
(
source_dir
)))
!=
NULL
)
{
char
*
child
;
if
(
!
strcmp
(
d
->
d_name
,
"."
)
||
!
strcmp
(
d
->
d_name
,
".."
))
continue
;
child
=
joinpath
(
source
,
d
->
d_name
,
-
1
);
fs_copy
(
child
,
dest
);
free
(
child
);
}
cl_assert_
(
errno
==
0
,
"Failed to iterate source dir"
);
closedir
(
source_dir
);
}
static
void
fs_copyfile_helper
(
const
char
*
source
,
size_t
source_len
,
const
char
*
dest
,
int
dest_mode
)
{
int
in
,
out
;
cl_must_pass
((
in
=
open
(
source
,
O_RDONLY
)));
cl_must_pass
((
out
=
open
(
dest
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
dest_mode
)));
#if USE_FCOPYFILE && (defined(__APPLE__) || defined(__FreeBSD__))
((
void
)(
source_len
));
/* unused */
cl_must_pass
(
fcopyfile
(
in
,
out
,
0
,
COPYFILE_DATA
));
#elif USE_SENDFILE && defined(__linux__)
{
ssize_t
ret
=
0
;
while
(
source_len
&&
(
ret
=
sendfile
(
out
,
in
,
NULL
,
source_len
))
>
0
)
{
source_len
-=
(
size_t
)
ret
;
}
cl_assert
(
ret
>=
0
);
}
#else
{
char
buf
[
131072
];
ssize_t
ret
;
((
void
)(
source_len
));
/* unused */
return
WEXITSTATUS
(
status
);
while
((
ret
=
read
(
in
,
buf
,
sizeof
(
buf
)))
>
0
)
{
size_t
len
=
(
size_t
)
ret
;
while
(
len
&&
(
ret
=
write
(
out
,
buf
,
len
))
>
0
)
{
cl_assert
(
ret
<=
(
ssize_t
)
len
);
len
-=
ret
;
}
cl_assert
(
ret
>=
0
);
}
cl_assert
(
ret
==
0
);
}
#endif
close
(
in
);
close
(
out
);
}
}
static
void
static
void
fs_copy
(
const
char
*
_source
,
const
char
*
dest
)
fs_copy
(
const
char
*
source
,
const
char
*
_
dest
)
{
{
char
*
argv
[
5
];
char
*
dbuf
=
NULL
;
char
*
source
;
const
char
*
dest
;
size_t
source_len
;
struct
stat
source_st
,
dest_st
;
cl_must_pass_
(
lstat
(
source
,
&
source_st
),
"Failed to stat copy source"
);
source
=
strdup
(
_source
);
if
(
lstat
(
_dest
,
&
dest_st
)
==
0
)
{
source_len
=
strlen
(
source
);
const
char
*
base
;
int
base_len
;
if
(
source
[
source_len
-
1
]
==
'/'
)
/* Target exists and is directory; append basename */
source
[
source_len
-
1
]
=
0
;
cl_assert
(
S_ISDIR
(
dest_st
.
st_mode
))
;
argv
[
0
]
=
"/bin/cp"
;
basename_r
(
&
base
,
&
base_len
,
source
);
argv
[
1
]
=
"-R"
;
cl_assert
(
base_len
<
INT_MAX
);
argv
[
2
]
=
source
;
argv
[
3
]
=
(
char
*
)
dest
;
argv
[
4
]
=
NULL
;
cl_must_pass_
(
dbuf
=
joinpath
(
_dest
,
base
,
base_len
);
shell_out
(
argv
),
dest
=
dbuf
;
"Failed to copy test fixtures to sandbox"
}
else
if
(
errno
!=
ENOENT
)
{
);
cl_fail
(
"Cannot copy; cannot stat destination"
);
}
else
{
dest
=
_dest
;
}
free
(
source
);
if
(
S_ISDIR
(
source_st
.
st_mode
))
{
fs_copydir_helper
(
source
,
dest
,
source_st
.
st_mode
);
}
else
{
fs_copyfile_helper
(
source
,
source_st
.
st_size
,
dest
,
source_st
.
st_mode
);
}
free
(
dbuf
);
}
}
static
void
static
void
fs_rm
(
const
char
*
source
)
fs_rm
dir_helper
(
const
char
*
path
)
{
{
char
*
argv
[
4
];
DIR
*
dir
;
struct
dirent
*
d
;
cl_assert_
(
dir
=
opendir
(
path
),
"Could not open dir"
);
while
((
d
=
(
errno
=
0
,
readdir
(
dir
)))
!=
NULL
)
{
char
*
child
;
if
(
!
strcmp
(
d
->
d_name
,
"."
)
||
!
strcmp
(
d
->
d_name
,
".."
))
continue
;
argv
[
0
]
=
"/bin/rm"
;
child
=
joinpath
(
path
,
d
->
d_name
,
-
1
);
argv
[
1
]
=
"-Rf"
;
fs_rm
(
child
);
argv
[
2
]
=
(
char
*
)
source
;
free
(
child
);
argv
[
3
]
=
NULL
;
}
cl_assert_
(
errno
==
0
,
"Failed to iterate source dir"
);
closedir
(
dir
);
cl_must_pass_
(
rmdir
(
path
),
"Could not remove directory"
);
}
cl_must_pass_
(
static
void
shell_out
(
argv
),
fs_rm
(
const
char
*
path
)
"Failed to cleanup the sandbox"
{
);
struct
stat
st
;
if
(
lstat
(
path
,
&
st
))
{
if
(
errno
==
ENOENT
)
return
;
cl_fail
(
"Cannot copy; cannot stat destination"
);
}
if
(
S_ISDIR
(
st
.
st_mode
))
{
fs_rmdir_helper
(
path
);
}
else
{
cl_must_pass
(
unlink
(
path
));
}
}
}
void
void
...
...
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