os_file.c revision 8a1362ad
1/* 2 * Copyright 2019 Intel Corporation 3 * SPDX-License-Identifier: MIT 4 */ 5 6#include "os_file.h" 7 8#include <errno.h> 9#include <stdlib.h> 10 11#if defined(__linux__) 12 13#include <fcntl.h> 14#include <sys/stat.h> 15#include <unistd.h> 16 17 18static ssize_t 19readN(int fd, char *buf, size_t len) 20{ 21 int err = -ENODATA; 22 size_t total = 0; 23 do { 24 ssize_t ret = read(fd, buf + total, len - total); 25 26 if (ret < 0) 27 ret = -errno; 28 29 if (ret == -EINTR || ret == -EAGAIN) 30 continue; 31 32 if (ret <= 0) { 33 err = ret; 34 break; 35 } 36 37 total += ret; 38 } while (total != len); 39 40 return total ? total : err; 41} 42 43char * 44os_read_file(const char *filename) 45{ 46 /* Note that this also serves as a slight margin to avoid a 2x grow when 47 * the file is just a few bytes larger when we read it than when we 48 * fstat'ed it. 49 * The string's NULL terminator is also included in here. 50 */ 51 size_t len = 64; 52 53 int fd = open(filename, O_RDONLY); 54 if (fd == -1) { 55 /* errno set by open() */ 56 return NULL; 57 } 58 59 /* Pre-allocate a buffer at least the size of the file if we can read 60 * that information. 61 */ 62 struct stat stat; 63 if (fstat(fd, &stat) == 0) 64 len += stat.st_size; 65 66 char *buf = malloc(len); 67 if (!buf) { 68 close(fd); 69 errno = -ENOMEM; 70 return NULL; 71 } 72 73 ssize_t read; 74 size_t offset = 0, remaining = len - 1; 75 while ((read = readN(fd, buf + offset, remaining)) == remaining) { 76 char *newbuf = realloc(buf, 2 * len); 77 if (!newbuf) { 78 free(buf); 79 close(fd); 80 errno = -ENOMEM; 81 return NULL; 82 } 83 84 buf = newbuf; 85 len *= 2; 86 offset += read; 87 remaining = len - offset - 1; 88 } 89 90 close(fd); 91 92 if (read > 0) 93 offset += read; 94 95 /* Final resize to actual size */ 96 len = offset + 1; 97 char *newbuf = realloc(buf, len); 98 if (!newbuf) { 99 free(buf); 100 errno = -ENOMEM; 101 return NULL; 102 } 103 buf = newbuf; 104 105 buf[offset] = '\0'; 106 107 return buf; 108} 109 110#else 111 112char * 113os_read_file(const char *filename) 114{ 115 errno = -ENOSYS; 116 return NULL; 117} 118 119#endif 120