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

« back to all changes in this revision

Viewing changes to fs/ext2.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ext2.c - Second Extended filesystem */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2003,2004,2005,2007,2008,2009  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
 
/* Magic value used to identify an ext2 filesystem.  */
21
 
#define EXT2_MAGIC              0xEF53
22
 
/* Amount of indirect blocks in an inode.  */
23
 
#define INDIRECT_BLOCKS         12
24
 
/* Maximum length of a pathname.  */
25
 
#define EXT2_PATH_MAX           4096
26
 
/* Maximum nesting of symlinks, used to prevent a loop.  */
27
 
#define EXT2_MAX_SYMLINKCNT     8
28
 
 
29
 
/* The good old revision and the default inode size.  */
30
 
#define EXT2_GOOD_OLD_REVISION          0
31
 
#define EXT2_GOOD_OLD_INODE_SIZE        128
32
 
 
33
 
/* Filetype used in directory entry.  */
34
 
#define FILETYPE_UNKNOWN        0
35
 
#define FILETYPE_REG            1
36
 
#define FILETYPE_DIRECTORY      2
37
 
#define FILETYPE_SYMLINK        7
38
 
 
39
 
/* Filetype information as used in inodes.  */
40
 
#define FILETYPE_INO_MASK       0170000
41
 
#define FILETYPE_INO_REG        0100000
42
 
#define FILETYPE_INO_DIRECTORY  0040000
43
 
#define FILETYPE_INO_SYMLINK    0120000
44
 
 
45
 
#include <grub/err.h>
46
 
#include <grub/file.h>
47
 
#include <grub/mm.h>
48
 
#include <grub/misc.h>
49
 
#include <grub/disk.h>
50
 
#include <grub/dl.h>
51
 
#include <grub/types.h>
52
 
#include <grub/fshelp.h>
53
 
 
54
 
/* Log2 size of ext2 block in 512 blocks.  */
55
 
