Blame view

fs/udf/misc.c 7.78 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/buffer_head.h>
f845fced9   Bob Copeland   udf: use crc_itu_...
27
  #include <linux/crc-itu-t.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  
  #include "udf_i.h"
  #include "udf_sb.h"
cb00ea352   Cyrill Gorcunov   UDF: coding style...
31
  struct buffer_head *udf_tgetblk(struct super_block *sb, int block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
  {
  	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
  		return sb_getblk(sb, udf_fixed_to_variable(block));
  	else
  		return sb_getblk(sb, block);
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
38
  struct buffer_head *udf_tread(struct super_block *sb, int block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
  {
  	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...
45
46
  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
47
48
49
50
  {
  	uint8_t *ea = NULL, *ad = NULL;
  	int offset;
  	uint16_t crclen;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
51
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

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

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

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

48d6d8ff7   Marcin Slusarz   udf: cache struct...
151
  	ea = iinfo->i_ext.i_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
169
  		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...
170
  		while (offset < iinfo->i_lenEAttr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  			gaf = (struct genericFormat *)&ea[offset];
4b11111ab   Marcin Slusarz   udf: fix coding s...
172
173
  			if (le32_to_cpu(gaf->attrType) == type &&
  					gaf->attrSubtype == subtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
  				return gaf;
  			else
  				offset += le32_to_cpu(gaf->attrLength);
  		}
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
179

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

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

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

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

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