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, GRUB_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);
944
*entry_name = 0; /* Make sure next entry name (which is just
945
before this one in disk order) stops before
950
if (next_offset == 0)
953
grub_reiserfs_set_key_offset (&(item_headers[block_position].key),
955
if (grub_reiserfs_get_item (data, &(item_headers[block_position].key),
956
&directory_item) != GRUB_ERR_NONE)
958
block_number = directory_item.block_number;
959
block_position = directory_item.block_position;
960
next_offset = directory_item.next_offset;
962
while (block_number);
965
assert (grub_errno == GRUB_ERR_NONE);
966
grub_free (block_header);
969
assert (grub_errno != GRUB_ERR_NONE);
970
grub_free (block_header);
974
/****************************************************************************/
975
/* grub api functions */
976
/****************************************************************************/
978
/* Open a file named NAME and initialize FILE. */
980
grub_reiserfs_open (struct grub_file *file, const char *name)
982
struct grub_reiserfs_data *data = 0;
983
struct grub_fshelp_node root, *found = 0, info;
984
struct grub_reiserfs_key key;
985
grub_uint32_t block_number;
986
grub_uint16_t entry_version, block_size, entry_location;
988
grub_dl_ref (my_mod);
989
data = grub_reiserfs_mount (file->device->disk);
992
block_size = grub_le_to_cpu16 (data->superblock.block_size);
993
key.directory_id = grub_cpu_to_le32 (1);
994
key.object_id = grub_cpu_to_le32 (2);
995
key.u.v2.offset_type = 0;
996
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECTORY, 2);
997
grub_reiserfs_set_key_offset (&key, 1);
998
if (grub_reiserfs_get_item (data, &key, &root) != GRUB_ERR_NONE)
1000
if (root.block_number == 0)
1002
grub_error (GRUB_ERR_BAD_FS, "unable to find root item");
1003
goto fail; /* Should never happen since checked at mount. */
1005
grub_fshelp_find_file (name, &root, &found,
1006
grub_reiserfs_iterate_dir,
1007
grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
1010
key.directory_id = found->header.key.directory_id;
1011
key.object_id = found->header.key.object_id;
1012
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_STAT, 2);
1013
grub_reiserfs_set_key_offset (&key, 0);
1014
if (grub_reiserfs_get_item (data, &key, &info) != GRUB_ERR_NONE)
1016
if (info.block_number == 0)
1018
grub_error (GRUB_ERR_BAD_FS, "unable to find searched item");
1021
entry_version = grub_le_to_cpu16 (info.header.version);
1022
entry_location = grub_le_to_cpu16 (info.header.item_location);
1023
block_number = info.block_number;
1024
if (entry_version == 0) /* Version 1 stat item. */
1026
struct grub_reiserfs_stat_item_v1 entry_v1_stat;
1027
grub_disk_read (data->disk,
1028
block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
1030
+ (((grub_off_t) block_number * block_size)
1031
& (GRUB_DISK_SECTOR_SIZE - 1)),
1032
sizeof (entry_v1_stat), &entry_v1_stat);
1035
file->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
1039
struct grub_reiserfs_stat_item_v2 entry_v2_stat;
1040
grub_disk_read (data->disk,
1041
block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
1043
+ (((grub_off_t) block_number * block_size)
1044
& (GRUB_DISK_SECTOR_SIZE - 1)),
1045
sizeof (entry_v2_stat), &entry_v2_stat);
1048
file->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
1050
grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
1051
(unsigned int) file->size,
1052
(unsigned int) (file->size >> 32), (unsigned int) file->size);
1055
return GRUB_ERR_NONE;
1058
assert (grub_errno != GRUB_ERR_NONE);
1061
grub_dl_unref (my_mod);
1066
grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
1068
unsigned int indirect_block, indirect_block_count;
1069
struct grub_reiserfs_key key;
1070
struct grub_fshelp_node *node = file->data;
1071
struct grub_reiserfs_data *data = node->data;
1072
struct grub_fshelp_node found;
1073
grub_uint16_t block_size = grub_le_to_cpu16 (data->superblock.block_size);
1074
grub_uint16_t item_size;
1075
grub_uint32_t *indirect_block_ptr = 0;
1076
grub_uint64_t current_key_offset = 1;
1077
grub_off_t initial_position, current_position, final_position, length;
1078
grub_disk_addr_t block;
1081
key.directory_id = node->header.key.directory_id;
1082
key.object_id = node->header.key.object_id;
1083
key.u.v2.offset_type = 0;
1084
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
1085
initial_position = file->offset;
1086
current_position = 0;
1087
final_position = MIN (len + initial_position, file->size);
1088
grub_dprintf ("reiserfs",
1089
"Reading from %lld to %lld (%lld instead of requested %ld)\n",
1090
(unsigned long long) initial_position,
1091
(unsigned long long) final_position,
1092
(unsigned long long) (final_position - initial_position),
1093
(unsigned long) len);
1094
while (current_position < final_position)
1096
grub_reiserfs_set_key_offset (&key, current_key_offset);
1098
if (grub_reiserfs_get_item (data, &key, &found) != GRUB_ERR_NONE)
1100
if (found.block_number == 0)
1102
item_size = grub_le_to_cpu16 (found.header.item_size);
1105
case GRUB_REISERFS_DIRECT:
1106
block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
1107
grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
1108
if (initial_position < current_position + item_size)
1110
offset = MAX ((signed) (initial_position - current_position), 0);
1111
length = (MIN (item_size, final_position - current_position)
1113
grub_dprintf ("reiserfs",
1114
"Reading direct block %u from %u to %u...\n",
1115
(unsigned) block, (unsigned) offset,
1116
(unsigned) (offset + length));
1117
found.data->disk->read_hook = file->read_hook;
1118
grub_disk_read (found.data->disk,
1121
+ grub_le_to_cpu16 (found.header.item_location),
1123
found.data->disk->read_hook = 0;
1127
current_position += offset + length;
1130
current_position += item_size;
1132
case GRUB_REISERFS_INDIRECT:
1133
indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1134
indirect_block_ptr = grub_malloc (item_size);
1135
if (! indirect_block_ptr)
1137
grub_disk_read (found.data->disk,
1138
found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
1139
grub_le_to_cpu16 (found.header.item_location),
1140
item_size, indirect_block_ptr);
1143
found.data->disk->read_hook = file->read_hook;
1144
for (indirect_block = 0;
1145
indirect_block < indirect_block_count
1146
&& current_position < final_position;
1149
block = grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) *
1150
(block_size >> GRUB_DISK_SECTOR_BITS);
1151
grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
1152
if (current_position + block_size >= initial_position)
1154
offset = MAX ((signed) (initial_position - current_position),
1156
length = (MIN (block_size, final_position - current_position)
1158
grub_dprintf ("reiserfs",
1159
"Reading indirect block %u from %u to %u...\n",
1160
(unsigned) block, (unsigned) offset,
1161
(unsigned) (offset + length));
1163
grub_dprintf ("reiserfs",
1164
"\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
1165
indirect_block + 1, indirect_block_count,
1166
initial_position, current_position,
1167
final_position, offset, length, len);
1169
grub_disk_read (found.data->disk, block, offset, length, buf);
1173
current_position += offset + length;
1176
current_position += block_size;
1178
found.data->disk->read_hook = 0;
1179
grub_free (indirect_block_ptr);
1180
indirect_block_ptr = 0;
1185
current_key_offset = current_position + 1;
1188
grub_dprintf ("reiserfs",
1189
"Have successfully read %lld bytes (%ld requested)\n",
1190
(unsigned long long) (current_position - initial_position),
1191
(unsigned long) len);
1192
return current_position - initial_position;
1197
case GRUB_REISERFS_DIRECT:
1198
read_length = MIN (len, item_size - file->offset);
1199
grub_disk_read (found.data->disk,
1200
(found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1201
grub_le_to_cpu16 (found.header.item_location) + file->offset,
1206
case GRUB_REISERFS_INDIRECT:
1207
indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1208
indirect_block_ptr = grub_malloc (item_size);
1209
if (!indirect_block_ptr)
1211
grub_disk_read (found.data->disk,
1212
(found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1213
grub_le_to_cpu16 (found.header.item_location),
1214
item_size, (char *) indirect_block_ptr);
1217
len = MIN (len, file->size - file->offset);
1218
for (indirect_block = file->offset / block_size;
1219
indirect_block < indirect_block_count && read_length < len;
1222
read = MIN (block_size, len - read_length);
1223
grub_disk_read (found.data->disk,
1224
(grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
1225
file->offset % block_size, read,
1226
((void *) buf) + read_length);
1229
read_length += read;
1231
grub_free (indirect_block_ptr);
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_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1342
grub_be_to_cpu16 (data->superblock.uuid[0]),
1343
grub_be_to_cpu16 (data->superblock.uuid[1]),
1344
grub_be_to_cpu16 (data->superblock.uuid[2]),
1345
grub_be_to_cpu16 (data->superblock.uuid[3]),
1346
grub_be_to_cpu16 (data->superblock.uuid[4]),
1347
grub_be_to_cpu16 (data->superblock.uuid[5]),
1348
grub_be_to_cpu16 (data->superblock.uuid[6]),
1349
grub_be_to_cpu16 (data->superblock.uuid[7]));
1354
grub_dl_unref (my_mod);
1361
static struct grub_fs grub_reiserfs_fs =
1364
.dir = grub_reiserfs_dir,
1365
.open = grub_reiserfs_open,
1366
.read = grub_reiserfs_read,
1367
.close = grub_reiserfs_close,
1368
.label = grub_reiserfs_label,
1369
.uuid = grub_reiserfs_uuid,
1373
GRUB_MOD_INIT(reiserfs)
1375
grub_fs_register (&grub_reiserfs_fs);
1379
GRUB_MOD_FINI(reiserfs)
1381
grub_fs_unregister (&grub_reiserfs_fs);