]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - fs/hpfs/anode.c
1 // SPDX-License-Identifier: GPL-2.0
3 * linux/fs/hpfs/anode.c
5 * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
7 * handling HPFS anode tree that contains file allocation info
12 /* Find a sector in allocation tree */
14 secno
hpfs_bplus_lookup(struct super_block
*s
, struct inode
*inode
,
15 struct bplus_header
*btree
, unsigned sec
,
16 struct buffer_head
*bh
)
23 if (hpfs_sb(s
)->sb_chk
) if (hpfs_stop_cycles(s
, a
, &c1
, &c2
, "hpfs_bplus_lookup")) return -1;
24 if (bp_internal(btree
)) {
25 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
26 if (le32_to_cpu(btree
->u
.internal
[i
].file_secno
) > sec
) {
27 a
= le32_to_cpu(btree
->u
.internal
[i
].down
);
29 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
30 btree
= &anode
->btree
;
33 hpfs_error(s
, "sector %08x not found in internal anode %08x", sec
, a
);
37 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
38 if (le32_to_cpu(btree
->u
.external
[i
].file_secno
) <= sec
&&
39 le32_to_cpu(btree
->u
.external
[i
].file_secno
) + le32_to_cpu(btree
->u
.external
[i
].length
) > sec
) {
40 a
= le32_to_cpu(btree
->u
.external
[i
].disk_secno
) + sec
- le32_to_cpu(btree
->u
.external
[i
].file_secno
);
41 if (hpfs_sb(s
)->sb_chk
) if (hpfs_chk_sectors(s
, a
, 1, "data")) {
46 struct hpfs_inode_info
*hpfs_inode
= hpfs_i(inode
);
47 hpfs_inode
->i_file_sec
= le32_to_cpu(btree
->u
.external
[i
].file_secno
);
48 hpfs_inode
->i_disk_sec
= le32_to_cpu(btree
->u
.external
[i
].disk_secno
);
49 hpfs_inode
->i_n_secs
= le32_to_cpu(btree
->u
.external
[i
].length
);
54 hpfs_error(s
, "sector %08x not found in external anode %08x", sec
, a
);
59 /* Add a sector to tree */
61 secno
hpfs_add_sector_to_btree(struct super_block
*s
, secno node
, int fnod
, unsigned fsecno
)
63 struct bplus_header
*btree
;
64 struct anode
*anode
= NULL
, *ranode
= NULL
;
66 anode_secno a
, na
= -1, ra
, up
= -1;
68 struct buffer_head
*bh
, *bh1
, *bh2
;
73 if (!(fnode
= hpfs_map_fnode(s
, node
, &bh
))) return -1;
74 btree
= &fnode
->btree
;
76 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) return -1;
77 btree
= &anode
->btree
;
81 if ((n
= btree
->n_used_nodes
- 1) < -!!fnod
) {
82 hpfs_error(s
, "anode %08x has no entries", a
);
86 if (bp_internal(btree
)) {
87 a
= le32_to_cpu(btree
->u
.internal
[n
].down
);
88 btree
->u
.internal
[n
].file_secno
= cpu_to_le32(-1);
89 mark_buffer_dirty(bh
);
91 if (hpfs_sb(s
)->sb_chk
)
92 if (hpfs_stop_cycles(s
, a
, &c1
, &c2
, "hpfs_add_sector_to_btree #1")) return -1;
93 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
94 btree
= &anode
->btree
;
98 if (le32_to_cpu(btree
->u
.external
[n
].file_secno
) + le32_to_cpu(btree
->u
.external
[n
].length
) != fsecno
) {
99 hpfs_error(s
, "allocated size %08x, trying to add sector %08x, %cnode %08x",
100 le32_to_cpu(btree
->u
.external
[n
].file_secno
) + le32_to_cpu(btree
->u
.external
[n
].length
), fsecno
,
105 if (hpfs_alloc_if_possible(s
, se
= le32_to_cpu(btree
->u
.external
[n
].disk_secno
) + le32_to_cpu(btree
->u
.external
[n
].length
))) {
106 le32_add_cpu(&btree
->u
.external
[n
].length
, 1);
107 mark_buffer_dirty(bh
);
113 hpfs_error(s
, "empty file %08x, trying to add sector %08x", node
, fsecno
);
117 se
= !fnod
? node
: (node
+ 16384) & ~16383;
119 if (!(se
= hpfs_alloc_sector(s
, se
, 1, fsecno
*ALLOC_M
>ALLOC_FWD_MAX
? ALLOC_FWD_MAX
: fsecno
*ALLOC_M
<ALLOC_FWD_MIN
? ALLOC_FWD_MIN
: fsecno
*ALLOC_M
))) {
123 fs
= n
< 0 ? 0 : le32_to_cpu(btree
->u
.external
[n
].file_secno
) + le32_to_cpu(btree
->u
.external
[n
].length
);
124 if (!btree
->n_free_nodes
) {
125 up
= a
!= node
? le32_to_cpu(anode
->up
) : -1;
126 if (!(anode
= hpfs_alloc_anode(s
, a
, &na
, &bh1
))) {
128 hpfs_free_sectors(s
, se
, 1);
131 if (a
== node
&& fnod
) {
132 anode
->up
= cpu_to_le32(node
);
133 anode
->btree
.flags
|= BP_fnode_parent
;
134 anode
->btree
.n_used_nodes
= btree
->n_used_nodes
;
135 anode
->btree
.first_free
= btree
->first_free
;
136 anode
->btree
.n_free_nodes
= 40 - anode
->btree
.n_used_nodes
;
137 memcpy(&anode
->u
, &btree
->u
, btree
->n_used_nodes
* 12);
138 btree
->flags
|= BP_internal
;
139 btree
->n_free_nodes
= 11;
140 btree
->n_used_nodes
= 1;
141 btree
->first_free
= cpu_to_le16((char *)&(btree
->u
.internal
[1]) - (char *)btree
);
142 btree
->u
.internal
[0].file_secno
= cpu_to_le32(-1);
143 btree
->u
.internal
[0].down
= cpu_to_le32(na
);
144 mark_buffer_dirty(bh
);
145 } else if (!(ranode
= hpfs_alloc_anode(s
, /*a*/0, &ra
, &bh2
))) {
148 hpfs_free_sectors(s
, se
, 1);
149 hpfs_free_sectors(s
, na
, 1);
154 btree
= &anode
->btree
;
156 btree
->n_free_nodes
--; n
= btree
->n_used_nodes
++;
157 le16_add_cpu(&btree
->first_free
, 12);
158 btree
->u
.external
[n
].disk_secno
= cpu_to_le32(se
);
159 btree
->u
.external
[n
].file_secno
= cpu_to_le32(fs
);
160 btree
->u
.external
[n
].length
= cpu_to_le32(1);
161 mark_buffer_dirty(bh
);
163 if ((a
== node
&& fnod
) || na
== -1) return se
;
165 while (up
!= (anode_secno
)-1) {
166 struct anode
*new_anode
;
167 if (hpfs_sb(s
)->sb_chk
)
168 if (hpfs_stop_cycles(s
, up
, &c1
, &c2
, "hpfs_add_sector_to_btree #2")) return -1;
169 if (up
!= node
|| !fnod
) {
170 if (!(anode
= hpfs_map_anode(s
, up
, &bh
))) return -1;
171 btree
= &anode
->btree
;
173 if (!(fnode
= hpfs_map_fnode(s
, up
, &bh
))) return -1;
174 btree
= &fnode
->btree
;
176 if (btree
->n_free_nodes
) {
177 btree
->n_free_nodes
--; n
= btree
->n_used_nodes
++;
178 le16_add_cpu(&btree
->first_free
, 8);
179 btree
->u
.internal
[n
].file_secno
= cpu_to_le32(-1);
180 btree
->u
.internal
[n
].down
= cpu_to_le32(na
);
181 btree
->u
.internal
[n
-1].file_secno
= cpu_to_le32(fs
);
182 mark_buffer_dirty(bh
);
185 hpfs_free_sectors(s
, ra
, 1);
186 if ((anode
= hpfs_map_anode(s
, na
, &bh
))) {
187 anode
->up
= cpu_to_le32(up
);
188 if (up
== node
&& fnod
)
189 anode
->btree
.flags
|= BP_fnode_parent
;
191 anode
->btree
.flags
&= ~BP_fnode_parent
;
192 mark_buffer_dirty(bh
);
197 up
= up
!= node
? le32_to_cpu(anode
->up
) : -1;
198 btree
->u
.internal
[btree
->n_used_nodes
- 1].file_secno
= cpu_to_le32(/*fs*/-1);
199 mark_buffer_dirty(bh
);
202 if ((new_anode
= hpfs_alloc_anode(s
, a
, &na
, &bh
))) {
204 /*anode->up = cpu_to_le32(up != -1 ? up : ra);*/
205 anode
->btree
.flags
|= BP_internal
;
206 anode
->btree
.n_used_nodes
= 1;
207 anode
->btree
.n_free_nodes
= 59;
208 anode
->btree
.first_free
= cpu_to_le16(16);
209 anode
->btree
.u
.internal
[0].down
= cpu_to_le32(a
);
210 anode
->btree
.u
.internal
[0].file_secno
= cpu_to_le32(-1);
211 mark_buffer_dirty(bh
);
213 if ((anode
= hpfs_map_anode(s
, a
, &bh
))) {
214 anode
->up
= cpu_to_le32(na
);
215 mark_buffer_dirty(bh
);
220 if ((anode
= hpfs_map_anode(s
, na
, &bh
))) {
221 anode
->up
= cpu_to_le32(node
);
223 anode
->btree
.flags
|= BP_fnode_parent
;
224 mark_buffer_dirty(bh
);
228 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) {
232 btree
= &anode
->btree
;
234 if (!(fnode
= hpfs_map_fnode(s
, node
, &bh
))) {
238 btree
= &fnode
->btree
;
240 ranode
->up
= cpu_to_le32(node
);
241 memcpy(&ranode
->btree
, btree
, le16_to_cpu(btree
->first_free
));
243 ranode
->btree
.flags
|= BP_fnode_parent
;
244 ranode
->btree
.n_free_nodes
= (bp_internal(&ranode
->btree
) ? 60 : 40) - ranode
->btree
.n_used_nodes
;
245 if (bp_internal(&ranode
->btree
)) for (n
= 0; n
< ranode
->btree
.n_used_nodes
; n
++) {
247 if ((unode
= hpfs_map_anode(s
, le32_to_cpu(ranode
->u
.internal
[n
].down
), &bh1
))) {
248 unode
->up
= cpu_to_le32(ra
);
249 unode
->btree
.flags
&= ~BP_fnode_parent
;
250 mark_buffer_dirty(bh1
);
254 btree
->flags
|= BP_internal
;
255 btree
->n_free_nodes
= fnod
? 10 : 58;
256 btree
->n_used_nodes
= 2;
257 btree
->first_free
= cpu_to_le16((char *)&btree
->u
.internal
[2] - (char *)btree
);
258 btree
->u
.internal
[0].file_secno
= cpu_to_le32(fs
);
259 btree
->u
.internal
[0].down
= cpu_to_le32(ra
);
260 btree
->u
.internal
[1].file_secno
= cpu_to_le32(-1);
261 btree
->u
.internal
[1].down
= cpu_to_le32(na
);
262 mark_buffer_dirty(bh
);
264 mark_buffer_dirty(bh2
);
270 * Remove allocation tree. Recursion would look much nicer but
271 * I want to avoid it because it can cause stack overflow.
274 void hpfs_remove_btree(struct super_block
*s
, struct bplus_header
*btree
)
276 struct bplus_header
*btree1
= btree
;
277 struct anode
*anode
= NULL
;
278 anode_secno ano
= 0, oano
;
279 struct buffer_head
*bh
;
287 while (bp_internal(btree1
)) {
288 ano
= le32_to_cpu(btree1
->u
.internal
[pos
].down
);
289 if (level
) brelse(bh
);
290 if (hpfs_sb(s
)->sb_chk
)
291 if (hpfs_stop_cycles(s
, ano
, &d1
, &d2
, "hpfs_remove_btree #1"))
293 if (!(anode
= hpfs_map_anode(s
, ano
, &bh
))) return;
294 btree1
= &anode
->btree
;
298 for (i
= 0; i
< btree1
->n_used_nodes
; i
++)
299 hpfs_free_sectors(s
, le32_to_cpu(btree1
->u
.external
[i
].disk_secno
), le32_to_cpu(btree1
->u
.external
[i
].length
));
303 if (hpfs_sb(s
)->sb_chk
)
304 if (hpfs_stop_cycles(s
, ano
, &c1
, &c2
, "hpfs_remove_btree #2")) return;
305 hpfs_free_sectors(s
, ano
, 1);
307 ano
= le32_to_cpu(anode
->up
);
309 if (!(anode
= hpfs_map_anode(s
, ano
, &bh
))) return;
310 btree1
= &anode
->btree
;
311 } else btree1
= btree
;
312 for (i
= 0; i
< btree1
->n_used_nodes
; i
++) {
313 if (le32_to_cpu(btree1
->u
.internal
[i
].down
) == oano
) {
314 if ((pos
= i
+ 1) < btree1
->n_used_nodes
)
321 "reference to anode %08x not found in anode %08x "
322 "(probably bad up pointer)",
323 oano
, level
? ano
: -1);
328 /* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
330 static secno
anode_lookup(struct super_block
*s
, anode_secno a
, unsigned sec
)
333 struct buffer_head
*bh
;
334 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
335 return hpfs_bplus_lookup(s
, NULL
, &anode
->btree
, sec
, bh
);
338 int hpfs_ea_read(struct super_block
*s
, secno a
, int ano
, unsigned pos
,
339 unsigned len
, char *buf
)
341 struct buffer_head
*bh
;
347 if ((sec
= anode_lookup(s
, a
, pos
>> 9)) == -1)
349 } else sec
= a
+ (pos
>> 9);
350 if (hpfs_sb(s
)->sb_chk
) if (hpfs_chk_sectors(s
, sec
, 1, "ea #1")) return -1;
351 if (!(data
= hpfs_map_sector(s
, sec
, &bh
, (len
- 1) >> 9)))
353 l
= 0x200 - (pos
& 0x1ff); if (l
> len
) l
= len
;
354 memcpy(buf
, data
+ (pos
& 0x1ff), l
);
356 buf
+= l
; pos
+= l
; len
-= l
;
361 int hpfs_ea_write(struct super_block
*s
, secno a
, int ano
, unsigned pos
,
362 unsigned len
, const char *buf
)
364 struct buffer_head
*bh
;
370 if ((sec
= anode_lookup(s
, a
, pos
>> 9)) == -1)
372 } else sec
= a
+ (pos
>> 9);
373 if (hpfs_sb(s
)->sb_chk
) if (hpfs_chk_sectors(s
, sec
, 1, "ea #2")) return -1;
374 if (!(data
= hpfs_map_sector(s
, sec
, &bh
, (len
- 1) >> 9)))
376 l
= 0x200 - (pos
& 0x1ff); if (l
> len
) l
= len
;
377 memcpy(data
+ (pos
& 0x1ff), buf
, l
);
378 mark_buffer_dirty(bh
);
380 buf
+= l
; pos
+= l
; len
-= l
;
385 void hpfs_ea_remove(struct super_block
*s
, secno a
, int ano
, unsigned len
)
388 struct buffer_head
*bh
;
390 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return;
391 hpfs_remove_btree(s
, &anode
->btree
);
393 hpfs_free_sectors(s
, a
, 1);
394 } else hpfs_free_sectors(s
, a
, (len
+ 511) >> 9);
397 /* Truncate allocation tree. Doesn't join anodes - I hope it doesn't matter */
399 void hpfs_truncate_btree(struct super_block
*s
, secno f
, int fno
, unsigned secs
)
403 struct buffer_head
*bh
;
404 struct bplus_header
*btree
;
405 anode_secno node
= f
;
409 if (!(fnode
= hpfs_map_fnode(s
, f
, &bh
))) return;
410 btree
= &fnode
->btree
;
412 if (!(anode
= hpfs_map_anode(s
, f
, &bh
))) return;
413 btree
= &anode
->btree
;
416 hpfs_remove_btree(s
, btree
);
418 btree
->n_free_nodes
= 8;
419 btree
->n_used_nodes
= 0;
420 btree
->first_free
= cpu_to_le16(8);
421 btree
->flags
&= ~BP_internal
;
422 mark_buffer_dirty(bh
);
423 } else hpfs_free_sectors(s
, f
, 1);
427 while (bp_internal(btree
)) {
428 nodes
= btree
->n_used_nodes
+ btree
->n_free_nodes
;
429 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
430 if (le32_to_cpu(btree
->u
.internal
[i
].file_secno
) >= secs
) goto f
;
432 hpfs_error(s
, "internal btree %08x doesn't end with -1", node
);
435 for (j
= i
+ 1; j
< btree
->n_used_nodes
; j
++)
436 hpfs_ea_remove(s
, le32_to_cpu(btree
->u
.internal
[j
].down
), 1, 0);
437 btree
->n_used_nodes
= i
+ 1;
438 btree
->n_free_nodes
= nodes
- btree
->n_used_nodes
;
439 btree
->first_free
= cpu_to_le16(8 + 8 * btree
->n_used_nodes
);
440 mark_buffer_dirty(bh
);
441 if (btree
->u
.internal
[i
].file_secno
== cpu_to_le32(secs
)) {
445 node
= le32_to_cpu(btree
->u
.internal
[i
].down
);
447 if (hpfs_sb(s
)->sb_chk
)
448 if (hpfs_stop_cycles(s
, node
, &c1
, &c2
, "hpfs_truncate_btree"))
450 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) return;
451 btree
= &anode
->btree
;
453 nodes
= btree
->n_used_nodes
+ btree
->n_free_nodes
;
454 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
455 if (le32_to_cpu(btree
->u
.external
[i
].file_secno
) + le32_to_cpu(btree
->u
.external
[i
].length
) >= secs
) goto ff
;
459 if (secs
<= le32_to_cpu(btree
->u
.external
[i
].file_secno
)) {
460 hpfs_error(s
, "there is an allocation error in file %08x, sector %08x", f
, secs
);
463 else if (le32_to_cpu(btree
->u
.external
[i
].file_secno
) + le32_to_cpu(btree
->u
.external
[i
].length
) > secs
) {
464 hpfs_free_sectors(s
, le32_to_cpu(btree
->u
.external
[i
].disk_secno
) + secs
-
465 le32_to_cpu(btree
->u
.external
[i
].file_secno
), le32_to_cpu(btree
->u
.external
[i
].length
)
466 - secs
+ le32_to_cpu(btree
->u
.external
[i
].file_secno
)); /* I hope gcc optimizes this :-) */
467 btree
->u
.external
[i
].length
= cpu_to_le32(secs
- le32_to_cpu(btree
->u
.external
[i
].file_secno
));
469 for (j
= i
+ 1; j
< btree
->n_used_nodes
; j
++)
470 hpfs_free_sectors(s
, le32_to_cpu(btree
->u
.external
[j
].disk_secno
), le32_to_cpu(btree
->u
.external
[j
].length
));
471 btree
->n_used_nodes
= i
+ 1;
472 btree
->n_free_nodes
= nodes
- btree
->n_used_nodes
;
473 btree
->first_free
= cpu_to_le16(8 + 12 * btree
->n_used_nodes
);
474 mark_buffer_dirty(bh
);
478 /* Remove file or directory and it's eas - note that directory must
479 be empty when this is called. */
481 void hpfs_remove_fnode(struct super_block
*s
, fnode_secno fno
)
483 struct buffer_head
*bh
;
485 struct extended_attribute
*ea
;
486 struct extended_attribute
*ea_end
;
487 if (!(fnode
= hpfs_map_fnode(s
, fno
, &bh
))) return;
488 if (!fnode_is_dir(fnode
)) hpfs_remove_btree(s
, &fnode
->btree
);
489 else hpfs_remove_dtree(s
, le32_to_cpu(fnode
->u
.external
[0].disk_secno
));
490 ea_end
= fnode_end_ea(fnode
);
491 for (ea
= fnode_ea(fnode
); ea
< ea_end
; ea
= next_ea(ea
))
493 hpfs_ea_remove(s
, ea_sec(ea
), ea_in_anode(ea
), ea_len(ea
));
494 hpfs_ea_ext_remove(s
, le32_to_cpu(fnode
->ea_secno
), fnode_in_anode(fnode
), le32_to_cpu(fnode
->ea_size_l
));
496 hpfs_free_sectors(s
, fno
, 1);