18dffb485Schristos /* Low-level file-handling. 2*5ba1f45fSchristos Copyright (C) 2012-2024 Free Software Foundation, Inc. 38dffb485Schristos 48dffb485Schristos This file is part of GDB. 58dffb485Schristos 68dffb485Schristos This program is free software; you can redistribute it and/or modify 78dffb485Schristos it under the terms of the GNU General Public License as published by 88dffb485Schristos the Free Software Foundation; either version 3 of the License, or 98dffb485Schristos (at your option) any later version. 108dffb485Schristos 118dffb485Schristos This program is distributed in the hope that it will be useful, 128dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 138dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148dffb485Schristos GNU General Public License for more details. 158dffb485Schristos 168dffb485Schristos You should have received a copy of the GNU General Public License 178dffb485Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 188dffb485Schristos 198dffb485Schristos #include "filestuff.h" 208dffb485Schristos #include "gdb_vecs.h" 218dffb485Schristos #include <fcntl.h> 228dffb485Schristos #include <unistd.h> 238dffb485Schristos #include <sys/types.h> 248dffb485Schristos #include <sys/stat.h> 258dffb485Schristos #include <algorithm> 268dffb485Schristos 278dffb485Schristos #ifdef USE_WIN32API 288dffb485Schristos #include <winsock2.h> 298dffb485Schristos #include <windows.h> 308dffb485Schristos #define HAVE_SOCKETS 1 318dffb485Schristos #elif defined HAVE_SYS_SOCKET_H 328dffb485Schristos #include <sys/socket.h> 338dffb485Schristos /* Define HAVE_F_GETFD if we plan to use F_GETFD. */ 348dffb485Schristos #define HAVE_F_GETFD F_GETFD 358dffb485Schristos #define HAVE_SOCKETS 1 368dffb485Schristos #endif 378dffb485Schristos 388dffb485Schristos #ifdef HAVE_KINFO_GETFILE 398dffb485Schristos #include <sys/user.h> 408dffb485Schristos #include <libutil.h> 418dffb485Schristos #endif 428dffb485Schristos 438dffb485Schristos #ifdef HAVE_SYS_RESOURCE_H 448dffb485Schristos #include <sys/resource.h> 458dffb485Schristos #endif /* HAVE_SYS_RESOURCE_H */ 468dffb485Schristos 478dffb485Schristos #ifndef O_CLOEXEC 488dffb485Schristos #define O_CLOEXEC 0 498dffb485Schristos #endif 508dffb485Schristos 518dffb485Schristos #ifndef O_NOINHERIT 528dffb485Schristos #define O_NOINHERIT 0 538dffb485Schristos #endif 548dffb485Schristos 558dffb485Schristos #ifndef SOCK_CLOEXEC 568dffb485Schristos #define SOCK_CLOEXEC 0 578dffb485Schristos #endif 588dffb485Schristos 598dffb485Schristos 608dffb485Schristos 618dffb485Schristos #ifndef HAVE_FDWALK 628dffb485Schristos 638dffb485Schristos #include <dirent.h> 648dffb485Schristos 658dffb485Schristos /* Replacement for fdwalk, if the system doesn't define it. Walks all 668dffb485Schristos open file descriptors (though this implementation may walk closed 678dffb485Schristos ones as well, depending on the host platform's capabilities) and 688dffb485Schristos call FUNC with ARG. If FUNC returns non-zero, stops immediately 698dffb485Schristos and returns the same value. Otherwise, returns zero when 708dffb485Schristos finished. */ 718dffb485Schristos 728dffb485Schristos static int 738dffb485Schristos fdwalk (int (*func) (void *, int), void *arg) 748dffb485Schristos { 758dffb485Schristos /* Checking __linux__ isn't great but it isn't clear what would be 768dffb485Schristos better. There doesn't seem to be a good way to check for this in 778dffb485Schristos configure. */ 788dffb485Schristos #ifdef __linux__ 798dffb485Schristos DIR *dir; 808dffb485Schristos 818dffb485Schristos dir = opendir ("/proc/self/fd"); 828dffb485Schristos if (dir != NULL) 838dffb485Schristos { 848dffb485Schristos struct dirent *entry; 858dffb485Schristos int result = 0; 868dffb485Schristos 878dffb485Schristos for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) 888dffb485Schristos { 898dffb485Schristos long fd; 908dffb485Schristos char *tail; 918dffb485Schristos 928dffb485Schristos errno = 0; 938dffb485Schristos fd = strtol (entry->d_name, &tail, 10); 948dffb485Schristos if (*tail != '\0' || errno != 0) 958dffb485Schristos continue; 968dffb485Schristos if ((int) fd != fd) 978dffb485Schristos { 988dffb485Schristos /* What can we do here really? */ 998dffb485Schristos continue; 1008dffb485Schristos } 1018dffb485Schristos 1028dffb485Schristos if (fd == dirfd (dir)) 1038dffb485Schristos continue; 1048dffb485Schristos 1058dffb485Schristos result = func (arg, fd); 1068dffb485Schristos if (result != 0) 1078dffb485Schristos break; 1088dffb485Schristos } 1098dffb485Schristos 1108dffb485Schristos closedir (dir); 1118dffb485Schristos return result; 1128dffb485Schristos } 1138dffb485Schristos /* We may fall through to the next case. */ 1148dffb485Schristos #endif 1158dffb485Schristos #ifdef HAVE_KINFO_GETFILE 1168dffb485Schristos int nfd; 1178dffb485Schristos gdb::unique_xmalloc_ptr<struct kinfo_file[]> fdtbl 1188dffb485Schristos (kinfo_getfile (getpid (), &nfd)); 1198dffb485Schristos if (fdtbl != NULL) 1208dffb485Schristos { 1218dffb485Schristos for (int i = 0; i < nfd; i++) 1228dffb485Schristos { 1238dffb485Schristos if (fdtbl[i].kf_fd >= 0) 1248dffb485Schristos { 1258dffb485Schristos int result = func (arg, fdtbl[i].kf_fd); 1268dffb485Schristos if (result != 0) 1278dffb485Schristos return result; 1288dffb485Schristos } 1298dffb485Schristos } 1308dffb485Schristos return 0; 1318dffb485Schristos } 1328dffb485Schristos /* We may fall through to the next case. */ 1338dffb485Schristos #endif 1348dffb485Schristos 1358dffb485Schristos { 1368dffb485Schristos int max, fd; 1378dffb485Schristos 1388dffb485Schristos #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) 1398dffb485Schristos struct rlimit rlim; 1408dffb485Schristos 1418dffb485Schristos if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) 1428dffb485Schristos max = rlim.rlim_max; 1438dffb485Schristos else 1448dffb485Schristos #endif 1458dffb485Schristos { 1468dffb485Schristos #ifdef _SC_OPEN_MAX 1478dffb485Schristos max = sysconf (_SC_OPEN_MAX); 1488dffb485Schristos #else 1498dffb485Schristos /* Whoops. */ 1508dffb485Schristos return 0; 1518dffb485Schristos #endif /* _SC_OPEN_MAX */ 1528dffb485Schristos } 1538dffb485Schristos 1548dffb485Schristos for (fd = 0; fd < max; ++fd) 1558dffb485Schristos { 1568dffb485Schristos struct stat sb; 1578dffb485Schristos int result; 1588dffb485Schristos 1598dffb485Schristos /* Only call FUNC for open fds. */ 1608dffb485Schristos if (fstat (fd, &sb) == -1) 1618dffb485Schristos continue; 1628dffb485Schristos 1638dffb485Schristos result = func (arg, fd); 1648dffb485Schristos if (result != 0) 1658dffb485Schristos return result; 1668dffb485Schristos } 1678dffb485Schristos 1688dffb485Schristos return 0; 1698dffb485Schristos } 1708dffb485Schristos } 1718dffb485Schristos 1728dffb485Schristos #endif /* HAVE_FDWALK */ 1738dffb485Schristos 1748dffb485Schristos 1758dffb485Schristos 1768dffb485Schristos /* A vector holding all the fds open when notice_open_fds was called. We 1778dffb485Schristos don't use a hashtab because we don't expect there to be many open fds. */ 1788dffb485Schristos 1798dffb485Schristos static std::vector<int> open_fds; 1808dffb485Schristos 1818dffb485Schristos /* An fdwalk callback function used by notice_open_fds. It puts the 1828dffb485Schristos given file descriptor into the vec. */ 1838dffb485Schristos 1848dffb485Schristos static int 1858dffb485Schristos do_mark_open_fd (void *ignore, int fd) 1868dffb485Schristos { 1878dffb485Schristos open_fds.push_back (fd); 1888dffb485Schristos return 0; 1898dffb485Schristos } 1908dffb485Schristos 1918dffb485Schristos /* See filestuff.h. */ 1928dffb485Schristos 1938dffb485Schristos void 1948dffb485Schristos notice_open_fds (void) 1958dffb485Schristos { 1968dffb485Schristos fdwalk (do_mark_open_fd, NULL); 1978dffb485Schristos } 1988dffb485Schristos 1998dffb485Schristos /* See filestuff.h. */ 2008dffb485Schristos 2018dffb485Schristos void 2028dffb485Schristos mark_fd_no_cloexec (int fd) 2038dffb485Schristos { 2048dffb485Schristos do_mark_open_fd (NULL, fd); 2058dffb485Schristos } 2068dffb485Schristos 2078dffb485Schristos /* See filestuff.h. */ 2088dffb485Schristos 2098dffb485Schristos void 2108dffb485Schristos unmark_fd_no_cloexec (int fd) 2118dffb485Schristos { 2128dffb485Schristos auto it = std::remove (open_fds.begin (), open_fds.end (), fd); 2138dffb485Schristos 2148dffb485Schristos if (it != open_fds.end ()) 2158dffb485Schristos open_fds.erase (it); 2168dffb485Schristos else 2174b169a6bSchristos gdb_assert_not_reached ("fd not found in open_fds"); 2188dffb485Schristos } 2198dffb485Schristos 2208dffb485Schristos /* Helper function for close_most_fds that closes the file descriptor 2218dffb485Schristos if appropriate. */ 2228dffb485Schristos 2238dffb485Schristos static int 2248dffb485Schristos do_close (void *ignore, int fd) 2258dffb485Schristos { 2268dffb485Schristos for (int val : open_fds) 2278dffb485Schristos { 2288dffb485Schristos if (fd == val) 2298dffb485Schristos { 2308dffb485Schristos /* Keep this one open. */ 2318dffb485Schristos return 0; 2328dffb485Schristos } 2338dffb485Schristos } 2348dffb485Schristos 2358dffb485Schristos close (fd); 2368dffb485Schristos return 0; 2378dffb485Schristos } 2388dffb485Schristos 2398dffb485Schristos /* See filestuff.h. */ 2408dffb485Schristos 2418dffb485Schristos void 2428dffb485Schristos close_most_fds (void) 2438dffb485Schristos { 2448dffb485Schristos fdwalk (do_close, NULL); 2458dffb485Schristos } 2468dffb485Schristos 2478dffb485Schristos 2488dffb485Schristos 2498dffb485Schristos /* This is a tri-state flag. When zero it means we haven't yet tried 2508dffb485Schristos O_CLOEXEC. When positive it means that O_CLOEXEC works on this 2518dffb485Schristos host. When negative, it means that O_CLOEXEC doesn't work. We 2528dffb485Schristos track this state because, while gdb might have been compiled 2538dffb485Schristos against a libc that supplies O_CLOEXEC, there is no guarantee that 2548dffb485Schristos the kernel supports it. */ 2558dffb485Schristos 2568dffb485Schristos static int trust_o_cloexec; 2578dffb485Schristos 2588dffb485Schristos /* Mark FD as close-on-exec, ignoring errors. Update 2598dffb485Schristos TRUST_O_CLOEXEC. */ 2608dffb485Schristos 2618dffb485Schristos static void 2628dffb485Schristos mark_cloexec (int fd) 2638dffb485Schristos { 2648dffb485Schristos #ifdef HAVE_F_GETFD 2658dffb485Schristos int old = fcntl (fd, F_GETFD, 0); 2668dffb485Schristos 2678dffb485Schristos if (old != -1) 2688dffb485Schristos { 2698dffb485Schristos fcntl (fd, F_SETFD, old | FD_CLOEXEC); 2708dffb485Schristos 2718dffb485Schristos if (trust_o_cloexec == 0) 2728dffb485Schristos { 2738dffb485Schristos if ((old & FD_CLOEXEC) != 0) 2748dffb485Schristos trust_o_cloexec = 1; 2758dffb485Schristos else 2768dffb485Schristos trust_o_cloexec = -1; 2778dffb485Schristos } 2788dffb485Schristos } 2798dffb485Schristos #endif /* HAVE_F_GETFD */ 2808dffb485Schristos } 2818dffb485Schristos 2828dffb485Schristos /* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ 2838dffb485Schristos 2848dffb485Schristos static void 2858dffb485Schristos maybe_mark_cloexec (int fd) 2868dffb485Schristos { 2878dffb485Schristos if (trust_o_cloexec <= 0) 2888dffb485Schristos mark_cloexec (fd); 2898dffb485Schristos } 2908dffb485Schristos 2918dffb485Schristos #ifdef HAVE_SOCKETS 2928dffb485Schristos 2938dffb485Schristos /* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ 2948dffb485Schristos 2958dffb485Schristos static void 2968dffb485Schristos socket_mark_cloexec (int fd) 2978dffb485Schristos { 2988dffb485Schristos if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) 2998dffb485Schristos mark_cloexec (fd); 3008dffb485Schristos } 3018dffb485Schristos 3028dffb485Schristos #endif 3038dffb485Schristos 3048dffb485Schristos 3058dffb485Schristos 3068dffb485Schristos /* See filestuff.h. */ 3078dffb485Schristos 3084b169a6bSchristos scoped_fd 3098dffb485Schristos gdb_open_cloexec (const char *filename, int flags, unsigned long mode) 3108dffb485Schristos { 3114b169a6bSchristos scoped_fd fd (open (filename, flags | O_CLOEXEC, mode)); 3128dffb485Schristos 3134b169a6bSchristos if (fd.get () >= 0) 3144b169a6bSchristos maybe_mark_cloexec (fd.get ()); 3158dffb485Schristos 3168dffb485Schristos return fd; 3178dffb485Schristos } 3188dffb485Schristos 3198dffb485Schristos /* See filestuff.h. */ 3208dffb485Schristos 3218dffb485Schristos gdb_file_up 3228dffb485Schristos gdb_fopen_cloexec (const char *filename, const char *opentype) 3238dffb485Schristos { 3248dffb485Schristos FILE *result; 3258dffb485Schristos /* Probe for "e" support once. But, if we can tell the operating 3268dffb485Schristos system doesn't know about close on exec mode "e" without probing, 3278dffb485Schristos skip it. E.g., the Windows runtime issues an "Invalid parameter 3288dffb485Schristos passed to C runtime function" OutputDebugString warning for 3298dffb485Schristos unknown modes. Assume that if O_CLOEXEC is zero, then "e" isn't 3308dffb485Schristos supported. On MinGW, O_CLOEXEC is an alias of O_NOINHERIT, and 3318dffb485Schristos "e" isn't supported. */ 3328dffb485Schristos static int fopen_e_ever_failed_einval = 3338dffb485Schristos O_CLOEXEC == 0 || O_CLOEXEC == O_NOINHERIT; 3348dffb485Schristos 3358dffb485Schristos if (!fopen_e_ever_failed_einval) 3368dffb485Schristos { 3378dffb485Schristos char *copy; 3388dffb485Schristos 3398dffb485Schristos copy = (char *) alloca (strlen (opentype) + 2); 3408dffb485Schristos strcpy (copy, opentype); 3418dffb485Schristos /* This is a glibc extension but we try it unconditionally on 3428dffb485Schristos this path. */ 3438dffb485Schristos strcat (copy, "e"); 3448dffb485Schristos result = fopen (filename, copy); 3458dffb485Schristos 3468dffb485Schristos if (result == NULL && errno == EINVAL) 3478dffb485Schristos { 3488dffb485Schristos result = fopen (filename, opentype); 3498dffb485Schristos if (result != NULL) 3508dffb485Schristos fopen_e_ever_failed_einval = 1; 3518dffb485Schristos } 3528dffb485Schristos } 3538dffb485Schristos else 3548dffb485Schristos result = fopen (filename, opentype); 3558dffb485Schristos 3568dffb485Schristos if (result != NULL) 3578dffb485Schristos maybe_mark_cloexec (fileno (result)); 3588dffb485Schristos 3598dffb485Schristos return gdb_file_up (result); 3608dffb485Schristos } 3618dffb485Schristos 3628dffb485Schristos #ifdef HAVE_SOCKETS 3638dffb485Schristos /* See filestuff.h. */ 3648dffb485Schristos 3658dffb485Schristos int 3668dffb485Schristos gdb_socketpair_cloexec (int domain, int style, int protocol, 3678dffb485Schristos int filedes[2]) 3688dffb485Schristos { 3698dffb485Schristos #ifdef HAVE_SOCKETPAIR 3708dffb485Schristos int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes); 3718dffb485Schristos 3728dffb485Schristos if (result != -1) 3738dffb485Schristos { 3748dffb485Schristos socket_mark_cloexec (filedes[0]); 3758dffb485Schristos socket_mark_cloexec (filedes[1]); 3768dffb485Schristos } 3778dffb485Schristos 3788dffb485Schristos return result; 3798dffb485Schristos #else 3804b169a6bSchristos gdb_assert_not_reached ("socketpair not available on this host"); 3818dffb485Schristos #endif 3828dffb485Schristos } 3838dffb485Schristos 3848dffb485Schristos /* See filestuff.h. */ 3858dffb485Schristos 3868dffb485Schristos int 3878dffb485Schristos gdb_socket_cloexec (int domain, int style, int protocol) 3888dffb485Schristos { 3898dffb485Schristos int result = socket (domain, style | SOCK_CLOEXEC, protocol); 3908dffb485Schristos 3918dffb485Schristos if (result != -1) 3928dffb485Schristos socket_mark_cloexec (result); 3938dffb485Schristos 3948dffb485Schristos return result; 3958dffb485Schristos } 3968dffb485Schristos #endif 3978dffb485Schristos 3988dffb485Schristos /* See filestuff.h. */ 3998dffb485Schristos 4008dffb485Schristos int 4018dffb485Schristos gdb_pipe_cloexec (int filedes[2]) 4028dffb485Schristos { 4038dffb485Schristos int result; 4048dffb485Schristos 4058dffb485Schristos #ifdef HAVE_PIPE2 4068dffb485Schristos result = pipe2 (filedes, O_CLOEXEC); 4078dffb485Schristos if (result != -1) 4088dffb485Schristos { 4098dffb485Schristos maybe_mark_cloexec (filedes[0]); 4108dffb485Schristos maybe_mark_cloexec (filedes[1]); 4118dffb485Schristos } 4128dffb485Schristos #else 4138dffb485Schristos #ifdef HAVE_PIPE 4148dffb485Schristos result = pipe (filedes); 4158dffb485Schristos if (result != -1) 4168dffb485Schristos { 4178dffb485Schristos mark_cloexec (filedes[0]); 4188dffb485Schristos mark_cloexec (filedes[1]); 4198dffb485Schristos } 4208dffb485Schristos #else /* HAVE_PIPE */ 4214b169a6bSchristos gdb_assert_not_reached ("pipe not available on this host"); 4228dffb485Schristos #endif /* HAVE_PIPE */ 4238dffb485Schristos #endif /* HAVE_PIPE2 */ 4248dffb485Schristos 4258dffb485Schristos return result; 4268dffb485Schristos } 4278dffb485Schristos 4288dffb485Schristos /* See gdbsupport/filestuff.h. */ 4298dffb485Schristos 4308dffb485Schristos bool 4318dffb485Schristos is_regular_file (const char *name, int *errno_ptr) 4328dffb485Schristos { 4338dffb485Schristos struct stat st; 4348dffb485Schristos const int status = stat (name, &st); 4358dffb485Schristos 4368dffb485Schristos /* Stat should never fail except when the file does not exist. 4378dffb485Schristos If stat fails, analyze the source of error and return true 4388dffb485Schristos unless the file does not exist, to avoid returning false results 4398dffb485Schristos on obscure systems where stat does not work as expected. */ 4408dffb485Schristos 4418dffb485Schristos if (status != 0) 4428dffb485Schristos { 4438dffb485Schristos if (errno != ENOENT) 4448dffb485Schristos return true; 4458dffb485Schristos *errno_ptr = ENOENT; 4468dffb485Schristos return false; 4478dffb485Schristos } 4488dffb485Schristos 4498dffb485Schristos if (S_ISREG (st.st_mode)) 4508dffb485Schristos return true; 4518dffb485Schristos 4528dffb485Schristos if (S_ISDIR (st.st_mode)) 4538dffb485Schristos *errno_ptr = EISDIR; 4548dffb485Schristos else 4558dffb485Schristos *errno_ptr = EINVAL; 4568dffb485Schristos return false; 4578dffb485Schristos } 4588dffb485Schristos 4598dffb485Schristos /* See gdbsupport/filestuff.h. */ 4608dffb485Schristos 4618dffb485Schristos bool 4628dffb485Schristos mkdir_recursive (const char *dir) 4638dffb485Schristos { 4648dffb485Schristos auto holder = make_unique_xstrdup (dir); 4658dffb485Schristos char * const start = holder.get (); 4668dffb485Schristos char *component_start = start; 4678dffb485Schristos char *component_end = start; 4688dffb485Schristos 4698dffb485Schristos while (1) 4708dffb485Schristos { 4718dffb485Schristos /* Find the beginning of the next component. */ 4728dffb485Schristos while (*component_start == '/') 4738dffb485Schristos component_start++; 4748dffb485Schristos 4758dffb485Schristos /* Are we done? */ 4768dffb485Schristos if (*component_start == '\0') 4778dffb485Schristos return true; 4788dffb485Schristos 4798dffb485Schristos /* Find the slash or null-terminator after this component. */ 4808dffb485Schristos component_end = component_start; 4818dffb485Schristos while (*component_end != '/' && *component_end != '\0') 4828dffb485Schristos component_end++; 4838dffb485Schristos 4848dffb485Schristos /* Temporarily replace the slash with a null terminator, so we can create 4858dffb485Schristos the directory up to this component. */ 4868dffb485Schristos char saved_char = *component_end; 4878dffb485Schristos *component_end = '\0'; 4888dffb485Schristos 4898dffb485Schristos /* If we get EEXIST and the existing path is a directory, then we're 4908dffb485Schristos happy. If it exists, but it's a regular file and this is not the last 4918dffb485Schristos component, we'll fail at the next component. If this is the last 4928dffb485Schristos component, the caller will fail with ENOTDIR when trying to 4938dffb485Schristos open/create a file under that path. */ 4948dffb485Schristos if (mkdir (start, 0700) != 0) 4958dffb485Schristos if (errno != EEXIST) 4968dffb485Schristos return false; 4978dffb485Schristos 4988dffb485Schristos /* Restore the overwritten char. */ 4998dffb485Schristos *component_end = saved_char; 5008dffb485Schristos component_start = component_end; 5018dffb485Schristos } 5028dffb485Schristos } 5034b169a6bSchristos 5044b169a6bSchristos /* See gdbsupport/filestuff.h. */ 5054b169a6bSchristos 506*5ba1f45fSchristos std::string 507*5ba1f45fSchristos read_remainder_of_file (FILE *file) 5084b169a6bSchristos { 5094b169a6bSchristos std::string res; 5104b169a6bSchristos for (;;) 5114b169a6bSchristos { 5124b169a6bSchristos std::string::size_type start_size = res.size (); 5134b169a6bSchristos constexpr int chunk_size = 1024; 5144b169a6bSchristos 515*5ba1f45fSchristos /* Resize to accommodate CHUNK_SIZE bytes. */ 5164b169a6bSchristos res.resize (start_size + chunk_size); 5174b169a6bSchristos 518*5ba1f45fSchristos int n = fread (&res[start_size], 1, chunk_size, file); 5194b169a6bSchristos if (n == chunk_size) 5204b169a6bSchristos continue; 5214b169a6bSchristos 5224b169a6bSchristos gdb_assert (n < chunk_size); 5234b169a6bSchristos 5244b169a6bSchristos /* Less than CHUNK means EOF or error. If it's an error, return 5254b169a6bSchristos no value. */ 526*5ba1f45fSchristos if (ferror (file)) 5274b169a6bSchristos return {}; 5284b169a6bSchristos 5294b169a6bSchristos /* Resize the string according to the data we read. */ 5304b169a6bSchristos res.resize (start_size + n); 5314b169a6bSchristos break; 5324b169a6bSchristos } 5334b169a6bSchristos 5344b169a6bSchristos return res; 5354b169a6bSchristos } 536*5ba1f45fSchristos 537*5ba1f45fSchristos /* See gdbsupport/filestuff.h. */ 538*5ba1f45fSchristos 539*5ba1f45fSchristos std::optional<std::string> 540*5ba1f45fSchristos read_text_file_to_string (const char *path) 541*5ba1f45fSchristos { 542*5ba1f45fSchristos gdb_file_up file = gdb_fopen_cloexec (path, "r"); 543*5ba1f45fSchristos if (file == nullptr) 544*5ba1f45fSchristos return {}; 545*5ba1f45fSchristos 546*5ba1f45fSchristos return read_remainder_of_file (file.get ()); 547*5ba1f45fSchristos } 548