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

« back to all changes in this revision

Viewing changes to grub-core/fs/ufs.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
/* ufs.c - Unix File System */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 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
#include <grub/err.h>
 
21
#include <grub/file.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/misc.h>
 
24
#include <grub/disk.h>
 
25
#include <grub/dl.h>
 
26
#include <grub/types.h>
 
27
 
 
28
#ifdef MODE_UFS2
 
29
#define GRUB_UFS_MAGIC          0x19540119
 
30
#else
 
31
#define GRUB_UFS_MAGIC          0x11954
 
32
#endif
 
33
 
 
34
#define GRUB_UFS_INODE          2
 
35
#define GRUB_UFS_FILETYPE_DIR   4
 
36
#define GRUB_UFS_FILETYPE_LNK   10
 
37
#define GRUB_UFS_MAX_SYMLNK_CNT 8
 
38
 
 
39
#define GRUB_UFS_DIRBLKS        12
 
40
#define GRUB_UFS_INDIRBLKS      3
 
41
 
 
42
#define GRUB_UFS_ATTR_TYPE      0160000
 
43
#define GRUB_UFS_ATTR_FILE      0100000
 
44
#define GRUB_UFS_ATTR_DIR       0040000
 
45
#define GRUB_UFS_ATTR_LNK       0120000
 
46
 
 
47
#define GRUB_UFS_VOLNAME_LEN    32
 
48
 
 
49
/* Calculate in which group the inode can be found.  */
 
50
#define UFS_BLKSZ(sblock) (grub_le_to_cpu32 (sblock->bsize))
 
51
 
 
52
#define INODE(data,field) data->inode.  field
 
53
#ifdef MODE_UFS2
 
54
#define INODE_ENDIAN(data,field,bits1,bits2) grub_le_to_cpu##bits2 (data->inode.field)
 
55
#else
 
56
#define INODE_ENDIAN(data,field,bits1,bits2) grub_le_to_cpu##bits1 (data->inode.field)
 
57
#endif
 
58
 
 
59
#define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
 
60
#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
 
61
 
 
62
#define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
 
63
#ifdef MODE_UFS2
 
64
#define INODE_BLKSZ 8
 
65
#else
 
66
#define INODE_BLKSZ 4
 
67
#endif
 
68
#ifdef MODE_UFS2
 
69
#define UFS_INODE_PER_BLOCK 2
 
70
#else
 
71
#define UFS_INODE_PER_BLOCK 4
 
72
#endif
 
73
#define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
 
74
                                   (data,blocks.dir_blocks[blk],32,64)
 
75
#define INODE_INDIRBLOCKS(data,blk) INODE_ENDIAN \
 
76
                                     (data,blocks.indir_blocks[blk],32,64)
 
77
 
 
78
/* The blocks on which the superblock can be found.  */
 
79
static int sblocklist[] = { 128, 16, 0, 512, -1 };
 
80
 
 
81
struct grub_ufs_sblock
 
82
{
 
83
  grub_uint8_t unused[16];
 
84
  /* The offset of the inodes in the cylinder group.  */
 
85
  grub_uint32_t inoblk_offs;
 
86
 
 
87
  grub_uint8_t unused2[4];
 
88
 
 
89
  /* The start of the cylinder group.  */
 
90
  grub_uint32_t cylg_offset;
 
91
  grub_uint32_t cylg_mask;
 
92
 
 
93
  grub_uint32_t mtime;
 
94
  grub_uint8_t unused4[12];
 
95
 
 
96
  /* The size of a block in bytes.  */
 
97
  grub_int32_t bsize;
 
98
  grub_uint8_t unused5[48];
 
99
 
 
100
  /* The size of filesystem blocks to disk blocks.  */
 
101
  grub_uint32_t log2_blksz;
 
102
  grub_uint8_t unused6[40];
 
103
  grub_uint32_t uuidhi;
 
104
  grub_uint32_t uuidlow;
 
105
  grub_uint8_t unused7[32];
 
106
 
 
107
  /* Inodes stored per cylinder group.  */
 
108
  grub_uint32_t ino_per_group;
 
109
 
 
110
  /* The frags per cylinder group.  */
 
111
  grub_uint32_t frags_per_group;
 
112
 
 
113
  grub_uint8_t unused8[488];
 
114
 
 
115
  /* Volume name for UFS2.  */
 
116
  grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
 
117
  grub_uint8_t unused9[360];
 
118
 
 
119
  grub_uint64_t mtime2;
 
120
  grub_uint8_t unused10[292];
 
121
 
 
122
  /* Magic value to check if this is really a UFS filesystem.  */
 
123
  grub_uint32_t magic;
 
124
};
 
