mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 09:41:03 -04:00
libc: Add fscandir(), fscandir_b(), scandirat_b().
While here, clean up scandir() a bit and improve the documentation. MFC after: never Sponsored by: Klara, Inc. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D50935
This commit is contained in:
parent
609720ed97
commit
deeebfdeca
8 changed files with 410 additions and 42 deletions
|
|
@ -130,9 +130,22 @@ int scandir_b(const char *, struct dirent ***,
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if __BSD_VISIBLE
|
#if __BSD_VISIBLE
|
||||||
|
int fscandir(int, struct dirent ***,
|
||||||
|
int (*)(const struct dirent *), int (*)(const struct dirent **,
|
||||||
|
const struct dirent **));
|
||||||
|
#ifdef __BLOCKS__
|
||||||
|
int fscandir_b(int, struct dirent ***,
|
||||||
|
int (^)(const struct dirent *),
|
||||||
|
int (^)(const struct dirent **, const struct dirent **));
|
||||||
|
#endif
|
||||||
int scandirat(int, const char *, struct dirent ***,
|
int scandirat(int, const char *, struct dirent ***,
|
||||||
int (*)(const struct dirent *), int (*)(const struct dirent **,
|
int (*)(const struct dirent *), int (*)(const struct dirent **,
|
||||||
const struct dirent **));
|
const struct dirent **));
|
||||||
|
#ifdef __BLOCKS__
|
||||||
|
int scandirat_b(int, const char *, struct dirent ***,
|
||||||
|
int (^)(const struct dirent *),
|
||||||
|
int (^)(const struct dirent **, const struct dirent **));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if __XSI_VISIBLE
|
#if __XSI_VISIBLE
|
||||||
void seekdir(DIR *, long);
|
void seekdir(DIR *, long);
|
||||||
|
|
|
||||||
|
|
@ -499,8 +499,11 @@ MLINKS+=rand48.3 _rand48.3 \
|
||||||
MLINKS+=rtld_get_var.3 \
|
MLINKS+=rtld_get_var.3 \
|
||||||
rtld_set_var.3
|
rtld_set_var.3
|
||||||
MLINKS+=scandir.3 alphasort.3 \
|
MLINKS+=scandir.3 alphasort.3 \
|
||||||
scandir.3 scandirat.3 \
|
scandir.3 fscandir.3 \
|
||||||
|
scandir.3 fscandir_b.3 \
|
||||||
scandir.3 scandir_b.3 \
|
scandir.3 scandir_b.3 \
|
||||||
|
scandir.3 scandirat.3 \
|
||||||
|
scandir.3 scandirat_b.3 \
|
||||||
scandir.3 versionsort.3
|
scandir.3 versionsort.3
|
||||||
MLINKS+=sem_open.3 sem_close.3 \
|
MLINKS+=sem_open.3 sem_close.3 \
|
||||||
sem_open.3 sem_unlink.3
|
sem_open.3 sem_unlink.3
|
||||||
|
|
|
||||||
|
|
@ -458,11 +458,14 @@ FBSD_1.8 {
|
||||||
aio_read2;
|
aio_read2;
|
||||||
aio_write2;
|
aio_write2;
|
||||||
execvpe;
|
execvpe;
|
||||||
|
fscandir;
|
||||||
|
fscandir_b;
|
||||||
fts_open_b;
|
fts_open_b;
|
||||||
glob_b;
|
glob_b;
|
||||||
psiginfo;
|
psiginfo;
|
||||||
rtld_get_var;
|
rtld_get_var;
|
||||||
rtld_set_var;
|
rtld_set_var;
|
||||||
|
scandirat_b;
|
||||||
uexterr_gettext;
|
uexterr_gettext;
|
||||||
sig2str;
|
sig2str;
|
||||||
str2sig;
|
str2sig;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,16 @@
|
||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd August 31, 2023
|
.Dd June 19, 2025
|
||||||
.Dt SCANDIR 3
|
.Dt SCANDIR 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm scandir ,
|
.Nm scandir ,
|
||||||
|
.Nm fscandir ,
|
||||||
.Nm scandirat ,
|
.Nm scandirat ,
|
||||||
.Nm scandir_b ,
|
.Nm scandir_b ,
|
||||||
|
.Nm fscandir_b ,
|
||||||
|
.Nm fscandirat_b ,
|
||||||
.Nm alphasort ,
|
.Nm alphasort ,
|
||||||
.Nm versionsort
|
.Nm versionsort
|
||||||
.Nd scan a directory
|
.Nd scan a directory
|
||||||
|
|
@ -47,6 +50,13 @@
|
||||||
.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||||
.Fc
|
.Fc
|
||||||
.Ft int
|
.Ft int
|
||||||
|
.Fo fscandir
|
||||||
|
.Fa "int dirfd"
|
||||||
|
.Fa "struct dirent ***namelist"
|
||||||
|
.Fa "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp"
|
||||||
|
.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
.Fo scandirat
|
.Fo scandirat
|
||||||
.Fa "int dirfd"
|
.Fa "int dirfd"
|
||||||
.Fa "const char *dirname"
|
.Fa "const char *dirname"
|
||||||
|
|
@ -62,6 +72,21 @@
|
||||||
.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||||
.Fc
|
.Fc
|
||||||
.Ft int
|
.Ft int
|
||||||
|
.Fo fscandir_b
|
||||||
|
.Fa "int dirfd"
|
||||||
|
.Fa "struct dirent ***namelist"
|
||||||
|
.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp"
|
||||||
|
.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo scandirat_b
|
||||||
|
.Fa "int dirfd"
|
||||||
|
.Fa "const char *dirname"
|
||||||
|
.Fa "struct dirent ***namelist"
|
||||||
|
.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp"
|
||||||
|
.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
|
.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn versionsort "const struct dirent **d1" "const struct dirent **d2"
|
.Fn versionsort "const struct dirent **d1" "const struct dirent **d2"
|
||||||
|
|
@ -118,6 +143,13 @@ The memory allocated for the array can be deallocated with
|
||||||
by freeing each pointer in the array and then the array itself.
|
by freeing each pointer in the array and then the array itself.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
|
.Fn fscandir
|
||||||
|
function is similar to
|
||||||
|
.Fn scandir ,
|
||||||
|
but takes a file descriptor referencing a directory instead of a path.
|
||||||
|
The file descriptor is left open on return, regardless of outcome.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
.Fn scandirat
|
.Fn scandirat
|
||||||
function is similar to
|
function is similar to
|
||||||
.Fn scandir ,
|
.Fn scandir ,
|
||||||
|
|
@ -151,17 +183,37 @@ See
|
||||||
for additional details.
|
for additional details.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fn scandir_b
|
.Fn scandir_b ,
|
||||||
function behaves in the same way as
|
.Fn fscandir_b ,
|
||||||
|
and
|
||||||
|
.Fn scandirat_b
|
||||||
|
functions behave in the same way as
|
||||||
.Fn scandir ,
|
.Fn scandir ,
|
||||||
but takes blocks as arguments instead of function pointers and calls
|
.Fn fscandir ,
|
||||||
|
and
|
||||||
|
.Fn scandirat ,
|
||||||
|
respectively,
|
||||||
|
but take blocks as arguments instead of function pointers and call
|
||||||
.Fn qsort_b
|
.Fn qsort_b
|
||||||
rather than
|
rather than
|
||||||
.Fn qsort .
|
.Fn qsort .
|
||||||
.Sh DIAGNOSTICS
|
.Sh DIAGNOSTICS
|
||||||
Returns \-1 if the directory cannot be opened for reading or if
|
The
|
||||||
|
.Fn scandir ,
|
||||||
|
.Fn fscandir ,
|
||||||
|
.Fn scandirat ,
|
||||||
|
.Fn scandir_b ,
|
||||||
|
.Fn fscandir_b ,
|
||||||
|
and
|
||||||
|
.Fn scandirat_b
|
||||||
|
functions return the number of directory entries found on succes.
|
||||||
|
If the directory cannot be opened for reading, an error occurs
|
||||||
|
while reading the directory, or
|
||||||
.Xr malloc 3
|
.Xr malloc 3
|
||||||
cannot allocate enough memory to hold all the data structures.
|
cannot allocate enough memory to hold all the directory entries,
|
||||||
|
they return \-1 and set
|
||||||
|
.Va errno
|
||||||
|
to an appropriate value.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr openat 2 ,
|
.Xr openat 2 ,
|
||||||
.Xr directory 3 ,
|
.Xr directory 3 ,
|
||||||
|
|
@ -172,8 +224,25 @@ cannot allocate enough memory to hold all the data structures.
|
||||||
.Xr dir 5
|
.Xr dir 5
|
||||||
.Sh STANDARDS
|
.Sh STANDARDS
|
||||||
The
|
The
|
||||||
|
.Fn alphasort
|
||||||
|
and
|
||||||
|
.Fn scandir
|
||||||
|
functions are expected to conform to
|
||||||
|
.St -p1003.1-2008 .
|
||||||
|
The
|
||||||
|
.Fn scandirat
|
||||||
|
and
|
||||||
.Fn versionsort
|
.Fn versionsort
|
||||||
function is a GNU extension and conforms to no standard.
|
functions are GNU extensions and conform to no standard.
|
||||||
|
The
|
||||||
|
.Fn fscandir ,
|
||||||
|
.Fn scandir_b ,
|
||||||
|
.Fn fscandir_b ,
|
||||||
|
and
|
||||||
|
.Fn scandirat_b
|
||||||
|
functions are
|
||||||
|
.Fx
|
||||||
|
extensions.
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Fn scandir
|
.Fn scandir
|
||||||
|
|
@ -182,8 +251,19 @@ and
|
||||||
functions appeared in
|
functions appeared in
|
||||||
.Bx 4.2 .
|
.Bx 4.2 .
|
||||||
The
|
The
|
||||||
|
.Fn scandir_b
|
||||||
|
function was added in
|
||||||
|
.Fx 11.0 .
|
||||||
|
The
|
||||||
.Fn scandirat
|
.Fn scandirat
|
||||||
and
|
and
|
||||||
.Fn versionsort
|
.Fn versionsort
|
||||||
functions were added in
|
functions were added in
|
||||||
.Fx 13.2 .
|
.Fx 13.2 .
|
||||||
|
The
|
||||||
|
.Fn fscandir ,
|
||||||
|
.Fn fscandir_b ,
|
||||||
|
and
|
||||||
|
.Fn scandirat_b
|
||||||
|
functions were added in
|
||||||
|
.Fx 15.0 .
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -64,7 +65,7 @@ static int scandir_thunk_cmp(const void *p1, const void *p2, void *thunk);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
#ifdef I_AM_SCANDIR_B
|
#ifdef I_AM_SCANDIR_B
|
||||||
scandir_b_dirp(DIR *dirp, struct dirent ***namelist, select_block select,
|
scandir_dirp_b(DIR *dirp, struct dirent ***namelist, select_block select,
|
||||||
dcomp_block dcomp)
|
dcomp_block dcomp)
|
||||||
#else
|
#else
|
||||||
scandir_dirp(DIR *dirp, struct dirent ***namelist,
|
scandir_dirp(DIR *dirp, struct dirent ***namelist,
|
||||||
|
|
@ -72,14 +73,9 @@ scandir_dirp(DIR *dirp, struct dirent ***namelist,
|
||||||
const struct dirent **))
|
const struct dirent **))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct dirent *d, *p, **names = NULL;
|
struct dirent *d, *p = NULL, **names = NULL, **names2;
|
||||||
size_t arraysz, numitems;
|
size_t arraysz = 0, numitems = 0;
|
||||||
|
int serrno;
|
||||||
numitems = 0;
|
|
||||||
arraysz = 32; /* initial estimate of the array size */
|
|
||||||
names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
|
|
||||||
if (names == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
while ((d = readdir(dirp)) != NULL) {
|
while ((d = readdir(dirp)) != NULL) {
|
||||||
if (select != NULL && !SELECT(d))
|
if (select != NULL && !SELECT(d))
|
||||||
|
|
@ -87,33 +83,27 @@ scandir_dirp(DIR *dirp, struct dirent ***namelist,
|
||||||
/*
|
/*
|
||||||
* Make a minimum size copy of the data
|
* Make a minimum size copy of the data
|
||||||
*/
|
*/
|
||||||
p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d));
|
p = malloc(_GENERIC_DIRSIZ(d));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
p->d_fileno = d->d_fileno;
|
p->d_fileno = d->d_fileno;
|
||||||
p->d_type = d->d_type;
|
p->d_type = d->d_type;
|
||||||
p->d_reclen = d->d_reclen;
|
p->d_reclen = d->d_reclen;
|
||||||
p->d_namlen = d->d_namlen;
|
p->d_namlen = d->d_namlen;
|
||||||
bcopy(d->d_name, p->d_name, p->d_namlen + 1);
|
memcpy(p->d_name, d->d_name, p->d_namlen + 1);
|
||||||
/*
|
/*
|
||||||
* Check to make sure the array has space left and
|
* Check to make sure the array has space left and
|
||||||
* realloc the maximum size.
|
* realloc the maximum size.
|
||||||
*/
|
*/
|
||||||
if (numitems >= arraysz) {
|
if (numitems >= arraysz) {
|
||||||
struct dirent **names2;
|
arraysz = arraysz ? arraysz * 2 : 32;
|
||||||
|
names2 = reallocarray(names, arraysz, sizeof(*names));
|
||||||
names2 = reallocarray(names, arraysz,
|
if (names2 == NULL)
|
||||||
2 * sizeof(struct dirent *));
|
|
||||||
if (names2 == NULL) {
|
|
||||||
free(p);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
names = names2;
|
names = names2;
|
||||||
arraysz *= 2;
|
|
||||||
}
|
}
|
||||||
names[numitems++] = p;
|
names[numitems++] = p;
|
||||||
}
|
}
|
||||||
closedir(dirp);
|
|
||||||
if (numitems && dcomp != NULL)
|
if (numitems && dcomp != NULL)
|
||||||
#ifdef I_AM_SCANDIR_B
|
#ifdef I_AM_SCANDIR_B
|
||||||
qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp);
|
qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp);
|
||||||
|
|
@ -125,10 +115,12 @@ scandir_dirp(DIR *dirp, struct dirent ***namelist,
|
||||||
return (numitems);
|
return (numitems);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
serrno = errno;
|
||||||
|
free(p);
|
||||||
while (numitems > 0)
|
while (numitems > 0)
|
||||||
free(names[--numitems]);
|
free(names[--numitems]);
|
||||||
free(names);
|
free(names);
|
||||||
closedir(dirp);
|
errno = serrno;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,39 +135,82 @@ scandir(const char *dirname, struct dirent ***namelist,
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
|
int ret, serrno;
|
||||||
|
|
||||||
dirp = opendir(dirname);
|
dirp = opendir(dirname);
|
||||||
if (dirp == NULL)
|
if (dirp == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
return (
|
ret =
|
||||||
#ifdef I_AM_SCANDIR_B
|
#ifdef I_AM_SCANDIR_B
|
||||||
scandir_b_dirp
|
scandir_dirp_b
|
||||||
#else
|
#else
|
||||||
scandir_dirp
|
scandir_dirp
|
||||||
#endif
|
#endif
|
||||||
(dirp, namelist, select, dcomp));
|
(dirp, namelist, select, dcomp);
|
||||||
|
serrno = errno;
|
||||||
|
closedir(dirp);
|
||||||
|
errno = serrno;
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef I_AM_SCANDIR_B
|
|
||||||
int
|
int
|
||||||
|
#ifdef I_AM_SCANDIR_B
|
||||||
|
fscandir_b(int dirfd, struct dirent ***namelist, select_block select,
|
||||||
|
dcomp_block dcomp)
|
||||||
|
#else
|
||||||
|
fscandir(int dirfd, struct dirent ***namelist,
|
||||||
|
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
|
||||||
|
const struct dirent **))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
DIR *dirp;
|
||||||
|
int ret, serrno;
|
||||||
|
|
||||||
|
dirp = fdopendir(dirfd);
|
||||||
|
if (dirp == NULL)
|
||||||
|
return (-1);
|
||||||
|
ret =
|
||||||
|
#ifdef I_AM_SCANDIR_B
|
||||||
|
scandir_dirp_b
|
||||||
|
#else
|
||||||
|
scandir_dirp
|
||||||
|
#endif
|
||||||
|
(dirp, namelist, select, dcomp);
|
||||||
|
serrno = errno;
|
||||||
|
fdclosedir(dirp);
|
||||||
|
errno = serrno;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
#ifdef I_AM_SCANDIR_B
|
||||||
|
scandirat_b(int dirfd, const char *dirname, struct dirent ***namelist,
|
||||||
|
select_block select, dcomp_block dcomp)
|
||||||
|
#else
|
||||||
scandirat(int dirfd, const char *dirname, struct dirent ***namelist,
|
scandirat(int dirfd, const char *dirname, struct dirent ***namelist,
|
||||||
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
|
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
|
||||||
const struct dirent **))
|
const struct dirent **))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
DIR *dirp;
|
int fd, ret, serrno;
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = _openat(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
fd = _openat(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return (-1);
|
return (-1);
|
||||||
dirp = fdopendir(fd);
|
ret =
|
||||||
if (dirp == NULL) {
|
#ifdef I_AM_SCANDIR_B
|
||||||
_close(fd);
|
fscandir_b
|
||||||
return (-1);
|
#else
|
||||||
}
|
fscandir
|
||||||
return (scandir_dirp(dirp, namelist, select, dcomp));
|
#endif
|
||||||
|
(fd, namelist, select, dcomp);
|
||||||
|
serrno = errno;
|
||||||
|
_close(fd);
|
||||||
|
errno = serrno;
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef I_AM_SCANDIR_B
|
||||||
/*
|
/*
|
||||||
* Alphabetic order comparison routine for those who want it.
|
* Alphabetic order comparison routine for those who want it.
|
||||||
* POSIX 2008 requires that alphasort() uses strcoll().
|
* POSIX 2008 requires that alphasort() uses strcoll().
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ ATF_TESTS_C+= makecontext_test
|
||||||
ATF_TESTS_C+= popen_test
|
ATF_TESTS_C+= popen_test
|
||||||
ATF_TESTS_C+= posix_spawn_test
|
ATF_TESTS_C+= posix_spawn_test
|
||||||
ATF_TESTS_C+= realpath2_test
|
ATF_TESTS_C+= realpath2_test
|
||||||
|
ATF_TESTS_C+= scandir_test
|
||||||
|
.if ${COMPILER_FEATURES:Mblocks}
|
||||||
|
ATF_TESTS_C+= scandir_blocks_test
|
||||||
|
.endif
|
||||||
ATF_TESTS_C+= sig2str_test
|
ATF_TESTS_C+= sig2str_test
|
||||||
ATF_TESTS_C+= sigsetops_test
|
ATF_TESTS_C+= sigsetops_test
|
||||||
ATF_TESTS_C+= wordexp_test
|
ATF_TESTS_C+= wordexp_test
|
||||||
|
|
@ -101,7 +105,7 @@ TESTS_SUBDIRS= execve
|
||||||
TESTS_SUBDIRS+= posix_spawn
|
TESTS_SUBDIRS+= posix_spawn
|
||||||
|
|
||||||
# Tests that require blocks support
|
# Tests that require blocks support
|
||||||
.for t in fts_blocks_test glob_blocks_test
|
.for t in fts_blocks_test glob_blocks_test scandir_blocks_test
|
||||||
CFLAGS.${t}.c+= -fblocks
|
CFLAGS.${t}.c+= -fblocks
|
||||||
LIBADD.${t}+= BlocksRuntime
|
LIBADD.${t}+= BlocksRuntime
|
||||||
.endfor
|
.endfor
|
||||||
|
|
|
||||||
118
lib/libc/tests/gen/scandir_blocks_test.c
Normal file
118
lib/libc/tests/gen/scandir_blocks_test.c
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2025 Klara, Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
scandir_blocks_prepare(const struct atf_tc *tc)
|
||||||
|
{
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755));
|
||||||
|
ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
|
||||||
|
ATF_REQUIRE_EQ(0, symlink("file", "dir/link"));
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scandir_blocks_verify(const struct atf_tc *tc, int n, struct dirent **namelist)
|
||||||
|
{
|
||||||
|
ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n);
|
||||||
|
ATF_CHECK_STREQ("link", namelist[0]->d_name);
|
||||||
|
ATF_CHECK_STREQ("file", namelist[1]->d_name);
|
||||||
|
ATF_CHECK_STREQ("dir", namelist[2]->d_name);
|
||||||
|
ATF_CHECK_STREQ("..", namelist[3]->d_name);
|
||||||
|
ATF_CHECK_STREQ(".", namelist[4]->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(scandir_b_test);
|
||||||
|
ATF_TC_HEAD(scandir_b_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test scandir_b()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(scandir_b_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
scandir_blocks_prepare(tc);
|
||||||
|
ret = scandir_b("dir", &namelist,
|
||||||
|
^(const struct dirent *ent) {
|
||||||
|
return (strcmp(ent->d_name, "skip") != 0);
|
||||||
|
},
|
||||||
|
^(const struct dirent **a, const struct dirent **b) {
|
||||||
|
return (strcmp((*b)->d_name, (*a)->d_name));
|
||||||
|
});
|
||||||
|
scandir_blocks_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(fscandir_b_test);
|
||||||
|
ATF_TC_HEAD(fscandir_b_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test fscandir_b()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(fscandir_b_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int fd, i, ret;
|
||||||
|
|
||||||
|
scandir_blocks_prepare(tc);
|
||||||
|
ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
|
||||||
|
ret = fscandir_b(fd, &namelist,
|
||||||
|
^(const struct dirent *ent) {
|
||||||
|
return (strcmp(ent->d_name, "skip") != 0);
|
||||||
|
},
|
||||||
|
^(const struct dirent **a, const struct dirent **b) {
|
||||||
|
return (strcmp((*b)->d_name, (*a)->d_name));
|
||||||
|
});
|
||||||
|
scandir_blocks_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
ATF_REQUIRE_EQ(0, close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(scandirat_b_test);
|
||||||
|
ATF_TC_HEAD(scandirat_b_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test scandirat_b()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(scandirat_b_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int fd, i, ret;
|
||||||
|
|
||||||
|
scandir_blocks_prepare(tc);
|
||||||
|
ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0);
|
||||||
|
ret = scandirat_b(fd, ".", &namelist,
|
||||||
|
^(const struct dirent *ent) {
|
||||||
|
return (strcmp(ent->d_name, "skip") != 0);
|
||||||
|
},
|
||||||
|
^(const struct dirent **a, const struct dirent **b) {
|
||||||
|
return (strcmp((*b)->d_name, (*a)->d_name));
|
||||||
|
});
|
||||||
|
scandir_blocks_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
ATF_REQUIRE_EQ(0, close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
ATF_TP_ADD_TC(tp, scandir_b_test);
|
||||||
|
ATF_TP_ADD_TC(tp, fscandir_b_test);
|
||||||
|
ATF_TP_ADD_TC(tp, scandirat_b_test);
|
||||||
|
return (atf_no_error());
|
||||||
|
}
|
||||||
112
lib/libc/tests/gen/scandir_test.c
Normal file
112
lib/libc/tests/gen/scandir_test.c
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2025 Klara, Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <atf-c.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
scandir_prepare(const struct atf_tc *tc)
|
||||||
|
{
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755));
|
||||||
|
ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
|
||||||
|
ATF_REQUIRE_EQ(0, symlink("file", "dir/link"));
|
||||||
|
ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scandir_verify(const struct atf_tc *tc, int n, struct dirent **namelist)
|
||||||
|
{
|
||||||
|
ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n);
|
||||||
|
ATF_CHECK_STREQ("link", namelist[0]->d_name);
|
||||||
|
ATF_CHECK_STREQ("file", namelist[1]->d_name);
|
||||||
|
ATF_CHECK_STREQ("dir", namelist[2]->d_name);
|
||||||
|
ATF_CHECK_STREQ("..", namelist[3]->d_name);
|
||||||
|
ATF_CHECK_STREQ(".", namelist[4]->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scandir_select(const struct dirent *ent)
|
||||||
|
{
|
||||||
|
return (strcmp(ent->d_name, "skip") != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scandir_compare(const struct dirent **a, const struct dirent **b)
|
||||||
|
{
|
||||||
|
return (strcmp((*b)->d_name, (*a)->d_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(scandir_test);
|
||||||
|
ATF_TC_HEAD(scandir_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test scandir()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(scandir_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
scandir_prepare(tc);
|
||||||
|
ret = scandir("dir", &namelist, scandir_select, scandir_compare);
|
||||||
|
scandir_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(fscandir_test);
|
||||||
|
ATF_TC_HEAD(fscandir_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test fscandir()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(fscandir_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int fd, i, ret;
|
||||||
|
|
||||||
|
scandir_prepare(tc);
|
||||||
|
ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
|
||||||
|
ret = fscandir(fd, &namelist, scandir_select, scandir_compare);
|
||||||
|
scandir_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
ATF_REQUIRE_EQ(0, close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC(scandirat_test);
|
||||||
|
ATF_TC_HEAD(scandirat_test, tc)
|
||||||
|
{
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Test scandirat()");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(scandirat_test, tc)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
int fd, i, ret;
|
||||||
|
|
||||||
|
scandir_prepare(tc);
|
||||||
|
ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0);
|
||||||
|
ret = scandirat(fd, ".", &namelist, scandir_select, scandir_compare);
|
||||||
|
scandir_verify(tc, ret, namelist);
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
ATF_REQUIRE_EQ(0, close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TP_ADD_TCS(tp)
|
||||||
|
{
|
||||||
|
ATF_TP_ADD_TC(tp, scandir_test);
|
||||||
|
ATF_TP_ADD_TC(tp, fscandir_test);
|
||||||
|
ATF_TP_ADD_TC(tp, scandirat_test);
|
||||||
|
return (atf_no_error());
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue