~ubuntu-branches/ubuntu/lucid/silo/lucid

« back to all changes in this revision

Viewing changes to second/fs/romfs.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-10-25 09:28:08 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20071025092808-pnva6x2ggmlkd65e
Tags: upstream-1.4.13a+git20070930
ImportĀ upstreamĀ versionĀ 1.4.13a+git20070930

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Linux ROMFS Interface for SILO filesystem access routines
 
2
   
 
3
   Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
 
4
                 1997 Janos Farkas <chexum@shadow.banki.hu>
 
5
                 2001 Ben Collins <bcollins@debian.org>
 
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 <ctype.h>
 
23
#include <sys/types.h>
 
24
#include <errno.h>
 
25
#include <silo.h>
 
26
#include <file.h>
 
27
#include <stringops.h>
 
28
#include <linux/romfs_fs.h>
 
29
 
 
30
/* Reuse and abuse */
 
31
typedef ext2_filsys romfs_filsys;
 
32
 
 
33
static ino_t inode = 0;
 
34
static int link_count = 0;
 
35
 
 
36
#define SUPROMFS (struct romfs_super_block *)(fs->io->private_data)
 
37
#define BLOCK_SIZE_BITS 9 /* 512 */
 
38
#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
 
39
 
 
40
static int inline min(int a, int b)
 
41
{
 
42
        return a<b ? a : b;
 
43
}
 
44
 
 
45
static __s32
 
46
romfs_checksum(void *data, int size)
 
47
{
 
48
        __s32 sum, *ptr;
 
49
 
 
50
        sum = 0; ptr = data;
 
51
        size>>=2;
 
52
        while (size>0) {
 
53
                sum += *ptr++;
 
54
                size--;
 
55
        }
 
56
        return sum;
 
57
}
 
58
 
 
59
static struct romfs_super_block *romfs_read_super(romfs_filsys fs)
 
60
{
 
61
    struct romfs_super_block *rsb;
 
62
 
 
63
    /* The 2048 comes from the space needed to make room for the first
 
64
     * stage loader. The image has to be created with "-A 2048,/.."
 
65
     */
 
66
    rsb = (struct romfs_super_block *) malloc (2048+ROMBSIZE);
 
67
    if (!rsb) return NULL;
 
68
 
 
69
    if (io_channel_read_blk (fs->io, 0, 1, (char *)rsb))
 
70
        return NULL;
 
71
 
 
72
    if (strncmp((char *)rsb, "-rom1fs-", 8) || rsb->size < ROMFH_SIZE)
 
73
        return NULL;
 
74
 
 
75
    if (romfs_checksum(rsb, min(rsb->size,512))) {
 
76
        printf("ROMFS: Bad initial checksum.\n");
 
77
        return NULL;
 
78
    }
 
79
 
 
80
    rsb->checksum = strlen(rsb->name);
 
81
    if (rsb->checksum > ROMFS_MAXFN) rsb->checksum = ROMFS_MAXFN;
 
82
    rsb->checksum += (ROMFH_SIZE + 1 + ROMFH_PAD);
 
83
    rsb->checksum &= ROMFH_MASK;
 
84
    rsb->word0 = -1;
 
85
    rsb->word1 = -1;
 
86
    rsb->name[0] = 0;
 
87
    return rsb;
 
88
}
 
89
 
 
90
static int romfs_copyfrom(romfs_filsys fs, void *dest, unsigned long offset, unsigned long count)
 
