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

« back to all changes in this revision

Viewing changes to grub-core/fs/nilfs2.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
/* 
 
2
 *  nilfs2.c - New Implementation of Log filesystem 
 
3
 *
 
4
 *  Written by Jiro SEKIBA <jir@unicus.jp>
 
5
 *
 
6
 *  Copyright (C) 2003,2004,2005,2007,2008,2010  Free Software Foundation, Inc.
 
7
 *
 
8
 *  GRUB is free software: you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation, either version 3 of the License, or
 
11
 *  (at your option) any later version.
 
12
 *
 
13
 *  GRUB is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
 
 
23
/* Filetype information as used in inodes.  */
 
24
#define FILETYPE_INO_MASK       0170000
 
25
#define FILETYPE_INO_REG        0100000
 
26
#define FILETYPE_INO_DIRECTORY  0040000
 
27
#define FILETYPE_INO_SYMLINK    0120000
 
28
 
 
29
#include <grub/err.h>
 
30
#include <grub/file.h>
 
31
#include <grub/mm.h>
 
32
#include <grub/misc.h>
 
33
#include <grub/disk.h>
 
34
#include <grub/dl.h>
 
35
#include <grub/types.h>
 
36
#include <grub/fshelp.h>
 
37
 
 
38
#define NILFS_INODE_BMAP_SIZE   7
 
39
 
 
40
#define NILFS_SUPORT_REV        2
 
41
 
 
42
/* Magic value used to identify an nilfs2 filesystem.  */
 
43
#define NILFS2_SUPER_MAGIC      0x3434
 
44
/* nilfs btree node flag.  */
 
45
#define NILFS_BTREE_NODE_ROOT   0x01
 
46
 
 
47
/* nilfs btree node level. */
 
48
#define NILFS_BTREE_LEVEL_DATA          0
 
49
#define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
 
50
#define NILFS_BTREE_LEVEL_MAX           14
 
51
 
 
52
/* nilfs 1st super block posission from beginning of the partition
 
53
   in 512 block size */
 
54
#define NILFS_1ST_SUPER_BLOCK   2
 
55
/* nilfs 2nd super block posission from beginning of the partition
 
56
   in 512 block size */
 
57
#define NILFS_2ND_SUPER_BLOCK(devsize)  (((devsize >> 3) - 1) << 3)
 
58
 
 
59
struct grub_nilfs2_inode
 
60
{
 
61
  grub_uint64_t i_blocks;
 
62
  grub_uint64_t i_size;
 
63
  grub_uint64_t i_ctime;
 
64
  grub_uint64_t i_mtime;
 
65
  grub_uint32_t i_ctime_nsec;
 
66
  grub_uint32_t i_mtime_nsec;
 
67
  grub_uint32_t i_uid;
 
68
  grub_uint32_t i_gid;
 
69
  grub_uint16_t i_mode;
 
70
  grub_uint16_t i_links_count;
 
71
  grub_uint32_t i_flags;
 
72
  grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
 
73
#define i_device_code   i_bmap[0]
 
74
  grub_uint64_t i_xattr;
 
75
  grub_uint32_t i_generation;
 
76
  grub_uint32_t i_pad;
 
77
};
 
78
 
 
79
struct grub_nilfs2_super_root
 
80
{
 
81
  grub_uint32_t sr_sum;
 
82
  grub_uint16_t sr_bytes;
 
83
  grub_uint16_t sr_flags;
 
84
  grub_uint64_t sr_nongc_ctime;
 
85
  struct grub_nilfs2_inode sr_dat;
 
86
  struct grub_nilfs2_inode sr_cpfile;
 
87
  struct grub_nilfs2_inode sr_sufile;
 
88
};
 
89
 
 
90
struct grub_nilfs2_super_block
 
91
{
 
92
  grub_uint32_t s_rev_level;
 
93
  grub_uint16_t s_minor_rev_level;
 
94
  grub_uint16_t s_magic;
 
95
  grub_uint16_t s_bytes;
 
96
  grub_uint16_t s_flags;
 
97
  grub_uint32_t s_crc_seed;
 
98
  grub_uint32_t s_sum;
 
99
  grub_uint32_t s_log_block_size;
 
100
  grub_uint64_t s_nsegments;
 
101
  grub_uint64_t s_dev_size;
 
102
  grub_uint64_t s_first_data_block;
 
103
  grub_uint32_t s_blocks_per_segment;
 
104
  grub_uint32_t s_r_segments_percentage;
 
105
  grub_uint64_t s_last_cno;
 
106
  grub_uint64_t s_last_pseg;
 
107
  grub_uint64_t s_last_seq;
 
108
  grub_uint64_t s_free_blocks_count;
 
109
  grub_uint64_t s_ctime;
 
110
  grub_uint64_t s_mtime;
 
111
  grub_uint64_t s_wtime;
 
112
  grub_uint16_t s_mnt_count;
 
113
  grub_uint16_t s_max_mnt_count;
 
114
  grub_uint16_t s_state;
 
115
  grub_uint16_t s_errors;
 
116
  grub_uint64_t s_lastcheck;
 
117
  grub_uint32_t s_checkinterval;
 
118
  grub_uint32_t s_creator_os;
 
119
  grub_uint16_t s_def_resuid;
 
120
  grub_uint16_t s_def_resgid;
 
121
  grub_uint32_t s_first_ino;
 
122
  grub_uint16_t s_inode_size;
 
123
  grub_uint16_t s_dat_entry_size;
 
124
  grub_uint16_t s_checkpoint_size;
 
125
  grub_uint16_t s_segment_usage_size;
 
126
  grub_uint8_t s_uuid[16];
 
127
  char s_volume_name[16];
 
128
  char s_last_mounted[64];
 
129
  grub_uint32_t s_c_interval;
 
130
  grub_uint32_t s_c_block_max;
 
131
  grub_uint32_t s_reserved[192];
 
132
};
 
133
 
 
134
struct grub_nilfs2_dir_entry
 
135
{
 
136
  grub_uint64_t inode;
 
137
  grub_uint16_t rec_len;
 
138
  grub_uint8_t name_len;
 
139
  grub_uint8_t file_type;
 
140
#if 0                           /* followed by file name. */
 
141
  char name[NILFS_NAME_LEN];
 
142
  char pad;
 
143
#endif
 
144
} __attribute__ ((packed));
 
145
 
 
146
enum
 
147
{
 
148
  NILFS_FT_UNKNOWN,
 
149
  NILFS_FT_REG_FILE,
 
150
  NILFS_FT_DIR,
 
151
  NILFS_FT_CHRDEV,
 
152
  NILFS_FT_BLKDEV,
 
153
  NILFS_FT_FIFO,
 
154
  NILFS_FT_SOCK,
 
155
  NILFS_FT_SYMLINK,
 
156
  NILFS_FT_MAX
 
157
};
 
158
 
 
159
struct grub_nilfs2_finfo
 
160
{
 
161
  grub_uint64_t fi_ino;
 
162
  grub_uint64_t fi_cno;
 
163
  grub_uint32_t fi_nblocks;
 
164
  grub_uint32_t fi_ndatablk;
 
165
};
 
166
 
 
167
struct grub_nilfs2_binfo_v
 
168
{
 
169
  grub_uint64_t bi_vblocknr;
 
170
  grub_uint64_t bi_blkoff;
 
171
};
 
172
 
 
173
struct grub_nilfs2_binfo_dat
 
174
{
 
175
  grub_uint64_t bi_blkoff;
 
176
  grub_uint8_t bi_level;
 
177
  grub_uint8_t bi_pad[7];
 
178
};
 
179
 
 
180
union grub_nilfs2_binfo
 
181
{
 
182
  struct grub_nilfs2_binfo_v bi_v;
 
183
  struct grub_nilfs2_binfo_dat bi_dat;
 
184
};
 
185
 
 
186
struct grub_nilfs2_segment_summary
 
187
{
 
188
  grub_uint32_t ss_datasum;
 
189
  grub_uint32_t ss_sumsum;
 
190
  grub_uint32_t ss_magic;
 
191
  grub_uint16_t ss_bytes;
 
192
  grub_uint16_t ss_flags;
 
193
  grub_uint64_t ss_seq;
 
194
  grub_uint64_t ss_create;
 
195
  grub_uint64_t ss_next;
 
196
  grub_uint32_t ss_nblocks;
 
197
  grub_uint32_t ss_nfinfo;
 
198
  grub_uint32_t ss_sumbytes;
 
199
  grub_uint32_t ss_pad;
 
200
};
 
201
 
 
202
struct grub_nilfs2_btree_node
 
203
{
 
204
  grub_uint8_t bn_flags;
 
205
  grub_uint8_t bn_level;
 
206
  grub_uint16_t bn_nchildren;
 
207
  grub_uint32_t bn_pad;
 
208
};
 
209
 
 
210
struct grub_nilfs2_palloc_group_desc
 
211
{
 
212
  grub_uint32_t pg_nfrees;
 
213
};
 
214
 
 
215
struct grub_nilfs2_dat_entry
 
216
{
 
217
  grub_uint64_t de_blocknr;
 
218
  grub_uint64_t de_start;
 
219
  grub_uint64_t de_end;
 
220
  grub_uint64_t de_rsv;
 
221
};
 
222
 
 
223
struct grub_nilfs2_snapshot_list
 
224
{
 
225
  grub_uint64_t ssl_next;
 
226
  grub_uint64_t ssl_prev;
 
227
};
 
228
 
 
229
struct grub_nilfs2_cpfile_header
 
230
{
 
231
  grub_uint64_t ch_ncheckpoints;
 
232
  grub_uint64_t ch_nsnapshots;
 
233
  struct grub_nilfs2_snapshot_list ch_snapshot_list;
 
234
};
 
235
 
 
236
struct grub_nilfs2_checkpoint
 
237
{
 
238
  grub_uint32_t cp_flags;
 
239
  grub_uint32_t cp_checkpoints_count;
 
240
  struct grub_nilfs2_snapshot_list cp_snapshot_list;
 
241
  grub_uint64_t cp_cno;
 
242
  grub_uint64_t cp_create;
 
243
  grub_uint64_t cp_nblk_inc;
 
244
  grub_uint64_t cp_inodes_count;
 
245
  grub_uint64_t cp_blocks_count;
 
246
  struct grub_nilfs2_inode cp_ifile_inode;
 
247
};
 
248
 
 
249
 
 
250
#define NILFS_BMAP_LARGE        0x1
 
251
#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
 
252
 
 
253
/* nilfs extra padding for nonroot btree node. */
 
254
#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
 
255
#define NILFS_BTREE_ROOT_SIZE   NILFS_BMAP_SIZE
 
256
#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
 
257
 ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
 
