• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-mcu / 1510560513

24 Oct 2024 12:04PM UTC coverage: 2.013% (+0.007%) from 2.006%
1510560513

push

gitlab-ci

lluiscampos
chore: Move variable declaration so that its always initialized at END

Clears `clang` warning:
```
.../mender-api.c:250:9: error: variable 'provides' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
  250 |     if (NULL == cJSON_AddStringToObject(json_provides, "device_type", mender_api_config.device_type)) {
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/llvm-18/lib/clang/18/include/__stddef_null.h:26:14: note: expanded from macro 'NULL'
   26 | #define NULL ((void*)0)
      |              ^
.../mender-api.c:302:35: note: uninitialized use occurs here
  302 |     mender_utils_free_linked_list(provides);
      |                                   ^~~~~~~~
.../mender-api.c:250:5: note: remove the 'if' if its condition is always false
  250 |     if (NULL == cJSON_AddStringToObject(json_provides, "device_type", mender_api_config.device_type)) {
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  251 |         mender_log_error("Unable to allocate memory");
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  252 |         goto END;
      |         ~~~~~~~~~
  253 |     }
      |     ~

```

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

31 of 1540 relevant lines covered (2.01%)

0.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/core/src/mender-artifact.c
1
/**
2
 * @file      mender-artifact.c
3
 * @brief     Mender artifact parser
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 * Copyright Northern.tech AS
7
 *
8
 * Licensed under the Apache License, Version 2.0 (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
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
#include <errno.h>
22

23
#include "mender-artifact.h"
24
#include "mender-deployment-data.h"
25
#include "mender-log.h"
26

27
/**
28
 * @brief Device type key
29
 */
30
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
31
#define MENDER_ARTIFACT_DEVICE_TYPE_KEY "device_type"
32
#endif
33

34
/**
35
 * @brief TAR file header
36
 */
37
typedef struct {
38
    char name[100];
39
    char mode[8];
40
    char uid[8];
41
    char gid[8];
42
    char size[12];
43
    char mtime[12];
44
    char chksum[8];
45
    char typeflag;
46
    char linkname[100];
47
    char magic[6];
48
    char version[2];
49
    char uname[32];
50
    char gname[32];
51
    char devmajor[8];
52
    char devminor[8];
53
    char prefix[155];
54
} mender_artifact_tar_header_t;
55

56
/**
57
 * @brief Supported artifact format and version
58
 */
59
#define MENDER_ARTIFACT_SUPPORTED_FORMAT  "mender"
60
#define MENDER_ARTIFACT_SUPPORTED_VERSION 3
61

62
/**
63
 * @brief Parse header of TAR file
64
 * @param ctx Artifact context
65
 * @return MENDER_DONE if the data have been parsed, MENDER_OK if there is not enough data to parse, error code if an error occurred
66
 */
67
static mender_err_t artifact_parse_tar_header(mender_artifact_ctx_t *ctx);
68

69
/**
70
 * @brief Read version file of the artifact
71
 * @param ctx Artifact context
72
 * @return MENDER_DONE if the data have been parsed and version verified, MENDER_OK if there is not enough data to parse, error code if an error occurred
73
 */
74
static mender_err_t artifact_read_version(mender_artifact_ctx_t *ctx);
75

76
/**
77
 * @brief Read header-info file of the artifact
78
 * @param ctx Artifact context
79
 * @return MENDER_DONE if the data have been parsed and payloads retrieved, MENDER_OK if there is not enough data to parse, error code if an error occurred
80
 */
81
static mender_err_t artifact_read_header_info(mender_artifact_ctx_t *ctx);
82

83
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
84
/**
85
 * @brief Read manifest file of the artifact
86
 * @param ctx Artifact context
87
 * @return MENDER_DONE if the data have been parsed and checksums retrieved, MENDER_OK if there is not enough data to parse, error code if an error occurred
88
 */
89
static mender_err_t artifact_read_manifest(mender_artifact_ctx_t *ctx);
90

91
/**
92
 * @brief Read type-info file of the artifact
93
 * @param ctx Artifact context
94
 * @return MENDER_DONE if the data have been parsed and payloads retrieved, MENDER_OK if there is not enough data to parse, error code if an error occurred
95
 */
96
static mender_err_t artifact_read_type_info(mender_artifact_ctx_t *ctx);
97

98
/**
99
 * @brief Parse provides/depends from JSON object
100
 * @param json_provides_depends JSON object to parse
101
 * @param provides_depends Pointer to the list of provides or depends
102
 * @return MENDER_SUCCESS if the function succeeds, MENDER_FAIL otherwise
103
 */
104
static mender_err_t artifact_parse_provides_depends(cJSON *json_provides_depends, mender_key_value_list_t **provides_depends);
105
#endif
106

107
/**
108
 * @brief Read meta-data file of the artifact
109
 * @param ctx Artifact context
110
 * @return MENDER_DONE if the data have been parsed and payloads retrieved, MENDER_OK if there is not enough data to parse, error code if an error occurred
111
 */
112
static mender_err_t artifact_read_meta_data(mender_artifact_ctx_t *ctx);
113

114
/**
115
 * @brief Read data file of the artifact
116
 * @param ctx Artifact context
117
 * @param dl_data Download data for the artifact
118
 * @return MENDER_DONE if the data have been parsed and payloads retrieved, MENDER_OK if there is not enough data to parse, error code if an error occurred
119
 */
120
static mender_err_t artifact_read_data(mender_artifact_ctx_t *ctx, mender_artifact_download_data_t *dl_data);
121

122
/**
123
 * @brief Process chunk of artifact data
124
 */
125
static mender_err_t process_artifact_data_callback(const char                      *type,
126
                                                   const cJSON                     *meta_data,
127
                                                   const char                      *filename,
128
                                                   size_t                           size,
129
                                                   void                            *data,
130
                                                   size_t                           index,
131
                                                   size_t                           length,
132
                                                   mender_artifact_download_data_t *dl_data);
133

134
/**
135
 * @brief Drop content of the current file of the artifact
136
 * @param ctx Artifact context
137
 * @return MENDER_DONE if the data have been parsed and dropped, MENDER_OK if there is not enough data to parse, error code if an error occurred
138
 */
139
static mender_err_t artifact_drop_file(mender_artifact_ctx_t *ctx);
140

141
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
142
static mender_err_t artifact_read_header(mender_artifact_ctx_t *ctx);
143
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
144

145
/**
146
 * @brief Shift data after parsing
147
 * @param ctx Artifact context
148
 * @param length Length of data to shift
149
 * @return MENDER_OK if the function succeeds, error code otherwise
150
 */
151
static mender_err_t artifact_shift_data(mender_artifact_ctx_t *ctx, size_t length);
152

