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