~ilya-yanok/ubuntu/precise/grub2/fix-for-948716

« back to all changes in this revision

Viewing changes to fs/ufs.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2009-07-25 19:00:53 UTC
  • mfrom: (1.6.3 upstream)
  • mto: (17.4.13 sid)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: james.westby@ubuntu.com-20090725190053-uv3lm6ya3zxs77ep
ImportĀ upstreamĀ versionĀ 1.96+20090725

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <grub/dl.h>
26
26
#include <grub/types.h>
27
27
 
28
 
#ifdef MODE_UFS2
29
 
#define GRUB_UFS_MAGIC          0x19540119
30
 
#else
 
28
 
31
29
#define GRUB_UFS_MAGIC          0x11954
32
 
#endif
33
 
 
 
30
#define GRUB_UFS2_MAGIC         0x19540119
34
31
#define GRUB_UFS_INODE          2
35
32
#define GRUB_UFS_FILETYPE_DIR   4
36
33
#define GRUB_UFS_FILETYPE_LNK   10
47
44
#define GRUB_UFS_VOLNAME_LEN    32
48
45
 
49
46
/* Calculate in which group the inode can be found.  */
 
47
#define inode_group(inode,sblock) ()
 
48
 
50
49
#define UFS_BLKSZ(sblock) (grub_le_to_cpu32 (sblock->bsize))
51
50
 
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
 
 
 
51
#define INODE(data,field) (data->ufs_type == UFS1 ? \
 
52
                           data->inode.  field : data->inode2.  field)
 
53
#define INODE_ENDIAN(data,field,bits1,bits2) (data->ufs_type == UFS1 ? \
 
54
                           grub_le_to_cpu##bits1 (data->inode.field) : \
 
55
                           grub_le_to_cpu##bits2 (data->inode2.field))
59
56
#define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
60
57
#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
61
58
 
62
59
#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
 
60
#define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
73
61
#define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
74
62
                                   (data,blocks.dir_blocks[blk],32,64)
75
63
#define INODE_INDIRBLOCKS(data,blk) INODE_ENDIAN \
88
76
 
89
77
  /* The start of the cylinder group.  */
90
78
  grub_uint32_t cylg_offset;
91
 
  grub_uint32_t cylg_mask;
 
79
  grub_uint8_t unused3[4];
92
80
 
93
81
  grub_uint32_t mtime;
94
82
  grub_uint8_t unused4[12];
123
111
  grub_uint32_t magic;
124
112
};
125
113
 
126
 
#ifdef MODE_UFS2
127
114
/* UFS inode.  */
128
115
struct grub_ufs_inode
129
116
{
130
117
  grub_uint16_t mode;
131
118
  grub_uint16_t nlinks;
 
119
  grub_uint16_t uid;
 
120
  grub_uint16_t gid;
 
121
  grub_int64_t size;
 
122
  grub_uint64_t atime;
 
123
  grub_uint64_t mtime;
 
124
  grub_uint64_t ctime;
 
125
  union
 
126
  {
 
127
    struct
 
128
    {
 
129
      grub_uint32_t dir_blocks[GRUB_UFS_DIRBLKS];
 
130
      grub_uint32_t indir_blocks[GRUB_UFS_INDIRBLKS];
 
131
    } blocks;
 
132
    grub_uint8_t symlink[(GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS) * 4];
 
133
  };
 
134
  grub_uint32_t flags;
 
135
  grub_uint32_t nblocks;
 
136
  grub_uint32_t gen;
 
137
  grub_uint32_t unused;
 
138
  grub_uint8_t pad[12];
 
139
} __attribute__ ((packed));
 
140
 
 
141
/* UFS inode.  */
 
142
struct grub_ufs2_inode
 
143
{
 
144
  grub_uint16_t mode;
 
145
  grub_uint16_t nlinks;
132
146
  grub_uint32_t uid;
133
147
  grub_uint32_t gid;
134
148
  grub_uint32_t blocksize;
159
173
 
160
174
  grub_uint8_t unused[24];
161
175
} __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
176
 
191
177
/* Directory entry.  */
192
178
struct grub_ufs_dirent
209
195
{
210
196
  struct grub_ufs_sblock sblock;
211
197
  grub_disk_t disk;
212
 
  struct grub_ufs_inode inode;
 
198
  union
 
199
  {
 
200
    struct grub_ufs_inode inode;
 
201
    struct grub_ufs2_inode inode2;
 
202
  };
 
203
  enum
 
204
    {
 
205
      UFS1,
 
206
      UFS2,
 
207
      UNKNOWN
 
208
    } ufs_type;
213
209
  int ino;
214
210
  int linknest;
215
211
};
221
217
                                      const char *path);
222
218
 
223
219
 
224
 
static grub_disk_addr_t
 
