19#define native_backup_restore_strdup _strdup
21#define native_backup_restore_strdup strdup
26 if (backend == NULL || backend[0] ==
'\0') {
36 if (db_path != NULL && db_path[0] !=
'\0') {
40 snprintf(buffer,
sizeof(buffer),
"/var/lib/pharos/%s.sqlite3", app != NULL && app->
app_id != NULL ? app->
app_id :
"app");
45 char *app_conf = NULL;
46 char *pharos_conf = NULL;
47 if (app_root == NULL) {
50 app_conf =
path_join(app_root,
"app.conf");
55 pharos_conf =
path_join(app_root,
"pharos.conf");
56 if (pharos_conf != NULL &&
path_exists(pharos_conf)) {
65 char *raw_value = NULL;
66 char *resolved = NULL;
67 char *conf_dir = NULL;
68 if (conf_path == NULL || key == NULL) {
73 if (raw_value == NULL || raw_value[0] ==
'\0') {
79 if (conf_dir != NULL) {
89 char *app_value = NULL;
90 char *runtime_value = NULL;
91 char *fallback = NULL;
92 if (app != NULL && app->
app_root != NULL) {
94 if (app_value != NULL && app_value[0] !=
'\0') {
100 if (runtime_value != NULL && runtime_value[0] !=
'\0') {
101 return runtime_value;
110 time_t now = time(NULL);
113 gmtime_s(&tm_now, &now);
115 gmtime_r(&now, &tm_now);
117 if (strftime(buffer,
sizeof(buffer),
"%Y%m%dT%H%M%SZ", &tm_now) == 0) {
129 if (text == NULL || key == NULL) {
130 return fallback_value;
132 snprintf(pattern,
sizeof(pattern),
"\"%s\"", key);
133 cursor = strstr(text, pattern);
134 if (cursor == NULL) {
135 return fallback_value;
137 colon = strchr(cursor + strlen(pattern),
':');
139 return fallback_value;
142 while (*colon ==
' ' || *colon ==
'\t' || *colon ==
'\r' || *colon ==
'\n') {
145 value = strtol(colon, &endptr, 10);
146 if (endptr == colon) {
147 return fallback_value;
153 char *manifest_path = NULL;
154 char *manifest_text = NULL;
155 char *relative_path = NULL;
156 char *resolved = NULL;
157 if (app == NULL || app->
app_root == NULL) {
161 if (manifest_path == NULL || !
path_exists(manifest_path)) {
166 if (manifest_text == NULL) {
171 if (relative_path != NULL && relative_path[0] !=
'\0') {
182 long schema_version = 0;
183 if (migration_fixture_path == NULL || !
path_exists(migration_fixture_path)) {
187 if (fixture_text == NULL) {
192 return schema_version;
203 char *metadata_text = NULL;
205 if (metadata_path == NULL || !
path_exists(metadata_path)) {
209 if (metadata_text == NULL) {
218 char *backend = NULL;
219 char *base_dir = NULL;
220 char *timestamp = NULL;
221 char *target_dir = NULL;
222 char *backup_dir_path = NULL;
223 char *state_backup_path = NULL;
224 char *metadata_path = NULL;
225 char *sqlite_db_path = NULL;
226 char *sqlite_snapshot_path = NULL;
227 char *migration_fixture = NULL;
228 char *migration_fixture_json = NULL;
229 char *target_id_json = NULL;
230 char *backend_json = NULL;
231 char *backup_dir_json = NULL;
232 char *metadata_path_json = NULL;
233 char *state_path_json = NULL;
234 char *sqlite_snapshot_path_json = NULL;
235 char *schema_json = NULL;
236 char *metadata_json = NULL;
238 long schema_version = 0;
239 size_t metadata_needed;
242 if (error_out != NULL) {
245 if (config == NULL || app == NULL || config->
target_id == NULL) {
246 if (error_out != NULL) {
253 if (backend == NULL || !
streq(backend,
"sqlite")) {
255 if (error_out != NULL) {
264 backup_dir_path =
path_join(target_dir, timestamp);
265 state_backup_path =
path_join(backup_dir_path,
"state.json");
266 metadata_path =
path_join(backup_dir_path,
"metadata.json");
268 sqlite_snapshot_path =
path_join(backup_dir_path,
"database.sqlite3");
272 if (base_dir == NULL || timestamp == NULL || target_dir == NULL || backup_dir_path == NULL || state_backup_path == NULL || metadata_path == NULL || sqlite_db_path == NULL || sqlite_snapshot_path == NULL) {
273 if (error_out != NULL) {
279 if (error_out != NULL) {
285 if (error_out != NULL) {
291 if (error_out != NULL) {
297 if (error_out != NULL) {
311 if (migration_fixture_json == NULL || schema_json == NULL || target_id_json == NULL || backend_json == NULL || backup_dir_json == NULL || metadata_path_json == NULL || state_path_json == NULL || sqlite_snapshot_path_json == NULL) {
312 if (error_out != NULL) {
318 metadata_needed = strlen(schema_json) + strlen(target_id_json) + strlen(backend_json) + strlen(timestamp) + strlen(state_path_json) + strlen(sqlite_snapshot_path_json) + strlen(migration_fixture_json) + 256;
319 metadata_json = (
char *)malloc(metadata_needed);
320 if (metadata_json == NULL) {
321 if (error_out != NULL) {
326 snprintf(metadata_json, metadata_needed,
"{\"schema\":\"pharos.backup.bundle.v1\",\"target_kind\":\"app\",\"target_id\":%s,\"backend\":%s,\"environment\":\"development\",\"created_at\":\"%s\",\"schema_version\":%ld,\"migration_fixture\":%s,\"artifacts\":{\"state_json\":%s,\"sqlite_snapshot\":%s}}", target_id_json, backend_json, timestamp, schema_version, migration_fixture_json, state_path_json, sqlite_snapshot_path_json);
328 if (error_out != NULL) {
334 needed = strlen(target_id_json) + strlen(backend_json) + strlen(backup_dir_json) + strlen(metadata_path_json) + strlen(state_path_json) + strlen(sqlite_snapshot_path_json) + 192;
335 result = (
char *)malloc(needed);
336 if (result != NULL) {
337 snprintf(result, needed,
"{\"report_id\":\"pharos-backup-v1\",\"target_kind\":\"app\",\"target_id\":%s,\"backend\":%s,\"status\":\"backed_up\",\"backup_dir\":%s,\"metadata_path\":%s,\"state_path\":%s,\"sqlite_snapshot\":%s}", target_id_json, backend_json, backup_dir_json, metadata_path_json, state_path_json, sqlite_snapshot_path_json);
339 if (result == NULL && error_out != NULL) {
348 free(backup_dir_path);
349 free(state_backup_path);
351 free(sqlite_db_path);
352 free(sqlite_snapshot_path);
353 free(migration_fixture);
354 free(migration_fixture_json);
355 free(target_id_json);
357 free(backup_dir_json);
358 free(metadata_path_json);
359 free(state_path_json);
360 free(sqlite_snapshot_path_json);
367 char *backend = NULL;
368 char *metadata_path = NULL;
369 char *state_path = NULL;
370 char *sqlite_snapshot_path = NULL;
371 char *metadata_snapshot_value = NULL;
372 char *metadata_state_value = NULL;
373 char *sqlite_db_path = NULL;
374 char *db_parent = NULL;
375 char *tmp_db_path = NULL;
376 char *target_id_json = NULL;
377 char *backend_json = NULL;
378 char *input_dir_json = NULL;
382 if (error_out != NULL) {
385 if (config == NULL || app == NULL || config->
target_id == NULL) {
386 if (error_out != NULL) {
391 if (input_dir == NULL || input_dir[0] ==
'\0') {
392 if (error_out != NULL) {
399 if (backend == NULL || !
streq(backend,
"sqlite")) {
401 if (error_out != NULL) {
407 metadata_path =
path_join(input_dir,
"metadata.json");
408 state_path =
path_join(input_dir,
"state.json");
411 sqlite_snapshot_path = metadata_snapshot_value != NULL && metadata_snapshot_value[0] !=
'\0' ? metadata_snapshot_value :
path_join(input_dir,
"database.sqlite3");
412 metadata_snapshot_value = NULL;
415 tmp_db_path = sqlite_db_path != NULL ? (
char *)malloc(strlen(sqlite_db_path) + 16) : NULL;
417 if (metadata_path == NULL || sqlite_db_path == NULL || db_parent == NULL || tmp_db_path == NULL) {
418 if (error_out != NULL) {
423 snprintf(tmp_db_path, strlen(sqlite_db_path) + 16,
"%s.restore.tmp", sqlite_db_path);
425 if (error_out != NULL) {
430 if (sqlite_snapshot_path == NULL || !
path_exists(sqlite_snapshot_path)) {
431 if (error_out != NULL) {
437 if (error_out != NULL) {
443 if (error_out != NULL) {
448 if (rename(tmp_db_path, sqlite_db_path) != 0) {
449 if (error_out != NULL) {
455 const char *state_source = metadata_state_value != NULL && metadata_state_value[0] !=
'\0' ? metadata_state_value : state_path;
456 if (state_source != NULL &&
path_exists(state_source)) {
464 if (target_id_json == NULL || backend_json == NULL || input_dir_json == NULL) {
465 if (error_out != NULL) {
470 needed = strlen(target_id_json) + strlen(backend_json) + strlen(input_dir_json) + 128;
471 result = (
char *)malloc(needed);
472 if (result != NULL) {
473 snprintf(result, needed,
"{\"report_id\":\"pharos-restore-v1\",\"target_kind\":\"app\",\"target_id\":%s,\"backend\":%s,\"input_dir\":%s,\"status\":\"restored\"}", target_id_json, backend_json, input_dir_json);
475 if (result == NULL && error_out != NULL) {
483 free(sqlite_snapshot_path);
484 free(metadata_snapshot_value);
485 free(metadata_state_value);
486 free(sqlite_db_path);
489 free(target_id_json);
491 free(input_dir_json);
char * json_string_dup_native(const char *value)
Duplicates a string while escaping it for JSON string output.
Declares helpers that build native artifact and report payload strings.
static char * native_metadata_artifact_value(const char *metadata_path, const char *key)
#define native_backup_restore_strdup
char * build_native_restore_report_local_json(const ServeConfig *config, const AppRuntime *app, const char *backend_override, const char *input_dir, char **error_out)
Builds a JSON report describing a native app restore operation.
static char * native_backup_timestamp_utc(void)
char * build_native_backup_report_local_json(const ServeConfig *config, const AppRuntime *app, const char *backend_override, const char *output_dir_override, char **error_out)
Builds a JSON report describing a native app backup operation.
static char * native_default_backend_local(const AppRuntime *app)
static char * native_migration_fixture_path(const AppRuntime *app)
static long native_json_top_level_long(const char *text, const char *key, long fallback_value)
static char * native_app_conf_path(const char *app_root)
static char * native_default_sqlite_path_local(const AppRuntime *app)
static int native_write_backup_state_snapshot(const AppRuntime *app, const char *output_path)
static long native_migration_schema_version(const char *migration_fixture_path)
static char * native_backup_base_dir(const AppRuntime *app)
static char * native_app_conf_value_path(const char *app_root, const char *key)
Declares native backup and restore report builders.
int ensure_directory(const char *path)
Creates a directory path and any missing parent directories.
int write_text_file(const char *path, const char *content)
Writes a text buffer to a file path.
int copy_file_binary(const char *source_path, const char *target_path)
Copies one file as binary data.
Declares native filesystem helper routines.
char * conf_lookup_value(const char *path, const char *key)
Reads a Pharos conf file and looks up one key.
char * json_find_string_in_section(const char *text, const char *section, const char *key)
Finds a JSON string value for a key inside a named section object.
Declares lightweight JSON and conf value lookup helpers.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
int streq(const char *a, const char *b)
Tests whether two strings are exactly equal.
char * path_dirname(const char *path)
Returns the parent directory component of a path.
char * resolve_relative_to(const char *base_dir, const char *value)
Resolves a path value relative to a base directory when needed.
char * read_file_text(const char *path)
Reads an entire file into a newly allocated text buffer.
int path_exists(const char *path)
Tests whether a filesystem path currently exists.
Declares shared low-level support helpers used across the Pharos native runtime.
Loaded runtime metadata for one Pharos app artifact.
Parsed native serve configuration used to bootstrap the runtime listener.