source: grub-pc/trunk/fuentes/grub-core/fs/reiserfs.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 41.5 KB
Line 
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
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#include <grub/i18n.h>
42
43GRUB_MOD_LICENSE ("GPLv3+");
44
45#define MIN(a, b) \
46  ({ typeof (a) _a = (a); \
47     typeof (b) _b = (b); \
48     _a < _b ? _a : _b; })
49
50#define MAX(a, b) \
51  ({ typeof (a) _a = (a); \
52     typeof (b) _b = (b); \
53     _a > _b ? _a : _b; })
54
55#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
56#define REISERFS_MAGIC_LEN 12
57#define REISERFS_MAGIC_STRING "ReIsEr"
58#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
59/* If the 3rd bit of an item state is set, then it's visible.  */
60#define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
61
62#define S_IFLNK 0xA000
63
64static grub_dl_t my_mod;
65
66#define assert(boolean) real_assert (boolean, GRUB_FILE, __LINE__)
67static inline void
68real_assert (int boolean, const char *file, const int line)
69{
70  if (! boolean)
71    grub_printf ("Assertion failed at %s:%d\n", file, line);
72}
73
74enum grub_reiserfs_item_type
75  {
76    GRUB_REISERFS_STAT,
77    GRUB_REISERFS_DIRECTORY,
78    GRUB_REISERFS_DIRECT,
79    GRUB_REISERFS_INDIRECT,
80    /* Matches both _DIRECT and _INDIRECT when searching.  */
81    GRUB_REISERFS_ANY,
82    GRUB_REISERFS_UNKNOWN
83  };
84
85struct grub_reiserfs_superblock
86{
87  grub_uint32_t block_count;
88  grub_uint32_t block_free_count;
89  grub_uint32_t root_block;
90  grub_uint32_t journal_block;
91  grub_uint32_t journal_device;
92  grub_uint32_t journal_original_size;
93  grub_uint32_t journal_max_transaction_size;
94  grub_uint32_t journal_block_count;
95  grub_uint32_t journal_max_batch;
96  grub_uint32_t journal_max_commit_age;
97  grub_uint32_t journal_max_transaction_age;
98  grub_uint16_t block_size;
99  grub_uint16_t oid_max_size;
100  grub_uint16_t oid_current_size;
101  grub_uint16_t state;
102  grub_uint8_t magic_string[REISERFS_MAGIC_LEN];
103  grub_uint32_t function_hash_code;
104  grub_uint16_t tree_height;
105  grub_uint16_t bitmap_number;
106  grub_uint16_t version;
107  grub_uint16_t reserved;
108  grub_uint32_t inode_generation;
109  grub_uint8_t unused[4];
110  grub_uint16_t uuid[8];
111  char label[16];
112} GRUB_PACKED;
113
114struct grub_reiserfs_journal_header
115{
116  grub_uint32_t last_flush_uid;
117  grub_uint32_t unflushed_offset;
118  grub_uint32_t mount_id;
119} GRUB_PACKED;
120
121struct grub_reiserfs_description_block
122{
123  grub_uint32_t id;
124  grub_uint32_t len;
125  grub_uint32_t mount_id;
126  grub_uint32_t real_blocks[0];
127} GRUB_PACKED;
128
129struct grub_reiserfs_commit_block
130{
131  grub_uint32_t id;
132  grub_uint32_t len;
133  grub_uint32_t real_blocks[0];
134} GRUB_PACKED;
135
136struct grub_reiserfs_stat_item_v1
137{
138  grub_uint16_t mode;
139  grub_uint16_t hardlink_count;
140  grub_uint16_t uid;
141  grub_uint16_t gid;
142  grub_uint32_t size;
143  grub_uint32_t atime;
144  grub_uint32_t mtime;
145  grub_uint32_t ctime;
146  grub_uint32_t rdev;
147  grub_uint32_t first_direct_byte;
148} GRUB_PACKED;
149
150struct grub_reiserfs_stat_item_v2
151{
152  grub_uint16_t mode;
153  grub_uint16_t reserved;
154  grub_uint32_t hardlink_count;
155  grub_uint64_t size;
156  grub_uint32_t uid;
157  grub_uint32_t gid;
158  grub_uint32_t atime;
159  grub_uint32_t mtime;
160  grub_uint32_t ctime;
161  grub_uint32_t blocks;
162  grub_uint32_t first_direct_byte;
163} GRUB_PACKED;
164
165struct grub_reiserfs_key
166{
167  grub_uint32_t directory_id;
168  grub_uint32_t object_id;
169  union
170  {
171    struct
172    {
173      grub_uint32_t offset;
174      grub_uint32_t type;
175    } GRUB_PACKED v1;
176    struct
177    {
178      grub_uint64_t offset_type;
179    } GRUB_PACKED v2;
180  } u;
181} GRUB_PACKED;
182
183struct grub_reiserfs_item_header
184{
185  struct grub_reiserfs_key key;
186  union
187  {
188    grub_uint16_t free_space;
189    grub_uint16_t entry_count;
190  } GRUB_PACKED u;
191  grub_uint16_t item_size;
192  grub_uint16_t item_location;
193  grub_uint16_t version;
194} GRUB_PACKED;
195
196struct grub_reiserfs_block_header
197{
198  grub_uint16_t level;
199  grub_uint16_t item_count;
200  grub_uint16_t free_space;
201  grub_uint16_t reserved;
202  struct grub_reiserfs_key block_right_delimiting_key;
203} GRUB_PACKED;
204
205struct grub_reiserfs_disk_child
206{
207  grub_uint32_t block_number;
208  grub_uint16_t size;
209  grub_uint16_t reserved;
210} GRUB_PACKED;
211
212struct grub_reiserfs_directory_header
213{
214  grub_uint32_t offset;
215  grub_uint32_t directory_id;
216  grub_uint32_t object_id;
217  grub_uint16_t location;
218  grub_uint16_t state;
219} GRUB_PACKED;
220
221struct grub_fshelp_node
222{
223  struct grub_reiserfs_data *data;
224  grub_uint32_t block_number; /* 0 if node is not found.  */
225  grub_uint16_t block_position;
226  grub_uint64_t next_offset;
227  grub_int32_t mtime;
228  grub_off_t size;
229  enum grub_reiserfs_item_type type; /* To know how to read the header.  */
230  struct grub_reiserfs_item_header header;
231};
232
233/* Returned when opening a file.  */
234struct grub_reiserfs_data
235{
236  struct grub_reiserfs_superblock superblock;
237  grub_disk_t disk;
238};
239
240static grub_ssize_t
241grub_reiserfs_read_real (struct grub_fshelp_node *node,
242                         grub_off_t off, char *buf, grub_size_t len,
243                         grub_disk_read_hook_t read_hook,
244                         void *read_hook_data);
245
246/* Internal-only functions. Not to be used outside of this file.  */
247
248/* Return the type of given v2 key.  */
249static enum grub_reiserfs_item_type
250grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key *key)
251{
252  switch (grub_le_to_cpu64 (key->u.v2.offset_type) >> 60)
253    {
254    case 0:
255      return GRUB_REISERFS_STAT;
256    case 15:
257      return GRUB_REISERFS_ANY;
258    case 3:
259      return GRUB_REISERFS_DIRECTORY;
260    case 2:
261      return GRUB_REISERFS_DIRECT;
262    case 1:
263      return GRUB_REISERFS_INDIRECT;
264    }
265  return GRUB_REISERFS_UNKNOWN;
266}
267
268/* Return the type of given v1 key.  */
269static enum grub_reiserfs_item_type
270grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key *key)
271{
272  switch (grub_le_to_cpu32 (key->u.v1.type))
273    {
274    case 0:
275      return GRUB_REISERFS_STAT;
276    case 555:
277      return GRUB_REISERFS_ANY;
278    case 500:
279      return GRUB_REISERFS_DIRECTORY;
280    case 0x20000000:
281    case 0xFFFFFFFF:
282      return GRUB_REISERFS_DIRECT;
283    case 0x10000000:
284    case 0xFFFFFFFE:
285      return GRUB_REISERFS_INDIRECT;
286    }
287  return GRUB_REISERFS_UNKNOWN;
288}
289
290/* Return 1 if the given key is version 1 key, 2 otherwise.  */
291static int
292grub_reiserfs_get_key_version (const struct grub_reiserfs_key *key)
293{
294  return grub_reiserfs_get_key_v1_type (key) == GRUB_REISERFS_UNKNOWN ? 2 : 1;
295}
296
297#ifdef GRUB_HEXDUMP
298static void
299grub_hexdump (char *buffer, grub_size_t len)
300{
301  grub_size_t a;
302  for (a = 0; a < len; a++)
303    {
304      if (! (a & 0x0F))
305        grub_printf ("\n%08x  ", a);
306      grub_printf ("%02x ",
307                   ((unsigned int) ((unsigned char *) buffer)[a]) & 0xFF);
308    }
309  grub_printf ("\n");
310}
311#endif
312
313#ifdef GRUB_REISERFS_DEBUG
314static grub_uint64_t
315grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key);
316
317static enum grub_reiserfs_item_type
318grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key);
319
320static void
321grub_reiserfs_print_key (const struct grub_reiserfs_key *key)
322{
323  unsigned int a;
324  char *reiserfs_type_strings[] = {
325    "stat     ",
326    "directory",
327    "direct   ",
328    "indirect ",
329    "any      ",
330    "unknown  "
331  };
332
333  for (a = 0; a < sizeof (struct grub_reiserfs_key); a++)
334    grub_printf ("%02x ", ((unsigned int) ((unsigned char *) key)[a]) & 0xFF);
335  grub_printf ("parent id = 0x%08x, self id = 0x%08x, type = %s, offset = ",
336               grub_le_to_cpu32 (key->directory_id),
337               grub_le_to_cpu32 (key->object_id),
338               reiserfs_type_strings [grub_reiserfs_get_key_type (key)]);
339  if (grub_reiserfs_get_key_version (key) == 1)
340    grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset (key));
341  else
342    grub_printf("0x%07x%08x",
343                (unsigned) (grub_reiserfs_get_key_offset (key) >> 32),
344                (unsigned) (grub_reiserfs_get_key_offset (key) & 0xFFFFFFFF));
345  grub_printf ("\n");
346}
347#endif
348
349/* Return the offset of given key.  */
350static grub_uint64_t
351grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key)
352{
353  if (grub_reiserfs_get_key_version (key) == 1)
354    return grub_le_to_cpu32 (key->u.v1.offset);
355  else
356    return grub_le_to_cpu64 (key->u.v2.offset_type) & (~0ULL >> 4);
357}
358
359/* Set the offset of given key.  */
360static void
361grub_reiserfs_set_key_offset (struct grub_reiserfs_key *key,
362                              grub_uint64_t value)
363{
364  if (grub_reiserfs_get_key_version (key) == 1)
365    key->u.v1.offset = grub_cpu_to_le32 (value);
366  else
367    key->u.v2.offset_type \
368      = ((key->u.v2.offset_type & grub_cpu_to_le64 (15ULL << 60))
369         | grub_cpu_to_le64 (value & (~0ULL >> 4)));
370}
371
372/* Return the type of given key.  */
373static enum grub_reiserfs_item_type
374grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key)
375{
376  if (grub_reiserfs_get_key_version (key) == 1)
377    return grub_reiserfs_get_key_v1_type (key);
378  else
379    return grub_reiserfs_get_key_v2_type (key);
380}
381
382/* Set the type of given key, with given version number.  */
383static void
384grub_reiserfs_set_key_type (struct grub_reiserfs_key *key,
385                            enum grub_reiserfs_item_type grub_type,
386                            int version)
387{
388  grub_uint32_t type;
389
390  switch (grub_type)
391    {
392    case GRUB_REISERFS_STAT:
393      type = 0;
394      break;
395    case GRUB_REISERFS_ANY:
396      type = (version == 1) ? 555 : 15;
397      break;
398    case GRUB_REISERFS_DIRECTORY:
399      type = (version == 1) ? 500 : 3;
400      break;
401    case GRUB_REISERFS_DIRECT:
402      type = (version == 1) ? 0xFFFFFFFF : 2;
403      break;
404    case GRUB_REISERFS_INDIRECT:
405      type = (version == 1) ? 0xFFFFFFFE : 1;
406      break;
407    default:
408      return;
409    }
410
411  if (version == 1)
412    key->u.v1.type = grub_cpu_to_le32 (type);
413  else
414    key->u.v2.offset_type
415      = ((key->u.v2.offset_type & grub_cpu_to_le64 (~0ULL >> 4))
416         | grub_cpu_to_le64 ((grub_uint64_t) type << 60));
417
418  assert (grub_reiserfs_get_key_type (key) == grub_type);
419}
420
421/* -1 if key 1 if lower than key 2.
422   0 if key 1 is equal to key 2.
423   1 if key 1 is higher than key 2.  */
424static int
425grub_reiserfs_compare_keys (const struct grub_reiserfs_key *key1,
426                            const struct grub_reiserfs_key *key2)
427{
428  grub_uint64_t offset1, offset2;
429  enum grub_reiserfs_item_type type1, type2;
430  grub_uint32_t id1, id2;
431
432  if (! key1 || ! key2)
433    return -2;
434
435  id1 = grub_le_to_cpu32 (key1->directory_id);
436  id2 = grub_le_to_cpu32 (key2->directory_id);
437  if (id1 < id2)
438    return -1;
439  if (id1 > id2)
440    return 1;
441
442  id1 = grub_le_to_cpu32 (key1->object_id);
443  id2 = grub_le_to_cpu32 (key2->object_id);
444  if (id1 < id2)
445    return -1;
446  if (id1 > id2)
447    return 1;
448
449  offset1 = grub_reiserfs_get_key_offset (key1);
450  offset2 = grub_reiserfs_get_key_offset (key2);
451  if (offset1 < offset2)
452    return -1;
453  if (offset1 > offset2)
454    return 1;
455
456  type1 = grub_reiserfs_get_key_type (key1);
457  type2 = grub_reiserfs_get_key_type (key2);
458  if ((type1 == GRUB_REISERFS_ANY
459       && (type2 == GRUB_REISERFS_DIRECT
460           || type2 == GRUB_REISERFS_INDIRECT))
461      || (type2 == GRUB_REISERFS_ANY
462          && (type1 == GRUB_REISERFS_DIRECT
463              || type1 == GRUB_REISERFS_INDIRECT)))
464    return 0;
465  if (type1 < type2)
466    return -1;
467  if (type1 > type2)
468    return 1;
469
470  return 0;
471}
472
473/* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
474   accordingly to what was found.  */
475static grub_err_t
476grub_reiserfs_get_item (struct grub_reiserfs_data *data,
477                        const struct grub_reiserfs_key *key,
478                        struct grub_fshelp_node *item, int exact)
479{
480  grub_uint32_t block_number;
481  struct grub_reiserfs_block_header *block_header = 0;
482  struct grub_reiserfs_key *block_key = 0;
483  grub_uint16_t block_size, item_count, current_level;
484  grub_uint16_t i;
485  grub_uint16_t previous_level = ~0;
486  struct grub_reiserfs_item_header *item_headers = 0;
487
488#if 0
489  if (! data)
490    {
491      grub_error (GRUB_ERR_BAD_FS, "data is NULL");
492      goto fail;
493    }
494
495  if (! key)
496    {
497      grub_error (GRUB_ERR_BAD_FS, "key is NULL");
498      goto fail;
499    }
500
501  if (! item)
502    {
503      grub_error (GRUB_ERR_BAD_FS, "item is NULL");
504      goto fail;
505    }
506#endif
507
508  block_size = grub_le_to_cpu16 (data->superblock.block_size);
509  block_number = grub_le_to_cpu32 (data->superblock.root_block);
510#ifdef GRUB_REISERFS_DEBUG
511  grub_printf("Searching for ");
512  grub_reiserfs_print_key (key);
513#endif
514  block_header = grub_malloc (block_size);
515  if (! block_header)
516    goto fail;
517
518  item->next_offset = 0;
519  do
520    {
521      grub_disk_read (data->disk,
522                      block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
523                      (((grub_off_t) block_number * block_size)
524                       & (GRUB_DISK_SECTOR_SIZE - 1)),
525                      block_size, block_header);
526      if (grub_errno)
527        goto fail;
528      current_level = grub_le_to_cpu16 (block_header->level);
529      grub_dprintf ("reiserfs_tree", " at level %d\n", current_level);
530      if (current_level >= previous_level)
531        {
532          grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
533          grub_error (GRUB_ERR_BAD_FS, "level loop");
534          goto fail;
535        }
536      previous_level = current_level;
537      item_count = grub_le_to_cpu16 (block_header->item_count);
538      grub_dprintf ("reiserfs_tree", " number of contained items : %d\n",
539                    item_count);
540      if (current_level > 1)
541        {
542          /* Internal node. Navigate to the child that should contain
543             the searched key.  */
544          struct grub_reiserfs_key *keys
545            = (struct grub_reiserfs_key *) (block_header + 1);
546          struct grub_reiserfs_disk_child *children
547            = ((struct grub_reiserfs_disk_child *)
548               (keys + item_count));
549
550          for (i = 0;
551               i < item_count
552                 && grub_reiserfs_compare_keys (key, &(keys[i])) >= 0;
553               i++)
554            {
555#ifdef GRUB_REISERFS_DEBUG
556              grub_printf("i %03d/%03d ", i + 1, item_count + 1);
557              grub_reiserfs_print_key (&(keys[i]));
558#endif
559            }
560          block_number = grub_le_to_cpu32 (children[i].block_number);
561          if ((i < item_count) && (key->directory_id == keys[i].directory_id)
562               && (key->object_id == keys[i].object_id))
563            item->next_offset = grub_reiserfs_get_key_offset(&(keys[i]));
564#ifdef GRUB_REISERFS_DEBUG
565          if (i == item_count
566              || grub_reiserfs_compare_keys (key, &(keys[i])) == 0)
567            grub_printf(">");
568          else
569            grub_printf("<");
570          if (i < item_count)
571            {
572              grub_printf (" %03d/%03d ", i + 1, item_count + 1);
573              grub_reiserfs_print_key (&(keys[i]));
574              if (i + 1 < item_count)
575                {
576                  grub_printf ("+ %03d/%03d ", i + 2, item_count);
577                  grub_reiserfs_print_key (&(keys[i + 1]));
578                }
579            }
580          else
581            grub_printf ("Accessing rightmost child at block %d.\n",
582                         block_number);
583#endif
584        }
585      else
586        {
587          /* Leaf node.  Check that the key is actually present.  */
588          item_headers
589            = (struct grub_reiserfs_item_header *) (block_header + 1);
590          for (i = 0;
591               i < item_count;
592               i++)
593            {
594              int val;
595              val = grub_reiserfs_compare_keys (key, &(item_headers[i].key));
596              if (val == 0)
597                {
598                  block_key = &(item_headers[i].key);
599                  break;
600                }
601              if (val < 0 && exact)
602                break;
603              if (val < 0)
604                {
605                  if (i == 0)
606                    {
607                      grub_error (GRUB_ERR_READ_ERROR, "unexpected btree node");
608                      goto fail;
609                    }
610                  i--;
611                  block_key = &(item_headers[i].key);
612                  break;
613                }
614            }
615          if (!exact && i == item_count)
616            {
617              if (i == 0)
618                {
619                  grub_error (GRUB_ERR_READ_ERROR, "unexpected btree node");
620                  goto fail;
621                }
622              i--;
623              block_key = &(item_headers[i].key);
624            }
625        }
626    }
627  while (current_level > 1);
628
629  item->data = data;
630
631  if (!block_key)
632    {
633      item->block_number = 0;
634      item->block_position = 0;
635      item->type = GRUB_REISERFS_UNKNOWN;
636#ifdef GRUB_REISERFS_DEBUG
637      grub_printf("Not found.\n");
638#endif
639    }
640  else
641    {
642      item->block_number = block_number;
643      item->block_position = i;
644      item->type = grub_reiserfs_get_key_type (block_key);
645      grub_memcpy (&(item->header), &(item_headers[i]),
646                   sizeof (struct grub_reiserfs_item_header));
647#ifdef GRUB_REISERFS_DEBUG
648      grub_printf ("F %03d/%03d ", i + 1, item_count);
649      grub_reiserfs_print_key (block_key);
650#endif
651    }
652
653  assert (grub_errno == GRUB_ERR_NONE);
654  grub_free (block_header);
655  return GRUB_ERR_NONE;
656
657 fail:
658  assert (grub_errno != GRUB_ERR_NONE);
659  grub_free (block_header);
660  assert (grub_errno != GRUB_ERR_NONE);
661  return grub_errno;
662}
663
664/* Return the path of the file which is pointed at by symlink NODE.  */
665static char *
666grub_reiserfs_read_symlink (grub_fshelp_node_t node)
667{
668  char *symlink_buffer = 0;
669  grub_size_t len = node->size;
670  grub_ssize_t ret;
671
672  symlink_buffer = grub_malloc (len + 1);
673  if (! symlink_buffer)
674    return 0;
675
676  ret = grub_reiserfs_read_real (node, 0, symlink_buffer, len, 0, 0);
677  if (ret < 0)
678    {
679      grub_free (symlink_buffer);
680      return 0;
681    }
682
683  symlink_buffer[ret] = 0;
684  return symlink_buffer;
685}
686
687/* Fill the mounted filesystem structure and return it.  */
688static struct grub_reiserfs_data *
689grub_reiserfs_mount (grub_disk_t disk)
690{
691  struct grub_reiserfs_data *data = 0;
692  data = grub_malloc (sizeof (*data));
693  if (! data)
694    goto fail;
695  grub_disk_read (disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
696                  0, sizeof (data->superblock), &(data->superblock));
697  if (grub_errno)
698    goto fail;
699  if (grub_memcmp (data->superblock.magic_string,
700                   REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1))
701    {
702      grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem");
703      goto fail;
704    }
705  data->disk = disk;
706  return data;
707
708 fail:
709  /* Disk is too small to contain a ReiserFS.  */
710  if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
711    grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem");
712
713  grub_free (data);
714  return 0;
715}
716
717/* Call HOOK for each file in directory ITEM.  */
718static int
719grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
720                           grub_fshelp_iterate_dir_hook_t hook,
721                           void *hook_data)
722{
723  struct grub_reiserfs_data *data = item->data;
724  struct grub_reiserfs_block_header *block_header = 0;
725  grub_uint16_t block_size, block_position;
726  grub_uint32_t block_number;
727  grub_uint64_t next_offset = item->next_offset;
728  int ret = 0;
729
730  if (item->type != GRUB_REISERFS_DIRECTORY)
731    {
732      grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
733      goto fail;
734    }
735  block_size = grub_le_to_cpu16 (data->superblock.block_size);
736  block_header = grub_malloc (block_size + 1);
737  if (! block_header)
738    goto fail;
739  block_number = item->block_number;
740  block_position = item->block_position;
741  grub_dprintf ("reiserfs", "Iterating directory...\n");
742  do
743    {
744      struct grub_reiserfs_directory_header *directory_headers;
745      struct grub_fshelp_node directory_item;
746      grub_uint16_t entry_count, entry_number;
747      struct grub_reiserfs_item_header *item_headers;
748
749      grub_disk_read (data->disk,
750                      block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
751                      (((grub_off_t) block_number * block_size)
752                       & (GRUB_DISK_SECTOR_SIZE - 1)),
753                      block_size, (char *) block_header);
754      if (grub_errno)
755        goto fail;
756
757      ((char *) block_header)[block_size] = 0;
758
759#if 0
760      if (grub_le_to_cpu16 (block_header->level) != 1)
761        {
762          grub_error (GRUB_ERR_BAD_FS,
763                      "reiserfs: block %d is not a leaf block",
764                      block_number);
765          goto fail;
766        }
767#endif
768
769      item_headers = (struct grub_reiserfs_item_header *) (block_header + 1);
770      directory_headers
771        = ((struct grub_reiserfs_directory_header *)
772           ((char *) block_header
773            + grub_le_to_cpu16 (item_headers[block_position].item_location)));
774      entry_count
775        = grub_le_to_cpu16 (item_headers[block_position].u.entry_count);
776      for (entry_number = 0; entry_number < entry_count; entry_number++)
777        {
778          struct grub_reiserfs_directory_header *directory_header
779            = &directory_headers[entry_number];
780          grub_uint16_t entry_state
781            = grub_le_to_cpu16 (directory_header->state);
782          grub_fshelp_node_t entry_item;
783          struct grub_reiserfs_key entry_key;
784          enum grub_fshelp_filetype entry_type;
785          char *entry_name;
786         
787          if (!(entry_state & GRUB_REISERFS_VISIBLE_MASK))
788            continue;
789
790          entry_name = (((char *) directory_headers)
791                        + grub_le_to_cpu16 (directory_header->location));
792          entry_key.directory_id = directory_header->directory_id;
793          entry_key.object_id = directory_header->object_id;
794          entry_key.u.v2.offset_type = 0;
795          grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_DIRECTORY,
796                                      2);
797          grub_reiserfs_set_key_offset (&entry_key, 1);
798
799          entry_item = grub_malloc (sizeof (*entry_item));
800          if (! entry_item)
801            goto fail;
802
803          if (grub_reiserfs_get_item (data, &entry_key, entry_item, 1)
804              != GRUB_ERR_NONE)
805            {
806              grub_free (entry_item);
807              goto fail;
808            }
809
810          if (entry_item->type == GRUB_REISERFS_DIRECTORY)
811            entry_type = GRUB_FSHELP_DIR;
812          else
813            {
814              grub_uint32_t entry_block_number;
815              /* Order is very important here.
816                 First set the offset to 0 using current key version.
817                 Then change the key type, which affects key version
818                 detection.  */
819              grub_reiserfs_set_key_offset (&entry_key, 0);
820              grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_STAT,
821                                          2);
822              if (grub_reiserfs_get_item (data, &entry_key, entry_item, 1)
823                  != GRUB_ERR_NONE)
824                {
825                  grub_free (entry_item);
826                  goto fail;
827                }
828
829              if (entry_item->block_number != 0)
830                {
831                  grub_uint16_t entry_version;
832                  entry_version
833                    = grub_le_to_cpu16 (entry_item->header.version);
834                  entry_block_number = entry_item->block_number;
835#if 0
836                  grub_dprintf ("reiserfs",
837                                "version %04x block %08x (%08x) position %08x\n",
838                                entry_version, entry_block_number,
839                                ((grub_disk_addr_t) entry_block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
840                                grub_le_to_cpu16 (entry_item->header.item_location));
841#endif
842                  if (entry_version == 0) /* Version 1 stat item. */
843                    {
844                      struct grub_reiserfs_stat_item_v1 entry_v1_stat;
845                      grub_disk_read (data->disk,
846                                      entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
847                                      grub_le_to_cpu16 (entry_item->header.item_location),
848                                      sizeof (entry_v1_stat),
849                                      (char *) &entry_v1_stat);
850                      if (grub_errno)
851                        goto fail;
852#if 0
853                      grub_dprintf ("reiserfs",
854                                    "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
855                                    grub_le_to_cpu16 (entry_v1_stat.mode),
856                                    grub_le_to_cpu16 (entry_v1_stat.hardlink_count),
857                                    grub_le_to_cpu16 (entry_v1_stat.uid),
858                                    grub_le_to_cpu16 (entry_v1_stat.gid),
859                                    grub_le_to_cpu32 (entry_v1_stat.size),
860                                    grub_le_to_cpu32 (entry_v1_stat.atime),
861                                    grub_le_to_cpu32 (entry_v1_stat.mtime),
862                                    grub_le_to_cpu32 (entry_v1_stat.ctime),
863                                    grub_le_to_cpu32 (entry_v1_stat.rdev),
864                                    grub_le_to_cpu32 (entry_v1_stat.first_direct_byte));
865                      grub_dprintf ("reiserfs",
866                                    "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
867                                    entry_v1_stat.mode,
868                                    entry_v1_stat.hardlink_count,
869                                    entry_v1_stat.uid,
870                                    entry_v1_stat.gid,
871                                    entry_v1_stat.size,
872                                    entry_v1_stat.atime,
873                                    entry_v1_stat.mtime,
874                                    entry_v1_stat.ctime,
875                                    entry_v1_stat.rdev,
876                                    entry_v1_stat.first_direct_byte);
877#endif
878                      entry_item->mtime = grub_le_to_cpu32 (entry_v1_stat.mtime);
879                      if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK)
880                          == S_IFLNK)
881                        entry_type = GRUB_FSHELP_SYMLINK;
882                      else
883                        entry_type = GRUB_FSHELP_REG;
884                      entry_item->size = (grub_off_t) grub_le_to_cpu32 (entry_v1_stat.size);
885                    }
886                  else
887                    {
888                      struct grub_reiserfs_stat_item_v2 entry_v2_stat;
889                      grub_disk_read (data->disk,
890                                      entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
891                                      grub_le_to_cpu16 (entry_item->header.item_location),
892                                      sizeof (entry_v2_stat),
893                                      (char *) &entry_v2_stat);
894                      if (grub_errno)
895                        goto fail;
896#if 0
897                      grub_dprintf ("reiserfs",
898                                    "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
899                                    grub_le_to_cpu16 (entry_v2_stat.mode),
900                                    grub_le_to_cpu16 (entry_v2_stat.reserved),
901                                    grub_le_to_cpu32 (entry_v2_stat.hardlink_count),
902                                    (unsigned int) (grub_le_to_cpu64 (entry_v2_stat.size) >> 32),
903                                    (unsigned int) (grub_le_to_cpu64 (entry_v2_stat.size) && 0xFFFFFFFF),
904                                    grub_le_to_cpu32 (entry_v2_stat.uid),
905                                    grub_le_to_cpu32 (entry_v2_stat.gid),
906                                    grub_le_to_cpu32 (entry_v2_stat.atime),
907                                    grub_le_to_cpu32 (entry_v2_stat.mtime),
908                                    grub_le_to_cpu32 (entry_v2_stat.ctime),
909                                    grub_le_to_cpu32 (entry_v2_stat.blocks),
910                                    grub_le_to_cpu32 (entry_v2_stat.first_direct_byte));
911                      grub_dprintf ("reiserfs",
912                                    "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
913                                    entry_v2_stat.mode,
914                                    entry_v2_stat.reserved,
915                                    entry_v2_stat.hardlink_count,
916                                    (unsigned int) (entry_v2_stat.size >> 32),
917                                    (unsigned int) (entry_v2_stat.size && 0xFFFFFFFF),
918                                    entry_v2_stat.uid,
919                                    entry_v2_stat.gid,
920                                    entry_v2_stat.atime,
921                                    entry_v2_stat.mtime,
922                                    entry_v2_stat.ctime,
923                                    entry_v2_stat.blocks,
924                                    entry_v2_stat.first_direct_byte);
925#endif
926                      entry_item->mtime = grub_le_to_cpu32 (entry_v2_stat.mtime);
927                      entry_item->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
928                      if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
929                          == S_IFLNK)
930                        entry_type = GRUB_FSHELP_SYMLINK;
931                      else
932                        entry_type = GRUB_FSHELP_REG;
933                    }
934                }
935              else
936                {
937                  /* Pseudo file ".." never has stat block.  */
938                  if (grub_strcmp (entry_name, ".."))
939                    grub_dprintf ("reiserfs",
940                                  "Warning : %s has no stat block !\n",
941                                  entry_name);
942                  grub_free (entry_item);
943                  goto next;
944                }
945            }
946          if (hook (entry_name, entry_type, entry_item, hook_data))
947            {
948              grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
949                            entry_name, entry_type);
950              ret = 1;
951              goto found;
952            }
953
954        next:
955          *entry_name = 0; /* Make sure next entry name (which is just
956                              before this one in disk order) stops before
957                              the current one.  */
958        }
959
960      if (next_offset == 0)
961        break;
962
963      grub_reiserfs_set_key_offset (&(item_headers[block_position].key),
964                                    next_offset);
965      if (grub_reiserfs_get_item (data, &(item_headers[block_position].key),
966                                  &directory_item, 1) != GRUB_ERR_NONE)
967        goto fail;
968      block_number = directory_item.block_number;
969      block_position = directory_item.block_position;
970      next_offset = directory_item.next_offset;
971    }
972  while (block_number);
973
974 found:
975  assert (grub_errno == GRUB_ERR_NONE);
976  grub_free (block_header);
977  return ret;
978 fail:
979  assert (grub_errno != GRUB_ERR_NONE);
980  grub_free (block_header);
981  return 0;
982}
983
984/****************************************************************************/
985/* grub api functions */
986/****************************************************************************/
987
988/* Open a file named NAME and initialize FILE.  */
989static grub_err_t
990grub_reiserfs_open (struct grub_file *file, const char *name)
991{
992  struct grub_reiserfs_data *data = 0;
993  struct grub_fshelp_node root, *found = 0;
994  struct grub_reiserfs_key key;
995
996  grub_dl_ref (my_mod);
997  data = grub_reiserfs_mount (file->device->disk);
998  if (! data)
999    goto fail;
1000  key.directory_id = grub_cpu_to_le32 (1);
1001  key.object_id = grub_cpu_to_le32 (2);
1002  key.u.v2.offset_type = 0;
1003  grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECTORY, 2);
1004  grub_reiserfs_set_key_offset (&key, 1);
1005  if (grub_reiserfs_get_item (data, &key, &root, 1) != GRUB_ERR_NONE)
1006    goto fail;
1007  if (root.block_number == 0)
1008    {
1009      grub_error (GRUB_ERR_BAD_FS, "unable to find root item");
1010      goto fail; /* Should never happen since checked at mount.  */
1011    }
1012  grub_fshelp_find_file (name, &root, &found,
1013                         grub_reiserfs_iterate_dir,
1014                         grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
1015  if (grub_errno)
1016    goto fail;
1017  file->size = found->size;
1018
1019  grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
1020                (unsigned int) file->size,
1021                (unsigned int) (file->size >> 32), (unsigned int) file->size);
1022  file->offset = 0;
1023  file->data = found;
1024  return GRUB_ERR_NONE;
1025
1026 fail:
1027  assert (grub_errno != GRUB_ERR_NONE);
1028  if (found != &root)
1029    grub_free (found);
1030  grub_free (data);
1031  grub_dl_unref (my_mod);
1032  return grub_errno;
1033}
1034
1035static grub_ssize_t
1036grub_reiserfs_read_real (struct grub_fshelp_node *node,
1037                         grub_off_t off, char *buf, grub_size_t len,
1038                         grub_disk_read_hook_t read_hook, void *read_hook_data)
1039{
1040  unsigned int indirect_block, indirect_block_count;
1041  struct grub_reiserfs_key key;
1042  struct grub_reiserfs_data *data = node->data;
1043  struct grub_fshelp_node found;
1044  grub_uint16_t block_size = grub_le_to_cpu16 (data->superblock.block_size);
1045  grub_uint16_t item_size;
1046  grub_uint32_t *indirect_block_ptr = 0;
1047  grub_uint64_t current_key_offset = 1;
1048  grub_off_t initial_position, current_position, final_position, length;
1049  grub_disk_addr_t block;
1050  grub_off_t offset;
1051
1052  key.directory_id = node->header.key.directory_id;
1053  key.object_id = node->header.key.object_id;
1054  key.u.v2.offset_type = 0;
1055  grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
1056  initial_position = off;
1057  current_position = 0;
1058  final_position = MIN (len + initial_position, node->size);
1059  grub_dprintf ("reiserfs",
1060                "Reading from %lld to %lld (%lld instead of requested %ld)\n",
1061                (unsigned long long) initial_position,
1062                (unsigned long long) final_position,
1063                (unsigned long long) (final_position - initial_position),
1064                (unsigned long) len);
1065
1066  grub_reiserfs_set_key_offset (&key, initial_position + 1);
1067
1068  if (grub_reiserfs_get_item (data, &key, &found, 0) != GRUB_ERR_NONE)
1069    goto fail;
1070
1071  if (found.block_number == 0)
1072    {
1073      grub_error (GRUB_ERR_READ_ERROR, "offset %lld not found",
1074                  (unsigned long long) initial_position);
1075      goto fail;
1076    }
1077
1078  current_key_offset = grub_reiserfs_get_key_offset (&found.header.key);
1079  current_position = current_key_offset - 1;
1080
1081  while (current_position < final_position)
1082    {
1083      grub_reiserfs_set_key_offset (&key, current_key_offset);
1084
1085      if (grub_reiserfs_get_item (data, &key, &found, 1) != GRUB_ERR_NONE)
1086        goto fail;
1087      if (found.block_number == 0)
1088        goto fail;
1089      item_size = grub_le_to_cpu16 (found.header.item_size);
1090      switch (found.type)
1091        {
1092        case GRUB_REISERFS_DIRECT:
1093          block = found.block_number * (block_size  >> GRUB_DISK_SECTOR_BITS);
1094          grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
1095          if (initial_position < current_position + item_size)
1096            {
1097              offset = MAX ((signed) (initial_position - current_position), 0);
1098              length = (MIN (item_size, final_position - current_position)
1099                        - offset);
1100              grub_dprintf ("reiserfs",
1101                            "Reading direct block %u from %u to %u...\n",
1102                            (unsigned) block, (unsigned) offset,
1103                            (unsigned) (offset + length));
1104              found.data->disk->read_hook = read_hook;
1105              found.data->disk->read_hook_data = read_hook_data;
1106              grub_disk_read (found.data->disk,
1107                              block,
1108                              offset
1109                              + grub_le_to_cpu16 (found.header.item_location),
1110                              length, buf);
1111              found.data->disk->read_hook = 0;
1112              if (grub_errno)
1113                goto fail;
1114              buf += length;
1115              current_position += offset + length;
1116            }
1117          else
1118            current_position += item_size;
1119          break;
1120        case GRUB_REISERFS_INDIRECT:
1121          indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1122          indirect_block_ptr = grub_malloc (item_size);
1123          if (! indirect_block_ptr)
1124            goto fail;
1125          grub_disk_read (found.data->disk,
1126                          found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
1127                          grub_le_to_cpu16 (found.header.item_location),
1128                          item_size, indirect_block_ptr);
1129          if (grub_errno)
1130            goto fail;
1131          found.data->disk->read_hook = read_hook;
1132          found.data->disk->read_hook_data = read_hook_data;
1133          for (indirect_block = 0;
1134               indirect_block < indirect_block_count
1135                 && current_position < final_position;
1136               indirect_block++)
1137            {
1138              block = grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) *
1139                      (block_size >> GRUB_DISK_SECTOR_BITS);
1140              grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
1141              if (current_position + block_size >= initial_position)
1142                {
1143                  offset = MAX ((signed) (initial_position - current_position),
1144                                0);
1145                  length = (MIN (block_size, final_position - current_position)
1146                            - offset);
1147                  grub_dprintf ("reiserfs",
1148                                "Reading indirect block %u from %u to %u...\n",
1149                                (unsigned) block, (unsigned) offset,
1150                                (unsigned) (offset + length));
1151#if 0
1152                  grub_dprintf ("reiserfs",
1153                                "\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
1154                                indirect_block + 1, indirect_block_count,
1155                                initial_position, current_position,
1156                                final_position, offset, length, len);
1157#endif
1158                  grub_disk_read (found.data->disk, block, offset, length, buf);
1159                  if (grub_errno)
1160                    goto fail;
1161                  buf += length;
1162                  current_position += offset + length;
1163                }
1164              else
1165                current_position += block_size;
1166            }
1167          found.data->disk->read_hook = 0;
1168          grub_free (indirect_block_ptr);
1169          indirect_block_ptr = 0;
1170          break;
1171        default:
1172          goto fail;
1173        }
1174      current_key_offset = current_position + 1;
1175    }
1176
1177  grub_dprintf ("reiserfs",
1178                "Have successfully read %lld bytes (%ld requested)\n",
1179                (unsigned long long) (current_position - initial_position),
1180                (unsigned long) len);
1181  return current_position - initial_position;
1182
1183#if 0
1184  switch (found.type)
1185    {
1186      case GRUB_REISERFS_DIRECT:
1187        read_length = MIN (len, item_size - file->offset);
1188        grub_disk_read (found.data->disk,
1189                        (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
1190                        grub_le_to_cpu16 (found.header.item_location) + file->offset,
1191                        read_length, buf);
1192        if (grub_errno)
1193          goto fail;
1194        break;
1195      case GRUB_REISERFS_INDIRECT:
1196        indirect_block_count = item_size / sizeof (*indirect_block_ptr);
1197        indirect_block_ptr = grub_malloc (item_size);
1198        if (!indirect_block_ptr)
1199          goto fail;
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),
1203                        item_size, (char *) indirect_block_ptr);
1204        if (grub_errno)
1205          goto fail;
1206        len = MIN (len, file->size - file->offset);
1207        for (indirect_block = file->offset / block_size;
1208             indirect_block < indirect_block_count && read_length < len;
1209             indirect_block++)
1210          {
1211            read = MIN (block_size, len - read_length);
1212            grub_disk_read (found.data->disk,
1213                            (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
1214                            file->offset % block_size, read,
1215                            ((void *) buf) + read_length);
1216            if (grub_errno)
1217              goto fail;
1218            read_length += read;
1219          }
1220        grub_free (indirect_block_ptr);
1221        break;
1222      default:
1223        goto fail;
1224    }
1225
1226  return read_length;
1227#endif
1228
1229 fail:
1230  grub_free (indirect_block_ptr);
1231  return -1;
1232}
1233
1234static grub_ssize_t
1235grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
1236{
1237  return grub_reiserfs_read_real (file->data, file->offset, buf, len,
1238                                  file->read_hook, file->read_hook_data);
1239}
1240
1241/* Close the file FILE.  */
1242static grub_err_t
1243grub_reiserfs_close (grub_file_t file)
1244{
1245  struct grub_fshelp_node *node = file->data;
1246  struct grub_reiserfs_data *data = node->data;
1247
1248  grub_free (data);
1249  grub_free (node);
1250  grub_dl_unref (my_mod);
1251  return GRUB_ERR_NONE;
1252}
1253
1254/* Context for grub_reiserfs_dir.  */
1255struct grub_reiserfs_dir_ctx
1256{
1257  grub_fs_dir_hook_t hook;
1258  void *hook_data;
1259};
1260
1261/* Helper for grub_reiserfs_dir.  */
1262static int
1263grub_reiserfs_dir_iter (const char *filename,
1264                        enum grub_fshelp_filetype filetype,
1265                        grub_fshelp_node_t node, void *data)
1266{
1267  struct grub_reiserfs_dir_ctx *ctx = data;
1268  struct grub_dirhook_info info;
1269
1270  grub_memset (&info, 0, sizeof (info));
1271  info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
1272  info.mtimeset = 1;
1273  info.mtime = node->mtime;
1274  grub_free (node);
1275  return ctx->hook (filename, &info, ctx->hook_data);
1276}
1277
1278/* Call HOOK with each file under DIR.  */
1279static grub_err_t
1280grub_reiserfs_dir (grub_device_t device, const char *path,
1281                   grub_fs_dir_hook_t hook, void *hook_data)
1282{
1283  struct grub_reiserfs_dir_ctx ctx = { hook, hook_data };
1284  struct grub_reiserfs_data *data = 0;
1285  struct grub_fshelp_node root, *found;
1286  struct grub_reiserfs_key root_key;
1287
1288  grub_dl_ref (my_mod);
1289  data = grub_reiserfs_mount (device->disk);
1290  if (! data)
1291    goto fail;
1292  root_key.directory_id = grub_cpu_to_le32 (1);
1293  root_key.object_id = grub_cpu_to_le32 (2);
1294  root_key.u.v2.offset_type = 0;
1295  grub_reiserfs_set_key_type (&root_key, GRUB_REISERFS_DIRECTORY, 2);
1296  grub_reiserfs_set_key_offset (&root_key, 1);
1297  if (grub_reiserfs_get_item (data, &root_key, &root, 1) != GRUB_ERR_NONE)
1298    goto fail;
1299  if (root.block_number == 0)
1300    {
1301      grub_error(GRUB_ERR_BAD_FS, "root not found");
1302      goto fail;
1303    }
1304  grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir,
1305                         grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
1306  if (grub_errno)
1307    goto fail;
1308  grub_reiserfs_iterate_dir (found, grub_reiserfs_dir_iter, &ctx);
1309  grub_free (data);
1310  grub_dl_unref (my_mod);
1311  return GRUB_ERR_NONE;
1312
1313 fail:
1314  grub_free (data);
1315  grub_dl_unref (my_mod);
1316  return grub_errno;
1317}
1318
1319/* Return the label of the device DEVICE in LABEL.  The label is
1320   returned in a grub_malloc'ed buffer and should be freed by the
1321   caller.  */
1322static grub_err_t
1323grub_reiserfs_label (grub_device_t device, char **label)
1324{
1325  struct grub_reiserfs_data *data;
1326  grub_disk_t disk = device->disk;
1327
1328  grub_dl_ref (my_mod);
1329
1330  data = grub_reiserfs_mount (disk);
1331  if (data)
1332    {
1333      *label = grub_strndup (data->superblock.label,
1334                             sizeof (data->superblock.label));
1335    }
1336  else
1337    *label = NULL;
1338
1339  grub_dl_unref (my_mod);
1340
1341  grub_free (data);
1342
1343  return grub_errno;
1344}
1345
1346static grub_err_t
1347grub_reiserfs_uuid (grub_device_t device, char **uuid)
1348{
1349  struct grub_reiserfs_data *data;
1350  grub_disk_t disk = device->disk;
1351
1352  grub_dl_ref (my_mod);
1353
1354  *uuid = NULL;
1355  data = grub_reiserfs_mount (disk);
1356  if (data)
1357    {
1358      unsigned i;
1359      for (i = 0; i < ARRAY_SIZE (data->superblock.uuid); i++)
1360        if (data->superblock.uuid[i])
1361          break;
1362      if (i < ARRAY_SIZE (data->superblock.uuid))
1363        *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1364                                grub_be_to_cpu16 (data->superblock.uuid[0]),
1365                                grub_be_to_cpu16 (data->superblock.uuid[1]),
1366                                grub_be_to_cpu16 (data->superblock.uuid[2]),
1367                                grub_be_to_cpu16 (data->superblock.uuid[3]),
1368                                grub_be_to_cpu16 (data->superblock.uuid[4]),
1369                                grub_be_to_cpu16 (data->superblock.uuid[5]),
1370                                grub_be_to_cpu16 (data->superblock.uuid[6]),
1371                                grub_be_to_cpu16 (data->superblock.uuid[7]));
1372    }
1373
1374  grub_dl_unref (my_mod);
1375
1376  grub_free (data);
1377
1378  return grub_errno;
1379}
1380
1381static struct grub_fs grub_reiserfs_fs =
1382  {
1383    .name = "reiserfs",
1384    .dir = grub_reiserfs_dir,
1385    .open = grub_reiserfs_open,
1386    .read = grub_reiserfs_read,
1387    .close = grub_reiserfs_close,
1388    .label = grub_reiserfs_label,
1389    .uuid = grub_reiserfs_uuid,
1390#ifdef GRUB_UTIL
1391    .reserved_first_sector = 1,
1392    .blocklist_install = 1,
1393#endif
1394    .next = 0
1395  };
1396
1397GRUB_MOD_INIT(reiserfs)
1398{
1399  grub_fs_register (&grub_reiserfs_fs);
1400  my_mod = mod;
1401}
1402
1403GRUB_MOD_FINI(reiserfs)
1404{
1405  grub_fs_unregister (&grub_reiserfs_fs);
1406}
Note: See TracBrowser for help on using the repository browser.