diff options
Diffstat (limited to 'lib/x1000-installer/src/xf_stream.c')
-rw-r--r-- | lib/x1000-installer/src/xf_stream.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/lib/x1000-installer/src/xf_stream.c b/lib/x1000-installer/src/xf_stream.c new file mode 100644 index 0000000000..5a0f86123c --- /dev/null +++ b/lib/x1000-installer/src/xf_stream.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "xf_stream.h" | ||
23 | #include "xf_error.h" | ||
24 | #include "file.h" | ||
25 | #include <stdbool.h> | ||
26 | #include <string.h> | ||
27 | #include <ctype.h> | ||
28 | |||
29 | /* | ||
30 | * File streams | ||
31 | */ | ||
32 | |||
33 | static off_t file_stream_get_size(struct xf_stream* s) | ||
34 | { | ||
35 | return filesize(s->data); | ||
36 | } | ||
37 | |||
38 | static ssize_t file_stream_read(struct xf_stream* s, void* buf, size_t len) | ||
39 | { | ||
40 | return read(s->data, buf, len); | ||
41 | } | ||
42 | |||
43 | static ssize_t file_stream_write(struct xf_stream* s, const void* buf, size_t len) | ||
44 | { | ||
45 | return write(s->data, buf, len); | ||
46 | } | ||
47 | |||
48 | static int file_stream_close(struct xf_stream* s) | ||
49 | { | ||
50 | return close(s->data); | ||
51 | } | ||
52 | |||
53 | static const struct xf_stream_ops file_stream_ops = { | ||
54 | .xget_size = file_stream_get_size, | ||
55 | .xread = file_stream_read, | ||
56 | .xwrite = file_stream_write, | ||
57 | .xclose = file_stream_close, | ||
58 | }; | ||
59 | |||
60 | int xf_open_file(const char* file, int flags, struct xf_stream* s) | ||
61 | { | ||
62 | s->data = open(file, flags, 0666); | ||
63 | s->ops = &file_stream_ops; | ||
64 | return (s->data >= 0) ? 0 : -1; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Tar streams | ||
69 | */ | ||
70 | |||
71 | static off_t tar_stream_get_size(struct xf_stream* s) | ||
72 | { | ||
73 | mtar_t* mtar = (mtar_t*)s->data; | ||
74 | return mtar_get_header(mtar)->size; | ||
75 | } | ||
76 | |||
77 | static ssize_t tar_stream_read(struct xf_stream* s, void* buffer, size_t count) | ||
78 | { | ||
79 | mtar_t* mtar = (mtar_t*)s->data; | ||
80 | |||
81 | int ret = mtar_read_data(mtar, buffer, count); | ||
82 | if(ret < 0) | ||
83 | return -1; | ||
84 | |||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | static ssize_t tar_stream_write(struct xf_stream* s, const void* buffer, size_t count) | ||
89 | { | ||
90 | mtar_t* mtar = (mtar_t*)s->data; | ||
91 | |||
92 | int ret = mtar_write_data(mtar, buffer, count); | ||
93 | if(ret < 0) | ||
94 | return -1; | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static int tar_stream_close(struct xf_stream* s) | ||
100 | { | ||
101 | mtar_t* mtar = (mtar_t*)s->data; | ||
102 | |||
103 | if(mtar_access_mode(mtar) == MTAR_WRITE) { | ||
104 | if(mtar_update_file_size(mtar) != MTAR_ESUCCESS) | ||
105 | return -1; | ||
106 | if(mtar_end_data(mtar) != MTAR_ESUCCESS) | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static const struct xf_stream_ops tar_stream_ops = { | ||
114 | .xget_size = tar_stream_get_size, | ||
115 | .xread = tar_stream_read, | ||
116 | .xwrite = tar_stream_write, | ||
117 | .xclose = tar_stream_close, | ||
118 | }; | ||
119 | |||
120 | int xf_open_tar(mtar_t* mtar, const char* file, struct xf_stream* s) | ||
121 | { | ||
122 | int err = mtar_find(mtar, file); | ||
123 | if(err != MTAR_ESUCCESS) | ||
124 | return err; | ||
125 | |||
126 | /* must only read normal files */ | ||
127 | const mtar_header_t* h = mtar_get_header(mtar); | ||
128 | if(h->type != 0 && h->type != MTAR_TREG) | ||
129 | return MTAR_EFAILURE; | ||
130 | |||
131 | s->data = (intptr_t)mtar; | ||
132 | s->ops = &tar_stream_ops; | ||
133 | return MTAR_ESUCCESS; | ||
134 | } | ||
135 | |||
136 | int xf_create_tar(mtar_t* mtar, const char* file, size_t size, struct xf_stream* s) | ||
137 | { | ||
138 | int err = mtar_write_file_header(mtar, file, size); | ||
139 | if(err) | ||
140 | return err; | ||
141 | |||
142 | s->data = (intptr_t)mtar; | ||
143 | s->ops = &tar_stream_ops; | ||
144 | return MTAR_ESUCCESS; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Utility functions | ||
149 | */ | ||
150 | |||
151 | int xf_stream_read_lines(struct xf_stream* s, char* buf, size_t bufsz, | ||
152 | int(*callback)(int n, char* buf, void* arg), void* arg) | ||
153 | { | ||
154 | char* startp, *endp; | ||
155 | ssize_t bytes_read; | ||
156 | int rc; | ||
157 | |||
158 | int n = 0; | ||
159 | size_t pos = 0; | ||
160 | bool at_eof = false; | ||
161 | |||
162 | while(!at_eof) { | ||
163 | bytes_read = xf_stream_read(s, &buf[pos], bufsz - pos - 1); | ||
164 | if(bytes_read < 0) | ||
165 | return XF_E_IO; | ||
166 | |||
167 | /* short read is end of file */ | ||
168 | if((size_t)bytes_read < bufsz - pos - 1) | ||
169 | at_eof = true; | ||
170 | |||
171 | pos += bytes_read; | ||
172 | buf[pos] = '\0'; | ||
173 | |||
174 | startp = endp = buf; | ||
175 | while(endp != &buf[pos]) { | ||
176 | endp = strchr(startp, '\n'); | ||
177 | if(endp) { | ||
178 | *endp = '\0'; | ||
179 | } else { | ||
180 | if(!at_eof) { | ||
181 | if(startp == buf) | ||
182 | return XF_E_LINE_TOO_LONG; | ||
183 | else | ||
184 | break; /* read ahead to look for newline */ | ||
185 | } else { | ||
186 | endp = &buf[pos]; /* treat EOF as a newline */ | ||
187 | } | ||
188 | } | ||
189 | |||
190 | /* skip whitespace */ | ||
191 | while(*startp && isspace(*startp)) | ||
192 | ++startp; | ||
193 | |||
194 | /* ignore blank lines and comment lines */ | ||
195 | if(*startp == '#' || *startp == '\0') { | ||
196 | startp = endp + 1; | ||
197 | continue; | ||
198 | } | ||
199 | |||
200 | rc = callback(n++, startp, arg); | ||
201 | if(rc != 0) | ||
202 | return rc; | ||
203 | |||
204 | startp = endp + 1; | ||
205 | } | ||
206 | |||
207 | if(startp <= &buf[pos]) { | ||
208 | memmove(buf, startp, &buf[pos] - startp); | ||
209 | pos = &buf[pos] - startp; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | return 0; | ||
214 | } | ||