HelenOS sources
This source file includes following definitions.
- udf_node_get
- udf_root_get
- udf_service_get
- udf_match
- udf_node_open
- udf_node_put
- udf_create_node
- udf_destroy_node
- udf_link
- udf_unlink
- udf_has_children
- udf_index_get
- udf_size_get
- udf_lnkcnt_get
- udf_is_directory
- udf_is_file
- udf_size_block
- udf_total_block_count
- udf_free_block_count
- udf_fsprobe
- udf_mounted
- udf_unmounted
- udf_read
- udf_close
- udf_sync
- udf_write
- udf_truncate
- udf_destroy
#include <libfs.h>
#include <block.h>
#include <ipc/services.h>
#include <ipc/loc.h>
#include <macros.h>
#include <async.h>
#include <errno.h>
#include <str.h>
#include <byteorder.h>
#include <adt/hash_table.h>
#include <adt/list.h>
#include <assert.h>
#include <fibril_synch.h>
#include <align.h>
#include <stdlib.h>
#include <inttypes.h>
#include <io/log.h>
#include "../../vfs/vfs.h"
#include "udf.h"
#include "udf_cksum.h"
#include "udf_volume.h"
#include "udf_idx.h"
#include "udf_file.h"
#include "udf_osta.h"
static LIST_INITIALIZE(ffn_list);
static errno_t udf_node_get(fs_node_t **rfn, service_id_t service_id,
fs_index_t index)
{
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
udf_node_t *node;
rc = udf_idx_get(&node, instance, index);
if (rc != EOK) {
rc = udf_idx_add(&node, instance, index);
if (rc != EOK)
return rc;
rc = udf_node_get_core(node);
if (rc != EOK) {
udf_idx_del(node);
return rc;
}
}
*rfn = FS_NODE(node);
return EOK;
}
static errno_t udf_root_get(fs_node_t **rfn, service_id_t service_id)
{
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
return udf_node_get(rfn, service_id,
instance->volumes[DEFAULT_VOL].root_dir);
}
static service_id_t udf_service_get(fs_node_t *node)
{
return 0;
}
static errno_t udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
{
char *name = malloc(MAX_FILE_NAME_LEN + 1);
if (name == NULL)
return ENOMEM;
block_t *block = NULL;
udf_file_identifier_descriptor_t *fid = NULL;
size_t pos = 0;
while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
udf_long_ad_t long_ad = fid->icb;
udf_to_unix_name(name, MAX_FILE_NAME_LEN,
(char *) fid->implementation_use + FLE16(fid->length_iu),
fid->length_file_id, &UDF_NODE(pfn)->instance->charset);
if (str_casecmp(name, component) == 0) {
errno_t rc = udf_node_get(rfn, udf_service_get(pfn),
udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
if (block != NULL)
block_put(block);
free(name);
return rc;
}
if (block != NULL) {
errno_t rc = block_put(block);
if (rc != EOK)
return rc;
}
pos++;
}
free(name);
return ENOENT;
}
static errno_t udf_node_open(fs_node_t *fn)
{
return EOK;
}
static errno_t udf_node_put(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (!node)
return EINVAL;
fibril_mutex_lock(&node->lock);
node->ref_cnt--;
fibril_mutex_unlock(&node->lock);
if (!node->ref_cnt)
udf_idx_del(node);
return EOK;
}
static errno_t udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
{
return ENOTSUP;
}
static errno_t udf_destroy_node(fs_node_t *fn)
{
return ENOTSUP;
}
static errno_t udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
{
return ENOTSUP;
}
static errno_t udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
{
return ENOTSUP;
}
static errno_t udf_has_children(bool *has_children, fs_node_t *fn)
{
*has_children = true;
return EOK;
}
static fs_index_t udf_index_get(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (node)
return node->index;
return 0;
}
static aoff64_t udf_size_get(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (node)
return node->data_size;
return 0;
}
static unsigned int udf_lnkcnt_get(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (node)
return node->link_cnt;
return 0;
}
static bool udf_is_directory(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (node)
return node->type == NODE_DIR;
return false;
}
static bool udf_is_file(fs_node_t *fn)
{
udf_node_t *node = UDF_NODE(fn);
if (node)
return node->type == NODE_FILE;
return false;
}
static errno_t udf_size_block(service_id_t service_id, uint32_t *size)
{
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
if (NULL == instance)
return ENOENT;
*size = instance->volumes[DEFAULT_VOL].logical_block_size;
return EOK;
}
static errno_t udf_total_block_count(service_id_t service_id, uint64_t *count)
{
*count = 0;
return EOK;
}
static errno_t udf_free_block_count(service_id_t service_id, uint64_t *count)
{
*count = 0;
return EOK;
}
libfs_ops_t udf_libfs_ops = {
.root_get = udf_root_get,
.match = udf_match,
.node_get = udf_node_get,
.node_open = udf_node_open,
.node_put = udf_node_put,
.create = udf_create_node,
.destroy = udf_destroy_node,
.link = udf_link,
.unlink = udf_unlink,
.has_children = udf_has_children,
.index_get = udf_index_get,
.size_get = udf_size_get,
.lnkcnt_get = udf_lnkcnt_get,
.is_directory = udf_is_directory,
.is_file = udf_is_file,
.service_get = udf_service_get,
.size_block = udf_size_block,
.total_block_count = udf_total_block_count,
.free_block_count = udf_free_block_count
};
static errno_t udf_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
{
return ENOTSUP;
}
static errno_t udf_mounted(service_id_t service_id, const char *opts,
fs_index_t *index, aoff64_t *size)
{
enum cache_mode cmode;
if (str_cmp(opts, "wtcache") == 0)
cmode = CACHE_MODE_WT;
else
cmode = CACHE_MODE_WB;
udf_instance_t *instance = malloc(sizeof(udf_instance_t));
if (!instance)
return ENOMEM;
instance->sector_size = 0;
if (str_cmp(opts, "bs=512") == 0)
instance->sector_size = 512;
else if (str_cmp(opts, "bs=1024") == 0)
instance->sector_size = 1024;
else if (str_cmp(opts, "bs=2048") == 0)
instance->sector_size = 2048;
errno_t rc = block_init(service_id);
if (rc != EOK) {
free(instance);
return rc;
}
rc = fs_instance_create(service_id, instance);
if (rc != EOK) {
free(instance);
block_fini(service_id);
return rc;
}
instance->service_id = service_id;
instance->open_nodes_count = 0;
rc = udf_volume_recongnition(service_id);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
fs_instance_destroy(service_id);
free(instance);
block_fini(service_id);
return rc;
}
udf_anchor_volume_descriptor_t avd;
rc = udf_get_anchor_volume_descriptor(service_id, &avd);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
fs_instance_destroy(service_id);
free(instance);
block_fini(service_id);
return rc;
}
log_msg(LOG_DEFAULT, LVL_DEBUG,
"Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
instance->sector_size);
log_msg(LOG_DEFAULT, LVL_DEBUG,
"Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
PRIu32 " (sector)]", avd.main_extent.length,
avd.main_extent.location);
log_msg(LOG_DEFAULT, LVL_DEBUG,
"Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
PRIu32 " (sector)]", avd.reserve_extent.length,
avd.reserve_extent.location);
rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
if (rc != EOK) {
fs_instance_destroy(service_id);
free(instance);
block_fini(service_id);
return rc;
}
rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
fs_instance_destroy(service_id);
free(instance);
block_cache_fini(service_id);
block_fini(service_id);
return rc;
}
fs_node_t *rfn;
rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
fs_instance_destroy(service_id);
free(instance);
block_cache_fini(service_id);
block_fini(service_id);
return rc;
}
udf_node_t *node = UDF_NODE(rfn);
*index = instance->volumes[DEFAULT_VOL].root_dir;
*size = node->data_size;
return EOK;
}
static errno_t udf_unmounted(service_id_t service_id)
{
fs_node_t *fn;
errno_t rc = udf_root_get(&fn, service_id);
if (rc != EOK)
return rc;
udf_node_t *nodep = UDF_NODE(fn);
udf_instance_t *instance = nodep->instance;
if (nodep->ref_cnt != 2) {
udf_node_put(fn);
return EBUSY;
}
udf_node_put(fn);
udf_node_put(fn);
fs_instance_destroy(service_id);
free(instance);
block_cache_fini(service_id);
block_fini(service_id);
return EOK;
}
static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
size_t *rbytes)
{
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
fs_node_t *rfn;
rc = udf_node_get(&rfn, service_id, index);
if (rc != EOK)
return rc;
udf_node_t *node = UDF_NODE(rfn);
ipc_call_t call;
size_t len = 0;
if (!async_data_read_receive(&call, &len)) {
async_answer_0(&call, EINVAL);
udf_node_put(rfn);
return EINVAL;
}
if (node->type == NODE_FILE) {
if (pos >= node->data_size) {
*rbytes = 0;
async_data_read_finalize(&call, NULL, 0);
udf_node_put(rfn);
return EOK;
}
size_t read_len = 0;
if (node->data == NULL)
rc = udf_read_file(&read_len, &call, node, pos, len);
else {
read_len = (len < node->data_size) ? len : node->data_size;
async_data_read_finalize(&call, node->data + pos, read_len);
rc = EOK;
}
*rbytes = read_len;
(void) udf_node_put(rfn);
return rc;
} else {
block_t *block = NULL;
udf_file_identifier_descriptor_t *fid = NULL;
if (udf_get_fid(&fid, &block, node, pos) == EOK) {
char *name = malloc(MAX_FILE_NAME_LEN + 1);
udf_to_unix_name(name, MAX_FILE_NAME_LEN,
(char *) fid->implementation_use + FLE16(fid->length_iu),
fid->length_file_id, &node->instance->charset);
async_data_read_finalize(&call, name, str_size(name) + 1);
*rbytes = 1;
free(name);
udf_node_put(rfn);
if (block != NULL)
return block_put(block);
return EOK;
} else {
*rbytes = 0;
udf_node_put(rfn);
async_answer_0(&call, ENOENT);
return ENOENT;
}
}
}
static errno_t udf_close(service_id_t service_id, fs_index_t index)
{
return EOK;
}
static errno_t udf_sync(service_id_t service_id, fs_index_t index)
{
return ENOTSUP;
}
static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
size_t *wbytes, aoff64_t *nsize)
{
return ENOTSUP;
}
static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
aoff64_t size)
{
return ENOTSUP;
}
static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
{
return ENOTSUP;
}
vfs_out_ops_t udf_ops = {
.fsprobe = udf_fsprobe,
.mounted = udf_mounted,
.unmounted = udf_unmounted,
.read = udf_read,
.write = udf_write,
.truncate = udf_truncate,
.close = udf_close,
.destroy = udf_destroy,
.sync = udf_sync
};
HelenOS homepage, sources at GitHub