125
 
 
126
#ifdef MODE_UFS2
 
127
/* UFS inode.  */
 
128
struct grub_ufs_inode
 
129
{
 
130
  grub_uint16_t mode;
 
131
  grub_uint16_t nlinks;
 
132
  grub_uint32_t uid;
 
133
  grub_uint32_t gid;
 
134
  grub_uint32_t blocksize;
 
135
  grub_int64_t size;
 
136
  grub_int64_t nblocks;
 
137
  grub_uint64_t atime;
 
138
  grub_uint64_t mtime;
 
139
  grub_uint64_t ctime;
 
140
  grub_uint64_t create_time;
 
141
  grub_uint32_t atime_sec;
 
142
  grub_uint32_t mtime_sec;
 
143
  grub_uint32_t ctime_sec;
 
144
  grub_uint32_t create_time_sec;
 
145
  grub_uint32_t gen;
 
146
  grub_uint32_t kernel_flags;
 
147
  grub_uint32_t flags;
 
148
  grub_uint32_t extsz;
 
149
  grub_uint64_t ext[2];
 
150
  union
 
151
  {
 
152
    struct
 
153
    {
 
154
      grub_uint64_t dir_blocks[GRUB_UFS_DIRBLKS];
 
155
      grub_uint64_t indir_blocks[GRUB_UFS_INDIRBLKS];
 
156
    } blocks;
 
157
    grub_uint8_t symlink[(GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS) * 8];
 
158
  };
 
159
 
 
160
  grub_uint8_t unused[24];
 
161
} __attribute__ ((packed));
 
162
#else
 
163
/* UFS inode.  */
 
164
struct grub_ufs_inode
 
165
{
 
166
  grub_uint16_t mode;
 
167
  grub_uint16_t nlinks;
 
168
  grub_uint16_t uid;
 
169
  grub_uint16_t gid;
 
170
  grub_int64_t size;
 
171
  grub_uint64_t atime;
 
172
  grub_uint64_t mtime;
 
173
  grub_uint64_t ctime;
 
174
  union
 
175
  {
 
176
    struct
 
177
    {
 
178
      grub_uint32_t dir_blocks[GRUB_UFS_DIRBLKS];
 
179
      grub_uint32_t indir_blocks[GRUB_UFS_INDIRBLKS];
 
180
    } blocks;
 
181
    grub_uint8_t symlink[(GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS) * 4];
 
182
  };
 
183
  grub_uint32_t flags;
 
184
  grub_uint32_t nblocks;
 
185
  grub_uint32_t gen;
 
186
  grub_uint32_t unused;
 
187
  grub_uint8_t pad[12];
 
188
} __attribute__ ((packed));
 
189
#endif
 
190
 
 
191
/* Directory entry.  */
 
192
struct grub_ufs_dirent
 
193
{
 
194
  grub_uint32_t ino;
 
195
  grub_uint16_t direntlen;
 
196
  union
 
197
  {
 
198
    grub_uint16_t namelen;
 
199
    struct
 
200
    {
 
201
      grub_uint8_t filetype_bsd;
 
202
      grub_uint8_t namelen_bsd;
 
203
    };
 
204
  };
 
205
} __attribute__ ((packed));
 
206
 
 
207
/* Information about a "mounted" ufs filesystem.  */
 
208
struct grub_ufs_data
 
209
{
 
210
  struct grub_ufs_sblock sblock;
 
211
  grub_disk_t disk;
 
212
  struct grub_ufs_inode inode;
 
213
  int ino;
 
214
  int linknest;
 
215
};
 
216
 
 
217
static grub_dl_t my_mod;
 
