ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_app_admin.c
Go to the documentation of this file.
1
9#include "mdl_app_internal.h"
10
13
26{
27 if ((error != k_ra8_ok) && (priv_mdl_app_context()->io_error == k_ra8_ok)) {
29 }
30}
31
47 const char* first,
48 const char* second,
49 const char* third)
50{
51 ra8_err_t error = priv_mdl_stream_text(k_ra8_ok, stream, first);
52 error = priv_mdl_stream_text(error, stream, second);
53 internal_admin_latch(priv_mdl_stream_text(error, stream, third));
54}
55
57 const mdl_run_opts_t* opts,
58 const mdl_series_run_t* base)
59{
60 mdl_site_t site;
61 if (mdl_config_load(&priv_mdl_app_context()->storage, request->cfg_path, &site) != k_ra8_ok) {
62 return 1;
63 }
64 if (opts->polite) {
66 }
67 mdl_net_iface_t net = {};
68 if (mdl_net_provider_open(opts->net, &opts->policy, &net) != k_ra8_ok) {
70 priv_mdl_app_context()->diagnostic,
71 "mdl: network init failed\n");
72 return 1;
73 }
74 char ua[k_mdl_ua_max];
75 if (priv_mdl_app_start_session(&net, opts, site.contact, ua, sizeof(ua)) != k_ra8_ok) {
76 mdl_net_destroy(&net);
77 return 1;
78 }
79
81 const mdl_gov_cfg_t cfg = mdl_config_gov_cfg(&site);
82 mdl_governor_init(&gov, &cfg, request->seed);
83
84 const mdl_discover_req_t req = {
85 .session = &priv_mdl_app_context()->session,
86 .gov = &gov,
87 .site = &site,
89 .term = request->term,
90 .timeout_ms = request->timeout,
91 .page_buf = priv_mdl_app_context()->page,
92 .page_cap = sizeof(priv_mdl_app_context()->page),
93 .hits = &s_results,
94 .output = priv_mdl_app_context()->output,
95 .diagnostic = priv_mdl_app_context()->diagnostic,
96 .io_error = &priv_mdl_app_context()->io_error,
97 };
98 char picked[k_mdl_url_max] = {};
99 const int rc = mdl_discover_run(&req, request->pick, picked, sizeof(picked));
100 mdl_net_destroy(&net);
101 if ((rc != 0) || (picked[0] == '\0')) {
102 return rc; /* listed results, or an error, with nothing to download */
103 }
104 mdl_series_run_t run = *base;
105 run.series_url = picked; /* combined search-and-select: feed the pick in */
106 return mdl_app_run_series(&run);
107}
108
131RA8_INTERNAL static bool internal_init_site_identity(const char* url,
132 const char* descriptor_dir,
133 char* host,
134 char* slug,
135 char* name,
136 char* out_path)
137{
138 if ((url == nullptr) || (url[0] == '\0') || (descriptor_dir == nullptr) ||
139 (descriptor_dir[0] != '/')) {
141 priv_mdl_app_context()->diagnostic,
142 "mdl: --init-site requires a URL\n");
143 return false;
144 }
145 if (!mdl_url_host(url, host, k_mdl_host_max)) {
147 "mdl: --init-site could not extract host from '",
148 url,
149 "'\n");
150 return false;
151 }
152 const char* hptr = (strncmp(host, "www.", 4) == 0) ? host + 4 : host;
153 size_t i = 0U;
154 for (; (hptr[i] != '\0') && (hptr[i] != '.') && (i + 1U < k_mdl_name_max); ++i) {
155 slug[i] = hptr[i];
156 }
157 slug[i] = '\0';
158 if (slug[0] == '\0') {
159 (void)snprintf(slug, k_mdl_name_max, "site");
160 }
161 (void)snprintf(name, k_mdl_name_max, "%s", slug);
162 if ((name[0] >= 'a') && (name[0] <= 'z')) {
163 name[0] = (char)(name[0] - 'a' + 'A');
164 }
165 char leaf[k_leaf_name_bytes];
166 const int leaf_bytes = snprintf(leaf, sizeof(leaf), "%s.conf", slug);
167 return (leaf_bytes > 0) && ((size_t)leaf_bytes < sizeof(leaf)) &&
168 mdl_path_join(descriptor_dir, leaf, out_path, (size_t)k_fw_fs_path_cap);
169}
170
171int mdl_app_run_init_site(const char* url, const char* descriptor_dir)
172{
173 char host[k_mdl_host_max] = {};
174 char slug[k_mdl_name_max] = {};
175 char name[k_mdl_name_max] = {};
176 char out_path[k_fw_fs_path_cap];
177 if (!internal_init_site_identity(url, descriptor_dir, host, slug, name, out_path)) {
178 return 2;
179 }
180 if (priv_mdl_app_storage_ensure_directory(&priv_mdl_app_context()->storage, descriptor_dir) !=
181 k_ra8_ok) {
183 "mdl: descriptor directory is unsafe '",
184 descriptor_dir,
185 "'\n");
186 return 1;
187 }
188 const ra8_err_t published =
189 priv_mdl_app_storage_publish_site(&priv_mdl_app_context()->storage, out_path, url, host, name);
190 if (published == k_ra8_err_exists) {
192 "mdl: refusing to overwrite existing site descriptor '",
193 out_path,
194 "'\n");
195 return 1;
196 }
197 if (published != k_ra8_ok) {
199 "mdl: failed to publish site descriptor '",
200 out_path,
201 "'\n");
202 return 1;
203 }
204
206 ra8_err_t error =
207 priv_mdl_stream_text(k_ra8_ok, output, "generated starter site descriptor template: ");
208 error = priv_mdl_stream_text(error, output, out_path);
209 error = priv_mdl_stream_text(error, output, "\nedit ");
210 error = priv_mdl_stream_text(error, output, out_path);
211 error = priv_mdl_stream_text(error,
212 output,
213 " to tune scraping selectors, then test with:\n mdl --config ");
214 error = priv_mdl_stream_text(error, output, out_path);
215 error = priv_mdl_stream_text(error, output, " --series ");
216 error = priv_mdl_stream_text(error, output, url);
217 error = priv_mdl_stream_text(error, output, "\n");
218 return (error == k_ra8_ok) ? 0 : 1;
219}
220
233
251 const fw_fs_dirent_value_t* entry,
252 verify_stats_t* st)
253{
255 if (mdl_format_from_path(entry->name, &format) != k_ra8_ok) {
256 return;
257 }
258 st->archives_checked += 1U;
259 char path[k_fw_fs_path_cap];
260 fw_fs_stat_t node = {};
261 if ((entry->type != k_fw_fs_node_file) || !mdl_path_join(dir, entry->name, path, sizeof(path)) ||
262 (fw_fs_stat(&priv_mdl_app_context()->storage.fs->names, path, &node) != k_ra8_ok) ||
263 !node.exists || (node.type != entry->type)) {
265 " [CORRUPT ARTIFACT] ",
266 entry->name,
267 " (not a regular file)\n");
268 st->archives_corrupt += 1U;
269 return;
270 }
271 mdl_verify_report_t report = {};
272 const ra8_err_t rc = mdl_verify_file(&priv_mdl_app_context()->storage,
273 format,
274 path,
275 &priv_mdl_app_context()->export_ws,
276 &report);
277 if (rc != k_ra8_ok) {
279 ra8_err_t error = priv_mdl_stream_text(k_ra8_ok, output, " [");
280 error = priv_mdl_stream_text(error,
281 output,
282 mdl_format_is_verifiable(format) ? "CORRUPT" : "UNSUPPORTED");
283 error = priv_mdl_stream_text(error, output, " ARTIFACT] ");
284 error = priv_mdl_stream_text(error, output, entry->name);
285 internal_admin_latch(priv_mdl_stream_text(error, output, "\n"));
286 st->archives_corrupt += 1U;
287 return;
288 }
290 ra8_err_t error = priv_mdl_stream_text(k_ra8_ok, output, " [VALID ARTIFACT] ");
291 error = priv_mdl_stream_text(error, output, entry->name);
292 error = priv_mdl_stream_text(error, output, " (");
293 error = priv_mdl_stream_u64(error, output, report.page_count);
294 error = priv_mdl_stream_text(error, output, " page(s), ");
295 error = priv_mdl_stream_u64(error, output, report.member_count);
296 internal_admin_latch(priv_mdl_stream_text(error, output, " member(s))\n"));
297 st->archives_valid += 1U;
298}
299
315{
316 fw_fs_dir_t directory = {};
317 ra8_err_t error =
318 fw_fs_dir_open(&priv_mdl_app_context()->storage.fs->names,
319 dir,
320 &directory,
321 priv_mdl_app_context()->admin_directory_workspace.bytes,
322 (uint32_t)sizeof(priv_mdl_app_context()->admin_directory_workspace.bytes));
323 if (error != k_ra8_ok) {
324 internal_admin_text3(priv_mdl_app_context()->output, " [VERIFY FAIL] cannot open ", dir, "\n");
325 st->fs_errors += 1U;
326 return;
327 }
328 while (error == k_ra8_ok) {
329 fw_fs_dirent_value_t entry = {};
330 bool present = false;
331 error = fw_fs_dir_next(&directory, &entry, &present);
332 if ((error != k_ra8_ok) || !present) {
333 break;
334 }
335 if (entry.name[0] == '.') {
336 continue;
337 }
338 internal_verify_artifact_entry(dir, &entry, st);
339 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
340 break;
341 }
342 }
343 if (error != k_ra8_ok) {
345 " [VERIFY FAIL] cannot finish reading ",
346 dir,
347 "\n");
348 st->fs_errors += 1U;
349 }
350 const ra8_err_t closed = fw_fs_dir_close(&directory);
351 if (closed != k_ra8_ok) {
352 st->fs_errors += 1U;
353 }
354}
355
376RA8_INTERNAL static bool
377internal_verify_page_rec(const char* series_dir, const mdl_page_rec_t* rec, verify_stats_t* st)
378{
379 char page_path[k_fw_fs_path_cap];
380 const int pn = snprintf(page_path, sizeof(page_path), "%s/%s", series_dir, rec->rel_path);
381 fw_fs_stat_t page = {};
382 if ((pn < 0) || ((size_t)pn >= sizeof(page_path)) ||
383 (fw_fs_stat(&priv_mdl_app_context()->storage.fs->names, page_path, &page) != k_ra8_ok) ||
384 !page.exists || (page.type != k_fw_fs_node_file)) {
386 " [MISSING/UNSAFE] ",
387 rec->rel_path,
388 "\n");
389 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
390 return false;
391 }
392 st->pages_missing += 1U;
393 return true;
394 }
395 uint64_t hash = 0U;
396 if ((mdl_hash_file(&priv_mdl_app_context()->storage, page_path, &hash) != k_ra8_ok) ||
397 (hash != rec->content_hash)) {
399 " [CORRUPT] ",
400 rec->rel_path,
401 " (hash mismatch)\n");
402 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
403 return false;
404 }
405 st->pages_corrupt += 1U;
406 return true;
407 }
408 st->pages_valid += 1U;
409 return true;
410}
411
426RA8_INTERNAL static void
427internal_verify_series_dir(const char* series_dir, const char* state_path, verify_stats_t* st)
428{
429 st->series_checked += 1U;
430 internal_admin_text3(priv_mdl_app_context()->output, "verifying ", series_dir, "...\n");
431 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
432 return;
433 }
434 if (mdl_state_load(&priv_mdl_app_context()->storage,
435 state_path,
436 &priv_mdl_app_context()->state) != k_ra8_ok) {
438 " [VERIFY FAIL] ",
439 series_dir,
440 ": .mdl_state file unreadable or corrupt\n");
441 st->state_errors += 1U;
442 } else {
443 for (uint32_t i = 0U; i < priv_mdl_app_context()->state.page_rec_count; ++i) {
445 if (!internal_verify_page_rec(series_dir, rec, st)) {
446 return;
447 }
448 }
449 }
450 if (priv_mdl_app_context()->io_error == k_ra8_ok) {
451 internal_verify_artifacts(series_dir, st);
452 }
453}
454
469RA8_INTERNAL static void internal_verify_library_root(const char* canonical, verify_stats_t* stats)
470{
471 internal_verify_artifacts(canonical, stats);
472 fw_fs_dir_t root = {};
473 ra8_err_t error =
474 fw_fs_dir_open(&priv_mdl_app_context()->storage.fs->names,
475 canonical,
476 &root,
477 priv_mdl_app_context()->library_workspace.directory_workspace,
478 priv_mdl_app_context()->library_workspace.directory_workspace_bytes);
479 if (error != k_ra8_ok) {
480 stats->fs_errors += 1U;
481 return;
482 }
483 while (error == k_ra8_ok) {
484 fw_fs_dirent_value_t entry = {};
485 bool present = false;
486 error = fw_fs_dir_next(&root, &entry, &present);
487 if ((error != k_ra8_ok) || !present) {
488 break;
489 }
490 if ((entry.name[0] == '.') || (entry.type != k_fw_fs_node_directory)) {
491 continue;
492 }
493 char child[k_fw_fs_path_cap];
494 char child_state[k_fw_fs_path_cap];
495 fw_fs_stat_t child_node = {};
496 bool marker_exists = false;
497 if (!mdl_path_join(canonical, entry.name, child, sizeof(child)) ||
498 !mdl_path_join(child, ".mdl_state", child_state, sizeof(child_state)) ||
499 (fw_fs_stat(&priv_mdl_app_context()->storage.fs->names, child, &child_node) != k_ra8_ok) ||
500 !child_node.exists || (child_node.type != entry.type) ||
501 (mdl_state_probe(&priv_mdl_app_context()->storage, child_state, &marker_exists) !=
502 k_ra8_ok) ||
503 !marker_exists) {
504 continue;
505 }
506 internal_verify_series_dir(child, child_state, stats);
507 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
508 break;
509 }
510 }
511 if (error != k_ra8_ok) {
512 stats->fs_errors += 1U;
513 }
514 if (fw_fs_dir_close(&root) != k_ra8_ok) {
515 stats->fs_errors += 1U;
516 }
517}
518
537 const verify_stats_t* st)
538{
539 ra8_err_t error = priv_mdl_stream_text(k_ra8_ok, output, "verify complete: ");
540 error = priv_mdl_stream_u64(error, output, st->series_checked);
541 error = priv_mdl_stream_text(error, output, " series; pages ");
542 error = priv_mdl_stream_u64(error, output, st->pages_valid);
543 error = priv_mdl_stream_text(error, output, " valid, ");
544 error = priv_mdl_stream_u64(error, output, st->pages_missing);
545 error = priv_mdl_stream_text(error, output, " missing, ");
546 error = priv_mdl_stream_u64(error, output, st->pages_corrupt);
547 error = priv_mdl_stream_text(error, output, " corrupt; artifacts ");
548 error = priv_mdl_stream_u64(error, output, st->archives_valid);
549 error = priv_mdl_stream_text(error, output, " valid, ");
550 error = priv_mdl_stream_u64(error, output, st->archives_corrupt);
551 return priv_mdl_stream_text(error, output, " failed\n");
552}
553
554int mdl_app_run_verify(const char* target_dir)
555{
556 const char* dir = target_dir;
557 verify_stats_t st = {};
558 fw_fs_stat_t root = {};
559 if ((dir == nullptr) || (dir[0] != '/') ||
560 (fw_fs_stat(&priv_mdl_app_context()->storage.fs->names, dir, &root) != k_ra8_ok) ||
561 !root.exists || (root.type != k_fw_fs_node_directory)) {
563 "mdl: verify target '",
564 (dir != nullptr) ? dir : "",
565 "' is not a readable directory\n");
566 return 1;
567 }
568 char state_path[k_fw_fs_path_cap];
569 bool state_exists = false;
570 if (mdl_path_join(dir, ".mdl_state", state_path, sizeof(state_path)) &&
571 (mdl_state_probe(&priv_mdl_app_context()->storage, state_path, &state_exists) == k_ra8_ok) &&
572 state_exists) {
573 internal_verify_series_dir(dir, state_path, &st);
574 } else {
576 }
577 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
578 return 1;
579 }
581 if (internal_verify_print_summary(output, &st) != k_ra8_ok) {
582 return 1;
583 }
584
585 const bool any_target = (st.series_checked != 0U) || (st.archives_checked != 0U);
586 if (!any_target) {
588 "mdl: no tracked series or recognized artifacts under '",
589 dir,
590 "'\n");
591 if (priv_mdl_app_context()->io_error != k_ra8_ok) {
592 return 1;
593 }
594 }
595 return (any_target && (st.state_errors == 0U) && (st.fs_errors == 0U) &&
596 (st.pages_missing == 0U) && (st.pages_corrupt == 0U) && (st.archives_corrupt == 0U))
597 ? 0
598 : 1;
599}
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
Definition fw_if_fs.c:480
ra8_err_t fw_fs_dir_next(fw_fs_dir_t *directory, fw_fs_dirent_value_t *out, bool *out_entry)
Copy one stable directory entry from an open cursor.
ra8_err_t fw_fs_dir_close(fw_fs_dir_t *directory)
Close and consume an open directory cursor, including on close error.
ra8_err_t fw_fs_dir_open(const fw_fs_namespace_t *names, const char *path, fw_fs_dir_t *directory, void *workspace, uint32_t workspace_size)
Open one directory cursor into caller-owned backend workspace.
@ k_fw_fs_node_directory
Directory.
@ k_fw_fs_node_file
Regular byte stream.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
mdl_app_context_t * priv_mdl_app_context(void)
The working set the composition root bound with mdl_app_bind.
Definition mdl_app.c:33
int mdl_app_run_series(const mdl_series_run_t *run)
Execute one prepared series download.
int mdl_app_run_discover(const mdl_discover_run_t *request, const mdl_run_opts_t *opts, const mdl_series_run_t *base)
Run search or browse discovery and optionally download one result.
static bool internal_verify_page_rec(const char *series_dir, const mdl_page_rec_t *rec, verify_stats_t *st)
Verify one tracked page's presence and content hash.
static void internal_verify_artifacts(const char *dir, verify_stats_t *st)
Structurally validate recognized artifacts in one directory.
static void internal_verify_artifact_entry(const char *dir, const fw_fs_dirent_value_t *entry, verify_stats_t *st)
Classify one recognized artifact directory entry.
static void internal_admin_latch(ra8_err_t error)
Latch the first administration presenter failure.
static void internal_verify_series_dir(const char *series_dir, const char *state_path, verify_stats_t *st)
Verify persisted pages and artifacts for one tracked series.
int mdl_app_run_verify(const char *target_dir)
Verify one library or artifact tree without mutating it.
int mdl_app_run_init_site(const char *url, const char *descriptor_dir)
Create a starter descriptor for one validated site URL.
static bool internal_init_site_identity(const char *url, const char *descriptor_dir, char *host, char *slug, char *name, char *out_path)
Derive bounded descriptor identity and destination fields.
static void internal_verify_library_root(const char *canonical, verify_stats_t *stats)
Verify root-level artifacts and every tracked child series.
static ra8_err_t internal_verify_print_summary(ra8_io_stream_t *output, const verify_stats_t *st)
Stream the verification totals summary line.
static mdl_hit_list_t s_results
Bounded titled discovery hits for the active query.
static void internal_admin_text3(ra8_io_stream_t *stream, const char *first, const char *second, const char *third)
Append three borrowed administration fragments and latch failure.
Module-private contract shared by the application-mode translation units.
ra8_err_t priv_mdl_app_start_session(mdl_net_iface_t *net, const mdl_run_opts_t *opts, const char *cfg_contact, char *ua, size_t ua_cap)
Initialize one bounded network-policy session.
@ k_leaf_name_bytes
Composed archive/dir leaf name.
ra8_err_t priv_mdl_app_storage_ensure_directory(mdl_storage_t *storage, const char *path)
Ensure one canonical portable path names a real directory.
ra8_err_t priv_mdl_app_storage_publish_site(mdl_storage_t *storage, const char *destination, const char *url, const char *host, const char *name)
Render and create one starter site descriptor transactionally.
ra8_err_t mdl_config_load(mdl_storage_t *storage, const char *path, mdl_site_t *out)
Load a site descriptor from a flat key=value file.
Definition mdl_config.c:557
mdl_gov_cfg_t mdl_config_gov_cfg(const mdl_site_t *site)
Build the politeness-governor tunables for a loaded site descriptor.
Definition mdl_config.c:594
void mdl_config_apply_polite(mdl_site_t *site)
Raise a descriptor's per-request delay floors for --polite.
Definition mdl_config.c:625
@ k_mdl_host_max
Host bytes.
Definition mdl_config.h:34
@ k_mdl_name_max
Site display name bytes.
Definition mdl_config.h:33
int mdl_discover_run(const mdl_discover_req_t *req, size_t pick, char *out_url, size_t out_cap)
Run one search/browse discovery: fetch, parse, present, and select.
@ k_mdl_discover_browse
browse_url latest-updates page, no term.
@ k_mdl_discover_search
search_url with a {q} term substitution.
@ k_mdl_url_max
Max bytes per URL, including the NUL.
Definition mdl_extract.h:25
mdl_format_t
Artifact format selected by a media-download composition root.
Definition mdl_format.h:35
@ k_mdl_format_invalid
Unrecognized or unsupported selection.
Definition mdl_format.h:45
ra8_err_t mdl_hash_file(mdl_storage_t *storage, const char *path, uint64_t *out)
FNV-1a 64 hash of a file's full contents.
Definition mdl_hash.c:103
void mdl_net_destroy(mdl_net_iface_t *net)
Deinitialise a caller-owned network interface.
Definition mdl_net.c:120
ra8_err_t mdl_net_provider_open(const mdl_net_provider_t *provider, const mdl_net_policy_t *policy, mdl_net_iface_t *out_net)
Open a transport through an injected provider.
Definition mdl_net.c:64
void mdl_governor_init(mdl_governor_t *g, const mdl_gov_cfg_t *cfg, uint64_t seed)
Initialise a governor on the real host clock and blocking sleep.
bool mdl_path_join(const char *parent, const char *seg, char *out, size_t cap)
Join one safe child segment under a parent directory path.
@ k_mdl_ua_max
Built User-Agent buffer bytes.
Definition mdl_session.h:27
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_probe(mdl_storage_t *storage, const char *path, bool *out_exists)
Probe the complete two-generation state marker through portable storage.
ra8_err_t priv_mdl_stream_text(ra8_err_t prior, ra8_io_stream_t *stream, const char *text)
Append text unless an earlier operation already failed.
Definition mdl_stream.c:16
ra8_err_t priv_mdl_stream_u64(ra8_err_t prior, ra8_io_stream_t *stream, uint64_t value)
Append one unsigned integer unless an earlier append failed.
Definition mdl_stream.c:21
bool mdl_url_host(const char *url, char *out, size_t cap)
Extract the authority (host and optional port) from an http(s) URL.
ra8_err_t mdl_verify_file(mdl_storage_t *storage, mdl_format_t format, const char *path, mdl_export_workspace_t *workspace, mdl_verify_report_t *report)
Validate a completed artifact using caller-owned scratch only.
Definition mdl_verify.c:520
bool mdl_format_is_verifiable(mdl_format_t format)
Report whether a format has an in-process structural validator.
Definition mdl_verify.c:131
ra8_err_t mdl_format_from_path(const char *path, mdl_format_t *out_format)
Infer an artifact format from its complete path suffix.
Definition mdl_verify.c:107
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
Caller-owned open directory cursor; fields are private to the facade.
Stable caller-owned value returned by fw_fs_dir_next.
fw_fs_node_type_t type
Entry kind.
char name[k_fw_fs_path_cap]
Copied NUL-terminated leaf.
Result of a portable metadata query.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
mdl_session_t session
Network policy session.
Definition mdl_app.h:163
ra8_io_stream_t * output
Borrowed command output sink.
Definition mdl_app.h:166
ra8_err_t io_error
First presenter sink failure.
Definition mdl_app.h:168
ra8_io_stream_t * diagnostic
Borrowed diagnostic sink.
Definition mdl_app.h:167
char page[k_page_buf_bytes]
Whole-page HTML buffer.
Definition mdl_app.h:169
mdl_state_t state
Persistent tracked state.
Definition mdl_app.h:172
Injected dependencies and inputs for one discovery run.
One search or browse request against a configured site descriptor.
Definition mdl_app.h:140
const char * term
Search term; unused when browsing.
Definition mdl_app.h:142
uint32_t timeout
Per-request budget, ms.
Definition mdl_app.h:144
const char * cfg_path
Site descriptor path.
Definition mdl_app.h:141
bool browse
Browse latest updates instead of search.
Definition mdl_app.h:146
size_t pick
1-based hit to download; 0 lists only.
Definition mdl_app.h:143
uint64_t seed
Governor jitter seed.
Definition mdl_app.h:145
Per-site politeness tunables the governor is initialised with.
Closed-loop per-host politeness governor (rate + backoff + concurrency).
Bounded list of titled hits plus the raw anchor tally.
Definition mdl_extract.h:68
A network backend handle: an immutable method table plus its state.
One page's dedup/verify record in the series-wide pool.
Definition mdl_state.h:151
uint64_t content_hash
FNV-1a 64 of the fetched bytes.
Definition mdl_state.h:153
char rel_path[k_mdl_relpath_max]
Path under the series directory.
Definition mdl_state.h:154
Cross-cutting policy and injected transport threaded into every mode.
Definition mdl_app.h:73
mdl_net_policy_t policy
Backend security policy.
Definition mdl_app.h:74
bool polite
True to raise per-host delays.
Definition mdl_app.h:78
const mdl_net_provider_t * net
Injected transport factory.
Definition mdl_app.h:75
Parameters of one series download, as values rather than arguments.
Definition mdl_app.h:114
One site's scraping rules (all data, no logic).
Definition mdl_config.h:46
char contact[k_mdl_contact_max]
Operator contact for the UA.
Definition mdl_config.h:50
uint32_t page_rec_count
Page records recorded.
Definition mdl_state.h:193
mdl_page_rec_t pages[k_mdl_max_page_recs]
Per-page identities.
Definition mdl_state.h:197
Caller-allocated byte-stream handle binding a sink to its context.
Stats accumulated during a library/series verification run.
size_t pages_corrupt
Page files failing hash match.
size_t archives_corrupt
Archive files empty/corrupt.
size_t archives_checked
Archive files checked.
size_t pages_missing
Page files missing from disk.
size_t fs_errors
Directory/path operations that failed.
size_t state_errors
State files that could not be parsed.
size_t archives_valid
Structurally valid artifacts.
size_t pages_valid
Pages matching content hash on disk.
size_t series_checked
Tracked series verified.