ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_state_store.c File Reference

Portable checksummed two-generation persistence for downloader state. More...

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "mdl_state.h"
#include "mdl_state_internal.h"
#include "ra8_attributes.h"
Include dependency graph for mdl_state_store.c:

Go to the source code of this file.

Data Structures

struct  mdl_state_envelope_t
 Decoded canonical journal envelope. More...
struct  mdl_state_slot_t
 One physical generation discovered under the logical path. More...
struct  mdl_state_writer_t
 Streaming serialization state for one transaction. More...
struct  mdl_state_validation_t
 Expected stage identity passed to the independent validator. More...

Enumerations

enum  mdl_state_store_limit_t : uint32_t {
  k_state_magic_bytes = 8U ,
  k_state_header_bytes = 40U ,
  k_state_header_crc_span = 36U ,
  k_state_envelope_v1 = 1U ,
  k_state_alt_suffix = 4U ,
  k_state_io_call_max = 8U * 1024U * 1024U ,
  k_state_crc32_polynomial = 0xEDB88320UL ,
  k_state_be32_high_shift = 24U ,
  k_state_be64_high_shift = 56U ,
  k_state_header_version_offset = 8U ,
  k_state_header_size_offset = 10U ,
  k_state_header_reserved_offset = 12U ,
  k_state_header_sequence_offset = 16U ,
  k_state_header_payload_size_offset = 24U ,
  k_state_header_payload_crc_offset = 32U ,
  k_state_header_crc_offset = 36U
}
 Canonical journal-envelope and bounded-I/O constants. More...

Functions

static uint32_t internal_mdl_state_crc32_update (uint32_t state, const uint8_t *bytes, uint32_t length)
 Update an unfinalized reflected CRC-32 state.
static void internal_mdl_state_put_be16 (uint8_t *out, uint16_t value)
 Encode one uint16 in canonical big-endian order.
static void internal_mdl_state_put_be32 (uint8_t *out, uint32_t value)
 Encode one uint32 in canonical big-endian order.
static void internal_mdl_state_put_be64 (uint8_t *out, uint64_t value)
 Encode one uint64 in canonical big-endian order.
static uint16_t internal_mdl_state_get_be16 (const uint8_t *in)
 Decode one canonical big-endian uint16.
static uint32_t internal_mdl_state_get_be32 (const uint8_t *in)
 Decode one canonical big-endian uint32.
static uint64_t internal_mdl_state_get_be64 (const uint8_t *in)
 Decode one canonical big-endian uint64.
static void internal_mdl_state_encode_header (const mdl_state_envelope_t *envelope, uint8_t *out)
 Encode one self-checking canonical envelope.
static bool internal_mdl_state_decode_header (const uint8_t *bytes, mdl_state_envelope_t *out)
 Decode and authenticate one canonical envelope.
static ra8_err_t internal_mdl_state_read_all (fw_fs_file_t *file, uint8_t *out, uint32_t length, uint32_t *calls)
 Read an exact byte count while rejecting zero progress.
static ra8_err_t internal_mdl_state_hash_payload (mdl_storage_t *storage, fw_fs_file_t *file, uint64_t length, uint32_t *out_crc)
 Hash one exact payload extent and reject early EOF.
static ra8_err_t internal_mdl_state_validate_open (mdl_storage_t *storage, fw_fs_file_t *file, mdl_state_envelope_t *out)
 Validate an open journal envelope, extent, and checksum.
static ra8_err_t internal_mdl_state_paths (const mdl_storage_t *storage, const char *path, char *base, char *alternate)
 Derive and validate both physical generation paths.
static void internal_mdl_state_scan_slot (mdl_storage_t *storage, const char *path, bool allow_legacy, mdl_state_slot_t *out)
 Scan one physical generation without parsing its payload.
static bool internal_mdl_state_same_generation (const mdl_state_slot_t *a, const mdl_state_slot_t *b)
 Check whether two slots describe the same generation.
static ra8_err_t internal_mdl_state_order (const mdl_state_slot_t *base, const mdl_state_slot_t *alternate, const mdl_state_slot_t **newest, const mdl_state_slot_t **older)
 Order valid generations newest first.
static ra8_err_t internal_mdl_state_load_slot (mdl_storage_t *storage, const mdl_state_slot_t *slot, mdl_state_t *st)
 Load and revalidate one previously scanned generation.
static ra8_err_t internal_mdl_state_write_all (mdl_state_writer_t *writer, const uint8_t *bytes, uint32_t length)
 Write all bytes to an active transaction with bounded retry.
static ra8_err_t internal_mdl_state_emit (mdl_state_writer_t *writer, const char *line, int length)
 Append one payload record and update its identity.
static ra8_err_t internal_mdl_state_emit_kv (mdl_state_writer_t *writer, char type, const char *value)
 Serialize one bounded key/value record.
static ra8_err_t internal_mdl_state_emit_metadata (mdl_state_writer_t *writer, const mdl_state_t *st)
 Serialize every fixed series identity and metadata record.
static ra8_err_t internal_mdl_state_emit_chapters (mdl_state_writer_t *writer, const mdl_state_t *st)
 Serialize every chapter with exact v3 numeric identity.
static ra8_err_t internal_mdl_state_emit_pages (mdl_state_writer_t *writer, const mdl_state_t *st)
 Serialize every page identity and cache record.
static ra8_err_t internal_mdl_state_serialize (mdl_state_writer_t *writer, const mdl_state_t *st)
 Serialize one complete current-schema payload.
static ra8_err_t internal_mdl_state_validate_stage (void *ctx, fw_fs_file_t *staged)
 Independently validate the staged journal before publication.
static ra8_err_t internal_mdl_state_abort (fw_fs_transaction_t *transaction, ra8_err_t primary)
 Abort an unpublished transaction with cleanup-error precedence.
