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

« back to all changes in this revision

Viewing changes to fs/iso9660.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
 
/* iso9660.c - iso9660 implementation with extensions:
2
 
   SUSP, Rock Ridge.  */
3
 
/*
4
 
 *  GRUB  --  GRand Unified Bootloader
5
 
 *  Copyright (C) 2004,2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
6
 
 *
7
 
 *  GRUB is free software: you can redistribute it and/or modify
8
 
 *  it under the terms of the GNU General Public License as published by
9
 
 *  the Free Software Foundation, either version 3 of the License, or
10
 
 *  (at your option) any later version.
11
 
 *
12
 
 *  GRUB is distributed in the hope that it will be useful,
13
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 *  GNU General Public License for more details.
16
 
 *
17
 
 *  You should have received a copy of the GNU General Public License
18
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
19
 
 */
20
 
 
21
 
#include <grub/err.h>
22
 
#include <grub/file.h>
23
 
#include <grub/mm.h>
24
 
#include <grub/misc.h>
25
 
#include <grub/disk.h>
26
 
#include <grub/dl.h>
27
 
#include <grub/types.h>
28
 
#include <grub/fshelp.h>
29
 
#include <grub/charset.h>
30
 
 
31
 
#define GRUB_ISO9660_FSTYPE_DIR         0040000
32
 
#define GRUB_ISO9660_FSTYPE_REG         0100000
33
 
#define GRUB_ISO9660_FSTYPE_SYMLINK     0120000
34
 
#define GRUB_ISO9660_FSTYPE_MASK        0170000
35
 
 
36
 
#define GRUB_ISO9660_LOG2_BLKSZ         2
37
 
#define GRUB_ISO9660_BLKSZ              2048
38
 
 
39
 
#define GRUB_ISO9660_RR_DOT             2
40
 
#define GRUB_ISO9660_RR_DOTDOT          4
41
 
 
42
 
#define GRUB_ISO9660_VOLDESC_BOOT       0
43
 
#define GRUB_ISO9660_VOLDESC_PRIMARY    1
44
 
#define GRUB_ISO9660_VOLDESC_SUPP       2
45
 
#define GRUB_ISO9660_VOLDESC_PART       3
46
 
#define GRUB_ISO9660_VOLDESC_END        255
47
 
 
48
 
/* The head of a volume descriptor.  */
49
 
struct grub_iso9660_voldesc
50
 
{
51
 
  grub_uint8_t type;
52
 
  grub_uint8_t magic[5];
53
 
  grub_uint8_t version;
54
 
} __attribute__ ((packed));
55
 
 
56
 
/* A directory entry.  */
57
 
struct grub_iso9660_dir
58
 
{
59
 
  grub_uint8_t len;
60
 
  grub_uint8_t ext_sectors;
61
 
  grub_uint32_t first_sector;
62
 
  grub_uint32_t first_sector_be;
63
 
  grub_uint32_t size;
64
 
  grub_uint32_t size_be;
65
 
  grub_uint8_t unused1[7];
66
 
  grub_uint8_t flags;
67
 
  grub_uint8_t unused2[6];
68
 
  grub_uint8_t namelen;
69
 
} __attribute__ ((packed));
70
 
 
71
 
struct grub_iso9660_date
72
 
{
73
 
  grub_uint8_t year[4];
74
 
  grub_uint8_t month[2];
75
 
  grub_uint8_t day[2];
76
 
  grub_uint8_t hour[2];
77
 
  grub_uint8_t minute[2];
78
 
  grub_uint8_t second[2];
79
 
  grub_uint8_t hundredth[2];
80
 
  grub_uint8_t offset;
81
 
} __attribute__ ((packed));
82
 
 
83
 
/* The primary volume descriptor.  Only little endian is used.  */
84
 
struct grub_iso9660_primary_voldesc
85
 
{
86
 
  struct grub_iso9660_voldesc voldesc;
87
 
  grub_uint8_t unused1[33];
88
 
  grub_uint8_t volname[32];
89
 
  grub_uint8_t unused2[16];
90
 
  grub_uint8_t escape[32];
91
 
  grub_uint8_t unused3[12];
92
 
  grub_uint32_t path_table_size;
93
 
  grub_uint8_t unused4[4];
94
 
  grub_uint32_t path_table;
95
 
  grub_uint8_t unused5[12];
96
 
  struct grub_iso9660_dir rootdir;
97
 
  grub_uint8_t unused6[624];
98
 
  struct grub_iso9660_date created;
99
 
  struct grub_iso9660_date modified;
100
 
} __attribute__ ((packed));
101
 
 
102
 
