/* $NetBSD$ */
/*
* File "udf_verbose.c" is part of the UDFclient toolkit.
* File $Id: udf_verbose.c,v 1.104 2007/11/06 18:35:27 reinoud Exp $ $Name: $
*
* Copyright (c) 2003, 2004, 2006 Reinoud Zandijk <reinoud@netbsd.org>
* All rights reserved.
*
* The UDFclient toolkit is distributed under the Clarified Artistic Licence.
* A copy of the licence is included in the distribution as
* `LICENCE.clearified.artistic' and a copy of the licence can also be
* requested at the GNU foundantion's website.
*
* Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/
*
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include "udf.h"
#include "udf_bswap.h"
/* globals */
void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp);
void udf_dump_long_ad(char *prefix, struct long_ad *adr);
void udf_dump_descriptor(union dscrptr *dscrpt);
void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping);
void udf_dump_unimpl(union dscrptr *dscrpt) {
dscrpt = dscrpt;
fprintf(stderr, "\t\t(unimplemented dump)\n");
}
void udf_dump_desc(struct desc_tag *tag) {
printf("\tTAG: descriptor %d, serial_num %d at sector %d, crc length %d bytes\n",
udf_rw16(tag->id), udf_rw16(tag->serial_num), udf_rw32(tag->tag_loc), udf_rw16(tag->desc_crc_len));
}
void udf_dump_anchor(struct anchor_vdp *vdp) {
printf("\t\tAnchor\n");
printf("\t\t\tMain volume descriptor set at %d for %d bytes\n",
udf_rw32(vdp->main_vds_ex.loc), udf_rw32(vdp->main_vds_ex.len));
printf("\t\t\tReserve volume descriptor set at %d for %d bytes\n",
udf_rw32(vdp->reserve_vds_ex.loc), udf_rw32(vdp->reserve_vds_ex.len));
}
void udf_dump_disc_anchors(struct udf_discinfo *disc) {
int session;
printf("\nUDF Dump of disc in device %s\n", disc->dev->dev_name);
printf("UDF sessions : ");
for (session = 0; session < disc->num_sessions; session++) {
if (disc->session_is_UDF[session]) {
printf("Yes");
#if 0
if (disc->session_quirks[session] & CD_SESS_QUIRK_SESSION_LOCAL) {
printf("(local)");
}
#endif
printf(" ");
} else {
printf("No ");
}
}
printf("\n\n");
UDF_VERBOSE_TABLES(
struct udf_session *udf_session;
/* Dump anchors */
STAILQ_FOREACH(udf_session, &disc->sessions, next_session) {
printf("UDF session %d (lba %d + %d sectors) anchor dump : \n", udf_session->session_num,
(uint32_t) disc->session_start[udf_session->session_num], (uint32_t) udf_session->session_length);
udf_dump_descriptor((union dscrptr *) &udf_session->anchor);
}
)
}
char *udf_messy_unicode_conv(char *buf) {
static char out_buf[1024];
uint16_t *uni_pos, uni_char;
char *pos;
pos = out_buf;
uni_pos = (uint16_t *) buf;
while ((uni_char = *uni_pos++)) {
if (uni_char & 0xff00) uni_char='_';
*pos++ = uni_char;
}
return out_buf;
}
char *udf_get_osname(int os_class, int os_id) {
static char buffer[40];
switch (os_class) {
case 0 : return "undefined OS";
case 1 : return "DOS/Windows 3.x";
case 2 : return "OS/2";
case 3 : return "MacOS";
case 4 :
switch (os_id) {
case 0 : return "UNIX";
case 1 : return "IBM AIX";
case 2 : return "SunOS/Solaris";
case 3 : return "HP/UX";
case 4 : return "Silicon Graphics Irix";
case 5 : return "Linux";
case 6 : return "MKLinux";
case 7 : return "FreeBSD";
case 8 : return "NetBSD";
default :
sprintf(buffer, "unknown UNIX (%d)", os_id);
return buffer;
}
case 5 : return "MS Windows 9x";
case 6 : return "MS Windows NT";
case 7 : return "OS/400";
case 8 : return "BeOS";
case 9 : return "MS Windows CE";
default :
break;
}
sprintf(buffer, "unknown OS (%d, %d)", os_class, os_id);
return buffer;
}
void udf_dump_regid(char *prefix, struct regid *id, int regid_type) {
char buffer[UDF_REGID_ID_SIZE+1];
int cnt, version;
uint8_t *pos;
memcpy(buffer, id->id, UDF_REGID_ID_SIZE);
buffer[UDF_REGID_ID_SIZE] = 0;
printf("%s `%s`", prefix, buffer);
if (regid_type == UDF_REGID_NAME) {
printf("\n");
return;
}
printf(" (");
pos = id->id_suffix;
switch (regid_type) {
case UDF_REGID_DOMAIN :
version = udf_rw16(*((uint16_t *) pos));
printf("UDFv %x; ", version);
if ((pos[2]) & UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT) printf("HARD ");
if ((pos[2]) & UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT) printf("SOFT");
if (((pos[2]) & 3) == 0) printf("no");
printf(" write protect ");
if ((pos[2]) & ~3) printf("; also undefined flags 0x%d", pos[2] & ~3);
break;
case UDF_REGID_UDF :
version = udf_rw16(*((uint16_t *) pos));
printf("UDFv %x; ", version);
printf("%s ", udf_get_osname(pos[2], pos[3]));
break;
case UDF_REGID_IMPLEMENTATION :
printf("%s [", udf_get_osname(pos[0], pos[1]));
for(cnt=2; cnt < 8; cnt++) {
printf("%02x ", *pos++);
}
printf("]");
break;
case UDF_REGID_NAME :
break;
case UDF_REGID_APPLICATION :
default :
printf("[");
for(cnt=0; cnt < 8; cnt++) {
printf("%02x ", *pos++);
}
printf("]");
break;
}
printf(") (flags=%d)\n", id->flags);
}
void udf_dump_timestamp(char *prefix, struct timestamp *t) {
printf("%s (%4d %02d %02d at %02d:%02d:%02d.%02d.%02d.%02d)\n", prefix, udf_rw16(t->year), t->month, t->day,
t->hour, t->minute, t->second, t->centisec, t->hund_usec, t->usec);
}
#if 0
void udf_dump_charspec(char *prefix, struct charspec *chsp) {
int cnt, ch;
printf("%s type CS%d (", prefix, chsp->type);
for (cnt=0; cnt<63; cnt++) {
ch = chsp->inf[cnt];
if (ch < 32 || ch > 126) {
printf(".");
} else {
printf("%c", ch);
}
}
printf(")\n");
}
#endif
void udf_dump_sparing_table(struct udf_sparing_table *spt) {
struct spare_map_entry *sp_entry;
uint32_t entry, entries;
printf("\t\tSparing table descriptor\n");
udf_dump_regid("\t\t\tSparing table Id ", &spt->id, UDF_REGID_UDF);
printf("\t\t\tRelocation table entries %d\n", udf_rw16(spt->rt_l));
printf("\t\t\tSequence number %d\n", udf_rw32(spt->seq_num));
printf("\t\t\tMappings :");
entries = udf_rw16(spt->rt_l);
for(entry = 0; entry < entries; entry++) {
if (entry % 4 == 0) printf("\n\t\t\t\t");
sp_entry = &spt->entries[entry];
printf("[%08x -> %08x] ", udf_rw32(sp_entry->org), udf_rw32(sp_entry->map));
}
printf("\n");
}
void udf_dump_pri_vol(struct pri_vol_desc *pvd) {
struct extent_ad *ext;
printf("\t\tPrimary volume descriptor\n");
printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pvd->seq_num));
printf("\t\t\tPrimary volume descriptor number %d\n", udf_rw32(pvd->pvd_num));
udf_dump_id("\t\t\tVolume Id ", 32, pvd->vol_id, &pvd->desc_charset);
printf("\t\t\tVolume sequence number %d\n", udf_rw16(pvd->vds_num));
printf("\t\t\tMaximum volume sequence number %d\n", udf_rw16(pvd->max_vol_seq));
printf("\t\t\tInterchange level %d\n", udf_rw16(pvd->ichg_lvl));
printf("\t\t\tMaximum interchange level %d\n", udf_rw16(pvd->max_ichg_lvl));
udf_dump_id("\t\t\tVolume set Id ", 128, pvd->volset_id, &pvd->desc_charset);
/* udf_dump_charspec("\t\t\tCharspec for this descriptor ", &pvd->desc_charset); */
/* udf_dump_charspec("\t\t\tCharspec for the explaination ", &pvd->explanatory_charset); */
ext = &pvd->vol_abstract;
printf("\t\t\tVolume abstract at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len));
ext = &pvd->vol_copyright;
printf("\t\t\tVolume copyright at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len));
udf_dump_regid("\t\t\tApplication id", &pvd->app_id, UDF_REGID_APPLICATION);
udf_dump_timestamp("\t\t\tTimestamp", &pvd->time);
udf_dump_regid("\t\t\tImplementator id", &pvd->imp_id, UDF_REGID_IMPLEMENTATION);
printf("\t\t\tPrevious volume descriptor sequence locator at sector %d\n", udf_rw32(pvd->prev_vds_loc));
printf("\t\t\tFlags %d\n", udf_rw16(pvd->flags));
}
void udf_dump_implementation_volume(struct impvol_desc *ivd) {
struct charspec *charspec;
printf("\t\tImplementation use volume descriptor\n");
printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(ivd->seq_num));
udf_dump_regid("\t\t\tImplementator identifier", &ivd->impl_id, UDF_REGID_UDF);
/* check on UDF implementation info ... */
if (strcmp((char *) ivd->impl_id.id, "*UDF LV Info") == 0) {
charspec = &ivd->_impl_use.lv_info.lvi_charset;
/* udf_dump_charspec("\t\t\tLV info charspec ", charspec); */
udf_dump_id("\t\t\tLogical volume identifier ", 128, ivd->_impl_use.lv_info.logvol_id, charspec);
udf_dump_id("\t\t\tLV info 1 ", 36, ivd->_impl_use.lv_info.lvinfo1, charspec);
udf_dump_id("\t\t\tLV info 2 ", 36, ivd->_impl_use.lv_info.lvinfo2, charspec);
udf_dump_id("\t\t\tLV info 3 ", 36, ivd->_impl_use.lv_info.lvinfo3, charspec);
udf_dump_regid("\t\t\tImplementation identifier", &ivd->_impl_use.lv_info.impl_id, UDF_REGID_IMPLEMENTATION);
}
}
char *udf_dump_partition_access_type(int type) {
switch (type) {
case UDF_ACCESSTYPE_PSEUDO_OVERWITE : return "Pseudo overwiteable";
case UDF_ACCESSTYPE_READ_ONLY : return "Read only";
case UDF_ACCESSTYPE_WRITE_ONCE : return "Write once";
case UDF_ACCESSTYPE_REWRITEABLE : return "Rewritable (blocked or with erase)";
case UDF_ACCESSTYPE_OVERWRITABLE : return "Overwritable";
}
return "Unknown partion access type";
}
void udf_dump_part(struct part_desc *pd) {
struct part_hdr_desc *part_hdr_desc;
printf("\t\tPartition descriptor\n");
printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pd->seq_num));
printf("\t\t\tFlags %d\n", udf_rw16(pd->flags));
printf("\t\t\tPartition number %d\n", udf_rw16(pd->part_num));
udf_dump_regid("\t\t\tContents", &pd->contents, UDF_REGID_APPLICATION);
printf("\t\t\tAccessType %s\n", udf_dump_partition_access_type(udf_rw32(pd->access_type)));
printf("\t\t\tPartition starts at sector %d for %d sectors\n", udf_rw32(pd->start_loc), udf_rw32(pd->part_len));
udf_dump_regid("\t\t\tImplementator id", &pd->imp_id, UDF_REGID_IMPLEMENTATION);
printf("\t\t\tPartition contents use (file) descriptors:\n");
if (strncmp((char *) pd->contents.id, "+NSR0", 5) == 0) {
part_hdr_desc = &pd->pd_part_hdr;
printf("\t\t\t\tUnallocated space table at logic block %d for %d bytes\n",
udf_rw32(part_hdr_desc->unalloc_space_table.lb_num),
udf_rw32(part_hdr_desc->unalloc_space_table.len)
);
printf("\t\t\t\tUnallocated space bitmap at logic block %d for %d bytes\n",
udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num),
udf_rw32(part_hdr_desc->unalloc_space_bitmap.len)
);
printf("\t\t\t\tPartition integrety table at logic block %d for %d bytes\n",
udf_rw32(part_hdr_desc->part_integrety_table.lb_num),
udf_rw32(part_hdr_desc->part_integrety_table.len)
);
printf("\t\t\t\tReusable (freed) space table at logic block %d for %d bytes\n",
udf_rw32(part_hdr_desc->freed_space_table.lb_num),
udf_rw32(part_hdr_desc->freed_space_table.len)
);
printf("\t\t\t\tReusable (freed) space bitmap at logic block %d for %d bytes\n",
udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num),
udf_rw32(part_hdr_desc->freed_space_bitmap.len)
);
} else {
printf("\t\t\t\tWARNING: Unknown or unused contents\n");
}
}
void udf_dump_log_vol(struct logvol_desc *lvd) {
union udf_pmap *pmap;
uint8_t pmap_type, pmap_size;
uint8_t *pmap_pos;
int map, sparing_table;
uint32_t lb_size, packet_len;
lb_size = udf_rw32(lvd->lb_size);
printf("\t\tLogical volume descriptor\n");
printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(lvd->seq_num));
udf_dump_id("\t\t\tLogical volume id ", 128, lvd->logvol_id, &lvd->desc_charset);
printf("\t\t\tLogical block size %d\n", udf_rw32(lvd->lb_size));
udf_dump_regid("\t\t\tDomainId", &lvd->domain_id, UDF_REGID_DOMAIN);
udf_dump_long_ad("\t\t\tFileset descriptor at", &lvd->_lvd_use.fsd_loc);
printf("\t\t\tMap table length %d\n", udf_rw32(lvd->mt_l));
printf("\t\t\tNumber of part maps %d\n", udf_rw32(lvd->n_pm));
udf_dump_regid("\t\t\tImplementation id", &lvd->imp_id, UDF_REGID_IMPLEMENTATION);
printf("\t\t\tIntegrety sequence at %d for %d bytes\n",
udf_rw32(lvd->integrity_seq_loc.loc), udf_rw32(lvd->integrity_seq_loc.len));
printf("\t\t\tPartion maps follow\n");
pmap_pos = &lvd->maps[0];
for (map = 0; map < udf_rw32(lvd->n_pm); map++) {
pmap = (union udf_pmap *) pmap_pos;
pmap_type = pmap->data[0];
pmap_size = pmap->data[1];
printf("\t\t\t\tPartion map type %d length %d \n", pmap_type, pmap_size);
/* only pmap types 1 and pmap types 2 are to be used */
printf("\t\t\t\t\tLogical %d maps to ", map);
switch (pmap_type) {
case 1 :
printf("partition %d on volume seq. number %d directly\n",
udf_rw16(pmap->pm1.part_num), udf_rw16(pmap->pm1.vol_seq_num));
break;
case 2 :
printf("partition %d on volume seq. number %d using\n",
udf_rw16(pmap->pm2.part_num), udf_rw16(pmap->pm2.vol_seq_num));
udf_dump_regid("\t\t\t\t\tmapping type", &pmap->pm2.part_id, UDF_REGID_UDF);
if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Virtual Partition", UDF_REGID_ID_SIZE) == 0) {
/* nothing to print... */
}
if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Sparable Partition", UDF_REGID_ID_SIZE) == 0) {
packet_len = udf_rw16(pmap->pms.packet_len);
printf("\t\t\t\t\t\tPacket length %d sectors (%d bytes)\n",
packet_len, packet_len * lb_size);
printf("\t\t\t\t\t\tNumber of sparing tables %d\n", pmap->pms.n_st);
printf("\t\t\t\t\t\tSize of each sparing table %d\n", udf_rw32(pmap->pms.st_size));
if (pmap->pms.n_st) {
printf("\t\t\t\t\t\tSparing tables at sectors ");
for (sparing_table = 0; sparing_table < pmap->pms.n_st; sparing_table++) {
printf("%d ", udf_rw32(pmap->pms.st_loc[sparing_table]));
}
printf("\n");
}
}
if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Metadata Partition", UDF_REGID_ID_SIZE) == 0) {
printf("\t\t\t\t\t\tMetadata is %sduplicated on disc\n", pmap->pmm.flags & METADATA_DUPLICATED ? "":"NOT ");
printf("\t\t\t\t\t\tAllocation unit size %d sectors\n", udf_rw32(pmap->pmm.alloc_unit_size));
printf("\t\t\t\t\t\tAlignment unit size %d sectors\n", udf_rw32(pmap->pmm.alignment_unit_size));
printf("\t\t\t\t\t\tMetadata file at part. sector %d\n", udf_rw32(pmap->pmm.meta_file_lbn));
if (udf_rw32(pmap->pmm.meta_mirror_file_lbn) != -1)
printf("\t\t\t\t\t\tMetadata mirror file at part. sector %d\n", udf_rw32(pmap->pmm.meta_mirror_file_lbn));
if (udf_rw32(pmap->pmm.meta_bitmap_file_lbn) != -1)
printf("\t\t\t\t\t\tMetadata bitmap file at part. sector %d\n", udf_rw32(pmap->pmm.meta_bitmap_file_lbn));
}
break;
default :
break;
}
pmap_pos += pmap_size;
}
}
void udf_dump_unalloc_space(struct unalloc_sp_desc *usd) {
struct extent_ad *alloc_desc;
int desc_num;
printf("\t\tUnallocated space descriptor\n");
printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(usd->seq_num));
printf("\t\t\tNumber of free space slots %d\n", udf_rw32(usd->alloc_desc_num));
if (udf_rw32(usd->alloc_desc_num)) {
printf("\t\t\tFree space at : ");
for (desc_num = 0; desc_num < udf_rw32(usd->alloc_desc_num); desc_num++) {
alloc_desc = &usd->alloc_desc[desc_num];
printf("[%d %d] ", udf_rw32(alloc_desc->loc), udf_rw32(alloc_desc->loc)+udf_rw32(alloc_desc->len));
}
printf("\n");
}
}
void udf_dump_terminating_desc(union dscrptr *desc) {
desc = desc;
printf("\t\tTerminating descriptor\n");
}
void udf_dump_logvol_integrity(struct logvol_int_desc *lvid) {
struct udf_logvol_info *impl;
uint32_t part, num_part;
uint32_t *pos1, *pos2;
uint32_t free, size, rest_bytes;
uint32_t version;
printf("\t\tLogical volume integrity descriptor\n");
udf_dump_timestamp("\t\t\tTimestamp ", &lvid->time);
printf("\t\t\tIntegrity type %s\n", udf_rw32(lvid->integrity_type) ? "closed":"open");
printf("\t\t\tNext integrety sequence at %d for %d bytes\n",
udf_rw32(lvid->next_extent.loc), udf_rw32(lvid->next_extent.len));
printf("\t\t\tNext free unique file ID %d\n", (uint32_t) udf_rw64(lvid->lvint_next_unique_id));
printf("\t\t\tLength of implementation use area %d bytes\n", udf_rw32(lvid->l_iu));
num_part = udf_rw32(lvid->num_part);
printf("\t\t\tNumber of partitions %d\n", num_part);
for (part=0; part < num_part; part++) {
pos1 = &lvid->tables[0] + part;
pos2 = &lvid->tables[0] + num_part + part;
free = udf_rw32(*pos1);
size = udf_rw32(*pos2);
printf("\t\t\tPartition %d : %d blocks free space out of %d blocks\n", part, free, size);
}
/* printout the implementation use field */
impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
udf_dump_regid("\t\t\tImplemenator Id", &impl->impl_id, UDF_REGID_IMPLEMENTATION );
printf("\t\t\tNumber of files %d\n", udf_rw32(impl->num_files));
printf("\t\t\tNumber of directories %d\n", udf_rw32(impl->num_directories));
version = udf_rw16(impl->min_udf_readver);
printf("\t\t\tMinimum readversion UDFv %x\n", version);
version = udf_rw16(impl->min_udf_writever);
printf("\t\t\tMinimum writeversion UDFv %x\n", version);
version = udf_rw16(impl->max_udf_writever);
printf("\t\t\tMaximum writeversion UDFv %x\n", version);
rest_bytes = udf_rw32(lvid->l_iu)-sizeof(struct udf_logvol_info);
if (rest_bytes > 0) printf("\t\t\t<%d bytes of undumped extra implementation use area>", rest_bytes);
printf("\n");
}
void udf_dump_fileset_desc(struct fileset_desc *fsd) {
printf("\t\tFileset descriptor\n");
udf_dump_timestamp("\t\t\tTimestamp ", &fsd->time);
printf("\t\t\tInterchange level %d\n", udf_rw16(fsd->ichg_lvl));
printf("\t\t\tMax interchange level %d\n", udf_rw16(fsd->max_ichg_lvl));
printf("\t\t\tCharset lists %d\n", udf_rw32(fsd->charset_list));
printf("\t\t\tMax charset lists %d\n", udf_rw32(fsd->max_charset_list));
printf("\t\t\tFileset number %d\n", udf_rw32(fsd->fileset_num));
printf("\t\t\tFileset descriptor number %d\n", udf_rw32(fsd->fileset_desc_num));
/* udf_dump_charspec("\t\t\tLogical volume id charspec ", &fsd->logvol_id_charset); */
/* udf_dump_charspec("\t\t\tFileset id charspec ", &fsd->fileset_charset); */
udf_dump_id("\t\t\tLogical volume id ", 128, fsd->logvol_id, &fsd->logvol_id_charset);
udf_dump_id("\t\t\tFileset id ", 32, fsd->fileset_id, &fsd->fileset_charset);
udf_dump_id("\t\t\tCopyright file id ", 32, fsd->copyright_file_id, &fsd->fileset_charset);
udf_dump_id("\t\t\tAbstract file id ", 32, fsd->abstract_file_id, &fsd->fileset_charset);
udf_dump_regid("\t\t\tDomainId", &fsd->domain_id, UDF_REGID_DOMAIN);
udf_dump_long_ad("\t\t\tRootdir ICB found ", &fsd->rootdir_icb);
udf_dump_long_ad("\t\t\tNext extend for fileset ", &fsd->next_ex);
udf_dump_long_ad("\t\t\tStreamdir ICB found ", &fsd->streamdir_icb);
}
void udf_dump_fileid_in_charspec(struct fileid_desc *fid, struct charspec *chsp) {
char *pos, file_char;
printf("\tFile id entry\n");
printf("\t\tFile version number %d\n", udf_rw16(fid->file_version_num));
file_char = fid->file_char;
printf("\t\tFile characteristics %d :\t", file_char);
if (file_char & UDF_FILE_CHAR_VIS) printf("hidden ");
if (file_char & UDF_FILE_CHAR_DEL) printf("deleted ");
if (file_char & UDF_FILE_CHAR_PAR) printf("parent(..) ");
if (file_char & UDF_FILE_CHAR_DIR) printf("directory ");
if (file_char & UDF_FILE_CHAR_META) printf("METADATA ");
printf("\n");
udf_dump_long_ad("\t\tFile ICB", &fid->icb);
printf("\t\tLength of file identifier area %d\n", fid->l_fi);
printf("\t\tOSTA UDF Unique ID %d\n", fid->icb.impl.im_used.unique_id);
printf("\t\tOSTA UDF fileflags %d\n", fid->icb.impl.im_used.flags);
printf("\t\tImplementation use length %d\n", udf_rw16(fid->l_iu));
if (udf_rw16(fid->l_iu)) {
/* Ecma 1/7.4 demands a (padded if wanted) implementation identifier */
if (udf_rw16(fid->l_iu) >= sizeof(struct regid)) {
udf_dump_regid("\t\t\tModified by", (struct regid *) &fid->data, UDF_REGID_IMPLEMENTATION);
} else {
printf("\t\t\tBROKEN fid, expected at least enough space for implementation regid\n");
}
}
pos = (char *) fid->data + udf_rw16(fid->l_iu);
if (file_char & UDF_FILE_CHAR_PAR) {
printf("\t\tParent directory ..\n");
} else {
udf_dump_id("\t\tFilename", fid->l_fi, pos, chsp);
}
}
void udf_dump_fileid(struct fileid_desc *fid) {
struct charspec chsp;
/* prolly OSTA compressed unicode anyway */
chsp.type = 0;
strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
udf_dump_fileid_in_charspec(fid, &chsp);
}
void udf_dump_icb_tag(struct icb_tag *icb_tag) {
uint32_t flags, strat_param16;
flags = udf_rw16(icb_tag->flags);
strat_param16 = udf_rw16(* (uint16_t *) icb_tag->strat_param);
printf("\t\tICB Prior direct entries recorded (excl.) %d\n", udf_rw32(icb_tag->prev_num_dirs));
printf("\t\tICB Strategy type %d\n", udf_rw16(icb_tag->strat_type));
printf("\t\tICB Strategy type flags %d %d\n", icb_tag->strat_param[0], icb_tag->strat_param[1]);
printf("\t\tICB Maximum number of entries (non strat 4) %d\n", udf_rw16(icb_tag->max_num_entries));
printf("\t\tICB indirect entries/depth %d\n", strat_param16);
printf("\t\tICB File type %d\n", icb_tag->file_type);
printf("\t\tICB Parent ICB in logical block %d of mapped partition %d\n",
udf_rw32(icb_tag->parent_icb.lb_num), udf_rw16(icb_tag->parent_icb.part_num));
printf("\t\tICB Flags %d\n", udf_rw16(icb_tag->flags));
printf("\t\t\tFile/directory information using : ");
switch (flags & UDF_ICB_TAG_FLAGS_ALLOC_MASK) {
case UDF_ICB_SHORT_ALLOC :
printf("short allocation descriptor\n");
break;
case UDF_ICB_LONG_ALLOC :
printf("long allocation descriptor\n");
break;
case UDF_ICB_EXT_ALLOC :
printf("extended allocation descriptor (out of specs)\n");
break;
case UDF_ICB_INTERN_ALLOC :
printf("internal in the ICB\n");
break;
}
if (icb_tag->file_type == UDF_ICB_FILETYPE_DIRECTORY)
if (flags & UDF_ICB_TAG_FLAGS_DIRORDERED)
printf("\t\t\tOrdered directory\n");
if (flags & UDF_ICB_TAG_FLAGS_NONRELOC) printf("\t\t\tNot relocatable\n");
printf("\t\t\tFile flags :");
if (flags & UDF_ICB_TAG_FLAGS_SETUID) printf("setuid() ");
if (flags & UDF_ICB_TAG_FLAGS_SETGID) printf("setgid() ");
if (flags & UDF_ICB_TAG_FLAGS_STICKY) printf("sticky ");
printf("\n");
if (flags & UDF_ICB_TAG_FLAGS_CONTIGUES)
printf("\t\t\tFile is contigues i.e. in one piece effectively \n");
if (flags & UDF_ICB_TAG_FLAGS_MULTIPLEVERS)
printf("\t\t\tExpect multiple versions of a file in this directory\n");
}
void udf_dump_indirect_entry(struct indirect_entry *inde) {
printf("\tIndirect (ICB) entry\n");
udf_dump_icb_tag(&inde->icbtag);
udf_dump_long_ad("\t\tPointing at", &inde->indirect_icb);
printf("\n");
}
void udf_dump_allocation_entries(uint8_t addr_type, uint8_t *pos, uint32_t data_length) {
union icb *icb;
uint32_t size, piece_length, piece_flags;
uint32_t entry;
entry = 0;
size = 0;
while (data_length) {
if (entry % 1 == 0) printf("\n\t");
printf(" [ ");
printf("blob at ");
/* what to do with strat type == 3 ? or is all set up ok then ? */
icb = (union icb *) pos;
switch (addr_type) {
case UDF_ICB_SHORT_ALLOC :
piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<30)-1);
piece_flags = udf_rw32(icb->s_ad.len) >> 30; /* XXX ecma167 48.14.1.1 XXX */
printf("sector %8u for %8d bytes", udf_rw32(icb->s_ad.lb_num), piece_length);
if (piece_flags) printf(" flags %d", piece_flags);
size = sizeof(struct short_ad);
if (piece_length == 0) size = data_length;
break;
case UDF_ICB_LONG_ALLOC :
piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<30)-1);
piece_flags = udf_rw32(icb->l_ad.len) >> 30; /* XXX ecma167 48.14.1.1 XXX */
printf("sector %8d for %8d bytes in logical partion %d", udf_rw32(icb->l_ad.loc.lb_num), piece_length,
udf_rw16(icb->l_ad.loc.part_num));
if (piece_flags) printf(" flags %d", piece_flags);
size = sizeof(struct long_ad);
if (piece_length == 0) size = data_length;
break;
case UDF_ICB_EXT_ALLOC :
printf("extended alloc (help)");
size = sizeof(struct ext_ad);
break;
case UDF_ICB_INTERN_ALLOC :
printf("internal blob here for %d bytes", data_length);
size = data_length;
break;
}
printf(" ] ");
entry++;
pos += size;
data_length -=size;
}
printf("\n");
}
/* TODO create a read-in/insert/cleanup etc. for extra attributes */
void udf_dump_extattrseq(char *prefix, uint8_t *start, uint32_t offset, uint32_t impl_offset, uint32_t appl_offset, uint32_t length) {
struct impl_extattr_entry *impl_extattr;
struct appl_extattr_entry *appl_extattr;
struct filetimes_extattr_entry *filetimes_extattr;
struct device_extattr_entry *device_extattr;
struct vatlvext_extattr_entry *vatlvext_extattr;
struct extattr_entry *extattr;
struct timestamp *timestamp;
struct charspec chsp;
uint32_t extattr_len, au_l, iu_l, d_l;
uint32_t type, subtype, chksum, attr_space, print_attr_space;
uint32_t existence;
uint8_t *pos;
char *type_txt, what[256];
int is_free_ea_space, is_free_app_ea_space, is_vatlvext_space, bit;
/* if used its OSTA compressed unicode anyway */
chsp.type = 0;
strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
/* if one of the offsets is `-1' (0xffffffff), it indicates that its not present; God i hate magic values */
if (impl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
printf("\t\tNOTE: indicated no implementation related attributes are recorded in this extent\n");
if (appl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
printf("\t\tNOTE: indicated no application related attributes are recorded in this extent\n");
pos = start;
attr_space = UDF_REGID_UDF; /* really? */
while (length > 0) {
extattr = (struct extattr_entry *) pos;
extattr_len = udf_rw32(extattr->a_l);
type = udf_rw32(extattr->type);
subtype = extattr->subtype;
if (pos == start) printf("\t\tStart of extended file related attributes area\n");
if (offset == impl_offset) printf("\t\tStart of implementation related attributes area\n");
if (offset == appl_offset) printf("\t\tStart of application related attributes area\n");
if (pos == start) attr_space = UDF_REGID_UDF;
if (offset == impl_offset) attr_space = UDF_REGID_IMPLEMENTATION;
if (offset == appl_offset) attr_space = UDF_REGID_APPLICATION;
if (subtype != 1) printf("\t\t\tWARNING: unknown subtype %d\n", subtype);
print_attr_space = attr_space;
switch (type) {
case 65536 : /* [4/48.10.8] application use extended attributes */
appl_extattr = (struct appl_extattr_entry *) pos;
au_l = udf_rw32(appl_extattr->au_l);
printf("\t\t\tApplication use extended attribute\n");
if (attr_space != UDF_REGID_APPLICATION)
printf("\t\t\t\t*** application use extended attribute found in non application use area ***\n");
printf("\t\t\t\tLength of application use space %d\n", au_l);
udf_dump_regid("\t\t\t\tApplication use Id", &appl_extattr->appl_id, attr_space);
break;
case 2048 : /* [4/48.10.9] implementation use extended attributes */
impl_extattr = (struct impl_extattr_entry *) pos;
iu_l = udf_rw32(impl_extattr->iu_l);
chksum = udf_rw16(*((uint16_t *) impl_extattr->data));
printf("\t\t\tImplementation use extended attribute\n");
if (chksum != udf_ea_cksum(pos))
printf("\t\t\t\t*** header checksum failed (%d should be %d) ***\n", chksum, udf_ea_cksum(pos));
if (attr_space != UDF_REGID_IMPLEMENTATION)
printf("\t\t\t\t*** implementation use extended attribute found in non implementation use area ***\n");
if (strncmp((char *) impl_extattr->imp_id.id, "*UDF", 4) == 0)
print_attr_space = UDF_REGID_UDF;
printf("\t\t\t\tLength of implementation use space %d\n", iu_l);
udf_dump_regid("\t\t\t\tImplemenation use Id", &impl_extattr->imp_id, print_attr_space);
is_free_ea_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeEASpace") == 0);
is_free_app_ea_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeAppEASpace") == 0);
is_vatlvext_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF VAT LVExtension") == 0);
if (is_free_ea_space || is_free_app_ea_space) {
printf("\t\t\t\tFree space for new extended attributes (%d bytes total)\n", extattr_len);
} else if (is_vatlvext_space) {
vatlvext_extattr = (struct vatlvext_extattr_entry *) (impl_extattr->data + iu_l);
printf("\t\t\t\t\tUniqueID check %"PRIu64"\n", udf_rw64(vatlvext_extattr->unique_id_chk));
printf("\t\t\t\t\tNumber of files %d\n", udf_rw32(vatlvext_extattr->num_files));
printf("\t\t\t\t\tNumber of directories %d\n", udf_rw32(vatlvext_extattr->num_directories));
udf_dump_id("\t\t\t\t\tLogical volume id ", 128, vatlvext_extattr->logvol_id, &chsp);
} else {
printf("\t\t\t\t<Undumped %d bytes of implementation use data>\n", iu_l);
}
break;
case 1 : /* [4/48.10.3] : Character set information; UDF does allow/disallow explicitly */
printf("\t\t\tCharacter set information attribute\n");
printf("\t\t\t\t<Undumped %d bytes attribute>\n", extattr_len);
break;
case 3 : /* [4/48.10.4] : Alternate permissions; UDF 3.3.4.2: not to be recorded */
printf("\t\t\tAlternate permission attribute\n");
printf("\t\t\t\t<Undumped %d bytes attribute>\n", extattr_len);
break;
case 5 : /* [4/48.10.5] : File Times Extended Attribute */
case 6 : /* [4/48.10.6] : Information Times Extended Attribute; recorded in UDF ? */
/* ASSUMPTION : bit fields are not exlusive */
filetimes_extattr = (struct filetimes_extattr_entry *) pos;
d_l = udf_rw32(filetimes_extattr->d_l);
existence = udf_rw32(filetimes_extattr->existence);
type_txt = "File";
if (type == 6) type_txt = "File information";
printf("\t\t\t%s times extended attribute\n", type_txt);
timestamp = &filetimes_extattr->times[0];
for (bit = 0; bit < 32; bit++) {
if (d_l == 0) break;
if (!existence & bit)
continue;
switch (bit) {
case 0 : /* File Creation Date and Time: the date and time of the day at which the file was created. */
sprintf(what, "\t\t\t\t%s created at ", type_txt);
break;
case 1 : /* Information Last Modification Date and Time: the date and time of the day at which the information in the file was last modified. */
sprintf(what, "\t\t\t\t%s last modified at ", type_txt);
break;
case 2 : /* File Deletion Date and Time: the date and time of the day after which the file may be deleted. */
sprintf(what, "\t\t\t\t%s may be deleted after ", type_txt);
break;
case 3 : /* File Effective Date and Time: the date and time of the day after which the file may be used. */
sprintf(what, "\t\t\t\t%s may only be used after ", type_txt);
break;
case 5 : /* File Last Backup Date and Time: the date and time of the day at which the file was last backed up. */
sprintf(what, "\t\t\t\t%s last backuped at ", type_txt);
break;
default : /* unspec */
sprintf(what, "\t\t\t\tUndefined meaning for %s time stamp ", type_txt);
break;
}
udf_dump_timestamp(what, timestamp);
d_l -= sizeof(struct timestamp);
timestamp++; /* advance */
}
break;
case 12 : /* [4/48.10.7] : Device Specification Extended Attribute */
device_extattr = (struct device_extattr_entry *) pos;
iu_l = udf_rw32(device_extattr->iu_l);
printf("\t\t\tDevice node extended attribute\n");
printf("\t\t\t\tMajor %d\n", udf_rw32(device_extattr->major));
printf("\t\t\t\tMinor %d\n", udf_rw32(device_extattr->minor));
if (iu_l >= sizeof(struct regid)) {
udf_dump_regid("\t\t\t\tImplementator", (struct regid *) (device_extattr->data), UDF_REGID_IMPLEMENTATION);
}
break;
default :
printf("\t\t\tUndumped extended attribute type %d\n", type);
printf("\t\t\t\tSubtype %d\n", subtype);
printf("\t\t\t\tLength %d\n", extattr_len);
break;
}
pos += extattr_len;
offset += extattr_len;
length -= extattr_len;
}
printf("\n");
}
void udf_dump_extattr_hdr(struct extattrhdr_desc *eahd, uint32_t length) {
uint32_t hdr_len, impl_attr_loc, appl_attr_loc;
uint8_t *pos;
hdr_len = (uint32_t) sizeof(struct extattrhdr_desc);
impl_attr_loc = udf_rw32(eahd->impl_attr_loc);
appl_attr_loc = udf_rw32(eahd->appl_attr_loc);
printf("\t\tExtended attributes header:\n");
printf("\t\t\tLength %d bytes\n", length);
printf("\t\t\tImplementation attributes at offset %d\n", impl_attr_loc);
printf("\t\t\tApplication attributes at offset %d\n", appl_attr_loc);
printf("\t\t\tBytes remaining after header %d\n", length - hdr_len);
/* determine length of file related attributes space */
pos = (uint8_t *) eahd;
pos += hdr_len;
length -= hdr_len;
udf_dump_extattrseq("\t\tExtended attributes:\n", pos, hdr_len, impl_attr_loc, appl_attr_loc, length);
}
void udf_dump_file_entry(struct file_entry *fe) {
uint8_t *pos;
uint32_t length;
uint8_t addr_type;
uint32_t entries;
uint16_t strategy, strat_param16;
/* direct_entries = udf_rw32(fe->icbtag.prev_num_dirs); */
strat_param16 = udf_rw16(* (uint16_t *) (fe->icbtag.strat_param));
entries = udf_rw16(fe->icbtag.max_num_entries);
strategy = udf_rw16(fe->icbtag.strat_type);
addr_type = udf_rw16(fe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
printf("\tFile entry\n");
udf_dump_icb_tag(&fe->icbtag);
printf("\t\tUid %d\n", udf_rw32(fe->uid));
printf("\t\tGid %d\n", udf_rw32(fe->gid));
printf("\t\tPermissions %x\n", udf_rw32(fe->perm));
printf("\t\tLink count %d\n", udf_rw16(fe->link_cnt));
printf("\t\tRecord format %d\n", fe->rec_format);
printf("\t\tRecord display attributes %d\n", fe->rec_disp_attr);
printf("\t\tRecord length %d\n", fe->rec_len);
printf("\t\tInformation length %"PRIu64"\n", (uint64_t) udf_rw64(fe->inf_len));
printf("\t\tLogical blocks recorded %"PRIu64"\n", (uint64_t) udf_rw64(fe->logblks_rec));
udf_dump_timestamp("\t\tAccess time ", &fe->atime);
udf_dump_timestamp("\t\tModification time ", &fe->mtime);
udf_dump_timestamp("\t\tAttribute time ", &fe->attrtime);
printf("\t\tCheckpoint %d\n", udf_rw32(fe->ckpoint));
udf_dump_long_ad("\t\tExtended attributes ICB at", &fe->ex_attr_icb);
udf_dump_regid("\t\tImplementation", &fe->imp_id, UDF_REGID_IMPLEMENTATION);
printf("\t\tUniqueID %d\n", (uint32_t) udf_rw64(fe->unique_id));
printf("\t\tLength of extended attribute area %d\n", udf_rw32(fe->l_ea));
printf("\t\tLength of allocation descriptors %d\n", udf_rw32(fe->l_ad));
if (udf_rw32(fe->l_ea)) {
udf_dump_extattr_hdr((struct extattrhdr_desc *) &fe->data[0], udf_rw32(fe->l_ea));
}
if (udf_rw32(fe->ex_attr_icb.len)) {
printf("\t\t<Undumped %d bytes of extended attributes descriptor\n", udf_rw32(fe->ex_attr_icb.len));
}
printf("\t\tAllocation descriptors : \n");
pos = &fe->data[0] + udf_rw32(fe->l_ea);
length = udf_rw32(fe->l_ad);
udf_dump_allocation_entries(addr_type, pos, length);
}
void udf_dump_extfile_entry(struct extfile_entry *efe) {
uint8_t *pos;
uint32_t length;
uint8_t addr_type;
uint32_t entries;
uint16_t strategy, strat_param16;
/* direct_entries = udf_rw32(efe->icbtag.prev_num_dirs); */
strat_param16 = udf_rw16(* (uint16_t *) (efe->icbtag.strat_param));
entries = udf_rw16(efe->icbtag.max_num_entries);
strategy = udf_rw16(efe->icbtag.strat_type);
addr_type = udf_rw16(efe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
printf("\tExtended file entry\n");
udf_dump_icb_tag(&efe->icbtag);
printf("\t\tUid %d\n", udf_rw32(efe->uid));
printf("\t\tGid %d\n", udf_rw32(efe->gid));
printf("\t\tPermissions %x\n", udf_rw32(efe->perm));
printf("\t\tLink count %d\n", udf_rw16(efe->link_cnt));
printf("\t\tRecord format %d\n", efe->rec_format);
printf("\t\tRecord display attributes %d\n", efe->rec_disp_attr);
printf("\t\tRecord length %d\n", efe->rec_len);
printf("\t\tInformation length %"PRIu64"\n", (uint64_t) udf_rw64(efe->inf_len));
printf("\t\tObject size %"PRIu64"\n", (uint64_t) udf_rw64(efe->obj_size));
printf("\t\tLogical blocks recorded %"PRIu64"\n", (uint64_t) udf_rw64(efe->logblks_rec));
udf_dump_timestamp("\t\tAccess time ", &efe->atime);
udf_dump_timestamp("\t\tModification time ", &efe->mtime);
udf_dump_timestamp("\t\tCreation time ", &efe->ctime);
udf_dump_timestamp("\t\tAttribute time ", &efe->attrtime);
printf("\t\tCheckpoint %d\n", udf_rw32(efe->ckpoint));
udf_dump_long_ad("\t\tExtended attributes ICB at", &efe->ex_attr_icb);
udf_dump_long_ad("\t\tStreamdir ICB at", &efe->streamdir_icb);
udf_dump_regid("\t\tImplementation", &efe->imp_id, UDF_REGID_IMPLEMENTATION);
printf("\t\tUniqueID %d\n", (uint32_t) udf_rw64(efe->unique_id));
printf("\t\tLength of extended attribute area %d\n", udf_rw32(efe->l_ea));
printf("\t\tLength of allocation descriptors %d\n", udf_rw32(efe->l_ad));
if (udf_rw32(efe->l_ea)) {
udf_dump_extattr_hdr((struct extattrhdr_desc *) &efe->data[0], udf_rw32(efe->l_ea));
}
if (udf_rw32(efe->ex_attr_icb.len)) {
printf("\t\t<Undumped %d bytes of extended attributes descriptor\n", udf_rw32(efe->ex_attr_icb.len));
}
printf("\t\tAllocation descriptors : \n");
pos = &efe->data[0] + udf_rw32(efe->l_ea);
length = udf_rw32(efe->l_ad);
udf_dump_allocation_entries(addr_type, pos, length);
}
/* dump a space table(entry) descriptor */
void udf_dump_space_entry(struct space_entry_desc *sed) {
union icb *icb;
uint32_t addr_type, size, bytes;
uint32_t piece_sector, piece_length, piece_part;
uint8_t *pos;
printf("\tSpace entry table\n");
udf_dump_icb_tag(&sed->icbtag);
printf("\t\tSize in bytes %d\n", udf_rw32(sed->l_ad));
pos = &sed->entry[0];
bytes = udf_rw32(sed->l_ad);
addr_type = udf_rw16(sed->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
while (bytes) {
size = piece_length = piece_sector = piece_part = 0;
icb = (union icb *) pos;
switch (addr_type) {
case UDF_ICB_SHORT_ALLOC :
piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<31)-1);
piece_sector = udf_rw32(icb->s_ad.lb_num);
printf("[at sec %u for %d bytes] ", piece_sector, piece_length);
size = sizeof(struct short_ad);
break;
case UDF_ICB_LONG_ALLOC :
piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<31)-1);
piece_sector = udf_rw32(icb->l_ad.loc.lb_num);
piece_part = udf_rw16(icb->l_ad.loc.part_num);
size = sizeof(struct long_ad);
printf("[at sec %u for %d bytes at partition %d] ", piece_sector, piece_length, piece_part);
break;
case UDF_ICB_EXT_ALLOC :
case UDF_ICB_INTERN_ALLOC :
printf("\t\t\tWARNING : an internal alloc in a space entry?\n");
return;
}
bytes -= size;
}
}
/* dump a space bitmap descriptor */
void udf_dump_space_bitmap(struct space_bitmap_desc *sbd) {
uint32_t bits, from, now, cnt;
uint8_t byte, bit, bitpos, state, *pos;
printf("\t\tSpace bitmap\n");
printf("\t\t\tNumber of bits %d\n", udf_rw32(sbd->num_bits));
printf("\t\t\tNumber of bytes %d\n", udf_rw32(sbd->num_bytes));
printf("\t\t\tMarked parts at :\n");
pos = sbd->data;
bits = udf_rw32(sbd->num_bits);
/* shield */
/* if (bits > 2000*8) bits = 2000*8; */
printf("\t\t\t\t");
cnt = 0; from = 0; now = 0; bitpos = 0; byte = *pos; state = byte & 1;
while (now < bits) {
if (bitpos == 0) {
byte = *pos++;
}
bit = byte & 1;
if (bit != state) {
if (state) {
printf("[%08d - %08d]", from, now-1);
if (cnt % 4 == 3) printf("\n\t\t\t\t"); else printf(" ");
cnt++;
}
from = now;
state = bit;
}
byte >>= 1;
bitpos = (bitpos+1) & 7;
now++;
}
if (state) printf("[%08d - %08d]", from, now);
if (bits < udf_rw32(sbd->num_bits)) printf(" .... <trimmed>\n");
}
/* main descriptor `dump' function */
void udf_dump_descriptor(union dscrptr *dscrpt) {
struct desc_tag *tag = &dscrpt->tag;
int error;
/* check if its a valid descritor */
if (udf_rw16(tag->id == 0) && udf_rw16(tag->descriptor_ver) == 0) return;
udf_dump_desc(tag);
error = udf_check_tag(dscrpt);
if (error) {
printf("\tBAD TAG\n");
return;
}
switch (udf_rw16(tag->id)) {
case TAGID_SPARING_TABLE :
udf_dump_sparing_table(&dscrpt->spt);
break;
case TAGID_PRI_VOL :
udf_dump_pri_vol(&dscrpt->pvd);
break;
case TAGID_ANCHOR :
udf_dump_anchor(&dscrpt->avdp);
break;
case TAGID_VOL :
udf_dump_unimpl(dscrpt);
break;
case TAGID_IMP_VOL :
udf_dump_implementation_volume(&dscrpt->ivd);
break;
case TAGID_PARTITION :
udf_dump_part(&dscrpt->pd);
break;
case TAGID_LOGVOL :
udf_dump_log_vol(&dscrpt->lvd);
break;
case TAGID_UNALLOC_SPACE :
udf_dump_unalloc_space(&dscrpt->usd);
break;
case TAGID_TERM :
udf_dump_terminating_desc(dscrpt);
break;
case TAGID_LOGVOL_INTEGRITY :
udf_dump_logvol_integrity(&dscrpt->lvid);
break;
case TAGID_FSD :
udf_dump_fileset_desc(&dscrpt->fsd);
break;
case TAGID_FID :
udf_dump_fileid(&dscrpt->fid);
break;
case TAGID_ALLOCEXTENT :
udf_dump_unimpl(dscrpt);
break;
case TAGID_INDIRECT_ENTRY :
udf_dump_indirect_entry(&dscrpt->inde);
break;
case TAGID_FENTRY :
udf_dump_file_entry(&dscrpt->fe);
break;
case TAGID_EXTATTR_HDR :
udf_dump_extattr_hdr(&dscrpt->eahd, sizeof(struct extattrhdr_desc));
break;
case TAGID_UNALL_SP_ENTRY :
udf_dump_space_entry(&dscrpt->sed);
break;
case TAGID_SPACE_BITMAP :
udf_dump_space_bitmap(&dscrpt->sbd);
break;
case TAGID_PART_INTEGRETY :
udf_dump_unimpl(dscrpt);
break;
case TAGID_EXTFENTRY :
udf_dump_extfile_entry(&dscrpt->efe);
break;
default :
break;
}
printf("\n");
}
/* this one is special since the VAT table has no tag but is a file */
void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping) {
struct charspec chsp;
struct udf_vat *vat;
uint32_t previous_vat, entry, vat_entries, *vat_pos, version;
/* prolly OSTA compressed unicode anyway */
chsp.type = 0;
strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
vat = udf_part_mapping->vat;
printf("\tVAT table: ");
printf("%s UDF 2.00 format\n", vat?"post":"pre");
vat_entries = udf_part_mapping->vat_entries;
vat_pos = (uint32_t *) udf_part_mapping->vat_translation;
if (vat) {
printf("\t\tHeader length %d\n", udf_rw16(vat->header_len));
printf("\t\tImplementation use length %d\n", udf_rw16(vat->impl_use_len));
udf_dump_id("\t\tLogical volume id ", 128, vat->logvol_id, &chsp);
printf("\t\tNumber of files %d\n", udf_rw32(vat->num_files));
printf("\t\tNumber of directories %d\n", udf_rw32(vat->num_directories));
version = udf_rw16(vat->min_udf_readver);
printf("\t\tMinimum readversion UDFv %x\n", version);
version = udf_rw16(vat->min_udf_writever);
printf("\t\tMinimum writeversion UDFv %x\n", version);
version = udf_rw16(vat->max_udf_writever);
printf("\t\tMaximum writeversion UDFv %x\n", version);
if (udf_rw16(vat->impl_use_len)) printf("\t\t<undumped implementation use area>");
previous_vat = udf_rw32(vat->prev_vat);
} else {
udf_dump_regid("\t\tIdentifier id (can be wrong) ", (struct regid *) (vat_pos+vat_entries), UDF_REGID_NAME);
previous_vat = udf_rw32(*(vat_pos + vat_entries + 32/4)); /* definition */
}
if (previous_vat == 0xffffffff) {
printf("\t\tNo previous VAT recorded\n");
} else {
printf("\t\tPrevious VAT recorded at offset %d\n", previous_vat);
}
printf("\t\tNumber of VAT entries %d\n", vat_entries);
printf("\t\tVAT dump :");
for (entry=0; entry < vat_entries; entry++) {
if ((entry % 4) == 0) printf("\n\t");
printf("[0x%08x -> 0x%08x] ", entry, *vat_pos++);
}
printf("\n");
}
void udf_dump_volumeset_info(struct udf_volumeset *udf_volumeset) {
struct udf_pri_vol *primary;
struct udf_log_vol *logical;
struct udf_partition *udf_partition;
struct udf_part_mapping *udf_part_mapping;
struct udf_discinfo *disc;
char *name;
int num_volumes, num_partitions;
int subvolume, part_num, track_num;
num_volumes = 0; /* shut up gcc */
if (udf_volumeset->obsolete) return;
primary = STAILQ_FIRST(&udf_volumeset->primaries);
if (primary) {
num_volumes = udf_rw16(primary->pri_vol->max_vol_seq);
if (udf_volumeset->obsolete) printf("OBSOLETE\n"); /* XXX */
printf("Volume set ");
udf_dump_id(NULL, 32, primary->pri_vol->volset_id, &primary->pri_vol->desc_charset);
printf(" (%d volume%s) ", num_volumes, num_volumes>1?"s":"");
num_partitions = udf_volumeset->max_partnum;
printf("with %d partition%s\n", num_partitions, (num_partitions!=1)?"s":"");
/* better loop trough the partition numbers to display them in a defined order */
SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) {
part_num = udf_rw16(udf_partition->partition->part_num);
if (udf_partition) {
/* there is information */
assert(udf_partition->udf_session);
assert(udf_partition->udf_session->disc);
assert(udf_partition->partition);
assert(part_num == udf_rw16(udf_partition->partition->part_num));
track_num = udf_partition->udf_session->session_num;
disc = udf_partition->udf_session->disc;
printf("\tPartition number %d at device `%s' session %d from sector %d(+%d) for %d sectors\n",
part_num,
disc->dev->dev_name,
track_num,
udf_rw32(udf_partition->partition->start_loc),
udf_partition->udf_session->session_offset,
udf_rw32(udf_partition->partition->part_len)
);
} else {
printf("\tUnknown partition %d [unknown]\n", part_num);
}
}
}
STAILQ_FOREACH(primary, &udf_volumeset->primaries, next_primary) {
subvolume = udf_rw16(primary->pri_vol->vds_num);
printf("\tPrimary volume ");
udf_dump_id(NULL, 32, primary->pri_vol->vol_id, &primary->pri_vol->desc_charset);
printf(" (part %d/%d) ", subvolume, num_volumes);
printf("created by implementator `%s' ", primary->pri_vol->imp_id.id);
if (*primary->pri_vol->app_id.id)
printf("by/for application `%s' ",primary->pri_vol->app_id.id);
printf("\n");
SLIST_FOREACH(logical, &primary->log_vols, next_logvol) {
name = logical->log_vol->logvol_id;
udf_dump_id("\t\tcontains logical volume ", 128, name, &logical->log_vol->desc_charset);
if (logical->broken) {
printf("\t\t\tBROKEN\n");
continue;
}
SLIST_FOREACH(udf_part_mapping, &logical->part_mappings, next_mapping) {
printf("\t\t\tmapping %d on %d as ", udf_part_mapping->udf_virt_part_num,
udf_part_mapping->udf_phys_part_num);
switch (udf_part_mapping->udf_part_mapping_type) {
case UDF_PART_MAPPING_ERROR :
printf("bad partition");
break;
case UDF_PART_MAPPING_PHYSICAL :
printf("direct");
break;
case UDF_PART_MAPPING_VIRTUAL :
printf("virtual partition");
break;
case UDF_PART_MAPPING_SPARABLE :
printf("sparable");
break;
case UDF_PART_MAPPING_META :
printf("metadata only");
}
printf(" recording");
if (udf_part_mapping->data_writable) printf(" data");
if (udf_part_mapping->metadata_writable) printf(" metadata");
if (!udf_part_mapping->data_writable && !udf_part_mapping->metadata_writable) printf(" nothing");
printf("\n");
}
}
printf("\n");
}
}
void udf_dump_alive_sets(void) {
struct udf_volumeset *udf_volumeset;
printf("UDF volume sets marked alive :\n");
SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) {
udf_dump_volumeset_info(udf_volumeset);
}
printf("\n");
}
/*
* extern defined read_logvol_descriptor breaks splitting rules but how
* otherwise to provide a detailed description of the file entry node
*/
#define DUMP_DIRBUFFER_SIZE (16*1024)
void udf_dump_file_entry_node(struct udf_node *node, char *prefix, int recurse) {
struct uio dir_uio;
struct iovec dir_iovec;
uint8_t *buffer;
uint32_t pos;
char fullpath[1024]; /* XXX arbitrary length XXX */
struct dirent *dirent;
struct udf_node *entry_node;
int new_recurse, isdir, eof;
int error;
if (!node) return;
/* XXX could pass on dirent XXX */
isdir = (node->udf_filetype == UDF_ICB_FILETYPE_DIRECTORY);
isdir |= (node->udf_filetype == UDF_ICB_FILETYPE_STREAMDIR);
if (isdir && recurse) {
buffer = malloc(DUMP_DIRBUFFER_SIZE);
if (!buffer) return;
/* recurse into this directory */
dir_uio.uio_offset = 0; /* begin at start */
do {
dir_iovec.iov_base = buffer;
dir_iovec.iov_len = DUMP_DIRBUFFER_SIZE;
dir_uio.uio_resid = DUMP_DIRBUFFER_SIZE;
dir_uio.uio_iovcnt = 1;
dir_uio.uio_iov = &dir_iovec;
dir_uio.uio_rw = UIO_WRITE;
error = udf_readdir(node, &dir_uio, &eof);
if (error) {
printf("While reading in dirbuffer for dumping file entry node : %s\n", strerror(error));
break;
}
pos = 0;
while (pos < DUMP_DIRBUFFER_SIZE - dir_uio.uio_resid) {
dirent = (struct dirent *) (buffer + pos);
sprintf(fullpath, "%s/%s", prefix, dirent->d_name);
error = udf_lookup(node, &entry_node, dirent->d_name);
new_recurse = (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."));
udf_dump_file_entry_node(entry_node, fullpath, new_recurse);
pos += sizeof(struct dirent);
}
} while (!eof);
free(buffer);
return;
}
/* leaf node */
/* error = udf_lookup(node, &entry_node, dirent->d_name); */
printf("%s\n", prefix);
}
#undef DUMP_DIRBUFFER_SIZE
void udf_dump_root_dir(struct udf_mountpoint *mountpoint) {
printf("\n\nRoot dir dump\n");
if (mountpoint->rootdir_node) udf_dump_file_entry_node(mountpoint->rootdir_node, ":Rootdir", 1);
printf("\n\nStreamdir dump\n");
if (mountpoint->streamdir_node) udf_dump_file_entry_node(mountpoint->streamdir_node, ":Streamdir", 1);
}
/* XXX These should move to form one cd verbose file with cd_discect XXX */
static char *print_disc_state(int state) {
switch (state) {
case 0: return "empty disc";
case 1: return "incomplete (appendable)";
case 2: return "full (not appendable)";
case 3: return "random writable";
}
return "unknown disc state";
}
static char *print_session_state(int state) {
switch (state) {
case 0 : return "empty";
case 1 : return "incomplete";
case 2 : return "reserved/damaged";
case 3 : return "complete/closed disc";
}
return "unknown session_state";
}
static char *print_mmc_profile(int profile) {
static char scrap[100];
switch (profile) {
case 0x00 : return "Unknown[0] profile";
case 0x01 : return "Non removeable disc";
case 0x02 : return "Removable disc";
case 0x03 : return "Magneto Optical with sector erase";
case 0x04 : return "Magneto Optical write once";
case 0x05 : return "Advance Storage Magneto Optical";
case 0x08 : return "CD-ROM";
case 0x09 : return "CD-R recordable";
case 0x0a : return "CD-RW rewritable";
case 0x10 : return "DVD-ROM";
case 0x11 : return "DVD-R sequential";
case 0x12 : return "DVD-RAM rewritable";
case 0x13 : return "DVD-RW restricted overwrite";
case 0x14 : return "DVD-RW sequential";
case 0x1a : return "DVD+RW rewritable";
case 0x1b : return "DVD+R recordable";
case 0x20 : return "DDCD readonly";
case 0x21 : return "DDCD-R recodable";
case 0x22 : return "DDCD-RW rewritable";
case 0x2b : return "DVD+R double layer";
case 0x40 : return "BD-ROM";
case 0x41 : return "BD-R Sequential Recording (SRM)";
case 0x42 : return "BD-R Random Recording (RRM)";
case 0x43 : return "BD-RE rewritable";
}
sprintf(scrap, "Reserved profile 0x%02x", profile);
return scrap;
}
void udf_dump_discinfo(struct udf_discinfo *disc) {
uint32_t session;
printf("Disc info for disc in device %s\n", disc->dev->dev_name);
printf("\tMMC profile : %s\n", print_mmc_profile(disc->mmc_profile));
printf("\tsequential : %s\n", disc->sequential ?"yes":" no");
printf("\trecordable : %s\n", disc->recordable ?"yes":" no");
printf("\terasable : %s\n", disc->erasable ?"yes":" no");
printf("\tblankable : %s\n", disc->blankable ?"yes":" no");
printf("\tformattable : %s\n", disc->formattable ?"yes":" no");
printf("\trewritable : %s\n", disc->rewritable ?"yes":" no");
printf("\tmount raineer : %s\n", disc->mrw ?"yes":" no");
printf("\tpacket writing : %s\n", disc->packet ?"yes":" no");
printf("\tstrict overwrite : %s\n", disc->strict_overwrite ?"yes":" no");
printf("\tblocking number : %d\n", disc->blockingnr);
printf("\tdisc state : %s\n", print_disc_state(disc->disc_state));
printf("\tlast session state : %s\n", print_session_state(disc->last_session_state));
printf("\tsectorsize : %d\n", disc->sector_size);
printf("\tNumber of sessions %d\n", disc->num_sessions);
for(session = 0; session < disc->num_sessions; session++) {
printf("\tSession %d\n", session);
printf("\t\tstart at %d\n", (uint32_t) disc->session_start[session]);
printf("\t\tends at %d\n", (uint32_t) disc->session_end[session]);
printf("\t\tlength for %d\n", (uint32_t) (disc->session_end[session] - disc->session_start[session]));
printf("\t\tnext writable at %d\n", disc->next_writable[session]);
printf("\t\tfree blocks %d\n", disc->free_blocks[session]);
printf("\t\tpacket size %d\n", disc->packet_size[session]);
printf("\n");
}
}
/* end of udf_verbose.c */
syntax highlighted by Code2HTML, v. 0.9.1