make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / fs / cpio.c
blob1692d6108ae111b171aa4282b40d122e2246dad6
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;
266 #ifndef GRUB_UTIL
267 grub_dl_ref (my_mod);
268 #endif
270 data = grub_cpio_mount (file->device->disk);
271 if (!data)
272 goto fail;
274 data->hofs = 0;
275 while (1)
277 if (grub_cpio_find_file (data, &fn, &ofs))
278 goto fail;
280 if (!ofs)
282 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
283 break;
286 if (grub_strcmp (name + 1, fn) == 0)
288 file->data = data;
289 file->size = data->size;
290 grub_free (fn);
292 return GRUB_ERR_NONE;
295 grub_free (fn);
296 data->hofs = ofs;
299 fail:
301 if (data)
302 grub_free (data);
304 #ifndef GRUB_UTIL
305 grub_dl_unref (my_mod);
306 #endif
308 return grub_errno;
311 static grub_ssize_t
312 grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
314 struct grub_cpio_data *data;
316 data = file->data;
317 return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
318 len, buf)) ? -1 : (grub_ssize_t) len;
321 static grub_err_t
322 grub_cpio_close (grub_file_t file)
324 grub_free (file->data);
326 #ifndef GRUB_UTIL
327 grub_dl_unref (my_mod);
328 #endif
330 return grub_errno;
333 static struct grub_fs grub_cpio_fs = {
334 .name = "cpiofs",
335 .dir = grub_cpio_dir,
336 .open = grub_cpio_open,
337 .read = grub_cpio_read,
338 .close = grub_cpio_close,
339 .label = 0,
340 .next = 0
343 GRUB_MOD_INIT (cpio)
345 grub_fs_register (&grub_cpio_fs);
346 #ifndef GRUB_UTIL
347 my_mod = mod;
348 #endif
351 GRUB_MOD_FINI (cpio)
353 grub_fs_unregister (&grub_cpio_fs);