/* A single entry in the path table.  */
103
 
struct grub_iso9660_path
104
 
{
105
 
  grub_uint8_t len;
106
 
  grub_uint8_t sectors;
107
 
  grub_uint32_t first_sector;
108
 
  grub_uint16_t parentdir;
109
 
  grub_uint8_t name[0];
110
 
} __attribute__ ((packed));
111
 
 
112
 
/* An entry in the System Usage area of the directory entry.  */
113
 
struct grub_iso9660_susp_entry
114
 
{
115
 
  grub_uint8_t sig[2];
116
 
  grub_uint8_t len;
117
 
  grub_uint8_t version;
118
 
  grub_uint8_t data[0];
119
 
} __attribute__ ((packed));
120
 
 
121
 
/* The CE entry.  This is used to describe the next block where data
122
 
   can be found.  */
123
 
struct grub_iso9660_susp_ce
124
 
{
125
 
  struct grub_iso9660_susp_entry entry;
126
 
  grub_uint32_t blk;
127
 
  grub_uint32_t blk_be;
128
 
  grub_uint32_t off;
129
 
  grub_uint32_t off_be;
130
 
  grub_uint32_t len;
131
 
  grub_uint32_t len_be;
132
 
} __attribute__ ((packed));
133
 
 
134
 
struct grub_iso9660_data
135
 
{
136
 
  struct grub_iso9660_primary_voldesc voldesc;
137
 
  grub_disk_t disk;
138
 
  unsigned int first_sector;
139
 
  unsigned int length;
140
 
  int rockridge;
141
 
  int susp_skip;
142
 
  int joliet;
143
 
};
144
 
 
145
 
struct grub_fshelp_node
146
 
{
147
 
  struct grub_iso9660_data *data;
148
 
  unsigned int size;
149
 
  unsigned int blk;
150
 
  unsigned int dir_blk;
151
 
  unsigned int dir_off;
152
 
};
153
 
 
154
 
static grub_dl_t my_mod;
155
 
 
156
 
 
157
 
/* Iterate over the susp entries, starting with block SUA_BLOCK on the
158
 
   offset SUA_POS with a size of SUA_SIZE bytes.  Hook is called for
159
 
   every entry.  */
160
 
static grub_err_t
161
 
grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
162
 
                           int sua_block, int sua_pos, int sua_size,
163
 
                           grub_err_t (*hook)
164
 
                           (struct grub_iso9660_susp_entry *entry))
165
 
{
166
 
  char *sua;
167
 
  struct grub_iso9660_susp_entry *entry;
168
 
 
169
 
  auto grub_err_t load_sua (void);
170
 
 
171
 
  /* Load a part of the System Usage Area.  */
172
 
  grub_err_t load_sua (void)
173
 
    {
174
 
      sua = grub_malloc (sua_size);
175
 
      if (!sua)
176
 
        return grub_errno;
177
 
 
178
 
      if (grub_disk_read (data->disk, sua_block, sua_pos,
179
 
                          sua_size, sua))
180
 
        return grub_errno;
181
 
 
182
 
      entry = (struct grub_iso9660_susp_entry *) sua;
183
 
      return 0;
184
 
    }
185
 
 
186
 
  if (load_sua ())
187
 
    return grub_errno;
188
 
 
189
 
  for (; (char *) entry < (char *) sua + sua_size - 1;
190
 
       entry = (struct grub_iso9660_susp_entry *)
191
 
         ((char *) entry + entry->len))
192
 
    {
193
 
      /* The last entry.  */
194
 
      if (grub_strncmp ((char *) entry->sig, "ST", 2) == 0)
195
 
        break;
196
 
 
197
 
      /* Additional entries are stored elsewhere.  */
198
 
      if (grub_strncmp ((char *) entry->sig, "CE", 2) == 0)
199
 
        {
200
 
          struct grub_iso9660_susp_ce *ce;
201
 
 
202
 
          ce = (struct grub_iso9660_susp_ce *) entry;
203
 
          sua_size = grub_le_to_cpu32 (ce->len);
204
 
          sua_pos = grub_le_to_cpu32 (ce->off);
205
 
          sua_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
206
 
 
207
 
          grub_free (sua);
208
 
          if (load_sua ())
209
 
            return grub_errno;
210
 
        }
211
 
 
212
 
      if (hook (entry))
213
 
        {
214
 
          grub_free (sua);
215
 
          return 0;
216
 
        }
217
 
    }
218
 
 
219
 
  grub_free (sua);
220
 
  return 0;
221
 
}
222
 
 
223
 
