Add scandirat(3); from freebsd
authorflorian <florian@openbsd.org>
Mon, 15 Apr 2024 15:47:58 +0000 (15:47 +0000)
committerflorian <florian@openbsd.org>
Mon, 15 Apr 2024 15:47:58 +0000 (15:47 +0000)
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.

include/dirent.h
lib/libc/Symbols.list
lib/libc/gen/opendir.c
lib/libc/gen/scandir.3
lib/libc/gen/scandir.c
lib/libc/hidden/dirent.h

index 61a5e01..207db24 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $   */
 
 /*-
@@ -90,6 +90,9 @@ int readdir_r(DIR *__restrict, struct dirent *__restrict,
 #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 *),
index 251760f..b1e7e91 100644 (file)
@@ -750,6 +750,7 @@ readdir_r
 readpassphrase
 rewinddir
 scandir
+scandirat
 seekdir
 setclasscontext
 setdomainname
index 71d30da..ef19892 100644 (file)
@@ -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;
index 5003313..fda3a82 100644 (file)
@@ -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.
 .\" 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
@@ -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
index f767ca5..5d62fb7 100644 (file)
@@ -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.
 #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.
  */
index 1e83982..e683252 100644 (file)
@@ -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>
  *
 
 #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);