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>
28 #define MAGIC_BCPIO 070707
39 grub_uint16_t mtime_1
;
40 grub_uint16_t mtime_2
;
41 grub_uint16_t namesize
;
42 grub_uint16_t filesize_1
;
43 grub_uint16_t filesize_2
;
44 } __attribute__ ((packed
));
47 #define MAGIC_USTAR "ustar"
66 } __attribute__ ((packed
));
77 static grub_dl_t my_mod
;
80 grub_cpio_find_file (struct grub_cpio_data
*data
, char **name
,
87 (data
->disk
, 0, data
->hofs
, sizeof (hd
), &hd
))
90 if (hd
.magic
!= MAGIC_BCPIO
)
91 return grub_error (GRUB_ERR_BAD_FS
, "Invalid cpio archive");
93 data
->size
= (((grub_uint32_t
) hd
.filesize_1
) << 16) + hd
.filesize_2
;
98 if ((*name
= grub_malloc (hd
.namesize
)) == NULL
)
101 if (grub_disk_read (data
->disk
, 0, data
->hofs
+ sizeof (hd
),
108 if (data
->size
== 0 && hd
.mode
== 0 && hd
.namesize
== 11 + 1
109 && ! grub_memcmp(*name
, "TRAILER!!!", 11))
112 return GRUB_ERR_NONE
;
115 data
->dofs
= data
->hofs
+ sizeof (hd
) + hd
.namesize
;
116 *ofs
= data
->dofs
+ data
->size
;
123 (data
->disk
, 0, data
->hofs
, sizeof (hd
), &hd
))
129 return GRUB_ERR_NONE
;
132 if (grub_memcmp (hd
.magic
, MAGIC_USTAR
, sizeof (MAGIC_USTAR
) - 1))
133 return grub_error (GRUB_ERR_BAD_FS
, "Invalid tar archive");
135 if ((*name
= grub_strdup (hd
.name
)) == NULL
)
138 data
->size
= grub_strtoul (hd
.size
, NULL
, 8);
139 data
->dofs
= data
->hofs
+ GRUB_DISK_SECTOR_SIZE
;
140 *ofs
= data
->dofs
+ ((data
->size
+ GRUB_DISK_SECTOR_SIZE
- 1) &
141 ~(GRUB_DISK_SECTOR_SIZE
- 1));
143 return GRUB_ERR_NONE
;
146 static struct grub_cpio_data
*
147 grub_cpio_mount (grub_disk_t disk
)
150 struct grub_cpio_data
*data
;
152 if (grub_disk_read (disk
, 0, 0, sizeof (hd
), &hd
))
156 if (hd
.magic
!= MAGIC_BCPIO
)
158 if (grub_memcmp (hd
.magic
, MAGIC_USTAR
,
159 sizeof (MAGIC_USTAR
) - 1))
163 data
= (struct grub_cpio_data
*) grub_malloc (sizeof (*data
));
172 grub_error (GRUB_ERR_BAD_FS
, "not a "
183 grub_cpio_dir (grub_device_t device
, const char *path
,
184 int (*hook
) (const char *filename
,
185 const struct grub_dirhook_info
*info
))
187 struct grub_cpio_data
*data
;
193 grub_dl_ref (my_mod
);
197 data
= grub_cpio_mount (device
->disk
);
202 len
= grub_strlen (path
) - 1;
207 if (grub_cpio_find_file (data
, &name
, &ofs
))
213 if (grub_memcmp (np
, name
, len
) == 0)
221 p
= grub_strchr (name
+ len
, '/');
225 if ((!prev
) || (grub_strcmp (prev
, name
) != 0))
227 struct grub_dirhook_info info
;
228 grub_memset (&info
, 0, sizeof (info
));
229 info
.dir
= (p
!= NULL
);
231 hook (name
+ len
, &info
);
250 grub_dl_unref (my_mod
);
256 grub_cpio_open (grub_file_t file
, const char *name
)
258 struct grub_cpio_data
*data
;
263 grub_dl_ref (my_mod
);
265 data
= grub_cpio_mount (file
->device
->disk
);
272 if (grub_cpio_find_file (data
, &fn
, &ofs
))
277 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
281 /* Compare NAME and FN by hand in order to cope with duplicate
287 if (name
[i
] != fn
[j
])
293 if (name
[i
] == '/' && name
[i
+1] == '/')
301 file
->size
= data
->size
;
304 return GRUB_ERR_NONE
;
317 grub_dl_unref (my_mod
);
323 grub_cpio_read (grub_file_t file
, char *buf
, grub_size_t len
)
325 struct grub_cpio_data
*data
;
328 return (grub_disk_read (data
->disk
, 0, data
->dofs
+ file
->offset
,
329 len
, buf
)) ? -1 : (grub_ssize_t
) len
;
333 grub_cpio_close (grub_file_t file
)
335 grub_free (file
->data
);
337 grub_dl_unref (my_mod
);
342 static struct grub_fs grub_cpio_fs
= {
348 .dir
= grub_cpio_dir
,
349 .open
= grub_cpio_open
,
350 .read
= grub_cpio_read
,
351 .close
= grub_cpio_close
,
360 grub_fs_register (&grub_cpio_fs
);
370 grub_fs_unregister (&grub_cpio_fs
);