1 /* cpio.c - cpio and tar filesystem. */
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>
22 #include <grub/misc.h>
23 #include <grub/disk.h>
26 #define MAGIC_BCPIO 070707
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"
65 } __attribute__ ((packed
));
67 #define HEAD_LENG sizeof(struct HEAD_USTAR)
78 static grub_dl_t my_mod
;
82 grub_cpio_find_file (struct grub_cpio_data
*data
, char **name
,
89 (data
->disk
, 0, data
->hofs
, sizeof (hd
), (char *) &hd
))
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
;
100 if ((*name
= grub_malloc (hd
.namesize
)) == NULL
)
103 if (grub_disk_read (data
->disk
, 0, data
->hofs
+ sizeof (hd
),
110 if (data
->size
== 0 && hd
.mode
== 0 && hd
.namesize
== 11 + 1
111 && ! grub_memcmp(*name
, "TRAILER!!!", 11))
114 return GRUB_ERR_NONE
;
117 data
->dofs
= data
->hofs
+ sizeof (hd
) + hd
.namesize
;
118 *ofs
= data
->dofs
+ data
->size
;
122 struct HEAD_USTAR hd
;
125 (data
->disk
, 0, data
->hofs
, sizeof (hd
), (char *) &hd
))
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
)
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));
145 return GRUB_ERR_NONE
;
148 static struct grub_cpio_data
*
149 grub_cpio_mount (grub_disk_t disk
)
152 struct grub_cpio_data
*data
;
154 if (grub_disk_read (disk
, 0, 0, sizeof (hd
), hd
))
158 if (((struct HEAD_BCPIO
*) hd
)->magic
!= MAGIC_BCPIO
)
160 if (grub_memcmp (((struct HEAD_USTAR
*) hd
)->magic
, MAGIC_USTAR
,
161 sizeof (MAGIC_USTAR
) - 1))
165 data
= (struct grub_cpio_data
*) grub_malloc (sizeof (*data
));
174 grub_error (GRUB_ERR_BAD_FS
, "not a "
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
;
195 grub_dl_ref (my_mod
);
200 data
= grub_cpio_mount (device
->disk
);
205 len
= grub_strlen (path
) - 1;
210 if (grub_cpio_find_file (data
, &name
, &ofs
))
216 if (grub_memcmp (np
, name
, len
) == 0)
224 p
= grub_strchr (name
+ len
, '/');
228 if ((!prev
) || (grub_strcmp (prev
, name
) != 0))
230 hook (name
+ len
, p
!= NULL
);
250 grub_dl_unref (my_mod
);
257 grub_cpio_open (grub_file_t file
, const char *name
)
259 struct grub_cpio_data
*data
;
265 grub_dl_ref (my_mod
);
268 data
= grub_cpio_mount (file
->device
->disk
);
275 if (grub_cpio_find_file (data
, &fn
, &ofs
))
280 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
284 /* Compare NAME and FN by hand in order to cope with duplicate
290 if (name
[i
] != fn
[j
])
296 if (name
[i
] == '/' && name
[i
+1] == '/')
304 file
->size
= data
->size
;
307 return GRUB_ERR_NONE
;
321 grub_dl_unref (my_mod
);
328 grub_cpio_read (grub_file_t file
, char *buf
, grub_size_t len
)
330 struct grub_cpio_data
*data
;
333 return (grub_disk_read (data
->disk
, 0, data
->dofs
+ file
->offset
,
334 len
, buf
)) ? -1 : (grub_ssize_t
) len
;
338 grub_cpio_close (grub_file_t file
)
340 grub_free (file
->data
);
343 grub_dl_unref (my_mod
);
349 static struct grub_fs grub_cpio_fs
= {
355 .dir
= grub_cpio_dir
,
356 .open
= grub_cpio_open
,
357 .read
= grub_cpio_read
,
358 .close
= grub_cpio_close
,
367 grub_fs_register (&grub_cpio_fs
);
379 grub_fs_unregister (&grub_cpio_fs
);