static ra8_err_t internal_mdl_state_build_stage (mdl_storage_t *storage, const char *target, uint64_t sequence, const mdl_state_t *st, fw_fs_transaction_t *transaction, mdl_state_envelope_t *envelope)
 Build and validate a private staged journal.
static ra8_err_t internal_mdl_state_save_plan (const mdl_state_slot_t *base, const mdl_state_slot_t *alternate, const mdl_state_slot_t **target, uint64_t *sequence)
 Select the preserved generation, rewrite target, and next sequence.
ra8_err_t mdl_state_probe (mdl_storage_t *storage, const char *path, bool *out_exists)
 Probe the complete two-generation state marker through portable storage.
static ra8_err_t internal_mdl_state_load_mode (mdl_storage_t *storage, const char *path, mdl_state_t *st, bool allow_legacy)
 Load the newest usable state with an explicit legacy policy.
ra8_err_t mdl_state_load (mdl_storage_t *storage, const char *path, mdl_state_t *st)
 Load a series' newest valid state through injected portable storage.
ra8_err_t mdl_state_load_authenticated (mdl_storage_t *storage, const char *path, mdl_state_t *st)
 Load only an authenticated checksummed state generation.
static ra8_err_t internal_mdl_state_prepare_target (mdl_storage_t *storage, const char *path, char *base, char *alternate, const char **out_target, uint64_t *out_sequence)
 Decide which generation slot the next save occupies, and clear it.
ra8_err_t mdl_state_save (mdl_storage_t *storage, const char *path, const mdl_state_t *st, bool *out_published)
 Publish a checksummed successor without sacrificing the newest state.

Variables

static const uint8_t s_state_magic [k_state_magic_bytes] = {'M', 'D', 'L', 'S', 'T', 'J', 'N', 'L'}
 Canonical journal magic, encoded byte-for-byte.

Detailed Description

Portable checksummed two-generation persistence for downloader state.

Encodes, validates, publishes, and recovers bounded state generations through fw_fs.

Definition in file mdl_state_store.c.

Enumeration Type Documentation

◆ mdl_state_store_limit_t

enum mdl_state_store_limit_t : uint32_t

Canonical journal-envelope and bounded-I/O constants.

Enumerator
k_state_magic_bytes 

Journal magic width.

k_state_header_bytes 

Canonical envelope width.

k_state_header_crc_span 

Header bytes authenticated.

k_state_envelope_v1 

Envelope schema version.

k_state_alt_suffix 

Bytes in .alt.

k_state_io_call_max 

Retry ceiling.

k_state_crc32_polynomial 

Reflected CRC-32 polynomial.

k_state_be32_high_shift 

High-byte shift for uint32.

k_state_be64_high_shift 

High-byte shift for uint64.

k_state_header_version_offset 

Envelope-version byte offset.

k_state_header_size_offset 

Header-size byte offset.

k_state_header_reserved_offset 

Reserved field byte offset.

k_state_header_sequence_offset 

Sequence field byte offset.

k_state_header_payload_size_offset 

Payload-size byte offset.

k_state_header_payload_crc_offset 

Payload-CRC byte offset.

k_state_header_crc_offset 

Header-CRC byte offset.

Definition at line 18 of file mdl_state_store.c.

Function Documentation

◆ internal_mdl_state_abort()

ra8_err_t internal_mdl_state_abort ( fw_fs_transaction_t * transaction,
ra8_err_t primary )
static

Abort an unpublished transaction with cleanup-error precedence.

Parameters
[in,out]transactionTransaction.
[in]primaryEarlier error.
Returns
Final error.
Return values
primaryAbort succeeded or no transaction was active.
Precondition
transaction is non-NULL.
Publication has not occurred.
Postcondition
Active stages are offered to abort.
Abort failure supersedes the primary error.
Note
This precedence exposes failed cleanup.
Since
0.1.0

Definition at line 736 of file mdl_state_store.c.

References fw_fs_transaction_t::active, fw_fs_transaction_abort(), k_ra8_ok, and RA8_INTERNAL.

Referenced by mdl_state_save().

◆ internal_mdl_state_build_stage()

ra8_err_t internal_mdl_state_build_stage ( mdl_storage_t * storage,
const char * target,
uint64_t sequence,
const mdl_state_t * st,
fw_fs_transaction_t * transaction,
mdl_state_envelope_t * envelope )
static

Build and validate a private staged journal.

Parameters
[in,out]storageScratch binding.
[in]targetAbsent target path.
[in]sequenceNew sequence.
[in]stValid state.
[out]transactionActive stage.
[out]envelopeIdentity.
Returns
Stage status.
Return values
k_ra8_okStage is independently validated.
Precondition
All pointers are non-NULL.
Target is absent and sequence is nonzero.
Postcondition
Success leaves an active validated transaction.
Failure leaves publication false.
Note
Header is backfilled after streaming payload identity.
Since
0.1.0

Definition at line 753 of file mdl_state_store.c.

References mdl_storage_t::fs, fw_fs_transaction_begin(), fw_fs_transaction_seek(), fw_fs_transaction_validate(), internal_mdl_state_encode_header(), internal_mdl_state_serialize(), internal_mdl_state_validate_stage(), internal_mdl_state_write_all(), k_fw_fs_txn_create_new, k_ra8_ok, k_state_header_bytes, mdl_state_writer_t::payload_bytes, RA8_INTERNAL, mdl_storage_t::transaction_workspace, mdl_storage_t::transaction_workspace_bytes, and fw_fs_t::transactions.

Referenced by mdl_state_save().

◆ internal_mdl_state_crc32_update()

uint32_t internal_mdl_state_crc32_update ( uint32_t state,
const uint8_t * bytes,
uint32_t length )
static

Update an unfinalized reflected CRC-32 state.

