Blame view

fs/udf/misc.c 7.7 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
  
  	/* Read the block */
  	if (block == 0xFFFFFFFF)
  		return NULL;
f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
202
  	bh = udf_tread(sb, block);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
203
204
205
  	if (!bh) {
  		udf_debug("block=%d, location=%d: read failed
  ",
f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
206
  			  block, location);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  		return NULL;
  	}
5ca4e4be8   Pekka Enberg   Remove struct typ...
209
  	tag_p = (struct tag *)(bh->b_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  
  	*ident = le16_to_cpu(tag_p->tagIdent);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
212
  	if (location != le32_to_cpu(tag_p->tagLocation)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  		udf_debug("location mismatch block %u, tag %u != %u
  ",
f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
215
  			  block, le32_to_cpu(tag_p->tagLocation), location);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  		goto error_out;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
218

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  	/* Verify the tag checksum */
3f2587bb2   Marcin Slusarz   udf: create commo...
220
  	if (udf_tag_checksum(tag_p) != tag_p->tagChecksum) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
  		printk(KERN_ERR "udf: tag checksum failed block %d
  ", block);
  		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)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  		udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d
  ",
cb00ea352   Cyrill Gorcunov   UDF: coding style...
231
  			  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

f4bcbbd92   Sebastian Manciulea   udf: Fix handling...
242
243
244
  	udf_debug("Crc failure block %d: crc = %d, crclen = %d
  ", block,
  	    le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245

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;
  }