summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2024-04-15 15:47:59 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2024-04-15 15:47:59 +0000
commit1d90ac41252b2d73e048a1fc0b11b5ac2aa78cf3 (patch)
tree353ea9246e72e8a2c0980fe237523f5237afe978 /lib/libc
parent3b9c76ef0bfa2d6ed3e2da376697e789a14e3c71 (diff)
Add scandirat(3); from freebsd
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.
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/Symbols.list1
-rw-r--r--lib/libc/gen/opendir.c5
-rw-r--r--lib/libc/gen/scandir.337
-rw-r--r--lib/libc/gen/scandir.c43
-rw-r--r--lib/libc/hidden/dirent.h7
5 files changed, 81 insertions, 12 deletions
diff --git a/lib/libc/Symbols.list b/lib/libc/Symbols.list
index 251760f812e..b1e7e916bbc 100644
--- a/lib/libc/Symbols.list
+++ b/lib/libc/Symbols.list
@@ -750,6 +750,7 @@ readdir_r
readpassphrase
rewinddir
scandir
+scandirat
seekdir
setclasscontext
setdomainname
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index 71d30da9386..ef198924efb 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -1,4 +1,4 @@
-/* $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.
@@ -39,7 +39,6 @@
#include "telldir.h"
-static DIR *__fdopendir(int fd);
/*
* Open a directory specified by name.
@@ -89,7 +88,7 @@ fdopendir(int fd)
}
DEF_WEAK(fdopendir);
-static DIR *
+DIR *
__fdopendir(int fd)
{
DIR *dirp;
diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3
index 50033134303..fda3a82f702 100644
--- a/lib/libc/gen/scandir.3
+++ b/lib/libc/gen/scandir.3
@@ -1,4 +1,4 @@
-.\" $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.
@@ -27,11 +27,12 @@
.\" 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
@@ -45,6 +46,14 @@
.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
@@ -91,6 +100,30 @@ parameter to sort the array alphabetically.
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
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index f767ca503fa..5d62fb7a089 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -1,4 +1,4 @@
-/* $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.
@@ -39,9 +39,11 @@
#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))
@@ -57,8 +59,8 @@
((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 **))
{
@@ -66,10 +68,7 @@ scandir(const char *dirname, struct dirent ***namelist,
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;
@@ -140,6 +139,38 @@ 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.
*/
diff --git a/lib/libc/hidden/dirent.h b/lib/libc/hidden/dirent.h
index 1e8398291c8..e683252e016 100644
--- a/lib/libc/hidden/dirent.h
+++ b/lib/libc/hidden/dirent.h
@@ -1,4 +1,4 @@
-/* $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>
*
@@ -20,6 +20,10 @@
#include_next <dirent.h>
+__BEGIN_HIDDEN_DECLS
+DIR *__fdopendir(int fd);
+__END_HIDDEN_DECLS
+
PROTO_DEPRECATED(alphasort);
PROTO_NORMAL(closedir);
PROTO_NORMAL(dirfd);
@@ -30,6 +34,7 @@ PROTO_NORMAL(readdir);
PROTO_DEPRECATED(readdir_r);
PROTO_DEPRECATED(rewinddir);
PROTO_DEPRECATED(scandir);
+PROTO_DEPRECATED(scandirat);
PROTO_NORMAL(seekdir);
PROTO_NORMAL(telldir);