Blame view

fs/hpfs/map.c 9.79 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
  /*
   *  linux/fs/hpfs/map.c
   *
   *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
   *
   *  mapping structures to memory with some minimal checks
   */
  
  #include "hpfs_fn.h"
52576da35   Al Viro   hpfs: bitmaps are...
11
  __le32 *hpfs_map_dnode_bitmap(struct super_block *s, struct quad_buffer_head *qbh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  {
  	return hpfs_map_4sectors(s, hpfs_sb(s)->sb_dmap, qbh, 0);
  }
52576da35   Al Viro   hpfs: bitmaps are...
15
  __le32 *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
  			 struct quad_buffer_head *qbh, char *id)
  {
  	secno sec;
275f495db   Mikulas Patocka   hpfs: implement p...
19
  	__le32 *ret;
3ebacb050   Mikulas Patocka   hpfs: better test...
20
21
  	unsigned n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14;
  	if (hpfs_sb(s)->sb_chk) if (bmp_block >= n_bands) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
  		hpfs_error(s, "hpfs_map_bitmap called with bad parameter: %08x at %s", bmp_block, id);
  		return NULL;
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
25
  	sec = le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[bmp_block]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
  	if (!sec || sec > hpfs_sb(s)->sb_fs_size-4) {
  		hpfs_error(s, "invalid bitmap block pointer %08x -> %08x at %s", bmp_block, sec, id);
  		return NULL;
  	}
275f495db   Mikulas Patocka   hpfs: implement p...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  	ret = hpfs_map_4sectors(s, sec, qbh, 4);
  	if (ret) hpfs_prefetch_bitmap(s, bmp_block + 1);
  	return ret;
  }
  
  void hpfs_prefetch_bitmap(struct super_block *s, unsigned bmp_block)
  {
  	unsigned to_prefetch, next_prefetch;
  	unsigned n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14;
  	if (unlikely(bmp_block >= n_bands))
  		return;
  	to_prefetch = le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[bmp_block]);
  	if (unlikely(bmp_block + 1 >= n_bands))
  		next_prefetch = 0;
  	else
  		next_prefetch = le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[bmp_block + 1]);
  	hpfs_prefetch_sectors(s, to_prefetch, 4 + 4 * (to_prefetch + 4 == next_prefetch));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
  }
  
  /*
   * Load first code page into kernel memory, return pointer to 256-byte array,
   * first 128 bytes are uppercasing table for chars 128-255, next 128 bytes are
   * lowercasing table
   */
7e7742ee0   Al Viro   sanitize signedne...
54
  unsigned char *hpfs_load_code_page(struct super_block *s, secno cps)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
