unsigned int udf_get_last_session(struct super_block *sb) { struct cdrom_multisession ms_info; unsigned int vol_desc_start; struct block_device *bdev = sb->s_bdev; int i; vol_desc_start=0; ms_info.addr_format=CDROM_LBA; i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); #define WE_OBEY_THE_WRITTEN_STANDARDS 1 if (i == 0) { udf_debug("XA disk: %s, vol_desc_start=%d\n", (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba); #if WE_OBEY_THE_WRITTEN_STANDARDS if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ #endif vol_desc_start = ms_info.addr.lba; } else { udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i); } return vol_desc_start; }
static void udf_bitmap_free_blocks(struct super_block *sb, struct inode *inode, struct udf_bitmap *bitmap, struct kernel_lb_addr *bloc, uint32_t offset, uint32_t count) { struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = NULL; struct udf_part_map *partmap; unsigned long block; unsigned long block_group; unsigned long bit; unsigned long i; int bitmap_nr; unsigned long overflow; mutex_lock(&sbi->s_alloc_mutex); partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; if (bloc->logicalBlockNum < 0 || (bloc->logicalBlockNum + count) > partmap->s_partition_len) { udf_debug("%d < %d || %d + %d > %d\n", bloc->logicalBlockNum, 0, bloc->logicalBlockNum, count, partmap->s_partition_len); goto error_return; } block = bloc->logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3); do { overflow = 0; block_group = block >> (sb->s_blocksize_bits + 3); bit = block % (sb->s_blocksize << 3); /* * Check to see if we are freeing blocks across a group boundary. */ if (bit + count > (sb->s_blocksize << 3)) { overflow = bit + count - (sb->s_blocksize << 3); count -= overflow; } bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto error_return; bh = bitmap->s_block_bitmap[bitmap_nr]; for (i = 0; i < count; i++) { if (udf_set_bit(bit + i, bh->b_data)) { udf_debug("bit %ld already set\n", bit + i); udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]); } else { if (inode) dquot_free_block(inode, 1); udf_add_free_space(sb, sbi->s_partition, 1); } }
/* * udf_read_tagged * * PURPOSE * Read the first block of a tagged descriptor. * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident) { struct tag *tag_p; struct buffer_head *bh = NULL; u8 checksum; if (block == 0xFFFFFFFF) return NULL; bh = udf_tread(sb, block); if (!bh) { udf_err(sb, "read failed, block=%u, location=%d\n", block, location); return NULL; } tag_p = (struct tag *)(bh->b_data); *ident = le16_to_cpu(tag_p->tagIdent); if (location != le32_to_cpu(tag_p->tagLocation)) { udf_debug("location mismatch block %u, tag %u != %u\n", block, le32_to_cpu(tag_p->tagLocation), location); goto error_out; } checksum = udf_tag_checksum(tag_p); if (checksum != tag_p->tagChecksum) { udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x\n", block, checksum, tag_p->tagChecksum); goto error_out; } if (tag_p->descVersion != cpu_to_le16(0x0002U) && tag_p->descVersion != cpu_to_le16(0x0003U)) { udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u\n", le16_to_cpu(tag_p->descVersion), block); goto error_out; } if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize || le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, bh->b_data + sizeof(struct tag), le16_to_cpu(tag_p->descCRCLength))) return bh; udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); return NULL; }
static void udf_bitmap_free_blocks(const struct inode * inode, struct udf_bitmap *bitmap, lb_addr bloc, Uint32 offset, Uint32 count) { struct buffer_head * bh = NULL; unsigned long block; unsigned long block_group; unsigned long bit; unsigned long i; int bitmap_nr; unsigned long overflow; struct super_block * sb; sb = inode->i_sb; if (!sb) { udf_debug("nonexistent device"); return; } lock_super(sb); if (bloc.logicalBlockNum < 0 || (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) { udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); goto error_return; } block = bloc.logicalBlockNum + offset + (sizeof(struct SpaceBitmapDesc) << 3); do_more: overflow = 0; block_group = block >> (sb->s_blocksize_bits + 3); bit = block % (sb->s_blocksize << 3); /* * Check to see if we are freeing blocks across a group boundary. */ if (bit + count > (sb->s_blocksize << 3)) { overflow = bit + count - (sb->s_blocksize << 3); count -= overflow; } bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto error_return; bh = bitmap->s_block_bitmap[bitmap_nr]; for (i=0; i < count; i++) { if (udf_set_bit(bit + i, bh->b_data)) { udf_debug("bit %ld already set\n", bit + i); udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]); } else {
/* * udf_read_tagged * * PURPOSE * Read the first block of a tagged descriptor. * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident) { tag *tag_p; struct buffer_head *bh = NULL; struct udf_sb_info *sbi = UDF_SB(sb); /* Read the block */ if (block == 0xFFFFFFFF) return NULL; bh = udf_tread(sb, block + sbi->s_session); if (!bh) { udf_debug("block=%d, location=%d: read failed\n", block + sbi->s_session, location); return NULL; } tag_p = (tag *)(bh->b_data); *ident = le16_to_cpu(tag_p->tagIdent); if (location != le32_to_cpu(tag_p->tagLocation)) { udf_debug("location mismatch block %u, tag %u != %u\n", block + sbi->s_session, le32_to_cpu(tag_p->tagLocation), location); goto error_out; } /* Verify the tag checksum */ if (udf_tag_checksum(tag_p) != tag_p->tagChecksum) { printk(KERN_ERR "udf: tag checksum failed block %d\n", block); goto error_out; } /* Verify the tag version */ if (tag_p->descVersion != cpu_to_le16(0x0002U) && tag_p->descVersion != cpu_to_le16(0x0003U)) { udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n", le16_to_cpu(tag_p->descVersion), block); goto error_out; } /* Verify the descriptor CRC */ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), le16_to_cpu(tag_p->descCRCLength), 0)) return bh; udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block + sbi->s_session, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); return NULL; }
long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_dentry->d_inode; long old_block, new_block; int result = -EINVAL; if (inode_permission(inode, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; goto out; } if (!arg) { udf_debug("invalid argument to udf_ioctl\n"); result = -EINVAL; goto out; } switch (cmd) { case UDF_GETVOLIDENT: if (copy_to_user((char __user *)arg, UDF_SB(inode->i_sb)->s_volume_ident, 32)) result = -EFAULT; else result = 0; goto out; case UDF_RELOCATE_BLOCKS: if (!capable(CAP_SYS_ADMIN)) { result = -EACCES; goto out; } if (get_user(old_block, (long __user *)arg)) { result = -EFAULT; goto out; } result = udf_relocate_blocks(inode->i_sb, old_block, &new_block); if (result == 0) result = put_user(new_block, (long __user *)arg); goto out; case UDF_GETEASIZE: result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg); goto out; case UDF_GETEABLOCK: result = copy_to_user((char __user *)arg, UDF_I(inode)->i_ext.i_data, UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0; goto out; } out: return result; }
uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) { struct buffer_head *bh = NULL; uint32_t newblock; uint32_t index; uint32_t loc; index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t); if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) { udf_debug("Trying to access block beyond end of VAT (%d max %d)\n", block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries); return 0xFFFFFFFF; } if (block >= index) { block -= index; newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); index = block % (sb->s_blocksize / sizeof(uint32_t)); } else { newblock = 0; index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block; } loc = udf_block_map(UDF_SB_VAT(sb), newblock, NULL); if (!(bh = sb_bread(sb, loc))) { udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n", sb, block, partition, loc, index); return 0xFFFFFFFF; } loc = le32_to_cpu(((__le32 *)bh->b_data)[index]); udf_release_data(bh); if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) { udf_debug("recursive call to udf_get_pblock!\n"); return 0xFFFFFFFF; } return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset); }
/* * udf_set_blocksize * * PURPOSE * Set the block size to be used in all transfers. * * DESCRIPTION * To allow room for a DMA transfer, it is best to guess big when unsure. * This routine picks 2048 bytes as the blocksize when guessing. This * should be adequate until devices with larger block sizes become common. * * Note that the Linux kernel can currently only deal with blocksizes of * 512, 1024, 2048, 4096, and 8192 bytes. * * PRE-CONDITIONS * sb Pointer to _locked_ superblock. * * POST-CONDITIONS * sb->s_blocksize Blocksize. * sb->s_blocksize_bits log2 of blocksize. * <return> 0 Blocksize is valid. * <return> 1 Blocksize is invalid. * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ static int udf_set_blocksize(struct super_block *sb, int bsize) { /* Use specified block size if specified */ if (bsize) sb->s_blocksize = bsize; if (get_hardsect_size(sb->s_dev) > sb->s_blocksize) sb->s_blocksize = get_hardsect_size(sb->s_dev); /* Block size must be an even multiple of 512 */ switch (sb->s_blocksize) { case 512: sb->s_blocksize_bits = 9; break; case 1024: sb->s_blocksize_bits = 10; break; case 2048: sb->s_blocksize_bits = 11; break; case 4096: sb->s_blocksize_bits = 12; break; case 8192: sb->s_blocksize_bits = 13; break; default: { udf_debug("Bad block size (%ld)\n", sb->s_blocksize); printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize); return 0; } } /* Set the block size */ set_blocksize(sb->s_dev, sb->s_blocksize); return sb->s_blocksize; }
/* * udf_ioctl * * PURPOSE * Issue an ioctl. * * DESCRIPTION * Optional - sys_ioctl() will return -ENOTTY if this routine is not * available, and the ioctl cannot be handled without filesystem help. * * sys_ioctl() handles these ioctls that apply only to regular files: * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD * These ioctls are also handled by sys_ioctl(): * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC * All other ioctls are passed to the filesystem. * * Refer to sys_ioctl() in fs/ioctl.c * sys_ioctl() -> . * * PRE-CONDITIONS * inode Pointer to inode that ioctl was issued on. * filp Pointer to file that ioctl was issued on. * cmd The ioctl command. * arg The ioctl argument [can be interpreted as a * user-space pointer if desired]. * * POST-CONDITIONS * <return> Success (>=0) or an error code (<=0) that * sys_ioctl() will return. * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { long old_block, new_block; int result = -EINVAL; if (file_permission(filp, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); return -EPERM; } if (!arg) { udf_debug("invalid argument to udf_ioctl\n"); return -EINVAL; } switch (cmd) { case UDF_GETVOLIDENT: return copy_to_user((char __user *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0; case UDF_RELOCATE_BLOCKS: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (get_user(old_block, (long __user *)arg)) return -EFAULT; if ((result = udf_relocate_blocks(inode->i_sb, old_block, &new_block)) == 0) result = put_user(new_block, (long __user *)arg); return result; case UDF_GETEASIZE: result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg); break; case UDF_GETEABLOCK: result = copy_to_user((char __user *)arg, UDF_I_DATA(inode), UDF_I_LENEATTR(inode)) ? -EFAULT : 0; break; } return result; }
inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) { if (partition >= UDF_SB_NUMPARTS(sb)) { udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n", block, partition, offset); return 0xFFFFFFFF; } if (UDF_SB_PARTFUNC(sb, partition)) return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset); else return UDF_SB_PARTROOT(sb, partition) + block + offset; }
static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { ssize_t retval; struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct udf_inode_info *iinfo = UDF_I(inode); int err; mutex_lock(&inode->i_mutex); retval = generic_write_checks(iocb, from); if (retval <= 0) goto out; down_write(&iinfo->i_data_sem); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { loff_t end = iocb->ki_pos + iov_iter_count(from); if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + end)) { err = udf_expand_file_adinicb(inode); if (err) { mutex_unlock(&inode->i_mutex); udf_debug("udf_expand_adinicb: err=%d\n", err); return err; } } else { iinfo->i_lenAlloc = max(end, inode->i_size); up_write(&iinfo->i_data_sem); } } else up_write(&iinfo->i_data_sem); retval = __generic_file_write_iter(iocb, from); out: mutex_unlock(&inode->i_mutex); if (retval > 0) { mark_inode_dirty(inode); err = generic_write_sync(file, iocb->ki_pos - retval, retval); if (err < 0) retval = err; } return retval; }
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { ssize_t retval; struct file *file = iocb->ki_filp; struct inode *inode = file->f_path.dentry->d_inode; int err, pos; size_t count = iocb->ki_left; struct udf_inode_info *iinfo = UDF_I(inode); down_write(&iinfo->i_data_sem); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (file->f_flags & O_APPEND) pos = inode->i_size; else pos = ppos; if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + pos + count)) { err = udf_expand_file_adinicb(inode); if (err) { udf_debug("udf_expand_adinicb: err=%d\n", err); return err; } } else { if (pos + count > inode->i_size) iinfo->i_lenAlloc = pos + count; else iinfo->i_lenAlloc = inode->i_size; up_write(&iinfo->i_data_sem); } } else up_write(&iinfo->i_data_sem); retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); if (retval > 0) mark_inode_dirty(inode); return retval; }
static int __load_block_bitmap(struct super_block * sb, struct udf_bitmap *bitmap, unsigned int block_group) { int retval = 0; int nr_groups = bitmap->s_nr_groups; if (block_group >= nr_groups) { udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups); } if (bitmap->s_block_bitmap[block_group]) return block_group; else { retval = read_block_bitmap(sb, bitmap, block_group, block_group); if (retval < 0) return retval; return block_group; } }
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { ssize_t retval; struct file *file = iocb->ki_filp; struct inode *inode = file->f_path.dentry->d_inode; int err, pos; size_t count = iocb->ki_left; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) { if (file->f_flags & O_APPEND) pos = inode->i_size; else pos = ppos; if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + pos + count)) { udf_expand_file_adinicb(inode, pos + count, &err); if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) { udf_debug("udf_expand_adinicb: err=%d\n", err); return err; } } else { if (pos + count > inode->i_size) UDF_I_LENALLOC(inode) = pos + count; else UDF_I_LENALLOC(inode) = inode->i_size; } } retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); if (retval > 0) mark_inode_dirty(inode); return retval; }
static int udf_vrs(struct super_block *sb, int silent) { struct VolStructDesc *vsd = NULL; int sector = 32768; int sectorsize; struct buffer_head *bh = NULL; int iso9660=0; int nsr02=0; int nsr03=0; /* Block size must be a multiple of 512 */ if (sb->s_blocksize & 511) return 0; if (sb->s_blocksize < sizeof(struct VolStructDesc)) sectorsize = sizeof(struct VolStructDesc); else sectorsize = sb->s_blocksize; sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits); udf_debug("Starting at sector %u (%ld byte sectors)\n", (sector >> sb->s_blocksize_bits), sb->s_blocksize); /* Process the sequence (if applicable) */ for (;!nsr02 && !nsr03; sector += sectorsize) { /* Read a block */ bh = udf_tread(sb, sector >> sb->s_blocksize_bits); if (!bh) break; /* Look for ISO descriptors */ vsd = (struct VolStructDesc *)(bh->b_data + (sector & (sb->s_blocksize - 1))); if (vsd->stdIdent[0] == 0) { udf_release_data(bh); break; } else if (!strncmp(vsd->stdIdent, STD_ID_CD001, STD_ID_LEN)) { iso9660 = sector; switch (vsd->structType) { case 0: udf_debug("ISO9660 Boot Record found\n"); break; case 1: udf_debug("ISO9660 Primary Volume Descriptor found\n"); break; case 2: udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); break; case 3: udf_debug("ISO9660 Volume Partition Descriptor found\n"); break; case 255: udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); break; default: udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); break; } } else if (!strncmp(vsd->stdIdent, STD_ID_BEA01, STD_ID_LEN)) { } else if (!strncmp(vsd->stdIdent, STD_ID_TEA01, STD_ID_LEN)) { udf_release_data(bh); break; } else if (!strncmp(vsd->stdIdent, STD_ID_NSR02, STD_ID_LEN)) { nsr02 = sector; } else if (!strncmp(vsd->stdIdent, STD_ID_NSR03, STD_ID_LEN)) { nsr03 = sector; } udf_release_data(bh); } if (nsr03) return nsr03; else if (nsr02) return nsr02; else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768) return -1; else return 0; }
/* * udf_read_tagged * * PURPOSE * Read the first block of a tagged descriptor. * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ struct buffer_head * udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident) { tag *tag_p; struct buffer_head *bh = NULL; register uint8_t checksum; register int i; /* Read the block */ if (block == 0xFFFFFFFF) return NULL; bh = udf_tread(sb, block + UDF_SB_SESSION(sb)); if (!bh) { udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location); return NULL; } tag_p = (tag *)(bh->b_data); *ident = le16_to_cpu(tag_p->tagIdent); if ( location != le32_to_cpu(tag_p->tagLocation) ) { udf_debug("location mismatch block %u, tag %u != %u\n", block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location); goto error_out; } /* Verify the tag checksum */ checksum = 0U; for (i = 0; i < 4; i++) checksum += (uint8_t)(bh->b_data[i]); for (i = 5; i < 16; i++) checksum += (uint8_t)(bh->b_data[i]); if (checksum != tag_p->tagChecksum) { printk(KERN_ERR "udf: tag checksum failed block %d\n", block); goto error_out; } /* Verify the tag version */ if (le16_to_cpu(tag_p->descVersion) != 0x0002U && le16_to_cpu(tag_p->descVersion) != 0x0003U) { udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n", le16_to_cpu(tag_p->descVersion), block); goto error_out; } /* Verify the descriptor CRC */ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), le16_to_cpu(tag_p->descCRCLength), 0)) { return bh; } udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); return NULL; }
void udf_fill_spartable(struct super_block *sb, struct udf_sparing_data *sdata, int partlen) { Uint16 ident; Uint32 spartable; int i; struct buffer_head *bh; struct SparingTable *st; for (i=0; i<4; i++) { if (!(spartable = sdata->s_spar_loc[i])) continue; bh = udf_read_tagged(sb, spartable, spartable, &ident); if (!bh) { sdata->s_spar_loc[i] = 0; continue; } if (ident == 0) { st = (struct SparingTable *)bh->b_data; if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) { SparingEntry *se; Uint16 rtl = le16_to_cpu(st->reallocationTableLen); int index; if (!sdata->s_spar_map) { int num = 1, mapsize; sdata->s_spar_indexsize = 8; while (rtl*sizeof(Uint32) >= (1 << sdata->s_spar_indexsize)) { num ++; sdata->s_spar_indexsize <<= 1; } mapsize = (rtl * sizeof(Uint32)) + ((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num); sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL); sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl]; memset(sdata->s_spar_map, 0xFF, mapsize); } index = sizeof(struct SparingTable); for (i=0; i<rtl; i++) { if (index > sb->s_blocksize) { udf_release_data(bh); bh = udf_tread(sb, ++spartable, sb->s_blocksize); if (!bh) { sdata->s_spar_loc[i] = 0; continue; } index = 0; } se = (SparingEntry *)&(bh->b_data[index]); index += sizeof(SparingEntry); if (sdata->s_spar_map[i] == 0xFFFFFFFF) sdata->s_spar_map[i] = le32_to_cpu(se->mappedLocation); else if (sdata->s_spar_map[i] != le32_to_cpu(se->mappedLocation)) { udf_debug("Found conflicting Sparing Data (%d vs %d for entry %d)\n", sdata->s_spar_map[i], le32_to_cpu(se->mappedLocation), i); } if (le32_to_cpu(se->origLocation) < 0xFFFFFFF0) { int packet = le32_to_cpu(se->origLocation) >> sdata->s_spar_pshift; if (sdata->s_spar_indexsize == 8) { if (sdata->s_spar_remap.s_spar_remap8[packet] == 0xFF) sdata->s_spar_remap.s_spar_remap8[packet] = i; else if (sdata->s_spar_remap.s_spar_remap8[packet] != i) { udf_debug("Found conflicting Sparing Data (%d vs %d)\n", sdata->s_spar_remap.s_spar_remap8[packet], i); } } else if (sdata->s_spar_indexsize == 16) { if (sdata->s_spar_remap.s_spar_remap16[packet] == 0xFFFF) sdata->s_spar_remap.s_spar_remap16[packet] = i; else if (sdata->s_spar_remap.s_spar_remap16[packet] != i) { udf_debug("Found conflicting Sparing Data (%d vs %d)\n", sdata->s_spar_remap.s_spar_remap16[packet], i); } } else if (sdata->s_spar_indexsize == 32) { if (sdata->s_spar_remap.s_spar_remap32[packet] == 0xFFFFFFFF) sdata->s_spar_remap.s_spar_remap32[packet] = i; else if (sdata->s_spar_remap.s_spar_remap32[packet] != i) { udf_debug("Found conflicting Sparing Data (%d vs %d)\n", sdata->s_spar_remap.s_spar_remap32[packet], i); } } } } }
/* * udf_find_anchor * * PURPOSE * Find an anchor volume descriptor. * * PRE-CONDITIONS * sb Pointer to _locked_ superblock. * lastblock Last block on media. * * POST-CONDITIONS * <return> 1 if not found, 0 if ok * * HISTORY * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ static void udf_find_anchor(struct super_block *sb) { int lastblock = UDF_SB_LASTBLOCK(sb); struct buffer_head *bh = NULL; Uint16 ident; Uint32 location; int i; if (lastblock) { int varlastblock = udf_variable_to_fixed(lastblock); int last[] = { lastblock, lastblock - 2, lastblock - 150, lastblock - 152, varlastblock, varlastblock - 2, varlastblock - 150, varlastblock - 152 }; lastblock = 0; /* Search for an anchor volume descriptor pointer */ /* according to spec, anchor is in either: * block 256 * lastblock-256 * lastblock * however, if the disc isn't closed, it could be 512 */ for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++) { if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) { ident = location = 0; } else { ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); udf_release_data(bh); } if (ident == TID_ANCHOR_VOL_DESC_PTR) { if (location == last[i] - UDF_SB_SESSION(sb)) { lastblock = UDF_SB_ANCHOR(sb)[0] = last[i]; UDF_SB_ANCHOR(sb)[1] = last[i] - 256; } else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) { UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]); UDF_SB_ANCHOR(sb)[1] = lastblock - 256; } else udf_debug("Anchor found at block %d, location mismatch %d.\n", last[i], location); } else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY) { lastblock = last[i]; UDF_SB_ANCHOR(sb)[3] = 512 + UDF_SB_SESSION(sb); } else { if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) { ident = location = 0; } else { ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); udf_release_data(bh); } if (ident == TID_ANCHOR_VOL_DESC_PTR && location == last[i] - 256 - UDF_SB_SESSION(sb)) { lastblock = last[i]; UDF_SB_ANCHOR(sb)[1] = last[i] - 256; } else { if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) { ident = location = 0; } else { ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); udf_release_data(bh); } if (ident == TID_ANCHOR_VOL_DESC_PTR && location == udf_variable_to_fixed(last[i]) - 256) { UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); lastblock = udf_variable_to_fixed(last[i]); UDF_SB_ANCHOR(sb)[1] = lastblock - 256; } } } } } if (!lastblock) { /* We havn't found the lastblock. check 312 */ if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) { ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); udf_release_data(bh); if (ident == TID_ANCHOR_VOL_DESC_PTR && location == 256) UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); } } for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++) { if (UDF_SB_ANCHOR(sb)[i]) { if (!(bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident))) { UDF_SB_ANCHOR(sb)[i] = 0; } else { udf_release_data(bh); if ((ident != TID_ANCHOR_VOL_DESC_PTR) && (i || (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY))) { UDF_SB_ANCHOR(sb)[i] = 0; } } } } UDF_SB_LASTBLOCK(sb) = lastblock; }