[libgroff]: Fix Savannah #65980 (open directory).

* src/libs/libgroff/searchpath.cpp (is_directory): New function uses
  stat(2) to check file name argument to see if it's a directory, and
  returns a Boolean.

  (search_path::open_file):
  (search_path::open_file_cautious): Use `is_directory()` before
  attempting to `fopen()` a file specification; fail and set `errno` to
  `EISDIR` if it's a directory so that the caller reports a useful
  diagnostic.

* bootstrap.conf: Add gnulib `stat` module, because the story of
  POSIX and non-POSIX systems alike trying and failing to sensibly
  implement the fundamental Unix file system model is a sorry tale of
  indifference and self-owns by rock star programmers.  (Seriously, read
  the "sys/stat.h" and "stat" sections of the gnulib manual.)

Fixes <https://savannah.gnu.org/bugs/?65980>.  Thanks to Dave Kemper for
the report.
This commit is contained in:
G. Branden Robinson 2024-07-13 13:09:21 -05:00
parent f680c55d38
commit 834afa4e0d
3 changed files with 55 additions and 1 deletions

View File

@ -1,3 +1,24 @@
2024-07-13 G. Branden Robinson <g.branden.robinson@gmail.com>
* src/libs/libgroff/searchpath.cpp (is_directory): New function
uses stat(2) to check file name argument to see if it's a
directory, and returns a Boolean.
(search_path::open_file):
(search_path::open_file_cautious): Use `is_directory()` before
attempting to `fopen()` a file specification; fail and set
`errno` to `EISDIR` if it's a directory so that the caller
reports a useful diagnostic.
* bootstrap.conf: Add gnulib `stat` module, because the story of
POSIX and non-POSIX systems alike trying and failing to sensibly
implement the fundamental Unix file system model is a sorry tale
of indifference and self-owns by rock star programmers.
{Seriously, read the "sys/stat.h" and "stat" sections of the
gnulib manual.}
Fixes <https://savannah.gnu.org/bugs/?65980>. Thanks to Dave
Kemper for the report.
2024-07-13 G. Branden Robinson <g.branden.robinson@gmail.com>
* tmac/an-ext.tmac: Fix incomplete changes to support `YS` with

View File

@ -43,6 +43,7 @@ gnulib_modules="
fprintf-posix
snprintf
vsnprintf
stat
stdbool-c99
stdint
sys_wait

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@ -26,6 +26,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <stdlib.h>
// for stat(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "searchpath.h"
#include "nonposix.h"
@ -35,6 +40,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
# define relocate(path) strsave(path)
#endif
static bool is_directory(const char *name)
{
struct stat statbuf;
// If stat() fails, a later fopen() will fail anyway (he said
// TOCTTOUishly).
if ((stat(name, &statbuf) == 0)
&& ((statbuf.st_mode & S_IFMT) == S_IFDIR))
return true;
return false;
}
search_path::search_path(const char *envvar, const char *standard,
int add_home, int add_current)
{
@ -99,6 +115,10 @@ FILE *search_path::open_file(const char *name, char **pathp)
{
assert(name != 0 /* nullptr */);
if (IS_ABSOLUTE(name) || *dirs == '\0') {
if (is_directory(name)) {
errno = EISDIR;
return 0 /* nullptr */;
}
FILE *fp = fopen(name, "r");
if (fp != 0 /* nullptr */) {
if (pathp != 0 /* nullptr */)
@ -128,6 +148,10 @@ FILE *search_path::open_file(const char *name, char **pathp)
#if 0
fprintf(stderr, "trying '%s'\n", path);
#endif
if (is_directory(name)) {
errno = EISDIR;
return 0 /* nullptr */;
}
FILE *fp = fopen(path, "r");
int err = errno;
if (fp != 0 /* nullptr */) {
@ -160,6 +184,10 @@ FILE *search_path::open_file_cautious(const char *name, char **pathp,
return (reading ? stdin : stdout);
}
if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') {
if (is_directory(name)) {
errno = EISDIR;
return 0 /* nullptr */;
}
FILE *fp = fopen(name, mode);
if (fp != 0 /* nullptr */) {
if (pathp != 0 /* nullptr */)
@ -190,6 +218,10 @@ FILE *search_path::open_file_cautious(const char *name, char **pathp,
#if 0
fprintf(stderr, "trying '%s'\n", path);
#endif
if (is_directory(name)) {
errno = EISDIR;
return 0 /* nullptr */;
}
FILE *fp = fopen(path, mode);
int err = errno;
if (fp != 0 /* nullptr */) {