153
/**
154
 * @brief Compute length rounded up to increment (usually the block size)
155
 * @param length Length
156
 * @param incr Increment
157
 * @return Rounded length
158
 */
159
static size_t artifact_round_up(size_t length, size_t incr);
160

161
/**
162
 * @brief Artifact context
163
 */
164
static mender_artifact_ctx_t *artifact_ctx = NULL;
165

166
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
167
/**
168
 * @brief Get checksum entry for a file in the context
169
 * @param ctx The mender artifact context
170
 * @param filename The name of the file in the artifact
171
 * @return The checksum entry or NULL on error.
172
 * @note Since other files may be parsed before the manifest file, we need to
173
 *       create these entries in a lazy fashion.
174
 */
175
static mender_artifact_checksum_t *
176
artifact_checksum_get_or_create(mender_artifact_ctx_t *ctx, const char *filename) {
177
    assert(NULL != ctx);
178
    assert(NULL != filename);
179

180
    /* See if we already have an entry for this file */
181
    mender_artifact_checksum_t *checksum;
182
    for (checksum = ctx->artifact_info.checksums; NULL != checksum; checksum = checksum->next) {
183
        if (StringEqual(checksum->filename, filename)) {
184
            break;
185
        }
186
    }
187

188
    if (NULL == checksum) {
189
        /* Create new if entry not found */
190
        checksum = (mender_artifact_checksum_t *)calloc(1, sizeof(mender_artifact_checksum_t));
191
        if (NULL == checksum) {
192
            mender_log_error("Unable to allocate memory");
193
            return NULL;
194
        }
195
        checksum->filename = strdup(filename);
196
        if (NULL == checksum->filename) {
197
            mender_log_error("Unable to allocate memory");
198
            free(checksum);
199
            return NULL;
200
        }
201
        checksum->next               = ctx->artifact_info.checksums;
202
        ctx->artifact_info.checksums = checksum;
203

204
        /* Start SHA-256 checksum computation */
205
        if (MENDER_OK != mender_sha256_begin(&(checksum->context))) {
206
            mender_log_error("Failed to start checksum for file '%s'", filename);
207
            return NULL;
208
        }
209
    }
210

211
    return checksum;
212
}
213
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
214

215
mender_err_t
216
mender_artifact_check_integrity(mender_artifact_ctx_t *ctx) {
×
217
    assert(NULL != ctx);
×
218

219
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
220
    for (mender_artifact_checksum_t *checksum = ctx->artifact_info.checksums; NULL != checksum; checksum = checksum->next) {
221
        unsigned char computed[MENDER_DIGEST_BUFFER_SIZE];
222
        mender_log_debug("Checking integrity for artifact file '%s'", checksum->filename);
223

224
        if (MENDER_OK != mender_sha256_finish(checksum->context, computed)) {
225
            mender_log_error("Failed to finish checksum for file '%s'", checksum->filename);
226
            checksum->context = NULL;
227
            return MENDER_FAIL;
228
        }
229
        checksum->context = NULL;
230

231
        if (0 != memcmp(checksum->manifest, computed, MENDER_DIGEST_BUFFER_SIZE)) {
232
            mender_log_error("Computed checksum for file '%s' does not match manifest", checksum->filename);
233
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_DBG
234
            /* Log the mismatching checksums for debugging */
235
            char checksum_str[(MENDER_DIGEST_BUFFER_SIZE * 2) + 1];
236

237
            for (int i = 0; i < MENDER_DIGEST_BUFFER_SIZE; i++) {
238
                if (2 != snprintf(checksum_str + (i * 2), 3, "%02hhx", checksum->manifest[i])) {
239
                    break;
240
                }
241
            }
242
            mender_log_debug("%s: '%s' (manifest)", checksum->filename, checksum_str);
243

244
            for (int i = 0; i < MENDER_DIGEST_BUFFER_SIZE; i++) {
245
                if (2 != snprintf(checksum_str + (i * 2), 3, "%02hhx", computed[i])) {
246
                    break;
247
                }
248
            }
249
            mender_log_debug("%s: '%s' (computed)", checksum->filename, checksum_str);
250
#endif /* CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_DBG */
251
            return MENDER_FAIL;
252
        }
253
    }
254
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
255
    return MENDER_OK;
×
256
}
257

258
mender_artifact_ctx_t *
259
mender_artifact_create_ctx(size_t buf_size) {
×
260

261
    mender_artifact_ctx_t *ctx;
262

263
    /* Create new context */
264
    if (NULL == (ctx = (mender_artifact_ctx_t *)calloc(1, sizeof(mender_artifact_ctx_t)))) {
×
265
        mender_log_error("Unable to allocate memory for artifact context");
×
266
        return NULL;
×
267
    }
268
    if (NULL == (ctx->input.data = malloc(buf_size))) {
×
269
        mender_log_error("Unable to allocate memory for artifact context buffer");
×
270
        free(ctx);
×
271
        return NULL;
×
272
    }
273
    ctx->input.size      = buf_size;
×
274
    ctx->input.orig_size = buf_size;
×
275

276
    /* Save context */
277
    artifact_ctx = ctx;
×
278

279
    return ctx;
×
280
}
281

282
mender_err_t
283
mender_artifact_get_ctx(mender_artifact_ctx_t **ctx) {
×
284

285
    assert(NULL != ctx);
×
286

287
    if (NULL == artifact_ctx) {
×
288
        return MENDER_FAIL;
×
289
    }
290

291
    *ctx = artifact_ctx;
×
292
    return MENDER_OK;
×
293
}
294

295
static bool
296
is_compressed(const char *filename) {
×
297

298
    static const char *compression_suffixes[] = { ".gz", ".xz", ".zst", NULL };
299

300
    for (size_t i = 0; NULL != compression_suffixes[i]; i++) {
×
301
        if (mender_utils_strendwith(filename, compression_suffixes[i])) {
×
302
            return true;
×
303
        }
304
    }
305

306
    return false;
×
307
}
308

