To be used in httpd(8) shortly to prevent toctu issues.
This makes __fdopendir internally accessible to avoid unnecessary
syscalls in scandirat(3). Suggested & diff by guenther
suggested by & OK millert
tweak & OK guenther
OK tb, jca
This rides the libc crank.
-/* $OpenBSD: dirent.h,v 1.34 2016/09/09 18:12:37 millert Exp $ */
+/* $OpenBSD: dirent.h,v 1.35 2024/04/15 15:47:58 florian Exp $ */
/* $NetBSD: dirent.h,v 1.9 1995/03/26 20:13:37 jtc Exp $ */
/*-
#if __POSIX_VISIBLE >= 200809
int scandir(const char *, struct dirent ***, int (*)(const struct dirent *),
int (*)(const struct dirent **, const struct dirent **));
+int scandirat(int, const char *, struct dirent ***,
+ int (*)(const struct dirent *),
+ int (*)(const struct dirent **, const struct dirent **));
int alphasort(const struct dirent **, const struct dirent **);
#elif __BSD_VISIBLE
int scandir(const char *, struct dirent ***, int (*)(struct dirent *),
readpassphrase
rewinddir
scandir
+scandirat
seekdir
setclasscontext
setdomainname
-/* $OpenBSD: opendir.c,v 1.30 2016/09/21 04:38:56 guenther Exp $ */
+/* $OpenBSD: opendir.c,v 1.31 2024/04/15 15:47:58 florian Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
#include "telldir.h"
-static DIR *__fdopendir(int fd);
/*
* Open a directory specified by name.
}
DEF_WEAK(fdopendir);
-static DIR *
+DIR *
__fdopendir(int fd)
{
DIR *dirp;
-.\" $OpenBSD: scandir.3,v 1.16 2021/06/17 18:18:15 jmc Exp $
+.\" $OpenBSD: scandir.3,v 1.17 2024/04/15 15:47:58 florian Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd $Mdocdate: June 17 2021 $
+.Dd $Mdocdate: April 15 2024 $
.Dt SCANDIR 3
.Os
.Sh NAME
.Nm scandir ,
+.Nm scandirat ,
.Nm alphasort
.Nd scan a directory
.Sh SYNOPSIS
.Fa "int (*compar)(const struct dirent **, const struct dirent **)"
.Fc
.Ft int
+.Fo scandirat
+.Fa "int dirfd"
+.Fa "const char *dirname"
+.Fa "struct dirent ***namelist"
+.Fa "int (*select)(const struct dirent *)"
+.Fa "int (*compar)(const struct dirent **, const struct dirent **)"
+.Fc
+.Ft int
.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
.Sh DESCRIPTION
The
The memory allocated for the array can be deallocated with
.Xr free 3 ,
by freeing each pointer in the array and then the array itself.
+.Pp
+The
+.Fn scandirat
+function is similar to
+.Fn scandir ,
+but takes an additional
+.Fa dirfd
+argument.
+If
+.Fa dirname
+is relative,
+.Fa dirfd
+must be a valid file descriptor referencing a directory, in which case the
+.Fa dirname
+lookup is performed relative to the directory referenced by
+.Fa dirfd .
+If
+.Fa dirfd
+has the special value
+.Va AT_FDCWD ,
+then the current process directory is used as the base for relative lookups.
+See
+.Xr openat 2
+for additional details.
.Sh DIAGNOSTICS
Returns \-1 if the directory cannot be opened for reading or if
.Xr malloc 3
-/* $OpenBSD: scandir.c,v 1.22 2024/04/14 11:21:08 florian Exp $ */
+/* $OpenBSD: scandir.c,v 1.23 2024/04/15 15:47:58 florian Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "telldir.h"
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
((sizeof(struct dirent) - sizeof(dp)->d_name) + \
(((dp)->d_namlen + 1 + 3) &~ 3))
-int
-scandir(const char *dirname, struct dirent ***namelist,
+static int
+scandir_dirp(DIR *dirp, struct dirent ***namelist,
int (*select)(const struct dirent *),
int (*dcomp)(const struct dirent **, const struct dirent **))
{
size_t nitems = 0;
struct stat stb;
long arraysz;
- DIR *dirp;
- if ((dirp = opendir(dirname)) == NULL)
- return (-1);
if (fstat(dirp->dd_fd, &stb) == -1)
goto fail;
return (-1);
}
+int
+scandir(const char *dirname, struct dirent ***namelist,
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
+{
+ DIR *dirp;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ return (-1);
+
+ return (scandir_dirp(dirp, namelist, select, dcomp));
+}
+
+int
+scandirat(int dirfd, const char *dirname, struct dirent ***namelist,
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
+{
+ DIR *dirp;
+ int fd;
+
+ fd = HIDDEN(openat)(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+ if (fd == -1)
+ return (-1);
+ dirp = __fdopendir(fd);
+ if (dirp == NULL) {
+ HIDDEN(close)(fd);
+ return (-1);
+ }
+ return (scandir_dirp(dirp, namelist, select, dcomp));
+}
+
/*
* Alphabetic order comparison routine for those who want it.
*/
-/* $OpenBSD: dirent.h,v 1.1 2015/09/12 13:34:22 guenther Exp $ */
+/* $OpenBSD: dirent.h,v 1.2 2024/04/15 15:47:58 florian Exp $ */
/*
* Copyright (c) 2015 Philip Guenther <guenther@openbsd.org>
*
#include_next <dirent.h>
+__BEGIN_HIDDEN_DECLS
+DIR *__fdopendir(int fd);
+__END_HIDDEN_DECLS
+
PROTO_DEPRECATED(alphasort);
PROTO_NORMAL(closedir);
PROTO_NORMAL(dirfd);
PROTO_DEPRECATED(readdir_r);
PROTO_DEPRECATED(rewinddir);
PROTO_DEPRECATED(scandir);
+PROTO_DEPRECATED(scandirat);
PROTO_NORMAL(seekdir);
PROTO_NORMAL(telldir);