~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to fs/iso9660.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

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