220
static int
225
221
grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
226
222
{
227
223
  struct grub_ufs_sblock *sblock = &data->sblock;
236
232
 
237
233
  blk -= GRUB_UFS_DIRBLKS;
238
234
 
239
 
  indirsz = UFS_BLKSZ (sblock) / INODE_BLKSZ;
 
235
  indirsz = UFS_BLKSZ (sblock) / INODE_BLKSZ (data);
240
236
  /* Single indirect block.  */
241
237
  if (blk < indirsz)
242
238
    {
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
 
239
      grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
248
240
      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 0) << log2_blksz,
249
241
                      0, sizeof (indir), indir);
250
 
      return indir[blk];
 
242
      return (data->ufs_type == UFS1) ? indir[blk] : indir[blk << 1];
251
243
    }
252
244
  blk -= indirsz;
253
245
 
254
246
  /* Double indirect block.  */
255
247
  if (blk < indirsz * indirsz)
256
248
    {
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
 
249
      grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
262
250
 
263
251
      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
264
252
                      0, sizeof (indir), indir);
265
253
      grub_disk_read (data->disk,
266
 
                      (indir [blk / indirsz])
 
254
                      ((data->ufs_type == UFS1) ?
 
255
                      indir[blk / indirsz] : indir [(blk / indirsz) << 1])
267
256
                      << log2_blksz,
268
257
                      0, sizeof (indir), indir);
269
258
 
270
 
      return indir[blk % indirsz];
 
259
      return (data->ufs_type == UFS1) ?
 
260
             indir[blk % indirsz] : indir[(blk % indirsz) << 1];
271
261
    }
272
262
 
273
263
 
290
280
  int blockcnt;
291
281
 
292
282
  /* 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;
 
283
  if (len > INODE_SIZE (data))
 
284
    len = INODE_SIZE (data);
295
285
 
296
286
  blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) / UFS_BLKSZ (sblock);
297
287
 
344
334
  return len;
345
335
}
346
336
 
 
337
 
347
338
/* Read inode INO from the mounted filesystem described by DATA.  This
348
339
   inode is used by default now.  */
349
340
static grub_err_t
360
351
  /* The first block of the group.  */
361
352
  int grpblk = group * (grub_le_to_cpu32 (sblock->frags_per_group));
362
353
 
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);
 
354
  if (data->ufs_type == UFS1)
 
355
    {
 
356
      if (!inode)
 
357
        {
 
358
          inode = (char *) &data->inode;
 
359
          data->ino = ino;
 
360
        }
 
361
 
 
362
      grub_disk_read (data->disk,
 
363
                      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 
364
                        << grub_le_to_cpu32 (data->sblock.log2_blksz)))
 
365
                      + grpino / 4,
 
366
                      (grpino % 4) * sizeof (struct grub_ufs_inode),
 
367
                      sizeof (struct grub_ufs_inode),
 
368
                      inode);
 
369
    }
 
370
  else
 
371
    {
 
372
      if (!inode)
 
373
        {
 
374
          inode = (char *) &data->inode2;
 
375
          data->ino = ino;
 
376
        }
 
377
 
 
378
      grub_disk_read (data->disk,
 
379
                      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 
380
                        << grub_le_to_cpu32 (data->sblock.log2_blksz)))
 
381
                      + grpino / 2,
 
382
                      (grpino % 2) * sizeof (struct grub_ufs2_inode),
 
383
                      sizeof (struct grub_ufs2_inode),
 
384
                      inode);
 
385
    }
382
386
 
383
387
  return grub_errno;
384
388
}
462
466
                              (char *) &dirent) < 0)
463
467
        return grub_errno;
464
468
 
465
 
#ifdef MODE_UFS2
466
 
      namelen = dirent.namelen_bsd;
467
 
#else
468
 
      namelen = grub_le_to_cpu16 (dirent.namelen);
469
 
#endif
 
469
      namelen = (data->ufs_type == UFS2)
 
470
        ? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
 
471
 
470
472
      {
471
473
        char filename[namelen + 1];
472
474
 
528
530
  if (!data)
529
531
    return 0;
530
532
 
531
 
  /* Find a UFS sblock.  */
 
533
  /* Find a UFS1 or UFS2 sblock.  */
 
534
  data->ufs_type = UNKNOWN;
532
535
  while (*sblklist != -1)
533
536
    {
534
537
      grub_disk_read (disk, *sblklist, 0, sizeof (struct grub_ufs_sblock),
538
541
 
539
542
      if (grub_le_to_cpu32 (data->sblock.magic) == GRUB_UFS_MAGIC)
540
543
        {
541
 
          data->disk = disk;
542
 
          data->linknest = 0;
543
 
          return data;
 
544
          data->ufs_type = UFS1;
 
545
          break;
 
546
        }
 
547
      else if (grub_le_to_cpu32 (data->sblock.magic) == GRUB_UFS2_MAGIC)
 
548
        {
 
549
          data->ufs_type = UFS2;
 
550
          break;
544
551
        }
545
552
      sblklist++;
546
553
    }
 
554
  if (data->ufs_type == UNKNOWN)
 
555
    {
 
556
      grub_error (GRUB_ERR_BAD_FS, "not an ufs filesystem");
 
557
      goto fail;
 
558
    }
 
559
 
 
560
  data->disk = disk;
 
561
  data->linknest = 0;
 
562
  return data;
547
563
 
548
564
 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
565
  grub_free (data);
560
566
 
 
567
  if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
 
568
    grub_error (GRUB_ERR_BAD_FS, "not a ufs filesystem");
 
569
 
561
570
  return 0;
562
571
}
563
572
 
606
615
                              (char *) &dirent) < 0)