Parameters
[in]statePrior CRC state.
[in]bytesInput bytes.
[in]lengthByte count.
Returns
Updated unfinalized state.
Return values
UINT32_MAXEmpty input from the initial state.
Precondition
bytes is non-NULL when length is nonzero.
Length describes accessible bytes.
Postcondition
Input remains unchanged.
Exactly length bytes contribute.
Note
Finalization is a separate bitwise complement.
Since
0.1.0

Definition at line 80 of file mdl_state_store.c.

References k_state_crc32_polynomial.

Referenced by internal_mdl_state_decode_header(), internal_mdl_state_emit(), internal_mdl_state_encode_header(), and internal_mdl_state_hash_payload().

◆ internal_mdl_state_decode_header()

bool internal_mdl_state_decode_header ( const uint8_t * bytes,
mdl_state_envelope_t * out )
static

Decode and authenticate one canonical envelope.

Parameters
[in]bytesHeader bytes.
[out]outDecoded identity.
Returns
Authentication result.
Return values
falseMagic, schema, reserved field, CRC, or sequence is invalid.
Precondition
Both pointers are non-NULL.
Input spans the canonical header size.
Postcondition
Success initializes every output field.
Zero sequence remains forbidden.
Note
Exact file extent is validated separately.
Since
0.1.0

Definition at line 204 of file mdl_state_store.c.

References internal_mdl_state_crc32_update(), internal_mdl_state_get_be16(), internal_mdl_state_get_be32(), internal_mdl_state_get_be64(), k_state_envelope_v1, k_state_header_bytes, k_state_header_crc_offset, k_state_header_crc_span, k_state_header_payload_crc_offset, k_state_header_payload_size_offset, k_state_header_reserved_offset, k_state_header_sequence_offset, k_state_header_size_offset, k_state_header_version_offset, memcmp(), mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, RA8_INTERNAL, s_state_magic, and mdl_state_envelope_t::sequence.

Referenced by internal_mdl_state_validate_open().

◆ internal_mdl_state_emit()

ra8_err_t internal_mdl_state_emit ( mdl_state_writer_t * writer,
const char * line,
int length )
static

Append one payload record and update its identity.

Parameters
[in,out]writerActive writer.
[in]lineSerialized record.
[in]lengthByte count.
Returns
Portable size/I/O status.
Return values
k_ra8_err_invalid_sizeRecord or aggregate extent overflow.
Precondition
Pointers are non-NULL.
length describes accessible bytes.
Postcondition
Success advances byte count and CRC together.
Failure never reports unwritten bytes as persisted.
Note
Record terminators are included in the checksum.
Since
0.1.0

Definition at line 549 of file mdl_state_store.c.

References mdl_state_writer_t::crc_state, internal_mdl_state_crc32_update(), internal_mdl_state_write_all(), k_mdl_state_line_max, k_ra8_err_invalid_size, k_ra8_ok, and mdl_state_writer_t::payload_bytes.

Referenced by internal_mdl_state_emit_chapters(), internal_mdl_state_emit_kv(), internal_mdl_state_emit_metadata(), internal_mdl_state_emit_pages(), and internal_mdl_state_serialize().

◆ internal_mdl_state_emit_chapters()

ra8_err_t internal_mdl_state_emit_chapters ( mdl_state_writer_t * writer,
const mdl_state_t * st )
static

Serialize every chapter with exact v3 numeric identity.

Parameters
[in,out]writerActive writer.
[in]stValid state.
Returns
Serialization status.
Return values
k_ra8_okEvery chapter was emitted.
Precondition
Both pointers are non-NULL.
Chapter values are finite and validated.
Postcondition
Success emits all chapters in state order.
Binary64 bits use exact lowercase hex.
Note
Bit extraction uses memcpy.
Since
0.1.0

Definition at line 622 of file mdl_state_store.c.

References mdl_state_t::chapter_count, mdl_chapter_rec_t::chapter_id, mdl_state_t::chapters, mdl_chapter_rec_t::complete, mdl_chapter_rec_t::fetched_at, internal_mdl_state_emit(), k_mdl_state_line_max, k_ra8_ok, memcpy(), mdl_chapter_rec_t::number, mdl_chapter_rec_t::number_known, mdl_chapter_rec_t::page_count, mdl_chapter_rec_t::pages_done, RA8_INTERNAL, mdl_chapter_rec_t::source_url, and mdl_chapter_rec_t::title.

Referenced by internal_mdl_state_serialize().

◆ internal_mdl_state_emit_kv()

ra8_err_t internal_mdl_state_emit_kv ( mdl_state_writer_t * writer,
char type,
const char * value )
static

Serialize one bounded key/value record.

Parameters
[in,out]writerActive writer.
[in]typeRecord type.
[in]valueValidated value.
Returns
Serialization status.
Return values
k_ra8_err_invalid_sizeFormatted record exceeds its bound.
Precondition
Writer and value are non-NULL.
Value contains no record delimiter.
Postcondition
Success appends one complete line.
Writer identity matches emitted bytes.
Note
Formatting uses fixed stack storage.
Since
0.1.0

Definition at line 574 of file mdl_state_store.c.

References internal_mdl_state_emit(), and k_mdl_state_line_max.

Referenced by internal_mdl_state_emit_metadata().

◆ internal_mdl_state_emit_metadata()

ra8_err_t internal_mdl_state_emit_metadata ( mdl_state_writer_t * writer,
const mdl_state_t * st )
static

Serialize every fixed series identity and metadata record.

Parameters
[in,out]writerActive writer.
[in]stValid state.
Returns
Serialization status.
Return values
k_ra8_okEvery metadata record was emitted.
Precondition
Both pointers are non-NULL.
State passed full persistence validation.
Postcondition
Success emits metadata in canonical order.
Failure stops at the first rejected write.
Note
Reading direction is emitted as a numeric record.
Since
0.1.0

Definition at line 588 of file mdl_state_store.c.

