1
/* Linux ROMFS Interface for SILO filesystem access routines
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>
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,
23
#include <sys/types.h>
27
#include <stringops.h>
28
#include <linux/romfs_fs.h>
31
typedef ext2_filsys romfs_filsys;
33
static ino_t inode = 0;
34
static int link_count = 0;
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)
40
static int inline min(int a, int b)
46
romfs_checksum(void *data, int size)
59
static struct romfs_super_block *romfs_read_super(romfs_filsys fs)
61
struct romfs_super_block *rsb;
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,/.."
66
rsb = (struct romfs_super_block *) malloc (2048+ROMBSIZE);
67
if (!rsb) return NULL;
69
if (io_channel_read_blk (fs->io, 0, 1, (char *)rsb))
72
if (strncmp((char *)rsb, "-rom1fs-", 8) || rsb->size < ROMFH_SIZE)
75
if (romfs_checksum(rsb, min(rsb->size,512))) {
76
printf("ROMFS: Bad initial checksum.\n");
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;
90
static int romfs_copyfrom(romfs_filsys fs, void *dest, unsigned long offset, unsigned long count)
92
struct romfs_super_block *rsb = SUPROMFS;
94
char buffer[ROMBSIZE];
97
if ((offset>>ROMBSBITS)<<ROMBSBITS >= rsb->size+ROMBSIZE || count > rsb->size ||
98
offset+count>rsb->size+ROMBSIZE)
101
maxsize = min(count, (ROMBSIZE - (offset & ROMBMASK)));
104
if (io_channel_read_blk (fs->io, offset>>ROMBSBITS, 1, buffer))
107
memcpy(dest, buffer + (offset & ROMBMASK), maxsize);
109
while (res < count) {
112
if (io_channel_read_blk (fs->io, offset>>ROMBSBITS, 1, buffer))
116
maxsize = min(count-res, ROMBSIZE);
118
memcpy(dest, buffer, maxsize);
125
static int romfs_read_inode (romfs_filsys fs, ino_t inode, struct romfs_inode *ui)
127
struct romfs_inode romfsip;
128
struct romfs_super_block *rsb = SUPROMFS;
130
if (inode < rsb->checksum || inode >= rsb->size)
133
if (romfs_copyfrom (fs, &romfsip, inode, ROMFH_SIZE))
140
static mode_t romfs_modemap[] =
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,
147
static int romfs_lookup (romfs_filsys fs, struct romfs_inode *dirui,
148
const char *name, int len, ino_t *result)
151
struct romfs_inode ui;
152
ino_t dir = dirui->spec & ROMFH_MASK;
153
struct romfs_super_block *rsb = SUPROMFS;
155
while (dir && dir < rsb->size) {
156
if (romfs_read_inode (fs, dir, &ui))
159
if (romfs_copyfrom (fs, buffer, dir + ROMFH_SIZE, ROMFS_MAXFN))
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];
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))
174
if (buffer[0] == '.' && (!buffer[1] || (buffer[1] == '.' && !buffer[2])))
175
mode = LINUX_S_IFDIR+0555;
177
register_silo_inode(0, ui.size, mode,
178
0, 0, buffer, symlink[0] ? symlink : NULL);
180
} else if ((!len && buffer[0] == '.' && !buffer[1]) ||
181
(strlen(buffer) == len && !memcmp(buffer, name, len))) {
182
if ((ui.next & ROMFH_TYPE) == ROMFH_HRD)
187
dir = ui.next & ROMFH_MASK;
195
static int open_namei(romfs_filsys, const char *, ino_t *, ino_t);
197
static int romfs_follow_link(romfs_filsys fs, ino_t dir, ino_t inode,
198
struct romfs_inode *ui, ino_t *res_inode)
203
if ((ui->next & ROMFH_TYPE) != ROMFH_SYM) {
207
if (link_count > 5) {
208
printf ("ROMFS: Symlink loop.\n");
209
return -1; /* Loop */
211
if (romfs_copyfrom (fs, buffer, inode + ROMFH_SIZE, ROMFS_MAXFN))
213
error = inode + ROMFH_SIZE + ((strlen(buffer) + ROMFH_SIZE) & ROMFH_MASK);
214
if (romfs_copyfrom (fs, buffer, error, ROMFS_MAXFN))
217
error = open_namei (fs, buffer, res_inode, dir);
222
static int dir_namei(romfs_filsys fs, const char *pathname, int *namelen,
223
const char **name, ino_t base, ino_t *res_inode)
226
const char *thisname;
228
struct romfs_inode ub;
231
if ((c = *pathname) == '/') {
236
if (romfs_read_inode (fs, base, &ub)) return -1;
239
for(len=0;(c = *(pathname++))&&(c != '/');len++);
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;
252
static int open_namei(romfs_filsys fs, const char *pathname,
253
ino_t *res_inode, ino_t base)
255
const char *basename;
258
struct romfs_inode ub;
260
if (dir_namei(fs, pathname, &namelen, &basename, base, &dir)) return -1;
261
if (!namelen) { /* special case: '/usr/' etc */
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;
273
struct fs_ops rom_fs_ops;
275
static int namei_follow_romfs (const char *filename)
281
ret = open_namei (fs, filename, &inode, root);
282
rom_fs_ops.have_inode = (ret) ? 0 : 1;
287
static void romfs_close(void)
293
static int romfs_block_iterate(void)
295
struct romfs_inode ub;
299
char buffer[ROMFS_MAXFN];
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);
305
printf("ROMFS: File not aligned on a %dB boundary.\n", ROMBSIZE);
308
size = (ub.size + ROMBMASK) / ROMBSIZE;
310
for (i = 0; i < size; i++, nr++) {
311
switch (dump_block (&nr, i)) {
317
return dump_finish();
320
static int open_romfs (char *device)
322
fs = (romfs_filsys) malloc (sizeof (struct struct_ext2_filsys));
326
if (((struct struct_io_manager *)(silo_io_manager))->open (device, 0, &fs->io))
329
io_channel_set_blksize (fs->io, ROMBSIZE);
331
fs->io->private_data = romfs_read_super(fs);
332
if (!fs->io->private_data)
335
root = ((struct romfs_super_block *)(fs->io->private_data))->checksum;
341
static int ino_size_romfs (void)
343
struct romfs_inode ri;
345
if (romfs_read_inode (fs, inode, &ri))
348
if ((ri.next & ROMFH_TYPE) != ROMFH_REG)
354
static int ls_romfs (void)
356
struct romfs_inode ub;
359
if (romfs_read_inode (fs, inode, &ub)) return -1;
361
if (romfs_lookup (fs, &ub, NULL, 0, NULL))
367
static void print_error_romfs (int error_val) {
368
printf("Unknown ROMFS error");
371
struct fs_ops rom_fs_ops = {
375
dump: romfs_block_iterate,
377
ino_size: ino_size_romfs,
378
print_error: print_error_romfs,
379
namei_follow: namei_follow_romfs,