Blame view

fs/udf/misc.c 7.72 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * misc.c
   *
   * PURPOSE
   *	Miscellaneous routines for the OSTA-UDF(tm) filesystem.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   * COPYRIGHT
   *	This file is distributed under the terms of the GNU General Public
   *	License (GPL). Copies of the GPL can be obtained from:
   *		ftp://prep.ai.mit.edu/pub/gnu/GPL
   *	Each contributing author retains all rights to their own work.
   *
   *  (C) 1998 Dave Boynton
   *  (C) 1998-2004 Ben Fennema
   *  (C) 1999-2000 Stelias Computing Inc
   *
   * HISTORY
   *
   *  04/19/99 blf  partial support for reading/writing specific EA's
   */
  
  #include "udfdecl.h"
  
  #include <linux/fs.h>
  #include <linux/string.h>
f845fced9   Bob Copeland   udf: use crc_itu_...
26
  #include <linux/crc-itu-t.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  
  #include "udf_i.h"
  #include "udf_sb.h"
b490bdd63   Steve Magnani   udf: Fix 64-bit s...
30
  struct buffer_head *udf_tgetblk(struct super_block *sb, udf_pblk_t block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
  {
  	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
  		return sb_getblk(sb, udf_fixed_to_variable(block));
  	else
  		return sb_getblk(sb, block);
  }
b490bdd63   Steve Magnani   udf: Fix 64-bit s...
37
  struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
  {
  	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
  		return sb_bread(sb, udf_fixed_to_variable(block));
  	else
  		return sb_bread(sb, block);
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
44
45
  struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
  					   uint32_t type, uint8_t loc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
  {
  	uint8_t *ea = NULL, *ad = NULL;
  	int offset;
  	uint16_t crclen;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
50
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

382a2287b   Jan Kara   udf: Remove point...
52
  	ea = iinfo->i_data;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
53
  	if (iinfo->i_lenEAttr) {
382a2287b   Jan Kara   udf: Remove point...
54
  		ad = iinfo->i_data + iinfo->i_lenEAttr;
28de7948a   Cyrill Gorcunov   UDF: coding style...
55
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
  		ad = ea;
  		size += sizeof(struct extendedAttrHeaderDesc);
  	}
  
  	offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
48d6d8ff7   Marcin Slusarz   udf: cache struct...
61
  		iinfo->i_lenAlloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  
  	/* TODO - Check for FreeEASpace */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
64
  	if (loc & 0x01 && offset >= size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
  		struct extendedAttrHeaderDesc *eahd;
  		eahd = (struct extendedAttrHeaderDesc *)ea;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
67
68
  		if (iinfo->i_lenAlloc)
  			memmove(&ad[size], ad, iinfo->i_lenAlloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69

48d6d8ff7   Marcin Slusarz   udf: cache struct...
70
  		if (iinfo->i_lenEAttr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  			/* check checksum/crc */
5e0f00173   Marcin Slusarz   udf: convert byte...
72
73
  			if (eahd->descTag.tagIdent !=
  					cpu_to_le16(TAG_IDENT_EAHD) ||
4b11111ab   Marcin Slusarz   udf: fix coding s...
74
  			    le32_to_cpu(eahd->descTag.tagLocation) !=
48d6d8ff7   Marcin Slusarz   udf: cache struct...
75
  					iinfo->i_location.logicalBlockNum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  				return NULL;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
77
  		} else {
6c79e987d   Marcin Slusarz   udf: remove some ...
78
  			struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  			size -= sizeof(struct extendedAttrHeaderDesc);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
80
  			iinfo->i_lenEAttr +=
4b11111ab   Marcin Slusarz   udf: fix coding s...
81
  				sizeof(struct extendedAttrHeaderDesc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  			eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
6c79e987d   Marcin Slusarz   udf: remove some ...
83
  			if (sbi->s_udfrev >= 0x0200)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
  				eahd->descTag.descVersion = cpu_to_le16(3);
  			else
  				eahd->descTag.descVersion = cpu_to_le16(2);
4b11111ab   Marcin Slusarz   udf: fix coding s...
87
88
89
  			eahd->descTag.tagSerialNum =
  					cpu_to_le16(sbi->s_serial_number);
  			eahd->descTag.tagLocation = cpu_to_le32(
48d6d8ff7   Marcin Slusarz   udf: cache struct...
90
  					iinfo->i_location.logicalBlockNum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  			eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
  			eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
  		}
48d6d8ff7   Marcin Slusarz   udf: cache struct...
94
  		offset = iinfo->i_lenEAttr;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
95
  		if (type < 2048) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
96
  			if (le32_to_cpu(eahd->appAttrLocation) <
48d6d8ff7   Marcin Slusarz   udf: cache struct...
97
  					iinfo->i_lenEAttr) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
98
99
  				uint32_t aal =
  					le32_to_cpu(eahd->appAttrLocation);
28de7948a   Cyrill Gorcunov   UDF: coding style...
100
101
  				memmove(&ea[offset - aal + size],
  					&ea[aal], offset - aal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  				offset -= aal;
4b11111ab   Marcin Slusarz   udf: fix coding s...
103
104
  				eahd->appAttrLocation =
  						cpu_to_le32(aal + size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  			}
4b11111ab   Marcin Slusarz   udf: fix coding s...
106
  			if (le32_to_cpu(eahd->impAttrLocation) <
48d6d8ff7   Marcin Slusarz   udf: cache struct...
107
  					iinfo->i_lenEAttr) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
108
109
  				uint32_t ial =
  					le32_to_cpu(eahd->impAttrLocation);
28de7948a   Cyrill Gorcunov   UDF: coding style...
110
111
  				memmove(&ea[offset - ial + size],
  					&ea[ial], offset - ial);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  				offset -= ial;
4b11111ab   Marcin Slusarz   udf: fix coding s...
113
114
  				eahd->impAttrLocation =
  						cpu_to_le32(ial + size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  			}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
116
  		} else if (type < 65536) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
117
  			if (le32_to_cpu(eahd->appAttrLocation) <
48d6d8ff7   Marcin Slusarz   udf: cache struct...
118
  					iinfo->i_lenEAttr) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
119
120
  				uint32_t aal =
  					le32_to_cpu(eahd->appAttrLocation);
28de7948a   Cyrill Gorcunov   UDF: coding style...
121
122
  				memmove(&ea[offset - aal + size],
  					&ea[aal], offset - aal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  				offset -= aal;
4b11111ab   Marcin Slusarz   udf: fix coding s...
124
125
  				eahd->appAttrLocation =
  						cpu_to_le32(aal + size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
  			}
  		}
  		/* rewrite CRC + checksum of eahd */
5ca4e4be8   Pekka Enberg   Remove struct typ...
129
  		crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  		eahd->descTag.descCRCLength = cpu_to_le16(crclen);
f845fced9   Bob Copeland   udf: use crc_itu_...
131
  		eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
5ca4e4be8   Pekka Enberg   Remove struct typ...
132
  						sizeof(struct tag), crclen));
3f2587bb2   Marcin Slusarz   udf: create commo...
133
  		eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
134
  		iinfo->i_lenEAttr += size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  		return (struct genericFormat *)&ea[offset];
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
137

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  	return NULL;
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
140
141
  struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
  					   uint8_t subtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
  {
  	struct genericFormat *gaf;
  	uint8_t *ea = NULL;
  	uint32_t offset;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
146
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147

382a2287b   Jan Kara   udf: Remove point...
148
  	ea = iinfo->i_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

48d6d8ff7   Marcin Slusarz   udf: cache struct...
150
  	if (iinfo->i_lenEAttr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  		struct extendedAttrHeaderDesc *eahd;
  		eahd = (struct extendedAttrHeaderDesc *)ea;
  
  		/* check checksum/crc */
5e0f00173   Marcin Slusarz   udf: convert byte...
155
156
  		if (eahd->descTag.tagIdent !=
  				cpu_to_le16(TAG_IDENT_EAHD) ||
4b11111ab   Marcin Slusarz   udf: fix coding s...
157
  		    le32_to_cpu(eahd->descTag.tagLocation) !=
48d6d8ff7   Marcin Slusarz   udf: cache struct...
158
  				iinfo->i_location.logicalBlockNum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  			return NULL;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
160

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
  		if (type < 2048)
  			offset = sizeof(struct extendedAttrHeaderDesc);
  		else if (type < 65536)
  			offset = le32_to_cpu(eahd->impAttrLocation);
  		else
  			offset = le32_to_cpu(eahd->appAttrLocation);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
167
  		while (offset < iinfo->i_lenEAttr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  			gaf = (struct genericFormat *)&ea[offset];
4b11111ab   Marcin Slusarz   udf: fix coding s...
169
170
  			if (le32_to_cpu(gaf->attrType) == type &&
  					gaf->attrSubtype == subtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
  				return gaf;
  			else
  				offset += le32_to_cpu(gaf->attrLength);
  		}
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
176

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
181
182
183
184
185
186
187
188
189
  	return NULL;
  }
  
  /*
   * udf_read_tagged
   *
   * PURPOSE
   *	Read the first block of a tagged descriptor.
   *
   * HISTORY
   *	July 1, 1997 - Andrew E. Mileski
   *	Written, tested, and released.
   */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
190
  struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
4b11111ab   Marcin Slusarz   udf: fix coding s...
191
  				    uint32_t location, uint16_t *ident)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
5ca4e4be8   Pekka Enberg   Remove struct typ...
193
  	struct tag *tag_p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  	struct buffer_head *bh = NULL;
7e273e3b4   Joe Perches   udf: Promote some...
195
  	u8 checksum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
  
  	/* Read the block */
  	if (block == 0xFFFFFFFF)
  		return NULL;
f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
200
  	bh = udf_tread(sb, block);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
201
  	if (!bh) {
fcbf7637e   Steve Magnani   udf: Fix signed/u...
202
203
  		udf_err(sb, "read failed, block=%u, location=%u
  ",
8076c363d   Joe Perches   udf: Rename udf_e...
204
  			block, location);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  		return NULL;
  	}
5ca4e4be8   Pekka Enberg   Remove struct typ...
207
  	tag_p = (struct tag *)(bh->b_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  
  	*ident = le16_to_cpu(tag_p->tagIdent);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
210
  	if (location != le32_to_cpu(tag_p->tagLocation)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  		udf_debug("location mismatch block %u, tag %u != %u
  ",
f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
213
  			  block, le32_to_cpu(tag_p->tagLocation), location);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
  		goto error_out;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
216

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	/* Verify the tag checksum */
7e273e3b4   Joe Perches   udf: Promote some...
218
219
  	checksum = udf_tag_checksum(tag_p);
  	if (checksum != tag_p->tagChecksum) {
8076c363d   Joe Perches   udf: Rename udf_e...
220
221
222
  		udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x
  ",
  			block, checksum, tag_p->tagChecksum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
  		goto error_out;
  	}
  
  	/* Verify the tag version */
5e0f00173   Marcin Slusarz   udf: convert byte...
227
228
  	if (tag_p->descVersion != cpu_to_le16(0x0002U) &&
  	    tag_p->descVersion != cpu_to_le16(0x0003U)) {
8076c363d   Joe Perches   udf: Rename udf_e...
229
230
231
  		udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u
  ",
  			le16_to_cpu(tag_p->descVersion), block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
  		goto error_out;
  	}
  
  	/* Verify the descriptor CRC */
5ca4e4be8   Pekka Enberg   Remove struct typ...
236
  	if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
f845fced9   Bob Copeland   udf: use crc_itu_...
237
  	    le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
5ca4e4be8   Pekka Enberg   Remove struct typ...
238
  					bh->b_data + sizeof(struct tag),
f845fced9   Bob Copeland   udf: use crc_itu_...
239
  					le16_to_cpu(tag_p->descCRCLength)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  		return bh;
4b11111ab   Marcin Slusarz   udf: fix coding s...
241

fcbf7637e   Steve Magnani   udf: Fix signed/u...
242
243
  	udf_debug("Crc failure block %u: crc = %u, crclen = %u
  ", block,
8076c363d   Joe Perches   udf: Rename udf_e...
244
245
  		  le16_to_cpu(tag_p->descCRC),
  		  le16_to_cpu(tag_p->descCRCLength));
28de7948a   Cyrill Gorcunov   UDF: coding style...
246
  error_out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  	brelse(bh);
  	return NULL;
  }
97e961fdb   Pekka Enberg   Fix the udf code ...
250
251
  struct buffer_head *udf_read_ptagged(struct super_block *sb,
  				     struct kernel_lb_addr *loc,
4b11111ab   Marcin Slusarz   udf: fix coding s...
252
  				     uint32_t offset, uint16_t *ident)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  {
  	return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
97e961fdb   Pekka Enberg   Fix the udf code ...
255
  			       loc->logicalBlockNum + offset, ident);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
  void udf_update_tag(char *data, int length)
  {
5ca4e4be8   Pekka Enberg   Remove struct typ...
259
260
  	struct tag *tptr = (struct tag *)data;
  	length -= sizeof(struct tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	tptr->descCRCLength = cpu_to_le16(length);
5ca4e4be8   Pekka Enberg   Remove struct typ...
263
  	tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
3f2587bb2   Marcin Slusarz   udf: create commo...
264
  	tptr->tagChecksum = udf_tag_checksum(tptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
  }
  
  void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
268
  		 uint32_t loc, int length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  {
5ca4e4be8   Pekka Enberg   Remove struct typ...
270
  	struct tag *tptr = (struct tag *)data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
  	tptr->tagIdent = cpu_to_le16(ident);
  	tptr->descVersion = cpu_to_le16(version);
  	tptr->tagSerialNum = cpu_to_le16(snum);
  	tptr->tagLocation = cpu_to_le32(loc);
  	udf_update_tag(data, length);
  }
3f2587bb2   Marcin Slusarz   udf: create commo...
277

5ca4e4be8   Pekka Enberg   Remove struct typ...
278
  u8 udf_tag_checksum(const struct tag *t)
3f2587bb2   Marcin Slusarz   udf: create commo...
279
280
281
282
  {
  	u8 *data = (u8 *)t;
  	u8 checksum = 0;
  	int i;
5ca4e4be8   Pekka Enberg   Remove struct typ...
283
  	for (i = 0; i < sizeof(struct tag); ++i)
3f2587bb2   Marcin Slusarz   udf: create commo...
284
285
286
287
  		if (i != 4) /* position of checksum */
  			checksum += data[i];
  	return checksum;
  }