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