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