218
 
 
219
/* Forward declaration.  */
 
220
static grub_err_t grub_ufs_find_file (struct grub_ufs_data *data,
 
221
                                      const char *path);
 
222
 
 
223
 
 
224
static grub_disk_addr_t
 
225
grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
 
226
{
 
227
  struct grub_ufs_sblock *sblock = &data->sblock;
 
228
  unsigned int indirsz;
 
229
  int log2_blksz;
 
230
 
 
231
  /* Direct.  */
 
232
  if (blk < GRUB_UFS_DIRBLKS)
 
233
    return INODE_DIRBLOCKS (data, blk);
 
234
 
 
235
  log2_blksz = grub_le_to_cpu32 (data->sblock.log2_blksz);
 
236
 
 
237
  blk -= GRUB_UFS_DIRBLKS;
 
238
 
 
239
  indirsz = UFS_BLKSZ (sblock) / INODE_BLKSZ;
 
240
  /* Single indirect block.  */
 
241
  if (blk < indirsz)
 
242
    {
 
243
#ifdef MODE_UFS2
 
244
      grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
 
245
#else
 
246
      grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
 
247
#endif
 
248
      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 0) << log2_blksz,
 
249
                      0, sizeof (indir), indir);
 
250
      return indir[blk];
 
251
    }
 
252
  blk -= indirsz;
 
253
 
 
254
  /* Double indirect block.  */
 
255
  if (blk < indirsz * indirsz)
 
256
    {
 
257
#ifdef MODE_UFS2
 
258
      grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
 
259
#else
 
260
      grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
 
261
#endif
 
262
 
 
263
      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
 
264
                      0, sizeof (indir), indir);
 
265
      grub_disk_read (data->disk,
 
266
                      (indir [blk / indirsz])
 
267
                      << log2_blksz,
 
268
                      0, sizeof (indir), indir);
 
269
 
 
270
      return indir[blk % indirsz];
 
271
    }
 
272
 
 
273
 
 
274
  grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
275
              "ufs does not support triple indirect blocks");
 
276
  return 0;
 
277
}
 
278
 
 
279
 
 
280
/* Read LEN bytes from the file described by DATA starting with byte
 
281
   POS.  Return the amount of read bytes in READ.  */
 
282
static grub_ssize_t
 
283
grub_ufs_read_file (struct grub_ufs_data *data,
 
284
                    void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
 
285
                                       unsigned offset, unsigned length),
 
286
                    int pos, grub_size_t len, char *buf)
 
287
{
 
288
  struct grub_ufs_sblock *sblock = &data->sblock;
 
289
  int i;
 
290
  int blockcnt;
 
291
 
 
292
  /* Adjust len so it we can't read past the end of the file.  */
 
293
  if (len + pos > INODE_SIZE (data))
 
294
    len = INODE_SIZE (data) - pos;
 
295
 
 
296
  blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) / UFS_BLKSZ (sblock);
 
297
 
 
298
  for (i = pos / UFS_BLKSZ (sblock); i < blockcnt; i++)
 
299
    {
 
300
      int blknr;
 
301
      int blockoff = pos % UFS_BLKSZ (sblock);
 
302
      int blockend = UFS_BLKSZ (sblock);
 
303
 
 
304
      int skipfirst = 0;
 
305
 
 
306
      blknr = grub_ufs_get_file_block (data, i);
 
307
      if (grub_errno)
 
308
        return -1;
 
309
 
 
310
      /* Last block.  */
 
311
      if (i == blockcnt - 1)
 
312
        {
 
313
          blockend = (len + pos) % UFS_BLKSZ (sblock);
 
314
 
 
315
          if (!blockend)
 
316
            blockend = UFS_BLKSZ (sblock);
 
317
        }
 
318
 
 
319
      /* First block.  */
 
320
      if (i == (pos / (int) UFS_BLKSZ (sblock)))
 
321
        {
 
322
          skipfirst = blockoff;
 
323
          blockend -= skipfirst;
 
324
        }
 
325
 
 
326
      /* XXX: If the block number is 0 this block is not stored on
 
327
         disk but is zero filled instead.  */
 
328
      if (blknr)
 
329
        {
 
330
          data->disk->read_hook = read_hook;
 
331
          grub_disk_read (data->disk,
 
332
                          blknr << grub_le_to_cpu32 (data->sblock.log2_blksz),
 
333
                          skipfirst, blockend, buf);
 
334
          data->disk->read_hook = 0;
 
335
          if (grub_errno)
 
336
            return -1;
 
337
        }
 
338
      else
 
339
        grub_memset (buf, UFS_BLKSZ (sblock) - skipfirst, 0);
 
340
 
 
341
      buf += UFS_BLKSZ (sblock) - skipfirst;
 
342
    }
 
