File: /usr/src/linux/fs/udf/misc.c
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-2000 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 #if defined(__linux__) && defined(__KERNEL__)
30
31 #include "udf_sb.h"
32 #include "udf_i.h"
33
34 #include <linux/fs.h>
35 #include <linux/string.h>
36 #include <linux/udf_fs.h>
37
38 #else
39
40 #include <sys/types.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
44
45 int udf_blocksize=0;
46 int udf_errno=0;
47
48 void
49 udf_setblocksize(int size)
50 {
51 udf_blocksize=size;
52 }
53 #endif
54
55 Uint32
56 udf64_low32(Uint64 indat)
57 {
58 return indat & 0x00000000FFFFFFFFULL;
59 }
60
61 Uint32
62 udf64_high32(Uint64 indat)
63 {
64 return indat >> 32;
65 }
66
67 #if defined(__linux__) && defined(__KERNEL__)
68
69 extern struct buffer_head *
70 udf_tgetblk(struct super_block *sb, int block, int size)
71 {
72 if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
73 return getblk(sb->s_dev, udf_fixed_to_variable(block), size);
74 else
75 return getblk(sb->s_dev, block, size);
76 }
77
78 extern struct buffer_head *
79 udf_tread(struct super_block *sb, int block, int size)
80 {
81 if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
82 return bread(sb->s_dev, udf_fixed_to_variable(block), size);
83 else
84 return bread(sb->s_dev, block, size);
85 }
86
87 extern struct GenericAttrFormat *
88 udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
89 Uint8 loc, struct buffer_head **bh)
90 {
91 Uint8 *ea = NULL, *ad = NULL;
92 long_ad eaicb;
93 int offset;
94
95 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
96
97 if (UDF_I_EXTENDED_FE(inode) == 0)
98 {
99 struct FileEntry *fe;
100
101 fe = (struct FileEntry *)(*bh)->b_data;
102 eaicb = lela_to_cpu(fe->extendedAttrICB);
103 offset = sizeof(struct FileEntry);
104 }
105 else
106 {
107 struct ExtendedFileEntry *efe;
108
109 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
110 eaicb = lela_to_cpu(efe->extendedAttrICB);
111 offset = sizeof(struct ExtendedFileEntry);
112 }
113
114 ea = &(*bh)->b_data[offset];
115 if (UDF_I_LENEATTR(inode))
116 offset += UDF_I_LENEATTR(inode);
117 else
118 size += sizeof(struct ExtendedAttrHeaderDesc);
119
120 ad = &(*bh)->b_data[offset];
121 if (UDF_I_LENALLOC(inode))
122 offset += UDF_I_LENALLOC(inode);
123
124 offset = inode->i_sb->s_blocksize - offset;
125
126 /* TODO - Check for FreeEASpace */
127
128 if (loc & 0x01 && offset >= size)
129 {
130 struct ExtendedAttrHeaderDesc *eahd;
131 eahd = (struct ExtendedAttrHeaderDesc *)ea;
132
133 if (UDF_I_LENALLOC(inode))
134 {
135 memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
136 }
137
138 if (UDF_I_LENEATTR(inode))
139 {
140 /* check checksum/crc */
141 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
142 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
143 {
144 udf_release_data(*bh);
145 return NULL;
146 }
147 }
148 else
149 {
150 size -= sizeof(struct ExtendedAttrHeaderDesc);
151 UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
152 eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
153 eahd->descTag.descVersion = cpu_to_le16(2);
154 eahd->descTag.tagSerialNum = cpu_to_le16(1);
155 eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
156 eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
157 eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
158 }
159
160 offset = UDF_I_LENEATTR(inode);
161 if (type < 2048)
162 {
163 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
164 {
165 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
166 memmove(&ea[offset - aal + size],
167 &ea[aal], offset - aal);
168 offset -= aal;
169 eahd->appAttrLocation = cpu_to_le32(aal + size);
170 }
171 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
172 {
173 Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
174 memmove(&ea[offset - ial + size],
175 &ea[ial], offset - ial);
176 offset -= ial;
177 eahd->impAttrLocation = cpu_to_le32(ial + size);
178 }
179 }
180 else if (type < 65536)
181 {
182 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
183 {
184 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
185 memmove(&ea[offset - aal + size],
186 &ea[aal], offset - aal);
187 offset -= aal;
188 eahd->appAttrLocation = cpu_to_le32(aal + size);
189 }
190 }
191 /* rewrite CRC + checksum of eahd */
192 UDF_I_LENEATTR(inode) += size;
193 return (struct GenericAttrFormat *)&ea[offset];
194 }
195 if (loc & 0x02)
196 {
197 }
198 udf_release_data(*bh);
199 return NULL;
200 }
201
202 extern struct GenericAttrFormat *
203 udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
204 struct buffer_head **bh)
205 {
206 struct GenericAttrFormat *gaf;
207 Uint8 *ea = NULL;
208 long_ad eaicb;
209 Uint32 offset;
210
211 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
212
213 if (UDF_I_EXTENDED_FE(inode) == 0)
214 {
215 struct FileEntry *fe;
216
217 fe = (struct FileEntry *)(*bh)->b_data;
218 eaicb = lela_to_cpu(fe->extendedAttrICB);
219 if (UDF_I_LENEATTR(inode))
220 ea = fe->extendedAttr;
221 }
222 else
223 {
224 struct ExtendedFileEntry *efe;
225
226 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
227 eaicb = lela_to_cpu(efe->extendedAttrICB);
228 if (UDF_I_LENEATTR(inode))
229 ea = efe->extendedAttr;
230 }
231
232 if (UDF_I_LENEATTR(inode))
233 {
234 struct ExtendedAttrHeaderDesc *eahd;
235 eahd = (struct ExtendedAttrHeaderDesc *)ea;
236
237 /* check checksum/crc */
238 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
239 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
240 {
241 udf_release_data(*bh);
242 return NULL;
243 }
244
245 if (type < 2048)
246 offset = sizeof(struct ExtendedAttrHeaderDesc);
247 else if (type < 65536)
248 offset = le32_to_cpu(eahd->impAttrLocation);
249 else
250 offset = le32_to_cpu(eahd->appAttrLocation);
251
252 while (offset < UDF_I_LENEATTR(inode))
253 {
254 gaf = (struct GenericAttrFormat *)&ea[offset];
255 if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
256 return gaf;
257 else
258 offset += le32_to_cpu(gaf->attrLength);
259 }
260 }
261
262 udf_release_data(*bh);
263 if (eaicb.extLength)
264 {
265 /* TODO */
266 }
267 return NULL;
268 }
269
270 extern struct buffer_head *
271 udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
272 {
273 struct buffer_head *bh = NULL;
274
275 /* Read the block */
276 bh = udf_tread(sb, block+offset, sb->s_blocksize);
277 if (!bh)
278 {
279 printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
280 sb, block, offset);
281 return NULL;
282 }
283 return bh;
284 }
285
286 /*
287 * udf_read_tagged
288 *
289 * PURPOSE
290 * Read the first block of a tagged descriptor.
291 *
292 * HISTORY
293 * July 1, 1997 - Andrew E. Mileski
294 * Written, tested, and released.
295 */
296 extern struct buffer_head *
297 udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
298 {
299 tag *tag_p;
300 struct buffer_head *bh = NULL;
301 register Uint8 checksum;
302 register int i;
303
304 /* Read the block */
305 if (block == 0xFFFFFFFF)
306 return NULL;
307
308 bh = udf_tread(sb, block, sb->s_blocksize);
309 if (!bh)
310 {
311 udf_debug("block=%d, location=%d: read failed\n", block, location);
312 return NULL;
313 }
314
315 tag_p = (tag *)(bh->b_data);
316
317 *ident = le16_to_cpu(tag_p->tagIdent);
318
319 if ( location != le32_to_cpu(tag_p->tagLocation) )
320 {
321 udf_debug("location mismatch block %u, tag %u != %u\n",
322 block, le32_to_cpu(tag_p->tagLocation), location);
323 goto error_out;
324 }
325
326 /* Verify the tag checksum */
327 checksum = 0U;
328 for (i = 0; i < 4; i++)
329 checksum += (Uint8)(bh->b_data[i]);
330 for (i = 5; i < 16; i++)
331 checksum += (Uint8)(bh->b_data[i]);
332 if (checksum != tag_p->tagChecksum) {
333 printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
334 goto error_out;
335 }
336
337 /* Verify the tag version */
338 if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
339 le16_to_cpu(tag_p->descVersion) != 0x0003U)
340 {
341 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
342 le16_to_cpu(tag_p->descVersion), block);
343 goto error_out;
344 }
345
346 /* Verify the descriptor CRC */
347 if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
348 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
349 le16_to_cpu(tag_p->descCRCLength), 0))
350 {
351 return bh;
352 }
353 udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
354 block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
355
356 error_out:
357 brelse(bh);
358 return NULL;
359 }
360
361 extern struct buffer_head *
362 udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
363 {
364 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
365 loc.logicalBlockNum + offset, ident);
366 }
367
368 void udf_release_data(struct buffer_head *bh)
369 {
370 if (bh)
371 brelse(bh);
372 }
373
374 #endif
375
376 void udf_update_tag(char *data, int length)
377 {
378 tag *tptr = (tag *)data;
379 int i;
380
381 length -= sizeof(tag);
382
383 tptr->tagChecksum = 0;
384 tptr->descCRCLength = le16_to_cpu(length);
385 tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
386
387 for (i=0; i<16; i++)
388 if (i != 4)
389 tptr->tagChecksum += (Uint8)(data[i]);
390 }
391
392 void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
393 Uint32 loc, int length)
394 {
395 tag *tptr = (tag *)data;
396 tptr->tagIdent = le16_to_cpu(ident);
397 tptr->descVersion = le16_to_cpu(version);
398 tptr->tagSerialNum = le16_to_cpu(snum);
399 tptr->tagLocation = le32_to_cpu(loc);
400 udf_update_tag(data, length);
401 }
402
403 #ifndef __KERNEL__
404 /*
405 * udf_read_tagged_data
406 *
407 * PURPOSE
408 * Read the first block of a tagged descriptor.
409 * Usable from user-land.
410 *
411 * HISTORY
412 * 10/4/98 dgb: written
413 */
414 int
415 udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
416 {
417 tag *tag_p;
418 register Uint8 checksum;
419 register int i;
420 unsigned long offs;
421
422 if (!buffer)
423 {
424 udf_errno = 1;
425 return -1;
426 }
427
428 if ( !udf_blocksize )
429 {
430 udf_errno = 2;
431 return -1;
432 }
433
434 if ( size < udf_blocksize )
435 {
436 udf_errno = 3;
437 return -1;
438 }
439 udf_errno = 0;
440
441 offs = (long)block * udf_blocksize;
442 if ( lseek(fd, offs, SEEK_SET) != offs )
443 {
444 udf_errno = 4;
445 return -1;
446 }
447
448 i = read(fd, buffer, udf_blocksize);
449 if ( i < udf_blocksize )
450 {
451 udf_errno = 5;
452 return -1;
453 }
454
455 tag_p = (tag *)(buffer);
456
457 /* Verify the tag location */
458 if ((block-offset) != tag_p->tagLocation)
459 {
460 #ifdef __KERNEL__
461 printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
462 block, tag_p->tagLocation);
463 #else
464 udf_errno = 6;
465 #endif
466 goto error_out;
467 }
468
469 /* Verify the tag checksum */
470 checksum = 0U;
471 for (i = 0; i < 4; i++)
472 checksum += (Uint8)(buffer[i]);
473 for (i = 5; i < 16; i++)
474 checksum += (Uint8)(buffer[i]);
475 if (checksum != tag_p->tagChecksum)
476 {
477 #ifdef __KERNEL__
478 printk(KERN_ERR "udf: tag checksum failed\n");
479 #else
480 udf_errno = 7;
481 #endif
482 goto error_out;
483 }
484
485 /* Verify the tag version */
486 if (tag_p->descVersion != 0x0002U)
487 {
488 #ifdef __KERNEL__
489 printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
490 tag_p->descVersion);
491 #else
492 udf_errno = 8;
493 #endif
494 goto error_out;
495 }
496
497 /* Verify the descriptor CRC */
498 if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0))
499 {
500 udf_errno = 0;
501 return 0;
502 }
503 #ifdef __KERNEL__
504 printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
505 #else
506 udf_errno = 9;
507 #endif
508
509 error_out:
510 return -1;
511 }
512 #endif
513