#define LOG2_EXT2_BLOCK_SIZE(data)                      \
56
 
        (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
57
 
 
58
 
/* Log2 size of ext2 block in bytes.  */
59
 
#define LOG2_BLOCK_SIZE(data)                                   \
60
 
        (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
61
 
 
62
 
/* The size of an ext2 block in bytes.  */
63
 
#define EXT2_BLOCK_SIZE(data)           (1 << LOG2_BLOCK_SIZE (data))
64
 
 
65
 
/* The revision level.  */
66
 
#define EXT2_REVISION(data)     grub_le_to_cpu32 (data->sblock.revision_level)
67
 
 
68
 
/* The inode size.  */
69
 
#define EXT2_INODE_SIZE(data)   \
70
 
        (EXT2_REVISION (data) == EXT2_GOOD_OLD_REVISION \
71
 
         ? EXT2_GOOD_OLD_INODE_SIZE \
72
 
         : grub_le_to_cpu16 (data->sblock.inode_size))
73
 
 
74
 
/* Superblock filesystem feature flags (RW compatible)
75
 
 * A filesystem with any of these enabled can be read and written by a driver
76
 
 * that does not understand them without causing metadata/data corruption.  */
77
 
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC        0x0001
78
 
#define EXT2_FEATURE_COMPAT_IMAGIC_INODES       0x0002
79
 
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL         0x0004
80
 
#define EXT2_FEATURE_COMPAT_EXT_ATTR            0x0008
81
 
#define EXT2_FEATURE_COMPAT_RESIZE_INODE        0x0010
82
 
#define EXT2_FEATURE_COMPAT_DIR_INDEX           0x0020
83
 
/* Superblock filesystem feature flags (RO compatible)
84
 
 * A filesystem with any of these enabled can be safely read by a driver that
85
 
 * does not understand them, but should not be written to, usually because
86
 
 * additional metadata is required.  */
87
 
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     0x0001
88
 
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE       0x0002
89
 
#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR        0x0004
90
 
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM         0x0010
91
 
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK        0x0020
92
 
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE      0x0040
93
 
/* Superblock filesystem feature flags (back-incompatible)
94
 
 * A filesystem with any of these enabled should not be attempted to be read
95
 
 * by a driver that does not understand them, since they usually indicate
96
 
 * metadata format changes that might confuse the reader.  */
97
 
#define EXT2_FEATURE_INCOMPAT_COMPRESSION       0x0001
98
 
#define EXT2_FEATURE_INCOMPAT_FILETYPE          0x0002
99
 
#define EXT3_FEATURE_INCOMPAT_RECOVER           0x0004 /* Needs recovery */
100
 
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV       0x0008 /* Volume is journal device */
101
 
#define EXT2_FEATURE_INCOMPAT_META_BG           0x0010
102
 
#define EXT4_FEATURE_INCOMPAT_EXTENTS           0x0040 /* Extents used */
103
 
#define EXT4_FEATURE_INCOMPAT_64BIT             0x0080
104
 
#define EXT4_FEATURE_INCOMPAT_FLEX_BG           0x0200
105
 
 
106
 
/* The set of back-incompatible features this driver DOES support. Add (OR)
107
 
 * flags here as the related features are implemented into the driver.  */
108
 
#define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
109
 
                                       | EXT4_FEATURE_INCOMPAT_EXTENTS  \
110
 
                                       | EXT4_FEATURE_INCOMPAT_FLEX_BG )
111
 
/* List of rationales for the ignored "incompatible" features:
112
 
 * needs_recovery: Not really back-incompatible - was added as such to forbid
113
 
 *                 ext2 drivers from mounting an ext3 volume with a dirty
114
 
 *                 journal because they will ignore the journal, but the next
115
 
 *                 ext3 driver to mount the volume will find the journal and
116
 
 *                 replay it, potentially corrupting the metadata written by
117
 
 *                 the ext2 drivers. Safe to ignore for this RO driver.  */
118
 
#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER )
119
 
 
120
 
 
121
 
#define EXT3_JOURNAL_MAGIC_NUMBER       0xc03b3998U
122
 
 
123
 
#define EXT3_JOURNAL_DESCRIPTOR_BLOCK   1
124
 
#define EXT3_JOURNAL_COMMIT_BLOCK       2
125
 
#define EXT3_JOURNAL_SUPERBLOCK_V1      3
126
 
#define EXT3_JOURNAL_SUPERBLOCK_V2      4
127
 
#define EXT3_JOURNAL_REVOKE_BLOCK       5
128
 
 
129
 
#define EXT3_JOURNAL_FLAG_ESCAPE        1
130
 
#define EXT3_JOURNAL_FLAG_SAME_UUID     2
131
 
#define EXT3_JOURNAL_FLAG_DELETED       4
132
 
#define EXT3_JOURNAL_FLAG_LAST_TAG      8
133
 
 
134
 
#define EXT4_EXTENTS_FLAG               0x80000
135
 
 
136
 
/* The ext2 superblock.  */
137
 
struct grub_ext2_sblock
138
 
{
139
 
  grub_uint32_t total_inodes;
140
 
  grub_uint32_t total_blocks;
141
 
  grub_uint32_t reserved_blocks;
142
 
  grub_uint32_t free_blocks;
143
 
  grub_uint32_t free_inodes;
144
 
  grub_uint32_t first_data_block;
145
 
  grub_uint32_t log2_block_size;
146
 
  grub_uint32_t log2_fragment_size;
147
 
  grub_uint32_t blocks_per_group;
148
 
  grub_uint32_t fragments_per_group;
149
 
  grub_uint32_t inodes_per_group;
150
 
  grub_uint32_t mtime;
151
 
  grub_uint32_t utime;
152
 
  grub_uint16_t mnt_count;
153
 
  grub_uint16_t max_mnt_count;
154
 
  grub_uint16_t magic;
155
 
  grub_uint16_t fs_state;
156
 
  grub_uint16_t error_handling;
157
 
  grub_uint16_t minor_revision_level;
158
 
  grub_uint32_t lastcheck;
159
 
  grub_uint32_t checkinterval;
160
 
  grub_uint32_t creator_os;
161
 
  grub_uint32_t revision_level;
162
 
  grub_uint16_t uid_reserved;
163
 
  grub_uint16_t gid_reserved;
164
 
  grub_uint32_t first_inode;
165
 
  grub_uint16_t inode_size;
166
 
  grub_uint16_t block_group_number;
167
 
  grub_uint32_t feature_compatibility;
168
 
  grub_uint32_t feature_incompat;
169
 
  grub_uint32_t feature_ro_compat;
170
 
  grub_uint16_t uuid[8];
171
 
  char volume_name[16];
172
 
  char last_mounted_on[64];
173
 
  grub_uint32_t compression_info;
174
 
  grub_uint8_t prealloc_blocks;
175
 
  grub_uint8_t prealloc_dir_blocks;
176
 
  grub_uint16_t reserved_gdt_blocks;
177
 
  grub_uint8_t journal_uuid[16];
178
 
  grub_uint32_t journal_inum;
179
 
  grub_uint32_t journal_dev;
180
 
  grub_uint32_t last_orphan;
181
 
  grub_uint32_t hash_seed[4];
182
 
  grub_uint8_t def_hash_version;
183
 
  grub_uint8_t jnl_backup_type;
184
 
  grub_uint16_t reserved_word_pad;
185
 
  grub_uint32_t default_mount_opts;
186
 
  grub_uint32_t first_meta_bg;
187
 
  grub_uint32_t mkfs_time;
188
 
  grub_uint32_t jnl_blocks[17];
189
 
};
190
 
 
191
 
/* The ext2 blockgroup.  */
192
 
struct grub_ext2_block_group
193
 
{
194
 
  grub_uint32_t block_id;
195
 
  grub_uint32_t inode_id;
196
 
  grub_uint32_t inode_table_id;
197
 
  grub_uint16_t free_blocks;
198
 
  grub_uint16_t free_inodes;
199
 
  grub_uint16_t used_dirs;
200
 
  grub_uint16_t pad;
201
 
  grub_uint32_t reserved[3];
202
 
};
203
 
 
204
 
/* The ext2 inode.  */
205
 
struct grub_ext2_inode
206
 
{
207
 
  grub_uint16_t mode;
208
 
  grub_uint16_t uid;
209
 
  grub_uint32_t size;
210
 
  grub_uint32_t atime;
211
 
  grub_uint32_t ctime;
212
 
  grub_uint32_t mtime;
213
 
  grub_uint32_t dtime;
214
 
  grub_uint16_t gid;
215
 
  grub_uint16_t nlinks;
216
 
  grub_uint32_t blockcnt;  /* Blocks of 512 bytes!! */
217
 
  grub_uint32_t flags;
218
 
  grub_uint32_t osd1;
219
 
  union
220
 
  {
221
 
    struct datablocks
222
 
    {
223
 
      grub_uint32_t dir_blocks[INDIRECT_BLOCKS];
224
 
      grub_uint32_t indir_block;
225
 
      grub_uint32_t double_indir_block;
226
 
      grub_uint32_t triple_indir_block;
227
 
    } blocks;
228
 
    char symlink[60];
229
 
  };
230
 
  grub_uint32_t version;
231
 
  grub_uint32_t acl;
232
 
  grub_uint32_t dir_acl;
233
 
  grub_uint32_t fragment_addr;
234
 
  grub_uint32_t osd2[3];
235
 
};
236
 
 
237
 
/* The header of an ext2 directory entry.  */
238
 
struct ext2_dirent
239
 
{
240
 
  grub_uint32_t inode;
241
 
  grub_uint16_t direntlen;
242
 
  grub_uint8_t namelen;
243
 
  grub_uint8_t filetype;
244
 
};
245
 
 
246
 
struct grub_ext3_journal_header
247
 
{
248
 
  grub_uint32_t magic;
249
 
  grub_uint32_t block_type;
250
 
  grub_uint32_t sequence;
251
 
};
252
 
 
253
 
struct grub_ext3_journal_revoke_header
254
 
{
255
 
  struct grub_ext3_journal_header header;
256
 
  grub_uint32_t count;
257
 
  grub_uint32_t data[0];
258
 
};
259
 
 
260
 
struct grub_ext3_journal_block_tag
261
 
{
262
 
  grub_uint32_t block;
263
 
  grub_uint32_t flags;
264
 
};
265
 
 
266
 
struct grub_ext3_journal_sblock
267
 
{
268
 
  struct grub_ext3_journal_header header;
269
 
  grub_uint32_t block_size;
270
 
  grub_uint32_t maxlen;
271
 
  grub_uint32_t first;
272
 
  grub_uint32_t sequence;
273
 
  grub_uint32_t start;
274
 
};
275
 
 
276
 
#define EXT4_EXT_MAGIC          0xf30a
277
 
 
278
 
struct grub_ext4_extent_header
279
 
{
280
 
  grub_uint16_t magic;
281
 
  grub_uint16_t entries;
282
 
  grub_uint16_t max;
283
 
  grub_uint16_t depth;
284
 
  grub_uint32_t generation;
285
 
};
286
 
 
287
 
struct grub_ext4_extent
288
 
{
289
 
  grub_uint32_t block;
290
 
  grub_uint16_t len;
291
 
  grub_uint16_t start_hi;
292
 
  grub_uint32_t start;
293
 
};
294
 
 
295
 
struct grub_ext4_extent_idx
296
 
{
297
 
  grub_uint32_t block;
298
 
  grub_uint32_t leaf;
299
 
  grub_uint16_t leaf_hi;
300
 
  grub_uint16_t unused;
301
 
};
302
 
 
303
 
struct grub_fshelp_node
304
 
{
305
 
  struct grub_ext2_data *data;
306
 
  struct grub_ext2_inode inode;
307
 
  int ino;
308
 
  int inode_read;
309
 
};
310
 
 
311
 
/* Information about a "mounted" ext2 filesystem.  */
312
 
struct grub_ext2_data
313
 
{
314
 
  struct grub_ext2_sblock sblock;
315
 
  grub_disk_t disk;
316
 
  struct grub_ext2_inode *inode;
317
 
  struct grub_fshelp_node diropen;
318
 
};
319
 
 
320
 
static grub_dl_t my_mod;
321
 
 
322
 
 
323
 
 
324
 
/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
325
 
   the mounted filesystem DATA.  */
326
 
inline static grub_err_t
327
 
grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
328
 
                      struct grub_ext2_block_group *blkgrp)
