From f73820fbbf2b6012ba3648f606712ae1e2a52511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Al=D0=B5x=D0=B0nder=20Lysik=D0=BEv?= <alexander.lysikov@demlabs.net> Date: Wed, 6 May 2020 14:56:14 +0500 Subject: [PATCH] added dap_file_get_contents() --- dap-sdk/core/include/dap_file_utils.h | 9 ++ dap-sdk/core/src/dap_file_utils.c | 205 ++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) diff --git a/dap-sdk/core/include/dap_file_utils.h b/dap-sdk/core/include/dap_file_utils.h index 92cfe9812c..9bc55055d7 100755 --- a/dap-sdk/core/include/dap_file_utils.h +++ b/dap-sdk/core/include/dap_file_utils.h @@ -44,6 +44,9 @@ #else +#ifndef O_BINARY +# define O_BINARY 0 +#endif #define DAP_DIR_SEPARATOR '/' #define DAP_DIR_SEPARATOR_S "/" #define DAP_IS_DIR_SEPARATOR(c) ((c) == DAP_DIR_SEPARATOR) @@ -102,4 +105,10 @@ char* dap_path_get_dirname(const char *a_file_name); */ dap_list_name_directories_t *dap_get_subs(const char *a_path_name); + +/* + * Reads an entire file into allocated memory, with error checking. + */ +bool dap_file_get_contents(const char *filename, char **contents, size_t *length); + #endif // _FILE_UTILS_H_ diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c index 910c64a79e..b57a898265 100755 --- a/dap-sdk/core/src/dap_file_utils.c +++ b/dap-sdk/core/src/dap_file_utils.c @@ -25,6 +25,11 @@ #include <stdlib.h> #include <stdint.h> #include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #if (OS_TARGET == OS_MACOS) #include <stdio.h> #else @@ -404,3 +409,203 @@ dap_list_name_directories_t *dap_get_subs(const char *a_path_dir){ #endif return list; } + +static bool get_contents_stdio(const char *filename, FILE *f, char **contents, size_t *length) +{ + char buf[4096]; + size_t bytes; /* always <= sizeof(buf) */ + char *str = NULL; + size_t total_bytes = 0; + size_t total_allocated = 0; + char *tmp; + assert(f != NULL); + while(!feof(f)) { + int save_errno; + + bytes = fread(buf, 1, sizeof(buf), f); + save_errno = errno; + + if(total_bytes > ULONG_MAX - bytes) + goto file_too_large; + + /* Possibility of overflow eliminated above. */ + while(total_bytes + bytes >= total_allocated) { + if(str) { + if(total_allocated > ULONG_MAX / 2) + goto file_too_large; + total_allocated *= 2; + } + else { + total_allocated = MIN(bytes + 1, sizeof(buf)); + } + + tmp = DAP_REALLOC(str, total_allocated); + + if(tmp == NULL) + goto error; + + str = tmp; + } + + if(ferror(f)) + goto error; + + assert(str != NULL); + memcpy(str + total_bytes, buf, bytes); + total_bytes += bytes; + } + + fclose(f); + + if(total_allocated == 0) + { + str = DAP_NEW_SIZE(char, 1); + total_bytes = 0; + } + + str[total_bytes] = '\0'; + + if(length) + *length = total_bytes; + + *contents = str; + + return true; + + file_too_large: + error: + + DAP_DELETE(str); + fclose(f); + return false; +} + +#ifndef _WIN32 + +static bool dap_get_contents_regfile(const char *filename, struct stat *stat_buf, int fd, char **contents, + size_t *length) +{ + char *buf; + size_t bytes_read; + size_t size; + size_t alloc_size; + + size = stat_buf->st_size; + + alloc_size = size + 1; + buf = DAP_NEW_SIZE(char, alloc_size); + + if(buf == NULL) { + goto error; + } + + bytes_read = 0; + while(bytes_read < size) { + size_t rc; + + rc = read(fd, buf + bytes_read, size - bytes_read); + + if(rc < 0) { + if(errno != EINTR) { + DAP_DELETE(buf); + goto error; + } + } + else if(rc == 0) + break; + else + bytes_read += rc; + } + + buf[bytes_read] = '\0'; + + if(length) + *length = bytes_read; + + *contents = buf; + + close(fd); + + return true; + + error: + + close(fd); + + return false; +} + +static bool dap_get_contents_posix(const char *filename, char **contents, size_t *length) +{ + struct stat stat_buf; + int fd; + + /* O_BINARY useful on Cygwin */ + fd = open(filename, O_RDONLY | O_BINARY); + + if(fd < 0) + return false; + + /* I don't think this will ever fail, aside from ENOMEM, but. */ + if(fstat(fd, &stat_buf) < 0) { + close(fd); + return false; + } + + if(stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) { + bool retval = dap_get_contents_regfile(filename, + &stat_buf, + fd, + contents, + length); + return retval; + } + else { + FILE *f; + bool retval; + f = fdopen(fd, "r"); + if(f == NULL) + return false; + retval = get_contents_stdio(filename, f, contents, length); + return retval; + } +} + +#else /* _WIN32 */ + +static bool dap_get_contents_win32(const char *filename, char **contents, size_t *length) +{ + FILE *f; + bool retval; + + f = fopen(filename, "rb"); + + if(f == NULL) + { + return false; + } + retval = get_contents_stdio (filename, f, contents, length, error); + return retval; +} + +#endif + +/* + * Reads an entire file into allocated memory, with error checking. + */ +bool dap_file_get_contents(const char *filename, char **contents, size_t *length) +{ + dap_return_val_if_fail(filename != NULL, false); + dap_return_val_if_fail(contents != NULL, false); + + *contents = NULL; + if(length) + *length = 0; + +#ifdef _WIN32 + return dap_get_contents_win32 (filename, contents, length); +#else + return dap_get_contents_posix(filename, contents, length); +#endif +} + -- GitLab