static char *
224
 
grub_iso9660_convert_string (grub_uint16_t *us, int len)
225
 
{
226
 
  char *p;
227
 
  int i;
228
 
 
229
 
  p = grub_malloc (len * 4 + 1);
230
 
  if (! p)
231
 
    return p;
232
 
 
233
 
  for (i=0; i<len; i++)
234
 
    us[i] = grub_be_to_cpu16 (us[i]);
235
 
 
236
 
  *grub_utf16_to_utf8 ((grub_uint8_t *) p, us, len) = '\0';
237
 
 
238
 
  return p;
239
 
}
240
 
 
241
 
static struct grub_iso9660_data *
242
 
grub_iso9660_mount (grub_disk_t disk)
243
 
{
244
 
  struct grub_iso9660_data *data = 0;
245
 
  struct grub_iso9660_dir rootdir;
246
 
  int sua_pos;
247
 
  int sua_size;
248
 
  char *sua;
249
 
  struct grub_iso9660_susp_entry *entry;
250
 
  struct grub_iso9660_primary_voldesc voldesc;
251
 
  int block;
252
 
 
253
 
  auto grub_err_t susp_iterate (struct grub_iso9660_susp_entry *);
254
 
 
255
 
  grub_err_t susp_iterate (struct grub_iso9660_susp_entry *susp_entry)
256
 
    {
257
 
      /* The "ER" entry is used to detect extensions.  The
258
 
         `IEEE_P1285' extension means Rock ridge.  */
259
 
      if (grub_strncmp ((char *) susp_entry->sig, "ER", 2) == 0)
260
 
        {
261
 
          data->rockridge = 1;
262
 
          return 1;
263
 
        }
264
 
      return 0;
265
 
    }
266
 
 
267
 
  data = grub_zalloc (sizeof (struct grub_iso9660_data));
268
 
  if (! data)
269
 
    return 0;
270
 
 
271
 
  data->disk = disk;
272
 
 
273
 
  block = 16;
274
 
  do
275
 
    {
276
 
      int copy_voldesc = 0;
277
 
 
278
 
      /* Read the superblock.  */
279
 
      if (grub_disk_read (disk, block << GRUB_ISO9660_LOG2_BLKSZ, 0,
280
 
                          sizeof (struct grub_iso9660_primary_voldesc),
281
 
                          (char *) &voldesc))
282
 
        {
283
 
          grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
284
 
          goto fail;
285
 
        }
286
 
 
287
 
      if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0)
288
 
        {
289
 
          grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
290
 
          goto fail;
291
 
        }
292
 
 
293
 
      if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY)
294
 
        copy_voldesc = 1;
295
 
      else if ((voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP) &&
296
 
               (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f) &&
297
 
               ((voldesc.escape[2] == 0x40) ||  /* UCS-2 Level 1.  */
298
 
                (voldesc.escape[2] == 0x43) ||  /* UCS-2 Level 2.  */
299
 
                (voldesc.escape[2] == 0x45)))   /* UCS-2 Level 3.  */
300
 
        {
301
 
          copy_voldesc = 1;
302
 
          data->joliet = 1;
303
 
        }
304
 
 
305
 
      if (copy_voldesc)
306
 
        grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
307
 
                    sizeof (struct grub_iso9660_primary_voldesc));
308
 
 
309
 
      block++;
310
 
    } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END);
311
 
 
312
 
  /* Read the system use area and test it to see if SUSP is
313
 
     supported.  */
314
 
  if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
315
 
                             << GRUB_ISO9660_LOG2_BLKSZ), 0,
316
 
                      sizeof (rootdir), (char *) &rootdir))