329
 
{
330
 
  return grub_disk_read (data->disk,
331
 
                         ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
332
 
                          << LOG2_EXT2_BLOCK_SIZE (data)),
333
 
                         group * sizeof (struct grub_ext2_block_group),
334
 
                         sizeof (struct grub_ext2_block_group), blkgrp);
335
 
}
336
 
 
337
 
static struct grub_ext4_extent_header *
338
 
grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
339
 
                     struct grub_ext4_extent_header *ext_block,
340
 
                     grub_uint32_t fileblock)
341
 
{
342
 
  struct grub_ext4_extent_idx *index;
343
 
 
344
 
  while (1)
345
 
    {
346
 
      int i;
347
 
      grub_disk_addr_t block;
348
 
 
349
 
      index = (struct grub_ext4_extent_idx *) (ext_block + 1);
350
 
 
351
 
      if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
352
 
        return 0;
353
 
 
354
 
      if (ext_block->depth == 0)
355
 
        return ext_block;
356
 
 
357
 
      for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
358
 
        {
359
 
          if (fileblock < grub_le_to_cpu32(index[i].block))
360
 
            break;
361
 
        }
362
 
 
363
 
      if (--i < 0)
364
 
        return 0;
365
 
 
366
 
      block = grub_le_to_cpu16 (index[i].leaf_hi);
367
 
      block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
368
 
      if (grub_disk_read (data->disk,
369
 
                          block << LOG2_EXT2_BLOCK_SIZE (data),
370
 
                          0, EXT2_BLOCK_SIZE(data), buf))
371
 
        return 0;
372
 
 
373
 
      ext_block = (struct grub_ext4_extent_header *) buf;
374
 
    }
375
 
}
376
 
 
377
 
