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

« back to all changes in this revision

Viewing changes to fs/cpio.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2008-01-28 00:01:11 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20080128000111-0764agvqzg601o1d
Tags: upstream-1.95+20080128
ImportĀ upstreamĀ versionĀ 1.95+20080128

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* cpio.c - cpio and tar filesystem.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2007 Free Software Foundation, Inc.
 
5
 *
 
6
 *  This program is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/file.h>
 
21
#include <grub/mm.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/disk.h>
 
24
#include <grub/dl.h>
 
25
 
 
26
#define MAGIC_BCPIO     070707
 
27
 
 
28
struct HEAD_BCPIO
 
29
{
 
30
  grub_uint16_t magic;
 
31
  grub_uint16_t dev;
 
32
  grub_uint16_t ino;
 
33
  grub_uint16_t mode;
 
34
  grub_uint16_t uid;
 
35
  grub_uint16_t gid;
 
36
  grub_uint16_t nlink;
 
37
  grub_uint16_t rdev;
 
38
  grub_uint16_t mtime_1;
 
39
  grub_uint16_t mtime_2;
 
40
  grub_uint16_t namesize;
 
41
  grub_uint16_t filesize_1;
 
42
  grub_uint16_t filesize_2;
 
43
} __attribute__ ((packed));
 
44
 
 
45
#define MAGIC_USTAR     "ustar"
 
46
 
 
47
struct HEAD_USTAR
 
48
{
 
49
  char name[100];
 
50
  char mode[8];
 
51
  char uid[8];
 
52
  char gid[8];
 
53
  char size[12];
 
54
  char mtime[12];
 
55
  char chksum[8];
 
56
  char typeflag;
 
57
  char linkname[100];
 
58
  char magic[6];
 
59
  char version[2];
 
60
  char uname[32];
 
61
  char gname[32];
 
62
  char devmajor[8];
 
63
  char devminor[8];
 
64
  char prefix[155];
 
65
} __attribute__ ((packed));
 
66
 
 
67
#define HEAD_LENG       sizeof(struct HEAD_USTAR)
 
68
 
 
69
#define MODE_BCPIO      1
 
70
#define MODE_USTAR      2
 
71
 
 
72
struct grub_cpio_data
 
73
{
 
74
  grub_disk_t disk;
 
75
  grub_uint32_t hofs;
 
76
  grub_uint32_t dofs;
 
77
  grub_uint32_t size;
 
78
  int mode;
 
79
};
 
80
 
 
81
#ifndef GRUB_UTIL
 
82
static grub_dl_t my_mod;
 
83
#endif
 
84
 
 
85
static grub_err_t
 
86
grub_cpio_find_file (struct grub_cpio_data *data, char **name,
 
87
                     grub_uint32_t * ofs)
 
