18a1362adSmaya/* 28a1362adSmaya * Copyright 2019 Intel Corporation 38a1362adSmaya * SPDX-License-Identifier: MIT 48a1362adSmaya */ 58a1362adSmaya 68a1362adSmaya#include "os_file.h" 77ec681f3Smrg#include "detect_os.h" 88a1362adSmaya 98a1362adSmaya#include <errno.h> 107ec681f3Smrg#include <fcntl.h> 118a1362adSmaya#include <stdlib.h> 127ec681f3Smrg#include <sys/stat.h> 137ec681f3Smrg 147ec681f3Smrg#if DETECT_OS_WINDOWS 157ec681f3Smrg#include <io.h> 167ec681f3Smrg#define open _open 177ec681f3Smrg#define fdopen _fdopen 187ec681f3Smrg#define O_CREAT _O_CREAT 197ec681f3Smrg#define O_EXCL _O_EXCL 207ec681f3Smrg#define O_WRONLY _O_WRONLY 217ec681f3Smrg#else 227ec681f3Smrg#include <unistd.h> 237ec681f3Smrg#ifndef F_DUPFD_CLOEXEC 247ec681f3Smrg#define F_DUPFD_CLOEXEC 1030 257ec681f3Smrg#endif 267ec681f3Smrg#endif 277ec681f3Smrg 287ec681f3Smrg 297ec681f3SmrgFILE * 307ec681f3Smrgos_file_create_unique(const char *filename, int filemode) 317ec681f3Smrg{ 327ec681f3Smrg int fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, filemode); 337ec681f3Smrg if (fd == -1) 347ec681f3Smrg return NULL; 357ec681f3Smrg return fdopen(fd, "w"); 367ec681f3Smrg} 377ec681f3Smrg 387ec681f3Smrg 397ec681f3Smrg#if DETECT_OS_WINDOWS 407ec681f3Smrgint 417ec681f3Smrgos_dupfd_cloexec(int fd) 427ec681f3Smrg{ 437ec681f3Smrg /* 447ec681f3Smrg * On Windows child processes don't inherit handles by default: 457ec681f3Smrg * https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873 467ec681f3Smrg */ 477ec681f3Smrg return dup(fd); 487ec681f3Smrg} 497ec681f3Smrg#else 507ec681f3Smrgint 517ec681f3Smrgos_dupfd_cloexec(int fd) 527ec681f3Smrg{ 537ec681f3Smrg int minfd = 3; 547ec681f3Smrg int newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd); 557ec681f3Smrg 567ec681f3Smrg if (newfd >= 0) 577ec681f3Smrg return newfd; 587ec681f3Smrg 597ec681f3Smrg if (errno != EINVAL) 607ec681f3Smrg return -1; 617ec681f3Smrg 627ec681f3Smrg newfd = fcntl(fd, F_DUPFD, minfd); 637ec681f3Smrg 647ec681f3Smrg if (newfd < 0) 657ec681f3Smrg return -1; 668a1362adSmaya 677ec681f3Smrg long flags = fcntl(newfd, F_GETFD); 687ec681f3Smrg if (flags == -1) { 697ec681f3Smrg close(newfd); 707ec681f3Smrg return -1; 717ec681f3Smrg } 727ec681f3Smrg 737ec681f3Smrg if (fcntl(newfd, F_SETFD, flags | FD_CLOEXEC) == -1) { 747ec681f3Smrg close(newfd); 757ec681f3Smrg return -1; 767ec681f3Smrg } 777ec681f3Smrg 787ec681f3Smrg return newfd; 797ec681f3Smrg} 807ec681f3Smrg#endif 818a1362adSmaya 828a1362adSmaya#include <fcntl.h> 838a1362adSmaya#include <sys/stat.h> 848a1362adSmaya 857ec681f3Smrg#if DETECT_OS_WINDOWS 867ec681f3Smrgtypedef ptrdiff_t ssize_t; 877ec681f3Smrg#endif 888a1362adSmaya 898a1362adSmayastatic ssize_t 908a1362adSmayareadN(int fd, char *buf, size_t len) 918a1362adSmaya{ 927ec681f3Smrg /* err was initially set to -ENODATA but in some BSD systems 937ec681f3Smrg * ENODATA is not defined and ENOATTR is used instead. 947ec681f3Smrg * As err is not returned by any function it can be initialized 957ec681f3Smrg * to -EFAULT that exists everywhere. 967ec681f3Smrg */ 977ec681f3Smrg int err = -EFAULT; 988a1362adSmaya size_t total = 0; 998a1362adSmaya do { 1008a1362adSmaya ssize_t ret = read(fd, buf + total, len - total); 1018a1362adSmaya 1028a1362adSmaya if (ret < 0) 1038a1362adSmaya ret = -errno; 1048a1362adSmaya 1058a1362adSmaya if (ret == -EINTR || ret == -EAGAIN) 1068a1362adSmaya continue; 1078a1362adSmaya 1088a1362adSmaya if (ret <= 0) { 1098a1362adSmaya err = ret; 1108a1362adSmaya break; 1118a1362adSmaya } 1128a1362adSmaya 1138a1362adSmaya total += ret; 1148a1362adSmaya } while (total != len); 1158a1362adSmaya 1167ec681f3Smrg return total ? (ssize_t)total : err; 1178a1362adSmaya} 1188a1362adSmaya 1197ec681f3Smrg#ifndef O_BINARY 1207ec681f3Smrg/* Unix makes no distinction between text and binary files. */ 1217ec681f3Smrg#define O_BINARY 0 1227ec681f3Smrg#endif 1237ec681f3Smrg 1248a1362adSmayachar * 1257ec681f3Smrgos_read_file(const char *filename, size_t *size) 1268a1362adSmaya{ 1278a1362adSmaya /* Note that this also serves as a slight margin to avoid a 2x grow when 1288a1362adSmaya * the file is just a few bytes larger when we read it than when we 1298a1362adSmaya * fstat'ed it. 1308a1362adSmaya * The string's NULL terminator is also included in here. 1318a1362adSmaya */ 1328a1362adSmaya size_t len = 64; 1338a1362adSmaya 1347ec681f3Smrg int fd = open(filename, O_RDONLY | O_BINARY); 1358a1362adSmaya if (fd == -1) { 1368a1362adSmaya /* errno set by open() */ 1378a1362adSmaya return NULL; 1388a1362adSmaya } 1398a1362adSmaya 1408a1362adSmaya /* Pre-allocate a buffer at least the size of the file if we can read 1418a1362adSmaya * that information. 1428a1362adSmaya */ 1438a1362adSmaya struct stat stat; 1448a1362adSmaya if (fstat(fd, &stat) == 0) 1458a1362adSmaya len += stat.st_size; 1468a1362adSmaya 1478a1362adSmaya char *buf = malloc(len); 1488a1362adSmaya if (!buf) { 1498a1362adSmaya close(fd); 1508a1362adSmaya errno = -ENOMEM; 1518a1362adSmaya return NULL; 1528a1362adSmaya } 1538a1362adSmaya 1547ec681f3Smrg ssize_t actually_read; 1558a1362adSmaya size_t offset = 0, remaining = len - 1; 1567ec681f3Smrg while ((actually_read = readN(fd, buf + offset, remaining)) == (ssize_t)remaining) { 1578a1362adSmaya char *newbuf = realloc(buf, 2 * len); 1588a1362adSmaya if (!newbuf) { 1598a1362adSmaya free(buf); 1608a1362adSmaya close(fd); 1618a1362adSmaya errno = -ENOMEM; 1628a1362adSmaya return NULL; 1638a1362adSmaya } 1648a1362adSmaya 1658a1362adSmaya buf = newbuf; 1668a1362adSmaya len *= 2; 1677ec681f3Smrg offset += actually_read; 1688a1362adSmaya remaining = len - offset - 1; 1698a1362adSmaya } 1708a1362adSmaya 1718a1362adSmaya close(fd); 1728a1362adSmaya 1737ec681f3Smrg if (actually_read > 0) 1747ec681f3Smrg offset += actually_read; 1758a1362adSmaya 1768a1362adSmaya /* Final resize to actual size */ 1778a1362adSmaya len = offset + 1; 1788a1362adSmaya char *newbuf = realloc(buf, len); 1798a1362adSmaya if (!newbuf) { 1808a1362adSmaya free(buf); 1818a1362adSmaya errno = -ENOMEM; 1828a1362adSmaya return NULL; 1838a1362adSmaya } 1848a1362adSmaya buf = newbuf; 1858a1362adSmaya 1868a1362adSmaya buf[offset] = '\0'; 1878a1362adSmaya 1887ec681f3Smrg if (size) 1897ec681f3Smrg *size = offset; 1907ec681f3Smrg 1918a1362adSmaya return buf; 1928a1362adSmaya} 1938a1362adSmaya 1947ec681f3Smrg#if DETECT_OS_LINUX 1957ec681f3Smrg 1967ec681f3Smrg#include <sys/syscall.h> 1977ec681f3Smrg#include <unistd.h> 1987ec681f3Smrg 1997ec681f3Smrg/* copied from <linux/kcmp.h> */ 2007ec681f3Smrg#define KCMP_FILE 0 2017ec681f3Smrg 2027ec681f3Smrgint 2037ec681f3Smrgos_same_file_description(int fd1, int fd2) 2047ec681f3Smrg{ 2057ec681f3Smrg pid_t pid = getpid(); 2067ec681f3Smrg 2077ec681f3Smrg /* Same file descriptor trivially implies same file description */ 2087ec681f3Smrg if (fd1 == fd2) 2097ec681f3Smrg return 0; 2107ec681f3Smrg 2117ec681f3Smrg return syscall(SYS_kcmp, pid, pid, KCMP_FILE, fd1, fd2); 2127ec681f3Smrg} 2137ec681f3Smrg 2148a1362adSmaya#else 2158a1362adSmaya 2167ec681f3Smrgint 2177ec681f3Smrgos_same_file_description(int fd1, int fd2) 2188a1362adSmaya{ 2197ec681f3Smrg /* Same file descriptor trivially implies same file description */ 2207ec681f3Smrg if (fd1 == fd2) 2217ec681f3Smrg return 0; 2227ec681f3Smrg 2237ec681f3Smrg /* Otherwise we can't tell */ 2247ec681f3Smrg return -1; 2258a1362adSmaya} 2268a1362adSmaya 2278a1362adSmaya#endif 228