317
 
    {
318
 
      grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
319
 
      goto fail;
320
 
    }
321
 
 
322
 
  sua_pos = (sizeof (rootdir) + rootdir.namelen
323
 
             + (rootdir.namelen % 2) - 1);
324
 
  sua_size = rootdir.len - sua_pos;
325
 
 
326
 
  sua = grub_malloc (sua_size);
327
 
  if (! sua)
328
 
    goto fail;
329
 
 
330
 
  if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
331
 
                             << GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
332
 
                      sua_size, sua))
333
 
    {
334
 
      grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
335
 
      goto fail;
336
 
    }
337
 
 
338
 
  entry = (struct grub_iso9660_susp_entry *) sua;
339
 
 
340
 
  /* Test if the SUSP protocol is used on this filesystem.  */
341
 
  if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
342
 
    {
343
 
      /* The 2nd data byte stored how many bytes are skipped every time
344
 
         to get to the SUA (System Usage Area).  */
345
 
      data->susp_skip = entry->data[2];
346
 
      entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
347
 
 
348
 
      /* Iterate over the entries in the SUA area to detect
349
 
         extensions.  */
350
 
      if (grub_iso9660_susp_iterate (data,
351
 
                                     (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
352
 
                                      << GRUB_ISO9660_LOG2_BLKSZ),
353
 
                                     sua_pos, sua_size, susp_iterate))
354
 
        goto fail;
355
 
    }
356
 
 
357
 
  return data;
358
 
 
359
 
 fail:
360
 
  grub_free (data);
361
 
  return 0;
362
 
}
363
 
 
364
 
 
365
 
static char *
366
 
grub_iso9660_read_symlink (grub_fshelp_node_t node)
367
 
{
368
 
  struct grub_iso9660_dir dirent;
369
 
  int sua_off;
370
 
  int sua_size;
371
 
  char *symlink = 0;
372
 
  int addslash = 0;
373
 
 
374
 
  auto void add_part (const char *part, int len);
375
 
  auto grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *);
376
 
 
377
 
  /* Extend the symlink.  */
378
 
  void add_part (const char *part, int len)
379
 
    {
380
 
      int size = grub_strlen (symlink);
381
 
 
382
 
      symlink = grub_realloc (symlink, size + len + 1);
383
 
      if (! symlink)
384
 
        return;
385
 
 
386
 
      grub_strncat (symlink, part, len);
387
 
    }
388
 
 
389
 
  /* Read in a symlink.  */
390
 
  grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *entry)
391
 
    {
392
 
      if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
393
 
        {
394
 
          unsigned int pos = 1;
395
 
 
396
 
          /* The symlink is not stored as a POSIX symlink, translate it.  */
397
 
          while (pos < grub_le_to_cpu32 (entry->len))
398
 
            {
399
 
              if (addslash)
400
 
                {
401
 
                  add_part ("/", 1);
402
 
                  addslash = 0;
403
 
                }
404
 
 
405
 
              /* The current position is the `Component Flag'.  */
406
 
              switch (entry->data[pos] & 30)
407
 
                {
408
 
                case 0:
409
 
                  {
410
 
                    /* The data on pos + 2 is the actual data, pos + 1
411
 
                       is the length.  Both are part of the `Component
412
 
                       Record'.  */
413
 
                    add_part ((char *) &entry->data[pos + 2],
414
 
                              entry->data[pos + 1]);
415
 
                    if ((entry->data[pos] & 1))
416
 
                      addslash = 1;
417
 
 
418
 
                    break;
419
 
                  }
420
 
 
421
 
                case 2:
422
 
                  add_part ("./", 2);
423
 
                  break;
424
 
 
425
 
                case 4:
426
 
                  add_part ("../", 3);
427
 
                  break;
428
 
 
429
 
                case 8:
430
 
                  add_part ("/", 1);
431
 
                  break;
432
 
                }
433
 
              /* In pos + 1 the length of the `Component Record' is
434
 
                 stored.  */
435
 
              pos += entry->data[pos + 1] + 2;
436
 
            }
437
 
 
438
 
          /* Check if `grub_realloc' failed.  */
439
 
          if (grub_errno)
440
 
            return grub_errno;
441
 
        }
442
 
 
443
 
      return 0;
444
 
    }
