2 * linux/fs/hpfs/anode.c
4 * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
6 * handling HPFS anode tree that contains file allocation info
11 /* Find a sector in allocation tree */
13 secno
hpfs_bplus_lookup(struct super_block
*s
, struct inode
*inode
,
14 struct bplus_header
*btree
, unsigned sec
,
15 struct buffer_head
*bh
)
22 if (s
->s_hpfs_chk
) if (hpfs_stop_cycles(s
, a
, &c1
, &c2
, "hpfs_bplus_lookup")) return -1;
23 if (btree
->internal
) {
24 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
25 if (btree
->u
.internal
[i
].file_secno
> sec
) {
26 a
= btree
->u
.internal
[i
].down
;
28 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
29 btree
= &anode
->btree
;
32 hpfs_error(s
, "sector %08x not found in internal anode %08x", sec
, a
);
36 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
37 if (btree
->u
.external
[i
].file_secno
<= sec
&&
38 btree
->u
.external
[i
].file_secno
+ btree
->u
.external
[i
].length
> sec
) {
39 a
= btree
->u
.external
[i
].disk_secno
+ sec
- btree
->u
.external
[i
].file_secno
;
40 if (s
->s_hpfs_chk
) if (hpfs_chk_sectors(s
, a
, 1, "data")) {
45 inode
->i_hpfs_file_sec
= btree
->u
.external
[i
].file_secno
;
46 inode
->i_hpfs_disk_sec
= btree
->u
.external
[i
].disk_secno
;
47 inode
->i_hpfs_n_secs
= btree
->u
.external
[i
].length
;
52 hpfs_error(s
, "sector %08x not found in external anode %08x", sec
, a
);
57 /* Add a sector to tree */
59 secno
hpfs_add_sector_to_btree(struct super_block
*s
, secno node
, int fnod
, unsigned fsecno
)
61 struct bplus_header
*btree
;
62 struct anode
*anode
= NULL
, *ranode
= NULL
;
64 anode_secno a
, na
= -1, ra
, up
= -1;
66 struct buffer_head
*bh
, *bh1
, *bh2
;
71 if (!(fnode
= hpfs_map_fnode(s
, node
, &bh
))) return -1;
72 btree
= &fnode
->btree
;
74 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) return -1;
75 btree
= &anode
->btree
;
79 if ((n
= btree
->n_used_nodes
- 1) < -!!fnod
) {
80 hpfs_error(s
, "anode %08x has no entries", a
);
84 if (btree
->internal
) {
85 a
= btree
->u
.internal
[n
].down
;
86 btree
->u
.internal
[n
].file_secno
= -1;
87 mark_buffer_dirty(bh
, 1);
90 if (hpfs_stop_cycles(s
, a
, &c1
, &c2
, "hpfs_add_sector_to_btree #1")) return -1;
91 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
92 btree
= &anode
->btree
;
96 if (btree
->u
.external
[n
].file_secno
+ btree
->u
.external
[n
].length
!= fsecno
) {
97 hpfs_error(s
, "allocated size %08x, trying to add sector %08x, %cnode %08x",
98 btree
->u
.external
[n
].file_secno
+ btree
->u
.external
[n
].length
, fsecno
,
103 if (hpfs_alloc_if_possible(s
, se
= btree
->u
.external
[n
].disk_secno
+ btree
->u
.external
[n
].length
)) {
104 btree
->u
.external
[n
].length
++;
105 mark_buffer_dirty(bh
, 1);
111 hpfs_error(s
, "empty file %08x, trying to add sector %08x", node
, fsecno
);
117 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
, 1))) {
121 fs
= n
< 0 ? 0 : btree
->u
.external
[n
].file_secno
+ btree
->u
.external
[n
].length
;
122 if (!btree
->n_free_nodes
) {
123 up
= a
!= node
? anode
->up
: -1;
124 if (!(anode
= hpfs_alloc_anode(s
, a
, &na
, &bh1
))) {
126 hpfs_free_sectors(s
, se
, 1);
129 if (a
== node
&& fnod
) {
131 anode
->btree
.fnode_parent
= 1;
132 anode
->btree
.n_used_nodes
= btree
->n_used_nodes
;
133 anode
->btree
.first_free
= btree
->first_free
;
134 anode
->btree
.n_free_nodes
= 40 - anode
->btree
.n_used_nodes
;
135 memcpy(&anode
->u
, &btree
->u
, btree
->n_used_nodes
* 12);
137 btree
->n_free_nodes
= 11;
138 btree
->n_used_nodes
= 1;
139 btree
->first_free
= (char *)&(btree
->u
.internal
[1]) - (char *)btree
;
140 btree
->u
.internal
[0].file_secno
= -1;
141 btree
->u
.internal
[0].down
= na
;
142 mark_buffer_dirty(bh
, 1);
143 } else if (!(ranode
= hpfs_alloc_anode(s
, /*a*/0, &ra
, &bh2
))) {
146 hpfs_free_sectors(s
, se
, 1);
147 hpfs_free_sectors(s
, na
, 1);
152 btree
= &anode
->btree
;
154 btree
->n_free_nodes
--; n
= btree
->n_used_nodes
++;
155 btree
->first_free
+= 12;
156 btree
->u
.external
[n
].disk_secno
= se
;
157 btree
->u
.external
[n
].file_secno
= fs
;
158 btree
->u
.external
[n
].length
= 1;
159 mark_buffer_dirty(bh
, 1);
161 if ((a
== node
&& fnod
) || na
== -1) return se
;
165 if (hpfs_stop_cycles(s
, up
, &c1
, &c2
, "hpfs_add_sector_to_btree #2")) return -1;
166 if (up
!= node
|| !fnod
) {
167 if (!(anode
= hpfs_map_anode(s
, up
, &bh
))) return -1;
168 btree
= &anode
->btree
;
170 if (!(fnode
= hpfs_map_fnode(s
, up
, &bh
))) return -1;
171 btree
= &fnode
->btree
;
173 if (btree
->n_free_nodes
) {
174 btree
->n_free_nodes
--; n
= btree
->n_used_nodes
++;
175 btree
->first_free
+= 8;
176 btree
->u
.internal
[n
].file_secno
= -1;
177 btree
->u
.internal
[n
].down
= na
;
178 btree
->u
.internal
[n
-1].file_secno
= fs
;
179 mark_buffer_dirty(bh
, 1);
182 hpfs_free_sectors(s
, ra
, 1);
183 if ((anode
= hpfs_map_anode(s
, na
, &bh
))) {
185 anode
->btree
.fnode_parent
= up
== node
&& fnod
;
186 mark_buffer_dirty(bh
, 1);
191 up
= up
!= node
? anode
->up
: -1;
192 btree
->u
.internal
[btree
->n_used_nodes
- 1].file_secno
= /*fs*/-1;
193 if (up
== -1) anode
->up
= ra
;
194 mark_buffer_dirty(bh
, 1);
197 if ((anode
= hpfs_alloc_anode(s
, a
, &na
, &bh
))) {
198 /*anode->up = up != -1 ? up : ra;*/
199 anode
->btree
.internal
= 1;
200 anode
->btree
.n_used_nodes
= 1;
201 anode
->btree
.n_free_nodes
= 59;
202 anode
->btree
.first_free
= 16;
203 anode
->btree
.u
.internal
[0].down
= a
;
204 anode
->btree
.u
.internal
[0].file_secno
= -1;
205 mark_buffer_dirty(bh
, 1);
207 if ((anode
= hpfs_map_anode(s
, a
, &bh
))) {
209 mark_buffer_dirty(bh
, 1);
214 if ((anode
= hpfs_map_anode(s
, na
, &bh
))) {
216 if (fnod
) anode
->btree
.fnode_parent
= 1;
217 mark_buffer_dirty(bh
, 1);
221 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) {
225 btree
= &anode
->btree
;
227 if (!(fnode
= hpfs_map_fnode(s
, node
, &bh
))) {
231 btree
= &fnode
->btree
;
234 memcpy(&ranode
->btree
, btree
, btree
->first_free
);
235 if (fnod
) ranode
->btree
.fnode_parent
= 1;
236 ranode
->btree
.n_free_nodes
= (ranode
->btree
.internal
? 60 : 40) - ranode
->btree
.n_used_nodes
;
237 if (ranode
->btree
.internal
) for (n
= 0; n
< ranode
->btree
.n_used_nodes
; n
++) {
239 if ((unode
= hpfs_map_anode(s
, ranode
->u
.internal
[n
].down
, &bh1
))) {
241 unode
->btree
.fnode_parent
= 0;
242 mark_buffer_dirty(bh1
, 1);
247 btree
->n_free_nodes
= fnod
? 10 : 58;
248 btree
->n_used_nodes
= 2;
249 btree
->first_free
= (char *)&btree
->u
.internal
[2] - (char *)btree
;
250 btree
->u
.internal
[0].file_secno
= fs
;
251 btree
->u
.internal
[0].down
= ra
;
252 btree
->u
.internal
[1].file_secno
= -1;
253 btree
->u
.internal
[1].down
= na
;
254 mark_buffer_dirty(bh
, 1);
256 mark_buffer_dirty(bh2
, 1);
262 * Remove allocation tree. Recursion would look much nicer but
263 * I want to avoid it because it can cause stack overflow.
266 void hpfs_remove_btree(struct super_block
*s
, struct bplus_header
*btree
)
268 struct bplus_header
*btree1
= btree
;
269 struct anode
*anode
= NULL
;
270 anode_secno ano
= 0, oano
;
271 struct buffer_head
*bh
;
279 while (btree1
->internal
) {
280 ano
= btree1
->u
.internal
[pos
].down
;
281 if (level
) brelse(bh
);
283 if (hpfs_stop_cycles(s
, ano
, &d1
, &d2
, "hpfs_remove_btree #1"))
285 anode
= hpfs_map_anode(s
, ano
, &bh
);
286 btree1
= &anode
->btree
;
290 for (i
= 0; i
< btree1
->n_used_nodes
; i
++)
291 hpfs_free_sectors(s
, btree1
->u
.external
[i
].disk_secno
, btree1
->u
.external
[i
].length
);
295 if (hpfs_stop_cycles(s
, ano
, &c1
, &c2
, "hpfs_remove_btree #2")) return;
296 hpfs_free_sectors(s
, ano
, 1);
301 anode
= hpfs_map_anode(s
, ano
, &bh
);
302 btree1
= &anode
->btree
;
303 } else btree1
= btree
;
304 for (i
= 0; i
< btree1
->n_used_nodes
; i
++) {
305 if (btree1
->u
.internal
[i
].down
== oano
) {
306 if ((pos
= i
+ 1) < btree1
->n_used_nodes
)
313 "reference to anode %08x not found in anode %08x "
314 "(probably bad up pointer)",
315 oano
, level
? ano
: -1);
320 /* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
322 static secno
anode_lookup(struct super_block
*s
, anode_secno a
, unsigned sec
)
325 struct buffer_head
*bh
;
326 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return -1;
327 return hpfs_bplus_lookup(s
, NULL
, &anode
->btree
, sec
, bh
);
330 int hpfs_ea_read(struct super_block
*s
, secno a
, int ano
, unsigned pos
,
331 unsigned len
, char *buf
)
333 struct buffer_head
*bh
;
339 if ((sec
= anode_lookup(s
, a
, pos
>> 9)) == -1)
341 } else sec
= a
+ (pos
>> 9);
342 if (s
->s_hpfs_chk
) if (hpfs_chk_sectors(s
, sec
, 1, "ea #1")) return -1;
343 if (!(data
= hpfs_map_sector(s
, sec
, &bh
, (len
- 1) >> 9)))
345 l
= 0x200 - (pos
& 0x1ff); if (l
> len
) l
= len
;
346 memcpy(buf
, data
+ (pos
& 0x1ff), l
);
348 buf
+= l
; pos
+= l
; len
-= l
;
353 int hpfs_ea_write(struct super_block
*s
, secno a
, int ano
, unsigned pos
,
354 unsigned len
, char *buf
)
356 struct buffer_head
*bh
;
362 if ((sec
= anode_lookup(s
, a
, pos
>> 9)) == -1)
364 } else sec
= a
+ (pos
>> 9);
365 if (s
->s_hpfs_chk
) if (hpfs_chk_sectors(s
, sec
, 1, "ea #2")) return -1;
366 if (!(data
= hpfs_map_sector(s
, sec
, &bh
, (len
- 1) >> 9)))
368 l
= 0x200 - (pos
& 0x1ff); if (l
> len
) l
= len
;
369 memcpy(data
+ (pos
& 0x1ff), buf
, l
);
370 mark_buffer_dirty(bh
, 1);
372 buf
+= l
; pos
+= l
; len
-= l
;
377 void hpfs_ea_remove(struct super_block
*s
, secno a
, int ano
, unsigned len
)
380 struct buffer_head
*bh
;
382 if (!(anode
= hpfs_map_anode(s
, a
, &bh
))) return;
383 hpfs_remove_btree(s
, &anode
->btree
);
385 hpfs_free_sectors(s
, a
, 1);
386 } else hpfs_free_sectors(s
, a
, (len
+ 511) >> 9);
389 /* Truncate allocation tree. Doesn't join anodes - I hope it doesn't matter */
391 void hpfs_truncate_btree(struct super_block
*s
, secno f
, int fno
, unsigned secs
)
395 struct buffer_head
*bh
;
396 struct bplus_header
*btree
;
397 anode_secno node
= f
;
401 if (!(fnode
= hpfs_map_fnode(s
, f
, &bh
))) return;
402 btree
= &fnode
->btree
;
404 if (!(anode
= hpfs_map_anode(s
, f
, &bh
))) return;
405 btree
= &anode
->btree
;
408 hpfs_remove_btree(s
, btree
);
410 btree
->n_free_nodes
= 8;
411 btree
->n_used_nodes
= 0;
412 btree
->first_free
= 8;
414 mark_buffer_dirty(bh
, 1);
415 } else hpfs_free_sectors(s
, f
, 1);
419 while (btree
->internal
) {
420 nodes
= btree
->n_used_nodes
+ btree
->n_free_nodes
;
421 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
422 if (btree
->u
.internal
[i
].file_secno
>= secs
) goto f
;
424 hpfs_error(s
, "internal btree %08x doesn't end with -1", node
);
427 for (j
= i
+ 1; j
< btree
->n_used_nodes
; j
++)
428 hpfs_ea_remove(s
, btree
->u
.internal
[j
].down
, 1, 0);
429 btree
->n_used_nodes
= i
+ 1;
430 btree
->n_free_nodes
= nodes
- btree
->n_used_nodes
;
431 btree
->first_free
= 8 + 8 * btree
->n_used_nodes
;
432 mark_buffer_dirty(bh
, 1);
433 if (btree
->u
.internal
[i
].file_secno
== secs
) {
437 node
= btree
->u
.internal
[i
].down
;
440 if (hpfs_stop_cycles(s
, node
, &c1
, &c2
, "hpfs_truncate_btree"))
442 if (!(anode
= hpfs_map_anode(s
, node
, &bh
))) return;
443 btree
= &anode
->btree
;
445 nodes
= btree
->n_used_nodes
+ btree
->n_free_nodes
;
446 for (i
= 0; i
< btree
->n_used_nodes
; i
++)
447 if (btree
->u
.external
[i
].file_secno
+ btree
->u
.external
[i
].length
>= secs
) goto ff
;
451 if (secs
<= btree
->u
.external
[i
].file_secno
) {
452 hpfs_error(s
, "there is an allocation error in file %08x, sector %08x", f
, secs
);
455 else if (btree
->u
.external
[i
].file_secno
+ btree
->u
.external
[i
].length
> secs
) {
456 hpfs_free_sectors(s
, btree
->u
.external
[i
].disk_secno
+ secs
-
457 btree
->u
.external
[i
].file_secno
, btree
->u
.external
[i
].length
458 - secs
+ btree
->u
.external
[i
].file_secno
); /* I hope gcc optimizes this :-) */
459 btree
->u
.external
[i
].length
= secs
- btree
->u
.external
[i
].file_secno
;
461 for (j
= i
+ 1; j
< btree
->n_used_nodes
; j
++)
462 hpfs_free_sectors(s
, btree
->u
.external
[j
].disk_secno
, btree
->u
.external
[j
].length
);
463 btree
->n_used_nodes
= i
+ 1;
464 btree
->n_free_nodes
= nodes
- btree
->n_used_nodes
;
465 btree
->first_free
= 8 + 12 * btree
->n_used_nodes
;
466 mark_buffer_dirty(bh
, 1);
470 /* Remove file or directory and it's eas - note that directory must
471 be empty when this is called. */
473 void hpfs_remove_fnode(struct super_block
*s
, fnode_secno fno
)
475 struct buffer_head
*bh
;
477 struct extended_attribute
*ea
;
478 struct extended_attribute
*ea_end
;
479 if (!(fnode
= hpfs_map_fnode(s
, fno
, &bh
))) return;
480 if (!fnode
->dirflag
) hpfs_remove_btree(s
, &fnode
->btree
);
481 else hpfs_remove_dtree(s
, fnode
->u
.external
[0].disk_secno
);
482 ea_end
= fnode_end_ea(fnode
);
483 for (ea
= fnode_ea(fnode
); ea
< ea_end
; ea
= next_ea(ea
))
485 hpfs_ea_remove(s
, ea_sec(ea
), ea
->anode
, ea_len(ea
));
486 hpfs_ea_ext_remove(s
, fnode
->ea_secno
, fnode
->ea_anode
, fnode
->ea_size_l
);
488 hpfs_free_sectors(s
, fno
, 1);