/* * 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; }
/* * 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; }
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; }