HelenOS sources
This source file includes following definitions.
- vol_volume_new
- vol_volume_delete
- vol_volumes_create
- vol_volumes_merge_to
- vol_volumes_sync
- vol_volumes_destroy
- vol_volume_add_locked
- vol_volume_lookup_ref_locked
- vol_volume_lookup_ref
- vol_volume_find_by_id_ref_locked
- vol_volume_find_by_id_ref
- vol_volume_is_persist
- vol_volume_del_ref
- vol_volume_set_mountp
- vol_get_ids
- vol_volumes_load
- vol_volumes_save
- vol_volume_get_info
#include <adt/list.h>
#include <errno.h>
#include <fibril_synch.h>
#include <io/log.h>
#include <sif.h>
#include <stdbool.h>
#include <stdlib.h>
#include <str.h>
#include "volume.h"
#include "types/volume.h"
static void vol_volume_delete(vol_volume_t *);
static void vol_volume_add_locked(vol_volumes_t *, vol_volume_t *);
static errno_t vol_volume_lookup_ref_locked(vol_volumes_t *, const char *,
vol_volume_t **);
static errno_t vol_volumes_load(sif_node_t *, vol_volumes_t *);
static errno_t vol_volumes_save(vol_volumes_t *, sif_node_t *);
static vol_volume_t *vol_volume_new(void)
{
vol_volume_t *volume = calloc(1, sizeof(vol_volume_t));
if (volume == NULL) {
log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating volume "
"structure. Out of memory.");
return NULL;
}
volume->label = str_dup("");
volume->mountp = str_dup("");
if (volume->label == NULL || volume->mountp == NULL) {
vol_volume_delete(volume);
return NULL;
}
refcount_init(&volume->refcnt);
link_initialize(&volume->lvolumes);
volume->volumes = NULL;
return volume;
}
static void vol_volume_delete(vol_volume_t *volume)
{
log_msg(LOG_DEFAULT, LVL_DEBUG, "Freeing volume %p", volume);
free(volume->label);
free(volume->mountp);
free(volume);
}
errno_t vol_volumes_create(const char *cfg_path,
vol_volumes_t **rvolumes)
{
vol_volumes_t *volumes;
sif_doc_t *doc = NULL;
sif_node_t *node;
sif_node_t *nvolumes;
const char *ntype;
errno_t rc;
volumes = calloc(1, sizeof(vol_volumes_t));
if (volumes == NULL)
return ENOMEM;
volumes->cfg_path = str_dup(cfg_path);
if (volumes->cfg_path == NULL) {
rc = ENOMEM;
goto error;
}
fibril_mutex_initialize(&volumes->lock);
list_initialize(&volumes->volumes);
volumes->next_id = 1;
rc = sif_load(cfg_path, &doc);
if (rc != EOK) {
rc = sif_new(&doc);
if (rc != EOK)
goto error;
rc = sif_node_append_child(sif_get_root(doc), "volumes",
&nvolumes);
if (rc != EOK)
goto error;
rc = sif_save(doc, cfg_path);
if (rc != EOK)
goto error;
sif_delete(doc);
} else {
node = sif_node_first_child(sif_get_root(doc));
ntype = sif_node_get_type(node);
if (str_cmp(ntype, "volumes") != 0) {
rc = EIO;
goto error;
}
rc = vol_volumes_load(node, volumes);
if (rc != EOK)
goto error;
sif_delete(doc);
}
*rvolumes = volumes;
return EOK;
error:
if (doc != NULL)
(void) sif_delete(doc);
if (volumes != NULL && volumes->cfg_path != NULL)
free(volumes->cfg_path);
if (volumes != NULL)
free(volumes);
return rc;
}
errno_t vol_volumes_merge_to(vol_volumes_t *volumes, const char *cfg_path)
{
sif_doc_t *doc = NULL;
sif_node_t *node;
const char *ntype;
char *dcfg_path;
errno_t rc;
dcfg_path = str_dup(cfg_path);
if (dcfg_path == NULL) {
rc = ENOMEM;
goto error;
}
free(volumes->cfg_path);
volumes->cfg_path = dcfg_path;
rc = sif_load(cfg_path, &doc);
if (rc != EOK) {
rc = vol_volumes_sync(volumes);
if (rc != EOK)
goto error;
} else {
node = sif_node_first_child(sif_get_root(doc));
ntype = sif_node_get_type(node);
if (str_cmp(ntype, "volumes") != 0) {
rc = EIO;
goto error;
}
rc = vol_volumes_load(node, volumes);
if (rc != EOK)
goto error;
sif_delete(doc);
}
return EOK;
error:
if (doc != NULL)
(void) sif_delete(doc);
return rc;
}
errno_t vol_volumes_sync(vol_volumes_t *volumes)
{
sif_doc_t *doc = NULL;
errno_t rc;
rc = sif_new(&doc);
if (rc != EOK)
goto error;
rc = vol_volumes_save(volumes, sif_get_root(doc));
if (rc != EOK)
goto error;
rc = sif_save(doc, volumes->cfg_path);
if (rc != EOK)
goto error;
sif_delete(doc);
return EOK;
error:
if (doc != NULL)
(void) sif_delete(doc);
return rc;
}
void vol_volumes_destroy(vol_volumes_t *volumes)
{
link_t *link;
vol_volume_t *volume;
if (volumes == NULL)
return;
link = list_first(&volumes->volumes);
while (link != NULL) {
volume = list_get_instance(link, vol_volume_t, lvolumes);
list_remove(&volume->lvolumes);
vol_volume_delete(volume);
link = list_first(&volumes->volumes);
}
free(volumes->cfg_path);
free(volumes);
}
static void vol_volume_add_locked(vol_volumes_t *volumes,
vol_volume_t *volume)
{
assert(fibril_mutex_is_locked(&volumes->lock));
log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_volume_add_locked(%p)", volume);
volume->volumes = volumes;
list_append(&volume->lvolumes, &volumes->volumes);
volume->id.id = volumes->next_id;
++volumes->next_id;
}
static errno_t vol_volume_lookup_ref_locked(vol_volumes_t *volumes,
const char *label, vol_volume_t **rvolume)
{
vol_volume_t *volume;
assert(fibril_mutex_is_locked(&volumes->lock));
list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
if (str_cmp(volume->label, label) == 0 &&
str_size(label) > 0) {
refcount_up(&volume->refcnt);
*rvolume = volume;
return EOK;
}
}
volume = vol_volume_new();
if (volume == NULL)
return ENOMEM;
free(volume->label);
volume->label = str_dup(label);
if (volume->label == NULL) {
vol_volume_delete(volume);
return ENOMEM;
}
vol_volume_add_locked(volumes, volume);
*rvolume = volume;
return EOK;
}
errno_t vol_volume_lookup_ref(vol_volumes_t *volumes, const char *label,
vol_volume_t **rvolume)
{
errno_t rc;
fibril_mutex_lock(&volumes->lock);
rc = vol_volume_lookup_ref_locked(volumes, label, rvolume);
fibril_mutex_unlock(&volumes->lock);
return rc;
}
static errno_t vol_volume_find_by_id_ref_locked(vol_volumes_t *volumes,
volume_id_t vid, vol_volume_t **rvolume)
{
assert(fibril_mutex_is_locked(&volumes->lock));
list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
log_msg(LOG_DEFAULT, LVL_DEBUG2,
"vol_volume_find_by_id_ref_locked(%zu==%zu)?",
volume->id.id, vid.id);
if (volume->id.id == vid.id) {
log_msg(LOG_DEFAULT, LVL_DEBUG2,
"vol_volume_find_by_id_ref_locked: found");
refcount_up(&volume->refcnt);
*rvolume = volume;
return EOK;
}
}
log_msg(LOG_DEFAULT, LVL_DEBUG2,
"vol_volume_find_by_id_ref_locked: not found");
return ENOENT;
}
errno_t vol_volume_find_by_id_ref(vol_volumes_t *volumes, volume_id_t vid,
vol_volume_t **rvolume)
{
errno_t rc;
fibril_mutex_lock(&volumes->lock);
rc = vol_volume_find_by_id_ref_locked(volumes, vid, rvolume);
fibril_mutex_unlock(&volumes->lock);
return rc;
}
static bool vol_volume_is_persist(vol_volume_t *volume)
{
return str_size(volume->mountp) > 0;
}
void vol_volume_del_ref(vol_volume_t *volume)
{
if (refcount_down(&volume->refcnt)) {
list_remove(&volume->lvolumes);
vol_volume_delete(volume);
}
}
errno_t vol_volume_set_mountp(vol_volume_t *volume, const char *mountp)
{
char *mp;
char *old_mp;
bool was_persist;
mp = str_dup(mountp);
if (mp == NULL)
return ENOMEM;
was_persist = vol_volume_is_persist(volume);
old_mp = volume->mountp;
volume->mountp = mp;
if (vol_volume_is_persist(volume)) {
if (!was_persist) {
refcount_up(&volume->refcnt);
}
} else {
if (was_persist) {
vol_volume_del_ref(volume);
}
}
vol_volumes_sync(volume->volumes);
free(old_mp);
return EOK;
}
errno_t vol_get_ids(vol_volumes_t *volumes, volume_id_t *id_buf,
size_t buf_size, size_t *act_size)
{
size_t act_cnt;
size_t buf_cnt;
fibril_mutex_lock(&volumes->lock);
buf_cnt = buf_size / sizeof(volume_id_t);
act_cnt = 0;
list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
if (vol_volume_is_persist(volume))
++act_cnt;
}
*act_size = act_cnt * sizeof(volume_id_t);
if (buf_size % sizeof(volume_id_t) != 0) {
fibril_mutex_unlock(&volumes->lock);
return EINVAL;
}
size_t pos = 0;
list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
if (vol_volume_is_persist(volume)) {
if (pos < buf_cnt)
id_buf[pos].id = volume->id.id;
pos++;
}
}
fibril_mutex_unlock(&volumes->lock);
return EOK;
}
static errno_t vol_volumes_load(sif_node_t *nvolumes, vol_volumes_t *volumes)
{
sif_node_t *nvolume;
vol_volume_t *volume = NULL;
const char *label;
const char *mountp;
errno_t rc;
nvolume = sif_node_first_child(nvolumes);
while (nvolume != NULL) {
if (str_cmp(sif_node_get_type(nvolume), "volume") != 0) {
rc = EIO;
goto error;
}
volume = vol_volume_new();
if (volume == NULL) {
rc = ENOMEM;
goto error;
}
label = sif_node_get_attr(nvolume, "label");
mountp = sif_node_get_attr(nvolume, "mountp");
if (label == NULL || mountp == NULL) {
rc = EIO;
goto error;
}
free(volume->label);
free(volume->mountp);
volume->label = str_dup(label);
volume->mountp = str_dup(mountp);
fibril_mutex_lock(&volumes->lock);
vol_volume_add_locked(volumes, volume);
fibril_mutex_unlock(&volumes->lock);
nvolume = sif_node_next_child(nvolume);
}
return EOK;
error:
if (volume != NULL)
vol_volume_delete(volume);
return rc;
}
errno_t vol_volumes_save(vol_volumes_t *volumes, sif_node_t *rnode)
{
sif_node_t *nvolumes;
sif_node_t *node;
link_t *link;
vol_volume_t *volume;
errno_t rc;
rc = sif_node_append_child(rnode, "volumes", &nvolumes);
if (rc != EOK)
goto error;
link = list_first(&volumes->volumes);
while (link != NULL) {
volume = list_get_instance(link, vol_volume_t, lvolumes);
if (vol_volume_is_persist(volume)) {
rc = sif_node_append_child(nvolumes, "volume", &node);
if (rc != EOK)
goto error;
rc = sif_node_set_attr(node, "label", volume->label);
if (rc != EOK)
goto error;
rc = sif_node_set_attr(node, "mountp", volume->mountp);
if (rc != EOK)
goto error;
}
link = list_next(&volume->lvolumes, &volumes->volumes);
}
return EOK;
error:
return rc;
}
errno_t vol_volume_get_info(vol_volume_t *volume, vol_info_t *vinfo)
{
vinfo->id = volume->id;
str_cpy(vinfo->label, sizeof(vinfo->label), volume->label);
str_cpy(vinfo->path, sizeof(vinfo->path), volume->mountp);
return EOK;
}
HelenOS homepage, sources at GitHub