343
 
 
344
  return len;
 
345
}
 
346
 
 
347
/* Read inode INO from the mounted filesystem described by DATA.  This
 
348
   inode is used by default now.  */
 
349
static grub_err_t
 
350
grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
 
351
{
 
352
  struct grub_ufs_sblock *sblock = &data->sblock;
 
353
 
 
354
  /* Determine the group the inode is in.  */
 
355
  int group = ino / grub_le_to_cpu32 (sblock->ino_per_group);
 
356
 
 
357
  /* Determine the inode within the group.  */
 
358
  int grpino = ino % grub_le_to_cpu32 (sblock->ino_per_group);
 
359
 
 
360
  /* The first block of the group.  */
 
361
  int grpblk = group * (grub_le_to_cpu32 (sblock->frags_per_group));
 
362
 
 
363
#ifndef MODE_UFS2
 
364
  grpblk += grub_le_to_cpu32 (sblock->cylg_offset)
 
365
    * (group & (~grub_le_to_cpu32 (sblock->cylg_mask)));
 
366
#endif
 
367
 
 
368
  if (!inode)
 
369
    {
 
370
      inode = (char *) &data->inode;
 
371
      data->ino = ino;
 
372
    }
 
373
 
 
374
  grub_disk_read (data->disk,
 
375
                  ((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 
376
                   << grub_le_to_cpu32 (data->sblock.log2_blksz))
 
377
                  + grpino / UFS_INODE_PER_BLOCK,
 
378
                  (grpino % UFS_INODE_PER_BLOCK)
 
379
                  * sizeof (struct grub_ufs_inode),
 
380
                  sizeof (struct grub_ufs_inode),
 
381
                  inode);
 
382
 
 
383
  return grub_errno;
 
384
}
 
385
 
 
386
 
 
387
/* Lookup the symlink the current inode points to.  INO is the inode
 
388
   number of the directory the symlink is relative to.  */
 
389
static grub_err_t
 
390
grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
 
391
{
 
392
  char symlink[INODE_SIZE (data)];
 
393
 
 
394
  if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
 
395
    return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
 
396
 
 
397
  if (INODE_NBLOCKS (data) == 0)
 
398
    grub_strcpy (symlink, (char *) INODE (data, symlink));
 
399
  else
 
400
    {
 
401
      grub_disk_read (data->disk,
 
402
                      (INODE_DIRBLOCKS (data, 0)
 
403
                       << grub_le_to_cpu32 (data->sblock.log2_blksz)),
 
404
                      0, INODE_SIZE (data), symlink);
 
405
      symlink[INODE_SIZE (data)] = '\0';
 
406
    }
 
407
 
 
408
  /* The symlink is an absolute path, go back to the root inode.  */
 
409
  if (symlink[0] == '/')
 
410
    ino = GRUB_UFS_INODE;
 
411
 
 
412
  /* Now load in the old inode.  */
 
413
  if (grub_ufs_read_inode (data, ino, 0))
 
414
    return grub_errno;
 
415
 
 
416
  grub_ufs_find_file (data, symlink);
 
417
  if (grub_errno)
 
418
    grub_error (grub_errno, "cannot follow symlink `%s'", symlink);
 
419
 
 
420
  return grub_errno;
 
421
}
 
422
 
 
423
 
 
424
/* Find the file with the pathname PATH on the filesystem described by
 
425
   DATA.  */
 
426
static grub_err_t
 
427
grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
 
428
{
 
429
  char fpath[grub_strlen (path) + 1];
 
430
  char *name = fpath;
 
431
  char *next;
 
432
  unsigned int pos = 0;
 
433
  int dirino;
 
434
 
 
435
  grub_strcpy (fpath, path);
 
436
 
 
437
  /* Skip the first slash.  */
 
438
  if (name[0] == '/')
 
439
    {
 
440
      name++;
 
441
      if (!*name)
 
442
        return 0;
 
443
    }
 
444
 
 
445
  /* Extract the actual part from the pathname.  */
 
446
  next = grub_strchr (name, '/');
 
447
  if (next)
 
448
    {
 
449
      next[0] = '\0';
 
450
      next++;
 
451
    }
 
452
 
 
453
  do
 
454
    {
 
455
      struct grub_ufs_dirent dirent;
 
456
      int namelen;
 
457
 
 
458
      if (grub_strlen (name) == 0)
 
459
        return GRUB_ERR_NONE;
 
460
 
 
461
      if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 
462
                              (char *) &dirent) < 0)
 
463
        return grub_errno;
 
464
 
 
465
#ifdef MODE_UFS2
 
466
      namelen = dirent.namelen_bsd;
 
467
#else
 
468
      namelen = grub_le_to_cpu16 (dirent.namelen);
 
469
#endif
 
470
      {
 
471
        char filename[namelen + 1];
 
472
 
 
473
        if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
 
474
                                namelen, filename) < 0)
 
