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

« back to all changes in this revision

Viewing changes to fs/ufs.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
 
/* 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
 
  struct grub_ufs_sblock *sblock;
572
 
  unsigned int pos = 0;
573
 
 
574
 
  data = grub_ufs_mount (device->disk);
575
 
  if (!data)
576
 
    return grub_errno;
577
 
 
578
 
  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
579
 
  if (grub_errno)
580
 
    return grub_errno;
581
 
 
582
 
  sblock = &data->sblock;
583
 
 
584
 
  if (!path || path[0] != '/')
585
 
    {
586
 
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
587
 
      return grub_errno;
588
 
    }
589
 
 
590
 
  grub_ufs_find_file (data, path);
591
 
  if (grub_errno)
592
 
    goto fail;
593
 
 
594
 
  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
595
 
    {
596
 
      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
597
 
      goto fail;
598
 
    }
599
 
 
600
 
  while (pos < INODE_SIZE (data))
601
 
    {
602
 
      struct grub_ufs_dirent dirent;
603
 
      int namelen;
604
 
 
605
 
      if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
606
 
                              (char *) &dirent) < 0)
607
 
        break;
608
 
 
609
 
#ifdef MODE_UFS2
610
 
      namelen = dirent.namelen_bsd;
611
 
#else
612
 
      namelen = grub_le_to_cpu16 (dirent.namelen);
613
 
#endif
614
 
 
615
 
      {
616
 
        char filename[namelen + 1];
617
 
        struct grub_dirhook_info info;
618
 
        struct grub_ufs_inode inode;
619
 
 
620
 
        grub_memset (&info, 0, sizeof (info));
621
 
 
622
 
        if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
623
 
                                namelen, filename) < 0)
624
 
          break;
625
 
 
626
 
        filename[namelen] = '\0';
627
 
        grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
628
 
 
629
 
        info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
630
 
                    == GRUB_UFS_ATTR_DIR);
631
 
        info.mtime = grub_le_to_cpu64 (inode.mtime);
632
 
        info.mtimeset = 1;
633
 
 
634
 
        if (hook (filename, &info))
635
 
          break;
636
 
      }
637
 
 
638
 
      pos += grub_le_to_cpu16 (dirent.direntlen);
639
 
    }
640
 
 
641
 
 fail:
642
 
  grub_free (data);
643
 
 
644
 
  return grub_errno;
645
 
}
646
 
 
647
 
 
648
 
/* Open a file named NAME and initialize FILE.  */
649
 
static grub_err_t
650
 
grub_ufs_open (struct grub_file *file, const char *name)
651
 
{
652
 
  struct grub_ufs_data *data;
653
 
  data = grub_ufs_mount (file->device->disk);
654
 
  if (!data)
655
 
    return grub_errno;
656
 
 
657
 
  grub_ufs_read_inode (data, 2, 0);
658
 
  if (grub_errno)
659
 
    {
660
 
      grub_free (data);
661
 
      return grub_errno;
662
 
    }
663
 
 
664
 
  if (!name || name[0] != '/')
665
 
    {
666
 
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
667
 
      return grub_errno;
668
 
    }
669
 
 
670
 
  grub_ufs_find_file (data, name);
671
 
  if (grub_errno)
672
 
    {
673
 
      grub_free (data);
674
 
      return grub_errno;
675
 
    }
676
 
 
677
 
  file->data = data;
678
 
  file->size = INODE_SIZE (data);
679
 
 
680
 
  return GRUB_ERR_NONE;
681
 
}
682
 
 
683
 
 
684
 
static grub_ssize_t
685
 
grub_ufs_read (grub_file_t file, char *buf, grub_size_t len)
686
 
{
687
 
  struct grub_ufs_data *data =
688
 
    (struct grub_ufs_data *) file->data;
689
 
 
690
 
  return grub_ufs_read_file (data, file->read_hook, file->offset, len, buf);
691
 
}
692
 
 
693
 
 
694
 
static grub_err_t
695
 
grub_ufs_close (grub_file_t file)
696
 
