diff --git a/include/cdio/ecma_167.h b/include/cdio/ecma_167.h index f73cc651..245d863a 100644 --- a/include/cdio/ecma_167.h +++ b/include/cdio/ecma_167.h @@ -618,12 +618,16 @@ typedef struct udf_icbtag_s udf_icbtag_t; #define UDF_ICB_TAG_FLAGS_SETGID 0x80 #define UDF_ICB_TAG_FLAGS_STICKY 0x100 -/** Strategy Type (ECMA 167r3 4/14.6.2) */ -#define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000 -#define ICBTAG_STRATEGY_TYPE_1 0x0001 -#define ICBTAG_STRATEGY_TYPE_2 0x0002 -#define ICBTAG_STRATEGY_TYPE_3 0x0003 -#define ICBTAG_STRATEGY_TYPE_4 0x0004 +/** Strategy Type (ECMA 167r3 4/14.6.2) which helpfully points + largely to 4/A.x */ +#define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000 +#define ICBTAG_STRATEGY_TYPE_1 0x0001 /**< 4/A.2 Direct entries Uint16 */ +#define ICBTAG_STRATEGY_TYPE_2 0x0002 /**< 4/A.3 List of ICB direct entries */ +#define ICBTAG_STRATEGY_TYPE_3 0x0003 /**< 4/A.4 */ +#define ICBTAG_STRATEGY_TYPE_4 0x0004 /**< 4/A.5 Hierarchy having one + single ICB with one direct entry. + This is what's most often used. + */ /** File Type (ECMA 167r3 4/14.6.6) @@ -649,11 +653,25 @@ typedef enum { /** Flags (ECMA 167r3 4/14.6.8) */ typedef enum { - ICBTAG_FLAG_AD_MASK = 0x0007, - ICBTAG_FLAG_AD_SHORT = 0x0000, - ICBTAG_FLAG_AD_LONG = 0x0001, + ICBTAG_FLAG_AD_MASK = 0x0007, /**< "&" this to get below address + flags */ + ICBTAG_FLAG_AD_SHORT = 0x0000, /**< The allocation descriptor + field is filled with + short_ad's. If the + offset is beyond the + current extent, look for + the next extent. */ + ICBTAG_FLAG_AD_LONG = 0x0001, /**< The allocation descriptor + field is filled with + long_ad's If the offset + is beyond the current + extent, look for the next + extent. */ ICBTAG_FLAG_AD_EXTENDED = 0x0002, - ICBTAG_FLAG_AD_IN_ICB = 0x0003, + ICBTAG_FLAG_AD_IN_ICB = 0x0003, /**< This type means that the + file *data* is stored in + the allocation descriptor + field of the file entry. */ ICBTAG_FLAG_SORTED = 0x0008, ICBTAG_FLAG_NONRELOCATABLE = 0x0010, ICBTAG_FLAG_ARCHIVE = 0x0020, @@ -978,15 +996,11 @@ PRAGMA_END_PACKED allow one refer to the enumeration value names in the typedefs above in a debugger and in debugger expressions. */ -typedef union -{ - tag_id_t debug_tagid; - file_characteristics_t debug_file_characteristics; - icbtag_file_type_enum_t debug_icbtag_file_type_enum; - icbtag_flag_enum_t debug_flag_enum; - ecma_167_enum1_t debug_ecma_167_enum1; - ecma_167_timezone_enum_t debug_ecma_167_timezone_enum; -} debug_ecma167_t; -extern debug_ecma167_t debug_ecma_167; +extern tag_id_t debug_tagid; +extern file_characteristics_t debug_file_characteristics; +extern icbtag_file_type_enum_t debug_icbtag_file_type_enum; +extern icbtag_flag_enum_t debug_flag_enum; +extern ecma_167_enum1_t debug_ecma_167_enum1; +extern ecma_167_timezone_enum_t debug_ecma_167_timezone_enum; #endif /* _ECMA_167_H */ diff --git a/lib/udf/udf.c b/lib/udf/udf.c index 5b5341e0..23953dd8 100644 --- a/lib/udf/udf.c +++ b/lib/udf/udf.c @@ -1,5 +1,5 @@ /* - $Id: udf.c,v 1.10 2006/04/16 02:34:10 rocky Exp $ + $Id: udf.c,v 1.11 2006/04/17 03:32:38 rocky Exp $ Copyright (C) 2005 Rocky Bernstein @@ -35,8 +35,12 @@ to the enumeration value names in the typedefs above in a debugger and debugger expressions */ -extern debug_ecma167_t debug_ecma_167; - +tag_id_t debug_tagid; +file_characteristics_t debug_file_characteristics; +icbtag_file_type_enum_t debug_icbtag_file_type_enum; +icbtag_flag_enum_t debug_flag_enum; +ecma_167_enum1_t debug_ecma_167_enum1; +ecma_167_timezone_enum_t debug_ecma_167_timezone_enum; udf_enum1_t debug_udf_enum1; diff --git a/lib/udf/udf_file.c b/lib/udf/udf_file.c index 47676aba..8276a5e0 100644 --- a/lib/udf/udf_file.c +++ b/lib/udf/udf_file.c @@ -1,5 +1,5 @@ /* - $Id: udf_file.c,v 1.11 2006/04/16 02:34:10 rocky Exp $ + $Id: udf_file.c,v 1.12 2006/04/17 03:32:38 rocky Exp $ Copyright (C) 2005, 2006 Rocky Bernstein @@ -29,7 +29,13 @@ #include /* Remove when adding cdio/logging.h */ +/* Useful defines */ + #define MIN(a, b) (aalloc_descs[offset] const char * udf_get_filename(const udf_dirent_t *p_udf_dirent) @@ -39,6 +45,8 @@ udf_get_filename(const udf_dirent_t *p_udf_dirent) return p_udf_dirent->psz_name; } +/* Get UDF File Entry. However we do NOT get the variable-length extended + attributes. */ bool udf_get_file_entry(const udf_dirent_t *p_udf_dirent, /*out*/ udf_file_entry_t *p_udf_fe) @@ -96,6 +104,112 @@ udf_is_dir(const udf_dirent_t *p_udf_dirent) return p_udf_dirent->b_dir; } +/* + * Translate a file offset into a logical block and then into a physical + * block. + */ +static lba_t +offset_to_lba(const udf_dirent_t *p_udf_dirent, off_t i_offset, + /*out*/ lba_t *pi_lba, /*out*/ uint32_t *pi_max_size) +{ + udf_t *p_udf = p_udf_dirent->p_udf; + const udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) + &p_udf_dirent->fe; + const udf_icbtag_t *p_icb_tag = &p_udf_fe->icb_tag; + const uint16_t strat_type= uint16_from_le(p_icb_tag->strat_type); + + switch (strat_type) { + case 4096: + printf("Cannot deal with strategy4096 yet!\n"); + return CDIO_INVALID_LBA; + break; + case ICBTAG_STRATEGY_TYPE_4: + { + uint32_t icblen = 0; + lba_t lsector; + int ad_offset, ad_num = 0; + uint16_t addr_ilk = uint16_from_le(p_icb_tag->flags&ICBTAG_FLAG_AD_MASK); + + switch (addr_ilk) { + case ICBTAG_FLAG_AD_SHORT: + { + udf_short_ad_t *p_icb; + /* + * The allocation descriptor field is filled with short_ad's. + * If the offset is beyond the current extent, look for the + * next extent. + */ + do { + i_offset -= icblen; + ad_offset = sizeof(udf_short_ad_t) * ad_num; + if (ad_offset > uint32_from_le(p_udf_fe->i_alloc_descs)) { + printf("File offset out of bounds\n"); + return CDIO_INVALID_LBA; + } + p_icb = (udf_short_ad_t *) + GETICB( uint32_from_le(p_udf_fe->i_extended_attr) + + ad_offset ); + icblen = p_icb->len; + ad_num++; + } while(i_offset >= icblen); + + lsector = (i_offset / UDF_BLOCKSIZE) + p_icb->pos; + + *pi_max_size = p_icb->len; + } + break; + case ICBTAG_FLAG_AD_LONG: + { + /* + * The allocation descriptor field is filled with long_ad's + * If the i_offset is beyond the current extent, look for the + * next extent. + */ + udf_long_ad_t *p_icb; + do { + i_offset -= icblen; + ad_offset = sizeof(udf_long_ad_t) * ad_num; + if (ad_offset > uint32_from_le(p_udf_fe->i_alloc_descs)) { + printf("File offset out of bounds\n"); + return CDIO_INVALID_LBA; + } + p_icb = (udf_long_ad_t *) + GETICB( uint32_from_le(p_udf_fe->i_extended_attr) + + ad_offset ); + icblen = p_icb->len; + ad_num++; + } while(i_offset >= icblen); + + lsector = (i_offset / UDF_BLOCKSIZE) + + uint32_from_le(((udf_long_ad_t *)(p_icb))->loc.lba); + + *pi_max_size = p_icb->len; + } + break; + case ICBTAG_FLAG_AD_IN_ICB: + /* + * This type means that the file *data* is stored in the + * allocation descriptor field of the file entry. + */ + *pi_max_size = 0; + printf("Don't know how to data in ICB handle yet\n"); + + case ICBTAG_FLAG_AD_EXTENDED: + printf("Don't know how to handle extended addresses yet\n"); + default: + printf("Unsupported allocation descriptor %d\n", addr_ilk); + return CDIO_INVALID_LBA; + } + + *pi_lba = lsector + p_udf->i_part_start; + return *pi_lba; + } + default: + printf("Unknown strategy type %d\n", strat_type); + return DRIVER_OP_ERROR; + } +} + /** Attempts to read up to count bytes from UDF directory entry p_udf_dirent into the buffer starting at buf. buf should be a @@ -113,39 +227,26 @@ udf_read_block(const udf_dirent_t *p_udf_dirent, void * buf, size_t count) { if (count == 0) return 0; else { - /* FIXME this code seems a bit convoluted. */ - udf_t *p_udf = p_udf_dirent->p_udf; - const udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) p_udf_dirent->data; driver_return_code_t ret; - const unsigned long int i_file_length = udf_get_file_length(p_udf_dirent); - - if (0 == p_udf->i_position) { - ret = udf_read_sectors(p_udf, p_udf_dirent->data, - p_udf_dirent->fe.unique_ID, 1); - if (ret != DRIVER_OP_SUCCESS) return DRIVER_OP_ERROR; - } - { - if (!udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) { - uint32_t i_lba_start, i_lba_end; - udf_get_lba( p_udf_fe, &i_lba_start, &i_lba_end); - - /* set i_lba_start to position of where we last left off. */ - i_lba_start += (p_udf->i_position / UDF_BLOCKSIZE); - - if ( (i_lba_end - i_lba_start+1) < count ) { - printf("Warning: don't know how to handle yet\n" ); - count = i_lba_end - i_lba_start+1; - } else { - const uint32_t i_lba = p_udf->i_part_start+i_lba_start; - ret = udf_read_sectors(p_udf, buf, i_lba, count); - if (DRIVER_OP_SUCCESS == ret) { - ssize_t i_read_len = MIN(i_file_length, count * UDF_BLOCKSIZE); - p_udf->i_position += i_read_len; - return i_read_len; - } - } + uint32_t i_max_size; + udf_t *p_udf = p_udf_dirent->p_udf; + lba_t i_lba = offset_to_lba(p_udf_dirent, p_udf->i_position, &i_lba, + &i_max_size); + if (i_lba != CDIO_INVALID_LBA) { + uint32_t i_max_blocks = CEILING(i_max_size, UDF_BLOCKSIZE); + if ( i_max_blocks < count ) { + printf("Warning: don't know how to handle yet\n" ); + count = i_max_blocks; } + ret = udf_read_sectors(p_udf, buf, i_lba, count); + if (DRIVER_OP_SUCCESS == ret) { + ssize_t i_read_len = MIN(i_max_size, count * UDF_BLOCKSIZE); + p_udf->i_position += i_read_len; + return i_read_len; + } + return ret; + } else { + return DRIVER_OP_ERROR; } - return ret; } } diff --git a/lib/udf/udf_fs.c b/lib/udf/udf_fs.c index b02d428a..271b739b 100644 --- a/lib/udf/udf_fs.c +++ b/lib/udf/udf_fs.c @@ -1,5 +1,5 @@ /* - $Id: udf_fs.c,v 1.19 2006/04/15 03:05:14 rocky Exp $ + $Id: udf_fs.c,v 1.20 2006/04/17 03:32:38 rocky Exp $ Copyright (C) 2005, 2006 Rocky Bernstein @@ -154,6 +154,7 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe, switch (p_udf_fe->icb_tag.flags & ICBTAG_FLAG_AD_MASK) { case ICBTAG_FLAG_AD_SHORT: { + /* The allocation descriptor field is filled with short_ad's. */ udf_short_ad_t *p_ad = (udf_short_ad_t *) (p_udf_fe->ext_attr + p_udf_fe->i_extended_attr); @@ -165,6 +166,7 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe, break; case ICBTAG_FLAG_AD_LONG: { + /* The allocation descriptor field is filled with long_ad's */ udf_long_ad_t *p_ad = (udf_long_ad_t *) (p_udf_fe->ext_attr + p_udf_fe->i_extended_attr); @@ -193,6 +195,11 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe, #define udf_PATH_DELIMITERS "/\\" +/* Searches p_udf_dirent a directory entry called psz_token. + Note p_udf_dirent is continuously updated. If the entry is + not found p_udf_dirent is useless and thus the caller should + not use it afterwards. +*/ static udf_dirent_t * udf_ff_traverse(udf_dirent_t *p_udf_dirent, char *psz_token) @@ -216,6 +223,7 @@ udf_ff_traverse(udf_dirent_t *p_udf_dirent, char *psz_token) } } } + free(p_udf_dirent->psz_name); return NULL; } @@ -233,8 +241,18 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name) strncpy(tokenline, psz_name, udf_MAX_PATHLEN); psz_token = strtok(tokenline, udf_PATH_DELIMITERS); - if (psz_token) - p_udf_file = udf_ff_traverse(p_udf_root, psz_token); + if (psz_token) { + /*** FIXME??? udf_dirent can be variable size due to the + extended attributes and descriptors. Given that, is this + correct? + */ + udf_dirent_t *p_udf_dirent = + udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf, + p_udf_root->psz_name, p_udf_root->b_dir, + p_udf_root->b_parent); + p_udf_file = udf_ff_traverse(p_udf_dirent, psz_token); + udf_dirent_free(p_udf_dirent); + } else if ( 0 == strncmp("/", psz_name, sizeof("/")) ) { return udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf, p_udf_root->psz_name, p_udf_root->b_dir, @@ -268,9 +286,13 @@ static udf_dirent_t * udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, const char *psz_name, bool b_dir, bool b_parent) { - udf_dirent_t *p_udf_dirent = - (udf_dirent_t *) calloc(1, sizeof(udf_dirent_t)); + const unsigned int i_alloc_size = p_udf_fe->i_alloc_descs + + p_udf_fe->i_extended_attr;; + + udf_dirent_t *p_udf_dirent = (udf_dirent_t *) + calloc(1, sizeof(udf_dirent_t) + i_alloc_size); if (!p_udf_dirent) return NULL; + p_udf_dirent->psz_name = strdup(psz_name); p_udf_dirent->b_dir = b_dir; p_udf_dirent->b_parent = b_parent; @@ -278,7 +300,8 @@ udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, p_udf_dirent->i_part_start = p_udf->i_part_start; p_udf_dirent->dir_left = uint64_from_le(p_udf_fe->info_len); - memcpy(&(p_udf_dirent->fe), p_udf_fe, sizeof(udf_file_entry_t)); + memcpy(&(p_udf_dirent->fe), p_udf_fe, + sizeof(udf_file_entry_t) + i_alloc_size); udf_get_lba( p_udf_fe, &(p_udf_dirent->i_loc), &(p_udf_dirent->i_loc_end) ); return p_udf_dirent; @@ -639,7 +662,9 @@ udf_readdir(udf_dirent_t *p_udf_dirent) udf_read_sectors(p_udf, p_udf_fe, p_udf->i_part_start + p_udf_dirent->fid->icb.loc.lba, 1); - memcpy(&(p_udf_dirent->fe), p_udf_fe, sizeof(udf_file_entry_t)); + memcpy(&(p_udf_dirent->fe), p_udf_fe, + sizeof(udf_file_entry_t) + p_udf_fe->i_alloc_descs + + p_udf_fe->i_extended_attr ); if (strlen(p_udf_dirent->psz_name) < i_len) p_udf_dirent->psz_name = (char *) diff --git a/lib/udf/udf_fs.h b/lib/udf/udf_fs.h index 25e5e6f8..7ac05a2e 100644 --- a/lib/udf/udf_fs.h +++ b/lib/udf/udf_fs.h @@ -1,5 +1,5 @@ /* - $Id: udf_fs.h,v 1.1 2006/04/11 05:47:58 rocky Exp $ + $Id: udf_fs.h,v 1.2 2006/04/17 03:32:38 rocky Exp $ Copyright (C) 2006 Rocky Bernstein @@ -21,6 +21,7 @@ #ifndef __CDIO_UDF_FS_H__ #define __CDIO_UDF_FS_H__ +#include /** * Check the descriptor tag for both the correct id and correct checksum. * Return zero if all is good, -1 if not. diff --git a/lib/udf/udf_private.h b/lib/udf/udf_private.h index 088877b7..b89a48b3 100644 --- a/lib/udf/udf_private.h +++ b/lib/udf/udf_private.h @@ -1,5 +1,5 @@ /* - $Id: udf_private.h,v 1.10 2006/04/16 02:34:10 rocky Exp $ + $Id: udf_private.h,v 1.11 2006/04/17 03:32:38 rocky Exp $ Copyright (C) 2005, 2006 Rocky Bernstein @@ -58,9 +58,10 @@ struct udf_dirent_s uint32_t i_loc, i_loc_end; uint64_t dir_left; uint8_t *sector; - udf_file_entry_t fe; udf_fileid_desc_t *fid; - uint8_t data[UDF_BLOCKSIZE]; + + /* This field has to come last because it is variable in length. */ + udf_file_entry_t fe; }; bool udf_get_lba(const udf_file_entry_t *p_udf_fe,