1 /* bfs.c - The Bee File System. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 Based on the book "Practical File System Design by Dominic Giampaolo
21 with corrections and completitions based on Haiku code.
25 #include <grub/file.h>
27 #include <grub/misc.h>
28 #include <grub/disk.h>
30 #include <grub/types.h>
31 #include <grub/i18n.h>
33 GRUB_MOD_LICENSE ("GPLv3+");
43 #define grub_bfs_to_cpu16 grub_le_to_cpu16
44 #define grub_bfs_to_cpu32 grub_le_to_cpu32
45 #define grub_bfs_to_cpu64 grub_le_to_cpu64
46 #define grub_cpu_to_bfs32_compile_time grub_cpu_to_le32_compile_time
49 #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu32
51 #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu16
55 #define SUPER_BLOCK_MAGIC1 0x41465331
57 #define SUPER_BLOCK_MAGIC1 0x42465331
59 #define SUPER_BLOCK_MAGIC2 0xdd121031
60 #define SUPER_BLOCK_MAGIC3 0x15b6830e
61 #define POINTER_INVALID 0xffffffffffffffffULL
63 #define ATTR_TYPE 0160000
64 #define ATTR_REG 0100000
65 #define ATTR_DIR 0040000
66 #define ATTR_LNK 0120000
68 #define DOUBLE_INDIRECT_SHIFT 2
70 #define LOG_EXTENT_SIZE 3
71 struct grub_bfs_extent
78 struct grub_bfs_superblock
82 grub_uint32_t unused1
;
84 grub_uint32_t log2_bsize
;
85 grub_uint8_t unused
[20];
87 grub_uint32_t unused2
;
88 grub_uint32_t log2_ag_size
;
89 grub_uint8_t unused3
[32];
91 struct grub_bfs_extent root_dir
;
96 grub_uint8_t unused
[20];
100 grub_uint8_t unused2
[12];
102 grub_uint8_t unused2
[8];
105 grub_uint8_t unused3
[8];
106 struct grub_bfs_extent attr
;
107 grub_uint8_t unused4
[12];
113 struct grub_bfs_extent direct
[12];
114 grub_uint64_t max_direct_range
;
115 struct grub_bfs_extent indirect
;
116 grub_uint64_t max_indirect_range
;
117 struct grub_bfs_extent double_indirect
;
118 grub_uint64_t max_double_indirect_range
;
120 grub_uint32_t pad
[4];
122 char inplace_link
[144];
124 grub_uint8_t small_data
[0];
132 struct grub_bfs_small_data_element_header
135 grub_uint16_t name_len
;
136 grub_uint16_t value_len
;
139 struct grub_bfs_btree_header
145 grub_uint32_t node_size
;
146 grub_uint32_t unused
;
148 grub_uint32_t node_size
;
150 grub_uint32_t unused
;
153 grub_uint32_t unused2
[2];
156 struct grub_bfs_btree_node
158 grub_uint64_t unused
;
160 grub_uint64_t overflow
;
162 grub_uint32_t count_keys
;
163 grub_uint32_t total_key_len
;
165 grub_uint16_t count_keys
;
166 grub_uint16_t total_key_len
;
172 struct grub_bfs_superblock sb
;
173 struct grub_bfs_inode ino
;
176 /* Context for grub_bfs_dir. */
177 struct grub_bfs_dir_ctx
179 grub_device_t device
;
180 grub_fs_dir_hook_t hook
;
182 struct grub_bfs_superblock sb
;
186 read_extent (grub_disk_t disk
,
187 const struct grub_bfs_superblock
*sb
,
188 const struct grub_bfs_extent
*in
,
189 grub_off_t off
, grub_off_t byteoff
, void *buf
, grub_size_t len
)
192 return grub_disk_read (disk
, ((grub_bfs_to_cpu32 (in
->ag
)
193 << (grub_bfs_to_cpu32 (sb
->log2_ag_size
)
194 - GRUB_DISK_SECTOR_BITS
))
195 + ((grub_bfs_to_cpu16 (in
->start
) + off
)
196 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
197 - GRUB_DISK_SECTOR_BITS
))),
200 return grub_disk_read (disk
, (((grub_bfs_to_cpu32 (in
->ag
)
201 << grub_bfs_to_cpu32 (sb
->log2_ag_size
))
202 + grub_bfs_to_cpu16 (in
->start
) + off
)
203 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
204 - GRUB_DISK_SECTOR_BITS
)),
210 #define RANGE_SHIFT grub_bfs_to_cpu32 (sb->log2_bsize)
212 #define RANGE_SHIFT 0
216 read_bfs_file (grub_disk_t disk
,
217 const struct grub_bfs_superblock
*sb
,
218 const struct grub_bfs_inode
*ino
,
219 grub_off_t off
, void *buf
, grub_size_t len
,
220 grub_disk_read_hook_t read_hook
, void *read_hook_data
)
223 return GRUB_ERR_NONE
;
225 if (off
+ len
> grub_bfs_to_cpu64 (ino
->size
))
226 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
227 N_("attempt to read past the end of file"));
229 if (off
< (grub_bfs_to_cpu64 (ino
->max_direct_range
) << RANGE_SHIFT
))
232 grub_uint64_t pos
= 0;
233 for (i
= 0; i
< ARRAY_SIZE (ino
->direct
); i
++)
235 grub_uint64_t newpos
;
236 newpos
= pos
+ (((grub_uint64_t
) grub_bfs_to_cpu16 (ino
->direct
[i
].len
))
237 << grub_bfs_to_cpu32 (sb
->log2_bsize
));
240 grub_size_t read_size
;
242 read_size
= newpos
- off
;
245 disk
->read_hook
= read_hook
;
246 disk
->read_hook_data
= read_hook_data
;
247 err
= read_extent (disk
, sb
, &ino
->direct
[i
], 0, off
- pos
,
254 buf
= (char *) buf
+ read_size
;
256 return GRUB_ERR_NONE
;
262 if (off
< (grub_bfs_to_cpu64 (ino
->max_direct_range
) << RANGE_SHIFT
))
263 return grub_error (GRUB_ERR_BAD_FS
, "incorrect direct blocks");
265 if (off
< (grub_bfs_to_cpu64 (ino
->max_indirect_range
) << RANGE_SHIFT
))
268 struct grub_bfs_extent
*entries
;
269 grub_size_t nentries
;
271 grub_uint64_t pos
= (grub_bfs_to_cpu64 (ino
->max_direct_range
)
273 nentries
= (((grub_size_t
) grub_bfs_to_cpu16 (ino
->indirect
.len
))
274 << (grub_bfs_to_cpu32 (sb
->log2_bsize
) - LOG_EXTENT_SIZE
));
275 entries
= grub_malloc (nentries
<< LOG_EXTENT_SIZE
);
278 err
= read_extent (disk
, sb
, &ino
->indirect
, 0, 0,
279 entries
, nentries
<< LOG_EXTENT_SIZE
);
280 for (i
= 0; i
< nentries
; i
++)
282 grub_uint64_t newpos
;
283 newpos
= pos
+ (((grub_uint64_t
) grub_bfs_to_cpu16 (entries
[i
].len
))
284 << grub_bfs_to_cpu32 (sb
->log2_bsize
));
287 grub_size_t read_size
;
288 read_size
= newpos
- off
;
291 disk
->read_hook
= read_hook
;
292 disk
->read_hook_data
= read_hook_data
;
293 err
= read_extent (disk
, sb
, &entries
[i
], 0, off
- pos
,
303 buf
= (char *) buf
+ read_size
;
307 return GRUB_ERR_NONE
;
315 if (off
< (grub_bfs_to_cpu64 (ino
->max_indirect_range
) << RANGE_SHIFT
))
316 return grub_error (GRUB_ERR_BAD_FS
, "incorrect indirect blocks");
319 struct grub_bfs_extent
*l1_entries
, *l2_entries
;
320 grub_size_t nl1_entries
, nl2_entries
;
321 grub_off_t last_l1n
= ~0ULL;
323 nl1_entries
= (((grub_uint64_t
) grub_bfs_to_cpu16 (ino
->double_indirect
.len
))
324 << (grub_bfs_to_cpu32 (sb
->log2_bsize
) - LOG_EXTENT_SIZE
));
325 l1_entries
= grub_malloc (nl1_entries
<< LOG_EXTENT_SIZE
);
329 l2_entries
= grub_malloc (1 << (DOUBLE_INDIRECT_SHIFT
330 + grub_bfs_to_cpu32 (sb
->log2_bsize
)));
333 grub_free (l1_entries
);
336 err
= read_extent (disk
, sb
, &ino
->double_indirect
, 0, 0,
337 l1_entries
, nl1_entries
<< LOG_EXTENT_SIZE
);
340 grub_free (l1_entries
);
341 grub_free (l2_entries
);
347 grub_off_t boff
, l2n
, l1n
;
348 grub_size_t read_size
;
349 grub_off_t double_indirect_offset
;
350 double_indirect_offset
= off
351 - grub_bfs_to_cpu64 (ino
->max_indirect_range
);
352 boff
= (double_indirect_offset
353 & ((1 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
354 + DOUBLE_INDIRECT_SHIFT
)) - 1));
355 l2n
= ((double_indirect_offset
>> (grub_bfs_to_cpu32 (sb
->log2_bsize
)
356 + DOUBLE_INDIRECT_SHIFT
))
357 & ((1 << (grub_bfs_to_cpu32 (sb
->log2_bsize
) - LOG_EXTENT_SIZE
358 + DOUBLE_INDIRECT_SHIFT
)) - 1));
360 (double_indirect_offset
>>
361 (2 * grub_bfs_to_cpu32 (sb
->log2_bsize
) - LOG_EXTENT_SIZE
+
362 2 * DOUBLE_INDIRECT_SHIFT
));
363 if (l1n
> nl1_entries
)
365 grub_free (l1_entries
);
366 grub_free (l2_entries
);
367 return grub_error (GRUB_ERR_BAD_FS
,
368 "incorrect double-indirect block");
372 nl2_entries
= (((grub_uint64_t
) grub_bfs_to_cpu16 (l1_entries
[l1n
].len
))
373 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
375 if (nl2_entries
> (1U << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
377 + DOUBLE_INDIRECT_SHIFT
)))
378 nl2_entries
= (1 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
380 + DOUBLE_INDIRECT_SHIFT
));
381 err
= read_extent (disk
, sb
, &l1_entries
[l1n
], 0, 0,
382 l2_entries
, nl2_entries
<< LOG_EXTENT_SIZE
);
385 grub_free (l1_entries
);
386 grub_free (l2_entries
);
391 if (l2n
> nl2_entries
)
393 grub_free (l1_entries
);
394 grub_free (l2_entries
);
395 return grub_error (GRUB_ERR_BAD_FS
,
396 "incorrect double-indirect block");
399 read_size
= (1 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
400 + DOUBLE_INDIRECT_SHIFT
)) - boff
;
403 disk
->read_hook
= read_hook
;
404 disk
->read_hook_data
= read_hook_data
;
405 err
= read_extent (disk
, sb
, &l2_entries
[l2n
], 0, boff
,
410 grub_free (l1_entries
);
411 grub_free (l2_entries
);
416 buf
= (char *) buf
+ read_size
;
418 return GRUB_ERR_NONE
;
423 read_b_node (grub_disk_t disk
,
424 const struct grub_bfs_superblock
*sb
,
425 const struct grub_bfs_inode
*ino
,
426 grub_uint64_t node_off
,
427 struct grub_bfs_btree_node
**node
,
428 char **key_data
, grub_uint16_t
**keylen_idx
,
429 grub_unaligned_uint64_t
**key_values
)
432 struct grub_bfs_btree_node node_head
;
433 grub_size_t total_size
;
441 err
= read_bfs_file (disk
, sb
, ino
, node_off
, &node_head
, sizeof (node_head
),
446 total_size
= ALIGN_UP (sizeof (node_head
) +
447 grub_bfs_to_cpu_treehead
448 (node_head
.total_key_len
),
450 grub_bfs_to_cpu_treehead (node_head
.count_keys
) *
451 sizeof (grub_uint16_t
)
452 + grub_bfs_to_cpu_treehead (node_head
.count_keys
) *
453 sizeof (grub_uint64_t
);
455 ret
= grub_malloc (total_size
);
459 err
= read_bfs_file (disk
, sb
, ino
, node_off
, ret
, total_size
, 0, 0);
467 *key_data
= (char *) ret
+ sizeof (node_head
);
468 *keylen_idx
= (grub_uint16_t
*) ret
469 + ALIGN_UP (sizeof (node_head
) +
470 grub_bfs_to_cpu_treehead (node_head
.total_key_len
),
472 *key_values
= (grub_unaligned_uint64_t
*)
474 grub_bfs_to_cpu_treehead (node_head
.count_keys
));
476 return GRUB_ERR_NONE
;
480 iterate_in_b_tree (grub_disk_t disk
,
481 const struct grub_bfs_superblock
*sb
,
482 const struct grub_bfs_inode
*ino
,
483 int (*hook
) (const char *name
, grub_uint64_t value
,
484 struct grub_bfs_dir_ctx
*ctx
),
485 struct grub_bfs_dir_ctx
*ctx
)
487 struct grub_bfs_btree_header head
;
490 grub_uint64_t node_off
;
492 err
= read_bfs_file (disk
, sb
, ino
, 0, &head
, sizeof (head
), 0, 0);
495 node_off
= grub_bfs_to_cpu64 (head
.root
);
497 level
= grub_bfs_to_cpu32 (head
.level
) - 1;
500 struct grub_bfs_btree_node node
;
501 grub_uint64_t key_value
;
502 err
= read_bfs_file (disk
, sb
, ino
, node_off
, &node
, sizeof (node
),
506 err
= read_bfs_file (disk
, sb
, ino
, node_off
507 + ALIGN_UP (sizeof (node
) +
508 grub_bfs_to_cpu_treehead (node
.
511 grub_bfs_to_cpu_treehead (node
.count_keys
) *
512 sizeof (grub_uint16_t
), &key_value
,
513 sizeof (grub_uint64_t
), 0, 0);
517 node_off
= grub_bfs_to_cpu64 (key_value
);
522 struct grub_bfs_btree_node
*node
;
524 grub_uint16_t
*keylen_idx
;
525 grub_unaligned_uint64_t
*key_values
;
527 grub_uint16_t start
= 0, end
= 0;
529 err
= read_b_node (disk
, sb
, ino
,
539 for (i
= 0; i
< grub_bfs_to_cpu_treehead (node
->count_keys
); i
++)
543 end
= grub_bfs_to_cpu16 (keylen_idx
[i
]);
544 if (grub_bfs_to_cpu_treehead (node
->total_key_len
) <= end
)
545 end
= grub_bfs_to_cpu_treehead (node
->total_key_len
);
548 if (hook (key_data
+ start
, grub_bfs_to_cpu64 (key_values
[i
].val
),
556 node_off
= grub_bfs_to_cpu64 (node
->right
);
558 if (node_off
== POINTER_INVALID
)
564 bfs_strcmp (const char *a
, const char *b
, grub_size_t alen
, grub_size_t blen
)
582 return (int) (grub_int8_t
) ac
- (int) (grub_int8_t
) bc
;
584 return (int) (grub_uint8_t
) ac
- (int) (grub_uint8_t
) bc
;
589 find_in_b_tree (grub_disk_t disk
,
590 const struct grub_bfs_superblock
*sb
,
591 const struct grub_bfs_inode
*ino
, const char *name
,
592 grub_size_t name_len
,
595 struct grub_bfs_btree_header head
;
598 grub_uint64_t node_off
;
600 err
= read_bfs_file (disk
, sb
, ino
, 0, &head
, sizeof (head
), 0, 0);
603 node_off
= grub_bfs_to_cpu64 (head
.root
);
605 level
= grub_bfs_to_cpu32 (head
.level
) - 1;
608 struct grub_bfs_btree_node
*node
;
610 grub_uint16_t
*keylen_idx
;
611 grub_unaligned_uint64_t
*key_values
;
615 err
= read_b_node (disk
, sb
, ino
, node_off
, &node
, &key_data
, &keylen_idx
, &key_values
);
619 if (node
->count_keys
== 0)
622 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"),
626 for (lg
= 0; grub_bfs_to_cpu_treehead (node
->count_keys
) >> lg
; lg
++);
630 for (j
= lg
- 1; j
>= 0; j
--)
633 grub_uint16_t start
= 0, end
= 0;
634 if ((i
| (1 << j
)) >= grub_bfs_to_cpu_treehead (node
->count_keys
))
636 start
= grub_bfs_to_cpu16 (keylen_idx
[(i
| (1 << j
)) - 1]);
637 end
= grub_bfs_to_cpu16 (keylen_idx
[(i
| (1 << j
))]);
638 if (grub_bfs_to_cpu_treehead (node
->total_key_len
) <= end
)
639 end
= grub_bfs_to_cpu_treehead (node
->total_key_len
);
640 cmp
= bfs_strcmp (key_data
+ start
, name
, end
- start
, name_len
);
641 if (cmp
== 0 && level
== 0)
643 *res
= grub_bfs_to_cpu64 (key_values
[i
| (1 << j
)].val
);
645 return GRUB_ERR_NONE
;
656 grub_uint16_t end
= 0;
658 end
= grub_bfs_to_cpu16 (keylen_idx
[0]);
659 if (grub_bfs_to_cpu_treehead (node
->total_key_len
) <= end
)
660 end
= grub_bfs_to_cpu_treehead (node
->total_key_len
);
661 cmp
= bfs_strcmp (key_data
, name
, end
, name_len
);
662 if (cmp
== 0 && level
== 0)
664 *res
= grub_bfs_to_cpu64 (key_values
[0].val
);
666 return GRUB_ERR_NONE
;
669 if (cmp
> 0 && level
!= 0)
671 if (cmp
>= 0 && level
!= 0)
674 node_off
= grub_bfs_to_cpu64 (key_values
[0].val
);
680 && grub_bfs_to_cpu_treehead (node
->count_keys
) >= 2)
682 node_off
= grub_bfs_to_cpu64 (key_values
[1].val
);
689 && i
+ 1 < grub_bfs_to_cpu_treehead (node
->count_keys
))
691 node_off
= grub_bfs_to_cpu64 (key_values
[i
+ 1].val
);
696 if (node
->overflow
!= POINTER_INVALID
)
698 node_off
= grub_bfs_to_cpu64 (node
->overflow
);
699 /* This level-- isn't specified but is needed. */
705 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"),
711 hop_level (grub_disk_t disk
,
712 const struct grub_bfs_superblock
*sb
,
713 struct grub_bfs_inode
*ino
, const char *name
,
714 const char *name_end
)
717 grub_uint64_t res
= 0;
719 if (((grub_bfs_to_cpu32 (ino
->mode
) & ATTR_TYPE
) != ATTR_DIR
))
720 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
722 err
= find_in_b_tree (disk
, sb
, ino
, name
, name_end
- name
, &res
);
726 return grub_disk_read (disk
, res
727 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
728 - GRUB_DISK_SECTOR_BITS
), 0,
729 sizeof (*ino
), (char *) ino
);
733 find_file (const char *path
, grub_disk_t disk
,
734 const struct grub_bfs_superblock
*sb
, struct grub_bfs_inode
*ino
)
736 const char *ptr
, *next
= path
;
740 struct grub_bfs_inode old_ino
;
741 unsigned symlinks_max
= 32;
743 err
= read_extent (disk
, sb
, &sb
->root_dir
, 0, 0, ino
,
756 return GRUB_ERR_NONE
;
758 for (next
= ptr
; *next
&& *next
!= '/'; next
++);
759 grub_memcpy (&old_ino
, ino
, sizeof (old_ino
));
760 err
= hop_level (disk
, sb
, ino
, ptr
, next
);
764 if (((grub_bfs_to_cpu32 (ino
->mode
) & ATTR_TYPE
) == ATTR_LNK
))
766 char *old_alloc
= alloc
;
767 if (--symlinks_max
== 0)
770 return grub_error (GRUB_ERR_SYMLINK_LOOP
,
771 N_("too deep nesting of symlinks"));
775 if (grub_bfs_to_cpu32 (ino
->flags
) & LONG_SYMLINK
)
778 grub_size_t symsize
= grub_bfs_to_cpu64 (ino
->size
);
779 alloc
= grub_malloc (grub_strlen (next
)
786 grub_free (old_alloc
);
787 err
= read_bfs_file (disk
, sb
, ino
, 0, alloc
, symsize
, 0, 0);
798 alloc
= grub_malloc (grub_strlen (next
)
799 + sizeof (ino
->inplace_link
) + 1);
805 grub_free (old_alloc
);
806 grub_memcpy (alloc
, ino
->inplace_link
,
807 sizeof (ino
->inplace_link
));
808 alloc
[sizeof (ino
->inplace_link
)] = 0;
813 err
= read_extent (disk
, sb
, &sb
->root_dir
, 0, 0, ino
,
822 grub_memcpy (ino
, &old_ino
, sizeof (old_ino
));
823 wptr
= alloc
+ grub_strlen (alloc
);
825 wptr
= grub_stpcpy (wptr
, next
);
834 mount (grub_disk_t disk
, struct grub_bfs_superblock
*sb
)
837 err
= grub_disk_read (disk
, SUPERBLOCK
, 0, sizeof (*sb
), sb
);
838 if (err
== GRUB_ERR_OUT_OF_RANGE
)
839 return grub_error (GRUB_ERR_BAD_FS
,
841 "not an AFS filesystem"
843 "not a BFS filesystem"
848 if (sb
->magic1
!= grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC1
)
849 || sb
->magic2
!= grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC2
)
850 || sb
->magic3
!= grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC3
)
852 || (grub_bfs_to_cpu32 (sb
->bsize
)
853 != (1U << grub_bfs_to_cpu32 (sb
->log2_bsize
)))
854 || grub_bfs_to_cpu32 (sb
->log2_bsize
) < GRUB_DISK_SECTOR_BITS
)
855 return grub_error (GRUB_ERR_BAD_FS
,
857 "not an AFS filesystem"
859 "not a BFS filesystem"
862 return GRUB_ERR_NONE
;
865 /* Helper for grub_bfs_dir. */
867 grub_bfs_dir_iter (const char *name
, grub_uint64_t value
,
868 struct grub_bfs_dir_ctx
*ctx
)
871 struct grub_bfs_inode ino
;
872 struct grub_dirhook_info info
;
874 err2
= grub_disk_read (ctx
->device
->disk
, value
875 << (grub_bfs_to_cpu32 (ctx
->sb
.log2_bsize
)
876 - GRUB_DISK_SECTOR_BITS
), 0,
877 sizeof (ino
), (char *) &ino
);
887 grub_divmod64 (grub_bfs_to_cpu64 (ino
.mtime
), 1000000, 0);
889 info
.mtime
= grub_bfs_to_cpu64 (ino
.mtime
) >> 16;
891 info
.dir
= ((grub_bfs_to_cpu32 (ino
.mode
) & ATTR_TYPE
) == ATTR_DIR
);
892 return ctx
->hook (name
, &info
, ctx
->hook_data
);
896 grub_bfs_dir (grub_device_t device
, const char *path
,
897 grub_fs_dir_hook_t hook
, void *hook_data
)
899 struct grub_bfs_dir_ctx ctx
= {
902 .hook_data
= hook_data
906 err
= mount (device
->disk
, &ctx
.sb
);
911 struct grub_bfs_inode ino
;
912 err
= find_file (path
, device
->disk
, &ctx
.sb
, &ino
);
915 if (((grub_bfs_to_cpu32 (ino
.mode
) & ATTR_TYPE
) != ATTR_DIR
))
916 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
917 iterate_in_b_tree (device
->disk
, &ctx
.sb
, &ino
, grub_bfs_dir_iter
,
925 grub_bfs_open (struct grub_file
*file
, const char *name
)
927 struct grub_bfs_superblock sb
;
930 err
= mount (file
->device
->disk
, &sb
);
935 struct grub_bfs_inode ino
;
936 struct grub_bfs_data
*data
;
937 err
= find_file (name
, file
->device
->disk
, &sb
, &ino
);
940 if (((grub_bfs_to_cpu32 (ino
.mode
) & ATTR_TYPE
) != ATTR_REG
))
941 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a regular file"));
943 data
= grub_zalloc (sizeof (struct grub_bfs_data
));
947 grub_memcpy (&data
->ino
, &ino
, sizeof (data
->ino
));
949 file
->size
= grub_bfs_to_cpu64 (ino
.size
);
952 return GRUB_ERR_NONE
;
956 grub_bfs_close (grub_file_t file
)
958 grub_free (file
->data
);
960 return GRUB_ERR_NONE
;
964 grub_bfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
967 struct grub_bfs_data
*data
= file
->data
;
969 err
= read_bfs_file (file
->device
->disk
, &data
->sb
,
970 &data
->ino
, file
->offset
, buf
, len
,
971 file
->read_hook
, file
->read_hook_data
);
978 grub_bfs_label (grub_device_t device
, char **label
)
980 struct grub_bfs_superblock sb
;
985 err
= mount (device
->disk
, &sb
);
989 *label
= grub_strndup (sb
.label
, sizeof (sb
.label
));
990 return GRUB_ERR_NONE
;
995 read_bfs_attr (grub_disk_t disk
,
996 const struct grub_bfs_superblock
*sb
,
997 struct grub_bfs_inode
*ino
,
998 const char *name
, void *buf
, grub_size_t len
)
1000 grub_uint8_t
*ptr
= (grub_uint8_t
*) ino
->small_data
;
1001 grub_uint8_t
*end
= ((grub_uint8_t
*) ino
+ grub_bfs_to_cpu32 (sb
->bsize
));
1003 while (ptr
+ sizeof (struct grub_bfs_small_data_element_header
) < end
)
1005 struct grub_bfs_small_data_element_header
*el
;
1008 el
= (struct grub_bfs_small_data_element_header
*) ptr
;
1009 if (el
->name_len
== 0)
1011 el_name
= (char *) (el
+ 1);
1012 data
= (grub_uint8_t
*) el_name
+ grub_bfs_to_cpu16 (el
->name_len
) + 3;
1013 ptr
= data
+ grub_bfs_to_cpu16 (el
->value_len
) + 1;
1014 if (grub_memcmp (name
, el_name
, grub_bfs_to_cpu16 (el
->name_len
)) == 0
1015 && name
[el
->name_len
] == 0)
1019 if (grub_bfs_to_cpu16 (el
->value_len
) > copy
)
1020 copy
= grub_bfs_to_cpu16 (el
->value_len
);
1021 grub_memcpy (buf
, data
, copy
);
1026 if (ino
->attr
.len
!= 0)
1032 err
= read_extent (disk
, sb
, &ino
->attr
, 0, 0, ino
,
1033 grub_bfs_to_cpu32 (sb
->bsize
));
1037 err
= find_in_b_tree (disk
, sb
, ino
, name
, grub_strlen (name
), &res
);
1040 grub_disk_read (disk
, res
1041 << (grub_bfs_to_cpu32 (sb
->log2_bsize
)
1042 - GRUB_DISK_SECTOR_BITS
), 0,
1043 grub_bfs_to_cpu32 (sb
->bsize
), (char *) ino
);
1044 read
= grub_bfs_to_cpu64 (ino
->size
);
1048 err
= read_bfs_file (disk
, sb
, ino
, 0, buf
, read
, 0, 0);
1057 grub_bfs_uuid (grub_device_t device
, char **uuid
)
1059 struct grub_bfs_superblock sb
;
1061 struct grub_bfs_inode
*ino
;
1066 err
= mount (device
->disk
, &sb
);
1070 ino
= grub_malloc (grub_bfs_to_cpu32 (sb
.bsize
));
1074 err
= read_extent (device
->disk
, &sb
, &sb
.root_dir
, 0, 0,
1075 ino
, grub_bfs_to_cpu32 (sb
.bsize
));
1081 if (read_bfs_attr (device
->disk
, &sb
, ino
, "be:volume_id",
1082 &vid
, sizeof (vid
)) == sizeof (vid
))
1084 grub_xasprintf ("%016" PRIxGRUB_UINT64_T
, grub_bfs_to_cpu64 (vid
));
1088 return GRUB_ERR_NONE
;
1092 static struct grub_fs grub_bfs_fs
= {
1098 .dir
= grub_bfs_dir
,
1099 .open
= grub_bfs_open
,
1100 .read
= grub_bfs_read
,
1101 .close
= grub_bfs_close
,
1102 .label
= grub_bfs_label
,
1104 .uuid
= grub_bfs_uuid
,
1107 .reserved_first_sector
= 1,
1108 .blocklist_install
= 1,
1118 COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE
==
1119 sizeof (struct grub_bfs_extent
));
1120 grub_fs_register (&grub_bfs_fs
);
1129 grub_fs_unregister (&grub_bfs_fs
);