Harden pointer head writes against ENOENT races
This commit is contained in:
parent
03d970c576
commit
327812ca96
|
|
@ -471,6 +471,7 @@ static amduat_asl_pointer_error_t amduat_asl_pointer_write_head(
|
||||||
const amduat_reference_t *prev_ref,
|
const amduat_reference_t *prev_ref,
|
||||||
bool has_prev) {
|
bool has_prev) {
|
||||||
char *tmp_path;
|
char *tmp_path;
|
||||||
|
char *parent_dir = NULL;
|
||||||
size_t tmp_len;
|
size_t tmp_len;
|
||||||
int tmp_fd;
|
int tmp_fd;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
@ -511,9 +512,22 @@ static amduat_asl_pointer_error_t amduat_asl_pointer_write_head(
|
||||||
free((void *)prev_bytes.data);
|
free((void *)prev_bytes.data);
|
||||||
return AMDUAT_ASL_POINTER_ERR_IO;
|
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);
|
snprintf(tmp_path, tmp_len, "%s.tmp.XXXXXX", path);
|
||||||
tmp_fd = mkstemp(tmp_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) {
|
if (tmp_fd < 0) {
|
||||||
|
free(parent_dir);
|
||||||
free(tmp_path);
|
free(tmp_path);
|
||||||
free((void *)ref_bytes.data);
|
free((void *)ref_bytes.data);
|
||||||
free((void *)prev_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) {
|
if (err == AMDUAT_ASL_POINTER_OK && rename(tmp_path, path) != 0) {
|
||||||
|
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;
|
err = AMDUAT_ASL_POINTER_ERR_IO;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (err == AMDUAT_ASL_POINTER_OK) {
|
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)) {
|
if (!amduat_asl_pointer_fsync_directory(parent_dir)) {
|
||||||
amduat_log(AMDUAT_LOG_WARN,
|
amduat_log(AMDUAT_LOG_WARN,
|
||||||
"pointer fsync dir failed for %s", parent_dir);
|
"pointer fsync dir failed for %s", parent_dir);
|
||||||
err = AMDUAT_ASL_POINTER_ERR_IO;
|
err = AMDUAT_ASL_POINTER_ERR_IO;
|
||||||
}
|
}
|
||||||
free(parent_dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (err != AMDUAT_ASL_POINTER_OK) {
|
if (err != AMDUAT_ASL_POINTER_OK) {
|
||||||
(void)remove(tmp_path);
|
(void)remove(tmp_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(parent_dir);
|
||||||
free(tmp_path);
|
free(tmp_path);
|
||||||
free((void *)ref_bytes.data);
|
free((void *)ref_bytes.data);
|
||||||
free((void *)prev_bytes.data);
|
free((void *)prev_bytes.data);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue