~ubuntu-branches/ubuntu/quantal/silo/quantal

« back to all changes in this revision

Viewing changes to second/file.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-10-25 09:28:08 UTC
  • mfrom: (15.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071025092808-1yhj12t7s4zqsfu5
Tags: 1.4.13a+git20070930-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Build with -fno-stack-protector.
  - Change silo.postinst to automatically update the boot block without
    invoking siloconfig and keep asking questions on upgrades.
  - Convert silo.conf to use /dev/disk/by-uuid.
  - Ubuntu maintainer foobar.
  - Fix debian/rules call to dh_installdocs.
  - Drop the requirement of gcc-4.1 and start using default gcc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Filesystem interface abstraction.
 
2
   
 
3
   Copyright (C) 1996 Maurizio Plaza
 
4
                 1996,1997,1999 Jakub Jelinek
 
5
                 2001 Ben Collins
 
6
   
 
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.
 
11
   
 
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.
 
16
 
 
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,
 
20
   USA.  */
 
21
 
 
22
#include <silo.h>
 
23
#include <file.h>
 
24
#include <stringops.h>
 
25
#include <setjmp.h>
 
26
 
 
27
ext2_filsys fs = 0;
 
28
 
 
29
unsigned int bs;
 
30
void *filebuffer;
 
31
ino_t root, cwd;
 
32
 
 
33
static int do_gunzip = 0;
 
34
static unsigned int *gzipped_blocks;
 
35
static unsigned int *cur_gzipped_block;
 
36
 
 
37
static char *filelimit;
 
38
static int first_block;
 
39
static int block_no;
 
40
static int block_cnt;
 
41
static int last_blockcnt;
 
42
static char *gunzip_buffer;
 
43
static char *gunzip_inp;
 
44
static char *gunzip_endbuf;
 
45
static char *match;
 
46
 
 
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;
 
52
 
 
53
/* Array of our supported ops */
 
54
static struct fs_ops *silo_fs_ops[] = {
 
55
    &ext2_fs_ops,
 
56
    &iso_fs_ops,
 
57
    &rom_fs_ops,
 
58
    &ufs_fs_ops,
 
59
    NULL,
 
60
};
 
61
 
 
62
static struct fs_ops *cur_ops;
 
63
 
 
64
extern jmp_buf gunzip_env;
 
65
 
 
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,
 
69
                          const char *symlink)
 
70
{
 
71
    struct silo_inode *sino = (struct silo_inode *)filebuffer;
 
72
    void *p;
 
73
    int name_len = strlen(name);
 
74
 
 
75
    if (match != NULL)
 
76
        if (strlen(match) > name_len || strncmp(match, name, strlen(match)))
 
77
            return;
 
78
 
 
79
    strncpy((char *)sino->name, name, name_len);
 
80
    sino->name[name_len] = 0;
 
81
    sino->mtime = mtime;
 
82
    sino->size = size;
 
83
    sino->mode = mode;
 
84
    sino->uid = uid;
 
85
    sino->gid = gid;
 
86
 
 
87
    p = strchr((char *)sino->name, 0) + 1;
 
88
    if (symlink) {
 
89
        strncpy ((char *)p, symlink, size);
 
90
        ((char *)p)[size] = 0;
 
91
        p += size + 1;
 
92
    }
 
93
    if ((long)p & 3) p += 4 - ((long)p & 3);
 
94
    sino->inolen = p - filebuffer;
 
95
    filebuffer = p;
 
96
 
 
97
    return;
 
98
}
 
99
 
 
100
static unsigned char get_gzip_input (void)
 
