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)
82 static grub_dl_t my_mod
;
86 grub_cpio_find_file (struct grub_cpio_data
*data
, char **name
,
89 if (data
->mode
== MODE_BCPIO
)
94 (data
->disk
, 0, data
->hofs
, sizeof (hd
), (char *) &hd
))
97 if (hd
.magic
!= MAGIC_BCPIO
)
98 return grub_error (GRUB_ERR_BAD_FS
, "Invalid cpio archive");
100 data
->size
= (((grub_uint32_t
) hd
.filesize_1
) << 16) + hd
.filesize_2
;
105 if ((*name
= grub_malloc (hd
.namesize
)) == NULL
)
108 if (grub_disk_read (data
->disk
, 0, data
->hofs
+ sizeof (hd
),
115 if (data
->size
== 0 && hd
.mode
== 0 && hd
.namesize
== 11 + 1
116 && ! grub_memcmp(*name
, "TRAILER!!!", 11))
119 return GRUB_ERR_NONE
;
122 data
->dofs
= data
->hofs
+ sizeof (hd
) + hd
.namesize
;
123 *ofs
= data
->dofs
+ data
->size
;
129 struct HEAD_USTAR hd
;
132 (data
->disk
, 0, data
->hofs
, sizeof (hd
), (char *) &hd
))
138 return GRUB_ERR_NONE
;
141 if (grub_memcmp (hd
.magic
, MAGIC_USTAR
, sizeof (MAGIC_USTAR
) - 1))
142 return grub_error (GRUB_ERR_BAD_FS
, "Invalid tar archive");
144 if ((*name
= grub_strdup (hd
.name
)) == NULL
)
147 data
->size
= grub_strtoul (hd
.size
, NULL
, 8);
148 data
->dofs
= data
->hofs
+ GRUB_DISK_SECTOR_SIZE
;
149 *ofs
= data
->dofs
+ ((data
->size
+ GRUB_DISK_SECTOR_SIZE
- 1) &
150 ~(GRUB_DISK_SECTOR_SIZE
- 1));
152 return GRUB_ERR_NONE
;
155 static struct grub_cpio_data
*
156 grub_cpio_mount (grub_disk_t disk
)
159 struct grub_cpio_data
*data
;
162 if (grub_disk_read (disk
, 0, 0, sizeof (hd
), hd
))
165 if (((struct HEAD_BCPIO
*) hd
)->magic
== MAGIC_BCPIO
)
167 else if (!grub_memcmp (((struct HEAD_USTAR
*) hd
)->magic
, MAGIC_USTAR
,
168 sizeof (MAGIC_USTAR
) - 1))
173 data
= (struct grub_cpio_data
*) grub_malloc (sizeof (*data
));
183 grub_error (GRUB_ERR_BAD_FS
, "not a cpio filesystem");
188 grub_cpio_dir (grub_device_t device
, const char *path
,
189 int (*hook
) (const char *filename
, int dir
))
191 struct grub_cpio_data
*data
;
198 grub_dl_ref (my_mod
);
203 data
= grub_cpio_mount (device
->disk
);
208 len
= grub_strlen (path
) - 1;
213 if (grub_cpio_find_file (data
, &name
, &ofs
))
219 if (grub_memcmp (np
, name
, len
) == 0)
227 p
= grub_strchr (name
+ len
, '/');
231 if ((!prev
) || (grub_strcmp (prev
, name
) != 0))
233 hook (name
+ len
, p
!= NULL
);
253 grub_dl_unref (my_mod
);
260 grub_cpio_open (grub_file_t file
, const char *name
)
262 struct grub_cpio_data
*data
;
268 grub_dl_ref (my_mod
);
271 data
= grub_cpio_mount (file
->device
->disk
);
278 if (grub_cpio_find_file (data
, &fn
, &ofs
))
283 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
287 /* Compare NAME and FN by hand in order to cope with duplicate
293 if (name
[i
] != fn
[j
])
299 if (name
[i
] == '/' && name
[i
+1] == '/')
307 file
->size
= data
->size
;
310 return GRUB_ERR_NONE
;
324 grub_dl_unref (my_mod
);
331 grub_cpio_read (grub_file_t file
, char *buf
, grub_size_t len
)
333 struct grub_cpio_data
*data
;
336 return (grub_disk_read (data
->disk
, 0, data
->dofs
+ file
->offset
,
337 len
, buf
)) ? -1 : (grub_ssize_t
) len
;
341 grub_cpio_close (grub_file_t file
)
343 grub_free (file
->data
);
346 grub_dl_unref (my_mod
);
352 static struct grub_fs grub_cpio_fs
= {
354 .dir
= grub_cpio_dir
,
355 .open
= grub_cpio_open
,
356 .read
= grub_cpio_read
,
357 .close
= grub_cpio_close
,
364 grub_fs_register (&grub_cpio_fs
);
372 grub_fs_unregister (&grub_cpio_fs
);