]> git.proxmox.com Git - grub2.git/blob - fs/reiserfs.c
2008-05-20 Bean <bean123ch@gmail.com>
[grub2.git] / fs / reiserfs.c
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)
23 test tail packing & direct files
24 validate partition label position
25 */
26 #warning "TODO : journal, tail packing (?)"
27
28 #if 0
29 # define GRUB_REISERFS_DEBUG
30 # define GRUB_REISERFS_JOURNALING
31 # define GRUB_HEXDUMP
32 #endif
33
34 #include <grub/err.h>
35 #include <grub/file.h>
36 #include <grub/mm.h>
37 #include <grub/misc.h>
38 #include <grub/disk.h>
39 #include <grub/dl.h>
40 #include <grub/types.h>
41 #include <grub/fshelp.h>
42
43 #define MIN(a, b) \
44 ({ typeof (a) _a = (a); \
45 typeof (b) _b = (b); \
46 _a < _b ? _a : _b; })
47
48 #define MAX(a, b) \
49 ({ typeof (a) _a = (a); \
50 typeof (b) _b = (b); \
51 _a > _b ? _a : _b; })
52
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
61
62 #define S_IFLNK 0xA000
63
64 #ifndef GRUB_UTIL
65 static grub_dl_t my_mod;
66 #endif
67
68 #define assert(boolean) real_assert (boolean, __FILE__, __LINE__)
69 static inline void
70 real_assert (int boolean, const char *file, const int line)
71 {
72 if (! boolean)
73 grub_printf ("Assertion failed at %s:%d\n", file, line);
74 }
75
76 enum grub_reiserfs_item_type
77 {
78 GRUB_REISERFS_STAT,
79 GRUB_REISERFS_DIRECTORY,
80 GRUB_REISERFS_DIRECT,
81 GRUB_REISERFS_INDIRECT,
82 /* Matches both _DIRECT and _INDIRECT when searching. */
83 GRUB_REISERFS_ANY,
84 GRUB_REISERFS_UNKNOWN
85 };
86
87 struct grub_reiserfs_superblock
88 {
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;
103 grub_uint16_t state;
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));
112
113 struct grub_reiserfs_journal_header
114 {
115 grub_uint32_t last_flush_uid;
116 grub_uint32_t unflushed_offset;
117 grub_uint32_t mount_id;
118 } __attribute__ ((packed));
119
120 struct grub_reiserfs_description_block
121 {
122 grub_uint32_t id;
123 grub_uint32_t len;
124 grub_uint32_t mount_id;
125 grub_uint32_t real_blocks[0];
126 } __attribute__ ((packed));
127
128 struct grub_reiserfs_commit_block
129 {
130 grub_uint32_t id;
131 grub_uint32_t len;
132 grub_uint32_t real_blocks[0];
133 } __attribute__ ((packed));
134
135 struct grub_reiserfs_stat_item_v1
136 {
137 grub_uint16_t mode;
138 grub_uint16_t hardlink_count;
139 grub_uint16_t uid;
140 grub_uint16_t gid;
141 grub_uint32_t size;
142 grub_uint32_t atime;
143 grub_uint32_t mtime;
144 grub_uint32_t ctime;
145 grub_uint32_t rdev;
146 grub_uint32_t first_direct_byte;
147 } __attribute__ ((packed));
148
149 struct grub_reiserfs_stat_item_v2
150 {
151 grub_uint16_t mode;
152 grub_uint16_t reserved;
153 grub_uint32_t hardlink_count;
154 grub_uint64_t size;
155 grub_uint32_t uid;
156 grub_uint32_t gid;
157 grub_uint32_t atime;
158 grub_uint32_t mtime;
159 grub_uint32_t ctime;
160 grub_uint32_t blocks;
161 grub_uint32_t first_direct_byte;
162 } __attribute__ ((packed));
163
164 struct grub_reiserfs_key
165 {
166 grub_uint32_t directory_id;
167 grub_uint32_t object_id;
168 union
169 {
170 struct
171 {
172 grub_uint32_t offset;
173 grub_uint32_t type;
174 } v1 __attribute__ ((packed));
175 struct
176 {
177 grub_uint64_t offset_type;
178 } v2 __attribute__ ((packed));
179 } u;
180 } __attribute__ ((packed));
181
182 struct grub_reiserfs_item_header
183 {
184 struct grub_reiserfs_key key;
185 union
186 {
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));
194
195 struct grub_reiserfs_block_header
196 {
197 grub_uint16_t level;
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));
203
204 struct grub_reiserfs_disk_child
205 {
206 grub_uint32_t block_number;
207 grub_uint16_t size;
208 grub_uint16_t reserved;
209 } __attribute__ ((packed));
210
211 struct grub_reiserfs_directory_header
212 {
213 grub_uint32_t offset;
214 grub_uint32_t directory_id;
215 grub_uint32_t object_id;
216 grub_uint16_t location;
217 grub_uint16_t state;
218 } __attribute__ ((packed));
219
220 struct grub_fshelp_node
221 {
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;
228 };
229
230 /* Returned when opening a file. */
231 struct grub_reiserfs_data
232 {
233 struct grub_reiserfs_superblock superblock;
234 grub_disk_t disk;
235 grub_fshelp_journal_t journal;
236 };
237
238 /* Internal-only functions. Not to be used outside of this file. */
239
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)
243 {
244 switch (grub_le_to_cpu64 (key->u.v2.offset_type) >> 60)
245 {
246 case 0:
247 return GRUB_REISERFS_STAT;
248 case 15:
249 return GRUB_REISERFS_ANY;
250 case 3:
251 return GRUB_REISERFS_DIRECTORY;
252 case 2:
253 return GRUB_REISERFS_DIRECT;
254 case 1:
255 return GRUB_REISERFS_INDIRECT;
256 }
257 return GRUB_REISERFS_UNKNOWN;
258 }
259
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)
263 {
264 switch (grub_le_to_cpu32 (key->u.v1.type))
265 {
266 case 0:
267 return GRUB_REISERFS_STAT;
268 case 555:
269 return GRUB_REISERFS_ANY;
270 case 500:
271 return GRUB_REISERFS_DIRECTORY;
272 case 0x20000000:
273 case 0xFFFFFFFF:
274 return GRUB_REISERFS_DIRECT;
275 case 0x10000000:
276 case 0xFFFFFFFE:
277 return GRUB_REISERFS_INDIRECT;
278 }
279 return GRUB_REISERFS_UNKNOWN;
280 }
281
282 /* Return 1 if the given key is version 1 key, 2 otherwise. */
283 static int
284 grub_reiserfs_get_key_version (const struct grub_reiserfs_key *key)
285 {
286 return grub_reiserfs_get_key_v1_type (key) == GRUB_REISERFS_UNKNOWN ? 2 : 1;
287 }
288
289 #ifdef GRUB_HEXDUMP
290 static void
291 grub_hexdump (char *buffer, grub_size_t len)
292 {
293 grub_size_t a;
294 for (a = 0; a < len; a++)
295 {
296 if (! (a & 0x0F))
297 grub_printf ("\n%08x ", a);
298 grub_printf ("%02x ",
299 ((unsigned int) ((unsigned char *) buffer)[a]) & 0xFF);
300 }
301 grub_printf ("\n");
302 }
303 #endif
304
305 #ifdef GRUB_REISERFS_DEBUG
306 static grub_uint64_t
307 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key);
308
309 static enum grub_reiserfs_item_type
310 grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key);
311
312 static void
313 grub_reiserfs_print_key (const struct grub_reiserfs_key *key)
314 {
315 unsigned int a;
316 char *reiserfs_type_strings[] = {
317 "stat ",
318 "directory",
319 "direct ",
320 "indirect ",
321 "any ",
322 "unknown "
323 };
324
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));
333 else
334 grub_printf("0x%07x%08x",
335 (unsigned) (grub_reiserfs_get_key_offset (key) >> 32),
336 (unsigned) (grub_reiserfs_get_key_offset (key) & 0xFFFFFFFF));
337 grub_printf ("\n");
338 }
339 #endif
340
341 /* Return the offset of given key. */
342 static grub_uint64_t
343 grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key)
344 {
345 if (grub_reiserfs_get_key_version (key) == 1)
346 return grub_le_to_cpu32 (key->u.v1.offset);
347 else
348 return grub_le_to_cpu64 (key->u.v2.offset_type) & (~0ULL >> 4);
349 }
350
351 /* Set the offset of given key. */
352 static void
353 grub_reiserfs_set_key_offset (struct grub_reiserfs_key *key,
354 grub_uint64_t value)
355 {
356 if (grub_reiserfs_get_key_version (key) == 1)
357 key->u.v1.offset = grub_cpu_to_le32 (value);
358 else
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)));
362 }
363
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)
367 {
368 if (grub_reiserfs_get_key_version (key) == 1)
369 return grub_reiserfs_get_key_v1_type (key);
370 else
371 return grub_reiserfs_get_key_v2_type (key);
372 }
373
374 /* Set the type of given key, with given version number. */
375 static void
376 grub_reiserfs_set_key_type (struct grub_reiserfs_key *key,
377 enum grub_reiserfs_item_type grub_type,
378 int version)
379 {
380 grub_uint32_t type;
381
382 switch (grub_type)
383 {
384 case GRUB_REISERFS_STAT:
385 type = 0;
386 break;
387 case GRUB_REISERFS_ANY:
388 type = (version == 1) ? 555 : 15;
389 break;
390 case GRUB_REISERFS_DIRECTORY:
391 type = (version == 1) ? 500 : 3;
392 break;
393 case GRUB_REISERFS_DIRECT:
394 type = (version == 1) ? 0xFFFFFFFF : 2;
395 break;
396 case GRUB_REISERFS_INDIRECT:
397 type = (version == 1) ? 0xFFFFFFFE : 1;
398 break;
399 default:
400 return;
401 }
402
403 if (version == 1)
404 key->u.v1.type = grub_cpu_to_le32 (type);
405 else
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));
409
410 assert (grub_reiserfs_get_key_type (key) == grub_type);
411 }
412
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. */
416 static int
417 grub_reiserfs_compare_keys (const struct grub_reiserfs_key *key1,
418 const struct grub_reiserfs_key *key2)
419 {
420 grub_uint64_t offset1, offset2;
421 enum grub_reiserfs_item_type type1, type2;
422 grub_uint32_t id1, id2;
423
424 if (! key1 || ! key2)
425 return -2;
426
427 id1 = grub_le_to_cpu32 (key1->directory_id);
428 id2 = grub_le_to_cpu32 (key2->directory_id);
429 if (id1 < id2)
430 return -1;
431 if (id1 > id2)
432 return 1;
433
434 id1 = grub_le_to_cpu32 (key1->object_id);
435 id2 = grub_le_to_cpu32 (key2->object_id);
436 if (id1 < id2)
437 return -1;
438 if (id1 > id2)
439 return 1;
440
441 offset1 = grub_reiserfs_get_key_offset (key1);
442 offset2 = grub_reiserfs_get_key_offset (key2);
443 if (offset1 < offset2)
444 return -1;
445 if (offset1 > offset2)
446 return 1;
447
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)))
456 return 0;
457 if (type1 < type2)
458 return -1;
459 if (type1 > type2)
460 return 1;
461
462 return 0;
463 }
464
465 /* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
466 accordingly to what was found. */
467 static grub_err_t
468 grub_reiserfs_get_item (struct grub_reiserfs_data *data,
469 const struct grub_reiserfs_key *key,
470 struct grub_fshelp_node *item)
471 {
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;
476 grub_uint16_t i;
477 grub_uint16_t previous_level = ~0;
478 struct grub_reiserfs_item_header *item_headers = 0;
479
480 if (! data)
481 {
482 grub_error (GRUB_ERR_TEST_FAILURE, "data is NULL");
483 goto fail;
484 }
485
486 if (! key)
487 {
488 grub_error (GRUB_ERR_TEST_FAILURE, "key is NULL");
489 goto fail;
490 }
491
492 if (! item)
493 {
494 grub_error (GRUB_ERR_TEST_FAILURE, "item is NULL");
495 goto fail;
496 }
497
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);
503 #endif
504 block_header = grub_malloc (block_size);
505 if (! block_header)
506 goto fail;
507
508 item->next_offset = 0;
509 do
510 {
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);
517 if (grub_errno)
518 goto fail;
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)
522 {
523 grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
524 grub_error (GRUB_ERR_FILE_READ_ERROR, "level loop");
525 goto fail;
526 }
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",
530 item_count);
531 if (current_level > 1)
532 {
533 /* Internal node. Navigate to the child that should contain
534 the searched key. */
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));
540
541 for (i = 0;
542 i < item_count
543 && grub_reiserfs_compare_keys (key, &(keys[i])) >= 0;
544 i++)
545 {
546 #ifdef GRUB_REISERFS_DEBUG
547 grub_printf("i %03d/%03d ", i + 1, item_count + 1);
548 grub_reiserfs_print_key (&(keys[i]));
549 #endif
550 }
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
556 if (i == item_count
557 || grub_reiserfs_compare_keys (key, &(keys[i])) == 0)
558 grub_printf(">");
559 else
560 grub_printf("<");
561 if (i < item_count)
562 {
563 grub_printf (" %03d/%03d ", i + 1, item_count + 1);
564 grub_reiserfs_print_key (&(keys[i]));
565 if (i + 1 < item_count)
566 {
567 grub_printf ("+ %03d/%03d ", i + 2, item_count);
568 grub_reiserfs_print_key (&(keys[i + 1]));
569 }
570 }
571 else
572 grub_printf ("Accessing rightmost child at block %d.\n",
573 block_number);
574 #endif
575 }
576 else
577 {
578 /* Leaf node. Check that the key is actually present. */
579 item_headers
580 = (struct grub_reiserfs_item_header *) (block_header + 1);
581 for (i = 0;
582 i < item_count
583 && (grub_reiserfs_compare_keys (key, &(item_headers[i].key))
584 != 0);
585 i++)
586 {
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)
590 grub_printf("C");
591 else
592 grub_printf(" ");
593 grub_printf(" %03d/%03d ", i + 1, item_count);
594 grub_reiserfs_print_key (&(item_headers[i].key));
595 #endif
596 }
597 if (i < item_count)
598 block_key = &(item_headers[i].key);
599 }
600 }
601 while (current_level > 1);
602
603 item->data = data;
604
605 if (i == item_count || grub_reiserfs_compare_keys (key, block_key))
606 {
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");
612 #endif
613 }
614 else
615 {
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);
624 #endif
625 }
626
627 assert (grub_errno == GRUB_ERR_NONE);
628 grub_free (block_header);
629 return GRUB_ERR_NONE;
630
631 fail:
632 assert (grub_errno != GRUB_ERR_NONE);
633 grub_free (block_header);
634 assert (grub_errno != GRUB_ERR_NONE);
635 return grub_errno;
636 }
637
638 /* Return the path of the file which is pointed at by symlink NODE. */
639 static char *
640 grub_reiserfs_read_symlink (grub_fshelp_node_t node)
641 {
642 char *symlink_buffer = 0;
643 grub_uint16_t block_size;
644 grub_disk_addr_t block;
645 grub_off_t offset;
646 grub_size_t len;
647 struct grub_fshelp_node found;
648 struct grub_reiserfs_key key;
649
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));
654
655 if (grub_reiserfs_get_item (node->data, &key, &found) != GRUB_ERR_NONE)
656 goto fail;
657
658 if (found.block_number == 0)
659 goto fail;
660
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);
666
667 symlink_buffer = grub_malloc (len + 1);
668 if (! symlink_buffer)
669 goto fail;
670
671 grub_disk_read (node->data->disk, block, offset, len, symlink_buffer);
672 if (grub_errno)
673 goto fail;
674
675 symlink_buffer[len] = 0;
676 return symlink_buffer;
677
678 fail:
679 grub_free (symlink_buffer);
680 return 0;
681 }
682
683 static void
684 grub_reiserfs_get_journal (struct grub_reiserfs_data *data)
685 {
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;
694
695 data->journal = 0;
696
697 if (! data->superblock.journal_block)
698 return;
699
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),
704 buf))
705 return;
706
707 log = grub_malloc (sizeof (struct grub_fshelp_journal) +
708 num_blocks * sizeof (grub_disk_addr_t));
709 if (! log)
710 return;
711
712 jh = (struct grub_reiserfs_journal_header *) &buf[0];
713
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);
719
720 seq_id = grub_le_to_cpu32 (jh->last_flush_uid);
721 mount_id = grub_le_to_cpu32 (jh->mount_id);
722
723 last_num = num = 0;
724 block = log->start_block;
725
726 while (1)
727 {
728 struct grub_reiserfs_description_block *db;
729 struct grub_reiserfs_commit_block *cb;
730 grub_uint32_t i, len, half_len, id, mid;
731
732 if (grub_disk_read (data->disk,
733 (base_block + block)
734 * (block_size >> GRUB_DISK_SECTOR_BITS),
735 0, sizeof (buf), buf))
736 break;
737
738 if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN],
739 REISERFS_MAGIC_DESC_BLOCK,
740 sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1))
741 break;
742
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))
748 break;
749
750 log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
751 half_len = ((block_size - 24) >> 2);
752 if (half_len > len)
753 half_len = len;
754
755 for (i = 0; i < half_len; i++)
756 log->mapping[num++] = db->real_blocks[i];
757
758 block += grub_le_to_cpu32 (db->len) + 1;
759 if (block >= log->last_block)
760 block -= log->last_block;
761
762 if (grub_disk_read (data->disk,
763 (base_block + block)
764 * (block_size >> GRUB_DISK_SECTOR_BITS),
765 0, sizeof (buf), buf))
766 break;
767
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))
771 break;
772
773 for (i = 0; i < len - half_len; i++)
774 log->mapping[num++] = cb->real_blocks[i];
775
776 last_num = num;
777 log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
778
779 block++;
780 if (block >= log->last_block)
781 block -= log->last_block;
782
783 seq_id = id;
784 mount_id = mid;
785 };
786
787 if (! last_num)
788 grub_free (log);
789 else
790 {
791 int size;
792
793 size = sizeof (struct grub_fshelp_journal) +
794 last_num * sizeof (grub_disk_addr_t);
795
796 log->num_mappings = last_num;
797 data->journal = grub_realloc (log, size);
798 }
799 }
800
801 /* Fill the mounted filesystem structure and return it. */
802 static struct grub_reiserfs_data *
803 grub_reiserfs_mount (grub_disk_t disk)
804 {
805 struct grub_reiserfs_data *data = 0;
806 data = grub_malloc (sizeof (*data));
807 if (! data)
808 goto fail;
809 grub_disk_read (disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
810 0, sizeof (data->superblock), (char *) &(data->superblock));
811 if (grub_errno)
812 goto fail;
813 if (grub_memcmp (data->superblock.magic_string,
814 REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1))
815 {
816 grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem");
817 goto fail;
818 }
819 data->disk = disk;
820 grub_reiserfs_get_journal (data);
821 return data;
822
823 fail:
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");
827
828 grub_free (data);
829 return 0;
830 }
831
832 /* Call HOOK for each file in directory ITEM. */
833 static int
834 grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
835 int NESTED_FUNC_ATTR
836 (*hook) (const char *filename,
837 enum grub_fshelp_filetype filetype,
838 grub_fshelp_node_t node))
839 {
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;
845 int ret = 0;
846
847 if (item->type != GRUB_REISERFS_DIRECTORY)
848 {
849 grub_error (GRUB_ERR_BAD_FILE_TYPE,
850 "grub_reiserfs_iterate_dir called on a non-directory item");
851 goto fail;
852 }
853 block_size = grub_le_to_cpu16 (data->superblock.block_size);
854 block_header = grub_malloc (block_size);
855 if (! block_header)
856 goto fail;
857 block_number = item->block_number;
858 block_position = item->block_position;
859 grub_dprintf ("reiserfs", "Iterating directory...\n");
860 do
861 {
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;
866
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);
873 if (grub_errno)
874 goto fail;
875
876 #if 0
877 if (grub_le_to_cpu16 (block_header->level) != 1)
878 {
879 grub_error (GRUB_ERR_TEST_FAILURE,
880 "reiserfs: block %d is not a leaf block",
881 block_number);
882 goto fail;
883 }
884 #endif
885
886 item_headers = (struct grub_reiserfs_item_header *) (block_header + 1);
887 directory_headers
888 = ((struct grub_reiserfs_directory_header *)
889 ((char *) block_header
890 + grub_le_to_cpu16 (item_headers[block_position].item_location)));
891 entry_count
892 = grub_le_to_cpu16 (item_headers[block_position].u.entry_count);
893 for (entry_number = 0; entry_number < entry_count; entry_number++)
894 {
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);
899
900 if (entry_state & GRUB_REISERFS_VISIBLE_MASK)
901 {
902 grub_fshelp_node_t entry_item;
903 struct grub_reiserfs_key entry_key;
904 enum grub_reiserfs_item_type entry_type;
905 char *entry_name;
906
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,
913 2);
914 grub_reiserfs_set_key_offset (&entry_key, 1);
915
916 entry_item = grub_malloc (sizeof (*entry_item));
917 if (! entry_item)
918 goto fail;
919
920 if (grub_reiserfs_get_item (data, &entry_key, entry_item)
921 != GRUB_ERR_NONE)
922 {
923 grub_free (entry_item);
924 goto fail;
925 }
926
927 if (entry_item->type == GRUB_REISERFS_DIRECTORY)
928 entry_type = GRUB_FSHELP_DIR;
929 else
930 {
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
935 detection. */
936 grub_reiserfs_set_key_offset (&entry_key, 0);
937 grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_STAT,
938 2);
939 if (grub_reiserfs_get_item (data, &entry_key, entry_item)
940 != GRUB_ERR_NONE)
941 {
942 grub_free (entry_item);
943 goto fail;
944 }
945
946 if (entry_item->block_number != 0)
947 {
948 grub_uint16_t entry_version;
949 entry_version
950 = grub_le_to_cpu16 (entry_item->header.version);
951 entry_block_number = entry_item->block_number;
952 #if 0
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));
958 #endif
959 if (entry_version == 0) /* Version 1 stat item. */
960 {
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);
968 if (grub_errno)
969 goto fail;
970 #if 0
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",
985 entry_v1_stat.mode,
986 entry_v1_stat.hardlink_count,
987 entry_v1_stat.uid,
988 entry_v1_stat.gid,
989 entry_v1_stat.size,
990 entry_v1_stat.atime,
991 entry_v1_stat.mtime,
992 entry_v1_stat.ctime,
993 entry_v1_stat.rdev,
994 entry_v1_stat.first_direct_byte);
995 #endif
996 if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK)
997 == S_IFLNK)
998 entry_type = GRUB_FSHELP_SYMLINK;
999 else
1000 entry_type = GRUB_FSHELP_REG;
1001 }
1002 else
1003 {
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);
1011 if (grub_errno)
1012 goto fail;
1013 #if 0
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",
1030 entry_v2_stat.mode,
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),
1035 entry_v2_stat.uid,
1036 entry_v2_stat.gid,
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);
1042 #endif
1043 if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
1044 == S_IFLNK)
1045 entry_type = GRUB_FSHELP_SYMLINK;
1046 else
1047 entry_type = GRUB_FSHELP_REG;
1048 }
1049 }
1050 else
1051 {
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",
1056 entry_name);
1057 grub_free (entry_item);
1058 continue;
1059 }
1060 }
1061 if (hook (entry_name, entry_type, entry_item))
1062 {
1063 grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
1064 entry_name, entry_type);
1065 ret = 1;
1066 goto found;
1067 }
1068
1069 *entry_name = 0; /* Make sure next entry name (which is just
1070 before this one in disk order) stops before
1071 the current one. */
1072 }
1073 }
1074
1075 if (next_offset == 0)
1076 break;
1077
1078 grub_reiserfs_set_key_offset (&(item_headers[block_position].key),
1079 next_offset);
1080 if (grub_reiserfs_get_item (data, &(item_headers[block_position].key),
1081 &directory_item) != GRUB_ERR_NONE)
1082 goto fail;
1083 block_number = directory_item.block_number;
1084 block_position = directory_item.block_position;
1085 next_offset = directory_item.next_offset;
1086 }
1087 while (block_number);
1088
1089 found:
1090 assert (grub_errno == GRUB_ERR_NONE);
1091 grub_free (block_header);
1092 return ret;
1093 fail:
1094 assert (grub_errno != GRUB_ERR_NONE);
1095 grub_free (block_header);
1096 return 0;
1097 }
1098
1099 /****************************************************************************/
1100 /* grub api functions */
1101 /****************************************************************************/
1102
1103 /* Open a file named NAME and initialize FILE. */
1104 static grub_err_t
1105 grub_reiserfs_open (struct grub_file *file, const char *name)
1106 {
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;
1112
1113 #ifndef GRUB_UTIL
1114 grub_dl_ref (my_mod);
1115 #endif
1116 data = grub_reiserfs_mount (file->device->disk);
1117 if (! data)
1118 goto fail;
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)
1126 goto fail;
1127 if (root.block_number == 0)
1128 {
1129 grub_error (GRUB_ERR_BAD_FS, "Unable to find root item");
1130 goto fail; /* Should never happen since checked at mount. */
1131 }
1132 grub_fshelp_find_file (name, &root, &found,
1133 grub_reiserfs_iterate_dir,
1134 grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
1135 if (grub_errno)
1136 goto fail;
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)
1142 goto fail;
1143 if (info.block_number == 0)
1144 {
1145 grub_error (GRUB_ERR_BAD_FS, "Unable to find searched item");
1146 goto fail;
1147 }
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. */
1152 {
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),
1157 entry_location
1158 + (((grub_off_t) block_number * block_size)
1159 & (GRUB_DISK_SECTOR_SIZE - 1)),
1160 sizeof (entry_v1_stat), (char *) &entry_v1_stat);
1161 if (grub_errno)
1162 goto fail;
1163 file->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
1164 }
1165 else
1166 {
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),
1171 entry_location
1172 + (((grub_off_t) block_number * block_size)
1173 & (GRUB_DISK_SECTOR_SIZE - 1)),
1174 sizeof (entry_v2_stat), (char *) &entry_v2_stat);
1175 if (grub_errno)
1176 goto fail;
1177 file->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
1178 }
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);
1182 file->offset = 0;
1183 file->data = found;
1184 return GRUB_ERR_NONE;
1185
1186 fail:
1187 assert (grub_errno != GRUB_ERR_NONE);
1188 grub_free (found);
1189 grub_free (data);
1190 #ifndef GRUB_UTIL
1191 grub_dl_unref (my_mod);
1192 #endif
1193 return grub_errno;
1194 }
1195
1196 static grub_ssize_t
1197 grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
1198 {
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;
1210 grub_off_t offset;
1211
1212 if (file->offset >= file->size)
1213 return 0;
1214
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)
1227 {
1228 grub_reiserfs_set_key_offset (&key, current_key_offset);
1229
1230 if (grub_reiserfs_get_item (data, &key, &found) != GRUB_ERR_NONE)
1231 goto fail;
1232 if (found.block_number == 0)
1233 goto fail;
1234 item_size = grub_le_to_cpu16 (found.header.item_size);
1235 switch (found.type)
1236 {
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)
1242 {
1243 offset = MAX ((signed) (initial_position - current_position), 0);
1244 length = (MIN (item_size, final_position - current_position)
1245 - offset);
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,
1252 block,
1253 offset
1254 + grub_le_to_cpu16 (found.header.item_location),
1255 length, buf);
1256 found.data->disk->read_hook = 0;
1257 if (grub_errno)
1258 goto fail;
1259 buf += length;
1260 current_position += offset + length;
1261 }
1262 else
1263 current_position += item_size;
1264 break;
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)
1269 goto fail;
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);
1275 if (grub_errno)
1276 goto fail;
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;
1281 indirect_block++)
1282 {
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)
1288 {
1289 offset = MAX ((signed) (initial_position - current_position),
1290 0);
1291 length = (MIN (block_size, final_position - current_position)
1292 - offset);
1293 grub_dprintf ("reiserfs",
1294 "Reading indirect block %u from %u to %u...\n",
1295 (unsigned) block, (unsigned) offset,
1296 (unsigned) offset + length);
1297 #if 0
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);
1303 #endif
1304 grub_disk_read (found.data->disk, block, offset, length, buf);
1305 if (grub_errno)
1306 goto fail;
1307 buf += length;
1308 current_position += offset + length;
1309 }
1310 else
1311 current_position += block_size;
1312 }
1313 found.data->disk->read_hook = 0;
1314 grub_free (indirect_block_ptr);
1315 indirect_block_ptr = 0;
1316 break;
1317 default:
1318 goto fail;
1319 }
1320 current_key_offset = current_position + 1;
1321 }
1322
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;
1327 /*
1328 switch (found.type)
1329 {
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,
1335 read_length, buf);
1336 if (grub_errno)
1337 goto fail;
1338 break;
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)
1343 goto fail;
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);
1348 if (grub_errno)
1349 goto fail;
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;
1353 indirect_block++)
1354 {
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);
1360 if (grub_errno)
1361 goto fail;
1362 read_length += read;
1363 }
1364 grub_free (indirect_block_ptr);
1365 break;
1366 default:
1367 goto fail;
1368 }
1369
1370 return read_length;*/
1371
1372 fail:
1373 grub_free (indirect_block_ptr);
1374 return 0;
1375 }
1376
1377 /* Close the file FILE. */
1378 static grub_err_t
1379 grub_reiserfs_close (grub_file_t file)
1380 {
1381 struct grub_fshelp_node *node = file->data;
1382 struct grub_reiserfs_data *data = node->data;
1383
1384 grub_free (data->journal);
1385 grub_free (data);
1386 grub_free (node);
1387 #ifndef GRUB_UTIL
1388 grub_dl_unref (my_mod);
1389 #endif
1390 return GRUB_ERR_NONE;
1391 }
1392
1393 /* Call HOOK with each file under DIR. */
1394 static grub_err_t
1395 grub_reiserfs_dir (grub_device_t device, const char *path,
1396 int (*hook) (const char *filename, int dir))
1397 {
1398 struct grub_reiserfs_data *data = 0;
1399 struct grub_fshelp_node root, *found;
1400 struct grub_reiserfs_key root_key;
1401
1402 auto int NESTED_FUNC_ATTR iterate (const char *filename,
1403 enum grub_fshelp_filetype filetype,
1404 grub_fshelp_node_t node);
1405
1406 int NESTED_FUNC_ATTR iterate (const char *filename,
1407 enum grub_fshelp_filetype filetype,
1408 grub_fshelp_node_t node)
1409 {
1410 grub_free (node);
1411
1412 if (filetype == GRUB_FSHELP_DIR)
1413 return hook (filename, 1);
1414 else
1415 return hook (filename, 0);
1416 }
1417 #ifndef GRUB_UTIL
1418 grub_dl_ref (my_mod);
1419 #endif
1420 data = grub_reiserfs_mount (device->disk);
1421 if (! data)
1422 goto fail;
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)
1429 goto fail;
1430 if (root.block_number == 0)
1431 {
1432 grub_error(GRUB_ERR_BAD_FS, "Root not found");
1433 goto fail;
1434 }
1435 grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir,
1436 grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
1437 if (grub_errno)
1438 goto fail;
1439 grub_reiserfs_iterate_dir (found, iterate);
1440 grub_free (data);
1441 #ifndef GRUB_UTIL
1442 grub_dl_unref (my_mod);
1443 #endif
1444 return GRUB_ERR_NONE;
1445
1446 fail:
1447 grub_free (data);
1448 #ifndef GRUB_UTIL
1449 grub_dl_unref (my_mod);
1450 #endif
1451 return grub_errno;
1452 }
1453
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
1456 caller. */
1457 static grub_err_t
1458 grub_reiserfs_label (grub_device_t device, char **label)
1459 {
1460 *label = grub_malloc (REISERFS_MAX_LABEL_LENGTH);
1461 if (*label)
1462 {
1463 grub_disk_read (device->disk,
1464 REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
1465 REISERFS_LABEL_OFFSET, REISERFS_MAX_LABEL_LENGTH,
1466 *label);
1467 }
1468 return grub_errno;
1469 }
1470
1471 static struct grub_fs grub_reiserfs_fs =
1472 {
1473 .name = "reiserfs",
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,
1479 .next = 0
1480 };
1481
1482 GRUB_MOD_INIT(reiserfs)
1483 {
1484 grub_fs_register (&grub_reiserfs_fs);
1485 #ifndef GRUB_UTIL
1486 my_mod = mod;
1487 #endif
1488 }
1489
1490 GRUB_MOD_FINI(reiserfs)
1491 {
1492 grub_fs_unregister (&grub_reiserfs_fs);
1493 }