Files
qdl/sparse.c
T
Bjorn Andersson 2bf8412c0b file: Introduce the qdl_file helper for reading files
Today there are a few different places through the code where files are
opened for reading, either in a oneshot fashion or for streaming (e.g.
during programming).

In order to allow these operations to read files packaged into
compressed zip files, and to avoid duplication of the load operation,
introduce the "qdl_file" file reading abstraction for these use cases.

It's not yet known how VIP is handled in these archives and to reduce
the impact of the change this time, the scope is limited to reading the
files used during normal flashing - this can obviously be considered for
extension later.

Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
2026-04-22 17:14:46 -05:00

119 lines
3.1 KiB
C

// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2025, Maksim Paimushkin <maxim.paymushkin.development@gmail.com>
* All rights reserved.
*/
#define _FILE_OFFSET_BITS 64
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "file.h"
#include "sparse.h"
#include "qdl.h"
int sparse_header_parse(struct qdl_file *file, sparse_header_t *sparse_header)
{
qdl_file_seek(file, 0, SEEK_SET);
if (qdl_file_read(file, sparse_header, sizeof(sparse_header_t)) != sizeof(sparse_header_t)) {
ux_err("[SPARSE] Unable to read sparse header\n");
return -EINVAL;
}
if (sparse_header->magic != SPARSE_HEADER_MAGIC) {
ux_err("[SPARSE] Invalid magic in sparse header\n");
return -EINVAL;
}
if (sparse_header->major_version != SPARSE_HEADER_MAJOR_VER) {
ux_err("[SPARSE] Invalid major version in sparse header\n");
return -EINVAL;
}
if (sparse_header->minor_version != SPARSE_HEADER_MINOR_VER) {
ux_err("[SPARSE] Invalid minor version in sparse header\n");
return -EINVAL;
}
if (sparse_header->file_hdr_sz > sizeof(sparse_header_t))
qdl_file_seek(file, sparse_header->file_hdr_sz - sizeof(sparse_header_t), SEEK_CUR);
return 0;
}
int sparse_chunk_header_parse(struct qdl_file *file,
sparse_header_t *sparse_header,
uint64_t *chunk_size,
uint32_t *value,
off_t *offset)
{
chunk_header_t chunk_header;
uint32_t fill_value = 0;
unsigned int type;
*chunk_size = 0;
*value = 0;
if (qdl_file_read(file, &chunk_header, sizeof(chunk_header_t)) != sizeof(chunk_header_t)) {
ux_err("[SPARSE] Unable to read sparse chunk header\n");
return -EINVAL;
}
if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
qdl_file_seek(file, sparse_header->chunk_hdr_sz - sizeof(chunk_header_t), SEEK_CUR);
type = chunk_header.chunk_type;
*chunk_size = (uint64_t)chunk_header.chunk_sz * sparse_header->blk_sz;
switch (type) {
case CHUNK_TYPE_RAW:
if (chunk_header.total_sz != (sparse_header->chunk_hdr_sz + *chunk_size)) {
ux_err("[SPARSE] Bogus chunk size, type Raw\n");
return -EINVAL;
}
/* Save the current file offset in the 'value' variable */
*offset = qdl_file_seek(file, 0, SEEK_CUR);
/* Move the file cursor forward by the size of the chunk */
qdl_file_seek(file, *chunk_size, SEEK_CUR);
break;
case CHUNK_TYPE_DONT_CARE:
if (chunk_header.total_sz != sparse_header->chunk_hdr_sz) {
ux_err("[SPARSE] Bogus chunk size, type Don't Care\n");
return -EINVAL;
}
break;
case CHUNK_TYPE_FILL:
if (chunk_header.total_sz != (sparse_header->chunk_hdr_sz + sizeof(fill_value))) {
ux_err("[SPARSE] Bogus chunk size, type Fill\n");
return -EINVAL;
}
if (qdl_file_read(file, &fill_value, sizeof(fill_value)) != sizeof(fill_value)) {
ux_err("[SPARSE] Unable to read fill value\n");
return -EINVAL;
}
/* Save the current fill value in the 'value' variable */
*value = fill_value;
break;
default:
ux_err("[SPARSE] Unknown chunk type: %#x\n", type);
return -EINVAL;
}
return type;
}