initial commit with v2.6.9
[linux-2.6.9-moxart.git] / fs / udf / misc.c
blobfd321f9ace83a1c7d06ce346f1adf6bded6331d3
1 /*
2 * misc.c
4 * PURPOSE
5 * Miscellaneous routines for the OSTA-UDF(tm) filesystem.
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
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.
18 * (C) 1998 Dave Boynton
19 * (C) 1998-2004 Ben Fennema
20 * (C) 1999-2000 Stelias Computing Inc
22 * HISTORY
24 * 04/19/99 blf partial support for reading/writing specific EA's
27 #include "udfdecl.h"
29 #include <linux/fs.h>
30 #include <linux/string.h>
31 #include <linux/udf_fs.h>
32 #include <linux/buffer_head.h>
34 #include "udf_i.h"
35 #include "udf_sb.h"
37 struct buffer_head *
38 udf_tgetblk(struct super_block *sb, int block)
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);
46 struct buffer_head *
47 udf_tread(struct super_block *sb, int block)
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);
55 struct genericFormat *
56 udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
57 uint8_t loc)
59 uint8_t *ea = NULL, *ad = NULL;
60 int offset;
61 uint16_t crclen;
62 int i;
64 ea = UDF_I_DATA(inode);
65 if (UDF_I_LENEATTR(inode))
66 ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
67 else
69 ad = ea;
70 size += sizeof(struct extendedAttrHeaderDesc);
73 offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
74 UDF_I_LENALLOC(inode);
76 /* TODO - Check for FreeEASpace */
78 if (loc & 0x01 && offset >= size)
80 struct extendedAttrHeaderDesc *eahd;
81 eahd = (struct extendedAttrHeaderDesc *)ea;
83 if (UDF_I_LENALLOC(inode))
85 memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
88 if (UDF_I_LENEATTR(inode))
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)
94 return NULL;
97 else
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);
112 offset = UDF_I_LENEATTR(inode);
113 if (type < 2048)
115 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
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);
123 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
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);
132 else if (type < 65536)
134 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
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);
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];
154 if (loc & 0x02)
157 return NULL;
160 struct genericFormat *
161 udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
163 struct genericFormat *gaf;
164 uint8_t *ea = NULL;
165 uint32_t offset;
167 ea = UDF_I_DATA(inode);
169 if (UDF_I_LENEATTR(inode))
171 struct extendedAttrHeaderDesc *eahd;
172 eahd = (struct extendedAttrHeaderDesc *)ea;
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)
178 return NULL;
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);
188 while (offset < UDF_I_LENEATTR(inode))
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);
197 return NULL;
201 * udf_read_tagged
203 * PURPOSE
204 * Read the first block of a tagged descriptor.
206 * HISTORY
207 * July 1, 1997 - Andrew E. Mileski
208 * Written, tested, and released.
210 struct buffer_head *
211 udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
213 tag *tag_p;
214 struct buffer_head *bh = NULL;
215 register uint8_t checksum;
216 register int i;
218 /* Read the block */
219 if (block == 0xFFFFFFFF)
220 return NULL;
222 bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
223 if (!bh)
225 udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
226 return NULL;
229 tag_p = (tag *)(bh->b_data);
231 *ident = le16_to_cpu(tag_p->tagIdent);
233 if ( location != le32_to_cpu(tag_p->tagLocation) )
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;
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;
251 /* Verify the tag version */
252 if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
253 le16_to_cpu(tag_p->descVersion) != 0x0003U)
255 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
256 le16_to_cpu(tag_p->descVersion), block);
257 goto error_out;
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))
265 return bh;
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));
270 error_out:
271 brelse(bh);
272 return NULL;
275 struct buffer_head *
276 udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
278 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
279 loc.logicalBlockNum + offset, ident);
282 void udf_release_data(struct buffer_head *bh)
284 if (bh)
285 brelse(bh);
288 void udf_update_tag(char *data, int length)
290 tag *tptr = (tag *)data;
291 int i;
293 length -= sizeof(tag);
295 tptr->tagChecksum = 0;
296 tptr->descCRCLength = cpu_to_le16(length);
297 tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
299 for (i=0; i<16; i++)
300 if (i != 4)
301 tptr->tagChecksum += (uint8_t)(data[i]);
304 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
305 uint32_t loc, int length)
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);