Line | Count | Source |
1 | | /** |
2 | | * @file in.c |
3 | | * @author Radek Krejci <rkrejci@cesnet.cz> |
4 | | * @brief libyang input functions. |
5 | | * |
6 | | * Copyright (c) 2015 - 2020 CESNET, z.s.p.o. |
7 | | * |
8 | | * This source code is licensed under BSD 3-Clause License (the "License"). |
9 | | * You may not use this file except in compliance with the License. |
10 | | * You may obtain a copy of the License at |
11 | | * |
12 | | * https://opensource.org/licenses/BSD-3-Clause |
13 | | */ |
14 | | |
15 | | #define _GNU_SOURCE |
16 | | |
17 | | #include "in.h" |
18 | | #include "in_internal.h" |
19 | | |
20 | | #include <errno.h> |
21 | | #include <fcntl.h> |
22 | | #include <limits.h> |
23 | | #include <stdint.h> |
24 | | #include <stdio.h> |
25 | | #include <stdlib.h> |
26 | | #include <string.h> |
27 | | #include <unistd.h> |
28 | | |
29 | | #include "compat.h" |
30 | | #include "dict.h" |
31 | | #include "log.h" |
32 | | #include "ly_common.h" |
33 | | #include "parser_data.h" |
34 | | #include "parser_internal.h" |
35 | | #include "set.h" |
36 | | #include "tree.h" |
37 | | #include "tree_data.h" |
38 | | #include "tree_data_internal.h" |
39 | | #include "tree_schema.h" |
40 | | #include "tree_schema_internal.h" |
41 | | |
42 | | LIBYANG_API_DEF LY_IN_TYPE |
43 | | ly_in_type(const struct ly_in *in) |
44 | 0 | { |
45 | 0 | LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR); |
46 | 0 | return in->type; |
47 | 0 | } |
48 | | |
49 | | LIBYANG_API_DEF LY_ERR |
50 | | ly_in_reset(struct ly_in *in) |
51 | 0 | { |
52 | 0 | LY_CHECK_ARG_RET(NULL, in, LY_EINVAL); |
53 | |
|
54 | 0 | in->current = in->func_start = in->start; |
55 | 0 | in->line = 1; |
56 | 0 | return LY_SUCCESS; |
57 | 0 | } |
58 | | |
59 | | LIBYANG_API_DEF LY_ERR |
60 | | ly_in_new_fd(int fd, struct ly_in **in) |
61 | 0 | { |
62 | 0 | size_t length; |
63 | 0 | char *addr; |
64 | |
|
65 | 0 | LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL); |
66 | |
|
67 | 0 | LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr)); |
68 | 0 | if (!addr) { |
69 | 0 | LOGERR(NULL, LY_EINVAL, "Empty input file."); |
70 | 0 | return LY_EINVAL; |
71 | 0 | } |
72 | | |
73 | 0 | *in = calloc(1, sizeof **in); |
74 | 0 | LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM); |
75 | |
|
76 | 0 | (*in)->type = LY_IN_FD; |
77 | 0 | (*in)->method.fd = fd; |
78 | 0 | (*in)->current = (*in)->start = (*in)->func_start = addr; |
79 | 0 | (*in)->line = 1; |
80 | 0 | (*in)->length = length; |
81 | |
|
82 | 0 | return LY_SUCCESS; |
83 | 0 | } |
84 | | |
85 | | LIBYANG_API_DEF int |
86 | | ly_in_fd(struct ly_in *in, int fd) |
87 | 0 | { |
88 | 0 | int prev_fd; |
89 | 0 | size_t length; |
90 | 0 | const char *addr; |
91 | |
|
92 | 0 | LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1); |
93 | |
|
94 | 0 | prev_fd = in->method.fd; |
95 | |
|
96 | 0 | if (fd != -1) { |
97 | 0 | LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1); |
98 | 0 | if (!addr) { |
99 | 0 | LOGERR(NULL, LY_EINVAL, "Empty input file."); |
100 | 0 | return -1; |
101 | 0 | } |
102 | | |
103 | 0 | ly_munmap((char *)in->start, in->length); |
104 | |
|
105 | 0 | in->method.fd = fd; |
106 | 0 | in->current = in->start = addr; |
107 | 0 | in->line = 1; |
108 | 0 | in->length = length; |
109 | 0 | } |
110 | | |
111 | 0 | return prev_fd; |
112 | 0 | } |
113 | | |
114 | | LIBYANG_API_DEF LY_ERR |
115 | | ly_in_new_file(FILE *f, struct ly_in **in) |
116 | 0 | { |
117 | 0 | LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL); |
118 | |
|
119 | 0 | LY_CHECK_RET(ly_in_new_fd(fileno(f), in)); |
120 | | |
121 | | /* convert the LY_IN_FD input handler into the LY_IN_FILE */ |
122 | 0 | (*in)->type = LY_IN_FILE; |
123 | 0 | (*in)->method.f = f; |
124 | |
|
125 | 0 | return LY_SUCCESS; |
126 | 0 | } |
127 | | |
128 | | LIBYANG_API_DEF FILE * |
129 | | ly_in_file(struct ly_in *in, FILE *f) |
130 | 0 | { |
131 | 0 | FILE *prev_f; |
132 | |
|
133 | 0 | LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL); |
134 | |
|
135 | 0 | prev_f = in->method.f; |
136 | |
|
137 | 0 | if (f) { |
138 | | /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */ |
139 | 0 | in->type = LY_IN_FD; |
140 | 0 | in->method.fd = fileno(prev_f); |
141 | 0 | if (ly_in_fd(in, fileno(f)) == -1) { |
142 | 0 | in->type = LY_IN_FILE; |
143 | 0 | in->method.f = prev_f; |
144 | 0 | return NULL; |
145 | 0 | } |
146 | | |
147 | | /* if success, convert the result back */ |
148 | 0 | in->type = LY_IN_FILE; |
149 | 0 | in->method.f = f; |
150 | 0 | } |
151 | | |
152 | 0 | return prev_f; |
153 | 0 | } |
154 | | |
155 | | LIBYANG_API_DEF LY_ERR |
156 | | ly_in_new_memory(const char *str, struct ly_in **in) |
157 | 19.4k | { |
158 | 19.4k | LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL); |
159 | | |
160 | 19.4k | *in = calloc(1, sizeof **in); |
161 | 19.4k | LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM); |
162 | | |
163 | 19.4k | (*in)->type = LY_IN_MEMORY; |
164 | 19.4k | (*in)->start = (*in)->current = (*in)->func_start = str; |
165 | 19.4k | (*in)->line = 1; |
166 | | |
167 | 19.4k | return LY_SUCCESS; |
168 | 19.4k | } |
169 | | |
170 | | LIBYANG_API_DEF const char * |
171 | | ly_in_memory(struct ly_in *in, const char *str) |
172 | 43.6k | { |
173 | 43.6k | const char *data; |
174 | | |
175 | 43.6k | LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL); |
176 | | |
177 | 43.6k | data = in->current; |
178 | | |
179 | 43.6k | if (str) { |
180 | 43.6k | in->start = in->current = str; |
181 | 43.6k | in->line = 1; |
182 | 43.6k | } |
183 | | |
184 | 43.6k | return data; |
185 | 43.6k | } |
186 | | |
187 | | LIBYANG_API_DEF LY_ERR |
188 | | ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in) |
189 | 0 | { |
190 | 0 | LY_ERR ret; |
191 | 0 | char *fp; |
192 | 0 | int fd; |
193 | |
|
194 | 0 | LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL); |
195 | |
|
196 | 0 | if (len) { |
197 | 0 | fp = strndup(filepath, len); |
198 | 0 | } else { |
199 | 0 | fp = strdup(filepath); |
200 | 0 | } |
201 | |
|
202 | 0 | fd = open(fp, O_RDONLY); |
203 | 0 | LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), |
204 | 0 | LY_ESYS); |
205 | |
|
206 | 0 | LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret); |
207 | | |
208 | | /* convert the LY_IN_FD input handler into the LY_IN_FILE */ |
209 | 0 | (*in)->type = LY_IN_FILEPATH; |
210 | 0 | (*in)->method.fpath.fd = fd; |
211 | 0 | (*in)->method.fpath.filepath = fp; |
212 | |
|
213 | 0 | return LY_SUCCESS; |
214 | 0 | } |
215 | | |
216 | | LIBYANG_API_DEF const char * |
217 | | ly_in_filepath(struct ly_in *in, const char *filepath, size_t len) |
218 | 0 | { |
219 | 0 | int fd, prev_fd; |
220 | 0 | char *fp = NULL; |
221 | |
|
222 | 0 | LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1)); |
223 | |
|
224 | 0 | if (!filepath) { |
225 | 0 | return in->method.fpath.filepath; |
226 | 0 | } |
227 | | |
228 | 0 | if (len) { |
229 | 0 | fp = strndup(filepath, len); |
230 | 0 | } else { |
231 | 0 | fp = strdup(filepath); |
232 | 0 | } |
233 | | |
234 | | /* replace filepath */ |
235 | 0 | fd = open(fp, O_RDONLY); |
236 | 0 | LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL); |
237 | | |
238 | | /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */ |
239 | 0 | in->type = LY_IN_FD; |
240 | 0 | prev_fd = ly_in_fd(in, fd); |
241 | 0 | LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL); |
242 | | |
243 | | /* and convert the result back */ |
244 | 0 | in->type = LY_IN_FILEPATH; |
245 | 0 | close(prev_fd); |
246 | 0 | free(in->method.fpath.filepath); |
247 | 0 | in->method.fpath.fd = fd; |
248 | 0 | in->method.fpath.filepath = fp; |
249 | |
|
250 | 0 | return NULL; |
251 | 0 | } |
252 | | |
253 | | LIBYANG_API_DEF size_t |
254 | | ly_in_parsed(const struct ly_in *in) |
255 | 0 | { |
256 | 0 | LY_CHECK_ARG_RET(NULL, in, 0); |
257 | |
|
258 | 0 | return in->current - in->func_start; |
259 | 0 | } |
260 | | |
261 | | LIBYANG_API_DEF void |
262 | | ly_in_free(struct ly_in *in, ly_bool destroy) |
263 | 19.4k | { |
264 | 19.4k | if (!in) { |
265 | 0 | return; |
266 | 19.4k | } else if (in->type == LY_IN_ERROR) { |
267 | 0 | LOGINT(NULL); |
268 | 0 | return; |
269 | 0 | } |
270 | | |
271 | 19.4k | if (destroy) { |
272 | 0 | if (in->type == LY_IN_MEMORY) { |
273 | 0 | free((char *)in->start); |
274 | 0 | } else { |
275 | 0 | ly_munmap((char *)in->start, in->length); |
276 | |
|
277 | 0 | if (in->type == LY_IN_FILE) { |
278 | 0 | fclose(in->method.f); |
279 | 0 | } else { |
280 | 0 | close(in->method.fd); |
281 | |
|
282 | 0 | if (in->type == LY_IN_FILEPATH) { |
283 | 0 | free(in->method.fpath.filepath); |
284 | 0 | } |
285 | 0 | } |
286 | 0 | } |
287 | 19.4k | } else if (in->type != LY_IN_MEMORY) { |
288 | 0 | ly_munmap((char *)in->start, in->length); |
289 | |
|
290 | 0 | if (in->type == LY_IN_FILEPATH) { |
291 | 0 | close(in->method.fpath.fd); |
292 | 0 | free(in->method.fpath.filepath); |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 19.4k | free(in); |
297 | 19.4k | } |
298 | | |
299 | | LIBYANG_API_DEF LY_ERR |
300 | | ly_in_read(struct ly_in *in, void *buf, size_t count) |
301 | 264M | { |
302 | 264M | LY_CHECK_ARG_RET(NULL, in, buf, LY_EINVAL); |
303 | | |
304 | 264M | if (in->length && (in->length - (in->current - in->start) < count)) { |
305 | | /* EOF */ |
306 | 0 | return LY_EDENIED; |
307 | 0 | } |
308 | | |
309 | 264M | if (count && in->peeked) { |
310 | | /* read the peeked byte */ |
311 | 0 | memcpy(buf, &in->peek, 1); |
312 | 0 | buf = (char *)buf + 1; |
313 | 0 | --count; |
314 | | |
315 | | /* clear the peek */ |
316 | 0 | in->peeked = 0; |
317 | 0 | } |
318 | | |
319 | 264M | if (count) { |
320 | 264M | memcpy(buf, in->current, count); |
321 | 264M | } |
322 | 264M | in->current += count; |
323 | 264M | return LY_SUCCESS; |
324 | 264M | } |
325 | | |
326 | | LIBYANG_API_DEF LY_ERR |
327 | | ly_in_peek(struct ly_in *in, uint8_t *peek) |
328 | 0 | { |
329 | 0 | LY_CHECK_ARG_RET(NULL, in, peek, LY_EINVAL); |
330 | |
|
331 | 0 | if (in->length && (in->length - (in->current - in->start) < 1)) { |
332 | | /* EOF */ |
333 | 0 | return LY_EDENIED; |
334 | 0 | } else if (in->peeked) { |
335 | | /* unsupported */ |
336 | 0 | return LY_ENOT; |
337 | 0 | } |
338 | | |
339 | 0 | memcpy(&in->peek, in->current, 1); |
340 | 0 | in->current += 1; |
341 | 0 | in->peeked = 1; |
342 | |
|
343 | 0 | *peek = in->peek; |
344 | 0 | return LY_SUCCESS; |
345 | 0 | } |
346 | | |
347 | | LIBYANG_API_DEF LY_ERR |
348 | | ly_in_skip(struct ly_in *in, size_t count) |
349 | 211M | { |
350 | 211M | LY_CHECK_ARG_RET(NULL, in, LY_EINVAL); |
351 | | |
352 | 211M | if (in->length && (in->length - (in->current - in->start) < count)) { |
353 | | /* EOF */ |
354 | 0 | return LY_EDENIED; |
355 | 0 | } |
356 | | |
357 | 211M | if (count && in->peeked) { |
358 | | /* skip the peeked byte */ |
359 | 0 | --count; |
360 | 0 | in->peeked = 0; |
361 | 0 | } |
362 | | |
363 | 211M | in->current += count; |
364 | 211M | return LY_SUCCESS; |
365 | 211M | } |