101
{
 
102
 
 
103
    if (gunzip_inp < gunzip_endbuf)
 
104
        return *gunzip_inp++;
 
105
    {
 
106
        int count = 1;
 
107
        unsigned int first = *cur_gzipped_block++;
 
108
 
 
109
        if (!first) {
 
110
            printf ("\nDecompression error: ran out of compressed data\n");
 
111
            longjmp (gunzip_env, 1);
 
112
        }
 
113
        if (first == 0xffffffff) {
 
114
            /* Hole */
 
115
            
 
116
            while (*cur_gzipped_block == 0xffffffff && count < 16) {
 
117
                count++;
 
118
                cur_gzipped_block++;
 
119
            }
 
120
            memset (gunzip_buffer, 0, count * bs);
 
121
        } else {
 
122
            while (*cur_gzipped_block == first + count && count < 16) {
 
123
                count++;
 
124
                cur_gzipped_block++;
 
125
            }
 
126
            if (io_channel_read_blk (fs->io, first, count, gunzip_buffer)) {
 
127
                printf ("\nRead error\n");
 
128
                longjmp (gunzip_env, 1);
 
129
            }
 
130
        }
 
131
        gunzip_endbuf = gunzip_buffer + count * bs;
 
132
        gunzip_inp = gunzip_buffer;
 
133
    }
 
134
    return *gunzip_inp++;
 
135
}
 
136
 
 
137
static void unget_gzip_input (void)
 
138
{
 
139
    if (gunzip_inp > gunzip_buffer)
 
140
        gunzip_inp--;
 
141
    else {
 
142
        printf ("\nInternal error\n");
 
143
        longjmp (gunzip_env, 1);
 
144
    }
 
145
}
 
146
 
 
147
static int gunzipped_len = 0;
 
148
static int do_rotate = 0;
 
149
 
 
150
static void rotate (void)
 
151
{
 
152
    static int i = 0, slowdown = 0;
 
153
    static char rot[] = "\\|/-";
 
154
 
 
155
    if (!do_rotate)
 
156
        return;
 
157
 
 
158
    if (slowdown++ % 4)
 
159
        return;
 
160
 
 
161
    printf ("%c\b", rot[i % 4]);
 
162
 
 
163
    i++;
 
164
}
 
165
 
 
166
int dump_block (blk_t * blocknr, int blockcnt)
 
167
{
 
168
    if (blockcnt < 0)
 
169
        return 0;
 
170
 
 
171
    rotate();
 
172
 
 
173
    if (!first_block && do_gunzip) {
 
174
        if (blockcnt != last_blockcnt + 1) {
 
175
            int i;
 
176
 
 
177
            for (i = blockcnt - last_blockcnt - 1; i > 0; i--)
 
178
                *cur_gzipped_block++ = 0xffffffff;
 
179
        }
 
180
        *cur_gzipped_block++ = *blocknr;
 
181
        last_blockcnt = blockcnt;
 
182
        return 0;
 
183
    }
 
184
    if (*blocknr || block_no) {
 
185
        if (first_block || !*blocknr || blockcnt != last_blockcnt + 1 || (block_no && *blocknr != block_no + block_cnt)) {
 
186
            if (first_block) {
 
187
                block_no = *blocknr;
 
188
                block_cnt = 1;
 
189
                if (blockcnt) {
 
190
                    silo_fatal("File cannot have a hole at beginning");
 
191
                    return BLOCK_ABORT;
 
192
                }
 
193
                last_blockcnt = -1;
 
194
            }
 
195
            if ((char *)filebuffer + (block_cnt + ((*blocknr) ? (blockcnt - last_blockcnt - 1) : 0)) * bs > filelimit) {
 
196
                silo_fatal("Image too large to fit in destination");
 
197
                return BLOCK_ABORT;
 
198
            }
 
199
            if (block_cnt > 0 && io_channel_read_blk (fs->io, block_no, block_cnt, filebuffer))
 
200
                return BLOCK_ABORT;
 
201
            if (first_block) {
 
202
                first_block = 0;
 
203
                last_blockcnt = 0;
 
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");
 
214
                    return 0;
 
215
                }
 
216
                do_gunzip = 0;
 
217
                filebuffer += bs;
 
218
                block_no = 0;
 
219
                block_cnt = 0;
 
220
                return 0;
 
221
            }
 
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;
 
226
            }
 
227
            block_no = 0;
 
228
        }
 