258
  (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
 
259
 
 
260
 
 
261
struct grub_fshelp_node
 
262
{
 
263
  struct grub_nilfs2_data *data;
 
264
  struct grub_nilfs2_inode inode;
 
265
  grub_uint64_t ino;
 
266
  int inode_read;
 
267
};
 
268
 
 
269
struct grub_nilfs2_data
 
270
{
 
271
  struct grub_nilfs2_super_block sblock;
 
272
  struct grub_nilfs2_super_root sroot;
 
273
  struct grub_nilfs2_inode ifile;
 
274
  grub_disk_t disk;
 
275
  struct grub_nilfs2_inode *inode;
 
276
  struct grub_fshelp_node diropen;
 
277
};
 
278
 
 
279
/* Log2 size of nilfs2 block in 512 blocks.  */
 
280
#define LOG2_NILFS2_BLOCK_SIZE(data)                    \
 
281
        (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
 
282
 
 
283
/* Log2 size of nilfs2 block in bytes.  */
 
284
#define LOG2_BLOCK_SIZE(data)                                   \
 
285
        (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
 
286
 
 
287
/* The size of an nilfs2 block in bytes.  */
 
288
#define NILFS2_BLOCK_SIZE(data)         (1 << LOG2_BLOCK_SIZE (data))
 
289
 
 
290
static grub_uint64_t
 
291
grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key);
 
292
static grub_dl_t my_mod;
 
293
 
 
294
 
 
295
 
 
296
static inline unsigned long
 
297
grub_nilfs2_palloc_entries_per_group (struct grub_nilfs2_data *data)
 
298
{
 
299
  return 1UL << (LOG2_BLOCK_SIZE (data) + 3);
 
300
}
 
301
 
 
302
static inline grub_uint64_t
 
303
grub_nilfs2_palloc_group (struct grub_nilfs2_data *data,
 
304
                          grub_uint64_t nr, grub_uint32_t * offset)
 
305
{
 
306
  return grub_divmod64 (nr, grub_nilfs2_palloc_entries_per_group (data),
 
307
                        offset);
 
308
}
 
309
 
 
310
static inline grub_uint32_t
 
311
grub_nilfs2_palloc_groups_per_desc_block (struct grub_nilfs2_data *data)
 
312
{
 
313
  return NILFS2_BLOCK_SIZE (data) /
 
314
    sizeof (struct grub_nilfs2_palloc_group_desc);
 
315
}
 
316
 
 
317
static inline grub_uint32_t
 
318
grub_nilfs2_entries_per_block (struct grub_nilfs2_data *data,
 
319
                               unsigned long entry_size)
 
320
{
 
321
  return NILFS2_BLOCK_SIZE (data) / entry_size;
 
322
}
 
323
 
 
324
 
 
325
static inline grub_uint32_t
 
326
grub_nilfs2_blocks_per_group (struct grub_nilfs2_data *data,
 
327
                              unsigned long entry_size)
 
328
{
 
329
  return grub_div_roundup (grub_nilfs2_palloc_entries_per_group (data),
 
330
                           grub_nilfs2_entries_per_block (data,
 
331
                                                          entry_size)) + 1;
 
332
}
 
333
 
 
334
static inline grub_uint32_t
 
335
grub_nilfs2_blocks_per_desc_block (struct grub_nilfs2_data *data,
 
336
                                   unsigned long entry_size)
 
337
{
 
338
  return grub_nilfs2_palloc_groups_per_desc_block (data) *
 
339
    grub_nilfs2_blocks_per_group (data, entry_size) + 1;
 
340
}
 
341
 
 
342
static inline grub_uint32_t
 
343
grub_nilfs2_palloc_desc_block_offset (struct grub_nilfs2_data *data,
 
344
                                      unsigned long group,
 
345
                                      unsigned long entry_size)
 
346
{
 
347
  grub_uint32_t desc_block =
 
348
    group / grub_nilfs2_palloc_groups_per_desc_block (data);
 
349
  return desc_block * grub_nilfs2_blocks_per_desc_block (data, entry_size);
 
350
}
 
351
 
 
352
static inline grub_uint32_t
 
353
grub_nilfs2_palloc_bitmap_block_offset (struct grub_nilfs2_data *data,
 
354
                                        unsigned long group,
 
355
                                        unsigned long entry_size)
 
356
{
 
357
  unsigned long desc_offset = group %
 
358
    grub_nilfs2_palloc_groups_per_desc_block (data);
 
359
 
 
360
  return grub_nilfs2_palloc_desc_block_offset (data, group, entry_size) + 1 +
 
361
    desc_offset * grub_nilfs2_blocks_per_group (data, entry_size);
 
362
}
 
363
 
 
364
static inline grub_uint32_t
 
365
grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data,
 
366
                                 grub_uint64_t nr, unsigned long entry_size)
 
367
{
 
368
  unsigned long group;
 
369
  grub_uint32_t group_offset;
 
370
 
 
371
  group = grub_nilfs2_palloc_group (data, nr, &group_offset);
 
372
 
 
373
  return grub_nilfs2_palloc_bitmap_block_offset (data, group,
 
374
                                                 entry_size) + 1 +
 
375
    group_offset / grub_nilfs2_entries_per_block (data, entry_size);
 
376
 
 
377
}
 
378
 
 
379
static inline struct grub_nilfs2_btree_node *
 
380
grub_nilfs2_btree_get_root (struct grub_nilfs2_inode *inode)
 
381
{
 
382
  return (struct grub_nilfs2_btree_node *) &inode->i_bmap[0];
 
383
}
 
384
 
 
385
static inline int
 
386
grub_nilfs2_btree_get_level (struct grub_nilfs2_btree_node *node)
 
387
{
 
388
  return node->bn_level;
 
389
}
 
390
 
 
391
static inline grub_uint64_t *
 
392
grub_nilfs2_btree_node_dkeys (struct grub_nilfs2_btree_node *node)
 
393
{
 
394
  return (grub_uint64_t *) ((char *) (node + 1) +
 
395
                            ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
 
396
                             0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
 
397
}
 
398
 
 
399
static inline grub_uint64_t
 
400
grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node,
 
401
                                int index)
 
402
{
 
403
  return grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dkeys (node) + index));
 
404
}
 
405
 
 
406
static inline int
 
407
grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node,
 
408
                               grub_uint64_t key, int *indexp)
 