static grub_disk_addr_t
378
 
grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
379
 
{
380
 
  struct grub_ext2_data *data = node->data;
381
 
  struct grub_ext2_inode *inode = &node->inode;
382
 
  int blknr = -1;
383
 
  unsigned int blksz = EXT2_BLOCK_SIZE (data);
384
 
  int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
385
 
 
386
 
  if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG)
387
 
    {
388
 
      char buf[EXT2_BLOCK_SIZE(data)];
389
 
      struct grub_ext4_extent_header *leaf;
390
 
      struct grub_ext4_extent *ext;
391
 
      int i;
392
 
 
393
 
      leaf = grub_ext4_find_leaf (data, buf,
394
 
                                  (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
395
 
                                  fileblock);
396
 
      if (! leaf)
397
 
        {
398
 
          grub_error (GRUB_ERR_BAD_FS, "invalid extent");
399
 
          return -1;
400
 
        }
401
 
 
402
 
      ext = (struct grub_ext4_extent *) (leaf + 1);
403
 
      for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
404
 
        {
405
 
          if (fileblock < grub_le_to_cpu32 (ext[i].block))
406
 
            break;
407
 
        }
408
 
 
409
 
      if (--i >= 0)
410
 
        {
411
 
          fileblock -= grub_le_to_cpu32 (ext[i].block);
412
 
          if (fileblock >= grub_le_to_cpu16 (ext[i].len))
413
 
            return 0;
414
 
          else
415
 
            {
416
 
              grub_disk_addr_t start;
417
 
 
418
 
              start = grub_le_to_cpu16 (ext[i].start_hi);
419
 
              start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
420
 
 
421
 
              return fileblock + start;
422
 
            }
423
 
        }
424
 
      else
425
 
        {
426
 
          grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
427
 
          return -1;
428
 
        }
429
 
    }
430
 
  /* Direct blocks.  */
431
 
  if (fileblock < INDIRECT_BLOCKS)
432
 
    blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
433
 
  /* Indirect.  */
434
 
  else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
435
 
    {
436
 
      grub_uint32_t indir[blksz / 4];
437
 
 
438
 
      if (grub_disk_read (data->disk,
439
 
                          grub_le_to_cpu32 (inode->blocks.indir_block)
440
 
                          << log2_blksz,
441
 
                          0, blksz, indir))
442
 
        return grub_errno;
443
 
 
444
 
      blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
445
 
    }
446
 
  /* Double indirect.  */
447
 
  else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1))
