]> git.proxmox.com Git - grub2.git/blame - fs/reiserfs.c
2009-08-17 Robert Millan <rmh.grub@aybabtu.com>
[grub2.git] / fs / reiserfs.c
CommitLineData
492e6d9d 1/* reiserfs.c - ReiserFS versions up to 3.6 */
2/*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2008 Free Software Foundation, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20/*
21 TODO:
22 implement journal handling (ram replay)
492e6d9d 23 test tail packing & direct files
24 validate partition label position
25*/
492e6d9d 26
492e6d9d 27#if 0
28# define GRUB_REISERFS_DEBUG
29# define GRUB_REISERFS_JOURNALING
30# define GRUB_HEXDUMP
31#endif
32
33#include <grub/err.h>
34#include <grub/file.h>
35#include <grub/mm.h>
36#include <grub/misc.h>
37#include <grub/disk.h>
38#include <grub/dl.h>
39#include <grub/types.h>
40#include <grub/fshelp.h>
41
42#define MIN(a, b) \
43 ({ typeof (a) _a = (a); \
44 typeof (b) _b = (b); \
45 _a < _b ? _a : _b; })
46
47#define MAX(a, b) \
48 ({ typeof (a) _a = (a); \
49 typeof (b) _b = (b); \
50 _a > _b ? _a : _b; })
51
52#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
53#define REISERFS_MAGIC_LEN 12
887d2619 54#define REISERFS_MAGIC_STRING "ReIsEr"
55#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
492e6d9d 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
60
61#define S_IFLNK 0xA000
62
492e6d9d 63static grub_dl_t my_mod;
492e6d9d 64
65#define assert(boolean) real_assert (boolean, __FILE__, __LINE__)
66static inline void
67real_assert (int boolean, const char *file, const int line)
68{
69 if (! boolean)
70 grub_printf ("Assertion failed at %s:%d\n", file, line);
71}
72
73enum grub_reiserfs_item_type
74 {
75 GRUB_REISERFS_STAT,
76 GRUB_REISERFS_DIRECTORY,
77 GRUB_REISERFS_DIRECT,
78 GRUB_REISERFS_INDIRECT,
79 /* Matches both _DIRECT and _INDIRECT when searching. */
80 GRUB_REISERFS_ANY,
81 GRUB_REISERFS_UNKNOWN
82 };
83
84struct grub_reiserfs_superblock
85{
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;
100 grub_uint16_t state;
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;
00c108a4 108 grub_uint8_t unused[4];
109 grub_uint16_t uuid[8];
492e6d9d 110} __attribute__ ((packed));
111
492e6d9d 112struct grub_reiserfs_journal_header
113{
114 grub_uint32_t last_flush_uid;
115 grub_uint32_t unflushed_offset;
116 grub_uint32_t mount_id;
117} __attribute__ ((packed));
118
887d2619 119struct grub_reiserfs_description_block
492e6d9d 120{
121 grub_uint32_t id;
122 grub_uint32_t len;
123 grub_uint32_t mount_id;
887d2619 124 grub_uint32_t real_blocks[0];
125} __attribute__ ((packed));
126
127struct grub_reiserfs_commit_block
128{
129 grub_uint32_t id;
130 grub_uint32_t len;
131 grub_uint32_t real_blocks[0];
492e6d9d 132} __attribute__ ((packed));
492e6d9d 133
134struct grub_reiserfs_stat_item_v1
135{
136 grub_uint16_t mode;
137 grub_uint16_t hardlink_count;
138 grub_uint16_t uid;
139 grub_uint16_t gid;
140 grub_uint32_t size;
141 grub_uint32_t atime;
142 grub_uint32_t mtime;
143 grub_uint32_t ctime;
144 grub_uint32_t rdev;
145 grub_uint32_t first_direct_byte;
146} __attribute__ ((packed));
147
148struct grub_reiserfs_stat_item_v2
149{
150 grub_uint16_t mode;
151 grub_uint16_t reserved;
152 grub_uint32_t hardlink_count;
153 grub_uint64_t size;
154 grub_uint32_t uid;
155 grub_uint32_t gid;
156 grub_uint32_t atime;
157 grub_uint32_t mtime;
158 grub_uint32_t ctime;
159 grub_uint32_t blocks;
160 grub_uint32_t first_direct_byte;
161} __attribute__ ((packed));
162
163struct grub_reiserfs_key
164{
165 grub_uint32_t directory_id;
166 grub_uint32_t object_id;
167 union
168 {
169 struct
170 {
171 grub_uint32_t offset;
172 grub_uint32_t type;
173 } v1 __attribute__ ((packed));
174 struct
175 {
492e6d9d 176 grub_uint64_t offset_type;
492e6d9d 177 } v2 __attribute__ ((packed));
178 } u;
179} __attribute__ ((packed));
180
181struct grub_reiserfs_item_header
182{
183 struct grub_reiserfs_key key;
184 union
185 {
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));
193
194struct grub_reiserfs_block_header
195{
196 grub_uint16_t level;
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));
202
203struct grub_reiserfs_disk_child
204{
205 grub_uint32_t block_number;
206 grub_uint16_t size;
207 grub_uint16_t reserved;
208} __attribute__ ((packed));
209
210struct grub_reiserfs_directory_header
211{
212 grub_uint32_t offset;
213 grub_uint32_t directory_id;
214 grub_uint32_t object_id;
215 grub_uint16_t location;
216 grub_uint16_t state;
217} __attribute__ ((packed));
218
492e6d9d 219struct grub_fshelp_node
220{
221 struct grub_reiserfs_data *data;
222 grub_uint32_t block_number; /* 0 if node is not found. */
223 grub_uint16_t block_position;
22da1f6f 224 grub_uint64_t next_offset;
492e6d9d 225 enum grub_reiserfs_item_type type; /* To know how to read the header. */
226 struct grub_reiserfs_item_header header;
227};
228
229/* Returned when opening a file. */
230struct grub_reiserfs_data
231{
232 struct grub_reiserfs_superblock superblock;
233 grub_disk_t disk;
234};
235
236/* Internal-only functions. Not to be used outside of this file. */
237
238/* Return the type of given v2 key. */
239static enum grub_reiserfs_item_type
240grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key *key)
241{
868967cf 242 switch (grub_le_to_cpu64 (key->u.v2.offset_type) >> 60)
492e6d9d 243 {
244 case 0:
245 return GRUB_REISERFS_STAT;
246 case 15:
247 return GRUB_REISERFS_ANY;
248 case 3:
249 return GRUB_REISERFS_DIRECTORY;
250 case 2:
251 return GRUB_REISERFS_DIRECT;
252 case 1:
253 return GRUB_REISERFS_INDIRECT;
254 }
255 return GRUB_REISERFS_UNKNOWN;
256}
257
258/* Return the type of given v1 key. */
259static enum grub_reiserfs_item_type
260grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key *key)
261{
262 switch (grub_le_to_cpu32 (key->u.v1.type))
263 {
264 case 0:
265 return GRUB_REISERFS_STAT;
266 case 555:
267 return GRUB_REISERFS_ANY;
268 case 500:
269 return GRUB_REISERFS_DIRECTORY;
270 case 0x20000000:
271 case 0xFFFFFFFF:
272 return GRUB_REISERFS_DIRECT;
273 case 0x10000000:
274 case 0xFFFFFFFE:
275 return GRUB_REISERFS_INDIRECT;
276 }
277 return GRUB_REISERFS_UNKNOWN;
278}
279
280/* Return 1 if the given key is version 1 key, 2 otherwise. */
281static int
282grub_reiserfs_get_key_version (const struct grub_reiserfs_key *key)
283{
284 return grub_reiserfs_get_key_v1_type (key) == GRUB_REISERFS_UNKNOWN ? 2 : 1;
285}
286
287#ifdef GRUB_HEXDUMP
288static void
289grub_hexdump (char *buffer, grub_size_t len)
290{
291 grub_size_t a;
292 for (a = 0; a < len; a++)
293 {
294 if (! (a & 0x0F))
295 grub_printf ("\n%08x ", a);
296 grub_printf ("%02x ",
297 ((unsigned int) ((unsigned char *) buffer)[a]) & 0xFF);
298 }
299 grub_printf ("\n");
300}
301#endif
302
303#ifdef GRUB_REISERFS_DEBUG
304static grub_uint64_t
305grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key);
306
307static enum grub_reiserfs_item_type
308grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key);
309
310static void
311grub_reiserfs_print_key (const struct grub_reiserfs_key *key)
312{
313 unsigned int a;
314 char *reiserfs_type_strings[] = {
315 "stat ",
316 "directory",
317 "direct ",
318 "indirect ",
319 "any ",
320 "unknown "
321 };
b39f9d20 322
492e6d9d 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));
331 else
332 grub_printf("0x%07x%08x",
333 (unsigned) (grub_reiserfs_get_key_offset (key) >> 32),
334 (unsigned) (grub_reiserfs_get_key_offset (key) & 0xFFFFFFFF));
335 grub_printf ("\n");
336}
337#endif
338
339/* Return the offset of given key. */
340static grub_uint64_t
341grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key)
342{
343 if (grub_reiserfs_get_key_version (key) == 1)
344 return grub_le_to_cpu32 (key->u.v1.offset);
345 else
52bd3de9 346 return grub_le_to_cpu64 (key->u.v2.offset_type) & (~0ULL >> 4);
492e6d9d 347}
348
349/* Set the offset of given key. */
350static void
351grub_reiserfs_set_key_offset (struct grub_reiserfs_key *key,
352 grub_uint64_t value)
353{
354 if (grub_reiserfs_get_key_version (key) == 1)
355 key->u.v1.offset = grub_cpu_to_le32 (value);
356 else
492e6d9d 357 key->u.v2.offset_type \
868967cf 358 = ((key->u.v2.offset_type & grub_cpu_to_le64 (15ULL << 60))
359 | grub_cpu_to_le64 (value & (~0ULL >> 4)));
492e6d9d 360}
361
362/* Return the type of given key. */
363static enum grub_reiserfs_item_type
364grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key)
365{
366 if (grub_reiserfs_get_key_version (key) == 1)
367 return grub_reiserfs_get_key_v1_type (key);
368 else
369 return grub_reiserfs_get_key_v2_type (key);
370}
371
372/* Set the type of given key, with given version number. */
373static void
374grub_reiserfs_set_key_type (struct grub_reiserfs_key *key,
375 enum grub_reiserfs_item_type grub_type,
376 int version)
377{
378 grub_uint32_t type;
b39f9d20 379
492e6d9d 380 switch (grub_type)
381 {
382 case GRUB_REISERFS_STAT:
383 type = 0;
384 break;
385 case GRUB_REISERFS_ANY:
386 type = (version == 1) ? 555 : 15;
387 break;
388 case GRUB_REISERFS_DIRECTORY:
389 type = (version == 1) ? 500 : 3;
390 break;
391 case GRUB_REISERFS_DIRECT:
392 type = (version == 1) ? 0xFFFFFFFF : 2;
393 break;
394 case GRUB_REISERFS_INDIRECT:
395 type = (version == 1) ? 0xFFFFFFFE : 1;
396 break;
397 default:
398 return;
399 }
b39f9d20 400
492e6d9d 401 if (version == 1)
402 key->u.v1.type = grub_cpu_to_le32 (type);
403 else
52bd3de9 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));
b39f9d20 407
492e6d9d 408 assert (grub_reiserfs_get_key_type (key) == grub_type);
409}
410
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. */
414static int
415grub_reiserfs_compare_keys (const struct grub_reiserfs_key *key1,
416 const struct grub_reiserfs_key *key2)
417{
418 grub_uint64_t offset1, offset2;
419 enum grub_reiserfs_item_type type1, type2;
420 grub_uint32_t id1, id2;
b39f9d20 421
492e6d9d 422 if (! key1 || ! key2)
423 return -2;
b39f9d20 424
492e6d9d 425 id1 = grub_le_to_cpu32 (key1->directory_id);
426 id2 = grub_le_to_cpu32 (key2->directory_id);
427 if (id1 < id2)
428 return -1;
429 if (id1 > id2)
430 return 1;
b39f9d20 431
492e6d9d 432 id1 = grub_le_to_cpu32 (key1->object_id);
433 id2 = grub_le_to_cpu32 (key2->object_id);
434 if (id1 < id2)
435 return -1;
436 if (id1 > id2)
437 return 1;
b39f9d20 438
492e6d9d 439 offset1 = grub_reiserfs_get_key_offset (key1);
440 offset2 = grub_reiserfs_get_key_offset (key2);
441 if (offset1 < offset2)
442 return -1;
443 if (offset1 > offset2)
444 return 1;
b39f9d20 445
492e6d9d 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)))
454 return 0;
455 if (type1 < type2)
456 return -1;
457 if (type1 > type2)
458 return 1;
b39f9d20 459
492e6d9d 460 return 0;
461}
462
463/* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
464 accordingly to what was found. */
465static grub_err_t
466grub_reiserfs_get_item (struct grub_reiserfs_data *data,
467 const struct grub_reiserfs_key *key,
468 struct grub_fshelp_node *item)
469{
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;
474 grub_uint16_t i;
475 grub_uint16_t previous_level = ~0;
476 struct grub_reiserfs_item_header *item_headers = 0;
b39f9d20 477
492e6d9d 478 if (! data)
479 {
480 grub_error (GRUB_ERR_TEST_FAILURE, "data is NULL");
481 goto fail;
482 }
483
484 if (! key)
485 {
486 grub_error (GRUB_ERR_TEST_FAILURE, "key is NULL");
487 goto fail;
488 }
489
490 if (! item)
491 {
492 grub_error (GRUB_ERR_TEST_FAILURE, "item is NULL");
493 goto fail;
494 }
b39f9d20 495
492e6d9d 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);
501#endif
502 block_header = grub_malloc (block_size);
503 if (! block_header)
504 goto fail;
b39f9d20 505
22da1f6f 506 item->next_offset = 0;
492e6d9d 507 do
508 {
509 grub_disk_read (data->disk,
d31a32a1 510 block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
492e6d9d 511 (((grub_off_t) block_number * block_size)
512 & (GRUB_DISK_SECTOR_SIZE - 1)),
238e871f 513 block_size, block_header);
492e6d9d 514 if (grub_errno)
515 goto fail;
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)
519 {
520 grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
521 grub_error (GRUB_ERR_FILE_READ_ERROR, "level loop");
522 goto fail;
523 }
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",
527 item_count);
528 if (current_level > 1)
529 {
530 /* Internal node. Navigate to the child that should contain
531 the searched key. */
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));
b39f9d20 537
492e6d9d 538 for (i = 0;
539 i < item_count
540 && grub_reiserfs_compare_keys (key, &(keys[i])) >= 0;
541 i++)
542 {
543#ifdef GRUB_REISERFS_DEBUG
544 grub_printf("i %03d/%03d ", i + 1, item_count + 1);
545 grub_reiserfs_print_key (&(keys[i]));
546#endif
547 }
548 block_number = grub_le_to_cpu32 (children[i].block_number);
22da1f6f 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]));
492e6d9d 552#ifdef GRUB_REISERFS_DEBUG
553 if (i == item_count
554 || grub_reiserfs_compare_keys (key, &(keys[i])) == 0)
555 grub_printf(">");
556 else
557 grub_printf("<");
558 if (i < item_count)
559 {
560 grub_printf (" %03d/%03d ", i + 1, item_count + 1);
561 grub_reiserfs_print_key (&(keys[i]));
562 if (i + 1 < item_count)
563 {
564 grub_printf ("+ %03d/%03d ", i + 2, item_count);
565 grub_reiserfs_print_key (&(keys[i + 1]));
566 }
567 }
568 else
569 grub_printf ("Accessing rightmost child at block %d.\n",
570 block_number);
571#endif
572 }
573 else
574 {
575 /* Leaf node. Check that the key is actually present. */
576 item_headers
577 = (struct grub_reiserfs_item_header *) (block_header + 1);
578 for (i = 0;
579 i < item_count
580 && (grub_reiserfs_compare_keys (key, &(item_headers[i].key))
581 != 0);
582 i++)
583 {
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)
587 grub_printf("C");
588 else
589 grub_printf(" ");
590 grub_printf(" %03d/%03d ", i + 1, item_count);
591 grub_reiserfs_print_key (&(item_headers[i].key));
592#endif
593 }
594 if (i < item_count)
595 block_key = &(item_headers[i].key);
596 }
597 }
598 while (current_level > 1);
599
600 item->data = data;
601
602 if (i == item_count || grub_reiserfs_compare_keys (key, block_key))
603 {
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");
609#endif
610 }
611 else
612 {
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);
621#endif
622 }
b39f9d20 623
492e6d9d 624 assert (grub_errno == GRUB_ERR_NONE);
625 grub_free (block_header);
626 return GRUB_ERR_NONE;
627
628 fail:
629 assert (grub_errno != GRUB_ERR_NONE);
630 grub_free (block_header);
631 assert (grub_errno != GRUB_ERR_NONE);
632 return grub_errno;
633}
634
635/* Return the path of the file which is pointed at by symlink NODE. */
636static char *
637grub_reiserfs_read_symlink (grub_fshelp_node_t node)
638{
639 char *symlink_buffer = 0;
640 grub_uint16_t block_size;
641 grub_disk_addr_t block;
642 grub_off_t offset;
643 grub_size_t len;
644 struct grub_fshelp_node found;
645 struct grub_reiserfs_key key;
646
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));
651
652 if (grub_reiserfs_get_item (node->data, &key, &found) != GRUB_ERR_NONE)
653 goto fail;
654
655 if (found.block_number == 0)
656 goto fail;
657
658 block_size = grub_le_to_cpu16 (node->data->superblock.block_size);
659 len = grub_le_to_cpu16 (found.header.item_size);
d31a32a1 660 block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
492e6d9d 661 offset = grub_le_to_cpu16 (found.header.item_location);
662
2b89344e 663 symlink_buffer = grub_malloc (len + 1);
492e6d9d 664 if (! symlink_buffer)
665 goto fail;
666
667 grub_disk_read (node->data->disk, block, offset, len, symlink_buffer);
668 if (grub_errno)
669 goto fail;
670
2b89344e 671 symlink_buffer[len] = 0;
492e6d9d 672 return symlink_buffer;
673
674 fail:
675 grub_free (symlink_buffer);
676 return 0;
677}
678
679/* Fill the mounted filesystem structure and return it. */
680static struct grub_reiserfs_data *
681grub_reiserfs_mount (grub_disk_t disk)
682{
683 struct grub_reiserfs_data *data = 0;
684 data = grub_malloc (sizeof (*data));
685 if (! data)
686 goto fail;
687 grub_disk_read (disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
238e871f 688 0, sizeof (data->superblock), &(data->superblock));
492e6d9d 689 if (grub_errno)
690 goto fail;
691 if (grub_memcmp (data->superblock.magic_string,
887d2619 692 REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1))
492e6d9d 693 {
694 grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem");
695 goto fail;
696 }
697 data->disk = disk;
698 return data;
699
700 fail:
1a8b0526 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");
704
492e6d9d 705 grub_free (data);
706 return 0;
707}
708
709/* Call HOOK for each file in directory ITEM. */
710static int
711grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
712 int NESTED_FUNC_ATTR
713 (*hook) (const char *filename,
714 enum grub_fshelp_filetype filetype,
715 grub_fshelp_node_t node))
716{
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;
22da1f6f 721 grub_uint64_t next_offset = item->next_offset;
868967cf 722 int ret = 0;
492e6d9d 723
724 if (item->type != GRUB_REISERFS_DIRECTORY)
725 {
726 grub_error (GRUB_ERR_BAD_FILE_TYPE,
727 "grub_reiserfs_iterate_dir called on a non-directory item");
728 goto fail;
729 }
730 block_size = grub_le_to_cpu16 (data->superblock.block_size);
731 block_header = grub_malloc (block_size);
732 if (! block_header)
733 goto fail;
734 block_number = item->block_number;
735 block_position = item->block_position;
736 grub_dprintf ("reiserfs", "Iterating directory...\n");
737 do
738 {
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;
b39f9d20 743
492e6d9d 744 grub_disk_read (data->disk,
d31a32a1 745 block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
492e6d9d 746 (((grub_off_t) block_number * block_size)
747 & (GRUB_DISK_SECTOR_SIZE - 1)),
748 block_size, (char *) block_header);
749 if (grub_errno)
750 goto fail;
751
752#if 0
753 if (grub_le_to_cpu16 (block_header->level) != 1)
754 {
755 grub_error (GRUB_ERR_TEST_FAILURE,
756 "reiserfs: block %d is not a leaf block",
757 block_number);
758 goto fail;
759 }
760#endif
b39f9d20 761
492e6d9d 762 item_headers = (struct grub_reiserfs_item_header *) (block_header + 1);
763 directory_headers
764 = ((struct grub_reiserfs_directory_header *)
765 ((char *) block_header
766 + grub_le_to_cpu16 (item_headers[block_position].item_location)));
767 entry_count
768 = grub_le_to_cpu16 (item_headers[block_position].u.entry_count);
769 for (entry_number = 0; entry_number < entry_count; entry_number++)
770 {
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);
b39f9d20 775
492e6d9d 776 if (entry_state & GRUB_REISERFS_VISIBLE_MASK)
777 {
f5db4291 778 grub_fshelp_node_t entry_item;
492e6d9d 779 struct grub_reiserfs_key entry_key;
780 enum grub_reiserfs_item_type entry_type;
781 char *entry_name;
782
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;
492e6d9d 787 entry_key.u.v2.offset_type = 0;
492e6d9d 788 grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_DIRECTORY,
789 2);
790 grub_reiserfs_set_key_offset (&entry_key, 1);
f5db4291 791
792 entry_item = grub_malloc (sizeof (*entry_item));
793 if (! entry_item)
492e6d9d 794 goto fail;
b39f9d20 795
f5db4291 796 if (grub_reiserfs_get_item (data, &entry_key, entry_item)
797 != GRUB_ERR_NONE)
798 {
799 grub_free (entry_item);
800 goto fail;
801 }
b39f9d20 802
f5db4291 803 if (entry_item->type == GRUB_REISERFS_DIRECTORY)
492e6d9d 804 entry_type = GRUB_FSHELP_DIR;
805 else
806 {
807 grub_uint32_t entry_block_number;
808 /* Order is very important here.
809 First set the offset to 0 using current key version.
4241d2b1 810 Then change the key type, which affects key version
492e6d9d 811 detection. */
812 grub_reiserfs_set_key_offset (&entry_key, 0);
813 grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_STAT,
814 2);
f5db4291 815 if (grub_reiserfs_get_item (data, &entry_key, entry_item)
492e6d9d 816 != GRUB_ERR_NONE)
f5db4291 817 {
818 grub_free (entry_item);
819 goto fail;
820 }
821
822 if (entry_item->block_number != 0)
492e6d9d 823 {
824 grub_uint16_t entry_version;
825 entry_version
f5db4291 826 = grub_le_to_cpu16 (entry_item->header.version);
827 entry_block_number = entry_item->block_number;
492e6d9d 828#if 0
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,
f5db4291 833 grub_le_to_cpu16 (entry_item->header.item_location));
492e6d9d 834#endif
835 if (entry_version == 0) /* Version 1 stat item. */
836 {
837 struct grub_reiserfs_stat_item_v1 entry_v1_stat;
838 grub_disk_read (data->disk,
d31a32a1 839 entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
f5db4291 840 grub_le_to_cpu16 (entry_item->header.item_location),
492e6d9d 841 sizeof (entry_v1_stat),
842 (char *) &entry_v1_stat);
843 if (grub_errno)
844 goto fail;
845#if 0
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",
860 entry_v1_stat.mode,
861 entry_v1_stat.hardlink_count,
862 entry_v1_stat.uid,
863 entry_v1_stat.gid,
864 entry_v1_stat.size,
865 entry_v1_stat.atime,
866 entry_v1_stat.mtime,
867 entry_v1_stat.ctime,
868 entry_v1_stat.rdev,
869 entry_v1_stat.first_direct_byte);
870#endif
871 if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK)
872 == S_IFLNK)
873 entry_type = GRUB_FSHELP_SYMLINK;
874 else
875 entry_type = GRUB_FSHELP_REG;
876 }
877 else
878 {
879 struct grub_reiserfs_stat_item_v2 entry_v2_stat;
880 grub_disk_read (data->disk,
d31a32a1 881 entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
f5db4291 882 grub_le_to_cpu16 (entry_item->header.item_location),
492e6d9d 883 sizeof (entry_v2_stat),
884 (char *) &entry_v2_stat);
885 if (grub_errno)
886 goto fail;
887#if 0
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",
904 entry_v2_stat.mode,
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),
909 entry_v2_stat.uid,
910 entry_v2_stat.gid,
911 entry_v2_stat.atime,
912 entry_v2_stat.mtime,
913 entry_v2_stat.ctime,
914 entry_v2_stat.blocks,
915 entry_v2_stat.first_direct_byte);
916#endif
917 if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
918 == S_IFLNK)
919 entry_type = GRUB_FSHELP_SYMLINK;
920 else
921 entry_type = GRUB_FSHELP_REG;
922 }
923 }
924 else
925 {
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",
930 entry_name);
f5db4291 931 grub_free (entry_item);
492e6d9d 932 continue;
933 }
934 }
f5db4291 935 if (hook (entry_name, entry_type, entry_item))
492e6d9d 936 {
937 grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
938 entry_name, entry_type);
868967cf 939 ret = 1;
492e6d9d 940 goto found;
941 }
f5db4291 942
492e6d9d 943 *entry_name = 0; /* Make sure next entry name (which is just
944 before this one in disk order) stops before
945 the current one. */
946 }
947 }
b39f9d20 948
22da1f6f 949 if (next_offset == 0)
950 break;
492e6d9d 951
492e6d9d 952 grub_reiserfs_set_key_offset (&(item_headers[block_position].key),
22da1f6f 953 next_offset);
492e6d9d 954 if (grub_reiserfs_get_item (data, &(item_headers[block_position].key),
955 &directory_item) != GRUB_ERR_NONE)
956 goto fail;
957 block_number = directory_item.block_number;
958 block_position = directory_item.block_position;
22da1f6f 959 next_offset = directory_item.next_offset;
492e6d9d 960 }
961 while (block_number);
962
963 found:
964 assert (grub_errno == GRUB_ERR_NONE);
965 grub_free (block_header);
868967cf 966 return ret;
492e6d9d 967 fail:
968 assert (grub_errno != GRUB_ERR_NONE);
969 grub_free (block_header);
868967cf 970 return 0;
492e6d9d 971}
972
973/****************************************************************************/
974/* grub api functions */
975/****************************************************************************/
976
977/* Open a file named NAME and initialize FILE. */
978static grub_err_t
979grub_reiserfs_open (struct grub_file *file, const char *name)
980{
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;
986
492e6d9d 987 grub_dl_ref (my_mod);
492e6d9d 988 data = grub_reiserfs_mount (file->device->disk);
989 if (! data)
990 goto fail;
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);
492e6d9d 994 key.u.v2.offset_type = 0;
492e6d9d 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)
998 goto fail;
999 if (root.block_number == 0)
1000 {
1001 grub_error (GRUB_ERR_BAD_FS, "Unable to find root item");
1002 goto fail; /* Should never happen since checked at mount. */
1003 }
1004 grub_fshelp_find_file (name, &root, &found,
1005 grub_reiserfs_iterate_dir,
1006 grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
1007 if (grub_errno)
1008 goto fail;
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)
1014 goto fail;
1015 if (info.block_number == 0)
1016 {
1017 grub_error (GRUB_ERR_BAD_FS, "Unable to find searched item");
1018 goto fail;
1019 }
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. */
1024 {
1025 struct grub_reiserfs_stat_item_v1 entry_v1_stat;
1026 grub_disk_read (data->disk,
d31a32a1 1027 block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
492e6d9d 1028 entry_location
1029 + (((grub_off_t) block_number * block_size)
1030 & (GRUB_DISK_SECTOR_SIZE - 1)),
238e871f 1031 sizeof (entry_v1_stat), &entry_v1_stat);
492e6d9d 1032 if (grub_errno)
1033 goto fail;
1034 file->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
1035 }
1036 else
1037 {
1038 struct grub_reiserfs_stat_item_v2 entry_v2_stat;
1039 grub_disk_read (data->disk,
d31a32a1 1040 block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
492e6d9d 1041 entry_location
1042 + (((grub_off_t) block_number * block_size)
1043 & (GRUB_DISK_SECTOR_SIZE - 1)),
238e871f 1044 sizeof (entry_v2_stat), &entry_v2_stat);
492e6d9d 1045 if (grub_errno)
1046 goto fail;
1047 file->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
1048 }
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);
1052 file->offset = 0;
1053 file->data = found;
1054 return GRUB_ERR_NONE;
1055
1056 fail:
1057 assert (grub_errno != GRUB_ERR_NONE);
1058 grub_free (found);
1059 grub_free (data);
492e6d9d 1060 grub_dl_unref (my_mod);
492e6d9d 1061 return grub_errno;
1062}
1063
1064static grub_ssize_t
1065grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
1066{
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;
c9c8e606 1076 grub_off_t initial_position, current_position, final_position, length;
492e6d9d 1077 grub_disk_addr_t block;
1078 grub_off_t offset;
1079
1080 if (file->offset >= file->size)
1081 return 0;
1082
1083 key.directory_id = node->header.key.directory_id;
1084 key.object_id = node->header.key.object_id;
492e6d9d 1085 key.u.v2.offset_type = 0;
492e6d9d 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",
c9c8e606 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);
492e6d9d 1096 while (current_position < final_position)
1097 {
1098 grub_reiserfs_set_key_offset (&key, current_key_offset);
b39f9d20 1099
492e6d9d 1100 if (grub_reiserfs_get_item (data, &key, &found) != GRUB_ERR_NONE)
1101 goto fail;
1102 if (found.block_number == 0)
1103 goto fail;
1104 item_size = grub_le_to_cpu16 (found.header.item_size);
1105 switch (found.type)
1106 {
1107 case GRUB_REISERFS_DIRECT:
d31a32a1 1108 block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
492e6d9d 1109 grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
1110 if (initial_position < current_position + item_size)
1111 {
1112 offset = MAX ((signed) (initial_position - current_position), 0);
1113 length = (MIN (item_size, final_position - current_position)
1114 - offset);
1115 grub_dprintf ("reiserfs",
1116 "Reading direct block %u from %u to %u...\n",
1117 (unsigned) block, (unsigned) offset,
0e9e51ec 1118 (unsigned) (offset + length));
492e6d9d 1119 found.data->disk->read_hook = file->read_hook;
1120 grub_disk_read (found.data->disk,
1121 block,
1122 offset
1123 + grub_le_to_cpu16 (found.header.item_location),
1124 length, buf);
1125 found.data->disk->read_hook = 0;
1126 if (grub_errno)
1127 goto fail;
1128 buf += length;
1129 current_position += offset + length;
1130 }
1131 else
1132 current_position += item_size;
1133 break;
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)
1138 goto fail;
1139 grub_disk_read (found.data->disk,
d31a32a1 1140 found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
492e6d9d 1141 grub_le_to_cpu16 (found.header.item_location),
238e871f 1142 item_size, indirect_block_ptr);
492e6d9d 1143 if (grub_errno)
1144 goto fail;
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;
1149 indirect_block++)
1150 {
d31a32a1 1151 block = grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) *
1152 (block_size >> GRUB_DISK_SECTOR_BITS);
492e6d9d 1153 grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
1154 if (current_position + block_size >= initial_position)
1155 {
1156 offset = MAX ((signed) (initial_position - current_position),
1157 0);
1158 length = (MIN (block_size, final_position - current_position)
1159 - offset);
1160 grub_dprintf ("reiserfs",
1161 "Reading indirect block %u from %u to %u...\n",
1162 (unsigned) block, (unsigned) offset,
0e9e51ec 1163 (unsigned) (offset + length));
492e6d9d 1164#if 0
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);
1170#endif
1171 grub_disk_read (found.data->disk, block, offset, length, buf);
1172 if (grub_errno)
1173 goto fail;
1174 buf += length;
1175 current_position += offset + length;
1176 }
1177 else
1178 current_position += block_size;
1179 }
1180 found.data->disk->read_hook = 0;
1181 grub_free (indirect_block_ptr);
1182 indirect_block_ptr = 0;
1183 break;
1184 default:
1185 goto fail;
1186 }
1187 current_key_offset = current_position + 1;
1188 }
b39f9d20 1189
c9c8e606 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);
492e6d9d 1194 return current_position - initial_position;
1195/*
1196 switch (found.type)
1197 {
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,
1203 read_length, buf);
1204 if (grub_errno)
1205 goto fail;
1206 break;
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)
1211 goto fail;
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);
1216 if (grub_errno)
1217 goto fail;
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;
1221 indirect_block++)
1222 {
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);
1228 if (grub_errno)
1229 goto fail;
1230 read_length += read;
1231 }
1232 grub_free (indirect_block_ptr);
1233 break;
1234 default:
1235 goto fail;
1236 }
1237
1238 return read_length;*/
1239
1240 fail:
1241 grub_free (indirect_block_ptr);
1242 return 0;
1243}
1244
1245/* Close the file FILE. */
1246static grub_err_t
1247grub_reiserfs_close (grub_file_t file)
1248{
1249 struct grub_fshelp_node *node = file->data;
1250 struct grub_reiserfs_data *data = node->data;
1251
1252 grub_free (data);
1253 grub_free (node);
492e6d9d 1254 grub_dl_unref (my_mod);
492e6d9d 1255 return GRUB_ERR_NONE;
1256}
1257
1258/* Call HOOK with each file under DIR. */
1259static grub_err_t
1260grub_reiserfs_dir (grub_device_t device, const char *path,
b39f9d20 1261 int (*hook) (const char *filename,
05aaebfb 1262 const struct grub_dirhook_info *info))
492e6d9d 1263{
1264 struct grub_reiserfs_data *data = 0;
1265 struct grub_fshelp_node root, *found;
1266 struct grub_reiserfs_key root_key;
1267
1268 auto int NESTED_FUNC_ATTR iterate (const char *filename,
1269 enum grub_fshelp_filetype filetype,
1270 grub_fshelp_node_t node);
1271
1272 int NESTED_FUNC_ATTR iterate (const char *filename,
1273 enum grub_fshelp_filetype filetype,
1274 grub_fshelp_node_t node)
1275 {
05aaebfb 1276 struct grub_dirhook_info info;
1277 grub_memset (&info, 0, sizeof (info));
1278 info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
492e6d9d 1279 grub_free (node);
05aaebfb 1280 return hook (filename, &info);
492e6d9d 1281 }
492e6d9d 1282 grub_dl_ref (my_mod);
492e6d9d 1283 data = grub_reiserfs_mount (device->disk);
1284 if (! data)
1285 goto fail;
1286 root_key.directory_id = grub_cpu_to_le32 (1);
1287 root_key.object_id = grub_cpu_to_le32 (2);
492e6d9d 1288 root_key.u.v2.offset_type = 0;
492e6d9d 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)
1292 goto fail;
1293 if (root.block_number == 0)
1294 {
1295 grub_error(GRUB_ERR_BAD_FS, "Root not found");
1296 goto fail;
1297 }
1298 grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir,
1299 grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
1300 if (grub_errno)
1301 goto fail;
1302 grub_reiserfs_iterate_dir (found, iterate);
1303 grub_free (data);
492e6d9d 1304 grub_dl_unref (my_mod);
492e6d9d 1305 return GRUB_ERR_NONE;
1306
1307 fail:
1308 grub_free (data);
492e6d9d 1309 grub_dl_unref (my_mod);
492e6d9d 1310 return grub_errno;
1311}
1312
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
1315 caller. */
1316static grub_err_t
1317grub_reiserfs_label (grub_device_t device, char **label)
1318{
1319 *label = grub_malloc (REISERFS_MAX_LABEL_LENGTH);
1320 if (*label)
1321 {
1322 grub_disk_read (device->disk,
1323 REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
1324 REISERFS_LABEL_OFFSET, REISERFS_MAX_LABEL_LENGTH,
1325 *label);
1326 }
1327 return grub_errno;
1328}
1329
00c108a4 1330static grub_err_t
1331grub_reiserfs_uuid (grub_device_t device, char **uuid)
1332{
1333 struct grub_reiserfs_data *data;
1334 grub_disk_t disk = device->disk;
1335
00c108a4 1336 grub_dl_ref (my_mod);
00c108a4 1337
1338 data = grub_reiserfs_mount (disk);
1339 if (data)
1340 {
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]));
1347 }
1348 else
1349 *uuid = NULL;
1350
00c108a4 1351 grub_dl_unref (my_mod);
00c108a4 1352
1353 grub_free (data);
1354
1355 return grub_errno;
1356}
1357
492e6d9d 1358static struct grub_fs grub_reiserfs_fs =
1359 {
1360 .name = "reiserfs",
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,
00c108a4 1366 .uuid = grub_reiserfs_uuid,
492e6d9d 1367 .next = 0
1368 };
1369
1370GRUB_MOD_INIT(reiserfs)
1371{
1372 grub_fs_register (&grub_reiserfs_fs);
492e6d9d 1373 my_mod = mod;
492e6d9d 1374}
1375
1376GRUB_MOD_FINI(reiserfs)
1377{
1378 grub_fs_unregister (&grub_reiserfs_fs);
1379}