1/*
2 * Copyright (c) 2003-2004,2006-2010 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/* Read a line from stdin into buffer as a null terminated string.  If buffer is
36   non NULL use at most buffer_size bytes and return a pointer to buffer.  Otherwise
37   return a newly malloced buffer.
38   if EOF is read this function returns NULL.  */
39char *
40readline(char *buffer, int buffer_size)
41{
42	int ix = 0, bytes_malloced = 0;
43
44	if (!buffer)
45	{
46		bytes_malloced = 64;
47		buffer = (char *)malloc(bytes_malloced);
48		buffer_size = bytes_malloced;
49	}
50
51	for (;;++ix)
52	{
53		int ch;
54
55		if (ix == buffer_size - 1)
56		{
57			if (!bytes_malloced)
58				break;
59			bytes_malloced += bytes_malloced;
60			buffer = (char *)realloc(buffer, bytes_malloced);
61			buffer_size = bytes_malloced;
62		}
63
64		ch = getchar();
65		if (ch == EOF)
66		{
67			if (bytes_malloced)
68				free(buffer);
69			return NULL;
70		}
71		if (ch == '\n')
72			break;
73		buffer[ix] = ch;
74	}
75
76	/* 0 terminate buffer. */
77	buffer[ix] = '\0';
78
79	return buffer;
80}
81
82/* Read the file name into buffer.  On return buffer contains a newly
83   malloced buffer or length buffer_size. Return 0 on success and -1 on failure.  */
84int
85read_file(const char *name, uint8_t **outData, size_t *outLength)
86{
87	int fd, result;
88	char *buffer = NULL;
89	off_t off_end;
90	ssize_t bytes_read;
91	size_t length;
92
93	do {
94		fd = open(name, O_RDONLY, 0);
95	} while (fd == -1 && errno == EINTR);
96
97	if (fd == -1)
98	{
99		fprintf(stderr, "open %s: %s", name, strerror(errno));
100		result = -1;
101		goto loser;
102	}
103
104	off_end = lseek(fd, 0, SEEK_END);
105	if (off_end == -1)
106	{
107		fprintf(stderr, "lseek %s, SEEK_END: %s", name, strerror(errno));
108		result = -1;
109		goto loser;
110	}
111
112	if (off_end > (off_t)SIZE_MAX) {
113		fprintf(stderr, "file %s too large %llu bytes", name, off_end);
114		result = -1;
115		goto loser;
116	}
117
118	length = (size_t)off_end;
119	buffer = malloc(length);
120
121	do {
122		bytes_read = pread(fd, buffer, length, 0);
123	} while (bytes_read == -1 && errno == EINTR);
124
125	if (bytes_read == -1)
126	{
127		fprintf(stderr, "pread %s: %s", name, strerror(errno));
128		result = -1;
129		goto loser;
130	}
131	if (bytes_read != (ssize_t)length)
132	{
133		fprintf(stderr, "read %s: only read %zu of %zu bytes", name, bytes_read, length);
134		result = -1;
135		goto loser;
136	}
137
138	do {
139		result = close(fd);
140	} while (result == -1 && errno == EINTR);
141
142	if (result == -1)
143	{
144		fprintf(stderr, "close %s: %s", name, strerror(errno));
145		goto loser;
146	}
147
148	*outData = (uint8_t *)buffer;
149	*outLength = length;
150
151	return result;
152
153loser:
154	if (buffer)
155		free(buffer);
156
157	return result;
158}
159
160CFDataRef copyFileContents(const char *path) {
161    CFMutableDataRef data = NULL;
162    int fd = open(path, O_RDONLY, 0666);
163    if (fd == -1) {
164        fprintf(stderr, "open %s: %s", path, strerror(errno));
165        goto badFile;
166    }
167
168    off_t fsize = lseek(fd, 0, SEEK_END);
169    if (fsize == (off_t)-1) {
170        fprintf(stderr, "lseek %s, 0, SEEK_END: %s", path, strerror(errno));
171        goto badFile;
172    }
173
174	if (fsize > (off_t)INT32_MAX) {
175		fprintf(stderr, "file %s too large %llu bytes", path, fsize);
176		goto badFile;
177	}
178
179    data = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)fsize);
180    CFDataSetLength(data, (CFIndex)fsize);
181    void *buf = CFDataGetMutableBytePtr(data);
182    off_t total_read = 0;
183    while (total_read < fsize) {
184        ssize_t bytes_read;
185
186        bytes_read = pread(fd, buf, (size_t)(fsize - total_read), total_read);
187        if (bytes_read == -1) {
188            fprintf(stderr, "read %s: %s", path, strerror(errno));
189            goto badFile;
190        }
191        if (bytes_read == 0) {
192            fprintf(stderr, "read %s: unexpected end of file", path);
193            goto badFile;
194        }
195        total_read += bytes_read;
196    }
197
198    if (close(fd) == -1) {
199        fprintf(stderr, "close %s: %s", path, strerror(errno));
200        /* Failure to close the file isn't fatal. */
201    }
202
203    return data;
204badFile:
205    if (fd != -1) {
206        if (close(fd) == -1) {
207            fprintf(stderr, "close %s: %s", path, strerror(errno));
208        }
209    }
210    if (data)
211        CFRelease(data);
212    return NULL;
213}
214
215
216bool writeFileContents(const char *path, CFDataRef data) {
217    int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
218    if (fd == -1) {
219        fprintf(stderr, "open %s: %s", path, strerror(errno));
220        goto badFile;
221    }
222
223    const void *buf = CFDataGetBytePtr(data);
224    off_t fsize = CFDataGetLength(data);
225
226    off_t total_write = 0;
227    while (total_write < fsize) {
228        ssize_t bytes_write;
229
230        bytes_write = pwrite(fd, buf, (size_t)(fsize - total_write), total_write);
231        if (bytes_write == -1) {
232            fprintf(stderr, "write %s: %s", path, strerror(errno));
233            goto badFile;
234        }
235        if (bytes_write == 0) {
236            fprintf(stderr, "write %s: unexpected end of file", path);
237            goto badFile;
238        }
239        total_write += bytes_write;
240    }
241
242    if (close(fd) == -1) {
243        fprintf(stderr, "close %s: %s", path, strerror(errno));
244        /* Failure to close the file isn't fatal. */
245    }
246
247    return true;
248badFile:
249    if (fd != -1) {
250        if (close(fd) == -1) {
251            fprintf(stderr, "close %s: %s", path, strerror(errno));
252        }
253    }
254    if (data)
255        CFRelease(data);
256    return false;
257}
258