feat(flatfile): warn on missing or mismatched log format-version
This commit is contained in:
@@ -205,6 +205,15 @@ _ff_state_build(ff_contact_state_t* state)
|
|||||||
|
|
||||||
state->bom_len = ff_skip_bom(fp);
|
state->bom_len = ff_skip_bom(fp);
|
||||||
|
|
||||||
|
int file_version = ff_read_format_version(fp);
|
||||||
|
if (file_version == 0) {
|
||||||
|
log_warning("flatfile: %s has no format-version marker, expected %d",
|
||||||
|
state->filepath, FLATFILE_FORMAT_VERSION);
|
||||||
|
} else if (file_version != FLATFILE_FORMAT_VERSION) {
|
||||||
|
log_warning("flatfile: %s format-version %d does not match expected %d",
|
||||||
|
state->filepath, file_version, FLATFILE_FORMAT_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
state->n_entries = 0;
|
state->n_entries = 0;
|
||||||
state->total_lines = 0;
|
state->total_lines = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,13 @@
|
|||||||
|
|
||||||
// --- Constants ---
|
// --- Constants ---
|
||||||
|
|
||||||
#define DIR_FLATLOG "flatlog"
|
#define DIR_FLATLOG "flatlog"
|
||||||
#define FLATFILE_HEADER "# profanity chat log — UTF-8, LF line endings\n# vim: set fileencoding=utf-8 fileformat=unix :\n"
|
#define FLATFILE_FORMAT_VERSION 1
|
||||||
|
#define FF_VERSION_PREFIX "# format-version: "
|
||||||
|
#define FLATFILE_HEADER \
|
||||||
|
"# profanity chat log — UTF-8, LF line endings\n" \
|
||||||
|
"# format-version: 1\n" \
|
||||||
|
"# vim: set fileencoding=utf-8 fileformat=unix :\n"
|
||||||
#define FF_MAX_LINE_LEN (10 * 1024 * 1024) /* 10 MB — reject lines longer than this */
|
#define FF_MAX_LINE_LEN (10 * 1024 * 1024) /* 10 MB — reject lines longer than this */
|
||||||
#define FF_MAX_LMC_DEPTH 100 /* max correction chain depth */
|
#define FF_MAX_LMC_DEPTH 100 /* max correction chain depth */
|
||||||
|
|
||||||
@@ -125,6 +130,11 @@ char* ff_unescape_meta_value(const char* val);
|
|||||||
// Skip UTF-8 BOM if present; returns 3 if skipped, 0 otherwise.
|
// Skip UTF-8 BOM if present; returns 3 if skipped, 0 otherwise.
|
||||||
int ff_skip_bom(FILE* fp);
|
int ff_skip_bom(FILE* fp);
|
||||||
|
|
||||||
|
// Scan leading '#' comment lines for the format-version marker. Returns
|
||||||
|
// the version found, 0 if no marker is present, or -1 on read error.
|
||||||
|
// File position is rewound to the start of the comment block on entry.
|
||||||
|
int ff_read_format_version(FILE* fp);
|
||||||
|
|
||||||
char* ff_readline(FILE* fp, gboolean* truncated);
|
char* ff_readline(FILE* fp, gboolean* truncated);
|
||||||
void ff_write_line(FILE* fp, const char* timestamp, const char* type, const char* enc,
|
void ff_write_line(FILE* fp, const char* timestamp, const char* type, const char* enc,
|
||||||
const char* stanza_id, const char* archive_id, const char* replace_id,
|
const char* stanza_id, const char* archive_id, const char* replace_id,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -338,6 +339,49 @@ ff_skip_bom(FILE* fp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format-version helper
|
||||||
|
// =========================================================================
|
||||||
|
//
|
||||||
|
// Scan leading '#' comment lines for `# format-version: <N>`. Stops at
|
||||||
|
// the first non-comment line or after FF_VERSION_SCAN_MAX comments.
|
||||||
|
// Restores fp to its position at entry, so callers can re-parse the
|
||||||
|
// header normally afterwards.
|
||||||
|
#define FF_VERSION_SCAN_MAX 16
|
||||||
|
|
||||||
|
int
|
||||||
|
ff_read_format_version(FILE* fp)
|
||||||
|
{
|
||||||
|
long start = ftell(fp);
|
||||||
|
if (start < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
|
size_t prefix_len = strlen(FF_VERSION_PREFIX);
|
||||||
|
|
||||||
|
for (int i = 0; i < FF_VERSION_SCAN_MAX; i++) {
|
||||||
|
gboolean truncated = FALSE;
|
||||||
|
char* line = ff_readline(fp, &truncated);
|
||||||
|
if (!line)
|
||||||
|
break;
|
||||||
|
if (line[0] != '#') {
|
||||||
|
free(line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp(line, FF_VERSION_PREFIX, prefix_len) == 0) {
|
||||||
|
char* endptr = NULL;
|
||||||
|
long v = strtol(line + prefix_len, &endptr, 10);
|
||||||
|
if (endptr != line + prefix_len && v > 0 && v <= INT_MAX)
|
||||||
|
version = (int)v;
|
||||||
|
free(line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, start, SEEK_SET);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
// Readline helper
|
// Readline helper
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user