From 327812ca96b7f9e6696af7e65cbd26de6aafe75a Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sun, 8 Feb 2026 08:46:06 +0100 Subject: [PATCH] Harden pointer head writes against ENOENT races --- src/adapters/asl_pointer_fs/asl_pointer_fs.c | 34 ++++++++++++++------ 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/adapters/asl_pointer_fs/asl_pointer_fs.c b/src/adapters/asl_pointer_fs/asl_pointer_fs.c index 2b3d1be..77cd140 100644 --- a/src/adapters/asl_pointer_fs/asl_pointer_fs.c +++ b/src/adapters/asl_pointer_fs/asl_pointer_fs.c @@ -471,6 +471,7 @@ static amduat_asl_pointer_error_t amduat_asl_pointer_write_head( const amduat_reference_t *prev_ref, bool has_prev) { char *tmp_path; + char *parent_dir = NULL; size_t tmp_len; int tmp_fd; FILE *fp; @@ -511,9 +512,22 @@ static amduat_asl_pointer_error_t amduat_asl_pointer_write_head( free((void *)prev_bytes.data); return AMDUAT_ASL_POINTER_ERR_IO; } + parent_dir = amduat_asl_pointer_parent_dir(path); + if (parent_dir == NULL || !amduat_asl_pointer_ensure_directory(parent_dir)) { + free(parent_dir); + free(tmp_path); + free((void *)ref_bytes.data); + free((void *)prev_bytes.data); + return AMDUAT_ASL_POINTER_ERR_IO; + } snprintf(tmp_path, tmp_len, "%s.tmp.XXXXXX", path); tmp_fd = mkstemp(tmp_path); + if (tmp_fd < 0 && errno == ENOENT && + amduat_asl_pointer_ensure_directory(parent_dir)) { + tmp_fd = mkstemp(tmp_path); + } if (tmp_fd < 0) { + free(parent_dir); free(tmp_path); free((void *)ref_bytes.data); free((void *)prev_bytes.data); @@ -575,23 +589,25 @@ static amduat_asl_pointer_error_t amduat_asl_pointer_write_head( } if (err == AMDUAT_ASL_POINTER_OK && rename(tmp_path, path) != 0) { - err = AMDUAT_ASL_POINTER_ERR_IO; + if (errno == ENOENT && amduat_asl_pointer_ensure_directory(parent_dir) && + rename(tmp_path, path) == 0) { + /* Recovered after recreating parent directory. */ + } else { + err = AMDUAT_ASL_POINTER_ERR_IO; + } } if (err == AMDUAT_ASL_POINTER_OK) { - char *parent_dir = amduat_asl_pointer_parent_dir(path); - if (parent_dir != NULL) { - if (!amduat_asl_pointer_fsync_directory(parent_dir)) { - amduat_log(AMDUAT_LOG_WARN, - "pointer fsync dir failed for %s", parent_dir); - err = AMDUAT_ASL_POINTER_ERR_IO; - } - free(parent_dir); + if (!amduat_asl_pointer_fsync_directory(parent_dir)) { + amduat_log(AMDUAT_LOG_WARN, + "pointer fsync dir failed for %s", parent_dir); + err = AMDUAT_ASL_POINTER_ERR_IO; } } if (err != AMDUAT_ASL_POINTER_OK) { (void)remove(tmp_path); } + free(parent_dir); free(tmp_path); free((void *)ref_bytes.data); free((void *)prev_bytes.data);