409
{
 
410
  grub_uint64_t nkey;
 
411
  int index, low, high, s;
 
412
 
 
413
  low = 0;
 
414
  high = grub_le_to_cpu16 (node->bn_nchildren) - 1;
 
415
  index = 0;
 
416
  s = 0;
 
417
  while (low <= high)
 
418
    {
 
419
      index = (low + high) / 2;
 
420
      nkey = grub_nilfs2_btree_node_get_key (node, index);
 
421
      if (nkey == key)
 
422
        {
 
423
          *indexp = index;
 
424
          return 1;
 
425
        }
 
426
      else if (nkey < key)
 
427
        {
 
428
          low = index + 1;
 
429
          s = -1;
 
430
        }
 
431
      else
 
432
        {
 
433
          high = index - 1;
 
434
          s = 1;
 
435
        }
 
436
    }
 
437
 
 
438
  if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
 
439
    {
 
440
      if (s > 0 && index > 0)
 
441
        index--;
 
442
    }
 
443
  else if (s < 0)
 
444
    index++;
 
445
 
 
446
  *indexp = index;
 
447
  return s == 0;
 
448
}
 
449
 
 
450
static inline int
 
451
grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data,
 
452
                                      struct grub_nilfs2_btree_node *node)
 
453
{
 
454
  int node_children_max = ((NILFS2_BLOCK_SIZE (data) -
 
455
                            sizeof (struct grub_nilfs2_btree_node) -
 
456
                            NILFS_BTREE_NODE_EXTRA_PAD_SIZE) /
 
457
                           (sizeof (grub_uint64_t) + sizeof (grub_uint64_t)));
 
458
 
 
459
  return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
 
460
}
 
461
 
 
462
static inline grub_uint64_t *
 
463
grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data,
 
464
                              struct grub_nilfs2_btree_node *node)
 
465
{
 
466
  return (grub_uint64_t *) (grub_nilfs2_btree_node_dkeys (node) +
 
467
                            grub_nilfs2_btree_node_nchildren_max (data,
 
468
                                                                  node));
 
469
}
 
470
 
 
471
static inline grub_uint64_t
 
472
grub_nilfs2_btree_node_get_ptr (struct grub_nilfs2_data *data,
 
473
                                struct grub_nilfs2_btree_node *node,
 
474
                                int index)
 
475
{
 
476
  return
 
477
    grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dptrs (data, node) + index));
 
478
}
 
479
 
 
480
static inline int
 
481
grub_nilfs2_btree_get_nonroot_node (struct grub_nilfs2_data *data,
 
482
                                    grub_uint64_t ptr, void *block)
 
483
{
 
484
  grub_disk_t disk = data->disk;
 
485
  unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
486
 
 
487
  return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
 
488
                         NILFS2_BLOCK_SIZE (data), block);
 
489
}
 
490
 
 
491
static grub_uint64_t
 
492
grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data,
 
493
                          struct grub_nilfs2_inode *inode,
 
494
                          grub_uint64_t key, int need_translate)
 
495
{
 
496
  struct grub_nilfs2_btree_node *node;
 
497
  unsigned char block[NILFS2_BLOCK_SIZE (data)];
 
498
  grub_uint64_t ptr;
 
499
  int level, found, index;
 
500
 
 
501
  node = grub_nilfs2_btree_get_root (inode);
 
502
  level = grub_nilfs2_btree_get_level (node);
 
503
 
 
504
  found = grub_nilfs2_btree_node_lookup (node, key, &index);
 
505
  ptr = grub_nilfs2_btree_node_get_ptr (data, node, index);
 
506
  if (need_translate)
 
507
    ptr = grub_nilfs2_dat_translate (data, ptr);
 
508
 
 
509
  for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
 
510
    {
 
511
      grub_nilfs2_btree_get_nonroot_node (data, ptr, block);
 
512
      if (grub_errno)
 
513
        {
 
514
          return -1;
 
515
        }
 
516
      node = (struct grub_nilfs2_btree_node *) block;
 
517
 
 
518
      if (node->bn_level != level)
 
519
        {
 
520
          grub_error (GRUB_ERR_BAD_FS, "btree level mismatch\n");
 
521
          return -1;
 
522
        }
 
523
 
 
524
      if (!found)
 
525
        found = grub_nilfs2_btree_node_lookup (node, key, &index);
 
526
      else
 
527
        index = 0;
 
528
 
 
529
      if (index < grub_nilfs2_btree_node_nchildren_max (data, node))
 
530
        {
 
531
          ptr = grub_nilfs2_btree_node_get_ptr (data, node, index);
 
532
          if (need_translate)
 
533
            ptr = grub_nilfs2_dat_translate (data, ptr);
 
534
        }
 
535
      else
 
536
        {
 
537
          grub_error (GRUB_ERR_BAD_FS, "btree corruption\n");
 
538
          return -1;
 
539
        }
 
540
    }
 
541
 
 
542
  if (!found)
 
543
    return -1;
 
544
 
 
545
  return ptr;
 
546
}
 
547
 
 
548
static inline grub_uint64_t
 
549
grub_nilfs2_direct_lookup (struct grub_nilfs2_inode *inode, grub_uint64_t key)
 
550
{
 
551
  return grub_le_to_cpu64 (inode->i_bmap[1 + key]);
 
552
}
 
553
 
 
554
static inline grub_uint64_t
 
555
grub_nilfs2_bmap_lookup (struct grub_nilfs2_data *data,
 
556
                         struct grub_nilfs2_inode *inode,
 
557
                         grub_uint64_t key, int need_translate)
 
558
{
 
559
  struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root (inode);
 
560
  if (root->bn_flags & NILFS_BMAP_LARGE)
 
561
    return grub_nilfs2_btree_lookup (data, inode, key, need_translate);
 
562
  else
 
563
    {
 
564
      grub_uint64_t ptr;
 
565
      ptr = grub_nilfs2_direct_lookup (inode, key);
 
566
      if (need_translate)
 
567
        ptr = grub_nilfs2_dat_translate (data, ptr);
 
568
      return ptr;
 
569
    }
 
570
}
 
571
 
 
572
static grub_uint64_t
 
573
grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key)
 