309
mender_err_t
310
mender_artifact_process_data(mender_artifact_ctx_t *ctx, void *input_data, size_t input_length, mender_artifact_download_data_t *dl_data) {
×
311

312
    assert(NULL != ctx);
×
313
    mender_err_t ret = MENDER_OK;
×
314
    void        *tmp;
315
    size_t       new_size;
316
    size_t       expected_required;
317

318
    /* Copy data to the end of the internal buffer */
319
    if ((NULL != input_data) && (0 != input_length)) {
×
320
        if ((ctx->input.length + input_length) > ctx->input.size) {
×
321
            new_size = ctx->input.length + input_length;
×
322
            /* data/ files are processed per block for which the original size of the buffer should
323
               be enough, but metadata is processed as whole files so there we expect we will need
324
               more. */
325
            if (mender_utils_strbeginwith(ctx->file.name, "data/")) {
×
326
                expected_required = ctx->input.orig_size;
×
327
            } else {
328
                expected_required = artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE) + MENDER_ARTIFACT_STREAM_BLOCK_SIZE;
×
329
            }
330
            if (new_size > expected_required) {
331
                mender_log_debug("Reallocating artifact context buffer to %zd [SHOULD NOT BE HAPPENING!]", new_size);
332
            }
333
            /* Let's try to get what we expect we will need anyway and if we don't get that much,
334
               let's get the minimum required now, leaving us with a chance to get more later. */
335
            if (NULL == (tmp = realloc(ctx->input.data, MAX(new_size, expected_required)))) {
×
336
                if (NULL == (tmp = realloc(ctx->input.data, new_size))) {
×
337
                    /* Unable to allocate memory */
338
                    return MENDER_FAIL;
×
339
                }
340
                ctx->input.size = new_size;
×
341
            } else {
342
                ctx->input.size = MAX(new_size, expected_required);
×
343
            }
344
            ctx->input.data = tmp;
×
345
        }
346
        memcpy((void *)(((uint8_t *)ctx->input.data) + ctx->input.length), input_data, input_length);
×
347
        ctx->input.length += input_length;
×
348
    }
349

350
    /* Parse data */
351
    do {
352

353
        /* We do not support compressed artifacts */
354
        if (is_compressed(ctx->file.name)) {
×
355
            mender_log_error("Artifact compression is not supported");
×
356
            return MENDER_FAIL;
×
357
        }
358

359
        /* Treatment depending of the stream state */
360
        if (MENDER_ARTIFACT_STREAM_STATE_PARSING_HEADER == ctx->stream_state) {
×
361

362
            /* Parse TAR header */
363
            ret = artifact_parse_tar_header(ctx);
×
364

365
        } else if (MENDER_ARTIFACT_STREAM_STATE_PARSING_DATA == ctx->stream_state) {
×
366

367
            /* Treatment depending of the file name */
368
            if (StringEqual(ctx->file.name, "version")) {
×
369

370
                /* Validate artifact version */
371
                ret = artifact_read_version(ctx);
×
372

373
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
374
            } else if (StringEqual(ctx->file.name, "manifest")) {
375

376
                /* Read manifest file */
377
                ret = artifact_read_manifest(ctx);
378
#endif
379
            } else if (StringEqual(ctx->file.name, "header.tar/header-info")) {
×
380

381
                /* Read header-info file */
382
                ret = artifact_read_header_info(ctx);
×
383

384
            } else if ((true == mender_utils_strbeginwith(ctx->file.name, "header.tar/headers"))
×
385
                       && (true == mender_utils_strendwith(ctx->file.name, "meta-data"))) {
×
386

387
                /* Read meta-data file */
388
                ret = artifact_read_meta_data(ctx);
×
389

390
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
391
            } else if (mender_utils_strbeginwith(ctx->file.name, "header.tar/headers") && mender_utils_strendwith(ctx->file.name, "type-info")) {
392

393
                /* Read type-info file */
394
                ret = artifact_read_type_info(ctx);
395
#endif
396
            } else if (true == mender_utils_strbeginwith(ctx->file.name, "data")) {
×
397

398
                /* Read data */
399
                ret = artifact_read_data(ctx, dl_data);
×
400

401
            } else if (false == mender_utils_strendwith(ctx->file.name, ".tar")) {
×
402

403
                /* Drop data, file is not relevant */
404
                ret = artifact_drop_file(ctx);
×
405
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
406
            } else if (StringEqual(ctx->file.name, "header.tar")) {
407
                ret = artifact_read_header(ctx);
408
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
409
            } else {
410

411
                /* Nothing to do */
412
                ret = MENDER_DONE;
×
413
            }
414

415
            /* Check if file have been parsed and treatment done */
416
            if (MENDER_DONE == ret) {
×
417

418
                /* Remove the previous file name */
419
                char *substring = mender_utils_strrstr(ctx->file.name, ".tar");
×
420
                if (NULL != substring) {
×
421
                    *(substring + strlen(".tar")) = '\0';
×
422
                } else {
423
                    FREE_AND_NULL(ctx->file.name);
×
424
                }
425
                ctx->file.size  = 0;
×
426
                ctx->file.index = 0;
×
427

428
                /* Update the stream state machine */
429
                ctx->stream_state = MENDER_ARTIFACT_STREAM_STATE_PARSING_HEADER;
×
430
            }
431
        }
432
    } while (MENDER_DONE == ret);
×
433

434
    return ret;
×
435
}
436

437
void
438
mender_artifact_release_ctx(mender_artifact_ctx_t *ctx) {
×
439

440
    /* Release memory */
441
    if (NULL != ctx) {
×
442
        free(ctx->input.data);
×
443
        if (NULL != ctx->payloads.values) {
×
444
            for (size_t index = 0; index < ctx->payloads.size; index++) {
×
445
                free(ctx->payloads.values[index].type);
×
446
                cJSON_Delete(ctx->payloads.values[index].meta_data);
×
447

448
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
449
                mender_utils_free_linked_list(ctx->payloads.values[index].provides);
450
                mender_utils_free_linked_list(ctx->payloads.values[index].depends);
451
                for (size_t i = 0; i < ctx->payloads.values[index].clears_provides_size; i++) {
452
                    free(ctx->payloads.values[index].clears_provides[i]);
453
                }
454
                free(ctx->payloads.values[index].clears_provides);
455
#endif
456
            }
457
            free(ctx->payloads.values);
×
458
        }
459
        free(ctx->file.name);
×
460
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
461
        mender_utils_free_linked_list(ctx->artifact_info.provides);
462
        mender_utils_free_linked_list(ctx->artifact_info.depends);
463
        for (mender_artifact_checksum_t *checksum = ctx->artifact_info.checksums; NULL != checksum; checksum = checksum->next) {
464
            free(checksum->filename);
465
            mender_sha256_finish(checksum->context, NULL);
466
        }
467
#endif
468
        free(ctx);
×
469
    }
470
}
×
471

