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
26 #warning "TODO : journal, tail packing (?)"
29 # define GRUB_REISERFS_DEBUG
30 # define GRUB_REISERFS_JOURNALING
35 #include <grub/file.h>
37 #include <grub/misc.h>
38 #include <grub/disk.h>
40 #include <grub/types.h>
41 #include <grub/fshelp.h>
44 ({ typeof (a) _a = (a); \
45 typeof (b) _b = (b); \
49 ({ typeof (a) _a = (a); \
50 typeof (b) _b = (b); \
53 #define REISERFS_SUPER_BLOCK_OFFSET 0x10000
54 #define REISERFS_MAGIC_LEN 12
55 #define REISERFS_MAGIC_STRING "ReIsEr"
56 #define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
57 /* If the 3rd bit of an item state is set, then it's visible. */
58 #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
59 #define REISERFS_MAX_LABEL_LENGTH 16
60 #define REISERFS_LABEL_OFFSET 0x64
62 #define S_IFLNK 0xA000
65 static grub_dl_t my_mod
;
68 #define assert(boolean) real_assert (boolean, __FILE__, __LINE__)
70 real_assert (int boolean
, const char *file
, const int line
)
73 grub_printf ("Assertion failed at %s:%d\n", file
, line
);
76 enum grub_reiserfs_item_type
79 GRUB_REISERFS_DIRECTORY
,
81 GRUB_REISERFS_INDIRECT
,
82 /* Matches both _DIRECT and _INDIRECT when searching. */
87 struct grub_reiserfs_superblock
89 grub_uint32_t block_count
;
90 grub_uint32_t block_free_count
;
91 grub_uint32_t root_block
;
92 grub_uint32_t journal_block
;
93 grub_uint32_t journal_device
;
94 grub_uint32_t journal_original_size
;
95 grub_uint32_t journal_max_transaction_size
;
96 grub_uint32_t journal_block_count
;
97 grub_uint32_t journal_max_batch
;
98 grub_uint32_t journal_max_commit_age
;
99 grub_uint32_t journal_max_transaction_age
;
100 grub_uint16_t block_size
;
101 grub_uint16_t oid_max_size
;
102 grub_uint16_t oid_current_size
;
104 grub_uint8_t magic_string
[REISERFS_MAGIC_LEN
];
105 grub_uint32_t function_hash_code
;
106 grub_uint16_t tree_height
;
107 grub_uint16_t bitmap_number
;
108 grub_uint16_t version
;
109 grub_uint16_t reserved
;
110 grub_uint32_t inode_generation
;
111 } __attribute__ ((packed
));
113 struct grub_reiserfs_journal_header
115 grub_uint32_t last_flush_uid
;
116 grub_uint32_t unflushed_offset
;
117 grub_uint32_t mount_id
;
118 } __attribute__ ((packed
));
120 struct grub_reiserfs_description_block
124 grub_uint32_t mount_id
;
125 grub_uint32_t real_blocks
[0];
126 } __attribute__ ((packed
));
128 struct grub_reiserfs_commit_block
132 grub_uint32_t real_blocks
[0];
133 } __attribute__ ((packed
));
135 struct grub_reiserfs_stat_item_v1
138 grub_uint16_t hardlink_count
;
146 grub_uint32_t first_direct_byte
;
147 } __attribute__ ((packed
));
149 struct grub_reiserfs_stat_item_v2
152 grub_uint16_t reserved
;
153 grub_uint32_t hardlink_count
;
160 grub_uint32_t blocks
;
161 grub_uint32_t first_direct_byte
;
162 } __attribute__ ((packed
));
164 struct grub_reiserfs_key
166 grub_uint32_t directory_id
;
167 grub_uint32_t object_id
;
172 grub_uint32_t offset
;
174 } v1
__attribute__ ((packed
));
177 grub_uint64_t offset_type
;
178 } v2
__attribute__ ((packed
));
180 } __attribute__ ((packed
));
182 struct grub_reiserfs_item_header
184 struct grub_reiserfs_key key
;
187 grub_uint16_t free_space
;
188 grub_uint16_t entry_count
;
189 } u
__attribute__ ((packed
));
190 grub_uint16_t item_size
;
191 grub_uint16_t item_location
;
192 grub_uint16_t version
;
193 } __attribute__ ((packed
));
195 struct grub_reiserfs_block_header
198 grub_uint16_t item_count
;
199 grub_uint16_t free_space
;
200 grub_uint16_t reserved
;
201 struct grub_reiserfs_key block_right_delimiting_key
;
202 } __attribute__ ((packed
));
204 struct grub_reiserfs_disk_child
206 grub_uint32_t block_number
;
208 grub_uint16_t reserved
;
209 } __attribute__ ((packed
));
211 struct grub_reiserfs_directory_header
213 grub_uint32_t offset
;
214 grub_uint32_t directory_id
;
215 grub_uint32_t object_id
;
216 grub_uint16_t location
;
218 } __attribute__ ((packed
));
220 struct grub_fshelp_node
222 struct grub_reiserfs_data
*data
;
223 grub_uint32_t block_number
; /* 0 if node is not found. */
224 grub_uint16_t block_position
;
225 grub_uint64_t next_offset
;
226 enum grub_reiserfs_item_type type
; /* To know how to read the header. */
227 struct grub_reiserfs_item_header header
;
230 /* Returned when opening a file. */
231 struct grub_reiserfs_data
233 struct grub_reiserfs_superblock superblock
;
235 grub_fshelp_journal_t journal
;
238 /* Internal-only functions. Not to be used outside of this file. */
240 /* Return the type of given v2 key. */
241 static enum grub_reiserfs_item_type
242 grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key
*key
)
244 switch (grub_le_to_cpu64 (key
->u
.v2
.offset_type
) >> 60)
247 return GRUB_REISERFS_STAT
;
249 return GRUB_REISERFS_ANY
;
251 return GRUB_REISERFS_DIRECTORY
;
253 return GRUB_REISERFS_DIRECT
;
255 return GRUB_REISERFS_INDIRECT
;
257 return GRUB_REISERFS_UNKNOWN
;
260 /* Return the type of given v1 key. */
261 static enum grub_reiserfs_item_type
262 grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key
*key
)
264 switch (grub_le_to_cpu32 (key
->u
.v1
.type
))
267 return GRUB_REISERFS_STAT
;
269 return GRUB_REISERFS_ANY
;
271 return GRUB_REISERFS_DIRECTORY
;
274 return GRUB_REISERFS_DIRECT
;
277 return GRUB_REISERFS_INDIRECT
;
279 return GRUB_REISERFS_UNKNOWN
;
282 /* Return 1 if the given key is version 1 key, 2 otherwise. */
284 grub_reiserfs_get_key_version (const struct grub_reiserfs_key
*key
)
286 return grub_reiserfs_get_key_v1_type (key
) == GRUB_REISERFS_UNKNOWN
? 2 : 1;
291 grub_hexdump (char *buffer
, grub_size_t len
)
294 for (a
= 0; a
< len
; a
++)
297 grub_printf ("\n%08x ", a
);
298 grub_printf ("%02x ",
299 ((unsigned int) ((unsigned char *) buffer
)[a
]) & 0xFF);
305 #ifdef GRUB_REISERFS_DEBUG
307 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
);
309 static enum grub_reiserfs_item_type
310 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
);
313 grub_reiserfs_print_key (const struct grub_reiserfs_key
*key
)
316 char *reiserfs_type_strings
[] = {
325 for (a
= 0; a
< sizeof (struct grub_reiserfs_key
); a
++)
326 grub_printf ("%02x ", ((unsigned int) ((unsigned char *) key
)[a
]) & 0xFF);
327 grub_printf ("parent id = 0x%08x, self id = 0x%08x, type = %s, offset = ",
328 grub_le_to_cpu32 (key
->directory_id
),
329 grub_le_to_cpu32 (key
->object_id
),
330 reiserfs_type_strings
[grub_reiserfs_get_key_type (key
)]);
331 if (grub_reiserfs_get_key_version (key
) == 1)
332 grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset (key
));
334 grub_printf("0x%07x%08x",
335 (unsigned) (grub_reiserfs_get_key_offset (key
) >> 32),
336 (unsigned) (grub_reiserfs_get_key_offset (key
) & 0xFFFFFFFF));
341 /* Return the offset of given key. */
343 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key
*key
)
345 if (grub_reiserfs_get_key_version (key
) == 1)
346 return grub_le_to_cpu32 (key
->u
.v1
.offset
);
348 return grub_le_to_cpu64 (key
->u
.v2
.offset_type
) & (~0ULL >> 4);
351 /* Set the offset of given key. */
353 grub_reiserfs_set_key_offset (struct grub_reiserfs_key
*key
,
356 if (grub_reiserfs_get_key_version (key
) == 1)
357 key
->u
.v1
.offset
= grub_cpu_to_le32 (value
);
359 key
->u
.v2
.offset_type \
360 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64 (15ULL << 60))
361 | grub_cpu_to_le64 (value
& (~0ULL >> 4)));
364 /* Return the type of given key. */
365 static enum grub_reiserfs_item_type
366 grub_reiserfs_get_key_type (const struct grub_reiserfs_key
*key
)
368 if (grub_reiserfs_get_key_version (key
) == 1)
369 return grub_reiserfs_get_key_v1_type (key
);
371 return grub_reiserfs_get_key_v2_type (key
);
374 /* Set the type of given key, with given version number. */
376 grub_reiserfs_set_key_type (struct grub_reiserfs_key
*key
,
377 enum grub_reiserfs_item_type grub_type
,
384 case GRUB_REISERFS_STAT
:
387 case GRUB_REISERFS_ANY
:
388 type
= (version
== 1) ? 555 : 15;
390 case GRUB_REISERFS_DIRECTORY
:
391 type
= (version
== 1) ? 500 : 3;
393 case GRUB_REISERFS_DIRECT
:
394 type
= (version
== 1) ? 0xFFFFFFFF : 2;
396 case GRUB_REISERFS_INDIRECT
:
397 type
= (version
== 1) ? 0xFFFFFFFE : 1;
404 key
->u
.v1
.type
= grub_cpu_to_le32 (type
);
406 key
->u
.v2
.offset_type
407 = ((key
->u
.v2
.offset_type
& grub_cpu_to_le64 (~0ULL >> 4))
408 | grub_cpu_to_le64 ((grub_uint64_t
) type
<< 60));
410 assert (grub_reiserfs_get_key_type (key
) == grub_type
);
413 /* -1 if key 1 if lower than key 2.
414 0 if key 1 is equal to key 2.
415 1 if key 1 is higher than key 2. */
417 grub_reiserfs_compare_keys (const struct grub_reiserfs_key
*key1
,
418 const struct grub_reiserfs_key
*key2
)
420 grub_uint64_t offset1
, offset2
;
421 enum grub_reiserfs_item_type type1
, type2
;
422 grub_uint32_t id1
, id2
;
424 if (! key1
|| ! key2
)
427 id1
= grub_le_to_cpu32 (key1
->directory_id
);
428 id2
= grub_le_to_cpu32 (key2
->directory_id
);
434 id1
= grub_le_to_cpu32 (key1
->object_id
);
435 id2
= grub_le_to_cpu32 (key2
->object_id
);
441 offset1
= grub_reiserfs_get_key_offset (key1
);
442 offset2
= grub_reiserfs_get_key_offset (key2
);
443 if (offset1
< offset2
)
445 if (offset1
> offset2
)
448 type1
= grub_reiserfs_get_key_type (key1
);
449 type2
= grub_reiserfs_get_key_type (key2
);
450 if ((type1
== GRUB_REISERFS_ANY
451 && (type2
== GRUB_REISERFS_DIRECT
452 || type2
== GRUB_REISERFS_INDIRECT
))
453 || (type2
== GRUB_REISERFS_ANY
454 && (type1
== GRUB_REISERFS_DIRECT
455 || type1
== GRUB_REISERFS_INDIRECT
)))
465 /* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
466 accordingly to what was found. */
468 grub_reiserfs_get_item (struct grub_reiserfs_data
*data
,
469 const struct grub_reiserfs_key
*key
,
470 struct grub_fshelp_node
*item
)
472 grub_uint32_t block_number
;
473 struct grub_reiserfs_block_header
*block_header
= 0;
474 struct grub_reiserfs_key
*block_key
= 0;
475 grub_uint16_t block_size
, item_count
, current_level
;
477 grub_uint16_t previous_level
= ~0;
478 struct grub_reiserfs_item_header
*item_headers
= 0;
482 grub_error (GRUB_ERR_TEST_FAILURE
, "data is NULL");
488 grub_error (GRUB_ERR_TEST_FAILURE
, "key is NULL");
494 grub_error (GRUB_ERR_TEST_FAILURE
, "item is NULL");
498 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
499 block_number
= grub_le_to_cpu32 (data
->superblock
.root_block
);
500 #ifdef GRUB_REISERFS_DEBUG
501 grub_printf("Searching for ");
502 grub_reiserfs_print_key (key
);
504 block_header
= grub_malloc (block_size
);
508 item
->next_offset
= 0;
511 grub_disk_read (data
->disk
,
512 grub_fshelp_map_block (data
->journal
, block_number
) *
513 (block_size
>> GRUB_DISK_SECTOR_BITS
),
514 (((grub_off_t
) block_number
* block_size
)
515 & (GRUB_DISK_SECTOR_SIZE
- 1)),
516 block_size
, (char *) block_header
);
519 current_level
= grub_le_to_cpu16 (block_header
->level
);
520 grub_dprintf ("reiserfs_tree", " at level %d\n", current_level
);
521 if (current_level
>= previous_level
)
523 grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
524 grub_error (GRUB_ERR_FILE_READ_ERROR
, "level loop");
527 previous_level
= current_level
;
528 item_count
= grub_le_to_cpu16 (block_header
->item_count
);
529 grub_dprintf ("reiserfs_tree", " number of contained items : %d\n",
531 if (current_level
> 1)
533 /* Internal node. Navigate to the child that should contain
535 struct grub_reiserfs_key
*keys
536 = (struct grub_reiserfs_key
*) (block_header
+ 1);
537 struct grub_reiserfs_disk_child
*children
538 = ((struct grub_reiserfs_disk_child
*)
539 (keys
+ item_count
));
543 && grub_reiserfs_compare_keys (key
, &(keys
[i
])) >= 0;
546 #ifdef GRUB_REISERFS_DEBUG
547 grub_printf("i %03d/%03d ", i
+ 1, item_count
+ 1);
548 grub_reiserfs_print_key (&(keys
[i
]));
551 block_number
= grub_le_to_cpu32 (children
[i
].block_number
);
552 if ((i
< item_count
) && (key
->directory_id
== keys
[i
].directory_id
)
553 && (key
->object_id
== keys
[i
].object_id
))
554 item
->next_offset
= grub_reiserfs_get_key_offset(&(keys
[i
]));
555 #ifdef GRUB_REISERFS_DEBUG
557 || grub_reiserfs_compare_keys (key
, &(keys
[i
])) == 0)
563 grub_printf (" %03d/%03d ", i
+ 1, item_count
+ 1);
564 grub_reiserfs_print_key (&(keys
[i
]));
565 if (i
+ 1 < item_count
)
567 grub_printf ("+ %03d/%03d ", i
+ 2, item_count
);
568 grub_reiserfs_print_key (&(keys
[i
+ 1]));
572 grub_printf ("Accessing rightmost child at block %d.\n",
578 /* Leaf node. Check that the key is actually present. */
580 = (struct grub_reiserfs_item_header
*) (block_header
+ 1);
583 && (grub_reiserfs_compare_keys (key
, &(item_headers
[i
].key
))
587 #ifdef GRUB_REISERFS_DEBUG
588 if (key
->directory_id
== item_headers
[i
].key
.directory_id
&& \
589 key
->object_id
== item_headers
[i
].key
.object_id
)
593 grub_printf(" %03d/%03d ", i
+ 1, item_count
);
594 grub_reiserfs_print_key (&(item_headers
[i
].key
));
598 block_key
= &(item_headers
[i
].key
);
601 while (current_level
> 1);
605 if (i
== item_count
|| grub_reiserfs_compare_keys (key
, block_key
))
607 item
->block_number
= 0;
608 item
->block_position
= 0;
609 item
->type
= GRUB_REISERFS_UNKNOWN
;
610 #ifdef GRUB_REISERFS_DEBUG
611 grub_printf("Not found.\n");
616 item
->block_number
= block_number
;
617 item
->block_position
= i
;
618 item
->type
= grub_reiserfs_get_key_type (block_key
);
619 grub_memcpy (&(item
->header
), &(item_headers
[i
]),
620 sizeof (struct grub_reiserfs_item_header
));
621 #ifdef GRUB_REISERFS_DEBUG
622 grub_printf ("F %03d/%03d ", i
+ 1, item_count
);
623 grub_reiserfs_print_key (block_key
);
627 assert (grub_errno
== GRUB_ERR_NONE
);
628 grub_free (block_header
);
629 return GRUB_ERR_NONE
;
632 assert (grub_errno
!= GRUB_ERR_NONE
);
633 grub_free (block_header
);
634 assert (grub_errno
!= GRUB_ERR_NONE
);
638 /* Return the path of the file which is pointed at by symlink NODE. */
640 grub_reiserfs_read_symlink (grub_fshelp_node_t node
)
642 char *symlink_buffer
= 0;
643 grub_uint16_t block_size
;
644 grub_disk_addr_t block
;
647 struct grub_fshelp_node found
;
648 struct grub_reiserfs_key key
;
650 grub_memcpy (&key
, &(node
->header
.key
), sizeof (key
));
651 grub_reiserfs_set_key_offset (&key
, 1);
652 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_DIRECT
,
653 grub_reiserfs_get_key_version (&key
));
655 if (grub_reiserfs_get_item (node
->data
, &key
, &found
) != GRUB_ERR_NONE
)
658 if (found
.block_number
== 0)
661 block_size
= grub_le_to_cpu16 (node
->data
->superblock
.block_size
);
662 len
= grub_le_to_cpu16 (found
.header
.item_size
);
663 block
= (grub_fshelp_map_block (node
->data
->journal
, found
.block_number
) *
664 (block_size
>> GRUB_DISK_SECTOR_BITS
));
665 offset
= grub_le_to_cpu16 (found
.header
.item_location
);
667 symlink_buffer
= grub_malloc (len
+ 1);
668 if (! symlink_buffer
)
671 grub_disk_read (node
->data
->disk
, block
, offset
, len
, symlink_buffer
);
675 symlink_buffer
[len
] = 0;
676 return symlink_buffer
;
679 grub_free (symlink_buffer
);
684 grub_reiserfs_get_journal (struct grub_reiserfs_data
*data
)
686 int block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
687 char buf
[block_size
];
688 struct grub_reiserfs_journal_header
*jh
;
689 grub_fshelp_journal_t log
;
690 grub_uint32_t seq_id
, mount_id
;
691 int num_blocks
= grub_le_to_cpu32 (data
->superblock
.journal_original_size
);
692 int base_block
= grub_le_to_cpu32 (data
->superblock
.journal_block
);
693 int last_num
, num
, block
;
697 if (! data
->superblock
.journal_block
)
700 if (grub_disk_read (data
->disk
,
701 (base_block
+ num_blocks
)
702 * (block_size
>> GRUB_DISK_SECTOR_BITS
),
703 0, sizeof (struct grub_reiserfs_journal_header
),
707 log
= grub_malloc (sizeof (struct grub_fshelp_journal
) +
708 num_blocks
* sizeof (grub_disk_addr_t
));
712 jh
= (struct grub_reiserfs_journal_header
*) &buf
[0];
714 log
->type
= GRUB_FSHELP_JOURNAL_TYPE_BLOCK
;
715 log
->blkno
= base_block
;
716 log
->first_block
= 0;
717 log
->last_block
= num_blocks
;
718 log
->start_block
= grub_le_to_cpu32 (jh
->unflushed_offset
);
720 seq_id
= grub_le_to_cpu32 (jh
->last_flush_uid
);
721 mount_id
= grub_le_to_cpu32 (jh
->mount_id
);
724 block
= log
->start_block
;
728 struct grub_reiserfs_description_block
*db
;
729 struct grub_reiserfs_commit_block
*cb
;
730 grub_uint32_t i
, len
, half_len
, id
, mid
;
732 if (grub_disk_read (data
->disk
,
734 * (block_size
>> GRUB_DISK_SECTOR_BITS
),
735 0, sizeof (buf
), buf
))
738 if (grub_memcmp (&buf
[block_size
- REISERFS_MAGIC_LEN
],
739 REISERFS_MAGIC_DESC_BLOCK
,
740 sizeof (REISERFS_MAGIC_DESC_BLOCK
) - 1))
743 db
= (struct grub_reiserfs_description_block
*) &buf
[0];
744 id
= grub_le_to_cpu32 (db
->id
);
745 len
= grub_le_to_cpu32 (db
->len
);
746 mid
= grub_le_to_cpu32 (db
->mount_id
);
747 if ((id
<= seq_id
) && (mid
<= mount_id
))
750 log
->mapping
[num
++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING
;
751 half_len
= ((block_size
- 24) >> 2);
755 for (i
= 0; i
< half_len
; i
++)
756 log
->mapping
[num
++] = db
->real_blocks
[i
];
758 block
+= grub_le_to_cpu32 (db
->len
) + 1;
759 if (block
>= log
->last_block
)
760 block
-= log
->last_block
;
762 if (grub_disk_read (data
->disk
,
764 * (block_size
>> GRUB_DISK_SECTOR_BITS
),
765 0, sizeof (buf
), buf
))
768 cb
= (struct grub_reiserfs_commit_block
*) &buf
[0];
769 if ((grub_le_to_cpu32 (cb
->id
) != id
) ||
770 (grub_le_to_cpu32 (cb
->len
) != len
))
773 for (i
= 0; i
< len
- half_len
; i
++)
774 log
->mapping
[num
++] = cb
->real_blocks
[i
];
777 log
->mapping
[num
++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING
;
780 if (block
>= log
->last_block
)
781 block
-= log
->last_block
;
793 size
= sizeof (struct grub_fshelp_journal
) +
794 last_num
* sizeof (grub_disk_addr_t
);
796 log
->num_mappings
= last_num
;
797 data
->journal
= grub_realloc (log
, size
);
801 /* Fill the mounted filesystem structure and return it. */
802 static struct grub_reiserfs_data
*
803 grub_reiserfs_mount (grub_disk_t disk
)
805 struct grub_reiserfs_data
*data
= 0;
806 data
= grub_malloc (sizeof (*data
));
809 grub_disk_read (disk
, REISERFS_SUPER_BLOCK_OFFSET
/ GRUB_DISK_SECTOR_SIZE
,
810 0, sizeof (data
->superblock
), (char *) &(data
->superblock
));
813 if (grub_memcmp (data
->superblock
.magic_string
,
814 REISERFS_MAGIC_STRING
, sizeof (REISERFS_MAGIC_STRING
) - 1))
816 grub_error (GRUB_ERR_BAD_FS
, "not a reiserfs filesystem");
820 grub_reiserfs_get_journal (data
);
824 /* Disk is too small to contain a ReiserFS. */
825 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
826 grub_error (GRUB_ERR_BAD_FS
, "not a reiserfs filesystem");
832 /* Call HOOK for each file in directory ITEM. */
834 grub_reiserfs_iterate_dir (grub_fshelp_node_t item
,
836 (*hook
) (const char *filename
,
837 enum grub_fshelp_filetype filetype
,
838 grub_fshelp_node_t node
))
840 struct grub_reiserfs_data
*data
= item
->data
;
841 struct grub_reiserfs_block_header
*block_header
= 0;
842 grub_uint16_t block_size
, block_position
;
843 grub_uint32_t block_number
;
844 grub_uint64_t next_offset
= item
->next_offset
;
847 if (item
->type
!= GRUB_REISERFS_DIRECTORY
)
849 grub_error (GRUB_ERR_BAD_FILE_TYPE
,
850 "grub_reiserfs_iterate_dir called on a non-directory item");
853 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
854 block_header
= grub_malloc (block_size
);
857 block_number
= item
->block_number
;
858 block_position
= item
->block_position
;
859 grub_dprintf ("reiserfs", "Iterating directory...\n");
862 struct grub_reiserfs_directory_header
*directory_headers
;
863 struct grub_fshelp_node directory_item
;
864 grub_uint16_t entry_count
, entry_number
;
865 struct grub_reiserfs_item_header
*item_headers
;
867 grub_disk_read (data
->disk
,
868 grub_fshelp_map_block (data
->journal
, block_number
) *
869 (block_size
>> GRUB_DISK_SECTOR_BITS
),
870 (((grub_off_t
) block_number
* block_size
)
871 & (GRUB_DISK_SECTOR_SIZE
- 1)),
872 block_size
, (char *) block_header
);
877 if (grub_le_to_cpu16 (block_header
->level
) != 1)
879 grub_error (GRUB_ERR_TEST_FAILURE
,
880 "reiserfs: block %d is not a leaf block",
886 item_headers
= (struct grub_reiserfs_item_header
*) (block_header
+ 1);
888 = ((struct grub_reiserfs_directory_header
*)
889 ((char *) block_header
890 + grub_le_to_cpu16 (item_headers
[block_position
].item_location
)));
892 = grub_le_to_cpu16 (item_headers
[block_position
].u
.entry_count
);
893 for (entry_number
= 0; entry_number
< entry_count
; entry_number
++)
895 struct grub_reiserfs_directory_header
*directory_header
896 = &directory_headers
[entry_number
];
897 grub_uint16_t entry_state
898 = grub_le_to_cpu16 (directory_header
->state
);
900 if (entry_state
& GRUB_REISERFS_VISIBLE_MASK
)
902 grub_fshelp_node_t entry_item
;
903 struct grub_reiserfs_key entry_key
;
904 enum grub_reiserfs_item_type entry_type
;
907 entry_name
= (((char *) directory_headers
)
908 + grub_le_to_cpu16 (directory_header
->location
));
909 entry_key
.directory_id
= directory_header
->directory_id
;
910 entry_key
.object_id
= directory_header
->object_id
;
911 entry_key
.u
.v2
.offset_type
= 0;
912 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_DIRECTORY
,
914 grub_reiserfs_set_key_offset (&entry_key
, 1);
916 entry_item
= grub_malloc (sizeof (*entry_item
));
920 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
)
923 grub_free (entry_item
);
927 if (entry_item
->type
== GRUB_REISERFS_DIRECTORY
)
928 entry_type
= GRUB_FSHELP_DIR
;
931 grub_uint32_t entry_block_number
;
932 /* Order is very important here.
933 First set the offset to 0 using current key version.
934 Then change the key type, which influes on key version
936 grub_reiserfs_set_key_offset (&entry_key
, 0);
937 grub_reiserfs_set_key_type (&entry_key
, GRUB_REISERFS_STAT
,
939 if (grub_reiserfs_get_item (data
, &entry_key
, entry_item
)
942 grub_free (entry_item
);
946 if (entry_item
->block_number
!= 0)
948 grub_uint16_t entry_version
;
950 = grub_le_to_cpu16 (entry_item
->header
.version
);
951 entry_block_number
= entry_item
->block_number
;
953 grub_dprintf ("reiserfs",
954 "version %04x block %08x (%08x) position %08x\n",
955 entry_version
, entry_block_number
,
956 ((grub_disk_addr_t
) entry_block_number
* block_size
) / GRUB_DISK_SECTOR_SIZE
,
957 grub_le_to_cpu16 (entry_item
->header
.item_location
));
959 if (entry_version
== 0) /* Version 1 stat item. */
961 struct grub_reiserfs_stat_item_v1 entry_v1_stat
;
962 grub_disk_read (data
->disk
,
963 grub_fshelp_map_block (data
->journal
, entry_block_number
) *
964 (block_size
>> GRUB_DISK_SECTOR_BITS
),
965 grub_le_to_cpu16 (entry_item
->header
.item_location
),
966 sizeof (entry_v1_stat
),
967 (char *) &entry_v1_stat
);
971 grub_dprintf ("reiserfs",
972 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
973 grub_le_to_cpu16 (entry_v1_stat
.mode
),
974 grub_le_to_cpu16 (entry_v1_stat
.hardlink_count
),
975 grub_le_to_cpu16 (entry_v1_stat
.uid
),
976 grub_le_to_cpu16 (entry_v1_stat
.gid
),
977 grub_le_to_cpu32 (entry_v1_stat
.size
),
978 grub_le_to_cpu32 (entry_v1_stat
.atime
),
979 grub_le_to_cpu32 (entry_v1_stat
.mtime
),
980 grub_le_to_cpu32 (entry_v1_stat
.ctime
),
981 grub_le_to_cpu32 (entry_v1_stat
.rdev
),
982 grub_le_to_cpu32 (entry_v1_stat
.first_direct_byte
));
983 grub_dprintf ("reiserfs",
984 "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
986 entry_v1_stat
.hardlink_count
,
994 entry_v1_stat
.first_direct_byte
);
996 if ((grub_le_to_cpu16 (entry_v1_stat
.mode
) & S_IFLNK
)
998 entry_type
= GRUB_FSHELP_SYMLINK
;
1000 entry_type
= GRUB_FSHELP_REG
;
1004 struct grub_reiserfs_stat_item_v2 entry_v2_stat
;
1005 grub_disk_read (data
->disk
,
1006 grub_fshelp_map_block (data
->journal
, entry_block_number
) *
1007 (block_size
>> GRUB_DISK_SECTOR_BITS
),
1008 grub_le_to_cpu16 (entry_item
->header
.item_location
),
1009 sizeof (entry_v2_stat
),
1010 (char *) &entry_v2_stat
);
1014 grub_dprintf ("reiserfs",
1015 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
1016 grub_le_to_cpu16 (entry_v2_stat
.mode
),
1017 grub_le_to_cpu16 (entry_v2_stat
.reserved
),
1018 grub_le_to_cpu32 (entry_v2_stat
.hardlink_count
),
1019 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) >> 32),
1020 (unsigned int) (grub_le_to_cpu64 (entry_v2_stat
.size
) && 0xFFFFFFFF),
1021 grub_le_to_cpu32 (entry_v2_stat
.uid
),
1022 grub_le_to_cpu32 (entry_v2_stat
.gid
),
1023 grub_le_to_cpu32 (entry_v2_stat
.atime
),
1024 grub_le_to_cpu32 (entry_v2_stat
.mtime
),
1025 grub_le_to_cpu32 (entry_v2_stat
.ctime
),
1026 grub_le_to_cpu32 (entry_v2_stat
.blocks
),
1027 grub_le_to_cpu32 (entry_v2_stat
.first_direct_byte
));
1028 grub_dprintf ("reiserfs",
1029 "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
1031 entry_v2_stat
.reserved
,
1032 entry_v2_stat
.hardlink_count
,
1033 (unsigned int) (entry_v2_stat
.size
>> 32),
1034 (unsigned int) (entry_v2_stat
.size
&& 0xFFFFFFFF),
1037 entry_v2_stat
.atime
,
1038 entry_v2_stat
.mtime
,
1039 entry_v2_stat
.ctime
,
1040 entry_v2_stat
.blocks
,
1041 entry_v2_stat
.first_direct_byte
);
1043 if ((grub_le_to_cpu16 (entry_v2_stat
.mode
) & S_IFLNK
)
1045 entry_type
= GRUB_FSHELP_SYMLINK
;
1047 entry_type
= GRUB_FSHELP_REG
;
1052 /* Pseudo file ".." never has stat block. */
1053 if (grub_strcmp (entry_name
, ".."))
1054 grub_dprintf ("reiserfs",
1055 "Warning : %s has no stat block !\n",
1057 grub_free (entry_item
);
1061 if (hook (entry_name
, entry_type
, entry_item
))
1063 grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
1064 entry_name
, entry_type
);
1069 *entry_name
= 0; /* Make sure next entry name (which is just
1070 before this one in disk order) stops before
1075 if (next_offset
== 0)
1078 grub_reiserfs_set_key_offset (&(item_headers
[block_position
].key
),
1080 if (grub_reiserfs_get_item (data
, &(item_headers
[block_position
].key
),
1081 &directory_item
) != GRUB_ERR_NONE
)
1083 block_number
= directory_item
.block_number
;
1084 block_position
= directory_item
.block_position
;
1085 next_offset
= directory_item
.next_offset
;
1087 while (block_number
);
1090 assert (grub_errno
== GRUB_ERR_NONE
);
1091 grub_free (block_header
);
1094 assert (grub_errno
!= GRUB_ERR_NONE
);
1095 grub_free (block_header
);
1099 /****************************************************************************/
1100 /* grub api functions */
1101 /****************************************************************************/
1103 /* Open a file named NAME and initialize FILE. */
1105 grub_reiserfs_open (struct grub_file
*file
, const char *name
)
1107 struct grub_reiserfs_data
*data
= 0;
1108 struct grub_fshelp_node root
, *found
= 0, info
;
1109 struct grub_reiserfs_key key
;
1110 grub_uint32_t block_number
;
1111 grub_uint16_t entry_version
, block_size
, entry_location
;
1114 grub_dl_ref (my_mod
);
1116 data
= grub_reiserfs_mount (file
->device
->disk
);
1119 block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
1120 key
.directory_id
= grub_cpu_to_le32 (1);
1121 key
.object_id
= grub_cpu_to_le32 (2);
1122 key
.u
.v2
.offset_type
= 0;
1123 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_DIRECTORY
, 2);
1124 grub_reiserfs_set_key_offset (&key
, 1);
1125 if (grub_reiserfs_get_item (data
, &key
, &root
) != GRUB_ERR_NONE
)
1127 if (root
.block_number
== 0)
1129 grub_error (GRUB_ERR_BAD_FS
, "Unable to find root item");
1130 goto fail
; /* Should never happen since checked at mount. */
1132 grub_fshelp_find_file (name
, &root
, &found
,
1133 grub_reiserfs_iterate_dir
,
1134 grub_reiserfs_read_symlink
, GRUB_FSHELP_REG
);
1137 key
.directory_id
= found
->header
.key
.directory_id
;
1138 key
.object_id
= found
->header
.key
.object_id
;
1139 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_STAT
, 2);
1140 grub_reiserfs_set_key_offset (&key
, 0);
1141 if (grub_reiserfs_get_item (data
, &key
, &info
) != GRUB_ERR_NONE
)
1143 if (info
.block_number
== 0)
1145 grub_error (GRUB_ERR_BAD_FS
, "Unable to find searched item");
1148 entry_version
= grub_le_to_cpu16 (info
.header
.version
);
1149 entry_location
= grub_le_to_cpu16 (info
.header
.item_location
);
1150 block_number
= info
.block_number
;
1151 if (entry_version
== 0) /* Version 1 stat item. */
1153 struct grub_reiserfs_stat_item_v1 entry_v1_stat
;
1154 grub_disk_read (data
->disk
,
1155 grub_fshelp_map_block (data
->journal
, block_number
) *
1156 (block_size
>> GRUB_DISK_SECTOR_BITS
),
1158 + (((grub_off_t
) block_number
* block_size
)
1159 & (GRUB_DISK_SECTOR_SIZE
- 1)),
1160 sizeof (entry_v1_stat
), (char *) &entry_v1_stat
);
1163 file
->size
= (grub_off_t
) grub_le_to_cpu64 (entry_v1_stat
.size
);
1167 struct grub_reiserfs_stat_item_v2 entry_v2_stat
;
1168 grub_disk_read (data
->disk
,
1169 grub_fshelp_map_block (data
->journal
, block_number
) *
1170 (block_size
>> GRUB_DISK_SECTOR_BITS
),
1172 + (((grub_off_t
) block_number
* block_size
)
1173 & (GRUB_DISK_SECTOR_SIZE
- 1)),
1174 sizeof (entry_v2_stat
), (char *) &entry_v2_stat
);
1177 file
->size
= (grub_off_t
) grub_le_to_cpu64 (entry_v2_stat
.size
);
1179 grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
1180 (unsigned int) file
->size
,
1181 (unsigned int) (file
->size
>> 32), (unsigned int) file
->size
);
1184 return GRUB_ERR_NONE
;
1187 assert (grub_errno
!= GRUB_ERR_NONE
);
1191 grub_dl_unref (my_mod
);
1197 grub_reiserfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1199 unsigned int indirect_block
, indirect_block_count
;
1200 struct grub_reiserfs_key key
;
1201 struct grub_fshelp_node
*node
= file
->data
;
1202 struct grub_reiserfs_data
*data
= node
->data
;
1203 struct grub_fshelp_node found
;
1204 grub_uint16_t block_size
= grub_le_to_cpu16 (data
->superblock
.block_size
);
1205 grub_uint16_t item_size
;
1206 grub_uint32_t
*indirect_block_ptr
= 0;
1207 grub_uint64_t current_key_offset
= 1;
1208 grub_size_t initial_position
, current_position
, final_position
, length
;
1209 grub_disk_addr_t block
;
1212 if (file
->offset
>= file
->size
)
1215 key
.directory_id
= node
->header
.key
.directory_id
;
1216 key
.object_id
= node
->header
.key
.object_id
;
1217 key
.u
.v2
.offset_type
= 0;
1218 grub_reiserfs_set_key_type (&key
, GRUB_REISERFS_ANY
, 2);
1219 initial_position
= file
->offset
;
1220 current_position
= 0;
1221 final_position
= MIN (len
+ initial_position
, file
->size
);
1222 grub_dprintf ("reiserfs",
1223 "Reading from %d to %d (%d instead of requested %d)\n",
1224 initial_position
, final_position
,
1225 final_position
- initial_position
, len
);
1226 while (current_position
< final_position
)
1228 grub_reiserfs_set_key_offset (&key
, current_key_offset
);
1230 if (grub_reiserfs_get_item (data
, &key
, &found
) != GRUB_ERR_NONE
)
1232 if (found
.block_number
== 0)
1234 item_size
= grub_le_to_cpu16 (found
.header
.item_size
);
1237 case GRUB_REISERFS_DIRECT
:
1238 block
= (grub_fshelp_map_block (data
->journal
, found
.block_number
) *
1239 (block_size
>> GRUB_DISK_SECTOR_BITS
));
1240 grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block
);
1241 if (initial_position
< current_position
+ item_size
)
1243 offset
= MAX ((signed) (initial_position
- current_position
), 0);
1244 length
= (MIN (item_size
, final_position
- current_position
)
1246 grub_dprintf ("reiserfs",
1247 "Reading direct block %u from %u to %u...\n",
1248 (unsigned) block
, (unsigned) offset
,
1249 (unsigned) offset
+ length
);
1250 found
.data
->disk
->read_hook
= file
->read_hook
;
1251 grub_disk_read (found
.data
->disk
,
1254 + grub_le_to_cpu16 (found
.header
.item_location
),
1256 found
.data
->disk
->read_hook
= 0;
1260 current_position
+= offset
+ length
;
1263 current_position
+= item_size
;
1265 case GRUB_REISERFS_INDIRECT
:
1266 indirect_block_count
= item_size
/ sizeof (*indirect_block_ptr
);
1267 indirect_block_ptr
= grub_malloc (item_size
);
1268 if (! indirect_block_ptr
)
1270 grub_disk_read (found
.data
->disk
,
1271 grub_fshelp_map_block (data
->journal
, found
.block_number
) *
1272 (block_size
>> GRUB_DISK_SECTOR_BITS
),
1273 grub_le_to_cpu16 (found
.header
.item_location
),
1274 item_size
, (char *) indirect_block_ptr
);
1277 found
.data
->disk
->read_hook
= file
->read_hook
;
1278 for (indirect_block
= 0;
1279 indirect_block
< indirect_block_count
1280 && current_position
< final_position
;
1283 block
= (grub_fshelp_map_block (data
->journal
,
1284 grub_le_to_cpu32 (indirect_block_ptr
[indirect_block
])) *
1285 (block_size
>> GRUB_DISK_SECTOR_BITS
));
1286 grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block
);
1287 if (current_position
+ block_size
>= initial_position
)
1289 offset
= MAX ((signed) (initial_position
- current_position
),
1291 length
= (MIN (block_size
, final_position
- current_position
)
1293 grub_dprintf ("reiserfs",
1294 "Reading indirect block %u from %u to %u...\n",
1295 (unsigned) block
, (unsigned) offset
,
1296 (unsigned) offset
+ length
);
1298 grub_dprintf ("reiserfs",
1299 "\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
1300 indirect_block
+ 1, indirect_block_count
,
1301 initial_position
, current_position
,
1302 final_position
, offset
, length
, len
);
1304 grub_disk_read (found
.data
->disk
, block
, offset
, length
, buf
);
1308 current_position
+= offset
+ length
;
1311 current_position
+= block_size
;
1313 found
.data
->disk
->read_hook
= 0;
1314 grub_free (indirect_block_ptr
);
1315 indirect_block_ptr
= 0;
1320 current_key_offset
= current_position
+ 1;
1323 grub_dprintf("reiserfs",
1324 "Have successfully read %d bytes (%d requested)\n",
1325 current_position
- initial_position
, len
);
1326 return current_position
- initial_position
;
1330 case GRUB_REISERFS_DIRECT:
1331 read_length = MIN (len, item_size - file->offset);
1332 grub_disk_read (found.data->disk,
1333 (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1334 grub_le_to_cpu16 (found.header.item_location) + file->offset,
1339 case GRUB_REISERFS_INDIRECT:
1340 indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1341 indirect_block_ptr = grub_malloc (item_size);
1342 if (!indirect_block_ptr)
1344 grub_disk_read (found.data->disk,
1345 (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1346 grub_le_to_cpu16 (found.header.item_location),
1347 item_size, (char *) indirect_block_ptr);
1350 len = MIN (len, file->size - file->offset);
1351 for (indirect_block = file->offset / block_size;
1352 indirect_block < indirect_block_count && read_length < len;
1355 read = MIN (block_size, len - read_length);
1356 grub_disk_read (found.data->disk,
1357 (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
1358 file->offset % block_size, read,
1359 ((void *) buf) + read_length);
1362 read_length += read;
1364 grub_free (indirect_block_ptr);
1370 return read_length;*/
1373 grub_free (indirect_block_ptr
);
1377 /* Close the file FILE. */
1379 grub_reiserfs_close (grub_file_t file
)
1381 struct grub_fshelp_node
*node
= file
->data
;
1382 struct grub_reiserfs_data
*data
= node
->data
;
1384 grub_free (data
->journal
);
1388 grub_dl_unref (my_mod
);
1390 return GRUB_ERR_NONE
;
1393 /* Call HOOK with each file under DIR. */
1395 grub_reiserfs_dir (grub_device_t device
, const char *path
,
1396 int (*hook
) (const char *filename
, int dir
))
1398 struct grub_reiserfs_data
*data
= 0;
1399 struct grub_fshelp_node root
, *found
;
1400 struct grub_reiserfs_key root_key
;
1402 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
1403 enum grub_fshelp_filetype filetype
,
1404 grub_fshelp_node_t node
);
1406 int NESTED_FUNC_ATTR
iterate (const char *filename
,
1407 enum grub_fshelp_filetype filetype
,
1408 grub_fshelp_node_t node
)
1412 if (filetype
== GRUB_FSHELP_DIR
)
1413 return hook (filename
, 1);
1415 return hook (filename
, 0);
1418 grub_dl_ref (my_mod
);
1420 data
= grub_reiserfs_mount (device
->disk
);
1423 root_key
.directory_id
= grub_cpu_to_le32 (1);
1424 root_key
.object_id
= grub_cpu_to_le32 (2);
1425 root_key
.u
.v2
.offset_type
= 0;
1426 grub_reiserfs_set_key_type (&root_key
, GRUB_REISERFS_DIRECTORY
, 2);
1427 grub_reiserfs_set_key_offset (&root_key
, 1);
1428 if (grub_reiserfs_get_item (data
, &root_key
, &root
) != GRUB_ERR_NONE
)
1430 if (root
.block_number
== 0)
1432 grub_error(GRUB_ERR_BAD_FS
, "Root not found");
1435 grub_fshelp_find_file (path
, &root
, &found
, grub_reiserfs_iterate_dir
,
1436 grub_reiserfs_read_symlink
, GRUB_FSHELP_DIR
);
1439 grub_reiserfs_iterate_dir (found
, iterate
);
1442 grub_dl_unref (my_mod
);
1444 return GRUB_ERR_NONE
;
1449 grub_dl_unref (my_mod
);
1454 /* Return the label of the device DEVICE in LABEL. The label is
1455 returned in a grub_malloc'ed buffer and should be freed by the
1458 grub_reiserfs_label (grub_device_t device
, char **label
)
1460 *label
= grub_malloc (REISERFS_MAX_LABEL_LENGTH
);
1463 grub_disk_read (device
->disk
,
1464 REISERFS_SUPER_BLOCK_OFFSET
/ GRUB_DISK_SECTOR_SIZE
,
1465 REISERFS_LABEL_OFFSET
, REISERFS_MAX_LABEL_LENGTH
,
1471 static struct grub_fs grub_reiserfs_fs
=
1474 .dir
= grub_reiserfs_dir
,
1475 .open
= grub_reiserfs_open
,
1476 .read
= grub_reiserfs_read
,
1477 .close
= grub_reiserfs_close
,
1478 .label
= grub_reiserfs_label
,
1482 GRUB_MOD_INIT(reiserfs
)
1484 grub_fs_register (&grub_reiserfs_fs
);
1490 GRUB_MOD_FINI(reiserfs
)
1492 grub_fs_unregister (&grub_reiserfs_fs
);