448
 
    {
449
 
      unsigned int perblock = blksz / 4;
450
 
      unsigned int rblock = fileblock - (INDIRECT_BLOCKS
451
 
                                         + blksz / 4);
452
 
      grub_uint32_t indir[blksz / 4];
453
 
 
454
 
      if (grub_disk_read (data->disk,
455
 
                          grub_le_to_cpu32 (inode->blocks.double_indir_block)
456
 
                          << log2_blksz,
457
 
                          0, blksz, indir))
458
 
        return grub_errno;
459
 
 
460
 
      if (grub_disk_read (data->disk,
461
 
                          grub_le_to_cpu32 (indir[rblock / perblock])
462
 
                          << log2_blksz,
463
 
                          0, blksz, indir))
464
 
        return grub_errno;
465
 
 
466
 
 
467
 
      blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
468
 
    }
469
 
  /* triple indirect.  */
470
 
  else
471
 
    {
472
 
      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
473
 
                  "ext2fs doesn't support triple indirect blocks");
474
 
    }
475
 
 
476
 
  return blknr;
477
 
}
478
 
 
479
 
/* Read LEN bytes from the file described by DATA starting with byte
480
 
   POS.  Return the amount of read bytes in READ.  */
481
 
static grub_ssize_t
482
 
grub_ext2_read_file (grub_fshelp_node_t node,
483
 
                     void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
484
 
                                        unsigned offset, unsigned length),
485
 
                     int pos, grub_size_t len, char *buf)
486
 
{
487
 
  return grub_fshelp_read_file (node->data->disk, node, read_hook,
488
 
                                pos, len, buf, grub_ext2_read_block,
489
 
                                node->inode.size,
490
 
                                LOG2_EXT2_BLOCK_SIZE (node->data));
491
 
 
492
 
}
493
 
 
494
 
 
495
 
/* Read the inode INO for the file described by DATA into INODE.  */
496
 
static grub_err_t
497
 
grub_ext2_read_inode (struct grub_ext2_data *data,
498
 
                      int ino, struct grub_ext2_inode *inode)
499
 
{
500
 
  struct grub_ext2_block_group blkgrp;
501
 
  struct grub_ext2_sblock *sblock = &data->sblock;
502
 
  int inodes_per_block;
503
 
  unsigned int blkno;
504
 
  unsigned int blkoff;
505
 
 
506
 
  /* It is easier to calculate if the first inode is 0.  */
507
 
  ino--;
508
 
 
509
 
  grub_ext2_blockgroup (data,
510
 
                        ino / grub_le_to_cpu32 (sblock->inodes_per_group),
511
 
                        &blkgrp);
512
 
  if (grub_errno)
513
 
    return grub_errno;
514
 
 
515
 
  inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data);
516
 
  blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
517
 
    / inodes_per_block;
518
 
  blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
519
 
    % inodes_per_block;
520
 
 
521
 
  /* Read the inode.  */
522
 
  if (grub_disk_read (data->disk,
523
 
                      ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
524
 
                        << LOG2_EXT2_BLOCK_SIZE (data)),
525
 
                      EXT2_INODE_SIZE (data) * blkoff,
526
 
                      sizeof (struct grub_ext2_inode), inode))
527
 
    return grub_errno;
528
 
 
529
 
  return 0;
530
 
}
531
 
 
532
 
static struct grub_ext2_data *
533
 
grub_ext2_mount (grub_disk_t disk)
534
 
{
535
 
  struct grub_ext2_data *data;
536
 
 
537
 
  data = grub_malloc (sizeof (struct grub_ext2_data));
538
 
  if (!data)
539
 
    return 0;
540
 
 
541
 
  /* Read the superblock.  */
542
 
  grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock),
543
 
                  &data->sblock);
544
 
  if (grub_errno)
545
 
    goto fail;
546
 
 
547
 
  /* Make sure this is an ext2 filesystem.  */
548
 
  if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)
549
 
    {
550
 
      grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
551
 
      goto fail;
552
 
    }
553
 
 
554
 
  /* Check the FS doesn't have feature bits enabled that we don't support. */
555
 
  if (grub_le_to_cpu32 (data->sblock.feature_incompat)
556
 
        & ~(EXT2_DRIVER_SUPPORTED_INCOMPAT | EXT2_DRIVER_IGNORED_INCOMPAT))
557
 
    {
558
 
      grub_error (GRUB_ERR_BAD_FS, "filesystem has unsupported incompatible features");
559
 
      goto fail;
560
 
    }
