Insert generated config fields before blank section separators
This commit is contained in:
1 parent
41930a35c4
commit
f9ccca85bb
3 files changed
+50
-4
No files matched your search
@@ -73,9 +73,10 @@ static int config_field_line(char *line, int *section, const struct config_field
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Собрать последние текстовые значения и конец последней секции каждого вида. */
|
||||
/* Собрать последние значения и точку вставки до завершающих пустых строк каждой секции. */
|
||||
static void config_scan(const char *text, size_t length, struct config_field fields[CFG_FIELD_COUNT], size_t ends[CFG_SECTION_COUNT]) {
|
||||
int section = CFG_OTHER_SECTION;
|
||||
size_t content_end = 0;
|
||||
for (int i = 0; i < CFG_SECTION_COUNT; i++) ends[i] = SIZE_MAX;
|
||||
for (size_t pos = 0; pos < length;) {
|
||||
const char *nl = memchr(text + pos, '\n', length - pos);
|
||||
@@ -84,7 +85,8 @@ static void config_scan(const char *text, size_t length, struct config_field fie
|
||||
memcpy(line, text + pos, end - pos); line[end - pos] = '\0';
|
||||
char *start = line;
|
||||
while (isspace((unsigned char)*start)) start++;
|
||||
if (*start == '[') ends[section] = pos;
|
||||
int nonempty = *start != '\0';
|
||||
if (*start == '[') ends[section] = content_end;
|
||||
int index = config_field_line(line, §ion, fields, value);
|
||||
if (index >= 0) {
|
||||
strcpy(fields[index].value, value); fields[index].present = 1;
|
||||
@@ -100,9 +102,10 @@ static void config_scan(const char *text, size_t length, struct config_field fie
|
||||
strcasecmp(value, "false") && strcasecmp(value, "true")) fields[index].invalid = 1;
|
||||
} else if (config_ini_hex(value, NULL, SC_PRIVKEY_SIZE)) fields[index].invalid = 1;
|
||||
}
|
||||
if (nonempty) content_end = end;
|
||||
pos = end;
|
||||
}
|
||||
ends[section] = length;
|
||||
ends[section] = content_end;
|
||||
}
|
||||
|
||||
/* Вставить отсутствующие поля в нужную секцию, при необходимости создать заголовок. */
|
||||
@@ -117,6 +120,7 @@ static int config_insert_missing(struct strbuf *output, const struct config_fiel
|
||||
started = 1;
|
||||
}
|
||||
if (strbuf_addf(output, "%s=%s%s", fields[i].key, fields[i].value, eol) < 0) return -1;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "inserted [%s] %s before section separator", config_section_names[section], fields[i].key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ HEX проверяется посимвольно до декодировани
|
||||
Корректная итоговая идентичность/REALITY не меняется и не генерируется заново только из-за раннего дубля.
|
||||
Файл без таких ошибок остаётся побайтно неизменным. Если поле требует исправления,
|
||||
обновляются все его вхождения в соответствующих секциях. Недостающие поля добавляются
|
||||
в конец последней подходящей секции; отсутствующая секция создаётся в конце файла.
|
||||
в конец последней подходящей секции, перед её завершающими пустыми строками.
|
||||
Разделитель перед следующей секцией остаётся после добавленных полей; пробелы и CRLF в нём сохраняются.
|
||||
Отсутствующая секция создаётся в конце файла.
|
||||
|
||||
Посторонние строки сохраняются побайтно. В изменяемых строках сохраняются пробелы,
|
||||
комментарии и окончания строк вокруг заменяемого значения. Добавляемые строки используют
|
||||
|
||||
@@ -367,6 +367,45 @@ static void test_allocation_failures(void) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS allocation failures: every allocation, original bytes and resource balance");
|
||||
}
|
||||
|
||||
/* Недостающие поля остаются в блоке; исходные пустые строки продолжают отделять секции. */
|
||||
static void test_insertion_before_separator(void) {
|
||||
const struct { const char *input, *anchor, *first, *last, *suffix; } cases[] = {
|
||||
{"[chatserver]\nstorage_autoload=1\n\n[gui]\nutun_enabled=no\n",
|
||||
"storage_autoload=1", "add_key=", "add_key=", "\n[gui]\nutun_enabled=no\n"},
|
||||
{"[chatserver]\nstorage_autoload=1\n\n\n",
|
||||
"storage_autoload=1", "add_key=", "add_key=", "\n\n"},
|
||||
{"[chatserver]\n\n[gui]\nutun_enabled=no\n",
|
||||
"[chatserver]", "add_key=", "add_key=", "\n[gui]\nutun_enabled=no\n"},
|
||||
{"[chatserver]\nstorage_autoload=0\n\n[chatserver]\nstorage_autoload=1\n\n[gui]\nutun_enabled=no\n",
|
||||
"storage_autoload=1", "add_key=", "add_key=", "\n[gui]\nutun_enabled=no\n"},
|
||||
{"[chatserver]\nstorage_autoload=1\n \t\n\n[gui]\nutun_enabled=no\n",
|
||||
"storage_autoload=1", "add_key=", "add_key=", " \t\n\n[gui]\nutun_enabled=no\n"},
|
||||
{"[global]\nmy_private_key=%s\n\n[gui]\nutun_enabled=no\n",
|
||||
"my_private_key=", "my_public_key=", "my_node_id=", "\n[gui]\nutun_enabled=no\n"},
|
||||
{"[reality]\nenabled=1\n\n[gui]\nutun_enabled=no\n",
|
||||
"enabled=1", "private_key=", "short_ids=", "\n[gui]\nutun_enabled=no\n"}
|
||||
};
|
||||
for (int crlf = 0; crlf < 2; crlf++) for (size_t i = 0; i < sizeof(cases) / sizeof(*cases); i++) {
|
||||
char plain[2048], input[4096], suffix[4096], after[8192], unchanged[8192];
|
||||
snprintf(plain, sizeof(plain), cases[i].input, private_hex);
|
||||
size_t pos = 0;
|
||||
for (const char* p = plain; *p; p++) { if (crlf && *p == '\n') input[pos++] = '\r'; input[pos++] = *p; }
|
||||
input[pos] = 0; pos = 0;
|
||||
for (const char* p = cases[i].suffix; *p; p++) { if (crlf && *p == '\n') suffix[pos++] = '\r'; suffix[pos++] = *p; }
|
||||
suffix[pos] = 0;
|
||||
const char* eol = crlf ? "\r\n" : "\n";
|
||||
write_text(input); assert(!config_ensure_keys_and_node_id(path)); read_text(after, sizeof(after));
|
||||
const char* anchor = strstr(after, cases[i].anchor); assert(anchor);
|
||||
const char* first = strstr(anchor, cases[i].first);
|
||||
assert(first && first == strstr(anchor, eol) + strlen(eol));
|
||||
const char* last = strstr(first, cases[i].last); assert(last);
|
||||
const char* end = strstr(last, eol); assert(end);
|
||||
assert(!strncmp(end + strlen(eol), suffix, strlen(suffix)));
|
||||
assert(!config_ensure_keys_and_node_id(path)); read_text(unchanged, sizeof(unchanged)); assert(!strcmp(after, unchanged));
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS field insertion: 14 LF/CRLF separator, EOF, empty/repeated section and stable-repeat cases");
|
||||
}
|
||||
|
||||
static void test_server_key(void) {
|
||||
char before[8192], after[8192]; uint8_t key[32];
|
||||
write_text("[chatserver]\n# server credential\n");
|
||||
@@ -401,6 +440,7 @@ int main(void) {
|
||||
test_reality_and_validation();
|
||||
test_failures();
|
||||
test_allocation_failures();
|
||||
test_insertion_before_separator();
|
||||
test_server_key();
|
||||
assert(!unlink(path) && !rmdir(directory));
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS config updater regression suite");
|
||||
|
||||
Reference in new issue
Block a user