References mdl_state_t::artist, mdl_state_t::config_path, mdl_state_t::cover_path, mdl_state_t::cover_url, internal_mdl_state_emit(), internal_mdl_state_emit_kv(), k_mdl_state_line_max, k_ra8_ok, mdl_state_t::language, RA8_INTERNAL, mdl_state_t::reading_direction, mdl_state_t::series_title, mdl_state_t::series_url, mdl_state_t::site_host, mdl_state_t::site_name, mdl_state_t::summary, and mdl_state_t::writer.

Referenced by internal_mdl_state_serialize().

◆ internal_mdl_state_emit_pages()

ra8_err_t internal_mdl_state_emit_pages ( mdl_state_writer_t * writer,
const mdl_state_t * st )
static

Serialize every page identity and cache record.

Parameters
[in,out]writerActive writer.
[in]stValid state.
Returns
Serialization status.
Return values
k_ra8_okEvery page was emitted.
Precondition
Both pointers are non-NULL.
Stored paths and validators are bounded.
Postcondition
Success emits all pages in state order.
Hash fields use fixed-width lowercase hex.
Note
Cache validators may be empty.
Since
0.1.0

Definition at line 655 of file mdl_state_store.c.

References mdl_page_rec_t::content_hash, mdl_page_rec_t::etag, mdl_page_rec_t::fetched_at, internal_mdl_state_emit(), k_mdl_state_line_max, k_ra8_ok, mdl_page_rec_t::last_modified, mdl_state_t::page_rec_count, mdl_state_t::pages, RA8_INTERNAL, mdl_page_rec_t::rel_path, mdl_page_rec_t::response_status, and mdl_page_rec_t::url_hash.

Referenced by internal_mdl_state_serialize().

◆ internal_mdl_state_encode_header()

void internal_mdl_state_encode_header ( const mdl_state_envelope_t * envelope,
uint8_t * out )
static

Encode one self-checking canonical envelope.

Parameters
[in]envelopeDecoded identity.
[out]outHeader bytes.
Precondition
Both pointers are non-NULL.
Output spans the canonical header size.
Postcondition
Reserved bytes are zero.
Header CRC authenticates every preceding field.
Note
Encoding is canonical big-endian.
Since
0.1.0

Definition at line 182 of file mdl_state_store.c.

References internal_mdl_state_crc32_update(), internal_mdl_state_put_be16(), internal_mdl_state_put_be32(), internal_mdl_state_put_be64(), k_state_envelope_v1, k_state_header_bytes, k_state_header_crc_offset, k_state_header_crc_span, k_state_header_payload_crc_offset, k_state_header_payload_size_offset, k_state_header_sequence_offset, k_state_header_size_offset, k_state_header_version_offset, memcpy(), memset(), mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, RA8_INTERNAL, s_state_magic, and mdl_state_envelope_t::sequence.

Referenced by internal_mdl_state_build_stage().

◆ internal_mdl_state_get_be16()

uint16_t internal_mdl_state_get_be16 ( const uint8_t * in)
static

Decode one canonical big-endian uint16.

Parameters
[in]inTwo-byte source.
Returns
Decoded value.
Return values
0Both bytes encode zero.
Precondition
in is non-NULL.
Two source bytes are readable.
Postcondition
Source remains unchanged.
Result is independent of host endianness.
Note
Input alignment is unrestricted.
Since
0.1.0

Definition at line 141 of file mdl_state_store.c.

References RA8_INTERNAL.

Referenced by internal_mdl_state_decode_header().

◆ internal_mdl_state_get_be32()

uint32_t internal_mdl_state_get_be32 ( const uint8_t * in)
static

Decode one canonical big-endian uint32.

Parameters
[in]inFour-byte source.
Returns
Decoded value.
Return values
0All bytes encode zero.
Precondition
in is non-NULL.
Four source bytes are readable.
Postcondition
Source remains unchanged.
Result is independent of host endianness.
Note
Input alignment is unrestricted.
Since
0.1.0

Definition at line 153 of file mdl_state_store.c.

References k_state_be32_high_shift, and RA8_INTERNAL.

Referenced by internal_mdl_state_decode_header().

◆ internal_mdl_state_get_be64()

uint64_t internal_mdl_state_get_be64 ( const uint8_t * in)
static

Decode one canonical big-endian uint64.

Parameters
[in]inEight-byte source.
Returns
Decoded value.
Return values
0All bytes encode zero.
Precondition
in is non-NULL.
Eight source bytes are readable.
Postcondition
Source remains unchanged.
Result is independent of host endianness.
Note
Input alignment is unrestricted.
Since
0.1.0

Definition at line 166 of file mdl_state_store.c.

References RA8_INTERNAL.

Referenced by internal_mdl_state_decode_header().

◆ internal_mdl_state_hash_payload()

ra8_err_t internal_mdl_state_hash_payload ( mdl_storage_t * storage,
fw_fs_file_t * file,
uint64_t length,
uint32_t * out_crc )
static

Hash one exact payload extent and reject early EOF.

Parameters
[in,out]storageI/O scratch binding.
[in,out]fileOpen stream.
[in]lengthExact extent.
[out]out_crcFinal CRC.
Returns
Portable I/O status.
Return values
k_ra8_err_invalid_stateEarly zero progress.
Precondition
All pointers are non-NULL.
Storage scratch has positive capacity.
Postcondition
Success hashes exactly length bytes.
Reads never cross that extent.
Note
Work and attempts are bounded.
Since
0.1.0

Definition at line 261 of file mdl_state_store.c.

References fw_fs_read(), internal_mdl_state_crc32_update(), mdl_storage_t::io_buffer, mdl_storage_t::io_buffer_bytes, k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_ok, k_state_io_call_max, and RA8_INTERNAL.

Referenced by internal_mdl_state_validate_open().

◆ internal_mdl_state_load_mode()

ra8_err_t internal_mdl_state_load_mode ( mdl_storage_t * storage,
const char * path,
mdl_state_t * st,
bool allow_legacy )
static

Load the newest usable state with an explicit legacy policy.

