1/*
2 * Copyright (c) 2003-2004,2006-2010,2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * readline.c
24 */
25
26#include "readline.h"
27
28#include <errno.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35/* Inspects a file's existence and size.  Returns a file handle or -1 on failure */
36int inspect_file_and_size(const char* name, off_t *out_off_end) {
37
38    int fd, result;
39    off_t off_end;
40
41    do {
42        fd = open(name, O_RDONLY, 0);
43    } while (fd == -1 && errno == EINTR);
44
45    if (fd == -1)
46    {
47        fprintf(stderr, "open %s: %s", name, strerror(errno));
48        result = -1;
49        goto loser;
50    }
51
52    off_end = lseek(fd, 0, SEEK_END);
53    if (off_end == -1)
54    {
55        fprintf(stderr, "lseek %s, SEEK_END: %s", name, strerror(errno));
56        result = -1;
57        goto loser;
58    }
59
60    if (off_end > (unsigned)SIZE_MAX) {
61        fprintf(stderr, "file %s too large %llu bytes", name, off_end);
62        result = -1;
63        goto loser;
64    }
65
66    if (out_off_end) {
67        *out_off_end = off_end;
68    }
69
70    return fd;
71
72loser:
73    return result;
74}
75
76
77/* Read a line from stdin into buffer as a null terminated string.  If buffer is
78 non NULL use at most buffer_size bytes and return a pointer to buffer.  Otherwise
79 return a newly malloced buffer.
80 if EOF is read this function returns NULL.  */
81char *
82readline(char *buffer, int buffer_size)
83{
84	int ix = 0, bytes_malloced = 0;
85
86	if (!buffer)
87	{
88		bytes_malloced = 64;
89		buffer = (char *)malloc(bytes_malloced);
90		buffer_size = bytes_malloced;
91	}
92
93	for (;;++ix)
94	{
95		int ch;
96
97		if (ix == buffer_size - 1)
98		{
99			if (!bytes_malloced)
100				break;
101			bytes_malloced += bytes_malloced;
102			buffer = (char *)realloc(buffer, bytes_malloced);
103			buffer_size = bytes_malloced;
104		}
105
106		ch = getchar();
107		if (ch == EOF)
108		{
109			if (bytes_malloced)
110				free(buffer);
111			return NULL;
112		}
113		if (ch == '\n')
114			break;
115		buffer[ix] = ch;
116	}
117
118	/* 0 terminate buffer. */
119	buffer[ix] = '\0';
120
121	return buffer;
122}
123
124/* Read the file name into buffer.  On return buffer contains a newly
125 malloced buffer or length buffer_size. Return 0 on success and -1 on failure.  */
126int
127read_file(const char *name, uint8_t **outData, size_t *outLength)
128{
129	int fd, result;
130	char *buffer = NULL;
131	off_t off_end;
132	ssize_t bytes_read;
133	size_t length;
134
135	if( (fd = inspect_file_and_size(name, &off_end)) == -1 ){
136        result = -1;
137        goto loser;
138    }
139
140	length = (size_t)off_end;
141	buffer = malloc(length);
142
143	do {
144		bytes_read = pread(fd, buffer, length, 0);
145	} while (bytes_read == -1 && errno == EINTR);
146
147	if (bytes_read == -1)
148	{
149		fprintf(stderr, "pread %s: %s", name, strerror(errno));
150		result = -1;
151		goto loser;
152	}
153	if (bytes_read != (ssize_t)length)
154	{
155		fprintf(stderr, "read %s: only read %zu of %zu bytes", name, bytes_read, length);
156		result = -1;
157		goto loser;
158	}
159
160	do {
161		result = close(fd);
162	} while (result == -1 && errno == EINTR);
163
164	if (result == -1)
165	{
166		fprintf(stderr, "close %s: %s", name, strerror(errno));
167		goto loser;
168	}
169
170	*outData = (uint8_t *)buffer;
171	*outLength = length;
172
173	return result;
174
175loser:
176	if (buffer)
177		free(buffer);
178
179	return result;
180}
181
182CFDataRef copyFileContents(const char *path) {
183    CFMutableDataRef data = NULL;
184    int fd = open(path, O_RDONLY, 0666);
185    if (fd == -1) {
186        fprintf(stderr, "open %s: %s", path, strerror(errno));
187        goto badFile;
188    }
189
190    off_t fsize = lseek(fd, 0, SEEK_END);
191    if (fsize == (off_t)-1) {
192        fprintf(stderr, "lseek %s, 0, SEEK_END: %s", path, strerror(errno));
193        goto badFile;
194    }
195
196	if (fsize > (off_t)INT32_MAX) {
197		fprintf(stderr, "file %s too large %llu bytes", path, fsize);
198		goto badFile;
199	}
200
201    data = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)fsize);
202    CFDataSetLength(data, (CFIndex)fsize);
203    void *buf = CFDataGetMutableBytePtr(data);
204    off_t total_read = 0;
205    while (total_read < fsize) {
206        ssize_t bytes_read;
207
208        bytes_read = pread(fd, buf, (size_t)(fsize - total_read), total_read);
209        if (bytes_read == -1) {
210            fprintf(stderr, "read %s: %s", path, strerror(errno));
211            goto badFile;
212        }
213        if (bytes_read == 0) {
214            fprintf(stderr, "read %s: unexpected end of file", path);
215            goto badFile;
216        }
217        total_read += bytes_read;
218    }
219
220    if (close(fd) == -1) {
221        fprintf(stderr, "close %s: %s", path, strerror(errno));
222        /* Failure to close the file isn't fatal. */
223    }
224
225    return data;
226badFile:
227    if (fd != -1) {
228        if (close(fd) == -1) {
229            fprintf(stderr, "close %s: %s", path, strerror(errno));
230        }
231    }
232    if (data)
233        CFRelease(data);
234    return NULL;
235}
236
237
238bool writeFileContents(const char *path, CFDataRef data) {
239    int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
240    if (fd == -1) {
241        fprintf(stderr, "open %s: %s", path, strerror(errno));
242        goto badFile;
243    }
244
245    const void *buf = CFDataGetBytePtr(data);
246    off_t fsize = CFDataGetLength(data);
247
248    off_t total_write = 0;
249    while (total_write < fsize) {
250        ssize_t bytes_write;
251
252        bytes_write = pwrite(fd, buf, (size_t)(fsize - total_write), total_write);
253        if (bytes_write == -1) {
254            fprintf(stderr, "write %s: %s", path, strerror(errno));
255            goto badFile;
256        }
257        if (bytes_write == 0) {
258            fprintf(stderr, "write %s: unexpected end of file", path);
259            goto badFile;
260        }
261        total_write += bytes_write;
262    }
263
264    if (close(fd) == -1) {
265        fprintf(stderr, "close %s: %s", path, strerror(errno));
266        /* Failure to close the file isn't fatal. */
267    }
268
269    return true;
270badFile:
271    if (fd != -1) {
272        if (close(fd) == -1) {
273            fprintf(stderr, "close %s: %s", path, strerror(errno));
274        }
275    }
276    if (data)
277        CFRelease(data);
278    return false;
279}
280