63
64
  {
  	struct buffer_head *bh;
  	secno cpds;
  	unsigned cpi;
  	unsigned char *ptr;
  	unsigned char *cp_table;
  	int i;
  	struct code_page_data *cpd;
  	struct code_page_directory *cp = hpfs_map_sector(s, cps, &bh, 0);
  	if (!cp) return NULL;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
65
  	if (le32_to_cpu(cp->magic) != CP_DIR_MAGIC) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
66
67
  		pr_err("Code page directory magic doesn't match (magic = %08x)
  ",
b7cb1ce22   Fabian Frederick   fs/hpfs: convert ...
68
  			le32_to_cpu(cp->magic));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
  		brelse(bh);
  		return NULL;
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
72
  	if (!le32_to_cpu(cp->n_code_pages)) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
73
74
  		pr_err("n_code_pages == 0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  		brelse(bh);
  		return NULL;
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
78
79
  	cpds = le32_to_cpu(cp->array[0].code_page_data);
  	cpi = le16_to_cpu(cp->array[0].index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
  	brelse(bh);
  
  	if (cpi >= 3) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
83
84
  		pr_err("Code page index out of array
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
  		return NULL;
  	}
  	
  	if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
89
  	if (le16_to_cpu(cpd->offs[cpi]) > 0x178) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
90
91
  		pr_err("Code page index out of sector
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
  		brelse(bh);
  		return NULL;
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
95
  	ptr = (unsigned char *)cpd + le16_to_cpu(cpd->offs[cpi]) + 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  	if (!(cp_table = kmalloc(256, GFP_KERNEL))) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
97
98
  		pr_err("out of memory for code page table
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  		brelse(bh);
  		return NULL;
  	}
  	memcpy(cp_table, ptr, 128);
  	brelse(bh);
  
  	/* Try to build lowercasing table from uppercasing one */
  
  	for (i=128; i<256; i++) cp_table[i]=i;
  	for (i=128; i<256; i++) if (cp_table[i-128]!=i && cp_table[i-128]>=128)
  		cp_table[cp_table[i-128]] = i;
  	
  	return cp_table;
  }
28fe3c196   Al Viro   hpfs: assorted en...
113
  __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
  {
  	struct buffer_head *bh;
  	int n = (hpfs_sb(s)->sb_fs_size + 0x200000 - 1) >> 21;
  	int i;
28fe3c196   Al Viro   hpfs: assorted en...
118
  	__le32 *b;
6da2ec560   Kees Cook   treewide: kmalloc...
119
  	if (!(b = kmalloc_array(n, 512, GFP_KERNEL))) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
120
121
  		pr_err("can't allocate memory for bitmap directory
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
  		return NULL;
  	}	
  	for (i=0;i<n;i++) {
28fe3c196   Al Viro   hpfs: assorted en...
125
  		__le32 *d = hpfs_map_sector(s, bmp+i, &bh, n - i - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
  		if (!d) {
  			kfree(b);
  			return NULL;
  		}
  		memcpy((char *)b + 512 * i, d, 512);
  		brelse(bh);
  	}
  	return b;
  }
a64eefaac   Mikulas Patocka   hpfs: support hot...
135
136
137
  void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock)
  {
  	struct quad_buffer_head qbh;
4e728cf8f   Al Viro   hpfs: missing end...
138
  	__le32 *directory;
a64eefaac   Mikulas Patocka   hpfs: support hot...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	u32 n_hotfixes, n_used_hotfixes;
  	unsigned i;
  
  	n_hotfixes = le32_to_cpu(spareblock->n_spares);
  	n_used_hotfixes = le32_to_cpu(spareblock->n_spares_used);
  
  	if (n_hotfixes > 256 || n_used_hotfixes > n_hotfixes) {
  		hpfs_error(s, "invalid number of hotfixes: %u, used: %u", n_hotfixes, n_used_hotfixes);
  		return;
  	}
  	if (!(directory = hpfs_map_4sectors(s, le32_to_cpu(spareblock->hotfix_map), &qbh, 0))) {
  		hpfs_error(s, "can't load hotfix map");
  		return;
  	}
  	for (i = 0; i < n_used_hotfixes; i++) {
  		hpfs_sb(s)->hotfix_from[i] = le32_to_cpu(directory[i]);
  		hpfs_sb(s)->hotfix_to[i] = le32_to_cpu(directory[n_hotfixes + i]);
  	}
  	hpfs_sb(s)->n_hotfixes = n_used_hotfixes;
  	hpfs_brelse4(&qbh);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  /*
   * Load fnode to memory
   */
  
  struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_head **bhp)
  {
  	struct fnode *fnode;
  	if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ino, 1, "fnode")) {
  		return NULL;
  	}
  	if ((fnode = hpfs_map_sector(s, ino, bhp, FNODE_RD_AHEAD))) {
  		if (hpfs_sb(s)->sb_chk) {
  			struct extended_attribute *ea;
  			struct extended_attribute *ea_end;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
174
  			if (le32_to_cpu(fnode->magic) != FNODE_MAGIC) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
175
176
  				hpfs_error(s, "bad magic on fnode %08lx",
  					(unsigned long)ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
  				goto bail;
  			}
c4c995430   Al Viro   hpfs: get rid of ...
179
  			if (!fnode_is_dir(fnode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  				if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes !=
ddc19e6e0   Al Viro   hpfs: annotate bt...
181
  				    (bp_internal(&fnode->btree) ? 12 : 8)) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
182
183
184
  					hpfs_error(s,
  					   "bad number of nodes in fnode %08lx",
  					    (unsigned long)ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  					goto bail;
  				}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
187
  				if (le16_to_cpu(fnode->btree.first_free) !=
ddc19e6e0   Al Viro   hpfs: annotate bt...
188
  				    8 + fnode->btree.n_used_nodes * (bp_internal(&fnode->btree) ? 8 : 12)) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
189
190
191
  					hpfs_error(s,
  					    "bad first_free pointer in fnode %08lx",
  					    (unsigned long)ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
  					goto bail;
  				}
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
195
196
  			if (le16_to_cpu(fnode->ea_size_s) && (le16_to_cpu(fnode->ea_offs) < 0xc4 ||
  			   le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200)) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
197
198
199
  				hpfs_error(s,
  					"bad EA info in fnode %08lx: ea_offs == %04x ea_size_s == %04x",
  					(unsigned long)ino,
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
200
  					le16_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
206
  				goto bail;
  			}
  			ea = fnode_ea(fnode);
  			ea_end = fnode_end_ea(fnode);
  			while (ea != ea_end) {
  				if (ea > ea_end) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
207
208
  					hpfs_error(s, "bad EA in fnode %08lx",
  						(unsigned long)ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  					goto bail;
  				}
  				ea = next_ea(ea);
  			}
  		}
  	}
  	return fnode;
  	bail:
  	brelse(*bhp);
  	return NULL;
  }
  
  struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buffer_head **bhp)
  {
  	struct anode *anode;
  	if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ano, 1, "anode")) return NULL;
  	if ((anode = hpfs_map_sector(s, ano, bhp, ANODE_RD_AHEAD)))
  		if (hpfs_sb(s)->sb_chk) {
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
227
  			if (le32_to_cpu(anode->magic) != ANODE_MAGIC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  				hpfs_error(s, "bad magic on anode %08x", ano);
  				goto bail;
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
231
232
233
234
  			if (le32_to_cpu(anode->self) != ano) {
  				hpfs_error(s, "self pointer invalid on anode %08x", ano);
  				goto bail;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  			if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes !=
ddc19e6e0   Al Viro   hpfs: annotate bt...
236
  			    (bp_internal(&anode->btree) ? 60 : 40)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
  				hpfs_error(s, "bad number of nodes in anode %08x", ano);
  				goto bail;
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
240
  			if (le16_to_cpu(anode->btree.first_free) !=
ddc19e6e0   Al Viro   hpfs: annotate bt...
241
  			    8 + anode->btree.n_used_nodes * (bp_internal(&anode->btree) ? 8 : 12)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  				hpfs_error(s, "bad first_free pointer in anode %08x", ano);
  				goto bail;
  			}
  		}
  	return anode;
  	bail:
  	brelse(*bhp);
  	return NULL;
  }
  
  /*
   * Load dnode to memory and do some checks
   */
  
  struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
  			     struct quad_buffer_head *qbh)
  {
  	struct dnode *dnode;
  	if (hpfs_sb(s)->sb_chk) {
  		if (hpfs_chk_sectors(s, secno, 4, "dnode")) return NULL;
  		if (secno & 3) {
  			hpfs_error(s, "dnode %08x not byte-aligned", secno);
  			return NULL;
  		}	
  	}
  	if ((dnode = hpfs_map_4sectors(s, secno, qbh, DNODE_RD_AHEAD)))
  		if (hpfs_sb(s)->sb_chk) {
  			unsigned p, pp = 0;
7e7742ee0   Al Viro   sanitize signedne...
270
  			unsigned char *d = (unsigned char *)dnode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  			int b = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
272
  			if (le32_to_cpu(dnode->magic) != DNODE_MAGIC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
  				hpfs_error(s, "bad magic on dnode %08x", secno);
  				goto bail;
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
276
277
  			if (le32_to_cpu(dnode->self) != secno)
  				hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, le32_to_cpu(dnode->self));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
  			/* Check dirents - bad dirents would cause infinite
  			   loops or shooting to memory */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
280
281
  			if (le32_to_cpu(dnode->first_free) > 2048) {
  				hpfs_error(s, "dnode %08x has first_free == %08x", secno, le32_to_cpu(dnode->first_free));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
  				goto bail;
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
284
  			for (p = 20; p < le32_to_cpu(dnode->first_free); p += d[p] + (d[p+1] << 8)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  				struct hpfs_dirent *de = (struct hpfs_dirent *)((char *)dnode + p);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
286
  				if (le16_to_cpu(de->length) > 292 || (le16_to_cpu(de->length) < 32) || (le16_to_cpu(de->length) & 3) || p + le16_to_cpu(de->length) > 2048) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
  					hpfs_error(s, "bad dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
  					goto bail;
  				}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
290
  				if (((31 + de->namelen + de->down*4 + 3) & ~3) != le16_to_cpu(de->length)) {
1751e8a6c   Linus Torvalds   Rename superblock...
291
  					if (((31 + de->namelen + de->down*4 + 3) & ~3) < le16_to_cpu(de->length) && s->s_flags & SB_RDONLY) goto ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
  					hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
  					goto bail;
  				}
  				ok:
  				if (hpfs_sb(s)->sb_chk >= 2) b |= 1 << de->down;
  				if (de->down) if (de_down_pointer(de) < 0x10) {
  					hpfs_error(s, "bad down pointer in dnode %08x, dirent %03x, last %03x", secno, p, pp);
  					goto bail;
  				}
  				pp = p;
  				
  			}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
304
  			if (p != le32_to_cpu(dnode->first_free)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
  				hpfs_error(s, "size on last dirent does not match first_free; dnode %08x", secno);
  				goto bail;
  			}
  			if (d[pp + 30] != 1 || d[pp + 31] != 255) {
  				hpfs_error(s, "dnode %08x does not end with \\377 entry", secno);
  				goto bail;
  			}
b7cb1ce22   Fabian Frederick   fs/hpfs: convert ...
312
  			if (b == 3)
a19189e55   Fabian Frederick   fs/hpfs: increase...
313
314
  				pr_err("unbalanced dnode tree, dnode %08x; see hpfs.txt 4 more info
  ",
b7cb1ce22   Fabian Frederick   fs/hpfs: convert ...
315
  					secno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  		}
  	return dnode;
  	bail:
  	hpfs_brelse4(qbh);
  	return NULL;
  }
  
  dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino)
  {
  	struct buffer_head *bh;
  	struct fnode *fnode;
  	dnode_secno dno;
  
  	fnode = hpfs_map_fnode(s, ino, &bh);
  	if (!fnode)
  		return 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
332
  	dno = le32_to_cpu(fnode->u.external[0].disk_secno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
  	brelse(bh);
  	return dno;
  }