Authenticates journal generations, optionally admits legacy base text, and retries the older valid generation after a decode error.

Parameters
[in,out]storageInitialized exclusive storage binding.
[in]pathCanonical logical state path.
[out]stState initialized on every return.
[in]allow_legacyWhether unenveloped base text may be selected.
Returns
Canonical path, stream, authentication, or decode status.
Precondition
Required pointers are non-NULL and storage workspaces are exclusively owned.
Postcondition
st is valid on every return and empty when loading fails.
Note
The alternate peer is always required to carry an authenticated envelope.
Since
0.1.0
Return values
k_ra8_okThe operation completed successfully.
otherThe originating validation, storage, stream, or network error.
Precondition
Every required pointer is non-null and remains valid for the call.
Postcondition
Documented outputs and the return value describe the same outcome.

Definition at line 881 of file mdl_state_store.c.

References mdl_state_slot_t::error, mdl_state_slot_t::exists, internal_mdl_state_load_slot(), internal_mdl_state_order(), internal_mdl_state_paths(), internal_mdl_state_scan_slot(), k_fw_fs_path_cap, k_ra8_err_invalid_arg, k_ra8_ok, mdl_state_init(), and RA8_INTERNAL.

Referenced by mdl_state_load(), and mdl_state_load_authenticated().

◆ internal_mdl_state_load_slot()

ra8_err_t internal_mdl_state_load_slot ( mdl_storage_t * storage,
const mdl_state_slot_t * slot,
mdl_state_t * st )
static

Load and revalidate one previously scanned generation.

Parameters
[in,out]storageScratch binding.
[in]slotScanned slot.
[out]stDestination state.
Returns
Parse/I/O status.
Return values
k_ra8_err_invalid_stateIdentity changed or payload is corrupt.
Precondition
All pointers are non-NULL.
slot was valid during scanning.
Postcondition
Success transactionally replaces st.
Failure resets st empty.
Note
Journal identity is checked again after open.
Since
0.1.0

Definition at line 476 of file mdl_state_store.c.

References mdl_state_slot_t::envelope, mdl_state_slot_t::file_bytes, mdl_storage_t::file_workspace, mdl_storage_t::file_workspace_bytes, mdl_storage_t::fs, fw_fs_close(), fw_fs_open(), internal_mdl_state_validate_open(), k_fw_fs_open_read, k_mdl_state_version, k_mdl_state_version_v2, k_ra8_err_invalid_state, k_ra8_ok, k_state_header_bytes, mdl_state_slot_t::legacy, mdl_state_init(), mdl_state_slot_t::path, mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, priv_mdl_state_parse_file(), mdl_state_envelope_t::sequence, and fw_fs_t::streams.

Referenced by internal_mdl_state_load_mode().

◆ internal_mdl_state_order()

ra8_err_t internal_mdl_state_order ( const mdl_state_slot_t * base,
const mdl_state_slot_t * alternate,
const mdl_state_slot_t ** newest,
const mdl_state_slot_t ** older )
static

Order valid generations newest first.

Parameters
[in]baseBase slot.
[in]alternateAlternate slot.
[out]newestNewest valid slot.
[out]olderOther valid slot.
Returns
Ordering status.
Return values
k_ra8_err_invalid_stateDivergent equal sequences.
Precondition
All pointers are non-NULL.
Slot scan results are complete.
Postcondition
Outputs are NULL or alias input slots.
No slot contents are modified.
Note
Invalid generations are excluded from ordering.
Since
0.1.0

Definition at line 440 of file mdl_state_store.c.

References mdl_state_slot_t::envelope, internal_mdl_state_same_generation(), k_ra8_err_invalid_state, k_ra8_ok, RA8_INTERNAL, mdl_state_envelope_t::sequence, and mdl_state_slot_t::valid.

Referenced by internal_mdl_state_load_mode(), and internal_mdl_state_save_plan().

◆ internal_mdl_state_paths()

ra8_err_t internal_mdl_state_paths ( const mdl_storage_t * storage,
const char * path,
char * base,
char * alternate )
static

Derive and validate both physical generation paths.

Parameters
[in]storageFilesystem binding.
[in]pathLogical base.
[out]baseBase path.
[out]alternate.alt path.
Returns
Canonical path status.
Return values
k_ra8_err_invalid_sizeSuffix would exceed capacity.
Precondition
Output buffers are distinct and full-capacity.
Storage has all required scratch bindings.
Postcondition
Success initializes two valid paths.
Failure performs no filesystem mutation.
Note
No host path API is used.
Since
0.1.0

Definition at line 336 of file mdl_state_store.c.

References fw_fs_t::caps, mdl_storage_t::file_workspace, mdl_storage_t::fs, fw_fs_path_validate(), mdl_storage_t::io_buffer, mdl_storage_t::io_buffer_bytes, k_fw_fs_path_cap, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_ok, k_state_alt_suffix, memcpy(), RA8_INTERNAL, strlen(), and mdl_storage_t::transaction_workspace.

Referenced by internal_mdl_state_load_mode(), internal_mdl_state_prepare_target(), and mdl_state_probe().

◆ internal_mdl_state_prepare_target()

ra8_err_t internal_mdl_state_prepare_target ( mdl_storage_t * storage,
const char * path,
char * base,
char * alternate,
const char ** out_target,
uint64_t * out_sequence )
static

Decide which generation slot the next save occupies, and clear it.

Derives both physical paths, scans both slots, asks the save plan which is next, and unlinks it when a previous generation is still there.

Parameters
[in,out]storageFilesystem binding.
[in]pathLogical base.
[out]baseBase path buffer.
[out]alternate.alt path buffer.
[out]out_targetChosen path, aliasing one of those buffers.
[out]out_sequenceSequence the save must carry.
Returns
Canonical save-planning status.
Return values
k_ra8_okThe slot is chosen and empty.
k_ra8_err_invalid_sizeSuffix would exceed capacity.
Precondition
Both buffers span k_fw_fs_path_cap bytes.
Both outputs are non-null and distinct.
Postcondition
Success leaves no file at the chosen path.
Failure mutates nothing beyond the attempted unlink.
Note
No host path API is used.
Since
0.1.0

