diff options
-rw-r--r-- | src/util/Makefile.sources | 2 | ||||
-rw-r--r-- | src/util/meson.build | 1 | ||||
-rw-r--r-- | src/util/os_file.c | 129 | ||||
-rw-r--r-- | src/util/os_file.h | 26 |
4 files changed, 158 insertions, 0 deletions
diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources index 541cb6b85be..ad8c56d3d1b 100644 --- a/src/util/Makefile.sources +++ b/src/util/Makefile.sources @@ -29,6 +29,8 @@ MESA_UTIL_FILES := \ mesa-sha1.h \ os_time.c \ os_time.h \ + os_file.c \ + os_file.h \ os_misc.c \ os_misc.h \ u_process.c \ diff --git a/src/util/meson.build b/src/util/meson.build index 322c75e5985..489b6df1710 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -52,6 +52,7 @@ files_mesa_util = files( 'mesa-sha1.h', 'os_time.c', 'os_time.h', + 'os_file.c', 'os_misc.c', 'os_misc.h', 'u_process.c', diff --git a/src/util/os_file.c b/src/util/os_file.c new file mode 100644 index 00000000000..cee9d22c8ec --- /dev/null +++ b/src/util/os_file.c @@ -0,0 +1,129 @@ +/* + * Copyright 2019 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#include "os_file.h" + +#include <errno.h> + +#if defined(__linux__) + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + + +static ssize_t +readN(int fd, char *buf, size_t len) +{ + int err = -ENODATA; + size_t total = 0; + do { + ssize_t ret = read(fd, buf + total, len - total); + + if (ret < 0) + ret = -errno; + + if (ret == -EINTR || ret == -EAGAIN) + continue; + + if (ret <= 0) + break; + + total += ret; + } while (total != len); + + return total ? total : err; +} + +static char * +read_grow(int fd) +{ + size_t len = 64; + + char *buf = malloc(len); + if (!buf) { + close(fd); + errno = -ENOMEM; + return NULL; + } + + ssize_t read; + size_t offset = 0, remaining = len - 1; + while ((read = readN(fd, buf + offset, remaining)) == remaining) { + char *newbuf = realloc(buf, 2 * len); + if (!newbuf) { + free(buf); + close(fd); + errno = -ENOMEM; + return NULL; + } + + buf = newbuf; + len *= 2; + offset += read; + remaining = len - offset - 1; + } + + close(fd); + + if (read > 0) + offset += read; + + buf[offset] = '\0'; + + return buf; +} + +char * +os_read_file(const char *filename) +{ + size_t len = 0; + + int fd = open(filename, O_RDONLY); + if (fd == -1) { + /* errno set by open() */ + return NULL; + } + + struct stat stat; + if (fstat(fd, &stat) == 0) + len = stat.st_size; + + if (!len) + return read_grow(fd); + + /* add NULL terminator */ + len++; + + char *buf = malloc(len); + if (!buf) { + close(fd); + errno = -ENOMEM; + return NULL; + } + + ssize_t read = readN(fd, buf, len - 1); + + close(fd); + + if (read == -1) + return NULL; + + buf[read] = '\0'; + + return buf; +} + +#else + +char * +os_read_file(const char *filename) +{ + errno = -ENOSYS; + return NULL; +} + +#endif diff --git a/src/util/os_file.h b/src/util/os_file.h new file mode 100644 index 00000000000..2f97c19ed55 --- /dev/null +++ b/src/util/os_file.h @@ -0,0 +1,26 @@ +/* + * Copyright 2019 Intel Corporation + * SPDX-License-Identifier: MIT + * + * File operations helpers + */ + +#ifndef _OS_FILE_H_ +#define _OS_FILE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Read a file. + * Returns a char* that the caller must free(), or NULL and sets errno. + */ +char * +os_read_file(const char *filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_FILE_H_ */ |