]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - fs/udf/misc.c
Linux-2.6.12-rc2
[karo-tx-linux.git] / 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-2004 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 #include <linux/fs.h>
30 #include <linux/string.h>
31 #include <linux/udf_fs.h>
32 #include <linux/buffer_head.h>
33
34 #include "udf_i.h"
35 #include "udf_sb.h"
36
37 struct buffer_head *
38 udf_tgetblk(struct super_block *sb, int block)
39 {
40         if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
41                 return sb_getblk(sb, udf_fixed_to_variable(block));
42         else
43                 return sb_getblk(sb, block);
44 }
45
46 struct buffer_head *
47 udf_tread(struct super_block *sb, int block)
48 {
49         if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
50                 return sb_bread(sb, udf_fixed_to_variable(block));
51         else
52                 return sb_bread(sb, block);
53 }
54
55 struct genericFormat *
56 udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
57         uint8_t loc)
58 {
59         uint8_t *ea = NULL, *ad = NULL;
60         int offset;
61         uint16_t crclen;
62         int i;
63
64         ea = UDF_I_DATA(inode);
65         if (UDF_I_LENEATTR(inode))
66                 ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
67         else
68         {
69                 ad = ea;
70                 size += sizeof(struct extendedAttrHeaderDesc);
71         }
72
73         offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
74                 UDF_I_LENALLOC(inode);
75
76         /* TODO - Check for FreeEASpace */
77
78         if (loc & 0x01 && offset >= size)
79         {
80                 struct extendedAttrHeaderDesc *eahd;
81                 eahd = (struct extendedAttrHeaderDesc *)ea;
82
83                 if (UDF_I_LENALLOC(inode))
84                 {
85                         memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
86                 }
87
88                 if (UDF_I_LENEATTR(inode))
89                 {
90                         /* check checksum/crc */
91                         if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
92                                 le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
93                         {
94                                 return NULL;
95                         }
96                 }
97                 else
98                 {
99                         size -= sizeof(struct extendedAttrHeaderDesc);
100                         UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
101                         eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
102                         if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
103                                 eahd->descTag.descVersion = cpu_to_le16(3);
104                         else
105                                 eahd->descTag.descVersion = cpu_to_le16(2);
106                         eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
107                         eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
108                         eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
109                         eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
110                 }
111
112                 offset = UDF_I_LENEATTR(inode);
113                 if (type < 2048)
114                 {
115                         if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
116                         {
117                                 uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
118                                 memmove(&ea[offset - aal + size],
119                                         &ea[aal], offset - aal);
120                                 offset -= aal;
121                                 eahd->appAttrLocation = cpu_to_le32(aal + size);
122                         }
123                         if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
124                         {
125                                 uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
126                                 memmove(&ea[offset - ial + size],
127                                         &ea[ial], offset - ial);
128                                 offset -= ial;
129                                 eahd->impAttrLocation = cpu_to_le32(ial + size);
130                         }
131                 }
132                 else if (type < 65536)
133                 {
134                         if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
135                         {
136                                 uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
137                                 memmove(&ea[offset - aal + size],
138                                         &ea[aal], offset - aal);
139                                 offset -= aal;
140                                 eahd->appAttrLocation = cpu_to_le32(aal + size);
141                         }
142                 }
143                 /* rewrite CRC + checksum of eahd */
144                 crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
145                 eahd->descTag.descCRCLength = cpu_to_le16(crclen);
146                 eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
147                 eahd->descTag.tagChecksum = 0;
148                 for (i=0; i<16; i++)
149                         if (i != 4)
150                                 eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
151                 UDF_I_LENEATTR(inode) += size;
152                 return (struct genericFormat *)&ea[offset];
153         }
154         if (loc & 0x02)
155         {
156         }
157         return NULL;
158 }
159
160 struct genericFormat *
161 udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
162 {
163         struct genericFormat *gaf;
164         uint8_t *ea = NULL;
165         uint32_t offset;
166
167         ea = UDF_I_DATA(inode);
168
169         if (UDF_I_LENEATTR(inode))
170         {
171                 struct extendedAttrHeaderDesc *eahd;
172                 eahd = (struct extendedAttrHeaderDesc *)ea;
173
174                 /* check checksum/crc */
175                 if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
176                         le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
177                 {
178                         return NULL;
179                 }
180         
181                 if (type < 2048)
182                         offset = sizeof(struct extendedAttrHeaderDesc);
183                 else if (type < 65536)
184                         offset = le32_to_cpu(eahd->impAttrLocation);
185                 else
186                         offset = le32_to_cpu(eahd->appAttrLocation);
187
188                 while (offset < UDF_I_LENEATTR(inode))
189                 {
190                         gaf = (struct genericFormat *)&ea[offset];
191                         if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
192                                 return gaf;
193                         else
194                                 offset += le32_to_cpu(gaf->attrLength);
195                 }
196         }
197         return NULL;
198 }
199
200 /*
201  * udf_read_tagged
202  *
203  * PURPOSE
204  *      Read the first block of a tagged descriptor.
205  *
206  * HISTORY
207  *      July 1, 1997 - Andrew E. Mileski
208  *      Written, tested, and released.
209  */
210 struct buffer_head *
211 udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
212 {
213         tag *tag_p;
214         struct buffer_head *bh = NULL;
215         register uint8_t checksum;
216         register int i;
217
218         /* Read the block */
219         if (block == 0xFFFFFFFF)
220                 return NULL;
221
222         bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
223         if (!bh)
224         {
225                 udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
226                 return NULL;
227         }
228
229         tag_p = (tag *)(bh->b_data);
230
231         *ident = le16_to_cpu(tag_p->tagIdent);
232
233         if ( location != le32_to_cpu(tag_p->tagLocation) )
234         {
235                 udf_debug("location mismatch block %u, tag %u != %u\n",
236                         block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
237                 goto error_out;
238         }
239         
240         /* Verify the tag checksum */
241         checksum = 0U;
242         for (i = 0; i < 4; i++)
243                 checksum += (uint8_t)(bh->b_data[i]);
244         for (i = 5; i < 16; i++)
245                 checksum += (uint8_t)(bh->b_data[i]);
246         if (checksum != tag_p->tagChecksum) {
247                 printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
248                 goto error_out;
249         }
250
251         /* Verify the tag version */
252         if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
253                 le16_to_cpu(tag_p->descVersion) != 0x0003U)
254         {
255                 udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
256                         le16_to_cpu(tag_p->descVersion), block);
257                 goto error_out;
258         }
259
260         /* Verify the descriptor CRC */
261         if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
262                 le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
263                         le16_to_cpu(tag_p->descCRCLength), 0))
264         {
265                 return bh;
266         }
267         udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
268                 block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
269
270 error_out:
271         brelse(bh);
272         return NULL;
273 }
274
275 struct buffer_head *
276 udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
277 {
278         return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
279                 loc.logicalBlockNum + offset, ident);
280 }
281
282 void udf_release_data(struct buffer_head *bh)
283 {
284         if (bh)
285                 brelse(bh);
286 }
287
288 void udf_update_tag(char *data, int length)
289 {
290         tag *tptr = (tag *)data;
291         int i;
292
293         length -= sizeof(tag);
294
295         tptr->tagChecksum = 0;
296         tptr->descCRCLength = cpu_to_le16(length);
297         tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
298
299         for (i=0; i<16; i++)
300                 if (i != 4)
301                         tptr->tagChecksum += (uint8_t)(data[i]);
302 }
303
304 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
305         uint32_t loc, int length)
306 {
307         tag *tptr = (tag *)data;
308         tptr->tagIdent = cpu_to_le16(ident);
309         tptr->descVersion = cpu_to_le16(version);
310         tptr->tagSerialNum = cpu_to_le16(snum);
311         tptr->tagLocation = cpu_to_le32(loc);
312         udf_update_tag(data, length);
313 }