static uint8_t * udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size, kernel_lb_addr fe_loc, int *pos, int *offset, struct buffer_head **bh, int *error) { int loffset = *offset; int block; uint8_t *ad; int remainder; *error = 0; ad = (uint8_t *)(*bh)->b_data + *offset; *offset += ad_size; if (!ad) { brelse(*bh); *error = 1; return NULL; } if (*offset == dir->i_sb->s_blocksize) { brelse(*bh); block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); if (!block) return NULL; if (!(*bh = udf_tread(dir->i_sb, block))) return NULL; } else if (*offset > dir->i_sb->s_blocksize) { ad = tmpad; remainder = dir->i_sb->s_blocksize - loffset; memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder); brelse(*bh); block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); if (!block) return NULL; if (!((*bh) = udf_tread(dir->i_sb, block))) return NULL; memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder); *offset = ad_size - remainder; } return ad; }
/* * 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; }
/* * 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; }
static int read_block_bitmap(struct super_block *sb, struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr) { struct buffer_head *bh = NULL; int retval = 0; kernel_lb_addr loc; loc.logicalBlockNum = bitmap->s_extPosition; loc.partitionReferenceNum = UDF_SB(sb)->s_partition; bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block)); if (!bh) retval = -EIO; bitmap->s_block_bitmap[bitmap_nr] = bh; return retval; }
static int udf_symlink_filler(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; struct buffer_head *bh = NULL; char *symlink; int err = -EIO; char *p = kmap(page); lock_kernel(); if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) { bh = udf_tread(inode->i_sb, inode->i_ino); if (!bh) goto out; symlink = bh->b_data + udf_file_entry_alloc_offset(inode); } else { bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); if (!bh) goto out; symlink = bh->b_data; } udf_pc_to_char(symlink, inode->i_size, p); udf_release_data(bh); unlock_kernel(); SetPageUptodate(page); kunmap(page); UnlockPage(page); return 0; out: unlock_kernel(); SetPageError(page); kunmap(page); UnlockPage(page); return err; }
/* * 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); } } } } }
struct FileIdentDesc * udf_fileident_read(struct inode *dir, loff_t *nf_pos, struct udf_fileident_bh *fibh, struct FileIdentDesc *cfi, lb_addr *bloc, Uint32 *extoffset, lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh) { struct FileIdentDesc *fi; int block; fibh->soffset = fibh->eoffset; if (fibh->eoffset == dir->i_sb->s_blocksize) { int lextoffset = *extoffset; if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != EXTENT_RECORDED_ALLOCATED) { return NULL; } block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); (*offset) ++; if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) *offset = 0; else *extoffset = lextoffset; udf_release_data(fibh->sbh); if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) return NULL; fibh->soffset = fibh->eoffset = 0; } else if (fibh->sbh != fibh->ebh) { udf_release_data(fibh->sbh); fibh->sbh = fibh->ebh; } fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, &(fibh->eoffset)); if (!fi) return NULL; *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); if (fibh->eoffset <= dir->i_sb->s_blocksize) { memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc)); } else if (fibh->eoffset > dir->i_sb->s_blocksize) { int lextoffset = *extoffset; if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != EXTENT_RECORDED_ALLOCATED) { return NULL; } block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); (*offset) ++; if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) *offset = 0; else *extoffset = lextoffset; fibh->soffset -= dir->i_sb->s_blocksize; fibh->eoffset -= dir->i_sb->s_blocksize; if (!(fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) return NULL; if (sizeof(struct FileIdentDesc) > - fibh->soffset) { int fi_len; memcpy((Uint8 *)cfi, (Uint8 *)fi, - fibh->soffset); memcpy((Uint8 *)cfi - fibh->soffset, fibh->ebh->b_data, sizeof(struct FileIdentDesc) + fibh->soffset); fi_len = (sizeof(struct FileIdentDesc) + cfi->lengthFileIdent + le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2); fibh->eoffset = fibh->soffset + fi_len; }