445
 
 
446
 
  if (grub_disk_read (node->data->disk, node->dir_blk, node->dir_off,
447
 
                      sizeof (dirent), (char *) &dirent))
448
 
    return 0;
449
 
 
450
 
  sua_off = (sizeof (dirent) + dirent.namelen + 1 - (dirent.namelen % 2)
451
 
             + node->data->susp_skip);
452
 
  sua_size = dirent.len - sua_off;
453
 
 
454
 
  symlink = grub_malloc (1);
455
 
  if (!symlink)
456
 
    return 0;
457
 
 
458
 
  *symlink = '\0';
459
 
 
460
 
  if (grub_iso9660_susp_iterate (node->data, node->dir_blk,
461
 
                                 node->dir_off + sua_off,
462
 
                                 sua_size, susp_iterate_sl))
463
 
    {
464
 
      grub_free (symlink);
465
 
      return 0;
466
 
    }
467
 
 
468
 
  return symlink;
469
 
}
470
 
 
471
 
 
472
 
static int
473
 
grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
474
 
                          int NESTED_FUNC_ATTR
475
 
                          (*hook) (const char *filename,
476
 
                                   enum grub_fshelp_filetype filetype,
477
 
                                   grub_fshelp_node_t node))
478
 
{
479
 
  struct grub_iso9660_dir dirent;
480
 
  unsigned int offset = 0;
481
 
  char *filename;
482
 
  int filename_alloc = 0;
483
 
  enum grub_fshelp_filetype type;
484
 
 
485
 
  auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *);
486
 
 
487
 
  grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *entry)
488
 
    {
489
 
      /* The filename in the rock ridge entry.  */
490
 
      if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
491
 
        {
492
 
          /* The flags are stored at the data position 0, here the
493
 
             filename type is stored.  */
494
 
          if (entry->data[0] & GRUB_ISO9660_RR_DOT)
495
 
            filename = ".";
496
 
          else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT)
497
 
            filename = "..";
498
 
          else
499
 
            {
500
 
              int size = 1;
501
 
              if (filename)
502
 
                {
503
 
                  size += grub_strlen (filename);
504
 
                  grub_realloc (filename,
505
 
                                grub_strlen (filename)
506
 
                                + entry->len);
507
 
                }
508
 
              else
509
 
                {
510
 
                  size = entry->len - 5;
511
 
                  filename = grub_zalloc (size + 1);
512
 
                }
513
 
              filename_alloc = 1;
514
 
              grub_strncpy (filename, (char *) &entry->data[1], size);
515
 
              filename[size] = '\0';
516
 
            }
517
 
        }
518
 
      /* The mode information (st_mode).  */
519
 
      else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
520
 
        {
521
 
          /* At position 0 of the PX record the st_mode information is
522
 
             stored (little-endian).  */
523
 
          grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8))
524
 
                                & GRUB_ISO9660_FSTYPE_MASK);
525
 
 
526
 
          switch (mode)
527
 
            {
528
 
            case GRUB_ISO9660_FSTYPE_DIR:
529
 
              type = GRUB_FSHELP_DIR;
530
 
              break;
531
 
            case GRUB_ISO9660_FSTYPE_REG:
532
 
              type = GRUB_FSHELP_REG;
533
 
              break;
534
 
            case GRUB_ISO9660_FSTYPE_SYMLINK:
535
 
              type = GRUB_FSHELP_SYMLINK;
536
 
              break;
537
 
            default:
538
 
              type = GRUB_FSHELP_UNKNOWN;
539
 
            }
540
 
        }
541
 
 
542
 
      return 0;
543
 
    }
544
 
 
545
 
  while (offset < dir->size)
