aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/misc.c')
-rw-r--r--fs/udf/misc.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
new file mode 100644
index 000000000000..fd321f9ace83
--- /dev/null
+++ b/fs/udf/misc.c
@@ -0,0 +1,313 @@
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
37struct buffer_head *
38udf_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
46struct buffer_head *
47udf_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
55struct genericFormat *
56udf_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
160struct genericFormat *
161udf_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 */
210struct buffer_head *
211udf_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
270error_out:
271 brelse(bh);
272 return NULL;
273}
274
275struct buffer_head *
276udf_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
282void udf_release_data(struct buffer_head *bh)
283{
284 if (bh)
285 brelse(bh);
286}
287
288void 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
304void 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}