88
{
 
89
  if (data->mode == MODE_BCPIO)
 
90
    {
 
91
      struct HEAD_BCPIO hd;
 
92
 
 
93
      if (grub_disk_read
 
94
          (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
 
95
        return grub_errno;
 
96
 
 
97
      if (hd.magic != MAGIC_BCPIO)
 
98
        return grub_error (GRUB_ERR_BAD_FS, "Invalid cpio archive");
 
99
 
 
100
      data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
 
101
      if (data->size == 0)
 
102
        {
 
103
          *ofs = 0;
 
104
          return GRUB_ERR_FILE_NOT_FOUND;
 
105
        }
 
106
 
 
107
      if (hd.namesize & 1)
 
108
        hd.namesize++;
 
109
 
 
110
      if ((*name = grub_malloc (hd.namesize)) == NULL)
 
111
        return grub_errno;
 
112
 
 
113
      if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
 
114
                          hd.namesize, *name))
 
115
        {
 
116
          grub_free (*name);
 
117
          return grub_errno;
 
118
        }
 
119
 
 
120
      data->dofs = data->hofs + sizeof (hd) + hd.namesize;
 
121
      *ofs = data->dofs + data->size;
 
122
      if (data->size & 1)
 
123
        (*ofs)++;
 
124
    }
 
125
  else
 
126
    {
 
127
      struct HEAD_USTAR hd;
 
128
 
 
129
      if (grub_disk_read
 
130
          (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
 
131
        return grub_errno;
 
132
 
 
133
      if (!hd.name[0])
 
134
        {
 
135
          *ofs = 0;
 
136
          return GRUB_ERR_FILE_NOT_FOUND;
 
137
        }
 
138
 
 
139
      if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
 
140
        return grub_error (GRUB_ERR_BAD_FS, "Invalid tar archive");
 
141
 
 
142
      if ((*name = grub_strdup (hd.name)) == NULL)
 
143
        return grub_errno;
 
144
 
 
145
      data->size = grub_strtoul (hd.size, NULL, 8);
 
146
      data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
 
147
      *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
 
148
                           ~(GRUB_DISK_SECTOR_SIZE - 1));
 
149
    }
 
150
  return GRUB_ERR_NONE;
 
151
}
 
152
 
 
153
static struct grub_cpio_data *
 
154
grub_cpio_mount (grub_disk_t disk)
 
155
{
 
156
  char hd[HEAD_LENG];
 
157
  struct grub_cpio_data *data;
 
158
  int mode;
 
159
 
 
160
  if (grub_disk_read (disk, 0, 0, sizeof (hd), hd))
 
161
    goto fail;
 
162
 
 
163
  if (((struct HEAD_BCPIO *) hd)->magic == MAGIC_BCPIO)
 
164
    mode = MODE_BCPIO;
 
165
  else if (!grub_memcmp (((struct HEAD_USTAR *) hd)->magic, MAGIC_USTAR,
 
166
                         sizeof (MAGIC_USTAR) - 1))
 
167
    mode = MODE_USTAR;
 
168
  else
 
169
    goto fail;
 
170
 
 
171
  data = (struct grub_cpio_data *) grub_malloc (sizeof (*data));
 
172
  if (!data)
 
173
    goto fail;
 
174
 
 
175
  data->disk = disk;
 
176
  data->mode = mode;
 
177
 
 
178
  return data;
 
179
 
 
180
fail:
 
181
  grub_error (GRUB_ERR_BAD_FS, "not a cpio filesystem");
 
182
  return 0;
 
183
}
 
184
 
 
185
static grub_err_t
 
186
grub_cpio_dir (grub_device_t device, const char *path,
 
187
               int (*hook) (const char *filename, int dir))
 
188
{
 
189
  struct grub_cpio_data *data;
 
190
  grub_uint32_t ofs;
 
191
  char *prev, *name, *np;
 
192
  int len;
 
193
 
 
194
#ifndef GRUB_UTIL
 
195
  grub_dl_ref (my_mod);
 
196
#endif
 
197
 
 
198
  prev = 0;
 
199
 
 
200
  data = grub_cpio_mount (device->disk);
 
201
  if (!data)
 
202
    goto fail;
 
203
 
 
204
  np = path + 1;
 
205
  len = grub_strlen (path) - 1;
 
206
 
 
207
  data->hofs = 0;
 
208
  while (1)
 
209
    {
 
210
      if (grub_cpio_find_file (data, &name, &ofs))
 
211
        goto fail;
 
212
 
 
213
      if (!ofs)
 
214
        break;
 
215
 
 
216
      if (grub_memcmp (np, name, len) == 0)
 
217
        {
 
218
          char *p, *n;
 
219
 
 
220
          n = name + len;
 
221
          if (*n == '/')
 
222
            n++;
 
223
 
 
224
          p = grub_strchr (name + len, '/');
 
225
          if (p)
 
226
            *p = 0;
 
227
 
 
228
          if ((!prev) || (grub_strcmp (prev, name) != 0))
 
229
            {
 
230
              hook (name + len, p != NULL);
 
231
              if (prev)
 
232
                grub_free (prev);
 
233
              prev = name;
 
234
            }
 
235
          else
 
236
            grub_free (name);
 
237
        }
 
238
      data->hofs = ofs;
 
239
    }
 
240
 
 
241
fail:
 
242
 
 
243
  if (prev)
 
244
    grub_free (prev);
 
245
 
 
246
  if (data)
 
247
    grub_free (data);
 
248
 
 
249
#ifndef GRUB_UTIL
 
250
  grub_dl_unref (my_mod);
 
251
#endif
 
252
 
 
253
  return grub_errno;
 
254
}
 
255
 
 
256
static grub_err_t
 
257
grub_cpio_open (grub_file_t file, const char *name)
 
258
{
 
259
  struct grub_cpio_data *data;
 
260
  grub_uint32_t ofs;
 
261
  char *fn;
 
262
 
 
263
#ifndef GRUB_UTIL
 
264
  grub_dl_ref (my_mod);
 
265
#endif
 
266
 
 
267
  data = grub_cpio_mount (file->device->disk);
 
268
  if (!data)
 
269
    goto fail;
 
270
 
 
271
  data->hofs = 0;
 
272
  while (1)
 
273
    {
 
274
      if (grub_cpio_find_file (data, &fn, &ofs))
 
275
        goto fail;
 
276
 
 
277
      if (!ofs)
 
278
        break;
 
279
 
 
280
      if (grub_strcmp (name + 1, fn) == 0)
 
281
        {
 
282
          file->data = data;
 
283
          file->size = data->size;
 
284
          grub_free (fn);
 
285
 
 
286
          return GRUB_ERR_NONE;
 
287
        }
 
288
 
 
289
      grub_free (fn);
 
290
      data->hofs = ofs;
 
291
    }
 
292
 
 
293
fail:
 
294
 
 
295
  if (data)
 
296
    grub_free (data);
 
297
 
 
298
#ifndef GRUB_UTIL
 
299
  grub_dl_unref (my_mod);
 
300
#endif
 
301
 
 
302
  return grub_errno;
 
303
}
 
304
 
 
305
static grub_ssize_t
 
306
grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
 
307
{
 
308
  struct grub_cpio_data *data;
 
309
 
 
310
  data = file->data;
 
311
  return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
 
312
                          len, buf)) ? -1 : len;
 
313
}
 
314
 
 
315
static grub_err_t
 
316
grub_cpio_close (grub_file_t file)
 
317
{
 
318
  grub_free (file->data);
 
319
 
 
320
#ifndef GRUB_UTIL
 
321
  grub_dl_unref (my_mod);
 
322
#endif
 
323
 
 
324
  return grub_errno;
 
325
}
 
326
 
 
327
static struct grub_fs grub_cpio_fs = {
 
328
  .name = "cpiofs",
 
329
  .dir = grub_cpio_dir,
 
330
  .open = grub_cpio_open,
 
331
  .read = grub_cpio_read,
 
332
  .close = grub_cpio_close,
 
333
  .label = 0,
 
334
  .next = 0
 
335
};
 
336
 
 
337
GRUB_MOD_INIT (cpio)
 
338
{
 
339
  grub_fs_register (&grub_cpio_fs);
 
340
#ifndef GRUB_UTIL
 
341
  my_mod = mod;
 
342
#endif
 
343
}
 
344
 
 
345
GRUB_MOD_FINI (cpio)
 
346
{
 
347
  grub_fs_unregister (&grub_cpio_fs);
 
348
}