91
{
 
92
    struct romfs_super_block *rsb = SUPROMFS;
 
93
    unsigned long res;
 
94
    char buffer[ROMBSIZE];
 
95
    int maxsize;
 
96
 
 
97
    if ((offset>>ROMBSBITS)<<ROMBSBITS >= rsb->size+ROMBSIZE || count > rsb->size ||
 
98
            offset+count>rsb->size+ROMBSIZE)
 
99
        return -1;
 
100
 
 
101
    maxsize = min(count, (ROMBSIZE - (offset & ROMBMASK)));
 
102
    res = maxsize;
 
103
 
 
104
    if (io_channel_read_blk (fs->io, offset>>ROMBSBITS, 1, buffer))
 
105
        return -1;
 
106
 
 
107
    memcpy(dest, buffer + (offset & ROMBMASK), maxsize);
 
108
 
 
109
    while (res < count) {
 
110
        offset += maxsize;
 
111
 
 
112
        if (io_channel_read_blk (fs->io, offset>>ROMBSBITS, 1, buffer))
 
113
            return -1;
 
114
 
 
115
        dest += maxsize;
 
116
        maxsize = min(count-res, ROMBSIZE);
 
117
 
 
118
        memcpy(dest, buffer, maxsize);
 
119
 
 
120
        res += maxsize;
 
121
    }
 
122
    return 0;
 
123
}
 
124
 
 
125
static int romfs_read_inode (romfs_filsys fs, ino_t inode, struct romfs_inode *ui)
 
126
{
 
127
    struct romfs_inode romfsip;
 
128
    struct romfs_super_block *rsb = SUPROMFS;
 
129
 
 
130
    if (inode < rsb->checksum || inode >= rsb->size)
 
131
        return -1;
 
132
 
 
133
    if (romfs_copyfrom (fs, &romfsip, inode, ROMFH_SIZE))
 
134
        return -1;
 
135
 
 
136
    *ui = romfsip;
 
137
    return 0;
 
138
}
 
139
 
 
140
static mode_t romfs_modemap[] =
 
141
{
 
142
    0, LINUX_S_IFDIR+0555, LINUX_S_IFREG+0444, LINUX_S_IFLNK+0777,
 
143
       LINUX_S_IFBLK+0600, LINUX_S_IFCHR+0600, LINUX_S_IFSOCK+0644,
 
144
       LINUX_S_IFIFO+0644
 
145
};
 
146
 
 
147
static int romfs_lookup (romfs_filsys fs, struct romfs_inode *dirui,
 
148
                       const char *name, int len, ino_t *result)
 
149
{
 
150
    char buffer [8192];
 
151
    struct romfs_inode ui;
 
152
    ino_t dir = dirui->spec & ROMFH_MASK;
 
153
    struct romfs_super_block *rsb = SUPROMFS;
 
154
 
 
155
    while (dir && dir < rsb->size) {
 
156
        if (romfs_read_inode (fs, dir, &ui))
 
157
            return -1;
 
158
 
 
159
        if (romfs_copyfrom (fs, buffer, dir + ROMFH_SIZE, ROMFS_MAXFN))
 
160
            return -1;
 
161
 
 
162
        if (result == NULL) {
 
163
            /* We aren't returning an inode, so we must be iterating */
 
164
            char symlink[1024] = {0};
 
165
            unsigned int mode = romfs_modemap[ui.next & ROMFH_TYPE];
 
166
 
 
167
            /* Check for symlinks */
 
168
            if ((ui.next & ROMFH_TYPE) == ROMFH_SYM) {
 
169
                int offset = dir + ROMFH_SIZE + ((strlen(buffer) + ROMFH_SIZE) & ROMFH_MASK);
 
170
                if (romfs_copyfrom (fs, symlink, offset, ROMFS_MAXFN))
 
171
                    return -1;
 
172
            }
 
173
 
 
174
            if (buffer[0] == '.' && (!buffer[1] || (buffer[1] == '.' && !buffer[2])))
 
175
                mode = LINUX_S_IFDIR+0555;
 
176
 
 
177
            register_silo_inode(0, ui.size, mode,
 
178
                                0, 0, buffer, symlink[0] ? symlink : NULL);
 
179
 
 
180
        } else if ((!len && buffer[0] == '.' && !buffer[1]) ||
 
181
            (strlen(buffer) == len && !memcmp(buffer, name, len))) {
 
182
            if ((ui.next & ROMFH_TYPE) == ROMFH_HRD)
 
183
                dir = ui.spec;
 
184
            *result = dir;
 
185
            return 0;
 
186
        }
 
187
        dir = ui.next & ROMFH_MASK;
 
188
    }
 
189
    if (result == NULL)
 
190
        return 0;
 
191
 
 
192
    return -1;
 
193
}
 
