summaryrefslogtreecommitdiff
path: root/lib/x1000-installer/src/xf_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x1000-installer/src/xf_stream.c')
-rw-r--r--lib/x1000-installer/src/xf_stream.c214
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
33static off_t file_stream_get_size(struct xf_stream* s)
34{
35 return filesize(s->data);
36}
37
38static ssize_t file_stream_read(struct xf_stream* s, void* buf, size_t len)
39{
40 return read(s->data, buf, len);
41}
42
43static 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
48static int file_stream_close(struct xf_stream* s)
49{
50 return close(s->data);
51}
52
53static 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
60int 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
71static 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
77static 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
88static 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
99static 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
113static 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
120int 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
136int 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
151int 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}