574
{
 
575
  struct grub_nilfs2_dat_entry entry;
 
576
  grub_disk_t disk = data->disk;
 
577
  grub_uint64_t pptr;
 
578
  grub_uint32_t blockno, offset;
 
579
  unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
580
 
 
581
  blockno = grub_nilfs2_palloc_entry_offset (data, key,
 
582
                                             sizeof (struct
 
583
                                                     grub_nilfs2_dat_entry));
 
584
 
 
585
  grub_divmod64 (key * sizeof (struct grub_nilfs2_dat_entry),
 
586
                 NILFS2_BLOCK_SIZE (data), &offset);
 
587
 
 
588
  pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_dat, blockno, 0);
 
589
  if (pptr == (grub_uint64_t) - 1)
 
590
    {
 
591
      grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
 
592
      return -1;
 
593
    }
 
594
 
 
595
  grub_disk_read (disk, pptr * nilfs2_block_count, offset,
 
596
                  sizeof (struct grub_nilfs2_dat_entry), &entry);
 
597
 
 
598
  return grub_le_to_cpu64 (entry.de_blocknr);
 
599
}
 
600
 
 
601
 
 
602
static grub_disk_addr_t
 
603
grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 
604
{
 
605
  struct grub_nilfs2_data *data = node->data;
 
606
  struct grub_nilfs2_inode *inode = &node->inode;
 
607
  grub_uint64_t pptr = -1;
 
608
 
 
609
  pptr = grub_nilfs2_bmap_lookup (data, inode, fileblock, 1);
 
610
  if (pptr == (grub_uint64_t) - 1)
 
611
    {
 
612
      grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
 
613
      return -1;
 
614
    }
 
615
 
 
616
  return pptr;
 
617
}
 
618
 
 
619
/* Read LEN bytes from the file described by DATA starting with byte
 
620
   POS.  Return the amount of read bytes in READ.  */
 
621
static grub_ssize_t
 
622
grub_nilfs2_read_file (grub_fshelp_node_t node,
 
623
                       void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t
 
624
                                                           sector,
 
625
                                                           unsigned offset,
 
626
                                                           unsigned length),
 
627
                       int pos, grub_size_t len, char *buf)
 
628
{
 
629
  return grub_fshelp_read_file (node->data->disk, node, read_hook,
 
630
                                pos, len, buf, grub_nilfs2_read_block,
 
631
                                grub_le_to_cpu64 (node->inode.i_size),
 
632
                                LOG2_NILFS2_BLOCK_SIZE (node->data));
 
633
 
 
634
}
 
635
 
 
636
static grub_err_t
 
637
grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data,
 
638
                             grub_uint64_t cpno,
 
639
                             struct grub_nilfs2_checkpoint *cpp)
 
640
{
 
641
  grub_uint64_t blockno;
 
642
  grub_uint32_t offset;
 
643
  grub_uint64_t pptr;
 
644
  grub_disk_t disk = data->disk;
 
645
  unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
646
 
 
647
  /* Assume sizeof(struct grub_nilfs2_cpfile_header) < 
 
648
     sizeof(struct grub_nilfs2_checkpoint).
 
649
   */
 
650
  blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) /
 
651
                           sizeof (struct grub_nilfs2_checkpoint), &offset);
 
652
 
 
653
  pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1);
 
654
  if (pptr == (grub_uint64_t) - 1)
 
655
    {
 
656
      return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
 
657
    }
 
658
 
 
659
  return grub_disk_read (disk, pptr * nilfs2_block_count,
 
660
                         offset * sizeof (struct grub_nilfs2_checkpoint),
 
661
                         sizeof (struct grub_nilfs2_checkpoint), cpp);
 
662
}
 
663
 
 
664
static inline grub_err_t
 
665
grub_nilfs2_read_last_checkpoint (struct grub_nilfs2_data *data,
 
666
                                  struct grub_nilfs2_checkpoint *cpp)
 
667
{
 
668
  return grub_nilfs2_read_checkpoint (data,
 
669
                                      grub_le_to_cpu64 (data->
 
670
                                                        sblock.s_last_cno),
 
671
                                      cpp);
 
672
}
 
673
 
 
674
/* Read the inode INO for the file described by DATA into INODE.  */
 
675
static grub_err_t
 
676
grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
 
677
                        grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
 
678
{
 
679
  grub_uint64_t blockno;
 
680
  unsigned int offset;
 
681
  grub_uint64_t pptr;
 
682
  grub_disk_t disk = data->disk;
 
683
  unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
684
 
 
685
  blockno = grub_nilfs2_palloc_entry_offset (data, ino,
 
686
                                             sizeof (struct
 
687
                                                     grub_nilfs2_inode));
 
688
 
 
689
  grub_divmod64 (sizeof (struct grub_nilfs2_inode) * ino,
 
690
                 NILFS2_BLOCK_SIZE (data), &offset);
 
691
  pptr = grub_nilfs2_bmap_lookup (data, &data->ifile, blockno, 1);
 
692
  if (pptr == (grub_uint64_t) - 1)
 
693
    {
 
694
      return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
 
695
    }
 
696
 
 
697
  return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
 
698
                         sizeof (struct grub_nilfs2_inode), inodep);
 
699
}
 
700
 
 
701
static int
 
702
grub_nilfs2_valid_sb (struct grub_nilfs2_super_block *sbp)
 
703
{
 
704
  if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
 
705
    return 0;
 
706
 
 
707
  if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
 
708
    return 0;
 
709
 
 
710
  return 1;
 
711
}
 
712
 
 
713
static grub_err_t
 
714
grub_nilfs2_load_sb (struct grub_nilfs2_data *data)
 