561
 
 
562
 
 
563
 
  data->disk = disk;
564
 
 
565
 
  data->diropen.data = data;
566
 
  data->diropen.ino = 2;
567
 
  data->diropen.inode_read = 1;
568
 
 
569
 
  data->inode = &data->diropen.inode;
570
 
 
571
 
  grub_ext2_read_inode (data, 2, data->inode);
572
 
  if (grub_errno)
573
 
    goto fail;
574
 
 
575
 
  return data;
576
 
 
577
 
 fail:
578
 
  if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
579
 
    grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
580
 
 
581
 
  grub_free (data);
582
 
  return 0;
583
 
}
584
 
 
585
 
static char *
586
 
grub_ext2_read_symlink (grub_fshelp_node_t node)
587
 
{
588
 
  char *symlink;
589
 
  struct grub_fshelp_node *diro = node;
590
 
 
591
 
  if (! diro->inode_read)
592
 
    {
593
 
      grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
594
 
      if (grub_errno)
595
 
        return 0;
596
 
    }
597
 
 
598
 
  symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
599
 
  if (! symlink)
600
 
    return 0;
601
 
 
602
 
  /* If the filesize of the symlink is bigger than
603
 
     60 the symlink is stored in a separate block,
604
 
     otherwise it is stored in the inode.  */
605
 
  if (grub_le_to_cpu32 (diro->inode.size) <= 60)
606
 
    grub_strncpy (symlink,
607
 
                  diro->inode.symlink,
608
 
                  grub_le_to_cpu32 (diro->inode.size));
609
 
  else
610
 
    {
611
 
      grub_ext2_read_file (diro, 0, 0,
612
 
                           grub_le_to_cpu32 (diro->inode.size),
613
 
                           symlink);
614
 
      if (grub_errno)
615
 
        {
616
 
          grub_free (symlink);
617
 
          return 0;
618
 
        }
619
 
    }
620
 
 
621
 
  symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0';
622
 
  return symlink;
623
 
}
624
 
 
625
 
static int
626
 
grub_ext2_iterate_dir (grub_fshelp_node_t dir,
627
 
                       int NESTED_FUNC_ATTR
628
 
                       (*hook) (const char *filename,
629
 
                                enum grub_fshelp_filetype filetype,
630
 
                                grub_fshelp_node_t node))
631
 