475
          return grub_errno;
 
476
 
 
477
        filename[namelen] = '\0';
 
478
 
 
479
        if (!grub_strcmp (name, filename))
 
480
          {
 
481
            dirino = data->ino;
 
482
            grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino), 0);
 
483
 
 
484
            if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
 
485
                == GRUB_UFS_ATTR_LNK)
 
486
              {
 
487
                grub_ufs_lookup_symlink (data, dirino);
 
488
                if (grub_errno)
 
489
                  return grub_errno;
 
490
              }
 
491
 
 
492
            if (!next)
 
493
              return 0;
 
494
 
 
495
            pos = 0;
 
496
 
 
497
            name = next;
 
498
            next = grub_strchr (name, '/');
 
499
            if (next)
 
500
              {
 
501
                next[0] = '\0';
 
502
                next++;
 
503
              }
 
504
 
 
505
            if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 
506
              return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 
507
 
 
508
            continue;
 
509
          }
 
510
      }
 
511
 
 
512
      pos += grub_le_to_cpu16 (dirent.direntlen);
 
513
    } while (pos < INODE_SIZE (data));
 
514
 
 
515
  grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
 
516
  return grub_errno;
 
517
}
 
518
 
 
519
 
 
520
/* Mount the filesystem on the disk DISK.  */
 
521
static struct grub_ufs_data *
 
522
grub_ufs_mount (grub_disk_t disk)
 
523
{
 
524
  struct grub_ufs_data *data;
 
525
  int *sblklist = sblocklist;
 
526
 
 
527
  data = grub_malloc (sizeof (struct grub_ufs_data));
 
528
  if (!data)
 
529
    return 0;
 
530
 
 
531
  /* Find a UFS sblock.  */
 
532
  while (*sblklist != -1)
 
533
    {
 
534
      grub_disk_read (disk, *sblklist, 0, sizeof (struct grub_ufs_sblock),
 
535
                      &data->sblock);
 
536
      if (grub_errno)
 
537
        goto fail;
 
538
 
 
539
      if (grub_le_to_cpu32 (data->sblock.magic) == GRUB_UFS_MAGIC)
 
540
        {
 
541
          data->disk = disk;
 
542
          data->linknest = 0;
 
543
          return data;
 
544
        }
 
545
      sblklist++;
 
546
    }
 
547
 
 
548
 fail:
 
549
 
 
550
  if (grub_errno == GRUB_ERR_NONE || grub_errno == GRUB_ERR_OUT_OF_RANGE)
 
551
    {
 
552
#ifdef MODE_UFS2
 
553
      grub_error (GRUB_ERR_BAD_FS, "not an ufs2 filesystem");
 
554
#else
 
555
      grub_error (GRUB_ERR_BAD_FS, "not an ufs1 filesystem");
 
556
#endif
 
557
    }
 
558
 
 
559
  grub_free (data);
 
560
 
 
561
  return 0;
 
562
}
 
563
 
 
564
 
 
565
static grub_err_t
 
566
grub_ufs_dir (grub_device_t device, const char *path,
 
567
               int (*hook) (const char *filename,
 
568
                            const struct grub_dirhook_info *info))
 
569
{
 
570
  struct grub_ufs_data *data;
 
571
  unsigned int pos = 0;
 
572
 
 
573
  data = grub_ufs_mount (device->disk);
 
574
  if (!data)
 
575
    return grub_errno;
 
576
 
 
577
  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
 
578
  if (grub_errno)
 
579
    return grub_errno;
 
580
 
 
581
  if (!path || path[0] != '/')
 
582
    {
 
583
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
 
584
      return grub_errno;
 
585
    }
 
586
 
 
587
  grub_ufs_find_file (data, path);
 
588
  if (grub_errno)
 
589
    goto fail;
 
590
 
 
591
  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 
592
    {
 
593
      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 
594
      goto fail;
 
595
    }
 
596
 
 
597
  while (pos < INODE_SIZE (data))
 
598
    {
 
599
      struct grub_ufs_dirent dirent;
 
600
      int namelen;
 
601
 
 
602
      if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 
603
                              (char *) &dirent) < 0)
 
604
        break;
 
605
 
 
606
#ifdef MODE_UFS2
 
607
      namelen = dirent.namelen_bsd;
 
608
#else
 
609
      namelen = grub_le_to_cpu16 (dirent.namelen);
 
610
#endif
 
611
 
 
612
      {
 
613
        char filename[namelen + 1];
 
614
        struct grub_dirhook_info info;
 
615
        struct grub_ufs_inode inode;
 
616
 
 
617
        grub_memset (&info, 0, sizeof (info));
 
618
 
 
619
        if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
 
620
                                namelen, filename) < 0)
 
621
          break;
 
622
 
 
623
        filename[namelen] = '\0';
 
624
        grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
 
625
 
 
626
        info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
 
627
                    == GRUB_UFS_ATTR_DIR);
 
628
        info.mtime = grub_le_to_cpu64 (inode.mtime);
 
629
        info.mtimeset = 1;
 
630
 
 
631
        if (hook (filename, &info))
 
632
          break;
 
633
      }
 
634
 
 
635
      pos += grub_le_to_cpu16 (dirent.direntlen);
 
636
    }
 
637
 
 
638
 fail:
 
639
  grub_free (data);
 
640
 
 
641
  return grub_errno;
 
642
}
 
643
 
 
644
 
 
645
/* Open a file named NAME and initialize FILE.  */
 
646
static grub_err_t
 
647
grub_ufs_open (struct grub_file *file, const char *name)
 
648
{
 
649
  struct grub_ufs_data *data;
 
650
  data = grub_ufs_mount (file->device->disk);
 
651
  if (!data)
 
652
    return grub_errno;
 
653
 
 
654
  grub_ufs_read_inode (data, 2, 0);
 
655
  if (grub_errno)
 
656
    {
 
657
      grub_free (data);
 
658
      return grub_errno;
 
659
    }
 
660
 
 
661
  if (!name || name[0] != '/')
 
662
    {
 
663
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
 
664
      return grub_errno;
 
665
    }
 
666
 
 
667
  grub_ufs_find_file (data, name);
 
668
  if (grub_errno)
 
669
    {
 
670
      grub_free (data);
 
671
      return grub_errno;
 
672
    }
 
673
 
 
674
  file->data = data;
 
675
  file->size = INODE_SIZE (data);
 
676
 
 
677
  return GRUB_ERR_NONE;
 
678
}
 
679
 
 
680
 
 
681
static grub_ssize_t
 
682
grub_ufs_read (grub_file_t file, char *buf, grub_size_t len)
 
683
{
 
684
  struct grub_ufs_data *data =
 
685
    (struct grub_ufs_data *) file->data;
 
686
 
 
687
  return grub_ufs_read_file (data, file->read_hook, file->offset, len, buf);
 
688
}
 
689
 
 
690
 
 
691
static grub_err_t
 
692
grub_ufs_close (grub_file_t file)
 
693
{
 
694
  grub_free (file->data);
 
695
 
 
696
  return GRUB_ERR_NONE;
 
697
}
 
698
 
 
699
 
 
700
#ifdef MODE_UFS2
 
701
static grub_err_t
 
702
grub_ufs_label (grub_device_t device, char **label)
 
703
{
 
704
  struct grub_ufs_data *data = 0;
 
705
 
 
706
  grub_dl_ref (my_mod);
 
707
 
 
708
  *label = 0;
 
709
 
 
710
  data = grub_ufs_mount (device->disk);
 
711
  if (data)
 
712
    *label = grub_strdup ((char *) data->sblock.volume_name);
 
713
 
 
714
  grub_dl_unref (my_mod);
 
715
 
 
716
  grub_free (data);
 
717
 
 
718
  return grub_errno;
 
719
}
 
720
#endif
 
721
 
 
722
static grub_err_t
 
723
grub_ufs_uuid (grub_device_t device, char **uuid)
 
724
{
 
725
  struct grub_ufs_data *data;
 
726
  grub_disk_t disk = device->disk;
 
727
 
 
728
  grub_dl_ref (my_mod);
 
729
 
 
730
  data = grub_ufs_mount (disk);
 
731
  if (data && (data->sblock.uuidhi != 0 || data->sblock.uuidlow != 0))
 
732
    *uuid = grub_xasprintf ("%08x%08x",
 
733
                           (unsigned) grub_le_to_cpu32 (data->sblock.uuidhi),
 
734
                           (unsigned) grub_le_to_cpu32 (data->sblock.uuidlow));
 
735
  else
 
736
    *uuid = NULL;
 
737
 
 
738
  grub_dl_unref (my_mod);
 
739
 
 
740
  grub_free (data);
 
741
 
 
742
  return grub_errno;
 
743
}
 
744
 
 
745
 
 
746
/* Get mtime.  */
 
747
static grub_err_t
 
748
grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
 
749
{
 
750
  struct grub_ufs_data *data = 0;
 
751
 
 
752
  grub_dl_ref (my_mod);
 
753
 
 
754
  data = grub_ufs_mount (device->disk);
 
755
  if (!data)
 
756
    *tm = 0;
 
757
  else
 
758
#ifdef MODE_UFS2
 
759
    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
 
760
#else
 
761
    *tm = grub_le_to_cpu32 (data->sblock.mtime);
 
762
#endif
 
763
 
 
764
  grub_dl_unref (my_mod);
 
765
 
 
766
  grub_free (data);
 
767
 
 
768
  return grub_errno;
 
769
}
 
770
 
 
771
 
 
772
 
 
773
static struct grub_fs grub_ufs_fs =
 
774
  {
 
775
#ifdef MODE_UFS2
 
776
    .name = "ufs2",
 
777
#else
 
778
    .name = "ufs1",
 
779
#endif
 
780
    .dir = grub_ufs_dir,
 
781
    .open = grub_ufs_open,
 
782
    .read = grub_ufs_read,
 
783
    .close = grub_ufs_close,
 
784
#ifdef MODE_UFS2
 
785
    .label = grub_ufs_label,
 
786
#endif
 
787
    .uuid = grub_ufs_uuid,
 
788
    .mtime = grub_ufs_mtime,
 
789
    .next = 0
 
790
  };
 
791
 
 
792
#ifdef MODE_UFS2
 
793
GRUB_MOD_INIT(ufs2)
 
794
#else
 
795
GRUB_MOD_INIT(ufs1)
 
796
#endif
 
797
{
 
798
  grub_fs_register (&grub_ufs_fs);
 
799
  my_mod = mod;
 
800
}
 
801
 
 
802
#ifdef MODE_UFS2
 
803
GRUB_MOD_FINI(ufs2)
 
804
#else
 
805
GRUB_MOD_FINI(ufs1)
 
806
#endif
 
807
{
 
808
  grub_fs_unregister (&grub_ufs_fs);
 
809
}
 
810