xref: /openbmc/linux/fs/udf/misc.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
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 }
314