libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
options.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2026 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18#include <errno.h>
19#include <limits.h>
20#include <stdbool.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "structs/options.h"
27
28#include "log.h"
29
30static char *aaru_strtok_reentrant(char *str, const char *delim, char **saveptr)
31{
32#if defined(_MSC_VER)
33 return strtok_s(str, delim, saveptr);
34#else
35 return strtok_r(str, delim, saveptr);
36#endif
37}
38
47aaru_options parse_options(const char *options, bool *table_shift_found)
48{
49 const char *options_str = options != NULL ? options : "(null)";
50 TRACE("Entering parse_options(%s)", options_str);
51
52 aaru_options parsed = {.compress = true,
53 .deduplicate = true,
54 .dictionary = 33554432,
55 .table_shift = -1,
56 .data_shift = 12,
57 .block_alignment = 9,
58 .md5 = false,
59 .sha1 = false,
60 .sha256 = false,
61 .blake3 = false,
62 .spamsum = false,
63 .zstd = false,
64 .zstd_level = 19,
65 .num_threads = 1};
66
67 if(options == NULL)
68 {
69 TRACE("Exiting parse_options() = {compress: %d, deduplicate: %d, dictionary: %u, table_shift: %d, "
70 "data_shift: %u, block_alignment: %u, md5: %d, sha1: %d, sha256: %d, blake3: %d, spamsum: %d, "
71 "zstd: %d, zstd_level: %d, num_threads: %d}",
72 parsed.compress, parsed.deduplicate, parsed.dictionary, parsed.table_shift, parsed.data_shift,
73 parsed.block_alignment, parsed.md5, parsed.sha1, parsed.sha256, parsed.blake3, parsed.spamsum,
74 parsed.zstd, parsed.zstd_level, parsed.num_threads);
75 return parsed;
76 }
77
78 char buffer[1024];
79 strncpy(buffer, options, sizeof(buffer));
80 buffer[sizeof(buffer) - 1] = '\0';
81
82 char *saveptr = NULL;
83 char *token = aaru_strtok_reentrant(buffer, ";", &saveptr);
84 while(token != NULL)
85 {
86 char *equal = strchr(token, '=');
87 if(equal)
88 {
89 *equal = '\0';
90 const char *key = token;
91 const char *value = equal + 1;
92
93 const bool bval = strncmp(value, "true", 4) == 0;
94
95 if(strncmp(key, "compress", 8) == 0)
96 parsed.compress = bval;
97 else if(strncmp(key, "deduplicate", 11) == 0)
98 parsed.deduplicate = bval;
99 else if(strncmp(key, "dictionary", 10) == 0)
100 {
101 parsed.dictionary = (uint32_t)strtoul(value, NULL, 10);
102 if(parsed.dictionary == 0) parsed.dictionary = 33554432;
103 }
104 else if(strncmp(key, "table_shift", 11) == 0)
105 {
106 errno = 0;
107 char *endptr = NULL;
108 long parsed_value = strtol(value, &endptr, 10);
109 if(errno == 0 && endptr != value)
110 {
111 if(parsed_value < INT8_MIN) parsed_value = INT8_MIN;
112 if(parsed_value > INT8_MAX) parsed_value = INT8_MAX;
113 parsed.table_shift = (int8_t)parsed_value;
114 *table_shift_found = true;
115 }
116 }
117 else if(strncmp(key, "data_shift", 10) == 0)
118 {
119 errno = 0;
120 char *endptr = NULL;
121 long parsed_value = strtol(value, &endptr, 10);
122 if(errno == 0 && endptr != value && parsed_value >= 0)
123 {
124 if(parsed_value > UINT8_MAX) parsed_value = UINT8_MAX;
125 parsed.data_shift = (uint8_t)parsed_value;
126 if(parsed.data_shift == 0) parsed.data_shift = 12;
127 }
128 }
129 else if(strncmp(key, "block_alignment", 15) == 0)
130 {
131 errno = 0;
132 char *endptr = NULL;
133 long parsed_value = strtol(value, &endptr, 10);
134 if(errno == 0 && endptr != value && parsed_value >= 0)
135 {
136 if(parsed_value > UINT8_MAX) parsed_value = UINT8_MAX;
137 parsed.block_alignment = (uint8_t)parsed_value;
138 if(parsed.block_alignment == 0) parsed.block_alignment = 9;
139 }
140 }
141 else if(strncmp(key, "md5", 3) == 0)
142 parsed.md5 = bval;
143 else if(strncmp(key, "sha1", 4) == 0)
144 parsed.sha1 = bval;
145 else if(strncmp(key, "sha256", 6) == 0)
146 parsed.sha256 = bval;
147 else if(strncmp(key, "blake3", 6) == 0)
148 parsed.blake3 = bval;
149 else if(strncmp(key, "spamsum", 7) == 0)
150 parsed.spamsum = bval;
151 else if(strncmp(key, "zstd_level", 10) == 0)
152 {
153 parsed.zstd_level = (int)strtol(value, NULL, 10);
154 if(parsed.zstd_level < 1) parsed.zstd_level = 1;
155 if(parsed.zstd_level > 22) parsed.zstd_level = 22;
156 }
157 else if(strncmp(key, "zstd", 4) == 0)
158 parsed.zstd = bval;
159 else if(strncmp(key, "threads", 7) == 0)
160 {
161 parsed.num_threads = (int)strtol(value, NULL, 10);
162 if(parsed.num_threads < 1) parsed.num_threads = 1;
163 }
164 }
165 token = aaru_strtok_reentrant(NULL, ";", &saveptr);
166 }
167
168 TRACE("Exiting parse_options() = {compress: %d, deduplicate: %d, dictionary: %u, table_shift: %d, "
169 "data_shift: %u, block_alignment: %u, md5: %d, sha1: %d, sha256: %d, blake3: %d, spamsum: %d, "
170 "zstd: %d, zstd_level: %d, num_threads: %d}",
171 parsed.compress, parsed.deduplicate, parsed.dictionary, parsed.table_shift, parsed.data_shift,
172 parsed.block_alignment, parsed.md5, parsed.sha1, parsed.sha256, parsed.blake3, parsed.spamsum,
173 parsed.zstd, parsed.zstd_level, parsed.num_threads);
174 return parsed;
175}
#define TRACE(fmt,...)
Definition log.h:25
static char * aaru_strtok_reentrant(char *str, const char *delim, char **saveptr)
Definition options.c:30
aaru_options parse_options(const char *options, bool *table_shift_found)
Parses the options string for AaruFormat image creation/opening.
Definition options.c:47
< For bool type used in aaru_options.
Parsed user-specified tunables controlling compression, deduplication, hashing and DDT geometry.
Definition options.h:220
bool zstd
Use Zstandard instead of LZMA for data blocks. Default: false.
Definition options.h:233
bool deduplicate
Storage dedup flag (DDT always exists).
Definition options.h:222
int zstd_level
Zstandard compression level (1-22). Default: 19.
Definition options.h:234
uint8_t data_shift
Global data shift: low bits encode sector offset inside a block (2^data_shift span).
Definition options.h:226
uint32_t dictionary
LZMA dictionary size in bytes (>= 4096 recommended). Default: 33554432 (32 MiB).
Definition options.h:224
bool compress
Enable adaptive compression (LZMA for data blocks, FLAC for audio). Default: true.
Definition options.h:221
bool sha256
Generate SHA-256 checksum (ChecksumAlgorithm::Sha256) when finalizing image.
Definition options.h:230
bool spamsum
Generate SpamSum fuzzy hash (ChecksumAlgorithm::SpamSum) if enabled.
Definition options.h:232
int8_t table_shift
DDT table shift (multi-level fan-out exponent). Default: heuristically calculated.
Definition options.h:225
int num_threads
Number of compression worker threads.
Definition options.h:235
bool md5
Generate MD5 checksum (ChecksumAlgorithm::Md5) when finalizing image.
Definition options.h:228
bool blake3
Generate BLAKE3 checksum if supported (not stored if algorithm unavailable).
Definition options.h:231
bool sha1
Generate SHA-1 checksum (ChecksumAlgorithm::Sha1) when finalizing image.
Definition options.h:229
uint8_t block_alignment
log2 underlying block alignment (2^n bytes). Default: 9 (512 bytes).
Definition options.h:227