1*5a6e8488SAndroid Build Coastguard Worker /*
2*5a6e8488SAndroid Build Coastguard Worker * *****************************************************************************
3*5a6e8488SAndroid Build Coastguard Worker *
4*5a6e8488SAndroid Build Coastguard Worker * SPDX-License-Identifier: BSD-2-Clause
5*5a6e8488SAndroid Build Coastguard Worker *
6*5a6e8488SAndroid Build Coastguard Worker * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7*5a6e8488SAndroid Build Coastguard Worker *
8*5a6e8488SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
9*5a6e8488SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
10*5a6e8488SAndroid Build Coastguard Worker *
11*5a6e8488SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright notice, this
12*5a6e8488SAndroid Build Coastguard Worker * list of conditions and the following disclaimer.
13*5a6e8488SAndroid Build Coastguard Worker *
14*5a6e8488SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright notice,
15*5a6e8488SAndroid Build Coastguard Worker * this list of conditions and the following disclaimer in the documentation
16*5a6e8488SAndroid Build Coastguard Worker * and/or other materials provided with the distribution.
17*5a6e8488SAndroid Build Coastguard Worker *
18*5a6e8488SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*5a6e8488SAndroid Build Coastguard Worker * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5a6e8488SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5a6e8488SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*5a6e8488SAndroid Build Coastguard Worker * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*5a6e8488SAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*5a6e8488SAndroid Build Coastguard Worker * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*5a6e8488SAndroid Build Coastguard Worker * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*5a6e8488SAndroid Build Coastguard Worker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*5a6e8488SAndroid Build Coastguard Worker * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*5a6e8488SAndroid Build Coastguard Worker * POSSIBILITY OF SUCH DAMAGE.
29*5a6e8488SAndroid Build Coastguard Worker *
30*5a6e8488SAndroid Build Coastguard Worker * *****************************************************************************
31*5a6e8488SAndroid Build Coastguard Worker *
32*5a6e8488SAndroid Build Coastguard Worker * Code to handle special I/O for bc.
33*5a6e8488SAndroid Build Coastguard Worker *
34*5a6e8488SAndroid Build Coastguard Worker */
35*5a6e8488SAndroid Build Coastguard Worker
36*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
37*5a6e8488SAndroid Build Coastguard Worker #include <ctype.h>
38*5a6e8488SAndroid Build Coastguard Worker #include <errno.h>
39*5a6e8488SAndroid Build Coastguard Worker #include <stdlib.h>
40*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
41*5a6e8488SAndroid Build Coastguard Worker
42*5a6e8488SAndroid Build Coastguard Worker #include <signal.h>
43*5a6e8488SAndroid Build Coastguard Worker
44*5a6e8488SAndroid Build Coastguard Worker #include <fcntl.h>
45*5a6e8488SAndroid Build Coastguard Worker #include <sys/stat.h>
46*5a6e8488SAndroid Build Coastguard Worker
47*5a6e8488SAndroid Build Coastguard Worker #ifndef _WIN32
48*5a6e8488SAndroid Build Coastguard Worker #include <unistd.h>
49*5a6e8488SAndroid Build Coastguard Worker #endif // _WIN32
50*5a6e8488SAndroid Build Coastguard Worker
51*5a6e8488SAndroid Build Coastguard Worker #include <read.h>
52*5a6e8488SAndroid Build Coastguard Worker #include <history.h>
53*5a6e8488SAndroid Build Coastguard Worker #include <program.h>
54*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
55*5a6e8488SAndroid Build Coastguard Worker
56*5a6e8488SAndroid Build Coastguard Worker /**
57*5a6e8488SAndroid Build Coastguard Worker * A portability file open function. This is copied to gen/strgen.c. Make sure
58*5a6e8488SAndroid Build Coastguard Worker * to update that if this changes.
59*5a6e8488SAndroid Build Coastguard Worker * @param path The path to the file to open.
60*5a6e8488SAndroid Build Coastguard Worker * @param mode The mode to open in.
61*5a6e8488SAndroid Build Coastguard Worker */
62*5a6e8488SAndroid Build Coastguard Worker static int
bc_read_open(const char * path,int mode)63*5a6e8488SAndroid Build Coastguard Worker bc_read_open(const char* path, int mode)
64*5a6e8488SAndroid Build Coastguard Worker {
65*5a6e8488SAndroid Build Coastguard Worker int fd;
66*5a6e8488SAndroid Build Coastguard Worker
67*5a6e8488SAndroid Build Coastguard Worker #ifndef _WIN32
68*5a6e8488SAndroid Build Coastguard Worker fd = open(path, mode);
69*5a6e8488SAndroid Build Coastguard Worker #else // _WIN32
70*5a6e8488SAndroid Build Coastguard Worker fd = -1;
71*5a6e8488SAndroid Build Coastguard Worker open(&fd, path, mode);
72*5a6e8488SAndroid Build Coastguard Worker #endif
73*5a6e8488SAndroid Build Coastguard Worker
74*5a6e8488SAndroid Build Coastguard Worker return fd;
75*5a6e8488SAndroid Build Coastguard Worker }
76*5a6e8488SAndroid Build Coastguard Worker
77*5a6e8488SAndroid Build Coastguard Worker /**
78*5a6e8488SAndroid Build Coastguard Worker * Returns true if the buffer data is non-text.
79*5a6e8488SAndroid Build Coastguard Worker * @param buf The buffer to test.
80*5a6e8488SAndroid Build Coastguard Worker * @param size The size of the buffer.
81*5a6e8488SAndroid Build Coastguard Worker */
82*5a6e8488SAndroid Build Coastguard Worker static bool
bc_read_binary(const char * buf,size_t size)83*5a6e8488SAndroid Build Coastguard Worker bc_read_binary(const char* buf, size_t size)
84*5a6e8488SAndroid Build Coastguard Worker {
85*5a6e8488SAndroid Build Coastguard Worker size_t i;
86*5a6e8488SAndroid Build Coastguard Worker
87*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < size; ++i)
88*5a6e8488SAndroid Build Coastguard Worker {
89*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_READ_BIN_CHAR(buf[i]))) return true;
90*5a6e8488SAndroid Build Coastguard Worker }
91*5a6e8488SAndroid Build Coastguard Worker
92*5a6e8488SAndroid Build Coastguard Worker return false;
93*5a6e8488SAndroid Build Coastguard Worker }
94*5a6e8488SAndroid Build Coastguard Worker
95*5a6e8488SAndroid Build Coastguard Worker bool
bc_read_buf(BcVec * vec,char * buf,size_t * buf_len)96*5a6e8488SAndroid Build Coastguard Worker bc_read_buf(BcVec* vec, char* buf, size_t* buf_len)
97*5a6e8488SAndroid Build Coastguard Worker {
98*5a6e8488SAndroid Build Coastguard Worker char* nl;
99*5a6e8488SAndroid Build Coastguard Worker
100*5a6e8488SAndroid Build Coastguard Worker // If nothing there, return.
101*5a6e8488SAndroid Build Coastguard Worker if (!*buf_len) return false;
102*5a6e8488SAndroid Build Coastguard Worker
103*5a6e8488SAndroid Build Coastguard Worker // Find the newline.
104*5a6e8488SAndroid Build Coastguard Worker nl = strchr(buf, '\n');
105*5a6e8488SAndroid Build Coastguard Worker
106*5a6e8488SAndroid Build Coastguard Worker // If a newline exists...
107*5a6e8488SAndroid Build Coastguard Worker if (nl != NULL)
108*5a6e8488SAndroid Build Coastguard Worker {
109*5a6e8488SAndroid Build Coastguard Worker // Get the size of the data up to, and including, the newline.
110*5a6e8488SAndroid Build Coastguard Worker size_t nllen = (size_t) ((nl + 1) - buf);
111*5a6e8488SAndroid Build Coastguard Worker
112*5a6e8488SAndroid Build Coastguard Worker nllen = *buf_len >= nllen ? nllen : *buf_len;
113*5a6e8488SAndroid Build Coastguard Worker
114*5a6e8488SAndroid Build Coastguard Worker // Move data into the vector, and move the rest of the data in the
115*5a6e8488SAndroid Build Coastguard Worker // buffer up.
116*5a6e8488SAndroid Build Coastguard Worker bc_vec_npush(vec, nllen, buf);
117*5a6e8488SAndroid Build Coastguard Worker *buf_len -= nllen;
118*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
119*5a6e8488SAndroid Build Coastguard Worker memmove(buf, nl + 1, *buf_len + 1);
120*5a6e8488SAndroid Build Coastguard Worker
121*5a6e8488SAndroid Build Coastguard Worker return true;
122*5a6e8488SAndroid Build Coastguard Worker }
123*5a6e8488SAndroid Build Coastguard Worker
124*5a6e8488SAndroid Build Coastguard Worker // Just put the data into the vector.
125*5a6e8488SAndroid Build Coastguard Worker bc_vec_npush(vec, *buf_len, buf);
126*5a6e8488SAndroid Build Coastguard Worker *buf_len = 0;
127*5a6e8488SAndroid Build Coastguard Worker
128*5a6e8488SAndroid Build Coastguard Worker return false;
129*5a6e8488SAndroid Build Coastguard Worker }
130*5a6e8488SAndroid Build Coastguard Worker
131*5a6e8488SAndroid Build Coastguard Worker BcStatus
bc_read_chars(BcVec * vec,const char * prompt)132*5a6e8488SAndroid Build Coastguard Worker bc_read_chars(BcVec* vec, const char* prompt)
133*5a6e8488SAndroid Build Coastguard Worker {
134*5a6e8488SAndroid Build Coastguard Worker bool done = false;
135*5a6e8488SAndroid Build Coastguard Worker
136*5a6e8488SAndroid Build Coastguard Worker assert(vec != NULL && vec->size == sizeof(char));
137*5a6e8488SAndroid Build Coastguard Worker
138*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_NOT_LOCKED;
139*5a6e8488SAndroid Build Coastguard Worker
140*5a6e8488SAndroid Build Coastguard Worker // Clear the vector.
141*5a6e8488SAndroid Build Coastguard Worker bc_vec_popAll(vec);
142*5a6e8488SAndroid Build Coastguard Worker
143*5a6e8488SAndroid Build Coastguard Worker // Handle the prompt, if desired.
144*5a6e8488SAndroid Build Coastguard Worker if (BC_PROMPT)
145*5a6e8488SAndroid Build Coastguard Worker {
146*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_none, prompt);
147*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_none);
148*5a6e8488SAndroid Build Coastguard Worker }
149*5a6e8488SAndroid Build Coastguard Worker
150*5a6e8488SAndroid Build Coastguard Worker // Try reading from the buffer, and if successful, just return.
151*5a6e8488SAndroid Build Coastguard Worker if (bc_read_buf(vec, vm->buf, &vm->buf_len))
152*5a6e8488SAndroid Build Coastguard Worker {
153*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushByte(vec, '\0');
154*5a6e8488SAndroid Build Coastguard Worker return BC_STATUS_SUCCESS;
155*5a6e8488SAndroid Build Coastguard Worker }
156*5a6e8488SAndroid Build Coastguard Worker
157*5a6e8488SAndroid Build Coastguard Worker // Loop until we have something.
158*5a6e8488SAndroid Build Coastguard Worker while (!done)
159*5a6e8488SAndroid Build Coastguard Worker {
160*5a6e8488SAndroid Build Coastguard Worker ssize_t r;
161*5a6e8488SAndroid Build Coastguard Worker
162*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
163*5a6e8488SAndroid Build Coastguard Worker
164*5a6e8488SAndroid Build Coastguard Worker // Read data from stdin.
165*5a6e8488SAndroid Build Coastguard Worker r = read(STDIN_FILENO, vm->buf + vm->buf_len,
166*5a6e8488SAndroid Build Coastguard Worker BC_VM_STDIN_BUF_SIZE - vm->buf_len);
167*5a6e8488SAndroid Build Coastguard Worker
168*5a6e8488SAndroid Build Coastguard Worker // If there was an error...
169*5a6e8488SAndroid Build Coastguard Worker if (BC_UNLIKELY(r < 0))
170*5a6e8488SAndroid Build Coastguard Worker {
171*5a6e8488SAndroid Build Coastguard Worker // If interupted...
172*5a6e8488SAndroid Build Coastguard Worker if (errno == EINTR)
173*5a6e8488SAndroid Build Coastguard Worker {
174*5a6e8488SAndroid Build Coastguard Worker int sig;
175*5a6e8488SAndroid Build Coastguard Worker
176*5a6e8488SAndroid Build Coastguard Worker // Jump out if we are supposed to quit, which certain signals
177*5a6e8488SAndroid Build Coastguard Worker // will require.
178*5a6e8488SAndroid Build Coastguard Worker if (vm->status == (sig_atomic_t) BC_STATUS_QUIT) BC_JMP;
179*5a6e8488SAndroid Build Coastguard Worker
180*5a6e8488SAndroid Build Coastguard Worker assert(vm->sig != 0);
181*5a6e8488SAndroid Build Coastguard Worker
182*5a6e8488SAndroid Build Coastguard Worker sig = (int) vm->sig;
183*5a6e8488SAndroid Build Coastguard Worker
184*5a6e8488SAndroid Build Coastguard Worker // Clear the signal and status.
185*5a6e8488SAndroid Build Coastguard Worker vm->sig = 0;
186*5a6e8488SAndroid Build Coastguard Worker vm->status = (sig_atomic_t) BC_STATUS_SUCCESS;
187*5a6e8488SAndroid Build Coastguard Worker
188*5a6e8488SAndroid Build Coastguard Worker #ifndef _WIN32
189*5a6e8488SAndroid Build Coastguard Worker // We don't want to print anything on a SIGWINCH.
190*5a6e8488SAndroid Build Coastguard Worker if (sig != SIGWINCH)
191*5a6e8488SAndroid Build Coastguard Worker #endif // _WIN32
192*5a6e8488SAndroid Build Coastguard Worker {
193*5a6e8488SAndroid Build Coastguard Worker // Print the ready message and prompt again.
194*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_none,
195*5a6e8488SAndroid Build Coastguard Worker bc_program_ready_msg);
196*5a6e8488SAndroid Build Coastguard Worker if (BC_PROMPT)
197*5a6e8488SAndroid Build Coastguard Worker {
198*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_none, prompt);
199*5a6e8488SAndroid Build Coastguard Worker }
200*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_none);
201*5a6e8488SAndroid Build Coastguard Worker }
202*5a6e8488SAndroid Build Coastguard Worker
203*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
204*5a6e8488SAndroid Build Coastguard Worker
205*5a6e8488SAndroid Build Coastguard Worker continue;
206*5a6e8488SAndroid Build Coastguard Worker }
207*5a6e8488SAndroid Build Coastguard Worker
208*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
209*5a6e8488SAndroid Build Coastguard Worker
210*5a6e8488SAndroid Build Coastguard Worker // If we get here, it's bad. Barf.
211*5a6e8488SAndroid Build Coastguard Worker bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
212*5a6e8488SAndroid Build Coastguard Worker }
213*5a6e8488SAndroid Build Coastguard Worker
214*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
215*5a6e8488SAndroid Build Coastguard Worker
216*5a6e8488SAndroid Build Coastguard Worker // If we read nothing, make sure to terminate the string and return EOF.
217*5a6e8488SAndroid Build Coastguard Worker if (r == 0)
218*5a6e8488SAndroid Build Coastguard Worker {
219*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushByte(vec, '\0');
220*5a6e8488SAndroid Build Coastguard Worker return BC_STATUS_EOF;
221*5a6e8488SAndroid Build Coastguard Worker }
222*5a6e8488SAndroid Build Coastguard Worker
223*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
224*5a6e8488SAndroid Build Coastguard Worker
225*5a6e8488SAndroid Build Coastguard Worker // Add to the buffer.
226*5a6e8488SAndroid Build Coastguard Worker vm->buf_len += (size_t) r;
227*5a6e8488SAndroid Build Coastguard Worker vm->buf[vm->buf_len] = '\0';
228*5a6e8488SAndroid Build Coastguard Worker
229*5a6e8488SAndroid Build Coastguard Worker // Read from the buffer.
230*5a6e8488SAndroid Build Coastguard Worker done = bc_read_buf(vec, vm->buf, &vm->buf_len);
231*5a6e8488SAndroid Build Coastguard Worker
232*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
233*5a6e8488SAndroid Build Coastguard Worker }
234*5a6e8488SAndroid Build Coastguard Worker
235*5a6e8488SAndroid Build Coastguard Worker // Terminate the string.
236*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushByte(vec, '\0');
237*5a6e8488SAndroid Build Coastguard Worker
238*5a6e8488SAndroid Build Coastguard Worker return BC_STATUS_SUCCESS;
239*5a6e8488SAndroid Build Coastguard Worker }
240*5a6e8488SAndroid Build Coastguard Worker
241*5a6e8488SAndroid Build Coastguard Worker BcStatus
bc_read_line(BcVec * vec,const char * prompt)242*5a6e8488SAndroid Build Coastguard Worker bc_read_line(BcVec* vec, const char* prompt)
243*5a6e8488SAndroid Build Coastguard Worker {
244*5a6e8488SAndroid Build Coastguard Worker BcStatus s;
245*5a6e8488SAndroid Build Coastguard Worker
246*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_HISTORY
247*5a6e8488SAndroid Build Coastguard Worker // Get a line from either history or manual reading.
248*5a6e8488SAndroid Build Coastguard Worker if (BC_TTY && !vm->history.badTerm)
249*5a6e8488SAndroid Build Coastguard Worker {
250*5a6e8488SAndroid Build Coastguard Worker s = bc_history_line(&vm->history, vec, prompt);
251*5a6e8488SAndroid Build Coastguard Worker }
252*5a6e8488SAndroid Build Coastguard Worker else s = bc_read_chars(vec, prompt);
253*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_HISTORY
254*5a6e8488SAndroid Build Coastguard Worker s = bc_read_chars(vec, prompt);
255*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_HISTORY
256*5a6e8488SAndroid Build Coastguard Worker
257*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(bc_read_binary(vec->v, vec->len - 1)))
258*5a6e8488SAndroid Build Coastguard Worker {
259*5a6e8488SAndroid Build Coastguard Worker bc_verr(BC_ERR_FATAL_BIN_FILE, bc_program_stdin_name);
260*5a6e8488SAndroid Build Coastguard Worker }
261*5a6e8488SAndroid Build Coastguard Worker
262*5a6e8488SAndroid Build Coastguard Worker return s;
263*5a6e8488SAndroid Build Coastguard Worker }
264*5a6e8488SAndroid Build Coastguard Worker
265*5a6e8488SAndroid Build Coastguard Worker char*
bc_read_file(const char * path)266*5a6e8488SAndroid Build Coastguard Worker bc_read_file(const char* path)
267*5a6e8488SAndroid Build Coastguard Worker {
268*5a6e8488SAndroid Build Coastguard Worker BcErr e = BC_ERR_FATAL_IO_ERR;
269*5a6e8488SAndroid Build Coastguard Worker size_t size, to_read;
270*5a6e8488SAndroid Build Coastguard Worker struct stat pstat;
271*5a6e8488SAndroid Build Coastguard Worker int fd;
272*5a6e8488SAndroid Build Coastguard Worker char* buf;
273*5a6e8488SAndroid Build Coastguard Worker char* buf2;
274*5a6e8488SAndroid Build Coastguard Worker
275*5a6e8488SAndroid Build Coastguard Worker // This has been copied to gen/strgen.c. Make sure to change that if this
276*5a6e8488SAndroid Build Coastguard Worker // changes.
277*5a6e8488SAndroid Build Coastguard Worker
278*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
279*5a6e8488SAndroid Build Coastguard Worker
280*5a6e8488SAndroid Build Coastguard Worker assert(path != NULL);
281*5a6e8488SAndroid Build Coastguard Worker
282*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
283*5a6e8488SAndroid Build Coastguard Worker // Need this to quiet MSan.
284*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
285*5a6e8488SAndroid Build Coastguard Worker memset(&pstat, 0, sizeof(struct stat));
286*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
287*5a6e8488SAndroid Build Coastguard Worker
288*5a6e8488SAndroid Build Coastguard Worker fd = bc_read_open(path, O_RDONLY);
289*5a6e8488SAndroid Build Coastguard Worker
290*5a6e8488SAndroid Build Coastguard Worker // If we can't read a file, we just barf.
291*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(fd < 0)) bc_verr(BC_ERR_FATAL_FILE_ERR, path);
292*5a6e8488SAndroid Build Coastguard Worker
293*5a6e8488SAndroid Build Coastguard Worker // The reason we call fstat is to eliminate TOCTOU race conditions. This
294*5a6e8488SAndroid Build Coastguard Worker // way, we have an open file, so it's not going anywhere.
295*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(fstat(fd, &pstat) == -1)) goto malloc_err;
296*5a6e8488SAndroid Build Coastguard Worker
297*5a6e8488SAndroid Build Coastguard Worker // Make sure it's not a directory.
298*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(S_ISDIR(pstat.st_mode)))
299*5a6e8488SAndroid Build Coastguard Worker {
300*5a6e8488SAndroid Build Coastguard Worker e = BC_ERR_FATAL_PATH_DIR;
301*5a6e8488SAndroid Build Coastguard Worker goto malloc_err;
302*5a6e8488SAndroid Build Coastguard Worker }
303*5a6e8488SAndroid Build Coastguard Worker
304*5a6e8488SAndroid Build Coastguard Worker // Get the size of the file and allocate that much.
305*5a6e8488SAndroid Build Coastguard Worker size = (size_t) pstat.st_size;
306*5a6e8488SAndroid Build Coastguard Worker buf = bc_vm_malloc(size + 1);
307*5a6e8488SAndroid Build Coastguard Worker buf2 = buf;
308*5a6e8488SAndroid Build Coastguard Worker to_read = size;
309*5a6e8488SAndroid Build Coastguard Worker
310*5a6e8488SAndroid Build Coastguard Worker do
311*5a6e8488SAndroid Build Coastguard Worker {
312*5a6e8488SAndroid Build Coastguard Worker // Read the file. We just bail if a signal interrupts. This is so that
313*5a6e8488SAndroid Build Coastguard Worker // users can interrupt the reading of big files if they want.
314*5a6e8488SAndroid Build Coastguard Worker ssize_t r = read(fd, buf2, to_read);
315*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(r < 0)) goto read_err;
316*5a6e8488SAndroid Build Coastguard Worker to_read -= (size_t) r;
317*5a6e8488SAndroid Build Coastguard Worker buf2 += (size_t) r;
318*5a6e8488SAndroid Build Coastguard Worker }
319*5a6e8488SAndroid Build Coastguard Worker while (to_read);
320*5a6e8488SAndroid Build Coastguard Worker
321*5a6e8488SAndroid Build Coastguard Worker // Got to have a nul byte.
322*5a6e8488SAndroid Build Coastguard Worker buf[size] = '\0';
323*5a6e8488SAndroid Build Coastguard Worker
324*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(bc_read_binary(buf, size)))
325*5a6e8488SAndroid Build Coastguard Worker {
326*5a6e8488SAndroid Build Coastguard Worker e = BC_ERR_FATAL_BIN_FILE;
327*5a6e8488SAndroid Build Coastguard Worker goto read_err;
328*5a6e8488SAndroid Build Coastguard Worker }
329*5a6e8488SAndroid Build Coastguard Worker
330*5a6e8488SAndroid Build Coastguard Worker close(fd);
331*5a6e8488SAndroid Build Coastguard Worker
332*5a6e8488SAndroid Build Coastguard Worker return buf;
333*5a6e8488SAndroid Build Coastguard Worker
334*5a6e8488SAndroid Build Coastguard Worker read_err:
335*5a6e8488SAndroid Build Coastguard Worker free(buf);
336*5a6e8488SAndroid Build Coastguard Worker malloc_err:
337*5a6e8488SAndroid Build Coastguard Worker close(fd);
338*5a6e8488SAndroid Build Coastguard Worker bc_verr(e, path);
339*5a6e8488SAndroid Build Coastguard Worker return NULL;
340*5a6e8488SAndroid Build Coastguard Worker }
341