1
/* Filesystem interface abstraction.
3
Copyright (C) 1996 Maurizio Plaza
4
1996,1997,1999 Jakub Jelinek
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
24
#include <stringops.h>
33
static int do_gunzip = 0;
34
static unsigned int *gzipped_blocks;
35
static unsigned int *cur_gzipped_block;
37
static char *filelimit;
38
static int first_block;
41
static int last_blockcnt;
42
static char *gunzip_buffer;
43
static char *gunzip_inp;
44
static char *gunzip_endbuf;
47
/* Externally provided filesystem interfaces */
48
extern struct fs_ops ext2_fs_ops;
49
extern struct fs_ops iso_fs_ops;
50
extern struct fs_ops rom_fs_ops;
51
extern struct fs_ops ufs_fs_ops;
53
/* Array of our supported ops */
54
static struct fs_ops *silo_fs_ops[] = {
62
static struct fs_ops *cur_ops;
64
extern jmp_buf gunzip_env;
66
void register_silo_inode (unsigned int mtime, unsigned int size,
67
unsigned int mode, unsigned int uid,
68
unsigned int gid, const char *name,
71
struct silo_inode *sino = (struct silo_inode *)filebuffer;
73
int name_len = strlen(name);
76
if (strlen(match) > name_len || strncmp(match, name, strlen(match)))
79
strncpy((char *)sino->name, name, name_len);
80
sino->name[name_len] = 0;
87
p = strchr((char *)sino->name, 0) + 1;
89
strncpy ((char *)p, symlink, size);
90
((char *)p)[size] = 0;
93
if ((long)p & 3) p += 4 - ((long)p & 3);
94
sino->inolen = p - filebuffer;
100
static unsigned char get_gzip_input (void)
103
if (gunzip_inp < gunzip_endbuf)
104
return *gunzip_inp++;
107
unsigned int first = *cur_gzipped_block++;
110
printf ("\nDecompression error: ran out of compressed data\n");
111
longjmp (gunzip_env, 1);
113
if (first == 0xffffffff) {
116
while (*cur_gzipped_block == 0xffffffff && count < 16) {
120
memset (gunzip_buffer, 0, count * bs);
122
while (*cur_gzipped_block == first + count && count < 16) {
126
if (io_channel_read_blk (fs->io, first, count, gunzip_buffer)) {
127
printf ("\nRead error\n");
128
longjmp (gunzip_env, 1);
131
gunzip_endbuf = gunzip_buffer + count * bs;
132
gunzip_inp = gunzip_buffer;
134
return *gunzip_inp++;
137
static void unget_gzip_input (void)
139
if (gunzip_inp > gunzip_buffer)
142
printf ("\nInternal error\n");
143
longjmp (gunzip_env, 1);
147
static int gunzipped_len = 0;
148
static int do_rotate = 0;
150
static void rotate (void)
152
static int i = 0, slowdown = 0;
153
static char rot[] = "\\|/-";
161
printf ("%c\b", rot[i % 4]);
166
int dump_block (blk_t * blocknr, int blockcnt)
173
if (!first_block && do_gunzip) {
174
if (blockcnt != last_blockcnt + 1) {
177
for (i = blockcnt - last_blockcnt - 1; i > 0; i--)
178
*cur_gzipped_block++ = 0xffffffff;
180
*cur_gzipped_block++ = *blocknr;
181
last_blockcnt = blockcnt;
184
if (*blocknr || block_no) {
185
if (first_block || !*blocknr || blockcnt != last_blockcnt + 1 || (block_no && *blocknr != block_no + block_cnt)) {
190
silo_fatal("File cannot have a hole at beginning");
195
if ((char *)filebuffer + (block_cnt + ((*blocknr) ? (blockcnt - last_blockcnt - 1) : 0)) * bs > filelimit) {
196
silo_fatal("Image too large to fit in destination");
199
if (block_cnt > 0 && io_channel_read_blk (fs->io, block_no, block_cnt, filebuffer))
204
if (*(unsigned char *)filebuffer == 037 &&
205
(((unsigned char *)filebuffer)[1] == 0213 ||
206
((unsigned char *)filebuffer)[1] == 0236)) { /* gzip magic */
207
unsigned long sa = (unsigned long)&_start;
208
gunzip_buffer = malloc (16 * bs);
209
memcpy (gunzip_buffer, filebuffer, bs);
210
gzipped_blocks = (unsigned int *) malloc ((sa / 512) * sizeof (int));
211
cur_gzipped_block = gzipped_blocks;
212
*cur_gzipped_block++ = *blocknr;
213
printf ("Uncompressing image...\n");
222
filebuffer += block_cnt * bs;
223
if (*blocknr && blockcnt && blockcnt != last_blockcnt + 1) {
224
memset (filebuffer, 0, (blockcnt - last_blockcnt - 1) * bs);
225
filebuffer += (blockcnt - last_blockcnt - 1) * bs;
235
last_blockcnt = blockcnt;
241
int dump_finish (void)
245
if (dump_block (&tmp, 0))
250
*cur_gzipped_block++ = 0;
251
cur_gzipped_block = gzipped_blocks + 1;
252
gunzip_endbuf = gunzip_buffer + bs;
253
gunzip_inp = gunzip_buffer;
254
if ((gunzipped_len = decompress (filebuffer, filelimit, get_gzip_input, unget_gzip_input)) < 0) {
255
free (gzipped_blocks);
256
free (gunzip_buffer);
263
static int dump_device_range (char *filename, char *bogusdev, int *len,
264
void (*lenfunc)(int, char **, char **))
266
/* Range of blocks on physical block device */
267
int start = 0, end = -1;
271
p = strchr (filename, '-');
273
if (p && *filename >= '0' && *filename <= '9') {
275
start = atoi (filename);
277
p = strchr (filename, ']');
278
if (p && *filename >= '0' && *filename <= '9' && !p[1]) {
280
end = atoi (filename);
284
if (prom_vers == PROM_V0)
285
printf ("\nRanges of physical blocks are specified as {device_name}{partno}[xx-yy]"
286
"\nwhere {} means optional part and xx is the starting block"
287
"\n(chunk of 512 bytes) and yy end (not inclusive, i.e. yy won't be read)\n");
289
printf ("\nRanges of physical blocks are specified as {prom_path;}{partno}[xx-yy]"
290
"\nwhere {} means optional part, partno defaults to 0 (i.e. whole disk)"
291
"\nand xx is the starting block (chunk of 512 bytes) and yy end (not"
292
"\ninclusive, i.e. yy won't be read)\n");
296
(*lenfunc)((end - start) << 9, (char **)&filebuffer, (char **)&filelimit);
297
fs = (ext2_filsys) malloc (sizeof (struct struct_ext2_filsys));
299
if (!((struct struct_io_manager *)(silo_io_manager))->open (bogusdev, 0, &fs->io)) {
302
first_block = do_gunzip;
306
for (tmp = start; tmp < end; tmp++) {
307
if (dump_block (&tmp, tmp - start))
311
if (tmp == end && dump_finish ()) {
314
*len = gunzipped_len;
316
*len = (end - start) << 9;
322
printf ("\nInternal error while loading physical blocks from device\n");
326
int silo_load_file(char *device, int partno, char *filename, unsigned char *buffer,
327
unsigned char *limit, int *len, int cmd,
328
void (*lenfunc)(int, char **, char **))
330
struct silo_inode *sino;
333
char bogusdev[] = "/dev/sdaX";
341
device = silo_disk_get_bootdevice();
345
if (prom_vers == PROM_V0) {
346
if (device[0] == 'f' && device[1] == 'd') {
350
bogusdev[8] = partno + '0';
352
bogusdev[8] = partno + '0';
354
if (silo_disk_setdisk(device) < 0)
357
do_gunzip = cmd & LOADFILE_GZIP;
358
if (cmd & ~LOADFILE_GZIP)
364
filelimit = (char *)limit;
366
if (*filename == '[') {
367
if (cmd & LOADFILE_LS) {
368
if (!(cmd & LOADFILE_QUIET))
369
printf ("You cannot ls a device range\n");
373
retval = dump_device_range (filename, bogdev, len, lenfunc);
377
solaris = 0; /* The UFS module will set this if needed */
378
for (i = 0; silo_fs_ops[i]; i++)
379
if (silo_fs_ops[i]->open(bogdev))
382
if (!silo_fs_ops[i]) {
383
if (!(cmd & LOADFILE_QUIET))
384
silo_fatal("Unable to open filesystem");
387
cur_ops = silo_fs_ops[i];
389
if (cmd & LOADFILE_LS && cur_ops->ls == NULL) {
390
if (!(cmd & LOADFILE_MATCH))
391
printf("\nls is not supported for the `%s' filesystems\n", cur_ops->name);
395
fn_len = strlen(filename);
397
/* Find the inode for the filename. If we are matching, always parse
398
* basedir and basename. */
399
if (cmd & LOADFILE_MATCH && fn_len > 1 && filename[fn_len - 1] != '/') {
400
dir = strdup(filename);
401
if ((match = strrchr(dir, '/')) != NULL && strlen(match) > 1) {
403
if (match != dir) base = dir;
406
retval = cur_ops->namei_follow (base);
410
retval = cur_ops->namei_follow (filename);
414
if (!(cmd & LOADFILE_QUIET)) {
415
printf ("\nCannot find %s (", dir != NULL ? dir : filename);
416
cur_ops->print_error (retval);
425
size = cur_ops->ino_size();
426
(*lenfunc)(size, (char **)&filebuffer, (char **)&filelimit);
427
do_gunzip = cmd & LOADFILE_GZIP;
430
first_block = do_gunzip;
436
if (cur_ops->have_inode) {
437
if (cmd & LOADFILE_LS) {
438
if ((retval = cur_ops->ls())) {
439
if (!(cmd & LOADFILE_MATCH)) {
440
printf("\nError: could not list (");
441
cur_ops->print_error(retval);
446
sino = (struct silo_inode *)filebuffer;
451
retval = cur_ops->dump();
452
if (!retval && !(cmd & LOADFILE_MATCH))
453
printf("\nError loading %s\n", filename);
461
*len = gunzipped_len;
463
*len = cur_ops->ino_size();