~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/fs/reiserfs.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

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