~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to 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
 
}