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>
43 ({ typeof (a) _a = (a); \
44 typeof (b) _b = (b); \
48 ({ typeof (a) _a = (a); \
49 typeof (b) _b = (b); \
52 #define REISERFS_SUPER_BLOCK_OFFSET 0x10000
53 #define REISERFS_MAGIC_LEN 12
54 #define REISERFS_MAGIC_STRING "ReIsEr"
55 #define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
56 /* If the 3rd bit of an item state is set, then it's visible. */
57 #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
58 #define REISERFS_MAX_LABEL_LENGTH 16
59 #define REISERFS_LABEL_OFFSET 0x64
61 #define S_IFLNK 0xA000
63 static grub_dl_t my_mod
;
65 #define assert(boolean) real_assert (boolean, __FILE__, __LINE__)
67 real_assert (int boolean
, const char *file
, const int line
)
70 grub_printf ("Assertion failed at %s:%d\n", file
, line
);
73 enum grub_reiserfs_item_type
76 GRUB_REISERFS_DIRECTORY
,
78 GRUB_REISERFS_INDIRECT
,
79 /* Matches both _DIRECT and _INDIRECT when searching. */
84 struct grub_reiserfs_superblock
86 grub_uint32_t block_count
;
87 grub_uint32_t block_free_count
;
88 grub_uint32_t root_block
;
89 grub_uint32_t journal_block
;
90 grub_uint32_t journal_device
;
91 grub_uint32_t journal_original_size
;
92 grub_uint32_t journal_max_transaction_size
;
93 grub_uint32_t journal_block_count
;
94 grub_uint32_t journal_max_batch
;
95 grub_uint32_t journal_max_commit_age
;
96 grub_uint32_t journal_max_transaction_age
;
97 grub_uint16_t block_size
;
98 grub_uint16_t oid_max_size
;
99 grub_uint16_t oid_current_size
;
101 grub_uint8_t magic_string
[REISERFS_MAGIC_LEN
];
102 grub_uint32_t function_hash_code
;
103 grub_uint16_t tree_height
;
104 grub_uint16_t bitmap_number
;
105 grub_uint16_t version
;
106 grub_uint16_t reserved
;
107 grub_uint32_t inode_generation
;
108 grub_uint8_t unused
[4];
109 grub_uint16_t uuid
[8];
110 } __attribute__ ((packed
));
112 struct grub_reiserfs_journal_header
114 grub_uint32_t last_flush_uid
;
115 grub_uint32_t unflushed_offset
;
116 grub_uint32_t mount_id
;
117 } __attribute__ ((packed
));
119 struct grub_reiserfs_description_block
123 grub_uint32_t mount_id
;
124 grub_uint32_t real_blocks
[0];
125 } __attribute__ ((packed
));
127 struct grub_reiserfs_commit_block
131 grub_uint32_t real_blocks
[0];
132 } __attribute__ ((packed
));
134 struct grub_reiserfs_stat_item_v1
137 grub_uint16_t hardlink_count
;
145 grub_uint32_t first_direct_byte
;
146 } __attribute__ ((packed
));
148 struct grub_reiserfs_stat_item_v2
151 grub_uint16_t reserved
;
152 grub_uint32_t hardlink_count
;
159 grub_uint32_t blocks
;
160 grub_uint32_t first_direct_byte
;
161 } __attribute__ ((packed
));
163 struct grub_reiserfs_key
165 grub_uint32_t directory_id
;
166 grub_uint32_t object_id
;
171 grub_uint32_t offset
;
173 } v1
__attribute__ ((packed
));
176 grub_uint64_t offset_type
;
177 } v2
__attribute__ ((packed
));
179 } __attribute__ ((packed
));
181 struct grub_reiserfs_item_header
183 struct grub_reiserfs_key key
;
186 grub_uint16_t free_space
;
187 grub_uint16_t entry_count
;
188 } u
__attribute__ ((packed
));
189 grub_uint16_t item_size
;
190 grub_uint16_t item_location
;
191 grub_uint16_t version
;
192 } __attribute__ ((packed
));
194 struct grub_reiserfs_block_header
197 grub_uint16_t item_count
;
198 grub_uint16_t free_space
;
199 grub_uint16_t reserved
;
200 struct grub_reiserfs_key block_right_delimiting_key
;
201 } __attribute__ ((packed
));
203 struct grub_reiserfs_disk_child
205 grub_uint32_t block_number
;
207 grub_uint16_t reserved
;
208 } __attribute__ ((packed
));
210 struct grub_reiserfs_directory_header
212 grub_uint32_t offset
;
213 grub_uint32_t directory_id
;
214 grub_uint32_t object_id
;
215 grub_uint16_t location
;
217 } __attribute__ ((packed
));
219 struct grub_fshelp_node
221 struct grub_reiserfs_data
*data
;
222 grub_uint32_t block_number
; /* 0 if node is not found. */
223 grub_uint16_t block_position
;
224 grub_uint64_t next_offset
;
225 enum grub_reiserfs_item_type type
; /* To know how to read the header. */
226 struct grub_reiserfs_item_header header
;
229 /* Returned when opening a file. */
230 struct grub_reiserfs_data
232 struct grub_reiserfs_superblock superblock
;
236 /* Internal-only functions. Not to be used outside of this file. */
238 /* Return the type of given v2 key. */
239 static enum grub_reiserfs_item_type
240 grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key
*key
)
242 switch (grub_le_to_cpu64 (key
->u
.v2
.offset_type
) >> 60)
245 return GRUB_REISERFS_STAT
;
247 return GRUB_REISERFS_ANY
;
249 return GRUB_REISERFS_DIRECTORY
;
251 return GRUB_REISERFS_DIRECT
;
253 return GRUB_REISERFS_INDIRECT
;
255 return GRUB_REISERFS_UNKNOWN
;
258 /* Return the type of given v1 key. */
259 static enum grub_reiserfs_item_type
260 grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key
*key
)
262 switch (grub_le_to_cpu32 (key
->u
.v1
.type
))
265 return GRUB_REISERFS_STAT
;
267 return GRUB_REISERFS_ANY
;
269 return GRUB_REISERFS_DIRECTORY
;
272 return GRUB_REISERFS_DIRECT
;
275 return GRUB_REISERFS_INDIRECT
;
277 return GRUB_REISERFS_UNKNOWN
;
280 /* Return 1 if the given key is version 1 key, 2 otherwise. */
282 grub_reiserfs_get_key_version (const struct grub_reiserfs_key
*key
)
284 return grub_reiserfs_get_key_v1_type (key
) == GRUB_REISERFS_UNKNOWN
? 2 : 1;
289 grub_hexdump (char *buffer
, grub_size_t len
)
292 for (a
= 0; a
< len
; a
++)
295 grub_printf ("\n%08x ", a
);
296 grub_printf ("%02x ",
297 ((unsigned int) ((unsigned char *) buffer
)[a
]) & 0xFF);
303 #ifdef GRUB_REISERFS_DEBUG
305 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
);
307 static enum grub_reiserfs_item_type
308 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
);
311 grub_reiserfs_print_key (const struct grub_reiserfs_key
*key
)
314 char *reiserfs_type_strings
[] = {
323 for (a
= 0; a
< sizeof (struct grub_reiserfs_key
); a
++)
324 grub_printf ("%02x ", ((unsigned int) ((unsigned char *) key
)[a
]) & 0xFF);
325 grub_printf ("parent id = 0x%08x, self id = 0x%08x, type = %s, offset = ",
326 grub_le_to_cpu32 (key
->directory_id
),
327 grub_le_to_cpu32 (key
->object_id
),
328 reiserfs_type_strings
[grub_reiserfs_get_key_type (key
)]);
329 if (grub_reiserfs_get_key_version (key
) == 1)
330 grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset (key
));
332 grub_printf("0x%07x%08x",
333 (unsigned) (grub_reiserfs_get_key_offset (key
) >> 32),
334 (unsigned) (grub_reiserfs_get_key_offset (key
) & 0xFFFFFFFF));
339 /* Return the offset of given key. */
341 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
)
343 if (grub_reiserfs_get_key_version (key
) == 1)
344 return grub_le_to_cpu32 (key
->u
.v1
.offset
);
346 return grub_le_to_cpu64 (key
->u
.v2
.offset_type
) & (~0ULL >> 4);
349 /* Set the offset of given key. */
351 grub_reiserfs_set_key_offset (struct grub_reiserfs_key
*key
,
354 if (grub_reiserfs_get_key_version (key
) == 1)
355 key
->u
.v1
.offset
= grub_cpu_to_le32 (value
);
357 key
->u
.v2
.offset_type \
358 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64 (15ULL << 60))
359 | grub_cpu_to_le64 (value
& (~0ULL >> 4)));
362 /* Return the type of given key. */
363 static enum grub_reiserfs_item_type
364 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
)
366 if (grub_reiserfs_get_key_version (key
) == 1)
367 return grub_reiserfs_get_key_v1_type (key
);
369 return grub_reiserfs_get_key_v2_type (key
);
372 /* Set the type of given key, with given version number. */
374 grub_reiserfs_set_key_type (struct grub_reiserfs_key
*key
,
375 enum grub_reiserfs_item_type grub_type
,
382 case GRUB_REISERFS_STAT
:
385 case GRUB_REISERFS_ANY
:
386 type
= (version
== 1) ? 555 : 15;
388 case GRUB_REISERFS_DIRECTORY
:
389 type
= (version
== 1) ? 500 : 3;
391 case GRUB_REISERFS_DIRECT
:
392 type
= (version
== 1) ? 0xFFFFFFFF : 2;
394 case GRUB_REISERFS_INDIRECT
:
395 type
= (version
== 1) ? 0xFFFFFFFE : 1;
402 key
->u
.v1
.type
= grub_cpu_to_le32 (type
);
404 key
->u
.v2
.offset_type
405 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64 (~0ULL >> 4))
406 | grub_cpu_to_le64 ((grub_uint64_t
) type
<< 60));
408 assert (grub_reiserfs_get_key_type (key
) == grub_type
);
411 /* -1 if key 1 if lower than key 2.
412 0 if key 1 is equal to key 2.
413 1 if key 1 is higher than key 2. */
415 grub_reiserfs_compare_keys (const struct grub_reiserfs_key
*key1
,
416 const struct grub_reiserfs_key
*key2
)
418 grub_uint64_t offset1
, offset2
;
419 enum grub_reiserfs_item_type type1
, type2
;
420 grub_uint32_t id1
, id2
;
422 if (! key1
|| ! key2
)
425 id1
= grub_le_to_cpu32 (key1
->directory_id
);
426 id2
= grub_le_to_cpu32 (key2
->directory_id
);
432 id1
= grub_le_to_cpu32 (key1
->object_id
);
433 id2
= grub_le_to_cpu32 (key2
->object_id
);
439 offset1
= grub_reiserfs_get_key_offset (key1
);
440 offset2
= grub_reiserfs_get_key_offset (key2
);
441 if (offset1
< offset2
)
443 if (offset1
> offset2
)
446 type1
= grub_reiserfs_get_key_type (key1
);
447 type2
= grub_reiserfs_get_key_type (key2
);
448 if ((type1
== GRUB_REISERFS_ANY
449 && (type2
== GRUB_REISERFS_DIRECT
450 || type2
== GRUB_REISERFS_INDIRECT
))
451 || (type2
== GRUB_REISERFS_ANY
452 && (type1
== GRUB_REISERFS_DIRECT
453 || type1
== GRUB_REISERFS_INDIRECT
)))
463 /* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
464 accordingly to what was found. */
466 grub_reiserfs_get_item (struct grub_reiserfs_data
*data
,
467 const struct grub_reiserfs_key
*key
,
468 struct grub_fshelp_node
*item
)
470 grub_uint32_t block_number
;
471 struct grub_reiserfs_block_header
*block_header
= 0;
472 struct grub_reiserfs_key
*block_key
= 0;
473 grub_uint16_t block_size
, item_count
, current_level
;
475 grub_uint16_t previous_level
= ~0;
476 struct grub_reiserfs_item_header
*item_headers
= 0;
480 grub_error (GRUB_ERR_TEST_FAILURE
, "data is NULL");
486 grub_error (GRUB_ERR_TEST_FAILURE
, "key is NULL");
492 grub_error (GRUB_ERR_TEST_FAILURE
, "item is NULL");
496 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
497 block_number
= grub_le_to_cpu32 (data
->superblock
.root_block
);
498 #ifdef GRUB_REISERFS_DEBUG
499 grub_printf("Searching for ");
500 grub_reiserfs_print_key (key
);
502 block_header
= grub_malloc (block_size
);
506 item
->next_offset
= 0;
509 grub_disk_read (data
->disk
,
510 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
511 (((grub_off_t
) block_number
* block_size
)
512 & (GRUB_DISK_SECTOR_SIZE
- 1)),
513 block_size
, block_header
);
516 current_level
= grub_le_to_cpu16 (block_header
->level
);
517 grub_dprintf ("reiserfs_tree", " at level %d\n", current_level
);
518 if (current_level
>= previous_level
)
520 grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
521 grub_error (GRUB_ERR_FILE_READ_ERROR
, "level loop");
524 previous_level
= current_level
;
525 item_count
= grub_le_to_cpu16 (block_header
->item_count
);
526 grub_dprintf ("reiserfs_tree", " number of contained items : %d\n",
528 if (current_level
> 1)
530 /* Internal node. Navigate to the child that should contain
532 struct grub_reiserfs_key
*keys
533 = (struct grub_reiserfs_key
*) (block_header
+ 1);
534 struct grub_reiserfs_disk_child
*children
535 = ((struct grub_reiserfs_disk_child
*)
536 (keys
+ item_count
));
540 && grub_reiserfs_compare_keys (key
, &(keys
[i
])) >= 0;
543 #ifdef GRUB_REISERFS_DEBUG
544 grub_printf("i %03d/%03d ", i
+ 1, item_count
+ 1);
545 grub_reiserfs_print_key (&(keys
[i
]));
548 block_number
= grub_le_to_cpu32 (children
[i
].block_number
);
549 if ((i
< item_count
) && (key
->directory_id
== keys
[i
].directory_id
)
550 && (key
->object_id
== keys
[i
].object_id
))
551 item
->next_offset
= grub_reiserfs_get_key_offset(&(keys
[i
]));
552 #ifdef GRUB_REISERFS_DEBUG
554 || grub_reiserfs_compare_keys (key
, &(keys
[i
])) == 0)
560 grub_printf (" %03d/%03d ", i
+ 1, item_count
+ 1);
561 grub_reiserfs_print_key (&(keys
[i
]));
562 if (i
+ 1 < item_count
)
564 grub_printf ("+ %03d/%03d ", i
+ 2, item_count
);
565 grub_reiserfs_print_key (&(keys
[i
+ 1]));
569 grub_printf ("Accessing rightmost child at block %d.\n",
575 /* Leaf node. Check that the key is actually present. */
577 = (struct grub_reiserfs_item_header
*) (block_header
+ 1);
580 && (grub_reiserfs_compare_keys (key
, &(item_headers
[i
].key
))
584 #ifdef GRUB_REISERFS_DEBUG
585 if (key
->directory_id
== item_headers
[i
].key
.directory_id
&& \
586 key
->object_id
== item_headers
[i
].key
.object_id
)
590 grub_printf(" %03d/%03d ", i
+ 1, item_count
);
591 grub_reiserfs_print_key (&(item_headers
[i
].key
));
595 block_key
= &(item_headers
[i
].key
);
598 while (current_level
> 1);
602 if (i
== item_count
|| grub_reiserfs_compare_keys (key
, block_key
))
604 item
->block_number
= 0;
605 item
->block_position
= 0;
606 item
->type
= GRUB_REISERFS_UNKNOWN
;
607 #ifdef GRUB_REISERFS_DEBUG
608 grub_printf("Not found.\n");
613 item
->block_number
= block_number
;
614 item
->block_position
= i
;
615 item
->type
= grub_reiserfs_get_key_type (block_key
);
616 grub_memcpy (&(item
->header
), &(item_headers
[i
]),
617 sizeof (struct grub_reiserfs_item_header
));
618 #ifdef GRUB_REISERFS_DEBUG
619 grub_printf ("F %03d/%03d ", i
+ 1, item_count
);
620 grub_reiserfs_print_key (block_key
);
624 assert (grub_errno
== GRUB_ERR_NONE
);
625 grub_free (block_header
);
626 return GRUB_ERR_NONE
;
629 assert (grub_errno
!= GRUB_ERR_NONE
);
630 grub_free (block_header
);
631 assert (grub_errno
!= GRUB_ERR_NONE
);
635 /* Return the path of the file which is pointed at by symlink NODE. */
637 grub_reiserfs_read_symlink (grub_fshelp_node_t node
)
639 char *symlink_buffer
= 0;
640 grub_uint16_t block_size
;
641 grub_disk_addr_t block
;
644 struct grub_fshelp_node found
;
645 struct grub_reiserfs_key key
;
647 grub_memcpy (&key
, &(node
->header
.key
), sizeof (key
));
648 grub_reiserfs_set_key_offset (&key
, 1);
649 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_DIRECT
,
650 grub_reiserfs_get_key_version (&key
));
652 if (grub_reiserfs_get_item (node
->data
, &key
, &found
) != GRUB_ERR_NONE
)
655 if (found
.block_number
== 0)
658 block_size
= grub_le_to_cpu16 (node
->data
->superblock
.block_size
);
659 len
= grub_le_to_cpu16 (found
.header
.item_size
);
660 block
= found
.block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
);
661 offset
= grub_le_to_cpu16 (found
.header
.item_location
);
663 symlink_buffer
= grub_malloc (len
+ 1);
664 if (! symlink_buffer
)
667 grub_disk_read (node
->data
->disk
, block
, offset
, len
, symlink_buffer
);
671 symlink_buffer
[len
] = 0;
672 return symlink_buffer
;
675 grub_free (symlink_buffer
);
679 /* Fill the mounted filesystem structure and return it. */
680 static struct grub_reiserfs_data
*
681 grub_reiserfs_mount (grub_disk_t disk
)
683 struct grub_reiserfs_data
*data
= 0;
684 data
= grub_malloc (sizeof (*data
));
687 grub_disk_read (disk
, REISERFS_SUPER_BLOCK_OFFSET
/ GRUB_DISK_SECTOR_SIZE
,
688 0, sizeof (data
->superblock
), &(data
->superblock
));
691 if (grub_memcmp (data
->superblock
.magic_string
,
692 REISERFS_MAGIC_STRING
, sizeof (REISERFS_MAGIC_STRING
) - 1))
694 grub_error (GRUB_ERR_BAD_FS
, "not a reiserfs filesystem");
701 /* Disk is too small to contain a ReiserFS. */
702 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
703 grub_error (GRUB_ERR_BAD_FS
, "not a reiserfs filesystem");
709 /* Call HOOK for each file in directory ITEM. */
711 grub_reiserfs_iterate_dir (grub_fshelp_node_t item
,
713 (*hook
) (const char *filename
,
714 enum grub_fshelp_filetype filetype
,
715 grub_fshelp_node_t node
))
717 struct grub_reiserfs_data
*data
= item
->data
;
718 struct grub_reiserfs_block_header
*block_header
= 0;
719 grub_uint16_t block_size
, block_position
;
720 grub_uint32_t block_number
;
721 grub_uint64_t next_offset
= item
->next_offset
;
724 if (item
->type
!= GRUB_REISERFS_DIRECTORY
)
726 grub_error (GRUB_ERR_BAD_FILE_TYPE
,
727 "grub_reiserfs_iterate_dir called on a non-directory item");
730 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
731 block_header
= grub_malloc (block_size
);
734 block_number
= item
->block_number
;
735 block_position
= item
->block_position
;
736 grub_dprintf ("reiserfs", "Iterating directory...\n");
739 struct grub_reiserfs_directory_header
*directory_headers
;
740 struct grub_fshelp_node directory_item
;
741 grub_uint16_t entry_count
, entry_number
;
742 struct grub_reiserfs_item_header
*item_headers
;
744 grub_disk_read (data
->disk
,
745 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
746 (((grub_off_t
) block_number
* block_size
)
747 & (GRUB_DISK_SECTOR_SIZE
- 1)),
748 block_size
, (char *) block_header
);
753 if (grub_le_to_cpu16 (block_header
->level
) != 1)
755 grub_error (GRUB_ERR_TEST_FAILURE
,
756 "reiserfs: block %d is not a leaf block",
762 item_headers
= (struct grub_reiserfs_item_header
*) (block_header
+ 1);
764 = ((struct grub_reiserfs_directory_header
*)
765 ((char *) block_header
766 + grub_le_to_cpu16 (item_headers
[block_position
].item_location
)));
768 = grub_le_to_cpu16 (item_headers
[block_position
].u
.entry_count
);
769 for (entry_number
= 0; entry_number
< entry_count
; entry_number
++)
771 struct grub_reiserfs_directory_header
*directory_header
772 = &directory_headers
[entry_number
];
773 grub_uint16_t entry_state
774 = grub_le_to_cpu16 (directory_header
->state
);
776 if (entry_state
& GRUB_REISERFS_VISIBLE_MASK
)
778 grub_fshelp_node_t entry_item
;
779 struct grub_reiserfs_key entry_key
;
780 enum grub_reiserfs_item_type entry_type
;
783 entry_name
= (((char *) directory_headers
)
784 + grub_le_to_cpu16 (directory_header
->location
));
785 entry_key
.directory_id
= directory_header
->directory_id
;
786 entry_key
.object_id
= directory_header
->object_id
;
787 entry_key
.u
.v2
.offset_type
= 0;
788 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_DIRECTORY
,
790 grub_reiserfs_set_key_offset (&entry_key
, 1);
792 entry_item
= grub_malloc (sizeof (*entry_item
));
796 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
)
799 grub_free (entry_item
);
803 if (entry_item
->type
== GRUB_REISERFS_DIRECTORY
)
804 entry_type
= GRUB_FSHELP_DIR
;
807 grub_uint32_t entry_block_number
;
808 /* Order is very important here.
809 First set the offset to 0 using current key version.
810 Then change the key type, which affects key version
812 grub_reiserfs_set_key_offset (&entry_key
, 0);
813 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_STAT
,
815 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
)
818 grub_free (entry_item
);
822 if (entry_item
->block_number
!= 0)
824 grub_uint16_t entry_version
;
826 = grub_le_to_cpu16 (entry_item
->header
.version
);
827 entry_block_number
= entry_item
->block_number
;
829 grub_dprintf ("reiserfs",
830 "version %04x block %08x (%08x) position %08x\n",
831 entry_version
, entry_block_number
,
832 ((grub_disk_addr_t
) entry_block_number
* block_size
) / GRUB_DISK_SECTOR_SIZE
,
833 grub_le_to_cpu16 (entry_item
->header
.item_location
));
835 if (entry_version
== 0) /* Version 1 stat item. */
837 struct grub_reiserfs_stat_item_v1 entry_v1_stat
;
838 grub_disk_read (data
->disk
,
839 entry_block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
840 grub_le_to_cpu16 (entry_item
->header
.item_location
),
841 sizeof (entry_v1_stat
),
842 (char *) &entry_v1_stat
);
846 grub_dprintf ("reiserfs",
847 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
848 grub_le_to_cpu16 (entry_v1_stat
.mode
),
849 grub_le_to_cpu16 (entry_v1_stat
.hardlink_count
),
850 grub_le_to_cpu16 (entry_v1_stat
.uid
),
851 grub_le_to_cpu16 (entry_v1_stat
.gid
),
852 grub_le_to_cpu32 (entry_v1_stat
.size
),
853 grub_le_to_cpu32 (entry_v1_stat
.atime
),
854 grub_le_to_cpu32 (entry_v1_stat
.mtime
),
855 grub_le_to_cpu32 (entry_v1_stat
.ctime
),
856 grub_le_to_cpu32 (entry_v1_stat
.rdev
),
857 grub_le_to_cpu32 (entry_v1_stat
.first_direct_byte
));
858 grub_dprintf ("reiserfs",
859 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
861 entry_v1_stat
.hardlink_count
,
869 entry_v1_stat
.first_direct_byte
);
871 if ((grub_le_to_cpu16 (entry_v1_stat
.mode
) & S_IFLNK
)
873 entry_type
= GRUB_FSHELP_SYMLINK
;
875 entry_type
= GRUB_FSHELP_REG
;
879 struct grub_reiserfs_stat_item_v2 entry_v2_stat
;
880 grub_disk_read (data
->disk
,
881 entry_block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
882 grub_le_to_cpu16 (entry_item
->header
.item_location
),
883 sizeof (entry_v2_stat
),
884 (char *) &entry_v2_stat
);
888 grub_dprintf ("reiserfs",
889 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
890 grub_le_to_cpu16 (entry_v2_stat
.mode
),
891 grub_le_to_cpu16 (entry_v2_stat
.reserved
),
892 grub_le_to_cpu32 (entry_v2_stat
.hardlink_count
),
893 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) >> 32),
894 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) && 0xFFFFFFFF),
895 grub_le_to_cpu32 (entry_v2_stat
.uid
),
896 grub_le_to_cpu32 (entry_v2_stat
.gid
),
897 grub_le_to_cpu32 (entry_v2_stat
.atime
),
898 grub_le_to_cpu32 (entry_v2_stat
.mtime
),
899 grub_le_to_cpu32 (entry_v2_stat
.ctime
),
900 grub_le_to_cpu32 (entry_v2_stat
.blocks
),
901 grub_le_to_cpu32 (entry_v2_stat
.first_direct_byte
));
902 grub_dprintf ("reiserfs",
903 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
905 entry_v2_stat
.reserved
,
906 entry_v2_stat
.hardlink_count
,
907 (unsigned int) (entry_v2_stat
.size
>> 32),
908 (unsigned int) (entry_v2_stat
.size
&& 0xFFFFFFFF),
914 entry_v2_stat
.blocks
,
915 entry_v2_stat
.first_direct_byte
);
917 if ((grub_le_to_cpu16 (entry_v2_stat
.mode
) & S_IFLNK
)
919 entry_type
= GRUB_FSHELP_SYMLINK
;
921 entry_type
= GRUB_FSHELP_REG
;
926 /* Pseudo file ".." never has stat block. */
927 if (grub_strcmp (entry_name
, ".."))
928 grub_dprintf ("reiserfs",
929 "Warning : %s has no stat block !\n",
931 grub_free (entry_item
);
935 if (hook (entry_name
, entry_type
, entry_item
))
937 grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
938 entry_name
, entry_type
);
943 *entry_name
= 0; /* Make sure next entry name (which is just
944 before this one in disk order) stops before
949 if (next_offset
== 0)
952 grub_reiserfs_set_key_offset (&(item_headers
[block_position
].key
),
954 if (grub_reiserfs_get_item (data
, &(item_headers
[block_position
].key
),
955 &directory_item
) != GRUB_ERR_NONE
)
957 block_number
= directory_item
.block_number
;
958 block_position
= directory_item
.block_position
;
959 next_offset
= directory_item
.next_offset
;
961 while (block_number
);
964 assert (grub_errno
== GRUB_ERR_NONE
);
965 grub_free (block_header
);
968 assert (grub_errno
!= GRUB_ERR_NONE
);
969 grub_free (block_header
);
973 /****************************************************************************/
974 /* grub api functions */
975 /****************************************************************************/
977 /* Open a file named NAME and initialize FILE. */
979 grub_reiserfs_open (struct grub_file
*file
, const char *name
)
981 struct grub_reiserfs_data
*data
= 0;
982 struct grub_fshelp_node root
, *found
= 0, info
;
983 struct grub_reiserfs_key key
;
984 grub_uint32_t block_number
;
985 grub_uint16_t entry_version
, block_size
, entry_location
;
987 grub_dl_ref (my_mod
);
988 data
= grub_reiserfs_mount (file
->device
->disk
);
991 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
992 key
.directory_id
= grub_cpu_to_le32 (1);
993 key
.object_id
= grub_cpu_to_le32 (2);
994 key
.u
.v2
.offset_type
= 0;
995 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_DIRECTORY
, 2);
996 grub_reiserfs_set_key_offset (&key
, 1);
997 if (grub_reiserfs_get_item (data
, &key
, &root
) != GRUB_ERR_NONE
)
999 if (root
.block_number
== 0)
1001 grub_error (GRUB_ERR_BAD_FS
, "Unable to find root item");
1002 goto fail
; /* Should never happen since checked at mount. */
1004 grub_fshelp_find_file (name
, &root
, &found
,
1005 grub_reiserfs_iterate_dir
,
1006 grub_reiserfs_read_symlink
, GRUB_FSHELP_REG
);
1009 key
.directory_id
= found
->header
.key
.directory_id
;
1010 key
.object_id
= found
->header
.key
.object_id
;
1011 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_STAT
, 2);
1012 grub_reiserfs_set_key_offset (&key
, 0);
1013 if (grub_reiserfs_get_item (data
, &key
, &info
) != GRUB_ERR_NONE
)
1015 if (info
.block_number
== 0)
1017 grub_error (GRUB_ERR_BAD_FS
, "Unable to find searched item");
1020 entry_version
= grub_le_to_cpu16 (info
.header
.version
);
1021 entry_location
= grub_le_to_cpu16 (info
.header
.item_location
);
1022 block_number
= info
.block_number
;
1023 if (entry_version
== 0) /* Version 1 stat item. */
1025 struct grub_reiserfs_stat_item_v1 entry_v1_stat
;
1026 grub_disk_read (data
->disk
,
1027 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
1029 + (((grub_off_t
) block_number
* block_size
)
1030 & (GRUB_DISK_SECTOR_SIZE
- 1)),
1031 sizeof (entry_v1_stat
), &entry_v1_stat
);
1034 file
->size
= (grub_off_t
) grub_le_to_cpu64 (entry_v1_stat
.size
);
1038 struct grub_reiserfs_stat_item_v2 entry_v2_stat
;
1039 grub_disk_read (data
->disk
,
1040 block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
1042 + (((grub_off_t
) block_number
* block_size
)
1043 & (GRUB_DISK_SECTOR_SIZE
- 1)),
1044 sizeof (entry_v2_stat
), &entry_v2_stat
);
1047 file
->size
= (grub_off_t
) grub_le_to_cpu64 (entry_v2_stat
.size
);
1049 grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
1050 (unsigned int) file
->size
,
1051 (unsigned int) (file
->size
>> 32), (unsigned int) file
->size
);
1054 return GRUB_ERR_NONE
;
1057 assert (grub_errno
!= GRUB_ERR_NONE
);
1060 grub_dl_unref (my_mod
);
1065 grub_reiserfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1067 unsigned int indirect_block
, indirect_block_count
;
1068 struct grub_reiserfs_key key
;
1069 struct grub_fshelp_node
*node
= file
->data
;
1070 struct grub_reiserfs_data
*data
= node
->data
;
1071 struct grub_fshelp_node found
;
1072 grub_uint16_t block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
1073 grub_uint16_t item_size
;
1074 grub_uint32_t
*indirect_block_ptr
= 0;
1075 grub_uint64_t current_key_offset
= 1;
1076 grub_off_t initial_position
, current_position
, final_position
, length
;
1077 grub_disk_addr_t block
;
1080 if (file
->offset
>= file
->size
)
1083 key
.directory_id
= node
->header
.key
.directory_id
;
1084 key
.object_id
= node
->header
.key
.object_id
;
1085 key
.u
.v2
.offset_type
= 0;
1086 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_ANY
, 2);
1087 initial_position
= file
->offset
;
1088 current_position
= 0;
1089 final_position
= MIN (len
+ initial_position
, file
->size
);
1090 grub_dprintf ("reiserfs",
1091 "Reading from %lld to %lld (%lld instead of requested %ld)\n",
1092 (unsigned long long) initial_position
,
1093 (unsigned long long) final_position
,
1094 (unsigned long long) (final_position
- initial_position
),
1095 (unsigned long) len
);
1096 while (current_position
< final_position
)
1098 grub_reiserfs_set_key_offset (&key
, current_key_offset
);
1100 if (grub_reiserfs_get_item (data
, &key
, &found
) != GRUB_ERR_NONE
)
1102 if (found
.block_number
== 0)
1104 item_size
= grub_le_to_cpu16 (found
.header
.item_size
);
1107 case GRUB_REISERFS_DIRECT
:
1108 block
= found
.block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
);
1109 grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block
);
1110 if (initial_position
< current_position
+ item_size
)
1112 offset
= MAX ((signed) (initial_position
- current_position
), 0);
1113 length
= (MIN (item_size
, final_position
- current_position
)
1115 grub_dprintf ("reiserfs",
1116 "Reading direct block %u from %u to %u...\n",
1117 (unsigned) block
, (unsigned) offset
,
1118 (unsigned) (offset
+ length
));
1119 found
.data
->disk
->read_hook
= file
->read_hook
;
1120 grub_disk_read (found
.data
->disk
,
1123 + grub_le_to_cpu16 (found
.header
.item_location
),
1125 found
.data
->disk
->read_hook
= 0;
1129 current_position
+= offset
+ length
;
1132 current_position
+= item_size
;
1134 case GRUB_REISERFS_INDIRECT
:
1135 indirect_block_count
= item_size
/ sizeof (*indirect_block_ptr
);
1136 indirect_block_ptr
= grub_malloc (item_size
);
1137 if (! indirect_block_ptr
)
1139 grub_disk_read (found
.data
->disk
,
1140 found
.block_number
* (block_size
>> GRUB_DISK_SECTOR_BITS
),
1141 grub_le_to_cpu16 (found
.header
.item_location
),
1142 item_size
, indirect_block_ptr
);
1145 found
.data
->disk
->read_hook
= file
->read_hook
;
1146 for (indirect_block
= 0;
1147 indirect_block
< indirect_block_count
1148 && current_position
< final_position
;
1151 block
= grub_le_to_cpu32 (indirect_block_ptr
[indirect_block
]) *
1152 (block_size
>> GRUB_DISK_SECTOR_BITS
);
1153 grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block
);
1154 if (current_position
+ block_size
>= initial_position
)
1156 offset
= MAX ((signed) (initial_position
- current_position
),
1158 length
= (MIN (block_size
, final_position
- current_position
)
1160 grub_dprintf ("reiserfs",
1161 "Reading indirect block %u from %u to %u...\n",
1162 (unsigned) block
, (unsigned) offset
,
1163 (unsigned) (offset
+ length
));
1165 grub_dprintf ("reiserfs",
1166 "\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
1167 indirect_block
+ 1, indirect_block_count
,
1168 initial_position
, current_position
,
1169 final_position
, offset
, length
, len
);
1171 grub_disk_read (found
.data
->disk
, block
, offset
, length
, buf
);
1175 current_position
+= offset
+ length
;
1178 current_position
+= block_size
;
1180 found
.data
->disk
->read_hook
= 0;
1181 grub_free (indirect_block_ptr
);
1182 indirect_block_ptr
= 0;
1187 current_key_offset
= current_position
+ 1;
1190 grub_dprintf ("reiserfs",
1191 "Have successfully read %lld bytes (%ld requested)\n",
1192 (unsigned long long) (current_position
- initial_position
),
1193 (unsigned long) len
);
1194 return current_position
- initial_position
;
1198 case GRUB_REISERFS_DIRECT:
1199 read_length = MIN (len, item_size - file->offset);
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) + file->offset,
1207 case GRUB_REISERFS_INDIRECT:
1208 indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1209 indirect_block_ptr = grub_malloc (item_size);
1210 if (!indirect_block_ptr)
1212 grub_disk_read (found.data->disk,
1213 (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1214 grub_le_to_cpu16 (found.header.item_location),
1215 item_size, (char *) indirect_block_ptr);
1218 len = MIN (len, file->size - file->offset);
1219 for (indirect_block = file->offset / block_size;
1220 indirect_block < indirect_block_count && read_length < len;
1223 read = MIN (block_size, len - read_length);
1224 grub_disk_read (found.data->disk,
1225 (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
1226 file->offset % block_size, read,
1227 ((void *) buf) + read_length);
1230 read_length += read;
1232 grub_free (indirect_block_ptr);
1238 return read_length;*/
1241 grub_free (indirect_block_ptr
);
1245 /* Close the file FILE. */
1247 grub_reiserfs_close (grub_file_t file
)
1249 struct grub_fshelp_node
*node
= file
->data
;
1250 struct grub_reiserfs_data
*data
= node
->data
;
1254 grub_dl_unref (my_mod
);
1255 return GRUB_ERR_NONE
;
1258 /* Call HOOK with each file under DIR. */
1260 grub_reiserfs_dir (grub_device_t device
, const char *path
,
1261 int (*hook
) (const char *filename
,
1262 const struct grub_dirhook_info
*info
))
1264 struct grub_reiserfs_data
*data
= 0;
1265 struct grub_fshelp_node root
, *found
;
1266 struct grub_reiserfs_key root_key
;
1268 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
1269 enum grub_fshelp_filetype filetype
,
1270 grub_fshelp_node_t node
);
1272 int NESTED_FUNC_ATTR
iterate (const char *filename
,
1273 enum grub_fshelp_filetype filetype
,
1274 grub_fshelp_node_t node
)
1276 struct grub_dirhook_info info
;
1277 grub_memset (&info
, 0, sizeof (info
));
1278 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
1280 return hook (filename
, &info
);
1282 grub_dl_ref (my_mod
);
1283 data
= grub_reiserfs_mount (device
->disk
);
1286 root_key
.directory_id
= grub_cpu_to_le32 (1);
1287 root_key
.object_id
= grub_cpu_to_le32 (2);
1288 root_key
.u
.v2
.offset_type
= 0;
1289 grub_reiserfs_set_key_type (&root_key
, GRUB_REISERFS_DIRECTORY
, 2);
1290 grub_reiserfs_set_key_offset (&root_key
, 1);
1291 if (grub_reiserfs_get_item (data
, &root_key
, &root
) != GRUB_ERR_NONE
)
1293 if (root
.block_number
== 0)
1295 grub_error(GRUB_ERR_BAD_FS
, "Root not found");
1298 grub_fshelp_find_file (path
, &root
, &found
, grub_reiserfs_iterate_dir
,
1299 grub_reiserfs_read_symlink
, GRUB_FSHELP_DIR
);
1302 grub_reiserfs_iterate_dir (found
, iterate
);
1304 grub_dl_unref (my_mod
);
1305 return GRUB_ERR_NONE
;
1309 grub_dl_unref (my_mod
);
1313 /* Return the label of the device DEVICE in LABEL. The label is
1314 returned in a grub_malloc'ed buffer and should be freed by the
1317 grub_reiserfs_label (grub_device_t device
, char **label
)
1319 *label
= grub_malloc (REISERFS_MAX_LABEL_LENGTH
);
1322 grub_disk_read (device
->disk
,
1323 REISERFS_SUPER_BLOCK_OFFSET
/ GRUB_DISK_SECTOR_SIZE
,
1324 REISERFS_LABEL_OFFSET
, REISERFS_MAX_LABEL_LENGTH
,
1331 grub_reiserfs_uuid (grub_device_t device
, char **uuid
)
1333 struct grub_reiserfs_data
*data
;
1334 grub_disk_t disk
= device
->disk
;
1336 grub_dl_ref (my_mod
);
1338 data
= grub_reiserfs_mount (disk
);
1341 *uuid
= grub_malloc (sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"));
1342 grub_sprintf (*uuid
, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1343 grub_be_to_cpu16 (data
->superblock
.uuid
[0]), grub_be_to_cpu16 (data
->superblock
.uuid
[1]),
1344 grub_be_to_cpu16 (data
->superblock
.uuid
[2]), grub_be_to_cpu16 (data
->superblock
.uuid
[3]),
1345 grub_be_to_cpu16 (data
->superblock
.uuid
[4]), grub_be_to_cpu16 (data
->superblock
.uuid
[5]),
1346 grub_be_to_cpu16 (data
->superblock
.uuid
[6]), grub_be_to_cpu16 (data
->superblock
.uuid
[7]));
1351 grub_dl_unref (my_mod
);
1358 static struct grub_fs grub_reiserfs_fs
=
1361 .dir
= grub_reiserfs_dir
,
1362 .open
= grub_reiserfs_open
,
1363 .read
= grub_reiserfs_read
,
1364 .close
= grub_reiserfs_close
,
1365 .label
= grub_reiserfs_label
,
1366 .uuid
= grub_reiserfs_uuid
,
1370 GRUB_MOD_INIT(reiserfs
)
1372 grub_fs_register (&grub_reiserfs_fs
);
1376 GRUB_MOD_FINI(reiserfs
)
1378 grub_fs_unregister (&grub_reiserfs_fs
);