Merge with Linux 2.4.0-test5-pre6.
[linux-2.6/linux-mips.git] / fs / udf / misc.c
blobae998258e490d53668278debc44772828d58a410
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@hootie.lvld.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-2000 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 #if defined(__linux__) && defined(__KERNEL__)
31 #include "udf_sb.h"
32 #include "udf_i.h"
34 #include <linux/fs.h>
35 #include <linux/string.h>
36 #include <linux/udf_fs.h>
38 #else
40 #include <sys/types.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
45 int udf_blocksize=0;
46 int udf_errno=0;
48 void
49 udf_setblocksize(int size)
51 udf_blocksize=size;
53 #endif
55 Uint32
56 udf64_low32(Uint64 indat)
58 return indat & 0x00000000FFFFFFFFULL;
61 Uint32
62 udf64_high32(Uint64 indat)
64 return indat >> 32;
67 #if defined(__linux__) && defined(__KERNEL__)
69 extern struct buffer_head *
70 udf_tread(struct super_block *sb, int block, int size)
72 if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
73 return bread(sb->s_dev, udf_fixed_to_variable(block), size);
74 else
75 return bread(sb->s_dev, block, size);
78 extern struct GenericAttrFormat *
79 udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
80 Uint8 loc, struct buffer_head **bh)
82 Uint8 *ea = NULL, *ad = NULL;
83 long_ad eaicb;
84 int offset;
86 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
88 if (UDF_I_EXTENDED_FE(inode) == 0)
90 struct FileEntry *fe;
92 fe = (struct FileEntry *)(*bh)->b_data;
93 eaicb = lela_to_cpu(fe->extendedAttrICB);
94 offset = sizeof(struct FileEntry);
96 else
98 struct ExtendedFileEntry *efe;
100 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
101 eaicb = lela_to_cpu(efe->extendedAttrICB);
102 offset = sizeof(struct ExtendedFileEntry);
105 ea = &(*bh)->b_data[offset];
106 if (UDF_I_LENEATTR(inode))
107 offset += UDF_I_LENEATTR(inode);
108 else
109 size += sizeof(struct ExtendedAttrHeaderDesc);
111 ad = &(*bh)->b_data[offset];
112 if (UDF_I_LENALLOC(inode))
113 offset += UDF_I_LENALLOC(inode);
115 offset = inode->i_sb->s_blocksize - offset;
117 /* TODO - Check for FreeEASpace */
119 if (loc & 0x01 && offset >= size)
121 struct ExtendedAttrHeaderDesc *eahd;
122 eahd = (struct ExtendedAttrHeaderDesc *)ea;
124 if (UDF_I_LENALLOC(inode))
126 memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
129 if (UDF_I_LENEATTR(inode))
131 /* check checksum/crc */
132 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
133 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
135 udf_release_data(*bh);
136 return NULL;
139 else
141 size -= sizeof(struct ExtendedAttrHeaderDesc);
142 UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
143 eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
144 eahd->descTag.descVersion = cpu_to_le16(2);
145 eahd->descTag.tagSerialNum = cpu_to_le16(1);
146 eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
147 eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
148 eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
151 offset = UDF_I_LENEATTR(inode);
152 if (type < 2048)
154 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
156 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
157 memmove(&ea[offset - aal + size],
158 &ea[aal], offset - aal);
159 offset -= aal;
160 eahd->appAttrLocation = cpu_to_le32(aal + size);
162 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
164 Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
165 memmove(&ea[offset - ial + size],
166 &ea[ial], offset - ial);
167 offset -= ial;
168 eahd->impAttrLocation = cpu_to_le32(ial + size);
171 else if (type < 65536)
173 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
175 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
176 memmove(&ea[offset - aal + size],
177 &ea[aal], offset - aal);
178 offset -= aal;
179 eahd->appAttrLocation = cpu_to_le32(aal + size);
182 /* rewrite CRC + checksum of eahd */
183 UDF_I_LENEATTR(inode) += size;
184 return (struct GenericAttrFormat *)&ea[offset];
186 if (loc & 0x02)
189 udf_release_data(*bh);
190 return NULL;
193 extern struct GenericAttrFormat *
194 udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
195 struct buffer_head **bh)
197 struct GenericAttrFormat *gaf;
198 Uint8 *ea = NULL;
199 long_ad eaicb;
200 Uint32 offset;
202 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
204 if (UDF_I_EXTENDED_FE(inode) == 0)
206 struct FileEntry *fe;
208 fe = (struct FileEntry *)(*bh)->b_data;
209 eaicb = lela_to_cpu(fe->extendedAttrICB);
210 if (UDF_I_LENEATTR(inode))
211 ea = fe->extendedAttr;
213 else
215 struct ExtendedFileEntry *efe;
217 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
218 eaicb = lela_to_cpu(efe->extendedAttrICB);
219 if (UDF_I_LENEATTR(inode))
220 ea = efe->extendedAttr;
223 if (UDF_I_LENEATTR(inode))
225 struct ExtendedAttrHeaderDesc *eahd;
226 eahd = (struct ExtendedAttrHeaderDesc *)ea;
228 /* check checksum/crc */
229 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
230 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
232 udf_release_data(*bh);
233 return NULL;
236 if (type < 2048)
237 offset = sizeof(struct ExtendedAttrHeaderDesc);
238 else if (type < 65536)
239 offset = le32_to_cpu(eahd->impAttrLocation);
240 else
241 offset = le32_to_cpu(eahd->appAttrLocation);
243 while (offset < UDF_I_LENEATTR(inode))
245 gaf = (struct GenericAttrFormat *)&ea[offset];
246 if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
247 return gaf;
248 else
249 offset += le32_to_cpu(gaf->attrLength);
253 udf_release_data(*bh);
254 if (eaicb.extLength)
256 /* TODO */
258 return NULL;
261 extern struct buffer_head *
262 udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
264 struct buffer_head *bh = NULL;
266 /* Read the block */
267 bh = udf_tread(sb, block+offset, sb->s_blocksize);
268 if (!bh)
270 printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
271 sb, block, offset);
272 return NULL;
274 return bh;
278 * udf_read_tagged
280 * PURPOSE
281 * Read the first block of a tagged descriptor.
283 * HISTORY
284 * July 1, 1997 - Andrew E. Mileski
285 * Written, tested, and released.
287 extern struct buffer_head *
288 udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
290 tag *tag_p;
291 struct buffer_head *bh = NULL;
292 register Uint8 checksum;
293 register int i;
295 /* Read the block */
296 if (block == 0xFFFFFFFF)
297 return NULL;
299 bh = udf_tread(sb, block, sb->s_blocksize);
300 if (!bh)
302 udf_debug("block=%d, location=%d: read failed\n", block, location);
303 return NULL;
306 tag_p = (tag *)(bh->b_data);
308 *ident = le16_to_cpu(tag_p->tagIdent);
310 if ( location != le32_to_cpu(tag_p->tagLocation) )
312 udf_debug("location mismatch block %d, tag %d != %d\n",
313 block, le32_to_cpu(tag_p->tagLocation), location);
314 goto error_out;
317 /* Verify the tag checksum */
318 checksum = 0U;
319 for (i = 0; i < 4; i++)
320 checksum += (Uint8)(bh->b_data[i]);
321 for (i = 5; i < 16; i++)
322 checksum += (Uint8)(bh->b_data[i]);
323 if (checksum != tag_p->tagChecksum) {
324 printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
325 goto error_out;
328 /* Verify the tag version */
329 if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
330 le16_to_cpu(tag_p->descVersion) != 0x0003U)
332 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
333 le16_to_cpu(tag_p->descVersion), block);
334 goto error_out;
337 /* Verify the descriptor CRC */
338 if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
339 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
340 le16_to_cpu(tag_p->descCRCLength), 0))
342 return bh;
344 udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
345 block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
347 error_out:
348 brelse(bh);
349 return NULL;
352 extern struct buffer_head *
353 udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
355 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
356 loc.logicalBlockNum + offset, ident);
359 void udf_release_data(struct buffer_head *bh)
361 if (bh)
362 brelse(bh);
365 #endif
367 void udf_update_tag(char *data, int length)
369 tag *tptr = (tag *)data;
370 int i;
372 length -= sizeof(tag);
374 tptr->tagChecksum = 0;
375 tptr->descCRCLength = le16_to_cpu(length);
376 tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
378 for (i=0; i<16; i++)
379 if (i != 4)
380 tptr->tagChecksum += (Uint8)(data[i]);
383 void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
384 Uint32 loc, int length)
386 tag *tptr = (tag *)data;
387 tptr->tagIdent = le16_to_cpu(ident);
388 tptr->descVersion = le16_to_cpu(version);
389 tptr->tagSerialNum = le16_to_cpu(snum);
390 tptr->tagLocation = le32_to_cpu(loc);
391 udf_update_tag(data, length);
394 #ifndef __KERNEL__
396 * udf_read_tagged_data
398 * PURPOSE
399 * Read the first block of a tagged descriptor.
400 * Usable from user-land.
402 * HISTORY
403 * 10/4/98 dgb: written
406 udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
408 tag *tag_p;
409 register Uint8 checksum;
410 register int i;
411 unsigned long offs;
413 if (!buffer)
415 udf_errno = 1;
416 return -1;
419 if ( !udf_blocksize )
421 udf_errno = 2;
422 return -1;
425 if ( size < udf_blocksize )
427 udf_errno=3;
428 return -1;
430 udf_errno=0;
432 offs=(long)block * udf_blocksize;
433 if ( lseek(fd, offs, SEEK_SET) != offs ) {
434 udf_errno=4;
435 return -1;
438 i=read(fd, buffer, udf_blocksize);
439 if ( i < udf_blocksize ) {
440 udf_errno=5;
441 return -1;
444 tag_p = (tag *)(buffer);
446 /* Verify the tag location */
447 if ((block-offset) != tag_p->tagLocation) {
448 #ifdef __KERNEL__
449 printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
450 block, tag_p->tagLocation);
451 #else
452 udf_errno=6;
453 #endif
454 goto error_out;
457 /* Verify the tag checksum */
458 checksum = 0U;
459 for (i = 0; i < 4; i++)
460 checksum += (Uint8)(buffer[i]);
461 for (i = 5; i < 16; i++)
462 checksum += (Uint8)(buffer[i]);
463 if (checksum != tag_p->tagChecksum) {
464 #ifdef __KERNEL__
465 printk(KERN_ERR "udf: tag checksum failed\n");
466 #else
467 udf_errno=7;
468 #endif
469 goto error_out;
472 /* Verify the tag version */
473 if (tag_p->descVersion != 0x0002U) {
474 #ifdef __KERNEL__
475 printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
476 tag_p->descVersion);
477 #else
478 udf_errno=8;
479 #endif
480 goto error_out;
483 /* Verify the descriptor CRC */
484 if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
485 udf_errno=0;
486 return 0;
488 #ifdef __KERNEL__
489 printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
490 #else
491 udf_errno=9;
492 #endif
494 error_out:
495 return -1;
497 #endif