2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation, Inc.
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 3 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
23
#include <parted/parted.h>
24
#include <parted/endian.h>
25
#include <parted/debug.h>
30
# define _(String) dgettext (PACKAGE, String)
32
# define _(String) (String)
33
#endif /* ENABLE_NLS */
40
/* - if a < b, 0 if a == b, + if a > b */
41
/* Comparaison is done in the following order : */
42
/* CNID, then fork type, then start block */
43
/* Note that HFS implementation in linux has a bug */
44
/* in this function */
46
hfs_extent_key_cmp(HfsPrivateGenericKey* a, HfsPrivateGenericKey* b)
48
HfsExtentKey* key1 = (HfsExtentKey*) a;
49
HfsExtentKey* key2 = (HfsExtentKey*) b;
51
/* do NOT use a substraction, because */
52
/* 0xFFFFFFFF - 1 = 0xFFFFFFFE so this */
53
/* would return -2, despite the fact */
54
/* 0xFFFFFFFF > 1 !!! (this is the 2.4 bug) */
55
if (key1->file_ID != key2->file_ID)
56
return PED_BE32_TO_CPU(key1->file_ID) <
57
PED_BE32_TO_CPU(key2->file_ID) ?
60
if (key1->type != key2->type)
61
return (int)(key1->type - key2->type);
63
if (key1->start == key2->start)
65
/* the whole thing wont work with 16 bits ints */
67
return (int)( PED_BE16_TO_CPU(key1->start) -
68
PED_BE16_TO_CPU(key2->start) );
71
/* do a B-Tree lookup */
72
/* read the first record immediatly inferior or egal to the given key */
73
/* return 0 on error */
74
/* record_out _must_ be large enough to receive record_size bytes */
75
/* WARNING : the compare function called only handle Extents BTree */
76
/* so modify this function if you want to do lookup in */
77
/* other BTrees has well */
79
hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
80
void *record_out, unsigned int record_size,
81
HfsCPrivateLeafRec* record_ref)
83
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
84
HfsHeaderRecord* header;
85
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
86
HfsPrivateGenericKey* record_key = NULL;
87
unsigned int node_number, record_number;
90
/* Read the header node */
91
if (!hfs_file_read_sector(b_tree_file, node, 0))
93
header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *)
94
(node+(PED_SECTOR_SIZE_DEFAULT-2))))));
96
/* Get the node number of the root */
97
node_number = PED_BE32_TO_CPU(header->root_node);
101
/* Read the root node */
102
if (!hfs_file_read_sector(b_tree_file, node, node_number))
105
/* Follow the white rabbit */
107
record_number = PED_BE16_TO_CPU (desc->rec_nb);
108
for (i = record_number; i; i--) {
109
record_key = (HfsPrivateGenericKey*)
110
(node + PED_BE16_TO_CPU(*((uint16_t *)
111
(node+(PED_SECTOR_SIZE_DEFAULT - 2*i)))));
112
/* check for obvious error in FS */
113
if (((uint8_t*)record_key - node < HFS_FIRST_REC)
114
|| ((uint8_t*)record_key - node
115
>= PED_SECTOR_SIZE_DEFAULT
116
- 2 * (signed)(record_number+1))) {
117
ped_exception_throw (
119
PED_EXCEPTION_CANCEL,
120
_("The file system contains errors."));
123
if (hfs_extent_key_cmp(record_key, key) <= 0)
127
if (desc->type == HFS_IDX_NODE) {
130
skip = (1 + record_key->key_length + 1) & ~1;
131
node_number = PED_BE32_TO_CPU (*((uint32_t *)
132
(((uint8_t *) record_key) + skip)));
133
if (!hfs_file_read_sector(b_tree_file, node,
140
/* copy the result if needed */
142
memcpy (record_out, record_key, record_size);
144
/* send record reference if needed */
146
record_ref->node_size = 1; /* in sectors */
147
record_ref->node_number = node_number;
148
record_ref->record_pos = (uint8_t*)record_key - node;
149
record_ref->record_number = i;
156
/* free the bad blocks linked list */
158
hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first)
160
HfsPrivateLinkExtent* next;
169
/* This function reads bad blocks extents in the extents file
170
and store it in f.s. specific data of fs */
172
hfs_read_bad_blocks (const PedFileSystem *fs)
174
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
177
if (priv_data->bad_blocks_loaded)
181
uint8_t record[sizeof (HfsExtentKey)
182
+ sizeof (HfsExtDataRec)];
184
HfsExtentKey* ret_key = (HfsExtentKey*) record;
185
HfsExtDescriptor* ret_cache = (HfsExtDescriptor*)
186
(record + sizeof (HfsExtentKey));
187
unsigned int block, last_start, first_pass = 1;
189
search.key_length = sizeof (HfsExtentKey) - 1;
190
search.type = HFS_DATA_FORK;
191
search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
193
last_start = -1; block = 0;
197
search.start = PED_CPU_TO_BE16 (block);
198
if (!hfs_btree_search (priv_data->extent_file,
199
(HfsPrivateGenericKey*) &search,
200
record, sizeof (record), NULL)
201
|| ret_key->file_ID != search.file_ID
202
|| ret_key->type != search.type) {
208
if (PED_BE16_TO_CPU (ret_key->start) == last_start)
211
last_start = PED_BE16_TO_CPU (ret_key->start);
212
for (i = 0; i < HFS_EXT_NB; i++) {
213
if (ret_cache[i].block_count) {
214
HfsPrivateLinkExtent* new_xt =
215
(HfsPrivateLinkExtent*) ped_malloc (
216
sizeof (HfsPrivateLinkExtent));
219
new_xt->next = priv_data->bad_blocks_xtent_list;
220
memcpy(&(new_xt->extent), ret_cache+i,
221
sizeof (HfsExtDescriptor));
222
priv_data->bad_blocks_xtent_list = new_xt;
223
priv_data->bad_blocks_xtent_nb++;
224
block += PED_BE16_TO_CPU (
225
ret_cache[i].block_count);
231
priv_data->bad_blocks_loaded = 1;
234
errbb: hfs_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
235
priv_data->bad_blocks_xtent_list=NULL;
236
priv_data->bad_blocks_xtent_nb=0;
240
/* This function check if fblock is a bad block */
242
hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
244
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
246
HfsPrivateLinkExtent* walk;
248
for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) {
249
/* Won't compile without the strange cast ! gcc bug ? */
250
/* or maybe C subtilties... */
251
if ((fblock >= PED_BE16_TO_CPU (walk->extent.start_block)) &&
252
(fblock < (unsigned int) (PED_BE16_TO_CPU (
253
walk->extent.start_block)
255
walk->extent.block_count))))
262
/* This function returns the first sector of the last free block of an
263
HFS volume we can get after a hfs_pack_free_space_from_block call */
264
/* On error this function returns 0 */
266
hfs_get_empty_end (const PedFileSystem *fs)
268
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
270
HfsMasterDirectoryBlock* mdb = priv_data->mdb;
271
unsigned int block, last_bad, end_free_blocks;
273
/* find the next block to the last bad block of the volume */
274
if (!hfs_read_bad_blocks (fs))
277
HfsPrivateLinkExtent* l;
279
for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
280
if ((unsigned int) PED_BE16_TO_CPU (l->extent.start_block)
281
+ PED_BE16_TO_CPU (l->extent.block_count) > last_bad)
282
last_bad = PED_BE16_TO_CPU (l->extent.start_block)
283
+ PED_BE16_TO_CPU (l->extent.block_count);
286
/* Count the free blocks from last_bad to the end of the volume */
288
for (block = last_bad;
289
block < PED_BE16_TO_CPU (mdb->total_blocks);
291
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
295
/* Calculate the block that will by the first free at the
297
block = PED_BE16_TO_CPU (mdb->total_blocks) - end_free_blocks;
299
return (PedSector) PED_BE16_TO_CPU (mdb->start_block)
300
+ (PedSector) block * (PED_BE32_TO_CPU (mdb->block_size)
301
/ PED_SECTOR_SIZE_DEFAULT);
304
/* return the block which should be used to pack data to have at
305
least free fblock blocks at the end of the volume */
307
hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
309
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
313
for (block = PED_BE16_TO_CPU (priv_data->mdb->total_blocks) - 1;
316
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
320
while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
322
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
328
#endif /* !DISCOVER_ONLY */