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

« back to all changes in this revision

Viewing changes to fs/iso9660.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

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