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