HelenOS sources
This source file includes following definitions.
- vol_volume_new
- vol_volume_delete
- vol_volumes_create
- 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_volume_get_info
#include <adt/list.h>
#include <errno.h>
#include <fibril_synch.h>
#include <io/log.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 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_sess_t *repo = NULL;
sif_trans_t *trans = NULL;
sif_node_t *node;
const char *ntype;
errno_t rc;
volumes = calloc(1, sizeof(vol_volumes_t));
if (volumes == NULL)
return ENOMEM;
fibril_mutex_initialize(&volumes->lock);
list_initialize(&volumes->volumes);
volumes->next_id = 1;
rc = sif_open(cfg_path, &repo);
if (rc != EOK) {
rc = sif_create(cfg_path, &repo);
if (rc != EOK)
goto error;
rc = sif_trans_begin(repo, &trans);
if (rc != EOK)
goto error;
rc = sif_node_append_child(trans, sif_get_root(repo),
"volumes", &volumes->nvolumes);
if (rc != EOK)
goto error;
rc = sif_trans_end(trans);
if (rc != EOK)
goto error;
trans = NULL;
} else {
node = sif_node_first_child(sif_get_root(repo));
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;
}
volumes->repo = repo;
*rvolumes = volumes;
return EOK;
error:
if (trans != NULL)
sif_trans_abort(trans);
if (repo != NULL)
(void) sif_close(repo);
if (volumes != NULL)
free(volumes);
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);
}
(void) sif_close(volumes->repo);
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;
errno_t rc;
sif_trans_t *trans = NULL;
sif_node_t *nvolume;
mp = str_dup(mountp);
if (mp == NULL)
return ENOMEM;
old_mp = volume->mountp;
volume->mountp = mp;
if (vol_volume_is_persist(volume)) {
if (volume->nvolume == NULL) {
refcount_up(&volume->refcnt);
rc = sif_trans_begin(volume->volumes->repo, &trans);
if (rc != EOK)
goto error;
rc = sif_node_append_child(trans,
volume->volumes->nvolumes, "volume", &nvolume);
if (rc != EOK)
goto error;
rc = sif_node_set_attr(trans, nvolume, "label",
volume->label);
if (rc != EOK)
goto error;
rc = sif_node_set_attr(trans, nvolume, "mountp",
volume->mountp);
if (rc != EOK)
goto error;
rc = sif_trans_end(trans);
if (rc != EOK)
goto error;
trans = NULL;
volume->nvolume = nvolume;
} else {
vol_volume_del_ref(volume);
rc = sif_trans_begin(volume->volumes->repo, &trans);
if (rc != EOK)
goto error;
rc = sif_node_set_attr(trans, volume->nvolume,
"mountp", volume->mountp);
if (rc != EOK)
goto error;
rc = sif_trans_end(trans);
if (rc != EOK)
goto error;
trans = NULL;
}
} else {
if (volume->nvolume != NULL) {
rc = sif_trans_begin(volume->volumes->repo, &trans);
if (rc != EOK)
goto error;
sif_node_destroy(trans, volume->nvolume);
rc = sif_trans_end(trans);
if (rc != EOK)
goto error;
volume->nvolume = NULL;
}
}
free(old_mp);
return EOK;
error:
free(mp);
volume->mountp = old_mp;
if (trans != NULL)
sif_trans_abort(trans);
return rc;
}
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;
volumes->nvolumes = nvolumes;
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);
volume->nvolume = nvolume;
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_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