229
        if (*blocknr) {
 
230
            if (!block_no) {
 
231
                block_no = *blocknr;
 
232
                block_cnt = 1;
 
233
            } else
 
234
                block_cnt++;
 
235
            last_blockcnt = blockcnt;
 
236
        }
 
237
    }
 
238
    return 0;
 
239
}
 
240
 
 
241
int dump_finish (void)
 
242
{
 
243
    if (block_no) {
 
244
        blk_t tmp = 0;
 
245
        if (dump_block (&tmp, 0))
 
246
            return 0;
 
247
    }
 
248
 
 
249
    if (do_gunzip) {
 
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);
 
257
            return 0;
 
258
        }
 
259
    }
 
260
    return 1;
 
261
}
 
262
 
 
263
static int dump_device_range (char *filename, char *bogusdev, int *len,
 
264
                              void (*lenfunc)(int, char **, char **))
 
265
{
 
266
    /* Range of blocks on physical block device */
 
267
    int start = 0, end = -1;
 
268
    char *p;
 
269
 
 
270
    bs = 512;
 
271
    p = strchr (filename, '-');
 
272
    filename++;
 
273
    if (p && *filename >= '0' && *filename <= '9') {
 
274
        *p = 0;
 
275
        start = atoi (filename);
 
276
        filename = p + 1;
 
277
        p = strchr (filename, ']');
 
278
        if (p && *filename >= '0' && *filename <= '9' && !p[1]) {
 
279
            *p = 0;
 
280
            end = atoi (filename);
 
281
        }
 
282
    }
 
283
    if (end == -1) {
 
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");
 
288
        else
 
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");
 
293
        return 0;
 
294
    }
 
295
    if (lenfunc)
 
296
        (*lenfunc)((end - start) << 9, (char **)&filebuffer, (char **)&filelimit);
 
297
    fs = (ext2_filsys) malloc (sizeof (struct struct_ext2_filsys));
 
298
    if (fs) {
 
299
        if (!((struct struct_io_manager *)(silo_io_manager))->open (bogusdev, 0, &fs->io)) {
 
300
            blk_t tmp;
 
301
 
 
302
            first_block = do_gunzip;
 
303
            block_no = 0;
 
304
            last_blockcnt = 0;
 
305
            block_cnt = 0;
 
306
            for (tmp = start; tmp < end; tmp++) {
 
307
                if (dump_block (&tmp, tmp - start))
 
308
                    break;
 
309
            }
 
310
 
 
311
            if (tmp == end && dump_finish ()) {
 
312
                if (len) {
 
313
                    if (do_gunzip)
 
314
                        *len = gunzipped_len;
 
315
                    else
 
316
                        *len = (end - start) << 9;
 
317
                }
 
318
                return 1;
 
319
            }
 
320
        }
 
321
    }
 
322
    printf ("\nInternal error while loading physical blocks from device\n");
 
323
    return 0;
 
324
}
 
325
 
 
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 **))
 