472
static mender_err_t
473
artifact_parse_tar_header(mender_artifact_ctx_t *ctx) {
×
474

475
    assert(NULL != ctx);
×
476
    char *tmp;
477

478
    /* Check if enough data are received (at least one block) */
479
    if ((NULL == ctx->input.data) || (ctx->input.length < MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
480
        return MENDER_OK;
×
481
    }
482

483
    /* Cast block to TAR header structure */
484
    mender_artifact_tar_header_t *tar_header = (mender_artifact_tar_header_t *)ctx->input.data;
×
485

486
    /* Check if file name is provided, else the end of the current TAR file is reached */
487
    if ('\0' == tar_header->name[0]) {
×
488

489
        /* Check if enough data are received (at least 2 blocks) */
490
        if (ctx->input.length < 2 * MENDER_ARTIFACT_STREAM_BLOCK_SIZE) {
×
491
            return MENDER_OK;
×
492
        }
493

494
        /* Remove the TAR file name */
495
        if (NULL != ctx->file.name) {
×
496
            char *substring = mender_utils_strrstr(ctx->file.name, ".tar");
×
497
            if (NULL != substring) {
×
498
                *substring = '\0';
×
499
                substring  = mender_utils_strrstr(ctx->file.name, ".tar");
×
500
                if (NULL != substring) {
×
501
                    *(substring + strlen(".tar")) = '\0';
×
502
                } else {
503
                    FREE_AND_NULL(ctx->file.name);
×
504
                }
505
            } else {
506
                FREE_AND_NULL(ctx->file.name);
×
507
            }
508
        }
509

510
        /* Shift data in the buffer */
511
        if (MENDER_OK != artifact_shift_data(ctx, 2 * MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
512
            mender_log_error("Unable to shift input data");
×
513
            return MENDER_FAIL;
×
514
        }
515

516
        return MENDER_DONE;
×
517
    }
518

519
    /* Check magic */
520
    if (strncmp(tar_header->magic, "ustar", strlen("ustar"))) {
×
521
        /* Invalid magic */
522
        mender_log_error("Invalid magic");
×
523
        return MENDER_FAIL;
×
524
    }
525

526
    /* Compute the new file name */
527
    if (NULL != ctx->file.name) {
×
528
        size_t str_length = strlen(ctx->file.name) + strlen("/") + strlen(tar_header->name) + 1;
×
529
        if (NULL == (tmp = (char *)malloc(str_length))) {
×
530
            mender_log_error("Unable to allocate memory");
×
531
            return MENDER_FAIL;
×
532
        }
533
        snprintf(tmp, str_length, "%s/%s", ctx->file.name, tar_header->name);
×
534
        free(ctx->file.name);
×
535
    } else {
536
        if (NULL == (tmp = strdup(tar_header->name))) {
×
537
            mender_log_error("Unable to allocate memory");
×
538
            return MENDER_FAIL;
×
539
        }
540
    }
541
    ctx->file.name = tmp;
×
542

543
    /* Retrieve file size */
544
    assert(sizeof(size_t) >= sizeof(unsigned long));
545
    char *end_ptr;
546
    errno = 0; /* to distinguish between success/failure */
×
547

548
    ctx->file.size = strtoul(tar_header->size, &end_ptr, 8);
×
549
    if ((end_ptr == tar_header->size) /* no conversion */
×
550
        || (0 != errno)) {            /* out of range (for unsigned long) */
×
551
        mender_log_error("Unable to retrieve file size");
×
552
        return MENDER_FAIL;
×
553
    }
554

555
    ctx->file.index = 0;
×
556

557
    /* Shift data in the buffer */
558
    if (MENDER_OK != artifact_shift_data(ctx, MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
559
        mender_log_error("Unable to shift input data");
×
560
        return MENDER_FAIL;
×
561
    }
562

563
    /* Update the stream state machine */
564
    ctx->stream_state = MENDER_ARTIFACT_STREAM_STATE_PARSING_DATA;
×
565

566
    return MENDER_DONE;
×
567
}
568

569
static mender_err_t
570
artifact_read_version(mender_artifact_ctx_t *ctx) {
×
571

572
    assert(NULL != ctx);
×
573
    cJSON       *object = NULL;
×
574
    mender_err_t ret    = MENDER_DONE;
×
575

576
    /* Check if all data have been received */
577
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
578
        return MENDER_OK;
×
579
    }
580

581
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
582
    /* Get checksum entry (create one if needed) */
583
    mender_artifact_checksum_t *checksum;
584
    if (NULL == (checksum = artifact_checksum_get_or_create(ctx, "version"))) {
585
        /* Error already logged */
586
        return MENDER_FAIL;
587
    }
588

589
    /* Update SHA-256 checksum */
590
    if (MENDER_OK != mender_sha256_update(checksum->context, ctx->input.data, ctx->file.size)) {
591
        mender_log_error("Failed to update update checksum");
592
        return MENDER_FAIL;
593
    }
594
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
595

596
    /* Check version file */
597
    if (NULL == (object = cJSON_ParseWithLength(ctx->input.data, ctx->file.size))) {
×
598
        mender_log_error("Unable to allocate memory");
×
599
        return MENDER_FAIL;
×
600
    }
601
    cJSON *json_format = cJSON_GetObjectItemCaseSensitive(object, "format");
×
602
    if (true == cJSON_IsString(json_format)) {
×
603
        if (!StringEqual(cJSON_GetStringValue(json_format), MENDER_ARTIFACT_SUPPORTED_FORMAT)) {
×
604
            mender_log_error("Invalid version format");
×
605
            ret = MENDER_FAIL;
×
606
            goto END;
×
607
        }
608
    } else {
609
        mender_log_error("Invalid version file");
×
610
        ret = MENDER_FAIL;
×
611
        goto END;
×
612
    }
613
    cJSON *json_version = cJSON_GetObjectItemCaseSensitive(object, "version");
×
614
    if (true == cJSON_IsNumber(json_version)) {
×
615
        if (MENDER_ARTIFACT_SUPPORTED_VERSION != (int)cJSON_GetNumberValue(json_version)) {
×
616
            mender_log_error("Invalid version value");
×
617
            ret = MENDER_FAIL;
×
618
            goto END;
×
619
        }
620
    } else {
621
        mender_log_error("Invalid version file");
×
622
        ret = MENDER_FAIL;
×
623
        goto END;
×
624
    }
625
    mender_log_debug("Artifact has valid version");
626

627
    /* Shift data in the buffer */
628
    if (MENDER_OK != artifact_shift_data(ctx, artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
629
        mender_log_error("Unable to shift input data");
×
630
        ret = MENDER_FAIL;
×
631
        goto END;
×
632
    }
633

634
END:
×
635

636
    /* Release memory */
637
    cJSON_Delete(object);
×
638

639
    return ret;
×
640
}
641

642
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
643
mender_err_t
644
mender_artifact_get_device_type(mender_artifact_ctx_t *ctx, const char **device_type) {
645

646
    assert(NULL != ctx);
647
    assert(NULL != device_type);
648

649
    mender_key_value_list_t *item = ctx->artifact_info.depends;
650
    while (NULL != item) {
651
        if (NULL != item->key) {
652
            if (StringEqual(MENDER_ARTIFACT_DEVICE_TYPE_KEY, item->key)) {
653
                *device_type = item->value;
654
                return MENDER_OK;
655
            }
656
        }
657
        item = item->next;
658
    }
659
    return MENDER_FAIL;
660
}
661

662
static mender_err_t
663
artifact_read_manifest(mender_artifact_ctx_t *ctx) {
664

665
    assert(NULL != ctx);
666

667
    /* Check if all data has been received */
668
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
669
        return MENDER_OK;
670
    }
671

672
    /*  The expected format matches the output of sha256sum: sum and the name of the file separated by two spaces
673
        1d0b820130ae028ce8a79b7e217fe505a765ac394718e795d454941487c53d32  data/0000/update.ext4
674
        4d480539cdb23a4aee6330ff80673a5af92b7793eb1c57c4694532f96383b619  header.tar.gz
675
        52c76ab66947278a897c2a6df8b4d77badfa343fec7ba3b2983c2ecbbb041a35  version
676
    */
677

678
    /* Read data line by line */
679
    char *line = ctx->input.data;
680
    char *end  = line + ctx->input.length;
681
    while (line < end) {
682
        char *next = strchr(line, '\n');
683
        if (NULL == next) {
684
            break;
685
        }
686
        *next = '\0';
687

688
        /* Process line */
689
        char *separator = strstr(line, "  ");
690
        if (NULL == separator) {
691
            mender_log_error("Invalid manifest file");
692
            return MENDER_FAIL;
693
        }
694
        *separator = '\0';
695

696
        const char *checksum_str = line;
697
        const char *filename     = separator + 2;
698

699
        /* Useful when debugging artifact integrity check failures */
700
        mender_log_debug("%s  %s", checksum_str, filename);
701

702
        /* Make sure digest is of expected length (two hex per byte) */
703
        if ((MENDER_DIGEST_BUFFER_SIZE * 2) != strlen(checksum_str)) {
704
            mender_log_error("Bad checksum '%s' in manifest for file '%s'", checksum_str, filename);
705
            return MENDER_FAIL;
706
        }
707

708
        /* Get checksum entry for the file (creates one if not found) */
709
        mender_artifact_checksum_t *checksum;
710
        if (NULL == (checksum = artifact_checksum_get_or_create(ctx, filename))) {
711
            /* Error already logged */
712
            return MENDER_FAIL;
713
        }
714

715
        /* Populate with manifest checksum */
716
        if (!mender_utils_hexdump_to_bytes(checksum_str, checksum->manifest, MENDER_DIGEST_BUFFER_SIZE)) {
717
            mender_log_error("Bad checksum '%s' in manifest for file '%s'", checksum_str, filename);
718
            return MENDER_FAIL;
719
        }
720

721
        ///* Move to the next line */
722
        line = next + 1;
723
    }
724

725
    /* Shift data in the buffer */
726
    if (MENDER_OK != artifact_shift_data(ctx, artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
727
        mender_log_error("Unable to shift input data");
728
        return MENDER_FAIL;
729
    }
730

731
    return MENDER_DONE;
732
}
733

734
static mender_err_t
735
artifact_parse_provides_depends(cJSON *json_provides_depends, mender_key_value_list_t **provides_depends) {
736

737
    assert(NULL != json_provides_depends);
738
    assert(NULL != provides_depends);
739

740
    /* Create linked-list from json object */
741
    /* The elements can either be a string or an array of strings */
742
    cJSON *json_element = NULL;
743
    cJSON_ArrayForEach(json_element, json_provides_depends) {
744
        if (cJSON_IsString(json_element)) {
745
            if (MENDER_OK != mender_utils_create_key_value_node(json_element->string, json_element->valuestring, provides_depends)) {
746
                mender_log_error("Unable to create linked list node for string element");
747
                goto ERROR;
748
            }
749
        } else if (cJSON_IsArray(json_element)) {
750
            cJSON *json_element_value = NULL;
751
            cJSON_ArrayForEach(json_element_value, json_element) {
752
                if (MENDER_OK != mender_utils_create_key_value_node(json_element->string, json_element_value->valuestring, provides_depends)) {
753
                    mender_log_error("Unable to create linked list node for array element");
754
                    goto ERROR;
755
                }
756
            }
757
        } else {
758
            mender_log_error("Invalid header-info file element type");
759
            goto ERROR;
760
        }
761
    }
762

763
    return MENDER_OK;
764

765
ERROR:
766
    /* Free linked list in case of error */
767
    mender_utils_free_linked_list(*provides_depends);
768
    return MENDER_FAIL;
769
}
770
#endif
771

772
static mender_err_t
773
artifact_read_header_info(mender_artifact_ctx_t *ctx) {
×
774

775
    assert(NULL != ctx);
×
776
    cJSON       *object = NULL;
×
777
    mender_err_t ret    = MENDER_DONE;
×
778

779
    /* Check if all data have been received */
780
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
781
        return MENDER_OK;
×
782
    }
783

784
    /* Read header-info */
785
    if (NULL == (object = cJSON_ParseWithLength(ctx->input.data, ctx->file.size))) {
×
786
        mender_log_error("Unable to allocate memory");
×
787
        return MENDER_FAIL;
×
788
    }
789
    cJSON *json_payloads = cJSON_GetObjectItemCaseSensitive(object, "payloads");
×
790
    if (true == cJSON_IsArray(json_payloads)) {
×
791
        ctx->payloads.size = cJSON_GetArraySize(json_payloads);
×
792
        if (NULL == (ctx->payloads.values = (mender_artifact_payload_t *)calloc(ctx->payloads.size, sizeof(mender_artifact_payload_t)))) {
×
793
            mender_log_error("Unable to allocate memory");
×
794
            ret = MENDER_FAIL;
×
795
            goto END;
×
796
        }
797
        size_t index        = 0;
×
798
        cJSON *json_payload = NULL;
×
799
        cJSON_ArrayForEach(json_payload, json_payloads) {
×
800
            if (true == cJSON_IsObject(json_payload)) {
×
801
                cJSON *json_payload_type = cJSON_GetObjectItemCaseSensitive(json_payload, "type");
×
802
                if (cJSON_IsString(json_payload_type)) {
×
803
                    if (NULL == (ctx->payloads.values[index].type = strdup(cJSON_GetStringValue(json_payload_type)))) {
×
804
                        mender_log_error("Unable to allocate memory");
×
805
                        ret = MENDER_FAIL;
×
806
                        goto END;
×
807
                    }
808
                } else {
809
                    mender_log_error("Invalid header-info file");
×
810
                    ret = MENDER_FAIL;
×
811
                    goto END;
×
812
                }
813
            } else {
814
                mender_log_error("Invalid header-info file");
×
815
                ret = MENDER_FAIL;
×
816
                goto END;
×
817
            }
818
            index++;
×
819
        }
820

821
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
822
        cJSON *json_provides = cJSON_GetObjectItemCaseSensitive(object, "artifact_provides");
823
        if (cJSON_IsObject(json_provides)) {
824
            if (MENDER_FAIL == artifact_parse_provides_depends(json_provides, &(ctx->artifact_info.provides))) {
825
                mender_log_error("Unable to parse artifact_provides");
826
                ret = MENDER_FAIL;
827
                goto END;
828
            }
829
        }
830

831
        cJSON *json_depends = cJSON_GetObjectItemCaseSensitive(object, "artifact_depends");
832
        if (cJSON_IsObject(json_depends)) {
833
            if (MENDER_FAIL == artifact_parse_provides_depends(json_depends, &(ctx->artifact_info.depends))) {
834
                mender_log_error("Unable to parse artifact_depends");
835
                ret = MENDER_FAIL;
836
                goto END;
837
            }
838
        }
839
#endif
840

841
    } else {
842
        mender_log_error("Invalid header-info file");
×
843
        ret = MENDER_FAIL;
×
844
        goto END;
×
845
    }
846

847
    /* Shift data in the buffer */
848
    if (MENDER_OK != artifact_shift_data(ctx, artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
849
        mender_log_error("Unable to shift input data");
×
850
        ret = MENDER_FAIL;
×
851
        goto END;
×
852
    }
853

854
END:
×
855

856
    /* Release memory */
857
    cJSON_Delete(object);
×
858

859
    return ret;
×
860
}
861

862
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
863
static mender_err_t
864
artifact_read_header(mender_artifact_ctx_t *ctx) {
865
    assert(NULL != ctx);
866

867
    /* Check if all data have been received */
868
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
869
        return MENDER_OK;
870
    }
871

872
    /* Get checksum entry (create one if needed) */
873
    mender_artifact_checksum_t *checksum;
874
    if (NULL == (checksum = artifact_checksum_get_or_create(ctx, "header.tar"))) {
875
        /* Error already logged */
876
        return MENDER_FAIL;
877
    }
878

879
    /* Update SHA-256 checksum */
880
    if (MENDER_OK != mender_sha256_update(checksum->context, ctx->input.data, ctx->file.size)) {
881
        mender_log_error("Failed to update update checksum");
882
        return MENDER_FAIL;
883
    }
884

885
    return MENDER_DONE;
886
}
887
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
888

889
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
890
static mender_err_t
891
artifact_read_type_info(mender_artifact_ctx_t *ctx) {
892

893
    assert(NULL != ctx);
894
    cJSON       *object = NULL;
895
    mender_err_t ret    = MENDER_DONE;
896
    size_t       index  = 0;
897

898
    /* Check if all data have been received */
899
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
900
        return MENDER_OK;
901
    }
902

903
    /* Read type-info */
904
    if (NULL == (object = cJSON_ParseWithLength(ctx->input.data, ctx->file.size))) {
905
        mender_log_error("Unable to allocate memory");
906
        return MENDER_FAIL;
907
    }
908

909
    /* Check if payload index is valid */
910
    if (NULL == ctx->payloads.values[index].type) {
911
        mender_log_error("Invalid artifact format; no payload found for index %d", index);
912
        ret = MENDER_FAIL;
913
        goto END;
914
    }
915
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
916
    cJSON *json_provides = cJSON_GetObjectItemCaseSensitive(object, "artifact_provides");
917
    if (cJSON_IsObject(json_provides)) {
918
        if (MENDER_FAIL == artifact_parse_provides_depends(json_provides, &(ctx->payloads.values[index].provides))) {
919
            mender_log_error("Unable to parse artifact_provides");
920
            ret = MENDER_FAIL;
921
            goto END;
922
        }
923
    }
924

925
    cJSON *json_depends = cJSON_GetObjectItemCaseSensitive(object, "artifact_depends");
926
    if (cJSON_IsObject(json_depends)) {
927
        if (MENDER_FAIL == artifact_parse_provides_depends(json_depends, &(ctx->payloads.values[index].depends))) {
928
            mender_log_error("Unable to parse artifact_depends");
929
            ret = MENDER_FAIL;
930
            goto END;
931
        }
932
    }
933

934
    cJSON *json_clears_provides = cJSON_GetObjectItemCaseSensitive(object, "clears_artifact_provides");
935
    if (cJSON_IsArray(json_clears_provides)) {
936
        ctx->payloads.values[index].clears_provides_size = cJSON_GetArraySize(json_clears_provides);
937
        ctx->payloads.values[index].clears_provides      = (char **)calloc(ctx->payloads.values[index].clears_provides_size, sizeof(char *));
938
        if (NULL == ctx->payloads.values[index].clears_provides) {
939
            mender_log_error("Unable to allocate memory");
940
            ret = MENDER_FAIL;
941
            goto END;
942
        }
943

944
        size_t i                            = 0;
945
        cJSON *json_clears_provides_element = NULL;
946

947
        cJSON_ArrayForEach(json_clears_provides_element, json_clears_provides) {
948
            if (cJSON_IsString(json_clears_provides_element)) {
949
                char *clears_provides = strdup(json_clears_provides_element->valuestring);
950
                if (NULL == clears_provides) {
951
                    mender_log_error("Unable to allocate memory");
952
                    ret = MENDER_FAIL;
953
                    goto END;
954
                }
955
                ctx->payloads.values[index].clears_provides[i] = clears_provides;
956
                i++;
957
            } else {
958
                mender_log_error("Invalid header-info file");
959
                ret = MENDER_FAIL;
960
                goto END;
961
            }
962
        }
963
    }
964
#endif
965

966
    /* Shift data in the buffer */
967
    if (MENDER_OK != artifact_shift_data(ctx, artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
968
        mender_log_error("Unable to shift input data");
969
        ret = MENDER_FAIL;
970
        goto END;
971
    }
972

973
END:
974

975
    /* Release memory */
976
    cJSON_Delete(object);
977

978
    return ret;
979
}
980
#endif
981

982
static mender_err_t
983
artifact_read_meta_data(mender_artifact_ctx_t *ctx) {
×
984

985
    assert(NULL != ctx);
×
986

987
    /* Retrieve payload index. We expect "header.tar/headers/%u/meta-data" where
988
     * %u is the index. Yes sscanf(3) would be nice, but we've experienced
989
     * unexplained segmentation faults on some hardware when using it. */
990
    const char *const prefix = "header.tar/headers/";
×
991
    if (!mender_utils_strbeginwith(ctx->file.name, prefix)) {
×
992
        mender_log_error("Invalid artifact format");
×
993
        return MENDER_FAIL;
×
994
    }
995

996
    assert(sizeof(size_t) >= sizeof(unsigned long));
997
    const char *start_ptr = ctx->file.name + strlen(prefix);
×
998
    char       *end_ptr;
999
    errno = 0; /* to distinguish between success/failure */
×
1000

1001
    const size_t index = strtoul(start_ptr, &end_ptr, 10);
×
1002
    if ((end_ptr == start_ptr)              /* no conversion */
×
1003
        || (0 != errno)                     /* out of range (for unsigned long) */
×
1004
        || (index >= ctx->payloads.size)) { /* index out of bounds */
×
1005
        mender_log_error("Invalid artifact format");
×
1006
        return MENDER_FAIL;
×
1007
    }
1008

1009
    assert(NULL != end_ptr);
×
1010
    assert(StringEqualN(end_ptr, "/meta-data", 10)); /* just one last sanity check */
×
1011

1012
    /* Check size of the meta-data */
1013
    if (0 == artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
1014
        /* Nothing to do */
1015
        return MENDER_DONE;
×
1016
    }
1017

1018
    /* Check if all data have been received */
1019
    if ((NULL == ctx->input.data) || (ctx->input.length < artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
1020
        return MENDER_OK;
×
1021
    }
1022

1023
    /* Read meta-data */
1024
    if (NULL == (ctx->payloads.values[index].meta_data = cJSON_ParseWithLength(ctx->input.data, ctx->file.size))) {
×
1025
        mender_log_error("Unable to allocate memory");
×
1026
        return MENDER_FAIL;
×
1027
    }
1028

1029
    /* Shift data in the buffer */
1030
    if (MENDER_OK != artifact_shift_data(ctx, artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
1031
        mender_log_error("Unable to shift input data");
×
1032
        return MENDER_FAIL;
×
1033
    }
1034

1035
    return MENDER_DONE;
×
1036
}
1037

1038
/**
1039
 * @brief Callback function to be invoked to perform the treatment of the data from the artifact
1040
 * @param type Type from header-info payloads
1041
 * @param meta_data Meta-data from header tarball
1042
 * @param filename Artifact filename
1043
 * @param size Artifact file size
1044
 * @param data Artifact data
1045
 * @param index Artifact data index
1046
 * @param length Artifact data length
1047
 * @param dl_data Download data for the artifact
1048
 * @return MENDER_OK if the function succeeds, error code if an error occurred
1049
 */
1050
static mender_err_t
1051
process_artifact_data_callback(const char                      *type,
×
1052
                               const cJSON                     *meta_data,
1053
                               const char                      *filename,
1054
                               size_t                           size,
1055
                               void                            *data,
1056
                               size_t                           index,
1057
                               size_t                           length,
1058
                               mender_artifact_download_data_t *dl_data) {
1059

1060
    assert(NULL != type);
×
1061
    mender_err_t ret = MENDER_FAIL;
×
1062

1063
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
1064
    if (size > 0) {
×
1065
        static size_t download_progress = 0;
1066
        /* New update */
1067
        if (0 == index) {
×
1068
            download_progress = 0;
×
1069
        }
1070

1071
        /* Update every 10% */
1072
        if (((index * 10) / size) > download_progress) {
×
1073
            download_progress = (index * 10) / size;
×
1074
            mender_log_info("Downloading '%s' %zu0%%... [%zu/%zu]", type, download_progress, index, size);
×
1075
        }
1076
    }
1077
#endif
1078

1079
    dl_data->update_module = mender_update_module_get(type);
×
1080
    if (NULL == dl_data->update_module) {
×
1081
        /* Content is not supported by the mender-mcu-client */
1082
        mender_log_error("Unable to handle artifact type '%s'", type);
×
1083
        return MENDER_FAIL;
×
1084
    }
1085

1086
    /* Retrieve ID and artifact name */
1087
    const char *id;
1088
    if (MENDER_OK != mender_deployment_data_get_id(dl_data->deployment, &id)) {
×
1089
        mender_log_error("Unable to get ID from the deployment data");
×
1090
        return MENDER_FAIL;
×
1091
    }
1092
    const char *artifact_name;
1093
    if (MENDER_OK != mender_deployment_data_get_artifact_name(dl_data->deployment, &artifact_name)) {
×
1094
        mender_log_error("Unable to get artifact name from the deployment data");
×
1095
        return MENDER_FAIL;
×
1096
    }
1097

1098
    /* Invoke update module download callback */
1099
    struct mender_update_download_state_data_s download_state_data = { id, artifact_name, type, meta_data, filename, size, data, index, length, false };
×
1100
    mender_update_state_data_t                 state_data          = { .download_state_data = &download_state_data };
×
1101
    if (MENDER_OK != (ret = dl_data->update_module->callbacks[MENDER_UPDATE_STATE_DOWNLOAD](MENDER_UPDATE_STATE_DOWNLOAD, state_data))) {
×
1102
        mender_log_error("An error occurred while processing data of the artifact '%s' of type '%s'", artifact_name, type);
×
1103
        return ret;
×
1104
    }
1105

1106
    /* Treatments related to the artifact type (once) */
1107
    if (0 == index) {
×
1108
        /* Add type to the deployment data */
1109
        if (MENDER_OK != (ret = mender_deployment_data_add_payload_type(dl_data->deployment, type))) {
×
1110
            /* Error already logged */
1111
            return ret;
×
1112
        }
1113
    }
1114

1115
    return MENDER_OK;
×
1116
}
1117

1118
static mender_err_t
1119
artifact_read_data(mender_artifact_ctx_t *ctx, mender_artifact_download_data_t *dl_data) {
×
1120

1121
    assert(NULL != ctx);
×
1122
    mender_err_t ret;
1123

1124
    /* Retrieve payload index. We expect "data/%u.tar" where %u is the index.
1125
     * Yes sscanf(3) would be nice, but we've experienced unexplained
1126
     * segmentation faults on some hardware when using it. */
1127
    const char *const prefix = "data/";
×
1128
    if (!mender_utils_strbeginwith(ctx->file.name, prefix)) {
×
1129
        mender_log_error("Invalid artifact format");
×
1130
        return MENDER_FAIL;
×
1131
    }
1132

1133
    assert(sizeof(size_t) >= sizeof(unsigned long));
1134
    const char *start_ptr = ctx->file.name + strlen(prefix);
×
1135
    char       *end_ptr;
1136
    errno = 0; /* to distinguish between success/failure */
×
1137

1138
    const size_t index = strtoul(start_ptr, &end_ptr, 10);
×
1139
    if ((end_ptr == start_ptr)              /* no conversion */
×
1140
        || (0 != errno)                     /* out of range (for unsigned long) */
×
1141
        || (index >= ctx->payloads.size)) { /* index out of bounds */
×
1142
        mender_log_error("Invalid artifact format");
×
1143
        return MENDER_FAIL;
×
1144
    }
1145

1146
    assert(NULL != end_ptr);
×
1147
    assert(StringEqualN(end_ptr, ".tar", 4)); /* just one last sanity check */
×
1148

1149
    /* Check if a file name is provided (we don't check the extension because we don't know it) */
1150
    if (strlen("data/xxxx.tar") == strlen(ctx->file.name)) {
×
1151

1152
        /* Beginning of the data file */
1153
        if (MENDER_OK
×
1154
            != (ret = process_artifact_data_callback(ctx->payloads.values[index].type, ctx->payloads.values[index].meta_data, NULL, 0, NULL, 0, 0, dl_data))) {
×
1155
            mender_log_error("An error occurred");
×
1156
            return ret;
×
1157
        }
1158

1159
        return MENDER_DONE;
×
1160
    }
1161

1162
    /* Check size of the data */
1163
    if (0 == artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
1164
        /* Nothing to do */
1165
        return MENDER_DONE;
×
1166
    }
1167

1168
    /* Parse data until the end of the file has been reached */
1169
    do {
1170

1171
        /* Check if enough data are received (at least one block) */
1172
        if ((NULL == ctx->input.data) || (ctx->input.length < MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
1173
            return MENDER_OK;
×
1174
        }
1175

1176
        /* Compute length */
1177
        size_t length
×
1178
            = ((ctx->file.size - ctx->file.index) > MENDER_ARTIFACT_STREAM_BLOCK_SIZE) ? MENDER_ARTIFACT_STREAM_BLOCK_SIZE : (ctx->file.size - ctx->file.index);
×
1179

1180
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1181
        mender_artifact_checksum_t *checksum;
1182
        {
1183
            /* The filename will be something like
1184
             * 'data/0000.tar/zephyr.signed.bin'. But the manifest will hold
1185
             * 'data/0000/zephyr.signed.bin'. Hence, we need to remove the
1186
             * '.tar' extension from the string.
1187
             */
1188
            char filename[strlen(ctx->file.name) + 1];
1189
            strcpy(filename, ctx->file.name);
1190

1191
            for (char *ch = strstr(filename, ".tar"); (NULL != ch) && (*ch != '\0'); ch++) {
1192
                /* Don't worry! The call to strlen() on a static string should
1193
                 * be optimized out by the compiler */
1194
                *ch = ch[strlen(".tar")];
1195
            }
1196

1197
            /* Get checksum entry (create one if needed) */
1198
            if (NULL == (checksum = artifact_checksum_get_or_create(ctx, filename))) {
1199
                /* Error already logged */
1200
                return MENDER_FAIL;
1201
            }
1202
        }
1203

1204
        /* Update SHA-256 checksum */
1205
        if (MENDER_OK != mender_sha256_update(checksum->context, ctx->input.data, length)) {
1206
            mender_log_error("Failed to update update checksum");
1207
            return MENDER_FAIL;
1208
        }
1209
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1210

1211
        /* Invoke the download artifact callback */
1212
        ret = process_artifact_data_callback(ctx->payloads.values[index].type,
×
1213
                                             ctx->payloads.values[index].meta_data,
×
1214
                                             strstr(ctx->file.name, ".tar") + strlen(".tar") + 1,
×
1215
                                             ctx->file.size,
1216
                                             ctx->input.data,
1217
                                             ctx->file.index,
1218
                                             length,
1219
                                             dl_data);
1220
        if (MENDER_OK != ret) {
×
1221
            mender_log_error("An error occurred");
×
1222
            return ret;
×
1223
        }
1224

1225
        /* Update index */
1226
        ctx->file.index += MENDER_ARTIFACT_STREAM_BLOCK_SIZE;
×
1227

1228
        /* Shift data in the buffer */
1229
        if (MENDER_OK != (ret = artifact_shift_data(ctx, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
1230
            mender_log_error("Unable to shift input data");
×
1231
            return ret;
×
1232
        }
1233

1234
    } while (ctx->file.index < ctx->file.size);
×
1235

1236
    return MENDER_DONE;
×
1237
}
1238

1239
static mender_err_t
1240
artifact_drop_file(mender_artifact_ctx_t *ctx) {
×
1241

1242
    assert(NULL != ctx);
×
1243
    mender_err_t ret;
1244

1245
    /* Check size of the data */
1246
    if (0 == artifact_round_up(ctx->file.size, MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
1247
        /* Nothing to do */
1248
        return MENDER_DONE;
×
1249
    }
1250

1251
    /* Parse data until the end of the file has been reached */
1252
    do {
1253

1254
        /* Check if enough data are received (at least one block) */
1255
        if ((NULL == ctx->input.data) || (ctx->input.length < MENDER_ARTIFACT_STREAM_BLOCK_SIZE)) {
×
1256
            return MENDER_OK;
×
1257
        }
1258

1259
        /* Update index */
1260
        ctx->file.index += MENDER_ARTIFACT_STREAM_BLOCK_SIZE;
×
1261

1262
        /* Shift data in the buffer */
1263
        if (MENDER_OK != (ret = artifact_shift_data(ctx, MENDER_ARTIFACT_STREAM_BLOCK_SIZE))) {
×
1264
            mender_log_error("Unable to shift input data");
×
1265
            return ret;
×
1266
        }
1267

1268
    } while (ctx->file.index < ctx->file.size);
×
1269

1270
    return MENDER_DONE;
×
1271
}
1272

1273
static mender_err_t
1274
artifact_shift_data(mender_artifact_ctx_t *ctx, size_t length) {
×
1275

1276
    assert(NULL != ctx);
×
1277

1278
    /* Shift data */
1279
    if (length > 0) {
×
1280
        if (ctx->input.length > length) {
×
1281
            memmove(ctx->input.data, (void *)(((uint8_t *)ctx->input.data) + length), ctx->input.length - length);
×
1282
            ctx->input.length -= length;
×
1283
            /* Here we could shrink the ctx->input.data buffer, but most likely, we would need to
1284
               grow it again when we receive another batch of data so there's little point in doing
1285
               so. */
1286
        } else {
1287
            ctx->input.length = 0;
×
1288
        }
1289
    }
1290

1291
    return MENDER_OK;
×
1292
}
1293

1294
static size_t
1295
artifact_round_up(size_t length, size_t incr) {
×
1296
    return length + (incr - length % incr) % incr;
×
1297
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc