Home | History | Annotate | Line # | Download | only in gdbsupport
      1      1.1  christos /* Low-level file-handling.
      2  1.1.1.3  christos    Copyright (C) 2012-2024 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    This file is part of GDB.
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9      1.1  christos    (at your option) any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18      1.1  christos 
     19      1.1  christos #include "filestuff.h"
     20      1.1  christos #include <fcntl.h>
     21      1.1  christos #include <unistd.h>
     22      1.1  christos #include <sys/types.h>
     23      1.1  christos #include <sys/stat.h>
     24      1.1  christos #include <algorithm>
     25      1.1  christos 
     26      1.1  christos #ifdef USE_WIN32API
     27      1.1  christos #include <winsock2.h>
     28      1.1  christos #include <windows.h>
     29      1.1  christos #define HAVE_SOCKETS 1
     30      1.1  christos #elif defined HAVE_SYS_SOCKET_H
     31      1.1  christos #include <sys/socket.h>
     32      1.1  christos /* Define HAVE_F_GETFD if we plan to use F_GETFD.  */
     33      1.1  christos #define HAVE_F_GETFD F_GETFD
     34      1.1  christos #define HAVE_SOCKETS 1
     35      1.1  christos #endif
     36      1.1  christos 
     37      1.1  christos #ifdef HAVE_KINFO_GETFILE
     38      1.1  christos #include <sys/user.h>
     39      1.1  christos #include <libutil.h>
     40      1.1  christos #endif
     41      1.1  christos 
     42      1.1  christos #ifdef HAVE_SYS_RESOURCE_H
     43      1.1  christos #include <sys/resource.h>
     44      1.1  christos #endif /* HAVE_SYS_RESOURCE_H */
     45      1.1  christos 
     46      1.1  christos #ifndef O_CLOEXEC
     47      1.1  christos #define O_CLOEXEC 0
     48      1.1  christos #endif
     49      1.1  christos 
     50      1.1  christos #ifndef O_NOINHERIT
     51      1.1  christos #define O_NOINHERIT 0
     52      1.1  christos #endif
     53      1.1  christos 
     54      1.1  christos #ifndef SOCK_CLOEXEC
     55      1.1  christos #define SOCK_CLOEXEC 0
     56      1.1  christos #endif
     57      1.1  christos 
     58      1.1  christos 
     59      1.1  christos 
     61      1.1  christos #ifndef HAVE_FDWALK
     62      1.1  christos 
     63      1.1  christos #include <dirent.h>
     64      1.1  christos 
     65      1.1  christos /* Replacement for fdwalk, if the system doesn't define it.  Walks all
     66      1.1  christos    open file descriptors (though this implementation may walk closed
     67      1.1  christos    ones as well, depending on the host platform's capabilities) and
     68      1.1  christos    call FUNC with ARG.  If FUNC returns non-zero, stops immediately
     69      1.1  christos    and returns the same value.  Otherwise, returns zero when
     70      1.1  christos    finished.  */
     71      1.1  christos 
     72      1.1  christos static int
     73      1.1  christos fdwalk (int (*func) (void *, int), void *arg)
     74      1.1  christos {
     75      1.1  christos   /* Checking __linux__ isn't great but it isn't clear what would be
     76      1.1  christos      better.  There doesn't seem to be a good way to check for this in
     77      1.1  christos      configure.  */
     78      1.1  christos #ifdef __linux__
     79      1.1  christos   DIR *dir;
     80      1.1  christos 
     81      1.1  christos   dir = opendir ("/proc/self/fd");
     82      1.1  christos   if (dir != NULL)
     83      1.1  christos     {
     84      1.1  christos       struct dirent *entry;
     85      1.1  christos       int result = 0;
     86      1.1  christos 
     87      1.1  christos       for (entry = readdir (dir); entry != NULL; entry = readdir (dir))
     88      1.1  christos 	{
     89      1.1  christos 	  long fd;
     90      1.1  christos 	  char *tail;
     91      1.1  christos 
     92      1.1  christos 	  errno = 0;
     93      1.1  christos 	  fd = strtol (entry->d_name, &tail, 10);
     94      1.1  christos 	  if (*tail != '\0' || errno != 0)
     95      1.1  christos 	    continue;
     96      1.1  christos 	  if ((int) fd != fd)
     97      1.1  christos 	    {
     98      1.1  christos 	      /* What can we do here really?  */
     99      1.1  christos 	      continue;
    100      1.1  christos 	    }
    101      1.1  christos 
    102      1.1  christos 	  if (fd == dirfd (dir))
    103      1.1  christos 	    continue;
    104      1.1  christos 
    105      1.1  christos 	  result = func (arg, fd);
    106      1.1  christos 	  if (result != 0)
    107      1.1  christos 	    break;
    108      1.1  christos 	}
    109      1.1  christos 
    110      1.1  christos       closedir (dir);
    111      1.1  christos       return result;
    112      1.1  christos     }
    113      1.1  christos   /* We may fall through to the next case.  */
    114      1.1  christos #endif
    115      1.1  christos #ifdef HAVE_KINFO_GETFILE
    116      1.1  christos   int nfd;
    117      1.1  christos   gdb::unique_xmalloc_ptr<struct kinfo_file[]> fdtbl
    118      1.1  christos     (kinfo_getfile (getpid (), &nfd));
    119      1.1  christos   if (fdtbl != NULL)
    120      1.1  christos     {
    121      1.1  christos       for (int i = 0; i < nfd; i++)
    122      1.1  christos 	{
    123      1.1  christos 	  if (fdtbl[i].kf_fd >= 0)
    124      1.1  christos 	    {
    125      1.1  christos 	      int result = func (arg, fdtbl[i].kf_fd);
    126      1.1  christos 	      if (result != 0)
    127      1.1  christos 		return result;
    128      1.1  christos 	    }
    129      1.1  christos 	}
    130      1.1  christos       return 0;
    131      1.1  christos     }
    132      1.1  christos   /* We may fall through to the next case.  */
    133      1.1  christos #endif
    134      1.1  christos 
    135      1.1  christos   {
    136      1.1  christos     int max, fd;
    137      1.1  christos 
    138      1.1  christos #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
    139      1.1  christos     struct rlimit rlim;
    140      1.1  christos 
    141      1.1  christos     if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY)
    142      1.1  christos       max = rlim.rlim_max;
    143      1.1  christos     else
    144      1.1  christos #endif
    145      1.1  christos       {
    146      1.1  christos #ifdef _SC_OPEN_MAX
    147      1.1  christos 	max = sysconf (_SC_OPEN_MAX);
    148      1.1  christos #else
    149      1.1  christos 	/* Whoops.  */
    150      1.1  christos 	return 0;
    151      1.1  christos #endif /* _SC_OPEN_MAX */
    152      1.1  christos       }
    153      1.1  christos 
    154      1.1  christos     for (fd = 0; fd < max; ++fd)
    155      1.1  christos       {
    156      1.1  christos 	struct stat sb;
    157      1.1  christos 	int result;
    158      1.1  christos 
    159      1.1  christos 	/* Only call FUNC for open fds.  */
    160      1.1  christos 	if (fstat (fd, &sb) == -1)
    161      1.1  christos 	  continue;
    162      1.1  christos 
    163      1.1  christos 	result = func (arg, fd);
    164      1.1  christos 	if (result != 0)
    165      1.1  christos 	  return result;
    166      1.1  christos       }
    167      1.1  christos 
    168      1.1  christos     return 0;
    169      1.1  christos   }
    170      1.1  christos }
    171      1.1  christos 
    172      1.1  christos #endif /* HAVE_FDWALK */
    173      1.1  christos 
    174      1.1  christos 
    175      1.1  christos 
    177      1.1  christos /* A vector holding all the fds open when notice_open_fds was called.  We
    178      1.1  christos    don't use a hashtab because we don't expect there to be many open fds.  */
    179      1.1  christos 
    180      1.1  christos static std::vector<int> open_fds;
    181      1.1  christos 
    182      1.1  christos /* An fdwalk callback function used by notice_open_fds.  It puts the
    183      1.1  christos    given file descriptor into the vec.  */
    184      1.1  christos 
    185      1.1  christos static int
    186      1.1  christos do_mark_open_fd (void *ignore, int fd)
    187      1.1  christos {
    188      1.1  christos   open_fds.push_back (fd);
    189      1.1  christos   return 0;
    190      1.1  christos }
    191      1.1  christos 
    192      1.1  christos /* See filestuff.h.  */
    193      1.1  christos 
    194      1.1  christos void
    195      1.1  christos notice_open_fds (void)
    196      1.1  christos {
    197      1.1  christos   fdwalk (do_mark_open_fd, NULL);
    198      1.1  christos }
    199      1.1  christos 
    200      1.1  christos /* See filestuff.h.  */
    201      1.1  christos 
    202      1.1  christos void
    203      1.1  christos mark_fd_no_cloexec (int fd)
    204      1.1  christos {
    205      1.1  christos   do_mark_open_fd (NULL, fd);
    206      1.1  christos }
    207      1.1  christos 
    208      1.1  christos /* See filestuff.h.  */
    209      1.1  christos 
    210      1.1  christos void
    211      1.1  christos unmark_fd_no_cloexec (int fd)
    212      1.1  christos {
    213      1.1  christos   auto it = std::remove (open_fds.begin (), open_fds.end (), fd);
    214      1.1  christos 
    215      1.1  christos   if (it != open_fds.end ())
    216  1.1.1.2  christos     open_fds.erase (it);
    217      1.1  christos   else
    218      1.1  christos     gdb_assert_not_reached ("fd not found in open_fds");
    219      1.1  christos }
    220      1.1  christos 
    221      1.1  christos /* Helper function for close_most_fds that closes the file descriptor
    222      1.1  christos    if appropriate.  */
    223      1.1  christos 
    224      1.1  christos static int
    225      1.1  christos do_close (void *ignore, int fd)
    226      1.1  christos {
    227      1.1  christos   for (int val : open_fds)
    228      1.1  christos     {
    229      1.1  christos       if (fd == val)
    230      1.1  christos 	{
    231      1.1  christos 	  /* Keep this one open.  */
    232      1.1  christos 	  return 0;
    233      1.1  christos 	}
    234      1.1  christos     }
    235      1.1  christos 
    236      1.1  christos   close (fd);
    237      1.1  christos   return 0;
    238      1.1  christos }
    239      1.1  christos 
    240      1.1  christos /* See filestuff.h.  */
    241      1.1  christos 
    242      1.1  christos void
    243      1.1  christos close_most_fds (void)
    244      1.1  christos {
    245      1.1  christos   fdwalk (do_close, NULL);
    246      1.1  christos }
    247      1.1  christos 
    248      1.1  christos 
    249      1.1  christos 
    251      1.1  christos /* This is a tri-state flag.  When zero it means we haven't yet tried
    252      1.1  christos    O_CLOEXEC.  When positive it means that O_CLOEXEC works on this
    253      1.1  christos    host.  When negative, it means that O_CLOEXEC doesn't work.  We
    254      1.1  christos    track this state because, while gdb might have been compiled
    255      1.1  christos    against a libc that supplies O_CLOEXEC, there is no guarantee that
    256      1.1  christos    the kernel supports it.  */
    257      1.1  christos 
    258      1.1  christos static int trust_o_cloexec;
    259      1.1  christos 
    260      1.1  christos /* Mark FD as close-on-exec, ignoring errors.  Update
    261      1.1  christos    TRUST_O_CLOEXEC.  */
    262      1.1  christos 
    263      1.1  christos static void
    264      1.1  christos mark_cloexec (int fd)
    265      1.1  christos {
    266      1.1  christos #ifdef HAVE_F_GETFD
    267      1.1  christos   int old = fcntl (fd, F_GETFD, 0);
    268      1.1  christos 
    269      1.1  christos   if (old != -1)
    270      1.1  christos     {
    271      1.1  christos       fcntl (fd, F_SETFD, old | FD_CLOEXEC);
    272      1.1  christos 
    273      1.1  christos       if (trust_o_cloexec == 0)
    274      1.1  christos 	{
    275      1.1  christos 	  if ((old & FD_CLOEXEC) != 0)
    276      1.1  christos 	    trust_o_cloexec = 1;
    277      1.1  christos 	  else
    278      1.1  christos 	    trust_o_cloexec = -1;
    279      1.1  christos 	}
    280      1.1  christos     }
    281      1.1  christos #endif /* HAVE_F_GETFD */
    282      1.1  christos }
    283      1.1  christos 
    284      1.1  christos /* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec.  */
    285      1.1  christos 
    286      1.1  christos static void
    287      1.1  christos maybe_mark_cloexec (int fd)
    288      1.1  christos {
    289      1.1  christos   if (trust_o_cloexec <= 0)
    290      1.1  christos     mark_cloexec (fd);
    291      1.1  christos }
    292      1.1  christos 
    293      1.1  christos #ifdef HAVE_SOCKETS
    294      1.1  christos 
    295      1.1  christos /* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC.  */
    296      1.1  christos 
    297      1.1  christos static void
    298      1.1  christos socket_mark_cloexec (int fd)
    299      1.1  christos {
    300      1.1  christos   if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0)
    301      1.1  christos     mark_cloexec (fd);
    302      1.1  christos }
    303      1.1  christos 
    304      1.1  christos #endif
    305      1.1  christos 
    306      1.1  christos 
    307  1.1.1.2  christos 
    309      1.1  christos /* See filestuff.h.  */
    310  1.1.1.2  christos 
    311      1.1  christos scoped_fd
    312  1.1.1.2  christos gdb_open_cloexec (const char *filename, int flags, unsigned long mode)
    313  1.1.1.2  christos {
    314      1.1  christos   scoped_fd fd (open (filename, flags | O_CLOEXEC, mode));
    315      1.1  christos 
    316      1.1  christos   if (fd.get () >= 0)
    317      1.1  christos     maybe_mark_cloexec (fd.get ());
    318      1.1  christos 
    319      1.1  christos   return fd;
    320      1.1  christos }
    321      1.1  christos 
    322      1.1  christos /* See filestuff.h.  */
    323      1.1  christos 
    324      1.1  christos gdb_file_up
    325      1.1  christos gdb_fopen_cloexec (const char *filename, const char *opentype)
    326      1.1  christos {
    327      1.1  christos   FILE *result;
    328      1.1  christos   /* Probe for "e" support once.  But, if we can tell the operating
    329      1.1  christos      system doesn't know about close on exec mode "e" without probing,
    330      1.1  christos      skip it.  E.g., the Windows runtime issues an "Invalid parameter
    331      1.1  christos      passed to C runtime function" OutputDebugString warning for
    332      1.1  christos      unknown modes.  Assume that if O_CLOEXEC is zero, then "e" isn't
    333      1.1  christos      supported.  On MinGW, O_CLOEXEC is an alias of O_NOINHERIT, and
    334      1.1  christos      "e" isn't supported.  */
    335      1.1  christos   static int fopen_e_ever_failed_einval =
    336      1.1  christos     O_CLOEXEC == 0 || O_CLOEXEC == O_NOINHERIT;
    337      1.1  christos 
    338      1.1  christos   if (!fopen_e_ever_failed_einval)
    339      1.1  christos     {
    340      1.1  christos       char *copy;
    341      1.1  christos 
    342      1.1  christos       copy = (char *) alloca (strlen (opentype) + 2);
    343      1.1  christos       strcpy (copy, opentype);
    344      1.1  christos       /* This is a glibc extension but we try it unconditionally on
    345      1.1  christos 	 this path.  */
    346      1.1  christos       strcat (copy, "e");
    347      1.1  christos       result = fopen (filename, copy);
    348      1.1  christos 
    349      1.1  christos       if (result == NULL && errno == EINVAL)
    350      1.1  christos 	{
    351      1.1  christos 	  result = fopen (filename, opentype);
    352      1.1  christos 	  if (result != NULL)
    353      1.1  christos 	    fopen_e_ever_failed_einval = 1;
    354      1.1  christos 	}
    355      1.1  christos     }
    356      1.1  christos   else
    357      1.1  christos     result = fopen (filename, opentype);
    358      1.1  christos 
    359      1.1  christos   if (result != NULL)
    360      1.1  christos     maybe_mark_cloexec (fileno (result));
    361      1.1  christos 
    362      1.1  christos   return gdb_file_up (result);
    363      1.1  christos }
    364      1.1  christos 
    365      1.1  christos #ifdef HAVE_SOCKETS
    366      1.1  christos /* See filestuff.h.  */
    367      1.1  christos 
    368      1.1  christos int
    369      1.1  christos gdb_socketpair_cloexec (int domain, int style, int protocol,
    370      1.1  christos 			int filedes[2])
    371      1.1  christos {
    372      1.1  christos #ifdef HAVE_SOCKETPAIR
    373      1.1  christos   int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes);
    374      1.1  christos 
    375      1.1  christos   if (result != -1)
    376      1.1  christos     {
    377      1.1  christos       socket_mark_cloexec (filedes[0]);
    378      1.1  christos       socket_mark_cloexec (filedes[1]);
    379  1.1.1.2  christos     }
    380      1.1  christos 
    381      1.1  christos   return result;
    382      1.1  christos #else
    383      1.1  christos   gdb_assert_not_reached ("socketpair not available on this host");
    384      1.1  christos #endif
    385      1.1  christos }
    386      1.1  christos 
    387      1.1  christos /* See filestuff.h.  */
    388      1.1  christos 
    389      1.1  christos int
    390      1.1  christos gdb_socket_cloexec (int domain, int style, int protocol)
    391      1.1  christos {
    392      1.1  christos   int result = socket (domain, style | SOCK_CLOEXEC, protocol);
    393      1.1  christos 
    394      1.1  christos   if (result != -1)
    395      1.1  christos     socket_mark_cloexec (result);
    396      1.1  christos 
    397      1.1  christos   return result;
    398      1.1  christos }
    399      1.1  christos #endif
    400      1.1  christos 
    401      1.1  christos /* See filestuff.h.  */
    402      1.1  christos 
    403      1.1  christos int
    404      1.1  christos gdb_pipe_cloexec (int filedes[2])
    405      1.1  christos {
    406      1.1  christos   int result;
    407      1.1  christos 
    408      1.1  christos #ifdef HAVE_PIPE2
    409      1.1  christos   result = pipe2 (filedes, O_CLOEXEC);
    410      1.1  christos   if (result != -1)
    411      1.1  christos     {
    412      1.1  christos       maybe_mark_cloexec (filedes[0]);
    413      1.1  christos       maybe_mark_cloexec (filedes[1]);
    414      1.1  christos     }
    415      1.1  christos #else
    416      1.1  christos #ifdef HAVE_PIPE
    417      1.1  christos   result = pipe (filedes);
    418      1.1  christos   if (result != -1)
    419      1.1  christos     {
    420  1.1.1.2  christos       mark_cloexec (filedes[0]);
    421      1.1  christos       mark_cloexec (filedes[1]);
    422      1.1  christos     }
    423      1.1  christos #else /* HAVE_PIPE */
    424      1.1  christos   gdb_assert_not_reached ("pipe not available on this host");
    425      1.1  christos #endif /* HAVE_PIPE */
    426      1.1  christos #endif /* HAVE_PIPE2 */
    427      1.1  christos 
    428      1.1  christos   return result;
    429      1.1  christos }
    430      1.1  christos 
    431      1.1  christos /* See gdbsupport/filestuff.h.  */
    432      1.1  christos 
    433      1.1  christos bool
    434      1.1  christos is_regular_file (const char *name, int *errno_ptr)
    435      1.1  christos {
    436      1.1  christos   struct stat st;
    437      1.1  christos   const int status = stat (name, &st);
    438      1.1  christos 
    439      1.1  christos   /* Stat should never fail except when the file does not exist.
    440      1.1  christos      If stat fails, analyze the source of error and return true
    441      1.1  christos      unless the file does not exist, to avoid returning false results
    442      1.1  christos      on obscure systems where stat does not work as expected.  */
    443      1.1  christos 
    444      1.1  christos   if (status != 0)
    445      1.1  christos     {
    446      1.1  christos       if (errno != ENOENT)
    447      1.1  christos 	return true;
    448      1.1  christos       *errno_ptr = ENOENT;
    449      1.1  christos       return false;
    450      1.1  christos     }
    451      1.1  christos 
    452      1.1  christos   if (S_ISREG (st.st_mode))
    453      1.1  christos     return true;
    454      1.1  christos 
    455      1.1  christos   if (S_ISDIR (st.st_mode))
    456      1.1  christos     *errno_ptr = EISDIR;
    457      1.1  christos   else
    458      1.1  christos     *errno_ptr = EINVAL;
    459      1.1  christos   return false;
    460      1.1  christos }
    461      1.1  christos 
    462      1.1  christos /* See gdbsupport/filestuff.h.  */
    463      1.1  christos 
    464      1.1  christos bool
    465      1.1  christos mkdir_recursive (const char *dir)
    466      1.1  christos {
    467      1.1  christos   auto holder = make_unique_xstrdup (dir);
    468      1.1  christos   char * const start = holder.get ();
    469      1.1  christos   char *component_start = start;
    470      1.1  christos   char *component_end = start;
    471      1.1  christos 
    472      1.1  christos   while (1)
    473      1.1  christos     {
    474      1.1  christos       /* Find the beginning of the next component.  */
    475      1.1  christos       while (*component_start == '/')
    476      1.1  christos 	component_start++;
    477      1.1  christos 
    478      1.1  christos       /* Are we done?  */
    479      1.1  christos       if (*component_start == '\0')
    480      1.1  christos 	return true;
    481      1.1  christos 
    482      1.1  christos       /* Find the slash or null-terminator after this component.  */
    483      1.1  christos       component_end = component_start;
    484  1.1.1.2  christos       while (*component_end != '/' && *component_end != '\0')
    485      1.1  christos 	component_end++;
    486      1.1  christos 
    487      1.1  christos       /* Temporarily replace the slash with a null terminator, so we can create
    488      1.1  christos 	 the directory up to this component.  */
    489  1.1.1.2  christos       char saved_char = *component_end;
    490  1.1.1.2  christos       *component_end = '\0';
    491  1.1.1.2  christos 
    492  1.1.1.2  christos       /* If we get EEXIST and the existing path is a directory, then we're
    493      1.1  christos 	 happy.  If it exists, but it's a regular file and this is not the last
    494      1.1  christos 	 component, we'll fail at the next component.  If this is the last
    495      1.1  christos 	 component, the caller will fail with ENOTDIR when trying to
    496      1.1  christos 	 open/create a file under that path.  */
    497      1.1  christos       if (mkdir (start, 0700) != 0)
    498      1.1  christos 	if (errno != EEXIST)
    499      1.1  christos 	  return false;
    500      1.1  christos 
    501      1.1  christos       /* Restore the overwritten char.  */
    502  1.1.1.2  christos       *component_end = saved_char;
    503  1.1.1.2  christos       component_start = component_end;
    504  1.1.1.2  christos     }
    505  1.1.1.3  christos }
    506  1.1.1.3  christos 
    507  1.1.1.2  christos /* See gdbsupport/filestuff.h.  */
    508  1.1.1.2  christos 
    509  1.1.1.2  christos std::string
    510  1.1.1.2  christos read_remainder_of_file (FILE *file)
    511  1.1.1.2  christos {
    512  1.1.1.2  christos   std::string res;
    513  1.1.1.2  christos   for (;;)
    514  1.1.1.3  christos     {
    515  1.1.1.2  christos       std::string::size_type start_size = res.size ();
    516  1.1.1.2  christos       constexpr int chunk_size = 1024;
    517  1.1.1.3  christos 
    518  1.1.1.2  christos       /* Resize to accommodate CHUNK_SIZE bytes.  */
    519  1.1.1.2  christos       res.resize (start_size + chunk_size);
    520  1.1.1.2  christos 
    521  1.1.1.2  christos       int n = fread (&res[start_size], 1, chunk_size, file);
    522  1.1.1.2  christos       if (n == chunk_size)
    523  1.1.1.2  christos 	continue;
    524  1.1.1.3  christos 
    525  1.1.1.3  christos       gdb_assert (n < chunk_size);
    526  1.1.1.2  christos 
    527  1.1.1.2  christos       /* Less than CHUNK means EOF or error.  If it's an error, return
    528  1.1.1.2  christos 	 no value.  */
    529  1.1.1.2  christos       if (ferror (file))
    530  1.1.1.2  christos 	return {};
    531  1.1.1.2  christos 
    532  1.1.1.2  christos       /* Resize the string according to the data we read.  */
    533  1.1.1.2  christos       res.resize (start_size + n);
    534  1.1.1.2  christos       break;
    535  1.1.1.3  christos     }
    536  1.1.1.3  christos 
    537  1.1.1.3  christos   return res;
    538  1.1.1.3  christos }
    539  1.1.1.3  christos 
    540  1.1.1.3  christos /* See gdbsupport/filestuff.h.  */
    541  1.1.1.3  christos 
    542  1.1.1.3  christos std::optional<std::string>
    543  1.1.1.3  christos read_text_file_to_string (const char *path)
    544  1.1.1.3  christos {
    545  1.1.1.3  christos   gdb_file_up file = gdb_fopen_cloexec (path, "r");
    546  1.1.1.3  christos   if (file == nullptr)
    547                        return {};
    548                    
    549                      return read_remainder_of_file (file.get ());
    550                    }
    551