1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
13 *
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * ----------------------------------------------------------------------- */
27
28 /*
29 * floadfile.c
30 *
31 * Read the contents of a data file into a malloc'd buffer
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <sys/stat.h>
40
41 #include <syslinux/loadfile.h>
42
43 #define INCREMENTAL_CHUNK 1024*1024
44
floadfile(FILE * f,void ** ptr,size_t * len,const void * prefix,size_t prefix_len)45 int floadfile(FILE * f, void **ptr, size_t * len, const void *prefix,
46 size_t prefix_len)
47 {
48 struct stat st;
49 void *data, *dp;
50 size_t alen, clen, rlen, xlen;
51
52 clen = alen = 0;
53 data = NULL;
54
55 if (fstat(fileno(f), &st))
56 goto err;
57
58 if (!S_ISREG(st.st_mode)) {
59 /* Not a regular file, we can't assume we know the file size */
60 if (prefix_len) {
61 clen = alen = prefix_len;
62 data = malloc(prefix_len);
63 if (!data)
64 goto err;
65
66 memcpy(data, prefix, prefix_len);
67 }
68
69 do {
70 alen += INCREMENTAL_CHUNK;
71 dp = realloc(data, alen);
72 if (!dp)
73 goto err;
74 data = dp;
75
76 rlen = fread((char *)data + clen, 1, alen - clen, f);
77 clen += rlen;
78 } while (clen == alen);
79
80 *len = clen;
81 xlen = (clen + LOADFILE_ZERO_PAD - 1) & ~(LOADFILE_ZERO_PAD - 1);
82 dp = realloc(data, xlen);
83 if (dp)
84 data = dp;
85 *ptr = data;
86 } else {
87 *len = clen = st.st_size + prefix_len - ftell(f);
88 xlen = (clen + LOADFILE_ZERO_PAD - 1) & ~(LOADFILE_ZERO_PAD - 1);
89
90 *ptr = data = malloc(xlen);
91 if (!data)
92 return -1;
93
94 memcpy(data, prefix, prefix_len);
95
96 if ((off_t) fread((char *)data + prefix_len, 1, clen - prefix_len, f)
97 != clen - prefix_len)
98 goto err;
99 }
100
101 memset((char *)data + clen, 0, xlen - clen);
102 return 0;
103
104 err:
105 if (data)
106 free(data);
107 return -1;
108 }
109