{
632
 
  unsigned int fpos = 0;
633
 
  struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
634
 
 
635
 
  if (! diro->inode_read)
636
 
    {
637
 
      grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
638
 
      if (grub_errno)
639
 
        return 0;
640
 
    }
641
 
 
642
 
  /* Search the file.  */
643
 
  while (fpos < grub_le_to_cpu32 (diro->inode.size))
644
 
    {
645
 
      struct ext2_dirent dirent;
646
 
 
647
 
      grub_ext2_read_file (diro, 0, fpos, sizeof (struct ext2_dirent),
648
 
                           (char *) &dirent);
649
 
      if (grub_errno)
650
 
        return 0;
651
 
 
652
 
      if (dirent.direntlen == 0)
653
 
        return 0;
654
 
 
655
 
      if (dirent.namelen != 0)
656
 
        {
657
 
          char filename[dirent.namelen + 1];
658
 
          struct grub_fshelp_node *fdiro;
659
 
          enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
660
 
 
661
 
          grub_ext2_read_file (diro, 0, fpos + sizeof (struct ext2_dirent),
662
 
                               dirent.namelen, filename);
663
 
          if (grub_errno)
664
 
            return 0;
665
 
 
666
 
          fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
667
 
          if (! fdiro)
668
 
            return 0;
669
 
 
670
 
          fdiro->data = diro->data;
671
 
          fdiro->ino = grub_le_to_cpu32 (dirent.inode);
672
 
 
673
 
          filename[dirent.namelen] = '\0';
674
 
 
675
 
          if (dirent.filetype != FILETYPE_UNKNOWN)
676
 
            {
677
 
              fdiro->inode_read = 0;
678
 
 
679
 
              if (dirent.filetype == FILETYPE_DIRECTORY)
680
 
                type = GRUB_FSHELP_DIR;
681
 
              else if (dirent.filetype == FILETYPE_SYMLINK)
682
 
                type = GRUB_FSHELP_SYMLINK;
683
 
              else if (dirent.filetype == FILETYPE_REG)
684
 
                type = GRUB_FSHELP_REG;
685
 
            }
686
 
          else
687
 
            {
688
 
              /* The filetype can not be read from the dirent, read
689
 
                 the inode to get more information.  */
690
 
              grub_ext2_read_inode (diro->data,
691
 
                                    grub_le_to_cpu32 (dirent.inode),
692
 
                                    &fdiro->inode);
693
 
              if (grub_errno)
694
 
                {
695
 
                  grub_free (fdiro);
696
 
                  return 0;
697
 
                }
698
 
 
699
 
              fdiro->inode_read = 1;
700
 
 
701
 
              if ((grub_le_to_cpu16 (fdiro->inode.mode)
702
 
                   & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
703
 
                type = GRUB_FSHELP_DIR;
704
 
              else if ((grub_le_to_cpu16 (fdiro->inode.mode)
705
 
                        & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
706
 
                type = GRUB_FSHELP_SYMLINK;
707
 
              else if ((grub_le_to_cpu16 (fdiro->inode.mode)
708
 
                        & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
709
 
                type = GRUB_FSHELP_REG;
710
 
            }
711
 
 
712
 
          if (hook (filename, type, fdiro))
713
 
            return 1;
714
 
        }
715
 
 
716
 
      fpos += grub_le_to_cpu16 (dirent.direntlen);
717
 
    }
718
 
 
719
 
  return 0;
720
 
}
721
 
 
722
 
/* Open a file named NAME and initialize FILE.  */
723
 
static grub_err_t
724
 
grub_ext2_open (struct grub_file *file, const char *name)
725
 
{
726
 
  struct grub_ext2_data *data;
727
 
  struct grub_fshelp_node *fdiro = 0;
728
 
 
729
 
  grub_dl_ref (my_mod);
730
 
 
731
 
  data = grub_ext2_mount (file->device->disk);
732
 
  if (! data)
733
 
    goto fail;
734
 
 
735
 
  grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_ext2_iterate_dir,
736
 
                         grub_ext2_read_symlink, GRUB_FSHELP_REG);
737
 
  if (grub_errno)
738
 
    goto fail;
739
 
 
740
 
  if (! fdiro->inode_read)
741
 
    {
742
 
      grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode);
743
 
      if (grub_errno)
744
 
        goto fail;
745
 
    }
746
 
 
747
 
  grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
748
 
  grub_free (fdiro);
749
 
 
750
 
  file->size = grub_le_to_cpu32 (data->inode->size);
751
 
  file->data = data;
752
 
  file->offset = 0;
753
 
 
754
 
  return 0;
755
 
 
756
 
 fail:
757
 
  if (fdiro != &data->diropen)
758
 
    grub_free (fdiro);
759
 
  grub_free (data);
760
 
 
761
 
  grub_dl_unref (my_mod);
762
 
 
763
 
  return grub_errno;
764
 
}
765
 
 
766
 
static grub_err_t
767
 
grub_ext2_close (grub_file_t file)
768
 
{
769
 
  grub_free (file->data);
770
 
 
771
 
  grub_dl_unref (my_mod);
772
 
 
773
 
  return GRUB_ERR_NONE;
774
 
}
775
 
 
776
 
/* Read LEN bytes data from FILE into BUF.  */
777
 
static grub_ssize_t
778
 
grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
779
 
{
780
 
  struct grub_ext2_data *data = (struct grub_ext2_data *) file->data;
781
 
 
782
 
  return grub_ext2_read_file (&data->diropen, file->read_hook,
783
 
                              file->offset, len, buf);
784
 
}
785
 
 
786
 
 
787
 
static grub_err_t
788
 
grub_ext2_dir (grub_device_t device, const char *path,
789
 
               int (*hook) (const char *filename,
790
 
                            const struct grub_dirhook_info *info))
791
 
{
792
 
  struct grub_ext2_data *data = 0;
793
 
  struct grub_fshelp_node *fdiro = 0;
794
 
 
795
 
  auto int NESTED_FUNC_ATTR iterate (const char *filename,
796
 
                                     enum grub_fshelp_filetype filetype,
797
 
                                     grub_fshelp_node_t node);
798
 
 
799
 
  int NESTED_FUNC_ATTR iterate (const char *filename,
800
 
                                enum grub_fshelp_filetype filetype,
801
 
                                grub_fshelp_node_t node)
802
 
    {
803
 
      struct grub_dirhook_info info;
804
 
      grub_memset (&info, 0, sizeof (info));
805
 
      if (! node->inode_read)
806
 
        {
807
 
          grub_ext2_read_inode (data, node->ino, &node->inode);
808
 
          if (!grub_errno)
809
 
            node->inode_read = 1;
810
 
          grub_errno = GRUB_ERR_NONE;
811
 
        }
812
 
      if (node->inode_read)
813
 
        {
814
 
          info.mtimeset = 1;
815
 
          info.mtime = grub_le_to_cpu32 (node->inode.mtime);
816
 
        }
817
 
 
818
 
      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
819
 
      grub_free (node);
820
 
      return hook (filename, &info);
821
 
    }
822
 
 
823
 
  grub_dl_ref (my_mod);
824
 
 
825
 
  data = grub_ext2_mount (device->disk);
826
 
  if (! data)
827
 
    goto fail;
828
 
 
829
 
  grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir,
830
 
                         grub_ext2_read_symlink, GRUB_FSHELP_DIR);
831
 
  if (grub_errno)
832
 
    goto fail;
833
 
 
834
 
  grub_ext2_iterate_dir (fdiro, iterate);
835
 
 
836
 
 fail:
837
 
  if (fdiro != &data->diropen)
838
 
    grub_free (fdiro);
839
 
  grub_free (data);
840
 
 
841
 
  grub_dl_unref (my_mod);
842
 
 
843
 
  return grub_errno;
844
 
}
845
 
 
846
 
static grub_err_t
847
 
grub_ext2_label (grub_device_t device, char **label)
848
 
{
849
 
  struct grub_ext2_data *data;
850
 
  grub_disk_t disk = device->disk;
851
 
 
852
 
  grub_dl_ref (my_mod);
853
 
 
854
 
  data = grub_ext2_mount (disk);
855
 
  if (data)
856
 
    *label = grub_strndup (data->sblock.volume_name, 14);
857
 
  else
858
 
    *label = NULL;
859
 
 
860
 
  grub_dl_unref (my_mod);
861
 
 
862
 
  grub_free (data);
863
 
 
864
 
  return grub_errno;
865
 
}
866
 
 
867
 
static grub_err_t
868
 
grub_ext2_uuid (grub_device_t device, char **uuid)
869
 
{
870
 
  struct grub_ext2_data *data;
871
 
  grub_disk_t disk = device->disk;
872
 
 
873
 
  grub_dl_ref (my_mod);
874
 
 
875
 
  data = grub_ext2_mount (disk);
876
 
  if (data)
877
 
    {
878
 
      *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
879
 
                             grub_be_to_cpu16 (data->sblock.uuid[0]),
880
 
                             grub_be_to_cpu16 (data->sblock.uuid[1]),
881
 
                             grub_be_to_cpu16 (data->sblock.uuid[2]),
882
 
                             grub_be_to_cpu16 (data->sblock.uuid[3]),
883
 
                             grub_be_to_cpu16 (data->sblock.uuid[4]),
884
 
                             grub_be_to_cpu16 (data->sblock.uuid[5]),
885
 
                             grub_be_to_cpu16 (data->sblock.uuid[6]),
886
 
                             grub_be_to_cpu16 (data->sblock.uuid[7]));
887
 
    }
888
 
  else
889
 
    *uuid = NULL;
890
 
 
891
 
  grub_dl_unref (my_mod);
892
 
 
893
 
  grub_free (data);
894
 
 
895
 
  return grub_errno;
896
 
}
897
 
 
898
 
/* Get mtime.  */
899
 
static grub_err_t
900
 
grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
901
 
{
902
 
  struct grub_ext2_data *data;
903
 
  grub_disk_t disk = device->disk;
904
 
 
905
 
  grub_dl_ref (my_mod);
906
 
 
907
 
  data = grub_ext2_mount (disk);
908
 
  if (!data)
909
 
    *tm = 0;
910
 
  else
911
 
    *tm = grub_le_to_cpu32 (data->sblock.utime);
912
 
 
913
 
  grub_dl_unref (my_mod);
914
 
 
915
 
  grub_free (data);
916
 
 
917
 
  return grub_errno;
918
 
 
919
 
}
920
 
 
921
 
 
922
 
 
923
 
static struct grub_fs grub_ext2_fs =
924
 
  {
925
 
    .name = "ext2",
926
 
    .dir = grub_ext2_dir,
927
 
    .open = grub_ext2_open,
928
 
    .read = grub_ext2_read,
929
 
    .close = grub_ext2_close,
930
 
    .label = grub_ext2_label,
931
 
    .uuid = grub_ext2_uuid,
932
 
    .mtime = grub_ext2_mtime,
933
 
#ifdef GRUB_UTIL
934
 
    .reserved_first_sector = 1,
935
 
#endif
936
 
    .next = 0
937
 
  };
938
 
 
939
 
GRUB_MOD_INIT(ext2)
940
 
{
941
 
  grub_fs_register (&grub_ext2_fs);
942
 
  my_mod = mod;
943
 
}
944
 
 
945
 
GRUB_MOD_FINI(ext2)
946
 
{
947
 
  grub_fs_unregister (&grub_ext2_fs);
948
 
}