Update svn:ignore property
[grub2/jjazz.git] / fs / cpio.c
blob3d8078ae9091928c97ea3478307ddaa4d50ac672
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 struct grub_cpio_data
71 grub_disk_t disk;
72 grub_uint32_t hofs;
73 grub_uint32_t dofs;
74 grub_uint32_t size;
77 #ifndef GRUB_UTIL
78 static grub_dl_t my_mod;
79 #endif
81 static grub_err_t
82 grub_cpio_find_file (struct grub_cpio_data *data, char **name,
83 grub_uint32_t * ofs)
85 #ifndef MODE_USTAR
86 struct HEAD_BCPIO hd;
88 if (grub_disk_read
89 (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
90 return grub_errno;
92 if (hd.magic != MAGIC_BCPIO)
93 return grub_error (GRUB_ERR_BAD_FS, "Invalid cpio archive");
95 data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
97 if (hd.namesize & 1)
98 hd.namesize++;
100 if ((*name = grub_malloc (hd.namesize)) == NULL)
101 return grub_errno;
103 if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
104 hd.namesize, *name))
106 grub_free (*name);
107 return grub_errno;
110 if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
111 && ! grub_memcmp(*name, "TRAILER!!!", 11))
113 *ofs = 0;
114 return GRUB_ERR_NONE;
117 data->dofs = data->hofs + sizeof (hd) + hd.namesize;
118 *ofs = data->dofs + data->size;
119 if (data->size & 1)
120 (*ofs)++;
121 #else
122 struct HEAD_USTAR hd;
124 if (grub_disk_read
125 (data->disk, 0, data->hofs, sizeof (hd), (char *) &hd))
126 return grub_errno;
128 if (!hd.name[0])
130 *ofs = 0;
131 return GRUB_ERR_NONE;
134 if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
135 return grub_error (GRUB_ERR_BAD_FS, "Invalid tar archive");
137 if ((*name = grub_strdup (hd.name)) == NULL)
138 return grub_errno;
140 data->size = grub_strtoul (hd.size, NULL, 8);
141 data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
142 *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
143 ~(GRUB_DISK_SECTOR_SIZE - 1));
144 #endif
145 return GRUB_ERR_NONE;
148 static struct grub_cpio_data *
149 grub_cpio_mount (grub_disk_t disk)
151 char hd[HEAD_LENG];
152 struct grub_cpio_data *data;
154 if (grub_disk_read (disk, 0, 0, sizeof (hd), hd))
155 goto fail;
157 #ifndef MODE_USTAR
158 if (((struct HEAD_BCPIO *) hd)->magic != MAGIC_BCPIO)
159 #else
160 if (grub_memcmp (((struct HEAD_USTAR *) hd)->magic, MAGIC_USTAR,
161 sizeof (MAGIC_USTAR) - 1))
162 #endif
163 goto fail;
165 data = (struct grub_cpio_data *) grub_malloc (sizeof (*data));
166 if (!data)
167 goto fail;
169 data->disk = disk;
171 return data;
173 fail:
174 grub_error (GRUB_ERR_BAD_FS, "not a "
175 #ifdef MODE_USTAR
176 "tar"
177 #else
178 "cpio"
179 #endif
180 " filesystem");
181 return 0;
184 static grub_err_t
185 grub_cpio_dir (grub_device_t device, const char *path,
186 int (*hook) (const char *filename, int dir))
188 struct grub_cpio_data *data;
189 grub_uint32_t ofs;
190 char *prev, *name;
191 const char *np;
192 int len;
194 #ifndef GRUB_UTIL
195 grub_dl_ref (my_mod);
196 #endif
198 prev = 0;
200 data = grub_cpio_mount (device->disk);
201 if (!data)
202 goto fail;
204 np = path + 1;
205 len = grub_strlen (path) - 1;
207 data->hofs = 0;
208 while (1)
210 if (grub_cpio_find_file (data, &name, &ofs))
211 goto fail;
213 if (!ofs)
214 break;
216 if (grub_memcmp (np, name, len) == 0)
218 char *p, *n;
220 n = name + len;
221 if (*n == '/')
222 n++;
224 p = grub_strchr (name + len, '/');
225 if (p)
226 *p = 0;
228 if ((!prev) || (grub_strcmp (prev, name) != 0))
230 hook (name + len, p != NULL);
231 if (prev)
232 grub_free (prev);
233 prev = name;
235 else
236 grub_free (name);
238 data->hofs = ofs;
241 fail:
243 if (prev)
244 grub_free (prev);
246 if (data)
247 grub_free (data);
249 #ifndef GRUB_UTIL
250 grub_dl_unref (my_mod);
251 #endif
253 return grub_errno;
256 static grub_err_t
257 grub_cpio_open (grub_file_t file, const char *name)
259 struct grub_cpio_data *data;
260 grub_uint32_t ofs;
261 char *fn;
262 int i, j;
264 #ifndef GRUB_UTIL
265 grub_dl_ref (my_mod);
266 #endif
268 data = grub_cpio_mount (file->device->disk);
269 if (!data)
270 goto fail;
272 data->hofs = 0;
273 while (1)
275 if (grub_cpio_find_file (data, &fn, &ofs))
276 goto fail;
278 if (!ofs)
280 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
281 break;
284 /* Compare NAME and FN by hand in order to cope with duplicate
285 slashes. */
286 i = 1;
287 j = 0;
288 while (1)
290 if (name[i] != fn[j])
291 goto no_match;
293 if (name[i] == '\0')
294 break;
296 if (name[i] == '/' && name[i+1] == '/')
297 i++;
299 i++;
300 j++;
303 file->data = data;
304 file->size = data->size;
305 grub_free (fn);
307 return GRUB_ERR_NONE;
309 no_match:
311 grub_free (fn);
312 data->hofs = ofs;
315 fail:
317 if (data)
318 grub_free (data);
320 #ifndef GRUB_UTIL
321 grub_dl_unref (my_mod);
322 #endif
324 return grub_errno;
327 static grub_ssize_t
328 grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
330 struct grub_cpio_data *data;
332 data = file->data;
333 return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
334 len, buf)) ? -1 : (grub_ssize_t) len;
337 static grub_err_t
338 grub_cpio_close (grub_file_t file)
340 grub_free (file->data);
342 #ifndef GRUB_UTIL
343 grub_dl_unref (my_mod);
344 #endif
346 return grub_errno;
349 static struct grub_fs grub_cpio_fs = {
350 #ifdef MODE_USTAR
351 .name = "tarfs",
352 #else
353 .name = "cpiofs",
354 #endif
355 .dir = grub_cpio_dir,
356 .open = grub_cpio_open,
357 .read = grub_cpio_read,
358 .close = grub_cpio_close,
361 #ifdef MODE_USTAR
362 GRUB_MOD_INIT (cpio)
363 #else
364 GRUB_MOD_INIT (tar)
365 #endif
367 grub_fs_register (&grub_cpio_fs);
368 #ifndef GRUB_UTIL
369 my_mod = mod;
370 #endif
373 #ifdef MODE_USTAR
374 GRUB_MOD_FINI (cpio)
375 #else
376 GRUB_MOD_FINI (tar)
377 #endif
379 grub_fs_unregister (&grub_cpio_fs);