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