xref: /aosp_15_r20/external/bc/src/read.c (revision 5a6e848804d15c18a0125914844ee4eb0bda4fcf)
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