18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * misc.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * PURPOSE 58c2ecf20Sopenharmony_ci * Miscellaneous routines for the OSTA-UDF(tm) filesystem. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * COPYRIGHT 88c2ecf20Sopenharmony_ci * This file is distributed under the terms of the GNU General Public 98c2ecf20Sopenharmony_ci * License (GPL). Copies of the GPL can be obtained from: 108c2ecf20Sopenharmony_ci * ftp://prep.ai.mit.edu/pub/gnu/GPL 118c2ecf20Sopenharmony_ci * Each contributing author retains all rights to their own work. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * (C) 1998 Dave Boynton 148c2ecf20Sopenharmony_ci * (C) 1998-2004 Ben Fennema 158c2ecf20Sopenharmony_ci * (C) 1999-2000 Stelias Computing Inc 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * HISTORY 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * 04/19/99 blf partial support for reading/writing specific EA's 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "udfdecl.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/fs.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "udf_i.h" 298c2ecf20Sopenharmony_ci#include "udf_sb.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct buffer_head *udf_tgetblk(struct super_block *sb, udf_pblk_t block) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) 348c2ecf20Sopenharmony_ci return sb_getblk(sb, udf_fixed_to_variable(block)); 358c2ecf20Sopenharmony_ci else 368c2ecf20Sopenharmony_ci return sb_getblk(sb, block); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) 428c2ecf20Sopenharmony_ci return sb_bread(sb, udf_fixed_to_variable(block)); 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci return sb_bread(sb, block); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, 488c2ecf20Sopenharmony_ci uint32_t type, uint8_t loc) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci uint8_t *ea = NULL, *ad = NULL; 518c2ecf20Sopenharmony_ci int offset; 528c2ecf20Sopenharmony_ci uint16_t crclen; 538c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ea = iinfo->i_data; 568c2ecf20Sopenharmony_ci if (iinfo->i_lenEAttr) { 578c2ecf20Sopenharmony_ci ad = iinfo->i_data + iinfo->i_lenEAttr; 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci ad = ea; 608c2ecf20Sopenharmony_ci size += sizeof(struct extendedAttrHeaderDesc); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) - 648c2ecf20Sopenharmony_ci iinfo->i_lenAlloc; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* TODO - Check for FreeEASpace */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (loc & 0x01 && offset >= size) { 698c2ecf20Sopenharmony_ci struct extendedAttrHeaderDesc *eahd; 708c2ecf20Sopenharmony_ci eahd = (struct extendedAttrHeaderDesc *)ea; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (iinfo->i_lenAlloc) 738c2ecf20Sopenharmony_ci memmove(&ad[size], ad, iinfo->i_lenAlloc); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (iinfo->i_lenEAttr) { 768c2ecf20Sopenharmony_ci /* check checksum/crc */ 778c2ecf20Sopenharmony_ci if (eahd->descTag.tagIdent != 788c2ecf20Sopenharmony_ci cpu_to_le16(TAG_IDENT_EAHD) || 798c2ecf20Sopenharmony_ci le32_to_cpu(eahd->descTag.tagLocation) != 808c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum) 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(inode->i_sb); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci size -= sizeof(struct extendedAttrHeaderDesc); 868c2ecf20Sopenharmony_ci iinfo->i_lenEAttr += 878c2ecf20Sopenharmony_ci sizeof(struct extendedAttrHeaderDesc); 888c2ecf20Sopenharmony_ci eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD); 898c2ecf20Sopenharmony_ci if (sbi->s_udfrev >= 0x0200) 908c2ecf20Sopenharmony_ci eahd->descTag.descVersion = cpu_to_le16(3); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci eahd->descTag.descVersion = cpu_to_le16(2); 938c2ecf20Sopenharmony_ci eahd->descTag.tagSerialNum = 948c2ecf20Sopenharmony_ci cpu_to_le16(sbi->s_serial_number); 958c2ecf20Sopenharmony_ci eahd->descTag.tagLocation = cpu_to_le32( 968c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum); 978c2ecf20Sopenharmony_ci eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); 988c2ecf20Sopenharmony_ci eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci offset = iinfo->i_lenEAttr; 1028c2ecf20Sopenharmony_ci if (type < 2048) { 1038c2ecf20Sopenharmony_ci if (le32_to_cpu(eahd->appAttrLocation) < 1048c2ecf20Sopenharmony_ci iinfo->i_lenEAttr) { 1058c2ecf20Sopenharmony_ci uint32_t aal = 1068c2ecf20Sopenharmony_ci le32_to_cpu(eahd->appAttrLocation); 1078c2ecf20Sopenharmony_ci memmove(&ea[offset - aal + size], 1088c2ecf20Sopenharmony_ci &ea[aal], offset - aal); 1098c2ecf20Sopenharmony_ci offset -= aal; 1108c2ecf20Sopenharmony_ci eahd->appAttrLocation = 1118c2ecf20Sopenharmony_ci cpu_to_le32(aal + size); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci if (le32_to_cpu(eahd->impAttrLocation) < 1148c2ecf20Sopenharmony_ci iinfo->i_lenEAttr) { 1158c2ecf20Sopenharmony_ci uint32_t ial = 1168c2ecf20Sopenharmony_ci le32_to_cpu(eahd->impAttrLocation); 1178c2ecf20Sopenharmony_ci memmove(&ea[offset - ial + size], 1188c2ecf20Sopenharmony_ci &ea[ial], offset - ial); 1198c2ecf20Sopenharmony_ci offset -= ial; 1208c2ecf20Sopenharmony_ci eahd->impAttrLocation = 1218c2ecf20Sopenharmony_ci cpu_to_le32(ial + size); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci } else if (type < 65536) { 1248c2ecf20Sopenharmony_ci if (le32_to_cpu(eahd->appAttrLocation) < 1258c2ecf20Sopenharmony_ci iinfo->i_lenEAttr) { 1268c2ecf20Sopenharmony_ci uint32_t aal = 1278c2ecf20Sopenharmony_ci le32_to_cpu(eahd->appAttrLocation); 1288c2ecf20Sopenharmony_ci memmove(&ea[offset - aal + size], 1298c2ecf20Sopenharmony_ci &ea[aal], offset - aal); 1308c2ecf20Sopenharmony_ci offset -= aal; 1318c2ecf20Sopenharmony_ci eahd->appAttrLocation = 1328c2ecf20Sopenharmony_ci cpu_to_le32(aal + size); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci /* rewrite CRC + checksum of eahd */ 1368c2ecf20Sopenharmony_ci crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag); 1378c2ecf20Sopenharmony_ci eahd->descTag.descCRCLength = cpu_to_le16(crclen); 1388c2ecf20Sopenharmony_ci eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd + 1398c2ecf20Sopenharmony_ci sizeof(struct tag), crclen)); 1408c2ecf20Sopenharmony_ci eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); 1418c2ecf20Sopenharmony_ci iinfo->i_lenEAttr += size; 1428c2ecf20Sopenharmony_ci return (struct genericFormat *)&ea[offset]; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return NULL; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistruct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type, 1498c2ecf20Sopenharmony_ci uint8_t subtype) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct genericFormat *gaf; 1528c2ecf20Sopenharmony_ci uint8_t *ea = NULL; 1538c2ecf20Sopenharmony_ci uint32_t offset; 1548c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ea = iinfo->i_data; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (iinfo->i_lenEAttr) { 1598c2ecf20Sopenharmony_ci struct extendedAttrHeaderDesc *eahd; 1608c2ecf20Sopenharmony_ci eahd = (struct extendedAttrHeaderDesc *)ea; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* check checksum/crc */ 1638c2ecf20Sopenharmony_ci if (eahd->descTag.tagIdent != 1648c2ecf20Sopenharmony_ci cpu_to_le16(TAG_IDENT_EAHD) || 1658c2ecf20Sopenharmony_ci le32_to_cpu(eahd->descTag.tagLocation) != 1668c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum) 1678c2ecf20Sopenharmony_ci return NULL; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (type < 2048) 1708c2ecf20Sopenharmony_ci offset = sizeof(struct extendedAttrHeaderDesc); 1718c2ecf20Sopenharmony_ci else if (type < 65536) 1728c2ecf20Sopenharmony_ci offset = le32_to_cpu(eahd->impAttrLocation); 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci offset = le32_to_cpu(eahd->appAttrLocation); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci while (offset + sizeof(*gaf) < iinfo->i_lenEAttr) { 1778c2ecf20Sopenharmony_ci uint32_t attrLength; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci gaf = (struct genericFormat *)&ea[offset]; 1808c2ecf20Sopenharmony_ci attrLength = le32_to_cpu(gaf->attrLength); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Detect undersized elements and buffer overflows */ 1838c2ecf20Sopenharmony_ci if ((attrLength < sizeof(*gaf)) || 1848c2ecf20Sopenharmony_ci (attrLength > (iinfo->i_lenEAttr - offset))) 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (le32_to_cpu(gaf->attrType) == type && 1888c2ecf20Sopenharmony_ci gaf->attrSubtype == subtype) 1898c2ecf20Sopenharmony_ci return gaf; 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci offset += attrLength; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return NULL; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * udf_read_tagged 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * PURPOSE 2028c2ecf20Sopenharmony_ci * Read the first block of a tagged descriptor. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * HISTORY 2058c2ecf20Sopenharmony_ci * July 1, 1997 - Andrew E. Mileski 2068c2ecf20Sopenharmony_ci * Written, tested, and released. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistruct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, 2098c2ecf20Sopenharmony_ci uint32_t location, uint16_t *ident) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct tag *tag_p; 2128c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 2138c2ecf20Sopenharmony_ci u8 checksum; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Read the block */ 2168c2ecf20Sopenharmony_ci if (block == 0xFFFFFFFF) 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci bh = udf_tread(sb, block); 2208c2ecf20Sopenharmony_ci if (!bh) { 2218c2ecf20Sopenharmony_ci udf_err(sb, "read failed, block=%u, location=%u\n", 2228c2ecf20Sopenharmony_ci block, location); 2238c2ecf20Sopenharmony_ci return NULL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci tag_p = (struct tag *)(bh->b_data); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci *ident = le16_to_cpu(tag_p->tagIdent); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (location != le32_to_cpu(tag_p->tagLocation)) { 2318c2ecf20Sopenharmony_ci udf_debug("location mismatch block %u, tag %u != %u\n", 2328c2ecf20Sopenharmony_ci block, le32_to_cpu(tag_p->tagLocation), location); 2338c2ecf20Sopenharmony_ci goto error_out; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Verify the tag checksum */ 2378c2ecf20Sopenharmony_ci checksum = udf_tag_checksum(tag_p); 2388c2ecf20Sopenharmony_ci if (checksum != tag_p->tagChecksum) { 2398c2ecf20Sopenharmony_ci udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x\n", 2408c2ecf20Sopenharmony_ci block, checksum, tag_p->tagChecksum); 2418c2ecf20Sopenharmony_ci goto error_out; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Verify the tag version */ 2458c2ecf20Sopenharmony_ci if (tag_p->descVersion != cpu_to_le16(0x0002U) && 2468c2ecf20Sopenharmony_ci tag_p->descVersion != cpu_to_le16(0x0003U)) { 2478c2ecf20Sopenharmony_ci udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u\n", 2488c2ecf20Sopenharmony_ci le16_to_cpu(tag_p->descVersion), block); 2498c2ecf20Sopenharmony_ci goto error_out; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Verify the descriptor CRC */ 2538c2ecf20Sopenharmony_ci if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize || 2548c2ecf20Sopenharmony_ci le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, 2558c2ecf20Sopenharmony_ci bh->b_data + sizeof(struct tag), 2568c2ecf20Sopenharmony_ci le16_to_cpu(tag_p->descCRCLength))) 2578c2ecf20Sopenharmony_ci return bh; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci udf_debug("Crc failure block %u: crc = %u, crclen = %u\n", block, 2608c2ecf20Sopenharmony_ci le16_to_cpu(tag_p->descCRC), 2618c2ecf20Sopenharmony_ci le16_to_cpu(tag_p->descCRCLength)); 2628c2ecf20Sopenharmony_cierror_out: 2638c2ecf20Sopenharmony_ci brelse(bh); 2648c2ecf20Sopenharmony_ci return NULL; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistruct buffer_head *udf_read_ptagged(struct super_block *sb, 2688c2ecf20Sopenharmony_ci struct kernel_lb_addr *loc, 2698c2ecf20Sopenharmony_ci uint32_t offset, uint16_t *ident) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset), 2728c2ecf20Sopenharmony_ci loc->logicalBlockNum + offset, ident); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_civoid udf_update_tag(char *data, int length) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct tag *tptr = (struct tag *)data; 2788c2ecf20Sopenharmony_ci length -= sizeof(struct tag); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci tptr->descCRCLength = cpu_to_le16(length); 2818c2ecf20Sopenharmony_ci tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length)); 2828c2ecf20Sopenharmony_ci tptr->tagChecksum = udf_tag_checksum(tptr); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_civoid udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum, 2868c2ecf20Sopenharmony_ci uint32_t loc, int length) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct tag *tptr = (struct tag *)data; 2898c2ecf20Sopenharmony_ci tptr->tagIdent = cpu_to_le16(ident); 2908c2ecf20Sopenharmony_ci tptr->descVersion = cpu_to_le16(version); 2918c2ecf20Sopenharmony_ci tptr->tagSerialNum = cpu_to_le16(snum); 2928c2ecf20Sopenharmony_ci tptr->tagLocation = cpu_to_le32(loc); 2938c2ecf20Sopenharmony_ci udf_update_tag(data, length); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ciu8 udf_tag_checksum(const struct tag *t) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci u8 *data = (u8 *)t; 2998c2ecf20Sopenharmony_ci u8 checksum = 0; 3008c2ecf20Sopenharmony_ci int i; 3018c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(struct tag); ++i) 3028c2ecf20Sopenharmony_ci if (i != 4) /* position of checksum */ 3038c2ecf20Sopenharmony_ci checksum += data[i]; 3048c2ecf20Sopenharmony_ci return checksum; 3058c2ecf20Sopenharmony_ci} 306