194
 
 
195
static int open_namei(romfs_filsys, const char *, ino_t *, ino_t);
 
196
 
 
197
static int romfs_follow_link(romfs_filsys fs, ino_t dir, ino_t inode,
 
198
                           struct romfs_inode *ui, ino_t *res_inode)
 
199
{
 
200
    int error;
 
201
    char buffer[1024];
 
202
 
 
203
    if ((ui->next & ROMFH_TYPE) != ROMFH_SYM) {
 
204
        *res_inode = inode;
 
205
        return 0;
 
206
    }
 
207
    if (link_count > 5) {
 
208
        printf ("ROMFS: Symlink loop.\n");
 
209
        return -1; /* Loop */
 
210
    }
 
211
    if (romfs_copyfrom (fs, buffer, inode + ROMFH_SIZE, ROMFS_MAXFN))
 
212
        return -1;
 
213
    error = inode + ROMFH_SIZE + ((strlen(buffer) + ROMFH_SIZE) & ROMFH_MASK);
 
214
    if (romfs_copyfrom (fs, buffer, error, ROMFS_MAXFN))
 
215
        return -1;
 
216
    link_count++;
 
217
    error = open_namei (fs, buffer, res_inode, dir);
 
218
    link_count--;
 
219
    return error;
 
220
}
 
221
 
 
222
static int dir_namei(romfs_filsys fs, const char *pathname, int *namelen, 
 
223
                     const char **name, ino_t base, ino_t *res_inode)
 
224
{
 
225
    char c;
 
226
    const char *thisname;
 
227
    int len;
 
228
    struct romfs_inode ub;
 
229
    ino_t inode;
 
230
 
 
231
    if ((c = *pathname) == '/') {
 
232
        base = root;
 
233
        pathname++;
 
234
    }
 
235
 
 
236
    if (romfs_read_inode (fs, base, &ub)) return -1;
 
237
    while (1) {
 
238
        thisname = pathname;
 
239
        for(len=0;(c = *(pathname++))&&(c != '/');len++);
 
240
        if (!c) break;
 
241
        if (romfs_lookup (fs, &ub, thisname, len, &inode)) return -1;
 
242
        if (romfs_read_inode (fs, inode, &ub)) return -1;
 
243
        if (romfs_follow_link (fs, base, inode, &ub, &base)) return -1;
 
244
        if (base != inode && romfs_read_inode (fs, base, &ub)) return -1;
 
245
    }
 
246
    *name = thisname;
 
247
    *namelen = len;
 
248
    *res_inode = base;
 
249
    return 0;
 
250
}
 
251
 
 
252
static int open_namei(romfs_filsys fs, const char *pathname, 
 
253
                      ino_t *res_inode, ino_t base)
 
254
{
 
255
    const char *basename;
 
256
    int namelen;
 
257
    ino_t dir, inode;
 
258
    struct romfs_inode ub;
 
259
 
 
260
    if (dir_namei(fs, pathname, &namelen, &basename, base, &dir)) return -1;
 
261
    if (!namelen) {                     /* special case: '/usr/' etc */
 
262
        *res_inode=dir;
 
263
        return 0;
 
264
    }
 
265
    if (romfs_read_inode (fs, dir, &ub)) return -1;
 
266
    if (romfs_lookup (fs, &ub, basename, namelen, &inode)) return -1;
 
267
    if (romfs_read_inode (fs, inode, &ub)) return -1;
 
268
    if (romfs_follow_link (fs, dir, inode, &ub, &inode)) return -1;
 
269
    *res_inode = inode;
 
270
    return 0;
 
271
}
 
272
 
 
273
struct fs_ops rom_fs_ops;
 
274
 
 
275
static int namei_follow_romfs (const char *filename)
 
276
{
 
277
    int ret;
 
278
    
 
279
    link_count = 0;
 
280
 
 
281
    ret = open_namei (fs, filename, &inode, root);
 
282
    rom_fs_ops.have_inode = (ret) ? 0 : 1;
 
283
 
 
284
    return ret;
 
285
}
 
286
 
 
287
static void romfs_close(void)
 
288
{
 
289
    free (fs->io);
 
290
    free (fs);
 
291
}
 
292
 
 
293
static int romfs_block_iterate(void)
 
294
{
 
295
    struct romfs_inode ub;
 
296
    int i;
 
297
    blk_t nr;
 
298
    int size;
 
299
    char buffer[ROMFS_MAXFN];
 
300
 
 
301
    if (romfs_read_inode (fs, inode, &ub)) return 0;
 
302
    if (romfs_copyfrom (fs, buffer, inode + ROMFH_SIZE, ROMFS_MAXFN)) return 0;
 
303
    nr = inode + ROMFH_SIZE + ((strlen(buffer) + ROMFH_SIZE) & ROMFH_MASK);
 
304
    if (nr & ROMBMASK) {
 
305
        printf("ROMFS: File not aligned on a %dB boundary.\n", ROMBSIZE);
 
306
        return 0;
 
307
    }
 
308
    size = (ub.size + ROMBMASK) / ROMBSIZE;
 
309
    nr /= ROMBSIZE;
 
310
    for (i = 0; i < size; i++, nr++) {
 
311
        switch (dump_block (&nr, i)) {
 
312
            case BLOCK_ABORT:
 
313
            case BLOCK_ERROR:
 
314
                return 0;
 
315
        }
 
316
    }
 
317
    return dump_finish();
 
318
}
 
319
 
 
320
static int open_romfs (char *device)
 
321
{
 
322
    fs = (romfs_filsys) malloc (sizeof (struct struct_ext2_filsys));
 
323
    if (!fs)
 
324
        return 0;
 
325
 
 
326
    if (((struct struct_io_manager *)(silo_io_manager))->open (device, 0, &fs->io))
 
327
        return 0;
 
328
 
 
329
    io_channel_set_blksize (fs->io, ROMBSIZE);
 
330
 
 
331
    fs->io->private_data = romfs_read_super(fs);
 
332
    if (!fs->io->private_data)
 
333
        return 0;
 
334
 
 
335
    root = ((struct romfs_super_block *)(fs->io->private_data))->checksum;
 
336
    inode = 1;
 
337
 
 
338
    return 1;
 
339
}
 
340
 
 
341
static int ino_size_romfs (void)
 
342
{
 
343
    struct romfs_inode ri;
 
344
 
 
345
    if (romfs_read_inode (fs, inode, &ri))
 
346
        return 0;
 
347
 
 
348
    if ((ri.next & ROMFH_TYPE) != ROMFH_REG)
 
349
        return 0;
 
350
 
 
351
    return ri.size;
 
352
}
 
353
 
 
354
static int ls_romfs (void)
 
355
{
 
356
    struct romfs_inode ub;
 
357
    link_count = 0;
 
358
 
 
359
    if (romfs_read_inode (fs, inode, &ub)) return -1;
 
360
 
 
361
    if (romfs_lookup (fs, &ub, NULL, 0, NULL))
 
362
        return -1;
 
363
 
 
364
    return 0;
 
365
}
 
366
 
 
367
static void print_error_romfs (int error_val) {
 
368
    printf("Unknown ROMFS error");
 
369
}
 
370
 
 
371
struct fs_ops rom_fs_ops = {
 
372
    name:               "Linux ROMFS",
 
373
    open:               open_romfs,
 
374
    ls:                 ls_romfs,
 
375
    dump:               romfs_block_iterate,
 
376
    close:              romfs_close,
 
377
    ino_size:           ino_size_romfs,
 
378
    print_error:        print_error_romfs,
 
379
    namei_follow:       namei_follow_romfs,
 
380
    have_inode:         0,
 
381
};