Definition at line 935 of file mdl_state_store.c.

References mdl_state_slot_t::exists, mdl_storage_t::fs, fw_fs_unlink(), internal_mdl_state_paths(), internal_mdl_state_save_plan(), internal_mdl_state_scan_slot(), k_ra8_ok, fw_fs_t::names, mdl_state_slot_t::path, and RA8_INTERNAL.

Referenced by mdl_state_save().

◆ internal_mdl_state_put_be16()

void internal_mdl_state_put_be16 ( uint8_t * out,
uint16_t value )
static

Encode one uint16 in canonical big-endian order.

Parameters
[out]outTwo-byte destination.
[in]valueValue to encode.
Precondition
out is non-NULL.
Two destination bytes are writable.
Postcondition
Both bytes are initialized.
Decoding them recovers value.
Note
Host endianness is irrelevant.
Since
0.1.0

Definition at line 99 of file mdl_state_store.c.

References RA8_INTERNAL.

Referenced by internal_mdl_state_encode_header().

◆ internal_mdl_state_put_be32()

void internal_mdl_state_put_be32 ( uint8_t * out,
uint32_t value )
static

Encode one uint32 in canonical big-endian order.

Parameters
[out]outFour-byte destination.
[in]valueValue to encode.
Precondition
out is non-NULL.
Four destination bytes are writable.
Postcondition
Every byte is initialized.
Decoding them recovers value.
Note
Host endianness is irrelevant.
Since
0.1.0

Definition at line 112 of file mdl_state_store.c.

References k_state_be32_high_shift, and RA8_INTERNAL.

Referenced by internal_mdl_state_encode_header().

◆ internal_mdl_state_put_be64()

void internal_mdl_state_put_be64 ( uint8_t * out,
uint64_t value )
static

Encode one uint64 in canonical big-endian order.

Parameters
[out]outEight-byte destination.
[in]valueValue to encode.
Precondition
out is non-NULL.
Eight destination bytes are writable.
Postcondition
Every byte is initialized.
Decoding them recovers value.
Note
Uses only defined unsigned shifts.
Since
0.1.0

Definition at line 127 of file mdl_state_store.c.

References k_state_be64_high_shift, and RA8_INTERNAL.

Referenced by internal_mdl_state_encode_header().

◆ internal_mdl_state_read_all()

ra8_err_t internal_mdl_state_read_all ( fw_fs_file_t * file,
uint8_t * out,
uint32_t length,
uint32_t * calls )
static

Read an exact byte count while rejecting zero progress.

Parameters
[in,out]fileOpen stream.
[out]outDestination.
[in]lengthByte count.
[in,out]callsAttempt counter.
Returns
Portable I/O status.
Return values
k_ra8_err_invalid_statePremature zero progress.
Precondition
All pointers are non-NULL.
Destination capacity is at least length.
Postcondition
Success initializes exactly length bytes.
Attempts never exceed the global cap.
Note
Short successful reads are retried.
Since
0.1.0

Definition at line 233 of file mdl_state_store.c.

References fw_fs_read(), k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_ok, and k_state_io_call_max.

Referenced by internal_mdl_state_scan_slot(), and internal_mdl_state_validate_open().

◆ internal_mdl_state_same_generation()

bool internal_mdl_state_same_generation ( const mdl_state_slot_t * a,
const mdl_state_slot_t * b )
static

Check whether two slots describe the same generation.

Parameters
[in]aFirst slot.
[in]bSecond slot.
Returns
Identity comparison.
Return values
falseSequence, extent, or checksum differs.
Precondition
Both pointers are non-NULL.
Both envelopes were authenticated.
Postcondition
Inputs remain unchanged.
Equal sequence alone is never sufficient.
Note
Detects ambiguous divergent ties.
Since
0.1.0

Definition at line 425 of file mdl_state_store.c.

References mdl_state_slot_t::envelope, mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, RA8_INTERNAL, and mdl_state_envelope_t::sequence.

Referenced by internal_mdl_state_order().

◆ internal_mdl_state_save_plan()

ra8_err_t internal_mdl_state_save_plan ( const mdl_state_slot_t * base,
const mdl_state_slot_t * alternate,
const mdl_state_slot_t ** target,
uint64_t * sequence )
static

Select the preserved generation, rewrite target, and next sequence.

Parameters
[in]baseBase slot.
[in]alternateAlternate slot.
[out]targetSlot to replace.
[out]sequenceNext sequence.
Returns
Planning status.
Return values
k_ra8_err_invalid_sizeSequence is exhausted.
Precondition
All pointers are non-NULL.
Both slot scans are complete.
Postcondition
Success never selects the newest slot as target.
Sequence increments without wrap.
Note
Existing scan errors propagate exactly.
Since
0.1.0

Definition at line 802 of file mdl_state_store.c.

References mdl_state_slot_t::envelope, mdl_state_slot_t::error, internal_mdl_state_order(), k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_ok, RA8_INTERNAL, and mdl_state_envelope_t::sequence.

Referenced by internal_mdl_state_prepare_target().

◆ internal_mdl_state_scan_slot()

void internal_mdl_state_scan_slot ( mdl_storage_t * storage,
const char * path,
bool allow_legacy,
mdl_state_slot_t * out )
static

Scan one physical generation without parsing its payload.

Parameters
[in,out]storageScratch binding.
[in]pathPhysical path.
[in]allow_legacyWhether text is accepted.
[out]outSlot result.
Precondition
All pointers are non-NULL.
path passed portable validation.
Postcondition
Output records existence, identity, and exact error.
Every opened stream is closed.
Note
Legacy recognition is restricted to the base slot.
Since
0.1.0

