Just ensuring individual config files are written atomically is good enough
to keep internal consistency, but we want to make sure directory metadata
is also synced to disk when returning from functions that expect the changes
to have been made permanent, such as meshlink_import() and
meshlink_blacklist(). Also do this when we create the initial directory
structure.
We already took care of syncing directory metadata when rotating keys for
encrypted storage.
if(fd < 0) {
logger(NULL, MESHLINK_ERROR, "Failed to open %s: %s\n", pathname, strerror(errno));
if(fd < 0) {
logger(NULL, MESHLINK_ERROR, "Failed to open %s: %s\n", pathname, strerror(errno));
+ meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
if(fsync(fd)) {
logger(NULL, MESHLINK_ERROR, "Failed to sync %s: %s\n", pathname, strerror(errno));
close(fd);
return false;
}
if(fsync(fd)) {
logger(NULL, MESHLINK_ERROR, "Failed to sync %s: %s\n", pathname, strerror(errno));
close(fd);
+ meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
if(close(fd)) {
logger(NULL, MESHLINK_ERROR, "Failed to close %s: %s\n", pathname, strerror(errno));
close(fd);
return false;
}
if(close(fd)) {
logger(NULL, MESHLINK_ERROR, "Failed to close %s: %s\n", pathname, strerror(errno));
close(fd);
+ meshlink_errno = MESHLINK_ESTORAGE;
return rename(old_path, new_path) == 0;
}
return rename(old_path, new_path) == 0;
}
+bool config_sync(meshlink_handle_t *mesh, const char *conf_subdir) {
+ if(!mesh->confbase) {
+ return true;
+ }
+
+ if(!conf_subdir) {
+ return false;
+ }
+
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "%s" SLASH "%s" SLASH "hosts", mesh->confbase, conf_subdir);
+
+ if(!sync_path(path)) {
+ return false;
+ }
+
+ snprintf(path, sizeof(path), "%s" SLASH "%s", mesh->confbase, conf_subdir);
+
+ if(!sync_path(path)) {
+ return false;
+ }
+
+ return true;
+}
+
bool meshlink_confbase_exists(meshlink_handle_t *mesh) {
if(!mesh->confbase) {
return false;
bool meshlink_confbase_exists(meshlink_handle_t *mesh) {
if(!mesh->confbase) {
return false;
extern bool config_destroy(const char *confbase, const char *conf_subdir);
extern bool config_copy(struct meshlink_handle *mesh, const char *src_dir_name, const void *src_key, const char *dst_dir_name, const void *dst_key);
extern bool config_rename(struct meshlink_handle *mesh, const char *old_conf_subdir, const char *new_conf_subdir);
extern bool config_destroy(const char *confbase, const char *conf_subdir);
extern bool config_copy(struct meshlink_handle *mesh, const char *src_dir_name, const void *src_key, const char *dst_dir_name, const void *dst_key);
extern bool config_rename(struct meshlink_handle *mesh, const char *old_conf_subdir, const char *new_conf_subdir);
+extern bool config_sync(struct meshlink_handle *mesh, const char *conf_subdir);
extern bool main_config_exists(struct meshlink_handle *mesh, const char *conf_subdir);
extern bool main_config_lock(struct meshlink_handle *mesh);
extern bool main_config_exists(struct meshlink_handle *mesh, const char *conf_subdir);
extern bool main_config_lock(struct meshlink_handle *mesh);
+ /* Ensure the configuration directory metadata is on disk */
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
sptps_send_record(&(mesh->sptps), 1, ecdsa_get_public_key(mesh->private_key), 32);
logger(mesh, MESHLINK_DEBUG, "Configuration stored in: %s\n", mesh->confbase);
sptps_send_record(&(mesh->sptps), 1, ecdsa_get_public_key(mesh->private_key), 32);
logger(mesh, MESHLINK_DEBUG, "Configuration stored in: %s\n", mesh->confbase);
+ /* Ensure the configuration directory metadata is on disk */
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
if(!main_config_lock(mesh)) {
logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
meshlink_errno = MESHLINK_ESTORAGE;
if(!main_config_lock(mesh)) {
logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
meshlink_errno = MESHLINK_ESTORAGE;
+ if(!config_sync(mesh, "current")) {
+ return false;
+ }
+
n->status.blacklisted = true;
node_write_config(mesh, n);
n->status.blacklisted = true;
node_write_config(mesh, n);
+ config_sync(mesh, "current");
+
logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
//Immediately terminate any connections we have with the blacklisted node
logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
//Immediately terminate any connections we have with the blacklisted node
n->status.blacklisted = false;
node_write_config(mesh, n);
n->status.blacklisted = false;
node_write_config(mesh, n);
+ config_sync(mesh, "current");
pthread_mutex_unlock(&(mesh->mesh_mutex));
return;
pthread_mutex_unlock(&(mesh->mesh_mutex));
return;