546
 
    {
547
 
      if (grub_disk_read (dir->data->disk,
548
 
                          (dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
549
 
                          + offset / GRUB_DISK_SECTOR_SIZE,
550
 
                          offset % GRUB_DISK_SECTOR_SIZE,
551
 
                          sizeof (dirent), (char *) &dirent))
552
 
        return 0;
553
 
 
554
 
      /* The end of the block, skip to the next one.  */
555
 
      if (!dirent.len)
556
 
        {
557
 
          offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ;
558
 
          continue;
559
 
        }
560
 
 
561
 
      {
562
 
        char name[dirent.namelen + 1];
563
 
        int nameoffset = offset + sizeof (dirent);
564
 
        struct grub_fshelp_node *node;
565
 
        int sua_off = (sizeof (dirent) + dirent.namelen + 1
566
 
                       - (dirent.namelen % 2));
567
 
        int sua_size = dirent.len - sua_off;
568
 
 
569
 
        sua_off += offset + dir->data->susp_skip;
570
 
 
571
 
        filename = 0;
572
 
        filename_alloc = 0;
573
 
        type = GRUB_FSHELP_UNKNOWN;
574
 
 
575
 
        if (dir->data->rockridge
576
 
            && grub_iso9660_susp_iterate (dir->data,
577
 
                                          (dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
578
 
                                          + (sua_off
579
 
                                             / GRUB_DISK_SECTOR_SIZE),
580
 
                                          sua_off % GRUB_DISK_SECTOR_SIZE,
581
 
                                          sua_size, susp_iterate_dir))
582
 
          return 0;
583
 
 
584
 
        /* Read the name.  */
585
 
        if (grub_disk_read (dir->data->disk,
586
 
                            (dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
587
 
                            + nameoffset / GRUB_DISK_SECTOR_SIZE,
588
 
                            nameoffset % GRUB_DISK_SECTOR_SIZE,
589
 
                            dirent.namelen, (char *) name))
590
 
          return 0;
591
 
 
592
 
        node = grub_malloc (sizeof (struct grub_fshelp_node));
593
 
        if (!node)
594
 
          return 0;
595
 
 
596
 
        /* Setup a new node.  */
597
 
        node->data = dir->data;
598
 
        node->size = grub_le_to_cpu32 (dirent.size);
599
 
        node->blk = grub_le_to_cpu32 (dirent.first_sector);
600
 
        node->dir_blk = ((dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
601
 
                         + offset / GRUB_DISK_SECTOR_SIZE);
602
 
        node->dir_off = offset % GRUB_DISK_SECTOR_SIZE;
603
 
 
604
 
        /* If the filetype was not stored using rockridge, use
605
 
           whatever is stored in the iso9660 filesystem.  */
606
 
        if (type == GRUB_FSHELP_UNKNOWN)
607
 
          {
608
 
            if ((dirent.flags & 3) == 2)
609
 
              type = GRUB_FSHELP_DIR;
610
 
            else
611
 
              type = GRUB_FSHELP_REG;
612
 
          }
613
 
 
614
 
        /* The filename was not stored in a rock ridge entry.  Read it
615
 
           from the iso9660 filesystem.  */
616
 
        if (!filename)
617
 
          {
618
 
            name[dirent.namelen] = '\0';
619
 
            filename = grub_strrchr (name, ';');
620
 
            if (filename)
621
 
              *filename = '\0';
622
 
 
623
 
            if (dirent.namelen == 1 && name[0] == 0)
624
 
              filename = ".";
625
 
            else if (dirent.namelen == 1 && name[0] == 1)
626
 
              filename = "..";
627
 
            else
628
 
              filename = name;
629
 
          }
630
 
 
631
 
        if (dir->data->joliet)
632
 
          {
633
 
            char *oldname;
634
 
 
635
 
            oldname = filename;
636
 
            filename = grub_iso9660_convert_string
637
 
                  ((grub_uint16_t *) oldname, dirent.namelen >> 1);
638
 
 
639
 
            if (filename_alloc)
640
 
              grub_free (oldname);
641
 
 
642
 
            filename_alloc = 1;
643
 
          }
644
 
 
645
 
        if (hook (filename, type, node))
646
 
          {
647
 
            if (filename_alloc)
648
 
              grub_free (filename);
649
 
            return 1;
650
 
          }
651
 
        if (filename_alloc)
652
 
          grub_free (filename);
653
 
      }
654
 
 
655
 
      offset += dirent.len;
656
 
    }
657
 
 
658
 
  return 0;
659
 
}
660
 
 
661
 
 
662
 
 
663
 
static grub_err_t
664
 
grub_iso9660_dir (grub_device_t device, const char *path,
665
 
                  int (*hook) (const char *filename,
666
 
                               const struct grub_dirhook_info *info))
667
 
{
668
 
  struct grub_iso9660_data *data = 0;
669
 
  struct grub_fshelp_node rootnode;
670
 
  struct grub_fshelp_node *foundnode;
671
 
 
672
 
  auto int NESTED_FUNC_ATTR iterate (const char *filename,
673
 
                                     enum grub_fshelp_filetype filetype,
674
 
                                     grub_fshelp_node_t node);
675
 
 
676
 
  int NESTED_FUNC_ATTR iterate (const char *filename,
677
 
                                enum grub_fshelp_filetype filetype,
678
 
                                grub_fshelp_node_t node)
679
 
    {
680
 
      struct grub_dirhook_info info;
681
 
      grub_memset (&info, 0, sizeof (info));
682
 
      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
683
 
      grub_free (node);
684
 
      return hook (filename, &info);
685
 
    }
686
 
 
687
 
  grub_dl_ref (my_mod);
688
 
 
689
 
  data = grub_iso9660_mount (device->disk);
690
 
  if (! data)
691
 
    goto fail;
692
 
 
693
 
  rootnode.data = data;
694
 
  rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
695
 
  rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
696
 
 
697
 
  /* Use the fshelp function to traverse the path.  */
698
 
  if (grub_fshelp_find_file (path, &rootnode,
699
 
                             &foundnode,
700
 
                             grub_iso9660_iterate_dir,
701
 
                             grub_iso9660_read_symlink,
702
 
                             GRUB_FSHELP_DIR))
703
 
    goto fail;
704
 
 
705
 
  /* List the files in the directory.  */
706
 
  grub_iso9660_iterate_dir (foundnode, iterate);
707
 
 
708
 
  if (foundnode != &rootnode)
709
 
    grub_free (foundnode);
710
 
 
711
 
 fail:
712
 
  grub_free (data);
713
 
 
714
 
  grub_dl_unref (my_mod);
715
 
 
716
 
  return grub_errno;
717
 
}
718
 
 
719
 
 
720
 
/* Open a file named NAME and initialize FILE.  */
721
 
static grub_err_t
722
 
grub_iso9660_open (struct grub_file *file, const char *name)
723
 
{
724
 
  struct grub_iso9660_data *data;
725
 
  struct grub_fshelp_node rootnode;
726
 
  struct grub_fshelp_node *foundnode;
727
 
 
728
 
  grub_dl_ref (my_mod);
729
 
 
730
 
  data = grub_iso9660_mount (file->device->disk);
731
 
  if (!data)
732
 
    goto fail;
733
 
 
734
 
  rootnode.data = data;
735
 
  rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
736
 
  rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
737
 
 
738
 
  /* Use the fshelp function to traverse the path.  */
739
 
  if (grub_fshelp_find_file (name, &rootnode,
740
 
                             &foundnode,
741
 
                             grub_iso9660_iterate_dir,
742
 
                             grub_iso9660_read_symlink,
743
 
                             GRUB_FSHELP_REG))
744
 
    goto fail;
745
 
 
746
 
  data->first_sector = foundnode->blk;
747
 
  data->length = foundnode->size;
748
 
 
749
 
  file->data = data;
750
 
  file->size = foundnode->size;
751
 
  file->offset = 0;
752
 
 
753
 
  return 0;
754
 
 
755
 
 fail:
756
 
  grub_dl_unref (my_mod);
757
 
 
758
 
  grub_free (data);
759
 
 
760
 
  return grub_errno;
761
 
}
762
 
 
763
 
 
764
 
static grub_ssize_t
765
 
grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
766
 
{
767
 
  struct grub_iso9660_data *data =
768
 
    (struct grub_iso9660_data *) file->data;
769
 
 
770
 
  /* XXX: The file is stored in as a single extent.  */
771
 
  data->disk->read_hook = file->read_hook;
772
 
  grub_disk_read (data->disk,
773
 
                  data->first_sector << GRUB_ISO9660_LOG2_BLKSZ,
774
 
                  file->offset,
775
 
                  len, buf);
776
 
  data->disk->read_hook = NULL;
777
 
 
778
 
  if (grub_errno)
779
 
    return -1;
780
 
 
781
 
  return len;
782
 
}
783
 
 
784
 
 
785
 
static grub_err_t
786
 
grub_iso9660_close (grub_file_t file)
787
 
{
788
 
  grub_free (file->data);
789
 
 
790
 
  grub_dl_unref (my_mod);
791
 
 
792
 
  return GRUB_ERR_NONE;
793
 
}
794
 
 
795
 
 
796
 
static grub_err_t
797
 
grub_iso9660_label (grub_device_t device, char **label)
798
 
{
799
 
  struct grub_iso9660_data *data;
800
 
  data = grub_iso9660_mount (device->disk);
801
 
 
802
 
  if (data)
803
 
    {
804
 
      if (data->joliet)
805
 
        *label = grub_iso9660_convert_string
806
 
                 ((grub_uint16_t *) &data->voldesc.volname, 16);
807
 
      else
808
 
        *label = grub_strndup ((char *) data->voldesc.volname, 32);
809
 
      grub_free (data);
810
 
    }
811
 
  else
812
 
    *label = 0;
813
 
 
814
 
  return grub_errno;
815
 
}
816
 
 
817
 
 
818
 
static grub_err_t
819
 
grub_iso9660_uuid (grub_device_t device, char **uuid)
820
 
{
821
 
  struct grub_iso9660_data *data;
822
 
  grub_disk_t disk = device->disk;
823
 
 
824
 
  grub_dl_ref (my_mod);
825
 
 
826
 
  data = grub_iso9660_mount (disk);
827
 
  if (data)
828
 
    {
829
 
      if (! data->voldesc.modified.year[0] && ! data->voldesc.modified.year[1]
830
 
          && ! data->voldesc.modified.year[2] && ! data->voldesc.modified.year[3]
831
 
          && ! data->voldesc.modified.month[0] && ! data->voldesc.modified.month[1]
832
 
          && ! data->voldesc.modified.day[0] && ! data->voldesc.modified.day[1]
833
 
          && ! data->voldesc.modified.hour[0] && ! data->voldesc.modified.hour[1]
834
 
          && ! data->voldesc.modified.minute[0] && ! data->voldesc.modified.minute[1]
835
 
          && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1]
836
 
          && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1])
837
 
        {
838
 
          grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID");
839
 
          *uuid = NULL;
840
 
        }
841
 
      else
842
 
        {
843
 
          *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
844
 
                                 data->voldesc.modified.year[0],
845
 
                                 data->voldesc.modified.year[1],
846
 
                                 data->voldesc.modified.year[2],
847
 
                                 data->voldesc.modified.year[3],
848
 
                                 data->voldesc.modified.month[0],
849
 
                                 data->voldesc.modified.month[1],
850
 
                                 data->voldesc.modified.day[0],
851
 
                                 data->voldesc.modified.day[1],
852
 
                                 data->voldesc.modified.hour[0],
853
 
                                 data->voldesc.modified.hour[1],
854
 
                                 data->voldesc.modified.minute[0],
855
 
                                 data->voldesc.modified.minute[1],
856
 
                                 data->voldesc.modified.second[0],
857
 
                                 data->voldesc.modified.second[1],
858
 
                                 data->voldesc.modified.hundredth[0],
859
 
                                 data->voldesc.modified.hundredth[1]);
860
 
        }
861
 
    }
862
 
  else
863
 
    *uuid = NULL;
864
 
 
865
 
        grub_dl_unref (my_mod);
866
 
 
867
 
  grub_free (data);
868
 
 
869
 
  return grub_errno;
870
 
}
871
 
 
872
 
 
873
 
 
874
 
static struct grub_fs grub_iso9660_fs =
875
 
  {
876
 
    .name = "iso9660",
877
 
    .dir = grub_iso9660_dir,
878
 
    .open = grub_iso9660_open,
879
 
    .read = grub_iso9660_read,
880
 
    .close = grub_iso9660_close,
881
 
    .label = grub_iso9660_label,
882
 
    .uuid = grub_iso9660_uuid,
883
 
    .next = 0
884
 
  };
885
 
 
886
 
GRUB_MOD_INIT(iso9660)
887
 
{
888
 
  grub_fs_register (&grub_iso9660_fs);
889
 
  my_mod = mod;
890
 
}
891
 
 
892
 
GRUB_MOD_FINI(iso9660)
893
 
{
894
 
  grub_fs_unregister (&grub_iso9660_fs);
895
 
}