Definition at line 369 of file mdl_state_store.c.

References mdl_state_slot_t::envelope, mdl_state_slot_t::error, fw_fs_stat_t::exists, mdl_state_slot_t::exists, mdl_state_slot_t::file_bytes, mdl_storage_t::file_workspace, mdl_storage_t::file_workspace_bytes, mdl_storage_t::fs, fw_fs_close(), fw_fs_open(), fw_fs_stat(), internal_mdl_state_read_all(), internal_mdl_state_validate_open(), k_fw_fs_node_file, k_fw_fs_open_read, k_ra8_err_invalid_state, k_ra8_ok, k_state_magic_bytes, mdl_state_slot_t::legacy, memcmp(), fw_fs_t::names, RA8_INTERNAL, s_state_magic, fw_fs_stat_t::size_bytes, fw_fs_t::streams, fw_fs_stat_t::type, and mdl_state_slot_t::valid.

Referenced by internal_mdl_state_load_mode(), and internal_mdl_state_prepare_target().

◆ internal_mdl_state_serialize()

ra8_err_t internal_mdl_state_serialize ( mdl_state_writer_t * writer,
const mdl_state_t * st )
static

Serialize one complete current-schema payload.

Parameters
[in,out]writerActive writer.
[in]stValid state.
Returns
Serialization status.
Return values
k_ra8_okVersion, metadata, chapters, and pages were emitted.
Precondition
Both pointers are non-NULL.
State passed full persistence validation.
Postcondition
Success emits canonical section order.
Writer identity covers the entire payload.
Note
Envelope bytes are not part of payload CRC.
Since
0.1.0

Definition at line 684 of file mdl_state_store.c.

References internal_mdl_state_emit(), internal_mdl_state_emit_chapters(), internal_mdl_state_emit_metadata(), internal_mdl_state_emit_pages(), k_mdl_state_line_max, k_mdl_state_version, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_mdl_state_build_stage().

◆ internal_mdl_state_validate_open()

ra8_err_t internal_mdl_state_validate_open ( mdl_storage_t * storage,
fw_fs_file_t * file,
mdl_state_envelope_t * out )
static

Validate an open journal envelope, extent, and checksum.

Parameters
[in,out]storageScratch binding.
[in,out]fileOpen stream.
[out]outEnvelope.
Returns
Validation status.
Return values
k_ra8_err_invalid_stateAny canonical identity mismatch.
Precondition
All pointers are non-NULL.
File is open for reading.
Postcondition
Success leaves the stream after the payload.
Trailing and missing bytes are rejected.
Note
Payload parsing is deliberately separate.
Since
0.1.0

Definition at line 299 of file mdl_state_store.c.

References fw_fs_file_size(), fw_fs_seek(), internal_mdl_state_decode_header(), internal_mdl_state_hash_payload(), internal_mdl_state_read_all(), k_ra8_err_invalid_state, k_ra8_ok, k_state_header_bytes, mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, and RA8_INTERNAL.

Referenced by internal_mdl_state_load_slot(), internal_mdl_state_scan_slot(), and internal_mdl_state_validate_stage().

◆ internal_mdl_state_validate_stage()

ra8_err_t internal_mdl_state_validate_stage ( void * ctx,
fw_fs_file_t * staged )
static

Independently validate the staged journal before publication.

Parameters
[in]ctxExpected identity context.
[in,out]stagedOpen staged stream.
Returns
Validation status.
Return values
k_ra8_err_protocol_errorStage differs from expected identity.
Precondition
Both pointers are non-NULL.
Stage is private and complete.
Postcondition
Success authenticates header, extent, and payload.
No publication occurs here.
Note
Invoked through the fw_fs transaction contract.
Since
0.1.0

Definition at line 710 of file mdl_state_store.c.

References mdl_state_validation_t::envelope, internal_mdl_state_validate_open(), k_ra8_err_invalid_arg, k_ra8_err_protocol_error, k_ra8_ok, mdl_state_envelope_t::payload_bytes, mdl_state_envelope_t::payload_crc32, RA8_INTERNAL, mdl_state_envelope_t::sequence, and mdl_state_validation_t::storage.

Referenced by internal_mdl_state_build_stage().

◆ internal_mdl_state_write_all()

ra8_err_t internal_mdl_state_write_all ( mdl_state_writer_t * writer,
const uint8_t * bytes,
uint32_t length )
static

Write all bytes to an active transaction with bounded retry.

Parameters
[in,out]writerActive writer.
[in]bytesSource.
[in]lengthByte count.
Returns
Portable transaction status.
Return values
k_ra8_err_invalid_stateSuccessful zero progress.
Precondition
Writer and source are non-NULL.
Transaction is active and unvalidated.
Postcondition
Success writes exactly length bytes.
Attempts remain bounded.
Note
Short successful writes are retried.
Since
0.1.0

Definition at line 519 of file mdl_state_store.c.

References mdl_state_writer_t::calls, fw_fs_transaction_write(), k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_ok, k_state_io_call_max, and mdl_state_writer_t::transaction.

Referenced by internal_mdl_state_build_stage(), and internal_mdl_state_emit().

◆ mdl_state_load()

ra8_err_t mdl_state_load ( mdl_storage_t * storage,
const char * path,
mdl_state_t * st )

Load a series' newest valid state through injected portable storage.

Authenticates both journal generations, chooses the highest valid sequence, and falls back to the older valid generation if semantic parsing fails. A legacy unenveloped v1/v2 base file remains readable as sequence zero. When neither generation exists, st is initialized empty and success is returned. Any final failure also leaves st initialized empty.

