Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub2 / fs / cpio.c
blob4965fe57dc5b328a97c3dd6083a79bbba0bb154b
1 /* cpio.c - cpio and tar filesystem. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007,2008 Free Software Foundation, Inc.
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.
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.
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/>.
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>
26 #define MAGIC_BCPIO 070707
28 struct HEAD_BCPIO
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));
45 #define MAGIC_USTAR "ustar"
47 struct HEAD_USTAR
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));
67 #define HEAD_LENG sizeof(struct HEAD_USTAR)
69 #define MODE_BCPIO 1
70 #define MODE_USTAR 2
72 struct grub_cpio_data
74 grub_disk_t disk;
75 grub_uint32_t hofs;
76 grub_uint32_t dofs;
77 grub_uint32_t size;
78 int mode;
81 #ifndef GRUB_UTIL
82 static grub_dl_t my_mod;
83 #endif
85 static grub_err_t
86 grub_cpio_find_file (struct grub_cpio_data *data, char **name,
87 grub_uint32_t * ofs)
89 if (data->mode == MODE_BCPIO)
91 struct HEAD_BCPIO hd;
93 if (grub_disk_read
94 (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
95 return grub_errno;
97 if (hd.magic != MAGIC_BCPIO)
98 return grub_error (GRUB_ERR_BAD_FS, "Invalid cpio archive");
100 data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
102 if (hd.namesize & 1)
103 hd.namesize++;
105 if ((*name = grub_malloc (hd.namesize)) == NULL)
106 return grub_errno;
108 if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
109 hd.namesize, *name))
111 grub_free (*name);
112 return grub_errno;
115 if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
116 && ! grub_memcmp(*name, "TRAILER!!!", 11))
118 *ofs = 0;
119 return GRUB_ERR_NONE;
122 data->dofs = data->hofs + sizeof (hd) + hd.namesize;
123 *ofs = data->dofs + data->size;
124 if (data->size & 1)
125 (*ofs)++;
127 else
129 struct HEAD_USTAR hd;
131 if (grub_disk_read
132 (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
133 return grub_errno;
135 if (!hd.name[0])
137 *ofs = 0;
138 return GRUB_ERR_NONE;
141 if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
142 return grub_error (GRUB_ERR_BAD_FS, "Invalid tar archive");
144 if ((*name = grub_strdup (hd.name)) == NULL)
145 return grub_errno;
147 data->size = grub_strtoul (hd.size, NULL, 8);
148 data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
149 *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
150 ~(GRUB_DISK_SECTOR_SIZE - 1));
152 return GRUB_ERR_NONE;
155 static struct grub_cpio_data *
156 grub_cpio_mount (grub_disk_t disk)
158 char hd[HEAD_LENG];
159 struct grub_cpio_data *data;
160 int mode;
162 if (grub_disk_read (disk, 0, 0, sizeof (hd), hd))
163 goto fail;
165 if (((struct HEAD_BCPIO *) hd)->magic == MAGIC_BCPIO)
166 mode = MODE_BCPIO;
167 else if (!grub_memcmp (((struct HEAD_USTAR *) hd)->magic, MAGIC_USTAR,
168 sizeof (MAGIC_USTAR) - 1))
169 mode = MODE_USTAR;
170 else
171 goto fail;
173 data = (struct grub_cpio_data *) grub_malloc (sizeof (*data));
174 if (!data)
175 goto fail;
177 data->disk = disk;
178 data->mode = mode;
180 return data;
182 fail:
183 grub_error (GRUB_ERR_BAD_FS, "not a cpio filesystem");
184 return 0;
187 static grub_err_t
188 grub_cpio_dir (grub_device_t device, const char *path,
189 int (*hook) (const char *filename, int dir))
191 struct grub_cpio_data *data;
192 grub_uint32_t ofs;
193 char *prev, *name;
194 const char *np;
195 int len;
197 #ifndef GRUB_UTIL
198 grub_dl_ref (my_mod);
199 #endif
201 prev = 0;
203 data = grub_cpio_mount (device->disk);
204 if (!data)
205 goto fail;
207 np = path + 1;
208 len = grub_strlen (path) - 1;
210 data->hofs = 0;
211 while (1)
213 if (grub_cpio_find_file (data, &name, &ofs))
214 goto fail;
216 if (!ofs)
217 break;
219 if (grub_memcmp (np, name, len) == 0)
221 char *p, *n;
223 n = name + len;
224 if (*n == '/')
225 n++;
227 p = grub_strchr (name + len, '/');
228 if (p)
229 *p = 0;
231 if ((!prev) || (grub_strcmp (prev, name) != 0))
233 hook (name + len, p != NULL);
234 if (prev)
235 grub_free (prev);
236 prev = name;
238 else
239 grub_free (name);
241 data->hofs = ofs;
244 fail:
246 if (prev)
247 grub_free (prev);
249 if (data)
250 grub_free (data);
252 #ifndef GRUB_UTIL
253 grub_dl_unref (my_mod);
254 #endif
256 return grub_errno;
259 static grub_err_t
260 grub_cpio_open (grub_file_t file, const char *name)
262 struct grub_cpio_data *data;
263 grub_uint32_t ofs;
264 char *fn;
265 int i, j;
267 #ifndef GRUB_UTIL
268 grub_dl_ref (my_mod);
269 #endif
271 data = grub_cpio_mount (file->device->disk);
272 if (!data)
273 goto fail;
275 data->hofs = 0;
276 while (1)
278 if (grub_cpio_find_file (data, &fn, &ofs))
279 goto fail;
281 if (!ofs)
283 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
284 break;
287 /* Compare NAME and FN by hand in order to cope with duplicate
288 slashes. */
289 i = 1;
290 j = 0;
291 while (1)
293 if (name[i] != fn[j])
294 goto no_match;
296 if (name[i] == '\0')
297 break;
299 if (name[i] == '/' && name[i+1] == '/')
300 i++;
302 i++;
303 j++;
306 file->data = data;
307 file->size = data->size;
308 grub_free (fn);
310 return GRUB_ERR_NONE;
312 no_match:
314 grub_free (fn);
315 data->hofs = ofs;
318 fail:
320 if (data)
321 grub_free (data);
323 #ifndef GRUB_UTIL
324 grub_dl_unref (my_mod);
325 #endif
327 return grub_errno;
330 static grub_ssize_t
331 grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
333 struct grub_cpio_data *data;
335 data = file->data;
336 return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
337 len, buf)) ? -1 : (grub_ssize_t) len;
340 static grub_err_t
341 grub_cpio_close (grub_file_t file)
343 grub_free (file->data);
345 #ifndef GRUB_UTIL
346 grub_dl_unref (my_mod);
347 #endif
349 return grub_errno;
352 static struct grub_fs grub_cpio_fs = {
353 .name = "cpiofs",
354 .dir = grub_cpio_dir,
355 .open = grub_cpio_open,
356 .read = grub_cpio_read,
357 .close = grub_cpio_close,
358 .label = 0,
359 .next = 0
362 GRUB_MOD_INIT (cpio)
364 grub_fs_register (&grub_cpio_fs);
365 #ifndef GRUB_UTIL
366 my_mod = mod;
367 #endif
370 GRUB_MOD_FINI (cpio)
372 grub_fs_unregister (&grub_cpio_fs);