Import 2.3.26pre2
[davej-history.git] / fs / udf / misc.c
blobf5b36dc7fe23fa8b6ba48d4422e6c92b2b389c59
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;
69 uid_t udf_convert_uid(int uidin)
71 if ( uidin == -1 )
72 return 0;
73 if ( uidin > (64*1024U - 1) ) /* 16 bit UID */
74 return 0;
75 return uidin;
78 gid_t udf_convert_gid(int gidin)
80 if ( gidin == -1 )
81 return 0;
82 if ( gidin > (64*1024U - 1) ) /* 16 bit GID */
83 return 0;
84 return gidin;
87 #if defined(__linux__) && defined(__KERNEL__)
89 extern struct buffer_head *
90 udf_tread(struct super_block *sb, int block, int size)
92 if (UDF_SB(sb)->s_flags & UDF_FLAG_VARCONV)
93 return bread(sb->s_dev, udf_fixed_to_variable(block), size);
94 else
95 return bread(sb->s_dev, block, size);
98 extern struct GenericAttrFormat *
99 udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
100 Uint8 loc, struct buffer_head **bh)
102 Uint8 *ea = NULL, *ad = NULL;
103 long_ad eaicb;
104 int offset;
106 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
108 if (UDF_I_EXTENDED_FE(inode) == 0)
110 struct FileEntry *fe;
112 fe = (struct FileEntry *)(*bh)->b_data;
113 eaicb = fe->extendedAttrICB;
114 offset = sizeof(struct FileEntry);
116 else
118 struct ExtendedFileEntry *efe;
120 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
121 eaicb = efe->extendedAttrICB;
122 offset = sizeof(struct ExtendedFileEntry);
125 ea = &(*bh)->b_data[offset];
126 if (UDF_I_LENEATTR(inode))
127 offset += UDF_I_LENEATTR(inode);
128 else
129 size += sizeof(struct ExtendedAttrHeaderDesc);
131 ad = &(*bh)->b_data[offset];
132 if (UDF_I_LENALLOC(inode))
133 offset += UDF_I_LENALLOC(inode);
135 offset = inode->i_sb->s_blocksize - offset;
137 /* TODO - Check for FreeEASpace */
139 if (loc & 0x01 && offset >= size)
141 struct ExtendedAttrHeaderDesc *eahd;
142 eahd = (struct ExtendedAttrHeaderDesc *)ea;
144 if (UDF_I_LENALLOC(inode))
146 memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
147 UDF_I_EXT0OFFS(inode) += size;
150 if (UDF_I_LENEATTR(inode))
152 /* check checksum/crc */
153 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
154 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
156 udf_release_data(*bh);
157 return NULL;
160 else
162 size -= sizeof(struct ExtendedAttrHeaderDesc);
163 UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
164 eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
165 eahd->descTag.descVersion = cpu_to_le16(2);
166 eahd->descTag.tagSerialNum = cpu_to_le16(1);
167 eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
168 eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
169 eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
172 offset = UDF_I_LENEATTR(inode);
173 if (type < 2048)
175 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
177 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
178 memmove(&ea[offset - aal + size],
179 &ea[aal], offset - aal);
180 offset -= aal;
181 eahd->appAttrLocation = cpu_to_le32(aal + size);
183 if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
185 Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
186 memmove(&ea[offset - ial + size],
187 &ea[ial], offset - ial);
188 offset -= ial;
189 eahd->impAttrLocation = cpu_to_le32(ial + size);
192 else if (type < 65536)
194 if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
196 Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
197 memmove(&ea[offset - aal + size],
198 &ea[aal], offset - aal);
199 offset -= aal;
200 eahd->appAttrLocation = cpu_to_le32(aal + size);
203 /* rewrite CRC + checksum of eahd */
204 UDF_I_LENEATTR(inode) += size;
205 return (struct GenericAttrFormat *)&ea[offset];
207 if (loc & 0x02)
210 udf_release_data(*bh);
211 return NULL;
214 extern struct GenericAttrFormat *
215 udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
216 struct buffer_head **bh)
218 struct GenericAttrFormat *gaf;
219 Uint8 *ea = NULL;
220 long_ad eaicb;
221 Uint32 offset;
223 *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
225 if (UDF_I_EXTENDED_FE(inode) == 0)
227 struct FileEntry *fe;
229 fe = (struct FileEntry *)(*bh)->b_data;
230 eaicb = fe->extendedAttrICB;
231 if (UDF_I_LENEATTR(inode))
232 ea = fe->extendedAttr;
234 else
236 struct ExtendedFileEntry *efe;
238 efe = (struct ExtendedFileEntry *)(*bh)->b_data;
239 eaicb = efe->extendedAttrICB;
240 if (UDF_I_LENEATTR(inode))
241 ea = efe->extendedAttr;
244 if (UDF_I_LENEATTR(inode))
246 struct ExtendedAttrHeaderDesc *eahd;
247 eahd = (struct ExtendedAttrHeaderDesc *)ea;
249 /* check checksum/crc */
250 if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
251 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
253 udf_release_data(*bh);
254 return NULL;
257 if (type < 2048)
258 offset = sizeof(struct ExtendedAttrHeaderDesc);
259 else if (type < 65536)
260 offset = le32_to_cpu(eahd->impAttrLocation);
261 else
262 offset = le32_to_cpu(eahd->appAttrLocation);
264 while (offset < UDF_I_LENEATTR(inode))
266 gaf = (struct GenericAttrFormat *)&ea[offset];
267 if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
268 return gaf;
269 else
270 offset += le32_to_cpu(gaf->attrLength);
274 udf_release_data(*bh);
275 if (eaicb.extLength)
277 /* TODO */
279 return NULL;
282 extern struct buffer_head *
283 udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
285 struct buffer_head *bh = NULL;
287 /* Read the block */
288 bh = udf_tread(sb, block+offset, sb->s_blocksize);
289 if (!bh)
291 printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
292 sb, block, offset);
293 return NULL;
295 return bh;
299 * udf_read_tagged
301 * PURPOSE
302 * Read the first block of a tagged descriptor.
304 * HISTORY
305 * July 1, 1997 - Andrew E. Mileski
306 * Written, tested, and released.
308 extern struct buffer_head *
309 udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
311 tag *tag_p;
312 struct buffer_head *bh = NULL;
313 register Uint8 checksum;
314 register int i;
316 /* Read the block */
317 if (block == 0xFFFFFFFF)
318 return NULL;
320 bh = udf_tread(sb, block, sb->s_blocksize);
321 if (!bh)
323 udf_debug("block=%d, location=%d: read failed\n", block, location);
324 return NULL;
327 tag_p = (tag *)(bh->b_data);
329 *ident = le16_to_cpu(tag_p->tagIdent);
331 if ( location != le32_to_cpu(tag_p->tagLocation) )
333 udf_debug("location mismatch block %d, tag %d != %d\n",
334 block, le32_to_cpu(tag_p->tagLocation), location);
335 goto error_out;
338 /* Verify the tag checksum */
339 checksum = 0U;
340 for (i = 0; i < 4; i++)
341 checksum += (Uint8)(bh->b_data[i]);
342 for (i = 5; i < 16; i++)
343 checksum += (Uint8)(bh->b_data[i]);
344 if (checksum != tag_p->tagChecksum) {
345 printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
346 goto error_out;
349 /* Verify the tag version */
350 if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
351 le16_to_cpu(tag_p->descVersion) != 0x0003U)
353 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
354 le16_to_cpu(tag_p->descVersion), block);
355 goto error_out;
358 /* Verify the descriptor CRC */
359 if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
360 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
361 le16_to_cpu(tag_p->descCRCLength), 0))
363 return bh;
365 udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
366 block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
368 error_out:
369 brelse(bh);
370 return NULL;
373 extern struct buffer_head *
374 udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
376 return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
377 loc.logicalBlockNum + offset, ident);
380 void udf_release_data(struct buffer_head *bh)
382 if (bh)
383 brelse(bh);
386 #endif
388 void udf_update_tag(char *data, int length)
390 tag *tptr = (tag *)data;
391 int i;
393 length -= sizeof(tag);
395 tptr->tagChecksum = 0;
396 tptr->descCRCLength = le16_to_cpu(length);
397 tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
399 for (i=0; i<16; i++)
400 if (i != 4)
401 tptr->tagChecksum += (Uint8)(data[i]);
404 void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
405 Uint32 loc, int length)
407 tag *tptr = (tag *)data;
408 tptr->tagIdent = le16_to_cpu(ident);
409 tptr->descVersion = le16_to_cpu(version);
410 tptr->tagSerialNum = le16_to_cpu(snum);
411 tptr->tagLocation = le32_to_cpu(loc);
412 udf_update_tag(data, length);
415 #ifndef __KERNEL__
417 * udf_read_tagged_data
419 * PURPOSE
420 * Read the first block of a tagged descriptor.
421 * Usable from user-land.
423 * HISTORY
424 * 10/4/98 dgb: written
427 udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
429 tag *tag_p;
430 register Uint8 checksum;
431 register int i;
432 unsigned long offs;
434 if (!buffer)
436 udf_errno = 1;
437 return -1;
440 if ( !udf_blocksize )
442 udf_errno = 2;
443 return -1;
446 if ( size < udf_blocksize )
448 udf_errno=3;
449 return -1;
451 udf_errno=0;
453 offs=(long)block * udf_blocksize;
454 if ( lseek(fd, offs, SEEK_SET) != offs ) {
455 udf_errno=4;
456 return -1;
459 i=read(fd, buffer, udf_blocksize);
460 if ( i < udf_blocksize ) {
461 udf_errno=5;
462 return -1;
465 tag_p = (tag *)(buffer);
467 /* Verify the tag location */
468 if ((block-offset) != tag_p->tagLocation) {
469 #ifdef __KERNEL__
470 printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
471 block, tag_p->tagLocation);
472 #else
473 udf_errno=6;
474 #endif
475 goto error_out;
478 /* Verify the tag checksum */
479 checksum = 0U;
480 for (i = 0; i < 4; i++)
481 checksum += (Uint8)(buffer[i]);
482 for (i = 5; i < 16; i++)
483 checksum += (Uint8)(buffer[i]);
484 if (checksum != tag_p->tagChecksum) {
485 #ifdef __KERNEL__
486 printk(KERN_ERR "udf: tag checksum failed\n");
487 #else
488 udf_errno=7;
489 #endif
490 goto error_out;
493 /* Verify the tag version */
494 if (tag_p->descVersion != 0x0002U) {
495 #ifdef __KERNEL__
496 printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
497 tag_p->descVersion);
498 #else
499 udf_errno=8;
500 #endif
501 goto error_out;
504 /* Verify the descriptor CRC */
505 if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
506 udf_errno=0;
507 return 0;
509 #ifdef __KERNEL__
510 printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
511 #else
512 udf_errno=9;
513 #endif
515 error_out:
516 return -1;
518 #endif