Coverage Report

Created: 2026-01-10 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/in.c
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
}