715
{
 
716
  grub_disk_t disk = data->disk;
 
717
  struct grub_nilfs2_super_block sb2;
 
718
  grub_uint64_t partition_size;
 
719
  int valid[2];
 
720
  int swp = 0;
 
721
  grub_err_t err;
 
722
 
 
723
  /* Read first super block. */
 
724
  err = grub_disk_read (disk, NILFS_1ST_SUPER_BLOCK, 0,
 
725
                        sizeof (struct grub_nilfs2_super_block), &data->sblock);
 
726
  if (err)
 
727
    return err;
 
728
  /* Make sure if 1st super block is valid.  */
 
729
  valid[0] = grub_nilfs2_valid_sb (&data->sblock);
 
730
 
 
731
  partition_size = grub_disk_get_size (disk);
 
732
  if (partition_size != GRUB_DISK_SIZE_UNKNOWN)
 
733
    {
 
734
      /* Read second super block. */
 
735
      err = grub_disk_read (disk, NILFS_2ND_SUPER_BLOCK (partition_size), 0,
 
736
                            sizeof (struct grub_nilfs2_super_block), &sb2);
 
737
      if (err)
 
738
        {
 
739
          valid[1] = 0;
 
740
          grub_errno = GRUB_ERR_NONE;
 
741
        }
 
742
      else
 
743
        /* Make sure if 2nd super block is valid.  */
 
744
        valid[1] = grub_nilfs2_valid_sb (&sb2);
 
745
    }
 
746
  else
 
747
    /* 2nd super block may not exist, so it's invalid. */
 
748
    valid[1] = 0;
 
749
 
 
750
  if (!valid[0] && !valid[1])
 
751
    return grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
 
752
 
 
753
  swp = valid[1] && (!valid[0] ||
 
754
                     grub_le_to_cpu64 (data->sblock.s_last_cno) <
 
755
                     grub_le_to_cpu64 (sb2.s_last_cno));
 
756
 
 
757
  /* swap if first super block is invalid or older than second one. */
 
758
  if (swp)
 
759
    grub_memcpy (&data->sblock, &sb2,
 
760
                 sizeof (struct grub_nilfs2_super_block));
 
761
 
 
762
  return GRUB_ERR_NONE;
 
763
}
 
764
 
 
765
static struct grub_nilfs2_data *
 
766
grub_nilfs2_mount (grub_disk_t disk)
 
767
{
 
768
  struct grub_nilfs2_data *data;
 
769
  struct grub_nilfs2_segment_summary ss;
 
770
  struct grub_nilfs2_checkpoint last_checkpoint;
 
771
  grub_uint64_t last_pseg;
 
772
  grub_uint32_t nblocks;
 
773
  unsigned int nilfs2_block_count;
 
774
 
 
775
  data = grub_malloc (sizeof (struct grub_nilfs2_data));
 
776
  if (!data)
 
777
    return 0;
 
778
 
 
779
  data->disk = disk;
 
780
 
 
781
  /* Read the superblock.  */
 
782
  grub_nilfs2_load_sb (data);
 
783
  if (grub_errno)
 
784
    goto fail;
 
785
 
 
786
  nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
787
 
 
788
  /* Read the last segment summary. */
 
789
  last_pseg = grub_le_to_cpu64 (data->sblock.s_last_pseg);
 
790
  grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
 
791
                  sizeof (struct grub_nilfs2_segment_summary), &ss);
 
792
 
 
793
  if (grub_errno)
 
794
    goto fail;
 
795
 
 
796
  /* Read the super root block. */
 
797
  nblocks = grub_le_to_cpu32 (ss.ss_nblocks);
 
798
  grub_disk_read (disk, (last_pseg + (nblocks - 1)) * nilfs2_block_count, 0,
 
799
                  sizeof (struct grub_nilfs2_super_root), &data->sroot);
 
800
 
 
801
  if (grub_errno)
 
802
    goto fail;
 
803
 
 
804
  grub_nilfs2_read_last_checkpoint (data, &last_checkpoint);
 
805
 
 
806
  if (grub_errno)
 
807
    goto fail;
 
808
 
 
809
  grub_memcpy (&data->ifile, &last_checkpoint.cp_ifile_inode,
 
810
               sizeof (struct grub_nilfs2_inode));
 
811
 
 
812
  data->diropen.data = data;
 
813
  data->diropen.ino = 2;
 
814
  data->diropen.inode_read = 1;
 
815
  data->inode = &data->diropen.inode;
 
816
 
 
817
  grub_nilfs2_read_inode (data, 2, data->inode);
 
818
 
 
819
  return data;
 
820
 
 
821
fail:
 
822
  if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
 
823
    grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
 
824
 
 
825
  grub_free (data);
 
826
  return 0;
 
827
}
 
828
 
 
829
static char *
 
830
grub_nilfs2_read_symlink (grub_fshelp_node_t node)
 
831
{
 
832
  char *symlink;
 
833
  struct grub_fshelp_node *diro = node;
 
834
 
 
835
  if (!diro->inode_read)
 
836
    {
 
837
      grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
 
838
      if (grub_errno)
 
839
        return 0;
 
840
    }
 
841
 
 
842
  symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
 
843
  if (!symlink)
 
844
    return 0;
 
845
 
 
846
  grub_nilfs2_read_file (diro, 0, 0,
 
847
                         grub_le_to_cpu64 (diro->inode.i_size), symlink);
 
848
  if (grub_errno)
 
849
    {
 
850
      grub_free (symlink);
 
851
      return 0;
 
852
    }
 
853
 
 
854
  symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
 
855
  return symlink;
 
856
}
 
857
 
 
858
static int
 
859
grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
 
860
                         int NESTED_FUNC_ATTR
 
861
                         (*hook) (const char *filename,
 
862
                                  enum grub_fshelp_filetype filetype,
 
863
                                  grub_fshelp_node_t node))
 
