1 /* reiserfs.c - ReiserFS versions up to 3.6 */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2008 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/>.
22 implement journal handling (ram replay)
23 test tail packing & direct files
24 validate partition label position
28 # define GRUB_REISERFS_DEBUG
29 # define GRUB_REISERFS_JOURNALING
34 #include <grub/file.h>
36 #include <grub/misc.h>
37 #include <grub/disk.h>
39 #include <grub/types.h>
40 #include <grub/fshelp.h>
41 #include <grub/i18n.h>
43 GRUB_MOD_LICENSE ("GPLv3+");
46 ({ typeof (a) _a = (a); \
47 typeof (b) _b = (b); \
51 ({ typeof (a) _a = (a); \
52 typeof (b) _b = (b); \
55 #define REISERFS_SUPER_BLOCK_OFFSET 0x10000
56 #define REISERFS_MAGIC_LEN 12
57 #define REISERFS_MAGIC_STRING "ReIsEr"
58 #define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
59 /* If the 3rd bit of an item state is set, then it's visible. */
60 #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
62 #define S_IFLNK 0xA000
64 static grub_dl_t my_mod
;
66 #define assert(boolean) real_assert (boolean, GRUB_FILE, __LINE__)
68 real_assert (int boolean
, const char *file
, const int line
)
71 grub_printf ("Assertion failed at %s:%d\n", file
, line
);
74 enum grub_reiserfs_item_type
77 GRUB_REISERFS_DIRECTORY
,
79 GRUB_REISERFS_INDIRECT
,
80 /* Matches both _DIRECT and _INDIRECT when searching. */
85 struct grub_reiserfs_superblock
87 grub_uint32_t block_count
;
88 grub_uint32_t block_free_count
;
89 grub_uint32_t root_block
;
90 grub_uint32_t journal_block
;
91 grub_uint32_t journal_device
;
92 grub_uint32_t journal_original_size
;
93 grub_uint32_t journal_max_transaction_size
;
94 grub_uint32_t journal_block_count
;
95 grub_uint32_t journal_max_batch
;
96 grub_uint32_t journal_max_commit_age
;
97 grub_uint32_t journal_max_transaction_age
;
98 grub_uint16_t block_size
;
99 grub_uint16_t oid_max_size
;
100 grub_uint16_t oid_current_size
;
102 grub_uint8_t magic_string
[REISERFS_MAGIC_LEN
];
103 grub_uint32_t function_hash_code
;
104 grub_uint16_t tree_height
;
105 grub_uint16_t bitmap_number
;
106 grub_uint16_t version
;
107 grub_uint16_t reserved
;
108 grub_uint32_t inode_generation
;
109 grub_uint8_t unused
[4];
110 grub_uint16_t uuid
[8];
114 struct grub_reiserfs_journal_header
116 grub_uint32_t last_flush_uid
;
117 grub_uint32_t unflushed_offset
;
118 grub_uint32_t mount_id
;
121 struct grub_reiserfs_description_block
125 grub_uint32_t mount_id
;
126 grub_uint32_t real_blocks
[0];
129 struct grub_reiserfs_commit_block
133 grub_uint32_t real_blocks
[0];
136 struct grub_reiserfs_stat_item_v1
139 grub_uint16_t hardlink_count
;
147 grub_uint32_t first_direct_byte
;
150 struct grub_reiserfs_stat_item_v2
153 grub_uint16_t reserved
;
154 grub_uint32_t hardlink_count
;
161 grub_uint32_t blocks
;
162 grub_uint32_t first_direct_byte
;
165 struct grub_reiserfs_key
167 grub_uint32_t directory_id
;
168 grub_uint32_t object_id
;
173 grub_uint32_t offset
;
178 grub_uint64_t offset_type
;
183 struct grub_reiserfs_item_header
185 struct grub_reiserfs_key key
;
188 grub_uint16_t free_space
;
189 grub_uint16_t entry_count
;
191 grub_uint16_t item_size
;
192 grub_uint16_t item_location
;
193 grub_uint16_t version
;
196 struct grub_reiserfs_block_header
199 grub_uint16_t item_count
;
200 grub_uint16_t free_space
;
201 grub_uint16_t reserved
;
202 struct grub_reiserfs_key block_right_delimiting_key
;
205 struct grub_reiserfs_disk_child
207 grub_uint32_t block_number
;
209 grub_uint16_t reserved
;
212 struct grub_reiserfs_directory_header
214 grub_uint32_t offset
;
215 grub_uint32_t directory_id
;
216 grub_uint32_t object_id
;
217 grub_uint16_t location
;
221 struct grub_fshelp_node
223 struct grub_reiserfs_data
*data
;
224 grub_uint32_t block_number
; /* 0 if node is not found. */
225 grub_uint16_t block_position
;
226 grub_uint64_t next_offset
;
229 enum grub_reiserfs_item_type type
; /* To know how to read the header. */
230 struct grub_reiserfs_item_header header
;
233 /* Returned when opening a file. */
234 struct grub_reiserfs_data
236 struct grub_reiserfs_superblock superblock
;
241 grub_reiserfs_read_real (struct grub_fshelp_node
*node
,
242 grub_off_t off
, char *buf
, grub_size_t len
,
243 grub_disk_read_hook_t read_hook
,
244 void *read_hook_data
);
246 /* Internal-only functions. Not to be used outside of this file. */
248 /* Return the type of given v2 key. */
249 static enum grub_reiserfs_item_type
250 grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key
*key
)
252 switch (grub_le_to_cpu64 (key
->u
.v2
.offset_type
) >> 60)
255 return GRUB_REISERFS_STAT
;
257 return GRUB_REISERFS_ANY
;
259 return GRUB_REISERFS_DIRECTORY
;
261 return GRUB_REISERFS_DIRECT
;
263 return GRUB_REISERFS_INDIRECT
;
265 return GRUB_REISERFS_UNKNOWN
;
268 /* Return the type of given v1 key. */
269 static enum grub_reiserfs_item_type
270 grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key
*key
)
272 switch (grub_le_to_cpu32 (key
->u
.v1
.type
))
275 return GRUB_REISERFS_STAT
;
277 return GRUB_REISERFS_ANY
;
279 return GRUB_REISERFS_DIRECTORY
;
282 return GRUB_REISERFS_DIRECT
;
285 return GRUB_REISERFS_INDIRECT
;
287 return GRUB_REISERFS_UNKNOWN
;
290 /* Return 1 if the given key is version 1 key, 2 otherwise. */
292 grub_reiserfs_get_key_version (const struct grub_reiserfs_key
*key
)
294 return grub_reiserfs_get_key_v1_type (key
) == GRUB_REISERFS_UNKNOWN
? 2 : 1;
299 grub_hexdump (char *buffer
, grub_size_t len
)
302 for (a
= 0; a
< len
; a
++)
305 grub_printf ("\n%08x ", a
);
306 grub_printf ("%02x ",
307 ((unsigned int) ((unsigned char *) buffer
)[a
]) & 0xFF);
313 #ifdef GRUB_REISERFS_DEBUG
315 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
);
317 static enum grub_reiserfs_item_type
318 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
);
321 grub_reiserfs_print_key (const struct grub_reiserfs_key
*key
)
324 char *reiserfs_type_strings
[] = {
333 for (a
= 0; a
< sizeof (struct grub_reiserfs_key
); a
++)
334 grub_printf ("%02x ", ((unsigned int) ((unsigned char *) key
)[a
]) & 0xFF);
335 grub_printf ("parent id = 0x%08x, self id = 0x%08x, type = %s, offset = ",
336 grub_le_to_cpu32 (key
->directory_id
),
337 grub_le_to_cpu32 (key
->object_id
),
338 reiserfs_type_strings
[grub_reiserfs_get_key_type (key
)]);
339 if (grub_reiserfs_get_key_version (key
) == 1)
340 grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset (key
));
342 grub_printf("0x%07x%08x",
343 (unsigned) (grub_reiserfs_get_key_offset (key
) >> 32),
344 (unsigned) (grub_reiserfs_get_key_offset (key
) & 0xFFFFFFFF));
349 /* Return the offset of given key. */
351 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
)
353 if (grub_reiserfs_get_key_version (key
) == 1)
354 return grub_le_to_cpu32 (key
->u
.v1
.offset
);
356 return grub_le_to_cpu64 (key
->u
.v2
.offset_type
) & (~0ULL >> 4);
359 /* Set the offset of given key. */
361 grub_reiserfs_set_key_offset (struct grub_reiserfs_key
*key
,
364 if (grub_reiserfs_get_key_version (key
) == 1)
365 key
->u
.v1
.offset
= grub_cpu_to_le32 (value
);
367 key
->u
.v2
.offset_type \
368 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64_compile_time (15ULL << 60))
369 | grub_cpu_to_le64 (value
& (~0ULL >> 4)));
372 /* Return the type of given key. */
373 static enum grub_reiserfs_item_type
374 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
)
376 if (grub_reiserfs_get_key_version (key
) == 1)
377 return grub_reiserfs_get_key_v1_type (key
);
379 return grub_reiserfs_get_key_v2_type (key
);
382 /* Set the type of given key, with given version number. */
384 grub_reiserfs_set_key_type (struct grub_reiserfs_key
*key
,
385 enum grub_reiserfs_item_type grub_type
,
392 case GRUB_REISERFS_STAT
:
395 case GRUB_REISERFS_ANY
:
396 type
= (version
== 1) ? 555 : 15;
398 case GRUB_REISERFS_DIRECTORY
:
399 type
= (version
== 1) ? 500 : 3;
401 case GRUB_REISERFS_DIRECT
:
402 type
= (version
== 1) ? 0xFFFFFFFF : 2;
404 case GRUB_REISERFS_INDIRECT
:
405 type
= (version
== 1) ? 0xFFFFFFFE : 1;
412 key
->u
.v1
.type
= grub_cpu_to_le32 (type
);
414 key
->u
.v2
.offset_type
415 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64_compile_time (~0ULL >> 4))
416 | grub_cpu_to_le64 ((grub_uint64_t
) type
<< 60));
418 assert (grub_reiserfs_get_key_type (key
) == grub_type
);
421 /* -1 if key 1 if lower than key 2.
422 0 if key 1 is equal to key 2.
423 1 if key 1 is higher than key 2. */
425 grub_reiserfs_compare_keys (const struct grub_reiserfs_key
*key1
,
426 const struct grub_reiserfs_key
*key2
)
428 grub_uint64_t offset1
, offset2
;
429 enum grub_reiserfs_item_type type1
, type2
;
430 grub_uint32_t id1
, id2
;
432 if (! key1
|| ! key2
)
435 id1
= grub_le_to_cpu32 (key1
->directory_id
);
436 id2
= grub_le_to_cpu32 (key2
->directory_id
);
442 id1
= grub_le_to_cpu32 (key1
->object_id
);
443 id2
= grub_le_to_cpu32 (key2
->object_id
);
449 offset1
= grub_reiserfs_get_key_offset (key1
);
450 offset2
= grub_reiserfs_get_key_offset (key2
);
451 if (offset1
< offset2
)
453 if (offset1
> offset2
)
456 type1
= grub_reiserfs_get_key_type (key1
);
457 type2
= grub_reiserfs_get_key_type (key2
);
458 if ((type1
== GRUB_REISERFS_ANY
459 && (type2
== GRUB_REISERFS_DIRECT
460 || type2
== GRUB_REISERFS_INDIRECT
))
461 || (type2
== GRUB_REISERFS_ANY
462 && (type1
== GRUB_REISERFS_DIRECT
463 || type1
== GRUB_REISERFS_INDIRECT
)))
473 /* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
474 accordingly to what was found. */
476 grub_reiserfs_get_item (struct grub_reiserfs_data
*data
,
477 const struct grub_reiserfs_key
*key
,
478 struct grub_fshelp_node
*item
, int exact
)
480 grub_uint32_t block_number
;
481 struct grub_reiserfs_block_header
*block_header
= 0;
482 struct grub_reiserfs_key
*block_key
= 0;
483 grub_uint16_t block_size
, item_count
, current_level
;
485 grub_uint16_t previous_level
= ~0;
486 struct grub_reiserfs_item_header
*item_headers
= 0;
491 grub_error (GRUB_ERR_BAD_FS
, "data is NULL");
497 grub_error (GRUB_ERR_BAD_FS
, "key is NULL");
503 grub_error (GRUB_ERR_BAD_FS
, "item is NULL");
508 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
509 block_number
= grub_le_to_cpu32 (data
->superblock
.root_block
);
510 #ifdef GRUB_REISERFS_DEBUG
511 grub_printf("Searching for ");
512 grub_reiserfs_print_key (key
);
514 block_header
= grub_malloc (block_size
);
518 item
->next_offset
= 0;
521 grub_disk_read (data
->disk
,
522 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
523 (((grub_off_t
) block_number
* block_size
)
524 & (GRUB_DISK_SECTOR_SIZE
- 1)),
525 block_size
, block_header
);
528 current_level
= grub_le_to_cpu16 (block_header
->level
);
529 grub_dprintf ("reiserfs_tree", " at level %d\n", current_level
);
530 if (current_level
>= previous_level
)
532 grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
533 grub_error (GRUB_ERR_BAD_FS
, "level loop");
536 previous_level
= current_level
;
537 item_count
= grub_le_to_cpu16 (block_header
->item_count
);
538 grub_dprintf ("reiserfs_tree", " number of contained items : %d\n",
540 if (current_level
> 1)
542 /* Internal node. Navigate to the child that should contain
544 struct grub_reiserfs_key
*keys
545 = (struct grub_reiserfs_key
*) (block_header
+ 1);
546 struct grub_reiserfs_disk_child
*children
547 = ((struct grub_reiserfs_disk_child
*)
548 (keys
+ item_count
));
552 && grub_reiserfs_compare_keys (key
, &(keys
[i
])) >= 0;
555 #ifdef GRUB_REISERFS_DEBUG
556 grub_printf("i %03d/%03d ", i
+ 1, item_count
+ 1);
557 grub_reiserfs_print_key (&(keys
[i
]));
560 block_number
= grub_le_to_cpu32 (children
[i
].block_number
);
561 if ((i
< item_count
) && (key
->directory_id
== keys
[i
].directory_id
)
562 && (key
->object_id
== keys
[i
].object_id
))
563 item
->next_offset
= grub_reiserfs_get_key_offset(&(keys
[i
]));
564 #ifdef GRUB_REISERFS_DEBUG
566 || grub_reiserfs_compare_keys (key
, &(keys
[i
])) == 0)
572 grub_printf (" %03d/%03d ", i
+ 1, item_count
+ 1);
573 grub_reiserfs_print_key (&(keys
[i
]));
574 if (i
+ 1 < item_count
)
576 grub_printf ("+ %03d/%03d ", i
+ 2, item_count
);
577 grub_reiserfs_print_key (&(keys
[i
+ 1]));
581 grub_printf ("Accessing rightmost child at block %d.\n",
587 /* Leaf node. Check that the key is actually present. */
589 = (struct grub_reiserfs_item_header
*) (block_header
+ 1);
595 val
= grub_reiserfs_compare_keys (key
, &(item_headers
[i
].key
));
598 block_key
= &(item_headers
[i
].key
);
601 if (val
< 0 && exact
)
607 grub_error (GRUB_ERR_READ_ERROR
, "unexpected btree node");
611 block_key
= &(item_headers
[i
].key
);
615 if (!exact
&& i
== item_count
)
619 grub_error (GRUB_ERR_READ_ERROR
, "unexpected btree node");
623 block_key
= &(item_headers
[i
].key
);
627 while (current_level
> 1);
633 item
->block_number
= 0;
634 item
->block_position
= 0;
635 item
->type
= GRUB_REISERFS_UNKNOWN
;
636 #ifdef GRUB_REISERFS_DEBUG
637 grub_printf("Not found.\n");
642 item
->block_number
= block_number
;
643 item
->block_position
= i
;
644 item
->type
= grub_reiserfs_get_key_type (block_key
);
645 grub_memcpy (&(item
->header
), &(item_headers
[i
]),
646 sizeof (struct grub_reiserfs_item_header
));
647 #ifdef GRUB_REISERFS_DEBUG
648 grub_printf ("F %03d/%03d ", i
+ 1, item_count
);
649 grub_reiserfs_print_key (block_key
);
653 assert (grub_errno
== GRUB_ERR_NONE
);
654 grub_free (block_header
);
655 return GRUB_ERR_NONE
;
658 assert (grub_errno
!= GRUB_ERR_NONE
);
659 grub_free (block_header
);
660 assert (grub_errno
!= GRUB_ERR_NONE
);
664 /* Return the path of the file which is pointed at by symlink NODE. */
666 grub_reiserfs_read_symlink (grub_fshelp_node_t node
)
668 char *symlink_buffer
= 0;
669 grub_size_t len
= node
->size
;
672 symlink_buffer
= grub_malloc (len
+ 1);
673 if (! symlink_buffer
)
676 ret
= grub_reiserfs_read_real (node
, 0, symlink_buffer
, len
, 0, 0);
679 grub_free (symlink_buffer
);
683 symlink_buffer
[ret
] = 0;
684 return symlink_buffer
;
687 /* Fill the mounted filesystem structure and return it. */
688 static struct grub_reiserfs_data
*
689 grub_reiserfs_mount (grub_disk_t disk
)
691 struct grub_reiserfs_data
*data
= 0;
692 data
= grub_malloc (sizeof (*data
));
695 grub_disk_read (disk
, REISERFS_SUPER_BLOCK_OFFSET
/ GRUB_DISK_SECTOR_SIZE
,
696 0, sizeof (data
->superblock
), &(data
->superblock
));
699 if (grub_memcmp (data
->superblock
.magic_string
,
700 REISERFS_MAGIC_STRING
, sizeof (REISERFS_MAGIC_STRING
) - 1))
702 grub_error (GRUB_ERR_BAD_FS
, "not a ReiserFS filesystem");
709 /* Disk is too small to contain a ReiserFS. */
710 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
711 grub_error (GRUB_ERR_BAD_FS
, "not a ReiserFS filesystem");
717 /* Call HOOK for each file in directory ITEM. */
719 grub_reiserfs_iterate_dir (grub_fshelp_node_t item
,
720 grub_fshelp_iterate_dir_hook_t hook
,
723 struct grub_reiserfs_data
*data
= item
->data
;
724 struct grub_reiserfs_block_header
*block_header
= 0;
725 grub_uint16_t block_size
, block_position
;
726 grub_uint32_t block_number
;
727 grub_uint64_t next_offset
= item
->next_offset
;
730 if (item
->type
!= GRUB_REISERFS_DIRECTORY
)
732 grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
735 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
736 block_header
= grub_malloc (block_size
+ 1);
739 block_number
= item
->block_number
;
740 block_position
= item
->block_position
;
741 grub_dprintf ("reiserfs", "Iterating directory...\n");
744 struct grub_reiserfs_directory_header
*directory_headers
;
745 struct grub_fshelp_node directory_item
;
746 grub_uint16_t entry_count
, entry_number
;
747 struct grub_reiserfs_item_header
*item_headers
;
749 grub_disk_read (data
->disk
,
750 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
751 (((grub_off_t
) block_number
* block_size
)
752 & (GRUB_DISK_SECTOR_SIZE
- 1)),
753 block_size
, (char *) block_header
);
757 ((char *) block_header
)[block_size
] = 0;
760 if (grub_le_to_cpu16 (block_header
->level
) != 1)
762 grub_error (GRUB_ERR_BAD_FS
,
763 "reiserfs: block %d is not a leaf block",
769 item_headers
= (struct grub_reiserfs_item_header
*) (block_header
+ 1);
771 = ((struct grub_reiserfs_directory_header
*)
772 ((char *) block_header
773 + grub_le_to_cpu16 (item_headers
[block_position
].item_location
)));
775 = grub_le_to_cpu16 (item_headers
[block_position
].u
.entry_count
);
776 for (entry_number
= 0; entry_number
< entry_count
; entry_number
++)
778 struct grub_reiserfs_directory_header
*directory_header
779 = &directory_headers
[entry_number
];
780 grub_uint16_t entry_state
781 = grub_le_to_cpu16 (directory_header
->state
);
782 grub_fshelp_node_t entry_item
;
783 struct grub_reiserfs_key entry_key
;
784 enum grub_fshelp_filetype entry_type
;
787 if (!(entry_state
& GRUB_REISERFS_VISIBLE_MASK
))
790 entry_name
= (((char *) directory_headers
)
791 + grub_le_to_cpu16 (directory_header
->location
));
792 entry_key
.directory_id
= directory_header
->directory_id
;
793 entry_key
.object_id
= directory_header
->object_id
;
794 entry_key
.u
.v2
.offset_type
= 0;
795 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_DIRECTORY
,
797 grub_reiserfs_set_key_offset (&entry_key
, 1);
799 entry_item
= grub_malloc (sizeof (*entry_item
));
803 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
, 1)
806 grub_free (entry_item
);
810 if (entry_item
->type
== GRUB_REISERFS_DIRECTORY
)
811 entry_type
= GRUB_FSHELP_DIR
;
814 grub_uint32_t entry_block_number
;
815 /* Order is very important here.
816 First set the offset to 0 using current key version.
817 Then change the key type, which affects key version
819 grub_reiserfs_set_key_offset (&entry_key
, 0);
820 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_STAT
,
822 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
, 1)
825 grub_free (entry_item
);
829 if (entry_item
->block_number
!= 0)
831 grub_uint16_t entry_version
;
833 = grub_le_to_cpu16 (entry_item
->header
.version
);
834 entry_block_number
= entry_item
->block_number
;
836 grub_dprintf ("reiserfs",
837 "version %04x block %08x (%08x) position %08x\n",
838 entry_version
, entry_block_number
,
839 ((grub_disk_addr_t
) entry_block_number
* block_size
) / GRUB_DISK_SECTOR_SIZE
,
840 grub_le_to_cpu16 (entry_item
->header
.item_location
));
842 if (entry_version
== 0) /* Version 1 stat item. */
844 struct grub_reiserfs_stat_item_v1 entry_v1_stat
;
845 grub_disk_read (data
->disk
,
846 entry_block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
847 grub_le_to_cpu16 (entry_item
->header
.item_location
),
848 sizeof (entry_v1_stat
),
849 (char *) &entry_v1_stat
);
853 grub_dprintf ("reiserfs",
854 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
855 grub_le_to_cpu16 (entry_v1_stat
.mode
),
856 grub_le_to_cpu16 (entry_v1_stat
.hardlink_count
),
857 grub_le_to_cpu16 (entry_v1_stat
.uid
),
858 grub_le_to_cpu16 (entry_v1_stat
.gid
),
859 grub_le_to_cpu32 (entry_v1_stat
.size
),
860 grub_le_to_cpu32 (entry_v1_stat
.atime
),
861 grub_le_to_cpu32 (entry_v1_stat
.mtime
),
862 grub_le_to_cpu32 (entry_v1_stat
.ctime
),
863 grub_le_to_cpu32 (entry_v1_stat
.rdev
),
864 grub_le_to_cpu32 (entry_v1_stat
.first_direct_byte
));
865 grub_dprintf ("reiserfs",
866 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
868 entry_v1_stat
.hardlink_count
,
876 entry_v1_stat
.first_direct_byte
);
878 entry_item
->mtime
= grub_le_to_cpu32 (entry_v1_stat
.mtime
);
879 if ((grub_le_to_cpu16 (entry_v1_stat
.mode
) & S_IFLNK
)
881 entry_type
= GRUB_FSHELP_SYMLINK
;
883 entry_type
= GRUB_FSHELP_REG
;
884 entry_item
->size
= (grub_off_t
) grub_le_to_cpu32 (entry_v1_stat
.size
);
888 struct grub_reiserfs_stat_item_v2 entry_v2_stat
;
889 grub_disk_read (data
->disk
,
890 entry_block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
891 grub_le_to_cpu16 (entry_item
->header
.item_location
),
892 sizeof (entry_v2_stat
),
893 (char *) &entry_v2_stat
);
897 grub_dprintf ("reiserfs",
898 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
899 grub_le_to_cpu16 (entry_v2_stat
.mode
),
900 grub_le_to_cpu16 (entry_v2_stat
.reserved
),
901 grub_le_to_cpu32 (entry_v2_stat
.hardlink_count
),
902 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) >> 32),
903 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) && 0xFFFFFFFF),
904 grub_le_to_cpu32 (entry_v2_stat
.uid
),
905 grub_le_to_cpu32 (entry_v2_stat
.gid
),
906 grub_le_to_cpu32 (entry_v2_stat
.atime
),
907 grub_le_to_cpu32 (entry_v2_stat
.mtime
),
908 grub_le_to_cpu32 (entry_v2_stat
.ctime
),
909 grub_le_to_cpu32 (entry_v2_stat
.blocks
),
910 grub_le_to_cpu32 (entry_v2_stat
.first_direct_byte
));
911 grub_dprintf ("reiserfs",
912 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
914 entry_v2_stat
.reserved
,
915 entry_v2_stat
.hardlink_count
,
916 (unsigned int) (entry_v2_stat
.size
>> 32),
917 (unsigned int) (entry_v2_stat
.size
&& 0xFFFFFFFF),
923 entry_v2_stat
.blocks
,
924 entry_v2_stat
.first_direct_byte
);
926 entry_item
->mtime
= grub_le_to_cpu32 (entry_v2_stat
.mtime
);
927 entry_item
->size
= (grub_off_t
) grub_le_to_cpu64 (entry_v2_stat
.size
);
928 if ((grub_le_to_cpu16 (entry_v2_stat
.mode
) & S_IFLNK
)
930 entry_type
= GRUB_FSHELP_SYMLINK
;
932 entry_type
= GRUB_FSHELP_REG
;
937 /* Pseudo file ".." never has stat block. */
938 if (grub_strcmp (entry_name
, ".."))
939 grub_dprintf ("reiserfs",
940 "Warning : %s has no stat block !\n",
942 grub_free (entry_item
);
946 if (hook (entry_name
, entry_type
, entry_item
, hook_data
))
948 grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
949 entry_name
, entry_type
);
955 *entry_name
= 0; /* Make sure next entry name (which is just
956 before this one in disk order) stops before
960 if (next_offset
== 0)
963 grub_reiserfs_set_key_offset (&(item_headers
[block_position
].key
),
965 if (grub_reiserfs_get_item (data
, &(item_headers
[block_position
].key
),
966 &directory_item
, 1) != GRUB_ERR_NONE
)
968 block_number
= directory_item
.block_number
;
969 block_position
= directory_item
.block_position
;
970 next_offset
= directory_item
.next_offset
;
972 while (block_number
);
975 assert (grub_errno
== GRUB_ERR_NONE
);
976 grub_free (block_header
);
979 assert (grub_errno
!= GRUB_ERR_NONE
);
980 grub_free (block_header
);
984 /****************************************************************************/
985 /* grub api functions */
986 /****************************************************************************/
988 /* Open a file named NAME and initialize FILE. */
990 grub_reiserfs_open (struct grub_file
*file
, const char *name
)
992 struct grub_reiserfs_data
*data
= 0;
993 struct grub_fshelp_node root
, *found
= 0;
994 struct grub_reiserfs_key key
;
996 grub_dl_ref (my_mod
);
997 data
= grub_reiserfs_mount (file
->device
->disk
);
1000 key
.directory_id
= grub_cpu_to_le32_compile_time (1);
1001 key
.object_id
= grub_cpu_to_le32_compile_time (2);
1002 key
.u
.v2
.offset_type
= 0;
1003 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_DIRECTORY
, 2);
1004 grub_reiserfs_set_key_offset (&key
, 1);
1005 if (grub_reiserfs_get_item (data
, &key
, &root
, 1) != GRUB_ERR_NONE
)
1007 if (root
.block_number
== 0)
1009 grub_error (GRUB_ERR_BAD_FS
, "unable to find root item");
1010 goto fail
; /* Should never happen since checked at mount. */
1012 grub_fshelp_find_file (name
, &root
, &found
,
1013 grub_reiserfs_iterate_dir
,
1014 grub_reiserfs_read_symlink
, GRUB_FSHELP_REG
);
1017 file
->size
= found
->size
;
1019 grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
1020 (unsigned int) file
->size
,
1021 (unsigned int) (file
->size
>> 32), (unsigned int) file
->size
);
1024 return GRUB_ERR_NONE
;
1027 assert (grub_errno
!= GRUB_ERR_NONE
);
1031 grub_dl_unref (my_mod
);
1036 grub_reiserfs_read_real (struct grub_fshelp_node
*node
,
1037 grub_off_t off
, char *buf
, grub_size_t len
,
1038 grub_disk_read_hook_t read_hook
, void *read_hook_data
)
1040 unsigned int indirect_block
, indirect_block_count
;
1041 struct grub_reiserfs_key key
;
1042 struct grub_reiserfs_data
*data
= node
->data
;
1043 struct grub_fshelp_node found
;
1044 grub_uint16_t block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
1045 grub_uint16_t item_size
;
1046 grub_uint32_t
*indirect_block_ptr
= 0;
1047 grub_uint64_t current_key_offset
= 1;
1048 grub_off_t initial_position
, current_position
, final_position
, length
;
1049 grub_disk_addr_t block
;
1052 key
.directory_id
= node
->header
.key
.directory_id
;
1053 key
.object_id
= node
->header
.key
.object_id
;
1054 key
.u
.v2
.offset_type
= 0;
1055 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_ANY
, 2);
1056 initial_position
= off
;
1057 current_position
= 0;
1058 final_position
= MIN (len
+ initial_position
, node
->size
);
1059 grub_dprintf ("reiserfs",
1060 "Reading from %lld to %lld (%lld instead of requested %ld)\n",
1061 (unsigned long long) initial_position
,
1062 (unsigned long long) final_position
,
1063 (unsigned long long) (final_position
- initial_position
),
1064 (unsigned long) len
);
1066 grub_reiserfs_set_key_offset (&key
, initial_position
+ 1);
1068 if (grub_reiserfs_get_item (data
, &key
, &found
, 0) != GRUB_ERR_NONE
)
1071 if (found
.block_number
== 0)
1073 grub_error (GRUB_ERR_READ_ERROR
, "offset %lld not found",
1074 (unsigned long long) initial_position
);
1078 current_key_offset
= grub_reiserfs_get_key_offset (&found
.header
.key
);
1079 current_position
= current_key_offset
- 1;
1081 while (current_position
< final_position
)
1083 grub_reiserfs_set_key_offset (&key
, current_key_offset
);
1085 if (grub_reiserfs_get_item (data
, &key
, &found
, 1) != GRUB_ERR_NONE
)
1087 if (found
.block_number
== 0)
1089 item_size
= grub_le_to_cpu16 (found
.header
.item_size
);
1092 case GRUB_REISERFS_DIRECT
:
1093 block
= ((grub_disk_addr_t
) found
.block_number
) * (block_size
>> GRUB_DISK_SECTOR_BITS
);
1094 grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block
);
1095 if (initial_position
< current_position
+ item_size
)
1097 offset
= MAX ((signed) (initial_position
- current_position
), 0);
1098 length
= (MIN (item_size
, final_position
- current_position
)
1100 grub_dprintf ("reiserfs",
1101 "Reading direct block %u from %u to %u...\n",
1102 (unsigned) block
, (unsigned) offset
,
1103 (unsigned) (offset
+ length
));
1104 found
.data
->disk
->read_hook
= read_hook
;
1105 found
.data
->disk
->read_hook_data
= read_hook_data
;
1106 grub_disk_read (found
.data
->disk
,
1109 + grub_le_to_cpu16 (found
.header
.item_location
),
1111 found
.data
->disk
->read_hook
= 0;
1115 current_position
+= offset
+ length
;
1118 current_position
+= item_size
;
1120 case GRUB_REISERFS_INDIRECT
:
1121 indirect_block_count
= item_size
/ sizeof (*indirect_block_ptr
);
1122 indirect_block_ptr
= grub_malloc (item_size
);
1123 if (! indirect_block_ptr
)
1125 grub_disk_read (found
.data
->disk
,
1126 found
.block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
1127 grub_le_to_cpu16 (found
.header
.item_location
),
1128 item_size
, indirect_block_ptr
);
1131 found
.data
->disk
->read_hook
= read_hook
;
1132 found
.data
->disk
->read_hook_data
= read_hook_data
;
1133 for (indirect_block
= 0;
1134 indirect_block
< indirect_block_count
1135 && current_position
< final_position
;
1138 block
= grub_le_to_cpu32 (indirect_block_ptr
[indirect_block
]) *
1139 (block_size
>> GRUB_DISK_SECTOR_BITS
);
1140 grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block
);
1141 if (current_position
+ block_size
>= initial_position
)
1143 offset
= MAX ((signed) (initial_position
- current_position
),
1145 length
= (MIN (block_size
, final_position
- current_position
)
1147 grub_dprintf ("reiserfs",
1148 "Reading indirect block %u from %u to %u...\n",
1149 (unsigned) block
, (unsigned) offset
,
1150 (unsigned) (offset
+ length
));
1152 grub_dprintf ("reiserfs",
1153 "\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
1154 indirect_block
+ 1, indirect_block_count
,
1155 initial_position
, current_position
,
1156 final_position
, offset
, length
, len
);
1158 grub_disk_read (found
.data
->disk
, block
, offset
, length
, buf
);
1162 current_position
+= offset
+ length
;
1165 current_position
+= block_size
;
1167 found
.data
->disk
->read_hook
= 0;
1168 grub_free (indirect_block_ptr
);
1169 indirect_block_ptr
= 0;
1174 current_key_offset
= current_position
+ 1;
1177 grub_dprintf ("reiserfs",
1178 "Have successfully read %lld bytes (%ld requested)\n",
1179 (unsigned long long) (current_position
- initial_position
),
1180 (unsigned long) len
);
1181 return current_position
- initial_position
;
1186 case GRUB_REISERFS_DIRECT
:
1187 read_length
= MIN (len
, item_size
- file
->offset
);
1188 grub_disk_read (found
.data
->disk
,
1189 (found
.block_number
* block_size
) / GRUB_DISK_SECTOR_SIZE
,
1190 grub_le_to_cpu16 (found
.header
.item_location
) + file
->offset
,
1195 case GRUB_REISERFS_INDIRECT
:
1196 indirect_block_count
= item_size
/ sizeof (*indirect_block_ptr
);
1197 indirect_block_ptr
= grub_malloc (item_size
);
1198 if (!indirect_block_ptr
)
1200 grub_disk_read (found
.data
->disk
,
1201 (found
.block_number
* block_size
) / GRUB_DISK_SECTOR_SIZE
,
1202 grub_le_to_cpu16 (found
.header
.item_location
),
1203 item_size
, (char *) indirect_block_ptr
);
1206 len
= MIN (len
, file
->size
- file
->offset
);
1207 for (indirect_block
= file
->offset
/ block_size
;
1208 indirect_block
< indirect_block_count
&& read_length
< len
;
1211 read
= MIN (block_size
, len
- read_length
);
1212 grub_disk_read (found
.data
->disk
,
1213 (grub_le_to_cpu32 (indirect_block_ptr
[indirect_block
]) * block_size
) / GRUB_DISK_SECTOR_SIZE
,
1214 file
->offset
% block_size
, read
,
1215 ((void *) buf
) + read_length
);
1218 read_length
+= read
;
1220 grub_free (indirect_block_ptr
);
1230 grub_free (indirect_block_ptr
);
1235 grub_reiserfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1237 return grub_reiserfs_read_real (file
->data
, file
->offset
, buf
, len
,
1238 file
->read_hook
, file
->read_hook_data
);
1241 /* Close the file FILE. */
1243 grub_reiserfs_close (grub_file_t file
)
1245 struct grub_fshelp_node
*node
= file
->data
;
1246 struct grub_reiserfs_data
*data
= node
->data
;
1250 grub_dl_unref (my_mod
);
1251 return GRUB_ERR_NONE
;
1254 /* Context for grub_reiserfs_dir. */
1255 struct grub_reiserfs_dir_ctx
1257 grub_fs_dir_hook_t hook
;
1261 /* Helper for grub_reiserfs_dir. */
1263 grub_reiserfs_dir_iter (const char *filename
,
1264 enum grub_fshelp_filetype filetype
,
1265 grub_fshelp_node_t node
, void *data
)
1267 struct grub_reiserfs_dir_ctx
*ctx
= data
;
1268 struct grub_dirhook_info info
;
1270 grub_memset (&info
, 0, sizeof (info
));
1271 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
1273 info
.mtime
= node
->mtime
;
1275 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
1278 /* Call HOOK with each file under DIR. */
1280 grub_reiserfs_dir (grub_device_t device
, const char *path
,
1281 grub_fs_dir_hook_t hook
, void *hook_data
)
1283 struct grub_reiserfs_dir_ctx ctx
= { hook
, hook_data
};
1284 struct grub_reiserfs_data
*data
= 0;
1285 struct grub_fshelp_node root
, *found
;
1286 struct grub_reiserfs_key root_key
;
1288 grub_dl_ref (my_mod
);
1289 data
= grub_reiserfs_mount (device
->disk
);
1292 root_key
.directory_id
= grub_cpu_to_le32_compile_time (1);
1293 root_key
.object_id
= grub_cpu_to_le32_compile_time (2);
1294 root_key
.u
.v2
.offset_type
= 0;
1295 grub_reiserfs_set_key_type (&root_key
, GRUB_REISERFS_DIRECTORY
, 2);
1296 grub_reiserfs_set_key_offset (&root_key
, 1);
1297 if (grub_reiserfs_get_item (data
, &root_key
, &root
, 1) != GRUB_ERR_NONE
)
1299 if (root
.block_number
== 0)
1301 grub_error(GRUB_ERR_BAD_FS
, "root not found");
1304 grub_fshelp_find_file (path
, &root
, &found
, grub_reiserfs_iterate_dir
,
1305 grub_reiserfs_read_symlink
, GRUB_FSHELP_DIR
);
1308 grub_reiserfs_iterate_dir (found
, grub_reiserfs_dir_iter
, &ctx
);
1310 grub_dl_unref (my_mod
);
1311 return GRUB_ERR_NONE
;
1315 grub_dl_unref (my_mod
);
1319 /* Return the label of the device DEVICE in LABEL. The label is
1320 returned in a grub_malloc'ed buffer and should be freed by the
1323 grub_reiserfs_label (grub_device_t device
, char **label
)
1325 struct grub_reiserfs_data
*data
;
1326 grub_disk_t disk
= device
->disk
;
1328 grub_dl_ref (my_mod
);
1330 data
= grub_reiserfs_mount (disk
);
1333 *label
= grub_strndup (data
->superblock
.label
,
1334 sizeof (data
->superblock
.label
));
1339 grub_dl_unref (my_mod
);
1347 grub_reiserfs_uuid (grub_device_t device
, char **uuid
)
1349 struct grub_reiserfs_data
*data
;
1350 grub_disk_t disk
= device
->disk
;
1352 grub_dl_ref (my_mod
);
1355 data
= grub_reiserfs_mount (disk
);
1359 for (i
= 0; i
< ARRAY_SIZE (data
->superblock
.uuid
); i
++)
1360 if (data
->superblock
.uuid
[i
])
1362 if (i
< ARRAY_SIZE (data
->superblock
.uuid
))
1363 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1364 grub_be_to_cpu16 (data
->superblock
.uuid
[0]),
1365 grub_be_to_cpu16 (data
->superblock
.uuid
[1]),
1366 grub_be_to_cpu16 (data
->superblock
.uuid
[2]),
1367 grub_be_to_cpu16 (data
->superblock
.uuid
[3]),
1368 grub_be_to_cpu16 (data
->superblock
.uuid
[4]),
1369 grub_be_to_cpu16 (data
->superblock
.uuid
[5]),
1370 grub_be_to_cpu16 (data
->superblock
.uuid
[6]),
1371 grub_be_to_cpu16 (data
->superblock
.uuid
[7]));
1374 grub_dl_unref (my_mod
);
1381 static struct grub_fs grub_reiserfs_fs
=
1384 .dir
= grub_reiserfs_dir
,
1385 .open
= grub_reiserfs_open
,
1386 .read
= grub_reiserfs_read
,
1387 .close
= grub_reiserfs_close
,
1388 .label
= grub_reiserfs_label
,
1389 .uuid
= grub_reiserfs_uuid
,
1391 .reserved_first_sector
= 1,
1392 .blocklist_install
= 1,
1397 GRUB_MOD_INIT(reiserfs
)
1399 grub_fs_register (&grub_reiserfs_fs
);
1403 GRUB_MOD_FINI(reiserfs
)
1405 grub_fs_unregister (&grub_reiserfs_fs
);