{
697
 
  grub_free (file->data);
698
 
 
699
 
  return GRUB_ERR_NONE;
700
 
}
701
 
 
702
 
 
703
 
#ifdef MODE_UFS2
704
 
static grub_err_t
705
 
grub_ufs_label (grub_device_t device, char **label)
706
 
{
707
 
  struct grub_ufs_data *data = 0;
708
 
 
709
 
  grub_dl_ref (my_mod);
710
 
 
711
 
  *label = 0;
712
 
 
713
 
  data = grub_ufs_mount (device->disk);
714
 
  if (data)
715
 
    *label = grub_strdup ((char *) data->sblock.volume_name);
716
 
 
717
 
  grub_dl_unref (my_mod);
718
 
 
719
 
  grub_free (data);
720
 
 
721
 
  return grub_errno;
722
 
}
723
 
#endif
724
 
 
725
 
static grub_err_t
726
 
grub_ufs_uuid (grub_device_t device, char **uuid)
727
 
{
728
 
  struct grub_ufs_data *data;
729
 
  grub_disk_t disk = device->disk;
730
 
 
731
 
  grub_dl_ref (my_mod);
732
 
 
733
 
  data = grub_ufs_mount (disk);
734
 
  if (data && (data->sblock.uuidhi != 0 || data->sblock.uuidlow != 0))
735
 
    *uuid = grub_xasprintf ("%08x%08x",
736
 
                           (unsigned) grub_le_to_cpu32 (data->sblock.uuidhi),
737
 
                           (unsigned) grub_le_to_cpu32 (data->sblock.uuidlow));
738
 
  else
739
 
    *uuid = NULL;
740
 
 
741
 
  grub_dl_unref (my_mod);
742
 
 
743
 
  grub_free (data);
744
 
 
745
 
  return grub_errno;
746
 
}
747
 
 
748
 
 
749
 
/* Get mtime.  */
750
 
static grub_err_t
751
 
grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
752
 
{
753
 
  struct grub_ufs_data *data = 0;
754
 
 
755
 
  grub_dl_ref (my_mod);
756
 
 
757
 
  data = grub_ufs_mount (device->disk);
758
 
  if (!data)
759
 
    *tm = 0;
760
 
  else
761
 
#ifdef MODE_UFS2
762
 
    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
763
 
#else
764
 
    *tm = grub_le_to_cpu32 (data->sblock.mtime);
765
 
#endif
766
 
 
767
 
  grub_dl_unref (my_mod);
768
 
 
769
 
  grub_free (data);
770
 
 
771
 
  return grub_errno;
772
 
}
773
 
 
774
 
 
775
 
 
776
 
static struct grub_fs grub_ufs_fs =
777
 
  {
778
 
#ifdef MODE_UFS2
779
 
    .name = "ufs2",
780
 
#else
781
 
    .name = "ufs1",
782
 
#endif
783
 
    .dir = grub_ufs_dir,
784
 
    .open = grub_ufs_open,
785
 
    .read = grub_ufs_read,
786
 
    .close = grub_ufs_close,
787
 
#ifdef MODE_UFS2
788
 
    .label = grub_ufs_label,
789
 
#endif
790
 
    .uuid = grub_ufs_uuid,
791
 
    .mtime = grub_ufs_mtime,
792
 
    .next = 0
793
 
  };
794
 
 
795
 
#ifdef MODE_UFS2
796
 
GRUB_MOD_INIT(ufs2)
797
 
#else
798
 
GRUB_MOD_INIT(ufs1)
799
 
#endif
800
 
{
801
 
  grub_fs_register (&grub_ufs_fs);
802
 
  my_mod = mod;
803
 
}
804
 
 
805
 
#ifdef MODE_UFS2
806
 
GRUB_MOD_FINI(ufs2)
807
 
#else
808
 
GRUB_MOD_FINI(ufs1)
809
 
#endif
810
 
{
811
 
  grub_fs_unregister (&grub_ufs_fs);
812
 
}
813