607
616
        break;
608
617
 
609
 
#ifdef MODE_UFS2
610
 
      namelen = dirent.namelen_bsd;
611
 
#else
612
 
      namelen = grub_le_to_cpu16 (dirent.namelen);
613
 
#endif
 
618
      namelen = (data->ufs_type == UFS2)
 
619
        ? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
614
620
 
615
621
      {
616
622
        char filename[namelen + 1];
617
623
        struct grub_dirhook_info info;
618
 
        struct grub_ufs_inode inode;
619
 
 
620
624
        grub_memset (&info, 0, sizeof (info));
621
625
 
622
626
        if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
624
628
          break;
625
629
 
626
630
        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;
 
631
        if (data->ufs_type == UFS1)
 
632
          {
 
633
            struct grub_ufs_inode inode;
 
634
            grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
 
635
            info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
 
636
                        == GRUB_UFS_ATTR_DIR);
 
637
            info.mtime = grub_le_to_cpu64 (inode.mtime);
 
638
            info.mtimeset = 1;
 
639
          }
 
640
        else
 
641
          {
 
642
            struct grub_ufs2_inode inode;
 
643
            grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
 
644
            info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
 
645
                        == GRUB_UFS_ATTR_DIR);
 
646
            info.mtime = grub_le_to_cpu64 (inode.mtime);
 
647
            info.mtimeset = 1;
 
648
          }
633
649
 
634
650
        if (hook (filename, &info))
635
651
          break;
700
716
}
701
717
 
702
718
 
703
 
#ifdef MODE_UFS2
704
719
static grub_err_t
705
720
grub_ufs_label (grub_device_t device, char **label)
706
721
{
712
727
 
713
728
  data = grub_ufs_mount (device->disk);
714
729
  if (data)
715
 
    *label = grub_strdup ((char *) data->sblock.volume_name);
 
730
    {
 
731
      if (data->ufs_type == UFS2)
 
732
        *label = grub_strdup ((char *) data->sblock.volume_name);
 
733
    }
716
734
 
717
735
  grub_dl_unref (my_mod);
718
736
 
720
738
 
721
739
  return grub_errno;
722
740
}
723
 
#endif
724
741
 
725
742
static grub_err_t
726
743
grub_ufs_uuid (grub_device_t device, char **uuid)
731
748
  grub_dl_ref (my_mod);
732
749
 
733
750
  data = grub_ufs_mount (disk);
734
 
  if (data && (data->sblock.uuidhi != 0 || data->sblock.uuidlow != 0))
 
751
  if (data)
735
752
    {
736
753
      *uuid = grub_malloc (16 + sizeof ('\0'));
737
754
      grub_sprintf (*uuid, "%08x%08x",
760
777
  data = grub_ufs_mount (device->disk);
761
778
  if (!data)
762
779
    *tm = 0;
 
780
  else if (data->ufs_type == UFS1)
 
781
    *tm = grub_le_to_cpu32 (data->sblock.mtime);
763
782
  else
764
 
#ifdef MODE_UFS2
765
783
    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
766
 
#else
767
 
    *tm = grub_le_to_cpu32 (data->sblock.mtime);
768
 
#endif
769
784
 
770
785
  grub_dl_unref (my_mod);
771
786
 
778
793
 
779
794
static struct grub_fs grub_ufs_fs =
780
795
  {
781
 
#ifdef MODE_UFS2
782
 
    .name = "ufs2",
783
 
#else
784
 
    .name = "ufs1",
785
 
#endif
 
796
    .name = "ufs",
786
797
    .dir = grub_ufs_dir,
787
798
    .open = grub_ufs_open,
788
799
    .read = grub_ufs_read,
789
800
    .close = grub_ufs_close,
790
 
#ifdef MODE_UFS2
791
801
    .label = grub_ufs_label,
792
 
#endif
793
802
    .uuid = grub_ufs_uuid,
794
803
    .mtime = grub_ufs_mtime,
795
804
    .next = 0
796
805
  };
797
806
 
798
 
#ifdef MODE_UFS2
799
 
GRUB_MOD_INIT(ufs2)
800
 
#else
801
 
GRUB_MOD_INIT(ufs1)
802
 
#endif
 
807
GRUB_MOD_INIT(ufs)
803
808
{
804
809
  grub_fs_register (&grub_ufs_fs);
805
810
  my_mod = mod;
806
811
}
807
812
 
808
 
#ifdef MODE_UFS2
809
 
GRUB_MOD_FINI(ufs2)
810
 
#else
811
 
GRUB_MOD_FINI(ufs1)
812
 
#endif
 
813
GRUB_MOD_FINI(ufs)
813
814
{
814
815
  grub_fs_unregister (&grub_ufs_fs);
815
816
}