* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / fs / udf / misc.c
blob2d7eb08f45c0f8b5d1dba0ea9962ac9f96073724
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-1999 Ben Fennema
20 * (C) 1999 Stelias Computing Inc
22 * HISTORY
24 * 04/19/99 blf partial support for reading/writing specific EA's
28 #if defined(__linux__) && defined(__KERNEL__)
30 #include "udfdecl.h"
32 #include "udf_sb.h"
33 #include "udf_i.h"
35 #include <linux/fs.h>
36 #include <linux/string.h>
37 #include <linux/udf_fs.h>
39 #else
41 #include "udfdecl.h"
42 #include <sys/types.h>
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <string.h>
47 int udf_blocksize=0;
48 int udf_errno=0;
50 void
51 udf_setblocksize(int size)
53 udf_blocksize=size;
55 #endif
57 Uint32
58 udf64_low32(Uint64 indat)
60 return indat & 0x00000000FFFFFFFFULL;
63 Uint32
64 udf64_high32(Uint64 indat)
66 return indat >> 32;
70 * udf_stamp_to_time
72 time_t *
73 udf_stamp_to_time(time_t *dest, timestamp src)
75 struct ktm tm;
77 if ((!dest))
78 return NULL;
80 /* this is very rough. need to find source to mktime() */
81 tm.tm_year=(src.year) - 1900;
82 tm.tm_mon=(src.month);
83 tm.tm_mday=(src.day);
84 tm.tm_hour=src.hour;
85 tm.tm_min=src.minute;
86 tm.tm_sec=src.second;
87 *dest = udf_converttime(&tm);
88 return dest;
91 uid_t udf_convert_uid(int uidin)
93 if ( uidin == -1 )
94 return 0;
95 if ( uidin > (64*1024U - 1) ) /* 16 bit UID */
96 return 0;
97 return uidin;
100 gid_t udf_convert_gid(int gidin)
102 if ( gidin == -1 )
103 return 0;
104 if ( gidin > (64*1024U - 1) ) /* 16 bit GID */
105 return 0;
106 return gidin;
109 #if defined(__linux__) && defined(__KERNEL__)
111 extern struct buffer_head *
112 udf_tread(struct super_block *sb, int block, int size)
114 if (UDF_SB(sb)->s_flags & UDF_FLAG_VARCONV)
115 return bread(sb->s_dev, udf_fixed_to_variable(block), size);
116 else
117 return bread(sb->s_dev, block, size);
120 extern struct GenericAttrFormat *
121 udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
122 Uint8 loc, struct buffer_head **bh)
124 Uint8 *ea = NULL, *ad = NULL;
125 long_ad eaicb;
126 int offset;
128 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
130 if (UDF_I_EXTENDED_FE(inode) == 0)
132 struct FileEntry *fe;
134 fe = (struct FileEntry *)(*bh)->b_data;
135 eaicb = fe->extendedAttrICB;
136 offset = sizeof(struct FileEntry);
138 else
140 struct ExtendedFileEntry *efe;
142 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
143 eaicb = efe->extendedAttrICB;
144 offset = sizeof(struct ExtendedFileEntry);
147 ea = &(*bh)->b_data[offset];
148 if (UDF_I_LENEATTR(inode))
149 offset += UDF_I_LENEATTR(inode);
150 else
151 size += sizeof(struct ExtendedAttrHeaderDesc);
153 ad = &(*bh)->b_data[offset];
154 if (UDF_I_LENALLOC(inode))
155 offset += UDF_I_LENALLOC(inode);
157 offset = inode->i_sb->s_blocksize - offset;
159 /* TODO - Check for FreeEASpace */
161 if (loc & 0x01 && offset >= size)
163 struct ExtendedAttrHeaderDesc *eahd;
164 eahd = (struct ExtendedAttrHeaderDesc *)ea;
166 if (UDF_I_LENALLOC(inode))
168 memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
169 UDF_I_EXT0OFFS(inode) += size;
172 if (UDF_I_LENEATTR(inode))
174 /* check checksum/crc */
175 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
176 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
178 udf_release_data(*bh);
179 return NULL;
182 else
184 size -= sizeof(struct ExtendedAttrHeaderDesc);
185 UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
186 eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
187 eahd->descTag.descVersion = cpu_to_le16(2);
188 eahd->descTag.tagSerialNum = cpu_to_le16(1);
189 eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
190 eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
191 eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
194 offset = UDF_I_LENEATTR(inode);
195 if (type < 2048)
197 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
199 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
200 memmove(&ea[offset - aal + size],
201 &ea[aal], offset - aal);
202 offset -= aal;
203 eahd->appAttrLocation = cpu_to_le32(aal + size);
205 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
207 Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
208 memmove(&ea[offset - ial + size],
209 &ea[ial], offset - ial);
210 offset -= ial;
211 eahd->impAttrLocation = cpu_to_le32(ial + size);
214 else if (type < 65536)
216 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
218 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
219 memmove(&ea[offset - aal + size],
220 &ea[aal], offset - aal);
221 offset -= aal;
222 eahd->appAttrLocation = cpu_to_le32(aal + size);
225 /* rewrite CRC + checksum of eahd */
226 UDF_I_LENEATTR(inode) += size;
227 return (struct GenericAttrFormat *)&ea[offset];
229 if (loc & 0x02)
232 udf_release_data(*bh);
233 return NULL;
236 extern struct GenericAttrFormat *
237 udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
238 struct buffer_head **bh)
240 struct GenericAttrFormat *gaf;
241 Uint8 *ea = NULL;
242 long_ad eaicb;
243 Uint32 offset;
245 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
247 if (UDF_I_EXTENDED_FE(inode) == 0)
249 struct FileEntry *fe;
251 fe = (struct FileEntry *)(*bh)->b_data;
252 eaicb = fe->extendedAttrICB;
253 if (UDF_I_LENEATTR(inode))
254 ea = fe->extendedAttr;
256 else
258 struct ExtendedFileEntry *efe;
260 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
261 eaicb = efe->extendedAttrICB;
262 if (UDF_I_LENEATTR(inode))
263 ea = efe->extendedAttr;
266 if (UDF_I_LENEATTR(inode))
268 struct ExtendedAttrHeaderDesc *eahd;
269 eahd = (struct ExtendedAttrHeaderDesc *)ea;
271 /* check checksum/crc */
272 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
273 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
275 udf_release_data(*bh);
276 return NULL;
279 if (type < 2048)
280 offset = sizeof(struct ExtendedAttrHeaderDesc);
281 else if (type < 65536)
282 offset = le32_to_cpu(eahd->impAttrLocation);
283 else
284 offset = le32_to_cpu(eahd->appAttrLocation);
286 while (offset < UDF_I_LENEATTR(inode))
288 gaf = (struct GenericAttrFormat *)&ea[offset];
289 if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
290 return gaf;
291 else
292 offset += le32_to_cpu(gaf->attrLength);
296 udf_release_data(*bh);
297 if (eaicb.extLength)
299 /* TODO */
301 return NULL;
304 extern struct buffer_head *
305 udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
307 struct buffer_head *bh = NULL;
309 /* Read the block */
310 bh = udf_tread(sb, block+offset, sb->s_blocksize);
311 if (!bh)
313 printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
314 sb, block, offset);
315 return NULL;
317 return bh;
321 * udf_read_tagged
323 * PURPOSE
324 * Read the first block of a tagged descriptor.
326 * HISTORY
327 * July 1, 1997 - Andrew E. Mileski
328 * Written, tested, and released.
330 extern struct buffer_head *
331 udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
333 tag *tag_p;
334 struct buffer_head *bh = NULL;
335 register Uint8 checksum;
336 register int i;
338 /* Read the block */
339 if (block == 0xFFFFFFFF)
340 return NULL;
342 bh = udf_tread(sb, block, sb->s_blocksize);
343 if (!bh)
345 udf_debug("block=%d, location=%d: read failed\n", block, location);
346 return NULL;
349 tag_p = (tag *)(bh->b_data);
351 *ident = le16_to_cpu(tag_p->tagIdent);
353 if ( location != le32_to_cpu(tag_p->tagLocation) )
355 udf_debug("location mismatch block %d, tag %d != %d\n",
356 block, le32_to_cpu(tag_p->tagLocation), location);
357 goto error_out;
360 /* Verify the tag checksum */
361 checksum = 0U;
362 for (i = 0; i < 4; i++)
363 checksum += (Uint8)(bh->b_data[i]);
364 for (i = 5; i < 16; i++)
365 checksum += (Uint8)(bh->b_data[i]);
366 if (checksum != tag_p->tagChecksum) {
367 printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
368 goto error_out;
371 /* Verify the tag version */
372 if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
373 le16_to_cpu(tag_p->descVersion) != 0x0003U)
375 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
376 le16_to_cpu(tag_p->descVersion), block);
377 goto error_out;
380 /* Verify the descriptor CRC */
381 if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
382 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
383 le16_to_cpu(tag_p->descCRCLength), 0))
385 return bh;
387 udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
388 block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
390 error_out:
391 brelse(bh);
392 return NULL;
395 extern struct buffer_head *
396 udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
398 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
399 loc.logicalBlockNum + offset, ident);
402 void udf_release_data(struct buffer_head *bh)
404 if (bh)
405 brelse(bh);
408 #endif
410 void udf_update_tag(char *data, int length)
412 tag *tptr = (tag *)data;
413 int i;
415 length -= sizeof(tag);
417 tptr->tagChecksum = 0;
418 tptr->descCRCLength = le16_to_cpu(length);
419 tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
421 for (i=0; i<16; i++)
422 if (i != 4)
423 tptr->tagChecksum += (Uint8)(data[i]);
426 void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
427 Uint32 loc, int length)
429 tag *tptr = (tag *)data;
430 tptr->tagIdent = le16_to_cpu(ident);
431 tptr->descVersion = le16_to_cpu(version);
432 tptr->tagSerialNum = le16_to_cpu(snum);
433 tptr->tagLocation = le32_to_cpu(loc);
434 udf_update_tag(data, length);
437 #ifndef __KERNEL__
439 * udf_read_tagged_data
441 * PURPOSE
442 * Read the first block of a tagged descriptor.
443 * Usable from user-land.
445 * HISTORY
446 * 10/4/98 dgb: written
449 udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
451 tag *tag_p;
452 register Uint8 checksum;
453 register int i;
454 unsigned long offs;
456 if (!buffer)
458 udf_errno = 1;
459 return -1;
462 if ( !udf_blocksize )
464 udf_errno = 2;
465 return -1;
468 if ( size < udf_blocksize )
470 udf_errno=3;
471 return -1;
473 udf_errno=0;
475 offs=(long)block * udf_blocksize;
476 if ( lseek(fd, offs, SEEK_SET) != offs ) {
477 udf_errno=4;
478 return -1;
481 i=read(fd, buffer, udf_blocksize);
482 if ( i < udf_blocksize ) {
483 udf_errno=5;
484 return -1;
487 tag_p = (tag *)(buffer);
489 /* Verify the tag location */
490 if ((block-offset) != tag_p->tagLocation) {
491 #ifdef __KERNEL__
492 printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
493 block, tag_p->tagLocation);
494 #else
495 udf_errno=6;
496 #endif
497 goto error_out;
500 /* Verify the tag checksum */
501 checksum = 0U;
502 for (i = 0; i < 4; i++)
503 checksum += (Uint8)(buffer[i]);
504 for (i = 5; i < 16; i++)
505 checksum += (Uint8)(buffer[i]);
506 if (checksum != tag_p->tagChecksum) {
507 #ifdef __KERNEL__
508 printk(KERN_ERR "udf: tag checksum failed\n");
509 #else
510 udf_errno=7;
511 #endif
512 goto error_out;
515 /* Verify the tag version */
516 if (tag_p->descVersion != 0x0002U) {
517 #ifdef __KERNEL__
518 printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
519 tag_p->descVersion);
520 #else
521 udf_errno=8;
522 #endif
523 goto error_out;
526 /* Verify the descriptor CRC */
527 if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
528 udf_errno=0;
529 return 0;
531 #ifdef __KERNEL__
532 printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
533 #else
534 udf_errno=9;
535 #endif
537 error_out:
538 return -1;
540 #endif