864
{
 
865
  unsigned int fpos = 0;
 
866
  struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
 
867
 
 
868
  if (!diro->inode_read)
 
869
    {
 
870
      grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
 
871
      if (grub_errno)
 
872
        return 0;
 
873
    }
 
874
 
 
875
  /* Iterate files.  */
 
876
  while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
 
877
    {
 
878
      struct grub_nilfs2_dir_entry dirent;
 
879
 
 
880
      grub_nilfs2_read_file (diro, 0, fpos,
 
881
                             sizeof (struct grub_nilfs2_dir_entry),
 
882
                             (char *) &dirent);
 
883
      if (grub_errno)
 
884
        return 0;
 
885
 
 
886
      if (dirent.rec_len == 0)
 
887
        return 0;
 
888
 
 
889
      if (dirent.name_len != 0)
 
890
        {
 
891
          char filename[dirent.name_len + 1];
 
892
          struct grub_fshelp_node *fdiro;
 
893
          enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
 
894
 
 
895
          grub_nilfs2_read_file (diro, 0,
 
896
                                 fpos + sizeof (struct grub_nilfs2_dir_entry),
 
897
                                 dirent.name_len, filename);
 
898
          if (grub_errno)
 
899
            return 0;
 
900
 
 
901
          fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
 
902
          if (!fdiro)
 
903
            return 0;
 
904
 
 
905
          fdiro->data = diro->data;
 
906
          fdiro->ino = grub_le_to_cpu64 (dirent.inode);
 
907
 
 
908
          filename[dirent.name_len] = '\0';
 
909
 
 
910
          if (dirent.file_type != NILFS_FT_UNKNOWN)
 
911
            {
 
912
              fdiro->inode_read = 0;
 
913
 
 
914
              if (dirent.file_type == NILFS_FT_DIR)
 
915
                type = GRUB_FSHELP_DIR;
 
916
              else if (dirent.file_type == NILFS_FT_SYMLINK)
 
917
                type = GRUB_FSHELP_SYMLINK;
 
918
              else if (dirent.file_type == NILFS_FT_REG_FILE)
 
919
                type = GRUB_FSHELP_REG;
 
920
            }
 
921
          else
 
922
            {
 
923
              /* The filetype can not be read from the dirent, read
 
924
                 the inode to get more information.  */
 
925
              grub_nilfs2_read_inode (diro->data,
 
926
                                      grub_le_to_cpu64 (dirent.inode),
 
927
                                      &fdiro->inode);
 
928
              if (grub_errno)
 
929
                {
 
930
                  grub_free (fdiro);
 
931
                  return 0;
 
932
                }
 
933
 
 
934
              fdiro->inode_read = 1;
 
935
 
 
936
              if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
 
937
                   & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
 
938
                type = GRUB_FSHELP_DIR;
 
939
              else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
 
940
                        & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
 
941
                type = GRUB_FSHELP_SYMLINK;
 
942
              else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
 
943
                        & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
 
944
                type = GRUB_FSHELP_REG;
 
945
            }
 
946
 
 
947
          if (hook (filename, type, fdiro))
 
948
            return 1;
 
949
        }
 
950
 
 
951
      fpos += grub_le_to_cpu16 (dirent.rec_len);
 
952
    }
 
953
 
 
954
  return 0;
 
955
}
 
956
 
 
957
/* Open a file named NAME and initialize FILE.  */
 
958
static grub_err_t
 
959
grub_nilfs2_open (struct grub_file *file, const char *name)
 
960
{
 
961
  struct grub_nilfs2_data *data = NULL;
 
962
  struct grub_fshelp_node *fdiro = 0;
 
963
 
 
964
  grub_dl_ref (my_mod);
 
965
 
 
966
  data = grub_nilfs2_mount (file->device->disk);
 
967
  if (!data)
 
968
    goto fail;
 
969
 
 
970
  grub_fshelp_find_file (name, &data->diropen, &fdiro,
 
971
                         grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink,
 
972
                         GRUB_FSHELP_REG);
 
973
  if (grub_errno)
 
974
    goto fail;
 
975
 
 
976
  if (!fdiro->inode_read)
 
977
    {
 
978
      grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
 
979
      if (grub_errno)
 
980
        goto fail;
 
981
    }
 
982
 
 
983
  grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
 
984
  grub_free (fdiro);
 
985
 
 
986
  file->size = grub_le_to_cpu64 (data->inode->i_size);
 
987
  file->data = data;
 
988
  file->offset = 0;
 
989
 
 
990
  return 0;
 
991
 
 
992
fail:
 
993
  if (fdiro != &data->diropen)
 
994
    grub_free (fdiro);
 
995
  grub_free (data);
 
996
 
 
997
  grub_dl_unref (my_mod);
 
998
 
 
999
  return grub_errno;
 
1000
}
 
1001
 
 
1002
static grub_err_t
 
1003
grub_nilfs2_close (grub_file_t file)
 
1004
{
 
1005
  grub_free (file->data);
 
1006
 
 
1007
  grub_dl_unref (my_mod);
 
1008
 
 
1009
  return GRUB_ERR_NONE;
 
1010
}
 
1011
 
 
1012
/* Read LEN bytes data from FILE into BUF.  */
 
1013
static grub_ssize_t
 
1014
grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
 
1015
{
 
1016
  struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
 
1017
 
 
1018
  return grub_nilfs2_read_file (&data->diropen, file->read_hook,
 
1019
                                file->offset, len, buf);
 
1020
}
 
1021
 
 
1022
static grub_err_t
 
1023
grub_nilfs2_dir (grub_device_t device, const char *path,
 
1024
                 int (*hook) (const char *filename,
 
1025
                              const struct grub_dirhook_info * info))
 