329
{
 
330
    struct silo_inode *sino;
 
331
    int retval = 0, i;
 
332
    int size = -1;
 
333
    char bogusdev[] = "/dev/sdaX";
 
334
    char *bogdev;
 
335
    void *mmark;
 
336
    char *dir = NULL;
 
337
    size_t fn_len;
 
338
 
 
339
    mark (&mmark);
 
340
    if (!device)
 
341
        device = silo_disk_get_bootdevice();
 
342
 
 
343
    bogdev = bogusdev;
 
344
 
 
345
    if (prom_vers == PROM_V0) {
 
346
        if (device[0] == 'f' && device[1] == 'd') {
 
347
            device = "fd()";
 
348
            bogdev = "/dev/fd0";
 
349
        } else
 
350
            bogusdev[8] = partno + '0';
 
351
    } else
 
352
        bogusdev[8] = partno + '0';
 
353
 
 
354
    if (silo_disk_setdisk(device) < 0)
 
355
        goto done_2;
 
356
 
 
357
    do_gunzip = cmd & LOADFILE_GZIP;
 
358
    if (cmd & ~LOADFILE_GZIP)
 
359
        do_rotate = 0;
 
360
    else
 
361
        do_rotate = 1;
 
362
 
 
363
    filebuffer = buffer;
 
364
    filelimit = (char *)limit;
 
365
 
 
366
    if (*filename == '[') {
 
367
        if (cmd & LOADFILE_LS) {
 
368
            if (!(cmd & LOADFILE_QUIET))
 
369
                printf ("You cannot ls a device range\n");
 
370
            goto done_2;
 
371
        }
 
372
        solaris = 0;
 
373
        retval = dump_device_range (filename, bogdev, len, lenfunc);
 
374
        goto done_2;
 
375
    }
 
376
 
 
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))
 
380
            break;
 
381
 
 
382
    if (!silo_fs_ops[i]) {
 
383
        if (!(cmd & LOADFILE_QUIET))
 
384
            silo_fatal("Unable to open filesystem");
 
385
        goto done_2;
 
386
    } else
 
387
        cur_ops = silo_fs_ops[i];
 
388
 
 
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);
 
392
        goto done_1;
 
393
    }
 
394
 
 
395
    fn_len = strlen(filename);
 
396
 
 
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) {
 
402
            char *base = "/";
 
403
            if (match != dir) base = dir;
 
404
            *match = '\0';
 
405
            match++;
 
406
            retval = cur_ops->namei_follow (base);
 
407
        }
 
408
    } else {
 
409
        match = NULL;
 
410
        retval = cur_ops->namei_follow (filename);
 
411
    }
 
412
 
 
413
    if (retval) {
 
414
        if (!(cmd & LOADFILE_QUIET)) {
 
415
            printf ("\nCannot find %s (", dir != NULL ? dir : filename);
 
416
            cur_ops->print_error (retval);
 
417
            printf (")\n");
 
418
        }
 
419
        retval = 0;
 
420
        goto done_1;
 
421
    }
 
422
 
 
423
    if (lenfunc) {
 
424
        do_gunzip = 0;
 
425
        size = cur_ops->ino_size();
 
426
        (*lenfunc)(size, (char **)&filebuffer, (char **)&filelimit);
 
427
        do_gunzip = cmd & LOADFILE_GZIP;
 
428
    }
 
429
 
 
430
    first_block = do_gunzip;
 
431
    last_blockcnt = 0;
 
432
    block_no = 0;
 
433
    block_cnt = 0;
 
434
    retval = 0;
 
435
 
 
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);
 
442
                    printf(").\n");
 
443
                }
 
444
                retval = 0;
 
445
            } else {
 
446
                sino = (struct silo_inode *)filebuffer;
 
447
                sino->inolen = 0;
 
448
                retval = 1;
 
449
            }
 
450
        } else {
 
451
            retval = cur_ops->dump();
 
452
            if (!retval && !(cmd & LOADFILE_MATCH))
 
453
                printf("\nError loading %s\n", filename);
 
454
        }
 
455
    }
 
456
 
 
457
    if (retval && len) {
 
458
        if (size != -1)
 
459
            *len = size;
 
460
        else if (do_gunzip)
 
461
            *len = gunzipped_len;
 
462
        else
 
463
            *len = cur_ops->ino_size();
 
464
    }
 
465
 
 
466
done_1:
 
467
    if (dir) free(dir);
 
468
    cur_ops->close();
 
469
 
 
470
done_2:
 
471
    release (mmark);
 
472
 
 
473
    return retval;
 
474
}