Parameters
[in,out]storageInitialized, exclusively-owned storage binding.
[in]pathCanonical logical state path (never NULL).
[out]stState to fill; always left in a valid (possibly empty) form.
Returns
An ra8_err_t result.
Return values
k_ra8_okLoaded, or the file was absent (empty state).
k_ra8_err_invalid_argpath or st was NULL.
k_ra8_err_invalid_stateThe file exists but is corrupt/unsupported.
Precondition
All pointers are non-NULL and storage was initialized successfully.
The caller exclusively owns every workspace bound to storage.
Postcondition
st is always a valid state object on return (empty on any error).
No filesystem generation is modified.
Note
Not thread-safe: borrows every workspace in storage.
See also
mdl_state_save
Since
0.1.0

Definition at line 920 of file mdl_state_store.c.

References internal_mdl_state_load_mode().

Referenced by internal_run_series_paths(), and internal_verify_series_dir().

◆ mdl_state_load_authenticated()

ra8_err_t mdl_state_load_authenticated ( mdl_storage_t * storage,
const char * path,
mdl_state_t * st )
nodiscard

Load only an authenticated checksummed state generation.

Scans the logical base path and its .alt peer, rejects legacy unenveloped text, selects the highest valid authenticated sequence, and falls back to the older authenticated generation when semantic decoding fails. An absent marker initializes st empty and succeeds; every failure also leaves st initialized empty.

Parameters
[in,out]storageInitialized, exclusively-owned storage binding.
[in]pathCanonical logical state path.
[out]stState filled from one authenticated generation.
Returns
Canonical path, stream, authentication, or schema status.
Return values
k_ra8_okAn authenticated generation loaded or both peers were absent.
k_ra8_err_invalid_stateExisting generations failed authentication.
k_ra8_err_invalid_argA pointer, path, or binding is invalid.
Precondition
Required pointers are non-NULL and storage is initialized.
The caller exclusively owns all workspaces bound to storage.
Postcondition
st is a valid state object on every return, empty on failure.
No filesystem generation is modified.
Note
Use for library trust decisions; mdl_state_load preserves import compatibility with legacy unenveloped state.
Since
0.1.0

Definition at line 925 of file mdl_state_store.c.

References internal_mdl_state_load_mode().

Referenced by internal_library_visit(), and internal_resolve_removal_target().

◆ mdl_state_probe()

ra8_err_t mdl_state_probe ( mdl_storage_t * storage,
const char * path,
bool * out_exists )
nodiscard

Probe the complete two-generation state marker through portable storage.

Reports a tracked marker when either the logical base path or its bounded alternate generation exists as a regular file. Integrity and schema validation remain the responsibility of mdl_state_load.

Parameters
[in,out]storageInitialized, exclusively-owned storage binding.
[in]pathCanonical logical state path.
[out]out_existsWhether at least one regular state generation exists.
Returns
Canonical namespace/path status.
Return values
k_ra8_okThe probe completed and initialized out_exists.
k_ra8_err_invalid_argA pointer/path is invalid or a marker is not a file.
Precondition
All pointers are non-NULL and storage was initialized successfully.
The caller exclusively owns the namespace binding in storage.
Postcondition
On every return out_exists is initialized false unless a marker was found.
No filesystem object or state model is modified.
Note
Not thread-safe because storage is a non-reentrant dependency bundle.
Since
0.1.0

Definition at line 835 of file mdl_state_store.c.

References fw_fs_stat_t::exists, mdl_storage_t::fs, fw_fs_stat(), internal_mdl_state_paths(), k_fw_fs_node_file, k_fw_fs_path_cap, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, fw_fs_t::names, and fw_fs_stat_t::type.

Referenced by internal_library_visit(), internal_resolve_removal_target(), internal_verify_library_root(), and mdl_app_run_verify().

◆ mdl_state_save()

ra8_err_t mdl_state_save ( mdl_storage_t * storage,
const char * path,
const mdl_state_t * st,
bool * out_published )

Publish a checksummed successor without sacrificing the newest state.

Selects the absent, invalid, or older physical generation; removes only that target; writes a create-new private transaction; independently validates its canonical envelope, exact length, and payload CRC; then commits it. The newest accepted generation remains intact until commit. Sequence exhaustion is reported rather than wrapped. Cleanup failure takes precedence while the transaction is unpublished. A commit-time durability error can accompany a true out_published and must not be retried as though nothing changed.

Parameters
[in,out]storageInitialized, exclusively-owned storage binding.
[in]pathCanonical logical state path (never NULL).
[in]stState to write (never NULL).
[out]out_publishedFalse initially; true exactly when the successor became visible, including after durability failure.
Returns
An ra8_err_t result.
Return values
k_ra8_okThe validated successor was published.
k_ra8_err_invalid_argA pointer, path, or binding is invalid.
k_ra8_err_invalid_stateExisting generations are ambiguous/corrupt.
k_ra8_err_invalid_sizeThe monotonic sequence or I/O bound is exhausted.
otherA namespace, transaction, validation, durability, or cleanup error.
Precondition
All pointers are non-NULL and storage was initialized successfully.
The caller exclusively owns every workspace bound to storage.
Postcondition
On success one generation contains the complete serialized st.
When out_published is false, the previously newest valid generation survives.
When out_published is true, the successor is visible regardless of return status.
Note
Not thread-safe: borrows every workspace in storage.
See also
mdl_state_load
Since
0.1.0

Definition at line 966 of file mdl_state_store.c.

References fw_fs_transaction_commit(), internal_mdl_state_abort(), internal_mdl_state_build_stage(), internal_mdl_state_prepare_target(), k_fw_fs_path_cap, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, and priv_mdl_state_valid().

Referenced by internal_save_series_state(), and priv_mdl_fetch_checkpoint().

Variable Documentation

◆ s_state_magic

const uint8_t s_state_magic[k_state_magic_bytes] = {'M', 'D', 'L', 'S', 'T', 'J', 'N', 'L'}
static

Canonical journal magic, encoded byte-for-byte.

Definition at line 38 of file mdl_state_store.c.

Referenced by internal_mdl_state_decode_header(), internal_mdl_state_encode_header(), and internal_mdl_state_scan_slot().