udf: Handle VAT packed inside inode properly
Jan Kara [Tue, 8 Apr 2008 00:08:53 +0000 (02:08 +0200)]
We didn't handle VAT packed inside the inode - we tried to call udf_block_map()
on such file which lead to strange results at best. Add proper handling of
packed VAT as we do it with other packed files.

Signed-off-by: Jan Kara <jack@suse.cz>

fs/udf/partition.c
fs/udf/super.c

index 307c9c3..b2e6e1e 100644 (file)
@@ -54,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map;
        struct udf_virtual_data *vdata;
-       struct udf_inode_info *iinfo;
+       struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
 
        map = &sbi->s_partmaps[partition];
        vdata = &map->s_type_specific.s_virtual;
-       index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
 
        if (block > vdata->s_num_entries) {
                udf_debug("Trying to access block beyond end of VAT "
@@ -66,6 +65,11 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
                return 0xFFFFFFFF;
        }
 
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               loc = le32_to_cpu(((__le32 *)iinfo->i_ext.i_data)[block]);
+               goto translate;
+       }
+       index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
        if (block >= index) {
                block -= index;
                newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
@@ -88,7 +92,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
 
        brelse(bh);
 
-       iinfo = UDF_I(sbi->s_vat_inode);
+translate:
        if (iinfo->i_location.partitionReferenceNum == partition) {
                udf_debug("recursive call to udf_get_pblock!\n");
                return 0xFFFFFFFF;
index 14f965e..abdb9b3 100644 (file)
@@ -1107,7 +1107,10 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map = &sbi->s_partmaps[p_index];
        kernel_lb_addr ino;
-       struct buffer_head *bh;
+       struct buffer_head *bh = NULL;
+       struct udf_inode_info *vati;
+       uint32_t pos;
+       struct virtualAllocationTable20 *vat20;
 
        /* VAT file entry is in the last recorded block */
        ino.partitionReferenceNum = type1_index;
@@ -1122,15 +1125,18 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
                map->s_type_specific.s_virtual.s_num_entries =
                        (sbi->s_vat_inode->i_size - 36) >> 2;
        } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
-               uint32_t pos;
-               struct virtualAllocationTable20 *vat20;
+               vati = UDF_I(sbi->s_vat_inode);
+               if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+                       pos = udf_block_map(sbi->s_vat_inode, 0);
+                       bh = sb_bread(sb, pos);
+                       if (!bh)
+                               return 1;
+                       vat20 = (struct virtualAllocationTable20 *)bh->b_data;
+               } else {
+                       vat20 = (struct virtualAllocationTable20 *)
+                                                       vati->i_ext.i_data;
+               }
 
-               pos = udf_block_map(sbi->s_vat_inode, 0);
-               bh = sb_bread(sb, pos);
-               if (!bh)
-                       return 1;
-               vat20 = (struct virtualAllocationTable20 *)bh->b_data +
-                               udf_ext0_offset(sbi->s_vat_inode);
                map->s_type_specific.s_virtual.s_start_offset =
                        le16_to_cpu(vat20->lengthHeader) +
                        udf_ext0_offset(sbi->s_vat_inode);