1 /* 2 * misc.c 3 * 4 * PURPOSE 5 * Miscellaneous routines for the OSTA-UDF(tm) filesystem. 6 * 7 * COPYRIGHT 8 * This file is distributed under the terms of the GNU General Public 9 * License (GPL). Copies of the GPL can be obtained from: 10 * ftp://prep.ai.mit.edu/pub/gnu/GPL 11 * Each contributing author retains all rights to their own work. 12 * 13 * (C) 1998 Dave Boynton 14 * (C) 1998-2004 Ben Fennema 15 * (C) 1999-2000 Stelias Computing Inc 16 * 17 * HISTORY 18 * 19 * 04/19/99 blf partial support for reading/writing specific EA's 20 */ 21 22 #include "udfdecl.h" 23 24 #include <linux/fs.h> 25 #include <linux/string.h> 26 #include <linux/udf_fs.h> 27 #include <linux/buffer_head.h> 28 29 #include "udf_i.h" 30 #include "udf_sb.h" 31 32 struct buffer_head * 33 udf_tgetblk(struct super_block *sb, int block) 34 { 35 if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) 36 return sb_getblk(sb, udf_fixed_to_variable(block)); 37 else 38 return sb_getblk(sb, block); 39 } 40 41 struct buffer_head * 42 udf_tread(struct super_block *sb, int block) 43 { 44 if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) 45 return sb_bread(sb, udf_fixed_to_variable(block)); 46 else 47 return sb_bread(sb, block); 48 } 49 50 struct genericFormat * 51 udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type, 52 uint8_t loc) 53 { 54 uint8_t *ea = NULL, *ad = NULL; 55 int offset; 56 uint16_t crclen; 57 int i; 58 59 ea = UDF_I_DATA(inode); 60 if (UDF_I_LENEATTR(inode)) 61 ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); 62 else 63 { 64 ad = ea; 65 size += sizeof(struct extendedAttrHeaderDesc); 66 } 67 68 offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) - 69 UDF_I_LENALLOC(inode); 70 71 /* TODO - Check for FreeEASpace */ 72 73 if (loc & 0x01 && offset >= size) 74 { 75 struct extendedAttrHeaderDesc *eahd; 76 eahd = (struct extendedAttrHeaderDesc *)ea; 77 78 if (UDF_I_LENALLOC(inode)) 79 { 80 memmove(&ad[size], ad, UDF_I_LENALLOC(inode)); 81 } 82 83 if (UDF_I_LENEATTR(inode)) 84 { 85 /* check checksum/crc */ 86 if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || 87 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) 88 { 89 return NULL; 90 } 91 } 92 else 93 { 94 size -= sizeof(struct extendedAttrHeaderDesc); 95 UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc); 96 eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD); 97 if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) 98 eahd->descTag.descVersion = cpu_to_le16(3); 99 else 100 eahd->descTag.descVersion = cpu_to_le16(2); 101 eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); 102 eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); 103 eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); 104 eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); 105 } 106 107 offset = UDF_I_LENEATTR(inode); 108 if (type < 2048) 109 { 110 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) 111 { 112 uint32_t aal = le32_to_cpu(eahd->appAttrLocation); 113 memmove(&ea[offset - aal + size], 114 &ea[aal], offset - aal); 115 offset -= aal; 116 eahd->appAttrLocation = cpu_to_le32(aal + size); 117 } 118 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) 119 { 120 uint32_t ial = le32_to_cpu(eahd->impAttrLocation); 121 memmove(&ea[offset - ial + size], 122 &ea[ial], offset - ial); 123 offset -= ial; 124 eahd->impAttrLocation = cpu_to_le32(ial + size); 125 } 126 } 127 else if (type < 65536) 128 { 129 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) 130 { 131 uint32_t aal = le32_to_cpu(eahd->appAttrLocation); 132 memmove(&ea[offset - aal + size], 133 &ea[aal], offset - aal); 134 offset -= aal; 135 eahd->appAttrLocation = cpu_to_le32(aal + size); 136 } 137 } 138 /* rewrite CRC + checksum of eahd */ 139 crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); 140 eahd->descTag.descCRCLength = cpu_to_le16(crclen); 141 eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0)); 142 eahd->descTag.tagChecksum = 0; 143 for (i=0; i<16; i++) 144 if (i != 4) 145 eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i]; 146 UDF_I_LENEATTR(inode) += size; 147 return (struct genericFormat *)&ea[offset]; 148 } 149 if (loc & 0x02) 150 { 151 } 152 return NULL; 153 } 154 155 struct genericFormat * 156 udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype) 157 { 158 struct genericFormat *gaf; 159 uint8_t *ea = NULL; 160 uint32_t offset; 161 162 ea = UDF_I_DATA(inode); 163 164 if (UDF_I_LENEATTR(inode)) 165 { 166 struct extendedAttrHeaderDesc *eahd; 167 eahd = (struct extendedAttrHeaderDesc *)ea; 168 169 /* check checksum/crc */ 170 if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || 171 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) 172 { 173 return NULL; 174 } 175 176 if (type < 2048) 177 offset = sizeof(struct extendedAttrHeaderDesc); 178 else if (type < 65536) 179 offset = le32_to_cpu(eahd->impAttrLocation); 180 else 181 offset = le32_to_cpu(eahd->appAttrLocation); 182 183 while (offset < UDF_I_LENEATTR(inode)) 184 { 185 gaf = (struct genericFormat *)&ea[offset]; 186 if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype) 187 return gaf; 188 else 189 offset += le32_to_cpu(gaf->attrLength); 190 } 191 } 192 return NULL; 193 } 194 195 /* 196 * udf_read_tagged 197 * 198 * PURPOSE 199 * Read the first block of a tagged descriptor. 200 * 201 * HISTORY 202 * July 1, 1997 - Andrew E. Mileski 203 * Written, tested, and released. 204 */ 205 struct buffer_head * 206 udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident) 207 { 208 tag *tag_p; 209 struct buffer_head *bh = NULL; 210 register uint8_t checksum; 211 register int i; 212 213 /* Read the block */ 214 if (block == 0xFFFFFFFF) 215 return NULL; 216 217 bh = udf_tread(sb, block + UDF_SB_SESSION(sb)); 218 if (!bh) 219 { 220 udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location); 221 return NULL; 222 } 223 224 tag_p = (tag *)(bh->b_data); 225 226 *ident = le16_to_cpu(tag_p->tagIdent); 227 228 if ( location != le32_to_cpu(tag_p->tagLocation) ) 229 { 230 udf_debug("location mismatch block %u, tag %u != %u\n", 231 block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location); 232 goto error_out; 233 } 234 235 /* Verify the tag checksum */ 236 checksum = 0U; 237 for (i = 0; i < 4; i++) 238 checksum += (uint8_t)(bh->b_data[i]); 239 for (i = 5; i < 16; i++) 240 checksum += (uint8_t)(bh->b_data[i]); 241 if (checksum != tag_p->tagChecksum) { 242 printk(KERN_ERR "udf: tag checksum failed block %d\n", block); 243 goto error_out; 244 } 245 246 /* Verify the tag version */ 247 if (le16_to_cpu(tag_p->descVersion) != 0x0002U && 248 le16_to_cpu(tag_p->descVersion) != 0x0003U) 249 { 250 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n", 251 le16_to_cpu(tag_p->descVersion), block); 252 goto error_out; 253 } 254 255 /* Verify the descriptor CRC */ 256 if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || 257 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), 258 le16_to_cpu(tag_p->descCRCLength), 0)) 259 { 260 return bh; 261 } 262 udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", 263 block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); 264 265 error_out: 266 brelse(bh); 267 return NULL; 268 } 269 270 struct buffer_head * 271 udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident) 272 { 273 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset), 274 loc.logicalBlockNum + offset, ident); 275 } 276 277 void udf_update_tag(char *data, int length) 278 { 279 tag *tptr = (tag *)data; 280 int i; 281 282 length -= sizeof(tag); 283 284 tptr->tagChecksum = 0; 285 tptr->descCRCLength = cpu_to_le16(length); 286 tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); 287 288 for (i=0; i<16; i++) 289 if (i != 4) 290 tptr->tagChecksum += (uint8_t)(data[i]); 291 } 292 293 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum, 294 uint32_t loc, int length) 295 { 296 tag *tptr = (tag *)data; 297 tptr->tagIdent = cpu_to_le16(ident); 298 tptr->descVersion = cpu_to_le16(version); 299 tptr->tagSerialNum = cpu_to_le16(snum); 300 tptr->tagLocation = cpu_to_le32(loc); 301 udf_update_tag(data, length); 302 } 303