1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2019 Intel Corporation 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci */ 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_ci#include "os_file.h" 7bf215546Sopenharmony_ci#include "detect_os.h" 8bf215546Sopenharmony_ci 9bf215546Sopenharmony_ci#include <errno.h> 10bf215546Sopenharmony_ci#include <fcntl.h> 11bf215546Sopenharmony_ci#include <stdlib.h> 12bf215546Sopenharmony_ci#include <sys/stat.h> 13bf215546Sopenharmony_ci 14bf215546Sopenharmony_ci#if DETECT_OS_WINDOWS 15bf215546Sopenharmony_ci#include <io.h> 16bf215546Sopenharmony_ci#define open _open 17bf215546Sopenharmony_ci#define fdopen _fdopen 18bf215546Sopenharmony_ci#define O_CREAT _O_CREAT 19bf215546Sopenharmony_ci#define O_EXCL _O_EXCL 20bf215546Sopenharmony_ci#define O_WRONLY _O_WRONLY 21bf215546Sopenharmony_ci#else 22bf215546Sopenharmony_ci#include <unistd.h> 23bf215546Sopenharmony_ci#ifndef F_DUPFD_CLOEXEC 24bf215546Sopenharmony_ci#define F_DUPFD_CLOEXEC 1030 25bf215546Sopenharmony_ci#endif 26bf215546Sopenharmony_ci#endif 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ciFILE * 30bf215546Sopenharmony_cios_file_create_unique(const char *filename, int filemode) 31bf215546Sopenharmony_ci{ 32bf215546Sopenharmony_ci int fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, filemode); 33bf215546Sopenharmony_ci if (fd == -1) 34bf215546Sopenharmony_ci return NULL; 35bf215546Sopenharmony_ci return fdopen(fd, "w"); 36bf215546Sopenharmony_ci} 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#if DETECT_OS_WINDOWS 40bf215546Sopenharmony_ciint 41bf215546Sopenharmony_cios_dupfd_cloexec(int fd) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci /* 44bf215546Sopenharmony_ci * On Windows child processes don't inherit handles by default: 45bf215546Sopenharmony_ci * https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873 46bf215546Sopenharmony_ci */ 47bf215546Sopenharmony_ci return dup(fd); 48bf215546Sopenharmony_ci} 49bf215546Sopenharmony_ci#else 50bf215546Sopenharmony_ciint 51bf215546Sopenharmony_cios_dupfd_cloexec(int fd) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci int minfd = 3; 54bf215546Sopenharmony_ci int newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd); 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci if (newfd >= 0) 57bf215546Sopenharmony_ci return newfd; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci if (errno != EINVAL) 60bf215546Sopenharmony_ci return -1; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci newfd = fcntl(fd, F_DUPFD, minfd); 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci if (newfd < 0) 65bf215546Sopenharmony_ci return -1; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci long flags = fcntl(newfd, F_GETFD); 68bf215546Sopenharmony_ci if (flags == -1) { 69bf215546Sopenharmony_ci close(newfd); 70bf215546Sopenharmony_ci return -1; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci if (fcntl(newfd, F_SETFD, flags | FD_CLOEXEC) == -1) { 74bf215546Sopenharmony_ci close(newfd); 75bf215546Sopenharmony_ci return -1; 76bf215546Sopenharmony_ci } 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci return newfd; 79bf215546Sopenharmony_ci} 80bf215546Sopenharmony_ci#endif 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci#include <fcntl.h> 83bf215546Sopenharmony_ci#include <sys/stat.h> 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci#if DETECT_OS_WINDOWS 86bf215546Sopenharmony_citypedef ptrdiff_t ssize_t; 87bf215546Sopenharmony_ci#endif 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_cistatic ssize_t 90bf215546Sopenharmony_cireadN(int fd, char *buf, size_t len) 91bf215546Sopenharmony_ci{ 92bf215546Sopenharmony_ci /* err was initially set to -ENODATA but in some BSD systems 93bf215546Sopenharmony_ci * ENODATA is not defined and ENOATTR is used instead. 94bf215546Sopenharmony_ci * As err is not returned by any function it can be initialized 95bf215546Sopenharmony_ci * to -EFAULT that exists everywhere. 96bf215546Sopenharmony_ci */ 97bf215546Sopenharmony_ci int err = -EFAULT; 98bf215546Sopenharmony_ci size_t total = 0; 99bf215546Sopenharmony_ci do { 100bf215546Sopenharmony_ci ssize_t ret = read(fd, buf + total, len - total); 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci if (ret < 0) 103bf215546Sopenharmony_ci ret = -errno; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (ret == -EINTR || ret == -EAGAIN) 106bf215546Sopenharmony_ci continue; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci if (ret <= 0) { 109bf215546Sopenharmony_ci err = ret; 110bf215546Sopenharmony_ci break; 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci total += ret; 114bf215546Sopenharmony_ci } while (total != len); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci return total ? (ssize_t)total : err; 117bf215546Sopenharmony_ci} 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci#ifndef O_BINARY 120bf215546Sopenharmony_ci/* Unix makes no distinction between text and binary files. */ 121bf215546Sopenharmony_ci#define O_BINARY 0 122bf215546Sopenharmony_ci#endif 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cichar * 125bf215546Sopenharmony_cios_read_file(const char *filename, size_t *size) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci /* Note that this also serves as a slight margin to avoid a 2x grow when 128bf215546Sopenharmony_ci * the file is just a few bytes larger when we read it than when we 129bf215546Sopenharmony_ci * fstat'ed it. 130bf215546Sopenharmony_ci * The string's NULL terminator is also included in here. 131bf215546Sopenharmony_ci */ 132bf215546Sopenharmony_ci size_t len = 64; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci int fd = open(filename, O_RDONLY | O_BINARY); 135bf215546Sopenharmony_ci if (fd == -1) { 136bf215546Sopenharmony_ci /* errno set by open() */ 137bf215546Sopenharmony_ci return NULL; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci /* Pre-allocate a buffer at least the size of the file if we can read 141bf215546Sopenharmony_ci * that information. 142bf215546Sopenharmony_ci */ 143bf215546Sopenharmony_ci struct stat stat; 144bf215546Sopenharmony_ci if (fstat(fd, &stat) == 0) 145bf215546Sopenharmony_ci len += stat.st_size; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci char *buf = malloc(len); 148bf215546Sopenharmony_ci if (!buf) { 149bf215546Sopenharmony_ci close(fd); 150bf215546Sopenharmony_ci errno = -ENOMEM; 151bf215546Sopenharmony_ci return NULL; 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci ssize_t actually_read; 155bf215546Sopenharmony_ci size_t offset = 0, remaining = len - 1; 156bf215546Sopenharmony_ci while ((actually_read = readN(fd, buf + offset, remaining)) == (ssize_t)remaining) { 157bf215546Sopenharmony_ci char *newbuf = realloc(buf, 2 * len); 158bf215546Sopenharmony_ci if (!newbuf) { 159bf215546Sopenharmony_ci free(buf); 160bf215546Sopenharmony_ci close(fd); 161bf215546Sopenharmony_ci errno = -ENOMEM; 162bf215546Sopenharmony_ci return NULL; 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci buf = newbuf; 166bf215546Sopenharmony_ci len *= 2; 167bf215546Sopenharmony_ci offset += actually_read; 168bf215546Sopenharmony_ci remaining = len - offset - 1; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci close(fd); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci if (actually_read > 0) 174bf215546Sopenharmony_ci offset += actually_read; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci /* Final resize to actual size */ 177bf215546Sopenharmony_ci len = offset + 1; 178bf215546Sopenharmony_ci char *newbuf = realloc(buf, len); 179bf215546Sopenharmony_ci if (!newbuf) { 180bf215546Sopenharmony_ci free(buf); 181bf215546Sopenharmony_ci errno = -ENOMEM; 182bf215546Sopenharmony_ci return NULL; 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci buf = newbuf; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci buf[offset] = '\0'; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (size) 189bf215546Sopenharmony_ci *size = offset; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci return buf; 192bf215546Sopenharmony_ci} 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci#if DETECT_OS_LINUX 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci#include <sys/syscall.h> 197bf215546Sopenharmony_ci#include <unistd.h> 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci/* copied from <linux/kcmp.h> */ 200bf215546Sopenharmony_ci#define KCMP_FILE 0 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ciint 203bf215546Sopenharmony_cios_same_file_description(int fd1, int fd2) 204bf215546Sopenharmony_ci{ 205bf215546Sopenharmony_ci pid_t pid = getpid(); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci /* Same file descriptor trivially implies same file description */ 208bf215546Sopenharmony_ci if (fd1 == fd2) 209bf215546Sopenharmony_ci return 0; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci return syscall(SYS_kcmp, pid, pid, KCMP_FILE, fd1, fd2); 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci#else 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ciint 217bf215546Sopenharmony_cios_same_file_description(int fd1, int fd2) 218bf215546Sopenharmony_ci{ 219bf215546Sopenharmony_ci /* Same file descriptor trivially implies same file description */ 220bf215546Sopenharmony_ci if (fd1 == fd2) 221bf215546Sopenharmony_ci return 0; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* Otherwise we can't tell */ 224bf215546Sopenharmony_ci return -1; 225bf215546Sopenharmony_ci} 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci#endif 228