1026
{
 
1027
  struct grub_nilfs2_data *data = 0;
 
1028
  struct grub_fshelp_node *fdiro = 0;
 
1029
 
 
1030
  auto int NESTED_FUNC_ATTR iterate (const char *filename,
 
1031
                                     enum grub_fshelp_filetype filetype,
 
1032
                                     grub_fshelp_node_t node);
 
1033
 
 
1034
  int NESTED_FUNC_ATTR iterate (const char *filename,
 
1035
                                enum grub_fshelp_filetype filetype,
 
1036
                                grub_fshelp_node_t node)
 
1037
  {
 
1038
    struct grub_dirhook_info info;
 
1039
    grub_memset (&info, 0, sizeof (info));
 
1040
    if (!node->inode_read)
 
1041
      {
 
1042
        grub_nilfs2_read_inode (data, node->ino, &node->inode);
 
1043
        if (!grub_errno)
 
1044
          node->inode_read = 1;
 
1045
        grub_errno = GRUB_ERR_NONE;
 
1046
      }
 
1047
    if (node->inode_read)
 
1048
      {
 
1049
        info.mtimeset = 1;
 
1050
        info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
 
1051
      }
 
1052
 
 
1053
    info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
 
1054
    grub_free (node);
 
1055
    return hook (filename, &info);
 
1056
  }
 
1057
 
 
1058
  grub_dl_ref (my_mod);
 
1059
 
 
1060
  data = grub_nilfs2_mount (device->disk);
 
1061
  if (!data)
 
1062
    goto fail;
 
1063
 
 
1064
  grub_fshelp_find_file (path, &data->diropen, &fdiro,
 
1065
                         grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink,
 
1066
                         GRUB_FSHELP_DIR);
 
1067
  if (grub_errno)
 
1068
    goto fail;
 
1069
 
 
1070
  grub_nilfs2_iterate_dir (fdiro, iterate);
 
1071
 
 
1072
fail:
 
1073
  if (fdiro != &data->diropen)
 
1074
    grub_free (fdiro);
 
1075
  grub_free (data);
 
1076
 
 
1077
  grub_dl_unref (my_mod);
 
1078
 
 
1079
  return grub_errno;
 
1080
}
 
1081
 
 
1082
static grub_err_t
 
1083
grub_nilfs2_label (grub_device_t device, char **label)
 
1084
{
 
1085
  struct grub_nilfs2_data *data;
 
1086
  grub_disk_t disk = device->disk;
 
1087
 
 
1088
  grub_dl_ref (my_mod);
 
1089
 
 
1090
  data = grub_nilfs2_mount (disk);
 
1091
  if (data)
 
1092
    *label = grub_strndup (data->sblock.s_volume_name, 14);
 
1093
  else
 
1094
    *label = NULL;
 
1095
 
 
1096
  grub_dl_unref (my_mod);
 
1097
 
 
1098
  grub_free (data);
 
1099
 
 
1100
  return grub_errno;
 
1101
}
 
1102
 
 
1103
static grub_err_t
 
1104
grub_nilfs2_uuid (grub_device_t device, char **uuid)
 
1105
{
 
1106
  struct grub_nilfs2_data *data;
 
1107
  grub_disk_t disk = device->disk;
 
1108
 
 
1109
  grub_dl_ref (my_mod);
 
1110
 
 
1111
  data = grub_nilfs2_mount (disk);
 
1112
  if (data)
 
1113
    {
 
1114
      *uuid =
 
1115
        grub_xasprintf
 
1116
        ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
 
1117
         data->sblock.s_uuid[0], data->sblock.s_uuid[1],
 
1118
         data->sblock.s_uuid[2], data->sblock.s_uuid[3],
 
1119
         data->sblock.s_uuid[4], data->sblock.s_uuid[5],
 
1120
         data->sblock.s_uuid[6], data->sblock.s_uuid[7],
 
1121
         data->sblock.s_uuid[8], data->sblock.s_uuid[9],
 
1122
         data->sblock.s_uuid[10], data->sblock.s_uuid[11],
 
1123
         data->sblock.s_uuid[12], data->sblock.s_uuid[13],
 
1124
         data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
 
1125
    }
 
1126
  else
 
1127
    *uuid = NULL;
 
1128
 
 
1129
  grub_dl_unref (my_mod);
 
1130
 
 
1131
  grub_free (data);
 
1132
 
 
1133
  return grub_errno;
 
1134
}
 
1135
 
 
1136
/* Get mtime.  */
 
1137
static grub_err_t
 
1138
grub_nilfs2_mtime (grub_device_t device, grub_int32_t * tm)
 
1139
{
 
1140
  struct grub_nilfs2_data *data;
 
1141
  grub_disk_t disk = device->disk;
 
1142
 
 
1143
  grub_dl_ref (my_mod);
 
1144
 
 
1145
  data = grub_nilfs2_mount (disk);
 
1146
  if (!data)
 
1147
    *tm = 0;
 
1148
  else
 
1149
    *tm = (grub_int32_t) grub_le_to_cpu64 (data->sblock.s_mtime);
 
1150
 
 
1151
  grub_dl_unref (my_mod);
 
1152
 
 
1153
  grub_free (data);
 
1154
 
 
1155
  return grub_errno;
 
1156
}
 
1157
 
 
1158
 
 
1159
 
 
1160
static struct grub_fs grub_nilfs2_fs = {
 
1161
  .name = "nilfs2",
 
1162
  .dir = grub_nilfs2_dir,
 
1163
  .open = grub_nilfs2_open,
 
1164
  .read = grub_nilfs2_read,
 
1165
  .close = grub_nilfs2_close,
 
1166
  .label = grub_nilfs2_label,
 
1167
  .uuid = grub_nilfs2_uuid,
 
1168
  .mtime = grub_nilfs2_mtime,
 
1169
#ifdef GRUB_UTIL
 
1170
  .reserved_first_sector = 1,
 
1171
#endif
 
1172
  .next = 0
 
1173
};
 
1174
 
 
1175
GRUB_MOD_INIT (nilfs2)
 
1176
{
 
1177
  grub_fs_register (&grub_nilfs2_fs);
 
1178
  my_mod = mod;
 
1179
}
 
1180
 
 
1181
GRUB_MOD_FINI (nilfs2)
 
1182
{
 
1183
  grub_fs_unregister (&grub_nilfs2_fs);
 
1184
}