/*
* Copyright (c) 2012 Julia Medvedeva
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @addtogroup udf
* @{
*/
/**
* @file udf_volume.c
* @brief Implementation of volume recognition operations.
*/
#include <byteorder.h>
#include <block.h>
#include <libfs.h>
#include <errno.h>
#include <stdlib.h>
#include <str.h>
#include <mem.h>
#include <inttypes.h>
#include <io/log.h>
#include "udf.h"
#include "udf_volume.h"
#include "udf_osta.h"
#include "udf_cksum.h"
#include "udf_file.h"
/** Convert long_ad to absolute sector position
*
* Convert address sector concerning origin of partition to position
* sector concerning origin of start of disk.
*
* @param instance UDF instance
* @param long_ad UDF long address
*
* @return Position of sector concerning origin of start of disk.
*
*/
fs_index_t udf_long_ad_to_pos(udf_instance_t *instance, udf_long_ad_t *long_ad)
{
log_msg(LOG_DEFAULT, LVL_DEBUG, "Long_Ad to Pos: "
"partition_num=%" PRIu16 ", partition_block=%" PRIu32,
FLE16(long_ad->location.partition_num),
FLE32(long_ad->location.lblock_num));
return instance->partitions[
FLE16(long_ad->location.partition_num)].start +
FLE32(long_ad->location.lblock_num);
}
/** Check type and version of VRS
*
* Not exactly clear which values could have type and version.
*
* @param service_id
* @param addr Position sector with Volume Descriptor
* @param vd Returned value - Volume Descriptor.
*
* @return EOK on success or an error code.
*
*/
static errno_t udf_volume_recongnition_structure_test(service_id_t service_id,
aoff64_t addr, udf_vrs_descriptor_t *vd)
{
return block_read_bytes_direct(service_id, addr,
sizeof(udf_vrs_descriptor_t), vd);
}
/** Read Volume Recognition Sequence
*
* It is a first udf data which we read.
* It stars from fixed address VRS_ADDR = 32768 (bytes)
*
* @param service_id
*
* @return EOK on success or an error code.
*/
errno_t udf_volume_recongnition(service_id_t service_id)
{
aoff64_t addr = VRS_ADDR;
bool nsr_found = false;
udf_vrs_descriptor_t *vd = malloc(sizeof(udf_vrs_descriptor_t));
if (!vd)
return ENOMEM;
errno_t rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
if (rc != EOK) {
free(vd);
return rc;
}
for (size_t i = 0; i < VRS_DEPTH; i++) {
addr += sizeof(udf_vrs_descriptor_t);
rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
if (rc != EOK) {
free(vd);
return rc;
}
/*
* UDF standard identifier. According to ECMA 167 2/9.1.2
*/
if ((str_lcmp(VRS_NSR2, (char *) vd->identifier, VRS_ID_LEN) == 0) ||
(str_lcmp(VRS_NSR3, (char *) vd->identifier, VRS_ID_LEN) == 0)) {
nsr_found = true;
log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: NSR found");
continue;
}
if (str_lcmp(VRS_END, (char *) vd->identifier, VRS_ID_LEN) == 0) {
log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: end found");
break;
}
}
free(vd);
if (nsr_found)
return EOK;
else
return EINVAL;
}
/** Convert descriptor tag fields from little-endian to current byte order
*
*/
static void udf_prepare_tag(udf_descriptor_tag_t *tag)
{
GET_LE16(tag->id);
GET_LE16(tag->version);
GET_LE16(tag->serial);
GET_LE16(tag->descriptor_crc);
GET_LE16(tag->descriptor_crc_length);
GET_LE32(tag->location);
}
/** Read AVD by using one of default sector size from array
*
* @param service_id
* @param avd Returned value - Anchor Volume Descriptor
* @param sector_size Expected sector size
*
* @return EOK on success or an error code.
*
*/
static errno_t udf_get_anchor_volume_descriptor_by_ssize(service_id_t service_id,
udf_anchor_volume_descriptor_t *avd, uint32_t sector_size)
{
errno_t rc = block_read_bytes_direct(service_id,
UDF_AVDP_SECTOR * sector_size,
sizeof(udf_anchor_volume_descriptor_t), avd);
if (rc != EOK)
return rc;
if (avd->tag.checksum != udf_tag_checksum((uint8_t *) &avd->tag))
return EINVAL;
// TODO: Should be tested in big-endian mode
udf_prepare_tag(&avd->tag);
if (avd->tag.id != UDF_TAG_AVDP)
return EINVAL;
GET_LE32(avd->main_extent.length);
GET_LE32(avd->main_extent.location);
GET_LE32(avd->reserve_extent.length);
GET_LE32(avd->reserve_extent.location);
return EOK;
}
/** Identification of the sector size
*
* We try to read Anchor Volume Descriptor by using one item from
* sequence of default values. If we could read avd, we found sector size.
*
* @param service_id
* @param avd Returned value - Anchor Volume Descriptor
*
* @return EOK on success or an error code.
*
*/
errno_t udf_get_anchor_volume_descriptor(service_id_t service_id,
udf_anchor_volume_descriptor_t *avd)
{
uint32_t default_sector_size[] = { 512, 1024, 2048, 4096, 8192, 0 };
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
if (instance->sector_size) {
return udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
instance->sector_size);
} else {
size_t i = 0;
while (default_sector_size[i] != 0) {
rc = udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
default_sector_size[i]);
if (rc == EOK) {
instance->sector_size = default_sector_size[i];
return EOK;
}
i++;
}
}
return EINVAL;
}
/** Check on prevailing primary volume descriptor
*
* Some discs couldn't be rewritten and new information is identified
* by descriptors with same data as one of already created descriptors.
* We should find prevailing descriptor (descriptor with the highest number)
* and delete old descriptor.
*
* @param pvd Array of primary volumes descriptors
* @param cnt Count of items in array
* @param desc Descriptor which could prevail over one
* of descriptors in array.
*
* @return True if desc prevails over some descriptor in array
*
*/
static bool udf_check_prevailing_pvd(udf_primary_volume_descriptor_t *pvd,
size_t cnt, udf_primary_volume_descriptor_t *desc)
{
for (size_t i = 0; i < cnt; i++) {
/*
* According to ECMA 167 3/8.4.3
* PVD, each of which has same contents of the corresponding
* Volume Identifier, Volume set identifier
* and Descriptor char set field.
*/
if ((memcmp((uint8_t *) pvd[i].volume_id,
(uint8_t *) desc->volume_id, 32) == 0) &&
(memcmp((uint8_t *) pvd[i].volume_set_id,
(uint8_t *) desc->volume_set_id, 128) == 0) &&
(memcmp((uint8_t *) &pvd[i].descriptor_charset,
(uint8_t *) &desc->descriptor_charset, 64) == 0) &&
(FLE32(desc->sequence_number) > FLE32(pvd[i].sequence_number))) {
memcpy(&pvd[i], desc, sizeof(udf_primary_volume_descriptor_t));
return true;
}
}
return false;
}
/** Check on prevailing logic volume descriptor
*
* Some discs couldn't be rewritten and new information is identified
* by descriptors with same data as one of already created descriptors.
* We should find prevailing descriptor (descriptor with the highest number)
* and delete old descriptor.
*
* @param lvd Array of logic volumes descriptors
* @param cnt Count of items in array
* @param desc Descriptor which could prevail over one
* of descriptors in array.
*
* @return True if desc prevails over some descriptor in array
*
*/
static bool udf_check_prevailing_lvd(udf_logical_volume_descriptor_t *lvd,
size_t cnt, udf_logical_volume_descriptor_t *desc)
{
for (size_t i = 0; i < cnt; i++) {
/*
* According to ECMA 167 3/8.4.3
* LVD, each of which has same contents of the corresponding
* Logic Volume Identifier and Descriptor char set field.
*/
if ((memcmp((uint8_t *) lvd[i].logical_volume_id,
(uint8_t *) desc->logical_volume_id, 128) == 0) &&
(memcmp((uint8_t *) &lvd[i].charset,
(uint8_t *) &desc->charset, 64) == 0) &&
(FLE32(desc->sequence_number) > FLE32(lvd[i].sequence_number))) {
memcpy(&lvd[i], desc, sizeof(udf_logical_volume_descriptor_t));
return true;
}
}
return false;
}
/** Check on prevailing partition descriptor
*
* Some discs couldn't be rewritten and new information is identified
* by descriptors with same data as one of already created descriptors.
* We should find prevailing descriptor (descriptor with the highest number)
* and delete old descriptor.
*
* @param pvd Array of partition descriptors
* @param cnt Count of items in array
* @param desc Descriptor which could prevail over one
* of descriptors in array.
*
* @return True if desc prevails over some descriptor in array
*
*/
static bool udf_check_prevailing_pd(udf_partition_descriptor_t *pd, size_t cnt,
udf_partition_descriptor_t *desc)
{
for (size_t i = 0; i < cnt; i++) {
/*
* According to ECMA 167 3/8.4.3
* Partition descriptors with identical Partition Number
*/
if ((FLE16(pd[i].number) == FLE16(desc->number)) &&
(FLE32(desc->sequence_number) > FLE32(pd[i].sequence_number))) {
memcpy(&pd[i], desc, sizeof(udf_partition_descriptor_t));
return true;
}
}
return false;
}
/** Read information about virtual partition
*
* Fill start and length fields for partition. This function quite similar of
* udf_read_icd. But in this we can meet only two descriptors and
* we have to read only one allocator.
*
* @param instance UDF instance
* @param pos Position (Extended) File entry descriptor
* @param id Index of partition in instance::partitions array
*
* @return EOK on success or an error code.
*
*/
static errno_t udf_read_virtual_partition(udf_instance_t *instance, uint32_t pos,
uint32_t id)
{
block_t *block = NULL;
errno_t rc = block_get(&block, instance->service_id, pos,
BLOCK_FLAGS_NONE);
if (rc != EOK)
return rc;
udf_descriptor_tag_t *desc = (udf_descriptor_tag_t *) (block->data);
if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
block_put(block);
return EINVAL;
}
/*
* We think that we have only one allocator. It is means that virtual
* partition, like physical, isn't fragmented.
* According to doc the type of allocator is short_ad.
*/
switch (FLE16(desc->id)) {
case UDF_FILE_ENTRY:
log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
udf_file_entry_descriptor_t *fed =
(udf_file_entry_descriptor_t *) block->data;
uint32_t start_alloc = FLE32(fed->ea_length) + UDF_FE_OFFSET;
udf_short_ad_t *short_d =
(udf_short_ad_t *) ((uint8_t *) fed + start_alloc);
instance->partitions[id].start = FLE32(short_d->position);
instance->partitions[id].length = FLE32(short_d->length);
break;
case UDF_EFILE_ENTRY:
log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
udf_extended_file_entry_descriptor_t *efed =
(udf_extended_file_entry_descriptor_t *) block->data;
start_alloc = FLE32(efed->ea_length) + UDF_EFE_OFFSET;
short_d = (udf_short_ad_t *) ((uint8_t *) efed + start_alloc);
instance->partitions[id].start = FLE32(short_d->position);
instance->partitions[id].length = FLE32(short_d->length);
break;
}
return block_put(block);
}
/** Search partition in array of partitions
*
* Used only in function udf_fill_volume_info
*
* @param pd Array of partitions
* @param pd_cnt Count items in array
* @param id Number partition (not index) which we want to find
*
* @return Index of partition or (size_t) -1 if we didn't find anything
*
*/
static size_t udf_find_partition(udf_partition_descriptor_t *pd, size_t pd_cnt,
size_t id)
{
for (size_t i = 0; i < pd_cnt; i++) {
if (FLE16(pd[i].number) == id)
return i;
}
return (size_t) -1;
}
/** Fill instance structures by information about partitions and logic
*
* @param lvd Array of logic volumes descriptors
* @param lvd_cnt Count of items in lvd array
* @param pd Array of partition descriptors
* @param pd_cnt Count of items in pd array
* @param instance UDF instance
*
* @return EOK on success or an error code.
*
*/
static errno_t udf_fill_volume_info(udf_logical_volume_descriptor_t *lvd,
size_t lvd_cnt, udf_partition_descriptor_t *pd, size_t pd_cnt,
udf_instance_t *instance)
{
instance->volumes = calloc(lvd_cnt, sizeof(udf_lvolume_t));
if (instance->volumes == NULL)
return ENOMEM;
instance->partitions = calloc(pd_cnt, sizeof(udf_partition_t));
if (instance->partitions == NULL) {
free(instance->volumes);
return ENOMEM;
}
instance->partition_cnt = pd_cnt;
/*
* Fill information about logical volumes. We will save
* information about all partitions placed inside each volumes.
*/
size_t vir_pd_cnt = 0;
for (size_t i = 0; i < lvd_cnt; i++) {
instance->volumes[i].partitions =
calloc(FLE32(lvd[i].number_of_partitions_maps),
sizeof(udf_partition_t *));
if (instance->volumes[i].partitions == NULL) {
// FIXME: Memory leak, cleanup code missing
return ENOMEM;
}
instance->volumes[i].partition_cnt = 0;
instance->volumes[i].logical_block_size =
FLE32(lvd[i].logical_block_size);
/*
* In theory we could have more than 1 logical volume. But now
* for current work of driver we will think that it single and all
* partitions from array pd belong to only first lvd
*/
uint8_t *idx = lvd[i].partition_map;
for (size_t j = 0; j < FLE32(lvd[i].number_of_partitions_maps);
j++) {
udf_type1_partition_map_t *pm1 =
(udf_type1_partition_map_t *) idx;
if (pm1->partition_map_type == 1) {
size_t pd_num = udf_find_partition(pd, pd_cnt,
FLE16(pm1->partition_number));
if (pd_num == (size_t) -1) {
// FIXME: Memory leak, cleanup code missing
return ENOENT;
}
/*
* Fill information about physical partitions. We will save all
* partitions (physical and virtual) inside one array
* instance::partitions
*/
instance->partitions[j].access_type =
FLE32(pd[pd_num].access_type);
instance->partitions[j].length =
FLE32(pd[pd_num].length);
instance->partitions[j].number =
FLE16(pm1->partition_number);
instance->partitions[j].start =
FLE32(pd[pd_num].starting_location);
instance->volumes[i].partitions[
instance->volumes[i].partition_cnt] =
&instance->partitions[j];
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
"found and filled", i, pm1->partition_map_type);
instance->volumes[i].partition_cnt++;
idx += pm1->partition_map_length;
continue;
}
udf_type2_partition_map_t *pm2 =
(udf_type2_partition_map_t *) idx;
if (pm2->partition_map_type == 2) {
// TODO: check partition_ident for metadata_partition_map
udf_metadata_partition_map_t *metadata =
(udf_metadata_partition_map_t *) idx;
log_msg(LOG_DEFAULT, LVL_DEBUG, "Metadata file location=%u",
FLE32(metadata->metadata_fileloc));
vir_pd_cnt++;
instance->partitions = realloc(instance->partitions,
(pd_cnt + vir_pd_cnt) * sizeof(udf_partition_t));
if (instance->partitions == NULL) {
// FIXME: Memory leak, cleanup code missing
return ENOMEM;
}
instance->partition_cnt++;
size_t pd_num = udf_find_partition(pd, pd_cnt,
FLE16(metadata->partition_number));
if (pd_num == (size_t) -1) {
// FIXME: Memory leak, cleanup code missing
return ENOENT;
}
instance->partitions[j].number =
FLE16(metadata->partition_number);
errno_t rc = udf_read_virtual_partition(instance,
FLE32(metadata->metadata_fileloc) +
FLE32(pd[pd_num].starting_location), j);
if (rc != EOK) {
// FIXME: Memory leak, cleanup code missing
return rc;
}
/* Virtual partition placed inside physical */
instance->partitions[j].start +=
FLE32(pd[pd_num].starting_location);
instance->volumes[i].partitions[
instance->volumes[i].partition_cnt] =
&instance->partitions[j];
log_msg(LOG_DEFAULT, LVL_DEBUG, "Virtual partition: num=%d, start=%d",
instance->partitions[j].number,
instance->partitions[j].start);
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
"found and filled", i, pm2->partition_map_type);
instance->volumes[i].partition_cnt++;
idx += metadata->partition_map_length;
continue;
}
/* Not type 1 nor type 2 */
udf_general_type_t *pm = (udf_general_type_t *) idx;
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
"found and skipped", i, pm->partition_map_type);
idx += pm->partition_map_length;
}
}
return EOK;
}
/** Read volume descriptors sequence
*
* @param service_id
* @param addr UDF extent descriptor (ECMA 167 3/7.1)
*
* @return EOK on success or an error code.
*
*/
errno_t udf_read_volume_descriptor_sequence(service_id_t service_id,
udf_extent_t addr)
{
udf_instance_t *instance;
errno_t rc = fs_instance_get(service_id, (void **) &instance);
if (rc != EOK)
return rc;
aoff64_t pos = addr.location;
aoff64_t end = pos + (addr.length / instance->sector_size) - 1;
if (pos == end)
return EINVAL;
size_t max_descriptors = ALL_UP(addr.length, instance->sector_size);
udf_primary_volume_descriptor_t *pvd = calloc(max_descriptors,
sizeof(udf_primary_volume_descriptor_t));
if (pvd == NULL)
return ENOMEM;
udf_logical_volume_descriptor_t *lvd = calloc(max_descriptors,
instance->sector_size);
if (lvd == NULL) {
free(pvd);
return ENOMEM;
}
udf_partition_descriptor_t *pd = calloc(max_descriptors,
sizeof(udf_partition_descriptor_t));
if (pd == NULL) {
free(pvd);
free(lvd);
return ENOMEM;
}
size_t pvd_cnt = 0;
size_t lvd_cnt = 0;
size_t pd_cnt = 0;
while (pos <= end) {
block_t *block = NULL;
rc = block_get(&block, service_id, pos, BLOCK_FLAGS_NONE);
if (rc != EOK) {
free(pvd);
free(lvd);
free(pd);
return rc;
}
udf_volume_descriptor_t *vol =
(udf_volume_descriptor_t *) block->data;
switch (FLE16(vol->common.tag.id)) {
/*
* One sector size descriptors
*/
case UDF_TAG_PVD:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Primary volume descriptor found");
if (!udf_check_prevailing_pvd(pvd, pvd_cnt, &vol->volume)) {
memcpy(&pvd[pvd_cnt], &vol->volume,
sizeof(udf_primary_volume_descriptor_t));
pvd_cnt++;
}
pos++;
break;
case UDF_TAG_VDP:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Volume descriptor pointer found");
pos++;
break;
case UDF_TAG_IUVD:
log_msg(LOG_DEFAULT, LVL_DEBUG,
"Volume: Implementation use volume descriptor found");
pos++;
break;
case UDF_TAG_PD:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Partition descriptor found");
log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition number: %u, contents: '%.6s', "
"access type: %" PRIu32, FLE16(vol->partition.number),
vol->partition.contents.id, FLE32(vol->partition.access_type));
log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition start: %" PRIu32 " (sector), "
"size: %" PRIu32 " (sectors)",
FLE32(vol->partition.starting_location),
FLE32(vol->partition.length));
if (!udf_check_prevailing_pd(pd, pd_cnt, &vol->partition)) {
memcpy(&pd[pd_cnt], &vol->partition,
sizeof(udf_partition_descriptor_t));
pd_cnt++;
}
udf_partition_header_descriptor_t *phd =
(udf_partition_header_descriptor_t *) vol->partition.contents_use;
if (FLE32(phd->unallocated_space_table.length)) {
log_msg(LOG_DEFAULT, LVL_DEBUG,
"space table: length=%" PRIu32 ", pos=%" PRIu32,
FLE32(phd->unallocated_space_table.length),
FLE32(phd->unallocated_space_table.position));
instance->space_type = SPACE_TABLE;
instance->uaspace_start =
FLE32(vol->partition.starting_location) +
FLE32(phd->unallocated_space_table.position);
instance->uaspace_length =
FLE32(phd->unallocated_space_table.length);
}
if (FLE32(phd->unallocated_space_bitmap.length)) {
log_msg(LOG_DEFAULT, LVL_DEBUG,
"space bitmap: length=%" PRIu32 ", pos=%" PRIu32,
FLE32(phd->unallocated_space_bitmap.length),
FLE32(phd->unallocated_space_bitmap.position));
instance->space_type = SPACE_BITMAP;
instance->uaspace_start =
FLE32(vol->partition.starting_location) +
FLE32(phd->unallocated_space_bitmap.position);
instance->uaspace_length =
FLE32(phd->unallocated_space_bitmap.length);
}
pos++;
break;
/*
* Relative size descriptors
*/
case UDF_TAG_LVD:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Logical volume descriptor found");
aoff64_t sct =
ALL_UP((sizeof(udf_logical_volume_descriptor_t) +
FLE32(vol->logical.map_table_length)),
sizeof(udf_common_descriptor_t));
pos += sct;
char tmp[130];
udf_to_unix_name(tmp, 129,
(char *) vol->logical.logical_volume_id, 128,
&vol->logical.charset);
log_msg(LOG_DEFAULT, LVL_DEBUG, "Logical Volume ID: '%s', "
"logical block size: %" PRIu32 " (bytes)", tmp,
FLE32(vol->logical.logical_block_size));
log_msg(LOG_DEFAULT, LVL_DEBUG, "Map table size: %" PRIu32 " (bytes), "
"number of partition maps: %" PRIu32,
FLE32(vol->logical.map_table_length),
FLE32(vol->logical.number_of_partitions_maps));
if (!udf_check_prevailing_lvd(lvd, lvd_cnt, &vol->logical)) {
memcpy(&lvd[lvd_cnt], &vol->logical,
sizeof(udf_logical_volume_descriptor_t) +
FLE32(vol->logical.map_table_length));
lvd_cnt++;
}
break;
case UDF_TAG_USD:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Unallocated space descriptor found");
sct = ALL_UP((sizeof(udf_unallocated_space_descriptor_t) +
FLE32(vol->unallocated.allocation_descriptors_num) *
sizeof(udf_extent_t)), sizeof(udf_common_descriptor_t));
instance->uaspace_start = pos;
instance->uaspace_length = sct;
instance->uasd = (udf_unallocated_space_descriptor_t *)
malloc(sct * instance->sector_size);
if (instance->uasd == NULL) {
// FIXME: Memory leak, cleanup missing
return ENOMEM;
}
memcpy(instance->uasd, block->data, instance->sector_size);
pos += sct;
break;
case UDF_TAG_LVID:
log_msg(LOG_DEFAULT, LVL_DEBUG,
"Volume: Logical volume integrity descriptor found");
pos++;
break;
case UDF_TAG_TD:
log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Terminating descriptor found");
/* Found terminating descriptor. Exiting */
pos = end + 1;
break;
default:
pos++;
}
rc = block_put(block);
if (rc != EOK) {
free(pvd);
free(lvd);
free(pd);
return rc;
}
}
/* Fill the instance */
udf_fill_volume_info(lvd, lvd_cnt, pd, pd_cnt, instance);
for (size_t i = 0; i < lvd_cnt; i++) {
pos = udf_long_ad_to_pos(instance,
(udf_long_ad_t *) &lvd[i].logical_volume_conents_use);
block_t *block = NULL;
rc = block_get(&block, instance->service_id, pos,
BLOCK_FLAGS_NONE);
if (rc != EOK) {
// FIXME: Memory leak, cleanup missing
return rc;
}
udf_descriptor_tag_t *desc = block->data;
log_msg(LOG_DEFAULT, LVL_DEBUG, "First tag ID=%" PRIu16, desc->id);
if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
// FIXME: Memory leak, cleanup missing
return EINVAL;
}
udf_prepare_tag(desc);
udf_fileset_descriptor_t *fd = block->data;
memcpy((uint8_t *) &instance->charset,
(uint8_t *) &fd->fileset_charset, sizeof(fd->fileset_charset));
instance->volumes[i].root_dir = udf_long_ad_to_pos(instance,
&fd->root_dir_icb);
}
free(pvd);
free(lvd);
free(pd);
return EOK;
}
/**
* @}
*/