Fix B-tree search in BFS, especially in presence of non-ASCII
characters. * grub-core/fs/bfs.c (bfs_strcmp): New function. (find_in_b_tree): Use standard bsearch + btree algorithm.
This commit is contained in:
parent
5700603549
commit
aa01499d05
2 changed files with 70 additions and 13 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2012-05-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Fix B-tree search in BFS, especially in presence of non-ASCII
|
||||||
|
characters.
|
||||||
|
|
||||||
|
* grub-core/fs/bfs.c (bfs_strcmp): New function.
|
||||||
|
(find_in_b_tree): Use standard bsearch + btree algorithm.
|
||||||
|
|
||||||
2012-05-03 Vladimir Serbinenko <phcoder@gmail.com>
|
2012-05-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* util/grub-fstest.c (cmd_cmp): Avoid comparing devices, pipes
|
* util/grub-fstest.c (cmd_cmp): Avoid comparing devices, pipes
|
||||||
|
|
|
@ -506,6 +506,25 @@ iterate_in_b_tree (grub_disk_t disk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bfs_strcmp (const char *a, const char *b, grub_size_t alen)
|
||||||
|
{
|
||||||
|
while (*b && alen)
|
||||||
|
{
|
||||||
|
if (*a != *b)
|
||||||
|
break;
|
||||||
|
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
alen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alen)
|
||||||
|
return - (int) (grub_uint8_t) *b;
|
||||||
|
|
||||||
|
return (int) (grub_uint8_t) *a - (int) (grub_uint8_t) *b;
|
||||||
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
find_in_b_tree (grub_disk_t disk,
|
find_in_b_tree (grub_disk_t disk,
|
||||||
const struct grub_bfs_superblock *sb,
|
const struct grub_bfs_superblock *sb,
|
||||||
|
@ -537,7 +556,6 @@ find_in_b_tree (grub_disk_t disk,
|
||||||
grub_uint16_t keylen_idx[grub_bfs_to_cpu_treehead (node.count_keys)];
|
grub_uint16_t keylen_idx[grub_bfs_to_cpu_treehead (node.count_keys)];
|
||||||
grub_uint64_t key_values[grub_bfs_to_cpu_treehead (node.count_keys)];
|
grub_uint64_t key_values[grub_bfs_to_cpu_treehead (node.count_keys)];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
grub_uint16_t start = 0, end = 0;
|
|
||||||
err =
|
err =
|
||||||
read_bfs_file (disk, sb, ino, node_off + sizeof (node), key_data,
|
read_bfs_file (disk, sb, ino, node_off + sizeof (node), key_data,
|
||||||
grub_bfs_to_cpu_treehead (node.total_key_len), 0);
|
grub_bfs_to_cpu_treehead (node.total_key_len), 0);
|
||||||
|
@ -566,31 +584,62 @@ find_in_b_tree (grub_disk_t disk,
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
for (i = 0; i < grub_bfs_to_cpu_treehead (node.count_keys); i++)
|
int lg, j;
|
||||||
|
|
||||||
|
for (lg = 0; grub_bfs_to_cpu_treehead (node.count_keys) >> lg; lg++);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (j = lg - 1; j >= 0; j--)
|
||||||
{
|
{
|
||||||
int cmp;
|
int cmp;
|
||||||
char c;
|
grub_uint16_t start = 0, end = 0;
|
||||||
start = end;
|
if ((i | (1 << j)) >= grub_bfs_to_cpu_treehead (node.count_keys))
|
||||||
end = grub_bfs_to_cpu16 (keylen_idx[i]);
|
continue;
|
||||||
|
start = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j)) - 1]);
|
||||||
|
end = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j))]);
|
||||||
if (grub_bfs_to_cpu_treehead (node.total_key_len) <= end)
|
if (grub_bfs_to_cpu_treehead (node.total_key_len) <= end)
|
||||||
end = grub_bfs_to_cpu_treehead (node.total_key_len);
|
end = grub_bfs_to_cpu_treehead (node.total_key_len);
|
||||||
c = key_data[end];
|
cmp = bfs_strcmp (key_data + start, name, end - start);
|
||||||
key_data[end] = 0;
|
|
||||||
cmp = grub_strcmp (key_data + start, name);
|
|
||||||
key_data[end] = c;
|
|
||||||
if (cmp == 0 && level == 0)
|
if (cmp == 0 && level == 0)
|
||||||
{
|
{
|
||||||
*res = grub_bfs_to_cpu64 (key_values[i]);
|
*res = grub_bfs_to_cpu64 (key_values[i | (1 << j)]);
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
if (cmp < 0)
|
||||||
|
i |= (1 << j);
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
grub_uint16_t end = 0;
|
||||||
|
int cmp;
|
||||||
|
end = grub_bfs_to_cpu16 (keylen_idx[0]);
|
||||||
|
if (grub_bfs_to_cpu_treehead (node.total_key_len) <= end)
|
||||||
|
end = grub_bfs_to_cpu_treehead (node.total_key_len);
|
||||||
|
cmp = bfs_strcmp (key_data, name, end);
|
||||||
|
if (cmp == 0 && level == 0)
|
||||||
|
{
|
||||||
|
*res = grub_bfs_to_cpu64 (key_values[0]);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
if (cmp >= 0 && level != 0)
|
if (cmp >= 0 && level != 0)
|
||||||
{
|
{
|
||||||
node_off = grub_bfs_to_cpu64 (key_values[i]);
|
node_off = grub_bfs_to_cpu64 (key_values[0]);
|
||||||
break;
|
level--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (level != 0
|
||||||
|
&& grub_bfs_to_cpu_treehead (node.count_keys) >= 2)
|
||||||
|
{
|
||||||
|
node_off = grub_bfs_to_cpu64 (key_values[1]);
|
||||||
|
level--;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < grub_bfs_to_cpu_treehead (node.count_keys))
|
else if (level != 0
|
||||||
|
&& i + 1 < grub_bfs_to_cpu_treehead (node.count_keys))
|
||||||
{
|
{
|
||||||
|
node_off = grub_bfs_to_cpu64 (key_values[i + 1]);
|
||||||
level--;
|
level--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue