Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / fs / tar.c
blob39bf197aabe225217ea7cd0f2b6f39165034a8f1
1 /* cpio.c - cpio and tar filesystem. */
2 /*
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>
25 #include <grub/mm.h>
26 #include <grub/dl.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 /* tar support */
32 #define MAGIC "ustar"
33 struct head
35 char name[100];
36 char mode[8];
37 char uid[8];
38 char gid[8];
39 char size[12];
40 char mtime[12];
41 char chksum[8];
42 char typeflag;
43 char linkname[100];
44 char magic[6];
45 char version[2];
46 char uname[32];
47 char gname[32];
48 char devmajor[8];
49 char devminor[8];
50 char prefix[155];
51 } GRUB_PACKED;
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);
59 return ret;
62 struct grub_archelp_data
64 grub_disk_t disk;
65 grub_off_t hofs, next_hofs;
66 grub_off_t dofs;
67 grub_off_t size;
68 char *linkname;
69 grub_size_t linkname_alloc;
72 static grub_err_t
73 grub_cpio_find_file (struct grub_archelp_data *data, char **name,
74 grub_int32_t *mtime,
75 grub_uint32_t *mode)
77 struct head hd;
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))
85 return grub_errno;
87 if (!hd.name[0] && !hd.prefix[0])
89 *mode = GRUB_ARCHELP_ATTR_END;
90 return GRUB_ERR_NONE;
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')
98 grub_err_t err;
99 grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
100 *name = grub_malloc (namesize + 1);
101 if (*name == NULL)
102 return grub_errno;
103 err = grub_disk_read (data->disk, 0,
104 data->hofs + GRUB_DISK_SECTOR_SIZE, namesize,
105 *name);
106 (*name)[namesize] = 0;
107 if (err)
108 return err;
109 data->hofs += GRUB_DISK_SECTOR_SIZE
110 + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) &
111 ~(GRUB_DISK_SECTOR_SIZE - 1));
112 have_longname = 1;
113 continue;
116 if (hd.typeflag == 'K')
118 grub_err_t err;
119 grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
120 if (data->linkname_alloc < linksize + 1)
122 char *n;
123 n = grub_malloc (2 * (linksize + 1));
124 if (!n)
125 return grub_errno;
126 grub_free (data->linkname);
127 data->linkname = n;
128 data->linkname_alloc = 2 * (linksize + 1);
131 err = grub_disk_read (data->disk, 0,
132 data->hofs + GRUB_DISK_SECTOR_SIZE, linksize,
133 data->linkname);
134 if (err)
135 return err;
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));
140 have_longlink = 1;
141 continue;
144 if (!have_longname)
146 grub_size_t extra_size = 0;
148 while (extra_size < sizeof (hd.prefix)
149 && hd.prefix[extra_size])
150 extra_size++;
151 *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
152 if (*name == NULL)
153 return grub_errno;
154 if (hd.prefix[0])
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));
167 if (mtime)
168 *mtime = read_number (hd.mtime, sizeof (hd.mtime));
169 if (mode)
171 *mode = read_number (hd.mode, sizeof (hd.mode));
172 switch (hd.typeflag)
174 /* Hardlink. */
175 case '1':
176 /* Symlink. */
177 case '2':
178 *mode |= GRUB_ARCHELP_ATTR_LNK;
179 break;
180 case '0':
181 *mode |= GRUB_ARCHELP_ATTR_FILE;
182 break;
183 case '5':
184 *mode |= GRUB_ARCHELP_ATTR_DIR;
185 break;
188 if (!have_longlink)
190 if (data->linkname_alloc < 101)
192 char *n;
193 n = grub_malloc (101);
194 if (!n)
195 return grub_errno;
196 grub_free (data->linkname);
197 data->linkname = n;
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;
208 static char *
209 grub_cpio_get_link_target (struct grub_archelp_data *data)
211 return grub_strdup (data->linkname);
214 static void
215 grub_cpio_rewind (struct grub_archelp_data *data)
217 data->next_hofs = 0;
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)
230 struct head hd;
231 struct grub_archelp_data *data;
233 if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd))
234 goto fail;
236 if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
237 goto fail;
239 data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data));
240 if (!data)
241 goto fail;
243 data->disk = disk;
245 return data;
247 fail:
248 grub_error (GRUB_ERR_BAD_FS, "not a tarfs filesystem");
249 return 0;
252 static grub_err_t
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;
257 grub_err_t err;
259 data = grub_cpio_mount (device->disk);
260 if (!data)
261 return grub_errno;
263 err = grub_archelp_dir (data, &arcops,
264 path_in, hook, hook_data);
266 grub_free (data->linkname);
267 grub_free (data);
269 return err;
272 static grub_err_t
273 grub_cpio_open (grub_file_t file, const char *name_in)
275 struct grub_archelp_data *data;
276 grub_err_t err;
278 data = grub_cpio_mount (file->device->disk);
279 if (!data)
280 return grub_errno;
282 err = grub_archelp_open (data, &arcops, name_in);
283 if (err)
285 grub_free (data->linkname);
286 grub_free (data);
288 else
290 file->data = data;
291 file->size = data->size;
293 return err;
296 static grub_ssize_t
297 grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
299 struct grub_archelp_data *data;
300 grub_ssize_t ret;
302 data = file->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;
310 return ret;
313 static grub_err_t
314 grub_cpio_close (grub_file_t file)
316 struct grub_archelp_data *data;
318 data = file->data;
319 grub_free (data->linkname);
320 grub_free (data);
322 return grub_errno;
325 static struct grub_fs grub_cpio_fs = {
326 .name = "tarfs",
327 .dir = grub_cpio_dir,
328 .open = grub_cpio_open,
329 .read = grub_cpio_read,
330 .close = grub_cpio_close,
331 #ifdef GRUB_UTIL
332 .reserved_first_sector = 0,
333 .blocklist_install = 0,
334 #endif
337 GRUB_MOD_INIT (tar)
339 grub_fs_register (&grub_cpio_fs);
342 GRUB_MOD_FINI (tar)
344 grub_fs_unregister (&grub_cpio_fs);