1 /* cpio.c - cpio and tar filesystem. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007,2008,2009,2013 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/misc.h>
21 #include <grub/disk.h>
22 #include <grub/archelp.h>
24 #include <grub/file.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
53 static inline unsigned long long
54 read_number (const char *str
, grub_size_t size
)
56 unsigned long long ret
= 0;
57 while (size
-- && *str
>= '0' && *str
<= '7')
58 ret
= (ret
<< 3) | (*str
++ & 0xf);
62 struct grub_archelp_data
65 grub_off_t hofs
, next_hofs
;
69 grub_size_t linkname_alloc
;
73 grub_cpio_find_file (struct grub_archelp_data
*data
, char **name
,
78 int reread
= 0, have_longname
= 0, have_longlink
= 0;
80 data
->hofs
= data
->next_hofs
;
82 for (reread
= 0; reread
< 3; reread
++)
84 if (grub_disk_read (data
->disk
, 0, data
->hofs
, sizeof (hd
), &hd
))
87 if (!hd
.name
[0] && !hd
.prefix
[0])
89 *mode
= GRUB_ARCHELP_ATTR_END
;
93 if (grub_memcmp (hd
.magic
, MAGIC
, sizeof (MAGIC
) - 1))
94 return grub_error (GRUB_ERR_BAD_FS
, "invalid tar archive");
96 if (hd
.typeflag
== 'L')
99 grub_size_t namesize
= read_number (hd
.size
, sizeof (hd
.size
));
100 *name
= grub_malloc (namesize
+ 1);
103 err
= grub_disk_read (data
->disk
, 0,
104 data
->hofs
+ GRUB_DISK_SECTOR_SIZE
, namesize
,
106 (*name
)[namesize
] = 0;
109 data
->hofs
+= GRUB_DISK_SECTOR_SIZE
110 + ((namesize
+ GRUB_DISK_SECTOR_SIZE
- 1) &
111 ~(GRUB_DISK_SECTOR_SIZE
- 1));
116 if (hd
.typeflag
== 'K')
119 grub_size_t linksize
= read_number (hd
.size
, sizeof (hd
.size
));
120 if (data
->linkname_alloc
< linksize
+ 1)
123 n
= grub_malloc (2 * (linksize
+ 1));
126 grub_free (data
->linkname
);
128 data
->linkname_alloc
= 2 * (linksize
+ 1);
131 err
= grub_disk_read (data
->disk
, 0,
132 data
->hofs
+ GRUB_DISK_SECTOR_SIZE
, linksize
,
136 data
->linkname
[linksize
] = 0;
137 data
->hofs
+= GRUB_DISK_SECTOR_SIZE
138 + ((linksize
+ GRUB_DISK_SECTOR_SIZE
- 1) &
139 ~(GRUB_DISK_SECTOR_SIZE
- 1));
146 grub_size_t extra_size
= 0;
148 while (extra_size
< sizeof (hd
.prefix
)
149 && hd
.prefix
[extra_size
])
151 *name
= grub_malloc (sizeof (hd
.name
) + extra_size
+ 2);
156 grub_memcpy (*name
, hd
.prefix
, extra_size
);
157 (*name
)[extra_size
++] = '/';
159 grub_memcpy (*name
+ extra_size
, hd
.name
, sizeof (hd
.name
));
160 (*name
)[extra_size
+ sizeof (hd
.name
)] = 0;
163 data
->size
= read_number (hd
.size
, sizeof (hd
.size
));
164 data
->dofs
= data
->hofs
+ GRUB_DISK_SECTOR_SIZE
;
165 data
->next_hofs
= data
->dofs
+ ((data
->size
+ GRUB_DISK_SECTOR_SIZE
- 1) &
166 ~(GRUB_DISK_SECTOR_SIZE
- 1));
168 *mtime
= read_number (hd
.mtime
, sizeof (hd
.mtime
));
171 *mode
= read_number (hd
.mode
, sizeof (hd
.mode
));
178 *mode
|= GRUB_ARCHELP_ATTR_LNK
;
181 *mode
|= GRUB_ARCHELP_ATTR_FILE
;
184 *mode
|= GRUB_ARCHELP_ATTR_DIR
;
190 if (data
->linkname_alloc
< 101)
193 n
= grub_malloc (101);
196 grub_free (data
->linkname
);
198 data
->linkname_alloc
= 101;
200 grub_memcpy (data
->linkname
, hd
.linkname
, sizeof (hd
.linkname
));
201 data
->linkname
[100] = 0;
203 return GRUB_ERR_NONE
;
205 return GRUB_ERR_NONE
;
209 grub_cpio_get_link_target (struct grub_archelp_data
*data
)
211 return grub_strdup (data
->linkname
);
215 grub_cpio_rewind (struct grub_archelp_data
*data
)
220 static struct grub_archelp_ops arcops
=
222 .find_file
= grub_cpio_find_file
,
223 .get_link_target
= grub_cpio_get_link_target
,
224 .rewind
= grub_cpio_rewind
227 static struct grub_archelp_data
*
228 grub_cpio_mount (grub_disk_t disk
)
231 struct grub_archelp_data
*data
;
233 if (grub_disk_read (disk
, 0, 0, sizeof (hd
), &hd
))
236 if (grub_memcmp (hd
.magic
, MAGIC
, sizeof (MAGIC
) - 1))
239 data
= (struct grub_archelp_data
*) grub_zalloc (sizeof (*data
));
248 grub_error (GRUB_ERR_BAD_FS
, "not a tarfs filesystem");
253 grub_cpio_dir (grub_device_t device
, const char *path_in
,
254 grub_fs_dir_hook_t hook
, void *hook_data
)
256 struct grub_archelp_data
*data
;
259 data
= grub_cpio_mount (device
->disk
);
263 err
= grub_archelp_dir (data
, &arcops
,
264 path_in
, hook
, hook_data
);
266 grub_free (data
->linkname
);
273 grub_cpio_open (grub_file_t file
, const char *name_in
)
275 struct grub_archelp_data
*data
;
278 data
= grub_cpio_mount (file
->device
->disk
);
282 err
= grub_archelp_open (data
, &arcops
, name_in
);
285 grub_free (data
->linkname
);
291 file
->size
= data
->size
;
297 grub_cpio_read (grub_file_t file
, char *buf
, grub_size_t len
)
299 struct grub_archelp_data
*data
;
304 data
->disk
->read_hook
= file
->read_hook
;
305 data
->disk
->read_hook_data
= file
->read_hook_data
;
306 ret
= (grub_disk_read (data
->disk
, 0, data
->dofs
+ file
->offset
,
307 len
, buf
)) ? -1 : (grub_ssize_t
) len
;
308 data
->disk
->read_hook
= 0;
314 grub_cpio_close (grub_file_t file
)
316 struct grub_archelp_data
*data
;
319 grub_free (data
->linkname
);
325 static struct grub_fs grub_cpio_fs
= {
327 .dir
= grub_cpio_dir
,
328 .open
= grub_cpio_open
,
329 .read
= grub_cpio_read
,
330 .close
= grub_cpio_close
,
332 .reserved_first_sector
= 0,
333 .blocklist_install
= 0,
339 grub_fs_register (&grub_cpio_fs
);
344 grub_fs_unregister (&grub_cpio_fs
);