OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [romfs/] [inode.c] - Diff between revs 901 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 901 Rev 1765
/*
/*
 * ROMFS file system, Linux implementation
 * ROMFS file system, Linux implementation
 *
 *
 * Copyright (C) 1997  Janos Farkas <chexum@shadow.banki.hu>
 * Copyright (C) 1997  Janos Farkas <chexum@shadow.banki.hu>
 *
 *
 * Using parts of the minix filesystem
 * Using parts of the minix filesystem
 * Copyright (C) 1991, 1992  Linus Torvalds
 * Copyright (C) 1991, 1992  Linus Torvalds
 *
 *
 * and parts of the affs filesystem additionally
 * and parts of the affs filesystem additionally
 * Copyright (C) 1993  Ray Burr
 * Copyright (C) 1993  Ray Burr
 * Copyright (C) 1996  Hans-Joachim Widmaier
 * Copyright (C) 1996  Hans-Joachim Widmaier
 *
 *
 * This program is free software; you can redistribute it and/or
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 * 2 of the License, or (at your option) any later version.
 *
 *
 * Changes
 * Changes
 *                                      Changed for 2.1.19 modules
 *                                      Changed for 2.1.19 modules
 *      Jan 1997                        Initial release
 *      Jan 1997                        Initial release
 *      Nov 1997        2.0.32          Merging applicable 2.1 bugfixes
 *      Nov 1997        2.0.32          Merging applicable 2.1 bugfixes
 *
 *
 */
 */
 
 
/* todo:
/* todo:
 *      - see Documentation/filesystems/romfs.txt
 *      - see Documentation/filesystems/romfs.txt
 *      - use malloced memory for file names?
 *      - use malloced memory for file names?
 *      - quicklist routines from fs/namei.c, get_page is possibly not
 *      - quicklist routines from fs/namei.c, get_page is possibly not
 *        intended to be used now
 *        intended to be used now
 *      - considering write access...
 *      - considering write access...
 *      - network (tftp) files?
 *      - network (tftp) files?
 *      - in the ancient times something leaked to made umounts
 *      - in the ancient times something leaked to made umounts
 *        impossible, but I've not seen it in the last months
 *        impossible, but I've not seen it in the last months
 */
 */
 
 
/*
/*
 * Sorry about some optimizations and for some goto's.  I just wanted
 * Sorry about some optimizations and for some goto's.  I just wanted
 * to squeeze some more bytes out of this code.. :)
 * to squeeze some more bytes out of this code.. :)
 */
 */
 
 
#include <linux/module.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/romfs_fs.h>
#include <linux/romfs_fs.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/locks.h>
 
 
#include <asm/byteorder.h>
#include <asm/byteorder.h>
 
 
static int inline min(int a, int b)
static int inline min(int a, int b)
{
{
        return a<b ? a : b;
        return a<b ? a : b;
}
}
 
 
static __s32
static __s32
romfs_checksum(void *data, int size)
romfs_checksum(void *data, int size)
{
{
        __s32 sum, *ptr;
        __s32 sum, *ptr;
 
 
        sum = 0; ptr = data;
        sum = 0; ptr = data;
        size>>=2;
        size>>=2;
        while (size>0) {
        while (size>0) {
                sum += ntohl(*ptr++);
                sum += ntohl(*ptr++);
                size--;
                size--;
        }
        }
        return sum;
        return sum;
}
}
 
 
static struct super_operations romfs_ops;
static struct super_operations romfs_ops;
 
 
static struct super_block *
static struct super_block *
romfs_read_super(struct super_block *s, void *data, int silent)
romfs_read_super(struct super_block *s, void *data, int silent)
{
{
        struct buffer_head *bh;
        struct buffer_head *bh;
        kdev_t dev = s->s_dev;
        kdev_t dev = s->s_dev;
        struct romfs_super_block *rsb;
        struct romfs_super_block *rsb;
        int sz;
        int sz;
 
 
        MOD_INC_USE_COUNT;
        MOD_INC_USE_COUNT;
 
 
        /* I would parse the options here, but there are none.. :) */
        /* I would parse the options here, but there are none.. :) */
 
 
        lock_super(s);
        lock_super(s);
        set_blocksize(dev, ROMBSIZE);
        set_blocksize(dev, ROMBSIZE);
        s->s_blocksize = ROMBSIZE;
        s->s_blocksize = ROMBSIZE;
        s->s_blocksize_bits = ROMBSBITS;
        s->s_blocksize_bits = ROMBSBITS;
        bh = bread(dev, 0, ROMBSIZE);
        bh = bread(dev, 0, ROMBSIZE);
        if (!bh) {
        if (!bh) {
                /* XXX merge with other printk? */
                /* XXX merge with other printk? */
                printk ("romfs: unable to read superblock\n");
                printk ("romfs: unable to read superblock\n");
                goto outnobh;
                goto outnobh;
        }
        }
 
 
        rsb = (struct romfs_super_block *)bh->b_data;
        rsb = (struct romfs_super_block *)bh->b_data;
        sz = ntohl(rsb->size);
        sz = ntohl(rsb->size);
        if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
        if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
           || sz < ROMFH_SIZE) {
           || sz < ROMFH_SIZE) {
                if (!silent)
                if (!silent)
                        printk ("VFS: Can't find a romfs filesystem on dev "
                        printk ("VFS: Can't find a romfs filesystem on dev "
                                "%s.\n", kdevname(dev));
                                "%s.\n", kdevname(dev));
                goto out;
                goto out;
        }
        }
        if (romfs_checksum(rsb, min(sz,512))) {
        if (romfs_checksum(rsb, min(sz,512))) {
                printk ("romfs: bad initial checksum on dev "
                printk ("romfs: bad initial checksum on dev "
                        "%s.\n", kdevname(dev));
                        "%s.\n", kdevname(dev));
                goto out;
                goto out;
        }
        }
 
 
        s->s_magic = ROMFS_MAGIC;
        s->s_magic = ROMFS_MAGIC;
        s->u.romfs_sb.s_maxsize = sz;
        s->u.romfs_sb.s_maxsize = sz;
 
 
        s->s_flags |= MS_RDONLY;
        s->s_flags |= MS_RDONLY;
 
 
        /* Find the start of the fs */
        /* Find the start of the fs */
        sz = (ROMFH_SIZE +
        sz = (ROMFH_SIZE +
              strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
              strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
             & ROMFH_MASK;
             & ROMFH_MASK;
 
 
        brelse(bh);
        brelse(bh);
 
 
        s->s_op = &romfs_ops;
        s->s_op = &romfs_ops;
 
 
        if (!(s->s_mounted = iget(s, sz)))
        if (!(s->s_mounted = iget(s, sz)))
                goto outnobh;
                goto outnobh;
 
 
        unlock_super(s);
        unlock_super(s);
 
 
        /* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
        /* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
        if (0) {
        if (0) {
out:
out:
                brelse(bh);
                brelse(bh);
outnobh:
outnobh:
                s->s_dev = 0;
                s->s_dev = 0;
                unlock_super(s);
                unlock_super(s);
                MOD_DEC_USE_COUNT;
                MOD_DEC_USE_COUNT;
                s = NULL;
                s = NULL;
        }
        }
 
 
        return s;
        return s;
}
}
 
 
/* Nothing to do.. */
/* Nothing to do.. */
 
 
static void
static void
romfs_put_super(struct super_block *sb)
romfs_put_super(struct super_block *sb)
{
{
        lock_super(sb);
        lock_super(sb);
        sb->s_dev = 0;
        sb->s_dev = 0;
        unlock_super(sb);
        unlock_super(sb);
        MOD_DEC_USE_COUNT;
        MOD_DEC_USE_COUNT;
        return;
        return;
}
}
 
 
/* That's simple too. */
/* That's simple too. */
 
 
static void
static void
romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
{
{
        struct statfs tmp;
        struct statfs tmp;
 
 
        memset(&tmp, 0, sizeof(tmp));
        memset(&tmp, 0, sizeof(tmp));
        tmp.f_type = ROMFS_MAGIC;
        tmp.f_type = ROMFS_MAGIC;
        tmp.f_bsize = ROMBSIZE;
        tmp.f_bsize = ROMBSIZE;
        tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
        tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
        memcpy_tofs(buf, &tmp, bufsize);
        memcpy_tofs(buf, &tmp, bufsize);
}
}
 
 
/* some helper routines */
/* some helper routines */
 
 
static int
static int
romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
{
{
        struct buffer_head *bh;
        struct buffer_head *bh;
        unsigned long avail, maxsize, res;
        unsigned long avail, maxsize, res;
 
 
        maxsize = i->i_sb->u.romfs_sb.s_maxsize;
        maxsize = i->i_sb->u.romfs_sb.s_maxsize;
        if (offset >= maxsize)
        if (offset >= maxsize)
                return -1;
                return -1;
 
 
        /* strnlen is almost always valid */
        /* strnlen is almost always valid */
        if (count > maxsize || offset+count > maxsize)
        if (count > maxsize || offset+count > maxsize)
                count = maxsize-offset;
                count = maxsize-offset;
 
 
        bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
        bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
        if (!bh)
        if (!bh)
                return -1;              /* error */
                return -1;              /* error */
 
 
        avail = ROMBSIZE - (offset & ROMBMASK);
        avail = ROMBSIZE - (offset & ROMBMASK);
        maxsize = min(count, avail);
        maxsize = min(count, avail);
        res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
        res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
        brelse(bh);
        brelse(bh);
 
 
        if (res < maxsize)
        if (res < maxsize)
                return res;             /* found all of it */
                return res;             /* found all of it */
 
 
        while (res < count) {
        while (res < count) {
                offset += maxsize;
                offset += maxsize;
 
 
                bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
                bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
                if (!bh)
                if (!bh)
                        return -1;
                        return -1;
                maxsize = min(count-res, ROMBSIZE);
                maxsize = min(count-res, ROMBSIZE);
                avail = strnlen(bh->b_data, maxsize);
                avail = strnlen(bh->b_data, maxsize);
                res += avail;
                res += avail;
                brelse(bh);
                brelse(bh);
                if (avail < maxsize)
                if (avail < maxsize)
                        return res;
                        return res;
        }
        }
        return res;
        return res;
}
}
 
 
static int
static int
romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
{
{
        struct buffer_head *bh;
        struct buffer_head *bh;
        unsigned long avail, maxsize, res;
        unsigned long avail, maxsize, res;
 
 
        maxsize = i->i_sb->u.romfs_sb.s_maxsize;
        maxsize = i->i_sb->u.romfs_sb.s_maxsize;
        if (offset >= maxsize || count > maxsize || offset+count>maxsize)
        if (offset >= maxsize || count > maxsize || offset+count>maxsize)
                return -1;
                return -1;
 
 
        bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
        bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
        if (!bh)
        if (!bh)
                return -1;              /* error */
                return -1;              /* error */
 
 
        avail = ROMBSIZE - (offset & ROMBMASK);
        avail = ROMBSIZE - (offset & ROMBMASK);
        maxsize = min(count, avail);
        maxsize = min(count, avail);
        memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
        memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
        brelse(bh);
        brelse(bh);
 
 
        res = maxsize;                  /* all of it */
        res = maxsize;                  /* all of it */
 
 
        while (res < count) {
        while (res < count) {
                offset += maxsize;
                offset += maxsize;
                dest += maxsize;
                dest += maxsize;
 
 
                bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
                bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
                if (!bh)
                if (!bh)
                        return -1;
                        return -1;
                maxsize = min(count-res, ROMBSIZE);
                maxsize = min(count-res, ROMBSIZE);
                memcpy(dest, bh->b_data, maxsize);
                memcpy(dest, bh->b_data, maxsize);
                brelse(bh);
                brelse(bh);
                res += maxsize;
                res += maxsize;
        }
        }
        return res;
        return res;
}
}
 
 
/* Directory operations */
/* Directory operations */
 
 
static int
static int
romfs_readdir(struct inode *i, struct file *filp, void *dirent, filldir_t filldir)
romfs_readdir(struct inode *i, struct file *filp, void *dirent, filldir_t filldir)
{
{
        struct romfs_inode ri;
        struct romfs_inode ri;
        unsigned long offset, maxoff;
        unsigned long offset, maxoff;
        int j, ino, nextfh;
        int j, ino, nextfh;
        int stored = 0;
        int stored = 0;
        char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
        char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
 
 
        if (!i || !S_ISDIR(i->i_mode))
        if (!i || !S_ISDIR(i->i_mode))
                return -EBADF;
                return -EBADF;
 
 
        maxoff = i->i_sb->u.romfs_sb.s_maxsize;
        maxoff = i->i_sb->u.romfs_sb.s_maxsize;
 
 
        offset = filp->f_pos;
        offset = filp->f_pos;
        if (!offset) {
        if (!offset) {
                offset = i->i_ino & ROMFH_MASK;
                offset = i->i_ino & ROMFH_MASK;
                if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
                if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
                        return stored;
                        return stored;
                offset = ntohl(ri.spec) & ROMFH_MASK;
                offset = ntohl(ri.spec) & ROMFH_MASK;
        }
        }
 
 
        /* Not really failsafe, but we are read-only... */
        /* Not really failsafe, but we are read-only... */
        for(;;) {
        for(;;) {
                if (!offset || offset >= maxoff) {
                if (!offset || offset >= maxoff) {
                        offset = 0xffffffff;
                        offset = 0xffffffff;
                        filp->f_pos = offset;
                        filp->f_pos = offset;
                        return stored;
                        return stored;
                }
                }
                filp->f_pos = offset;
                filp->f_pos = offset;
 
 
                /* Fetch inode info */
                /* Fetch inode info */
                if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
                if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
                        return stored;
                        return stored;
 
 
                j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
                j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
                if (j < 0)
                if (j < 0)
                        return stored;
                        return stored;
 
 
                fsname[j]=0;
                fsname[j]=0;
                romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
                romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
 
 
                ino = offset;
                ino = offset;
                nextfh = ntohl(ri.next);
                nextfh = ntohl(ri.next);
                if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
                if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
                        ino = ntohl(ri.spec);
                        ino = ntohl(ri.spec);
                if (filldir(dirent, fsname, j, offset, ino) < 0) {
                if (filldir(dirent, fsname, j, offset, ino) < 0) {
                        return stored;
                        return stored;
                }
                }
                stored++;
                stored++;
                offset = nextfh & ROMFH_MASK;
                offset = nextfh & ROMFH_MASK;
        }
        }
}
}
 
 
static int
static int
romfs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
romfs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
{
{
        unsigned long offset, maxoff;
        unsigned long offset, maxoff;
        int fslen, res;
        int fslen, res;
        char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
        char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
        struct romfs_inode ri;
        struct romfs_inode ri;
 
 
        *result = NULL;
        *result = NULL;
        if (!dir || !S_ISDIR(dir->i_mode)) {
        if (!dir || !S_ISDIR(dir->i_mode)) {
                res = -EBADF;
                res = -EBADF;
                goto out;
                goto out;
        }
        }
 
 
        offset = dir->i_ino & ROMFH_MASK;
        offset = dir->i_ino & ROMFH_MASK;
        if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
        if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
                res = -ENOENT;
                res = -ENOENT;
                goto out;
                goto out;
        }
        }
 
 
        maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
        maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
        offset = ntohl(ri.spec) & ROMFH_MASK;
        offset = ntohl(ri.spec) & ROMFH_MASK;
 
 
        for(;;) {
        for(;;) {
                if (!offset || offset >= maxoff
                if (!offset || offset >= maxoff
                    || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
                    || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
                        res = -ENOENT;
                        res = -ENOENT;
                        goto out;
                        goto out;
                }
                }
 
 
                /* try to match the first 16 bytes of name */
                /* try to match the first 16 bytes of name */
                fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
                fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
                if (len < ROMFH_SIZE) {
                if (len < ROMFH_SIZE) {
                        if (len == fslen) {
                        if (len == fslen) {
                                /* both are shorter, and same size */
                                /* both are shorter, and same size */
                                romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
                                romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
                                if (strncmp (name, fsname, len) == 0)
                                if (strncmp (name, fsname, len) == 0)
                                        break;
                                        break;
                        }
                        }
                } else if (fslen >= ROMFH_SIZE) {
                } else if (fslen >= ROMFH_SIZE) {
                        /* both are longer; XXX optimize max size */
                        /* both are longer; XXX optimize max size */
                        fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
                        fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
                        if (len == fslen) {
                        if (len == fslen) {
                                romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
                                romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
                                if (strncmp(name, fsname, len) == 0)
                                if (strncmp(name, fsname, len) == 0)
                                        break;
                                        break;
                        }
                        }
                }
                }
                /* next entry */
                /* next entry */
                offset = ntohl(ri.next) & ROMFH_MASK;
                offset = ntohl(ri.next) & ROMFH_MASK;
        }
        }
 
 
        /* Hard link handling */
        /* Hard link handling */
        if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
        if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
                offset = ntohl(ri.spec) & ROMFH_MASK;
                offset = ntohl(ri.spec) & ROMFH_MASK;
 
 
        res = 0;
        res = 0;
        if (!(*result = iget(dir->i_sb, offset)))
        if (!(*result = iget(dir->i_sb, offset)))
                res = -EACCES;
                res = -EACCES;
 
 
out:
out:
        iput(dir);
        iput(dir);
        return res;
        return res;
}
}
 
 
/*
/*
 * Ok, we do readpage, to be able to execute programs.  Unfortunately,
 * Ok, we do readpage, to be able to execute programs.  Unfortunately,
 * we can't use bmap, since we have looser alignments.
 * we can't use bmap, since we have looser alignments.
 */
 */
 
 
static int
static int
romfs_readpage(struct inode * inode, struct page * page)
romfs_readpage(struct inode * inode, struct page * page)
{
{
        unsigned long buf;
        unsigned long buf;
        unsigned long offset, avail, readlen;
        unsigned long offset, avail, readlen;
        int result = -EIO;
        int result = -EIO;
 
 
        page->count++;
        page->count++;
        set_bit(PG_locked, &page->flags);
        set_bit(PG_locked, &page->flags);
 
 
        buf = page_address(page);
        buf = page_address(page);
        clear_bit(PG_uptodate, &page->flags);
        clear_bit(PG_uptodate, &page->flags);
        clear_bit(PG_error, &page->flags);
        clear_bit(PG_error, &page->flags);
        offset = page->offset;
        offset = page->offset;
        if (offset < inode->i_size) {
        if (offset < inode->i_size) {
                avail = inode->i_size-offset;
                avail = inode->i_size-offset;
                readlen = min(avail, PAGE_SIZE);
                readlen = min(avail, PAGE_SIZE);
                if (romfs_copyfrom(inode, (void *)buf, inode->u.romfs_i.i_dataoffset+offset, readlen) == readlen) {
                if (romfs_copyfrom(inode, (void *)buf, inode->u.romfs_i.i_dataoffset+offset, readlen) == readlen) {
                        if (readlen < PAGE_SIZE) {
                        if (readlen < PAGE_SIZE) {
                                memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
                                memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
                        }
                        }
                        set_bit(PG_uptodate, &page->flags);
                        set_bit(PG_uptodate, &page->flags);
                        result = 0;
                        result = 0;
                }
                }
        }
        }
        if (result) {
        if (result) {
                set_bit(PG_error, &page->flags);
                set_bit(PG_error, &page->flags);
                memset((void *)buf, 0, PAGE_SIZE);
                memset((void *)buf, 0, PAGE_SIZE);
        }
        }
 
 
        clear_bit(PG_locked, &page->flags);
        clear_bit(PG_locked, &page->flags);
        wake_up(&page->wait);
        wake_up(&page->wait);
        free_page(buf);
        free_page(buf);
 
 
        return result;
        return result;
}
}
 
 
#ifdef MAGIC_ROM_PTR
#ifdef MAGIC_ROM_PTR
static int
static int
romfs_romptr(struct inode * inode, struct file * filp, struct vm_area_struct * vma)
romfs_romptr(struct inode * inode, struct file * filp, struct vm_area_struct * vma)
{
{
        vma->vm_offset += inode->u.romfs_i.i_dataoffset;
        vma->vm_offset += inode->u.romfs_i.i_dataoffset;
 
 
        if ((vma->vm_flags & VM_WRITE) || bromptr(inode->i_dev, vma))
        if ((vma->vm_flags & VM_WRITE) || bromptr(inode->i_dev, vma))
                return -ENOSYS;
                return -ENOSYS;
 
 
        return 0;
        return 0;
}
}
#endif
#endif
 
 
static int
static int
romfs_readlink(struct inode *inode, char *buffer, int len)
romfs_readlink(struct inode *inode, char *buffer, int len)
{
{
        int mylen;
        int mylen;
        char buf[ROMFS_MAXFN];          /* XXX dynamic */
        char buf[ROMFS_MAXFN];          /* XXX dynamic */
 
 
        if (!inode || !S_ISLNK(inode->i_mode)) {
        if (!inode || !S_ISLNK(inode->i_mode)) {
                mylen = -EBADF;
                mylen = -EBADF;
                goto out;
                goto out;
        }
        }
 
 
        mylen = min(sizeof(buf), inode->i_size);
        mylen = min(sizeof(buf), inode->i_size);
 
 
        if (romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, mylen) <= 0) {
        if (romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, mylen) <= 0) {
                mylen = -EIO;
                mylen = -EIO;
                goto out;
                goto out;
        }
        }
        memcpy_tofs(buffer, buf, mylen);
        memcpy_tofs(buffer, buf, mylen);
 
 
out:
out:
        iput(inode);
        iput(inode);
        return mylen;
        return mylen;
}
}
 
 
static int
static int
romfs_follow_link(struct inode *dir, struct inode *inode,
romfs_follow_link(struct inode *dir, struct inode *inode,
        int flag, int mode, struct inode **res_inode)
        int flag, int mode, struct inode **res_inode)
{
{
        int error, len;
        int error, len;
        char *buf;
        char *buf;
 
 
        *res_inode = NULL;
        *res_inode = NULL;
        if (!dir) {
        if (!dir) {
                dir = current->fs->root;
                dir = current->fs->root;
                dir->i_count++;
                dir->i_count++;
        }
        }
 
 
        if (!inode) {
        if (!inode) {
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (!S_ISLNK(inode->i_mode)) {
        if (!S_ISLNK(inode->i_mode)) {
                *res_inode = inode;
                *res_inode = inode;
                iput(dir);
                iput(dir);
                return 0;
                return 0;
        }
        }
        if (current->link_count > 5) {
        if (current->link_count > 5) {
                iput(inode);
                iput(inode);
                iput(dir);
                iput(dir);
                return -ELOOP;
                return -ELOOP;
        }
        }
 
 
        /* Eek. Short enough. */
        /* Eek. Short enough. */
        len = inode->i_size;
        len = inode->i_size;
        if (!(buf = kmalloc(len+1, GFP_KERNEL))) {
        if (!(buf = kmalloc(len+1, GFP_KERNEL))) {
                iput(inode);
                iput(inode);
                iput(dir);
                iput(dir);
                /* correct?  spin? */
                /* correct?  spin? */
                return -EAGAIN;
                return -EAGAIN;
        }
        }
        error = romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, len);
        error = romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, len);
        if (error != len) {
        if (error != len) {
                iput(inode);
                iput(inode);
                iput(dir);
                iput(dir);
                error = -EIO;
                error = -EIO;
        } else {
        } else {
                iput(inode);
                iput(inode);
                buf[len] = 0;
                buf[len] = 0;
                current->link_count++;
                current->link_count++;
                error = open_namei(buf, flag, mode, res_inode, dir);
                error = open_namei(buf, flag, mode, res_inode, dir);
                current->link_count--;
                current->link_count--;
        }
        }
 
 
        kfree(buf);
        kfree(buf);
        return error;
        return error;
}
}
 
 
/* Mapping from our types to the kernel */
/* Mapping from our types to the kernel */
 
 
static struct file_operations romfs_file_operations = {
static struct file_operations romfs_file_operations = {
        NULL,                   /* lseek - default */
        NULL,                   /* lseek - default */
        generic_file_read,      /* read */
        generic_file_read,      /* read */
        NULL,                   /* write - bad */
        NULL,                   /* write - bad */
        NULL,                   /* readdir */
        NULL,                   /* readdir */
        NULL,                   /* select - default */
        NULL,                   /* select - default */
        NULL,                   /* ioctl */
        NULL,                   /* ioctl */
        generic_file_mmap,      /* mmap */
        generic_file_mmap,      /* mmap */
        NULL,                   /* open */
        NULL,                   /* open */
        NULL,                   /* release */
        NULL,                   /* release */
        NULL,                   /* fsync */
        NULL,                   /* fsync */
        NULL,                   /* fasync */
        NULL,                   /* fasync */
        NULL,                   /* check_media_change */
        NULL,                   /* check_media_change */
        NULL,                   /* revalidate */
        NULL,                   /* revalidate */
#ifdef MAGIC_ROM_PTR
#ifdef MAGIC_ROM_PTR
        romfs_romptr,           /* romptr */
        romfs_romptr,           /* romptr */
#endif
#endif
};
};
 
 
static struct inode_operations romfs_file_inode_operations = {
static struct inode_operations romfs_file_inode_operations = {
        &romfs_file_operations,
        &romfs_file_operations,
        NULL,                   /* create */
        NULL,                   /* create */
        NULL,                   /* lookup */
        NULL,                   /* lookup */
        NULL,                   /* link */
        NULL,                   /* link */
        NULL,                   /* unlink */
        NULL,                   /* unlink */
        NULL,                   /* symlink */
        NULL,                   /* symlink */
        NULL,                   /* mkdir */
        NULL,                   /* mkdir */
        NULL,                   /* rmdir */
        NULL,                   /* rmdir */
        NULL,                   /* mknod */
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* rename */
        NULL,                   /* readlink */
        NULL,                   /* readlink */
        NULL,                   /* follow_link */
        NULL,                   /* follow_link */
        romfs_readpage,         /* readpage */
        romfs_readpage,         /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* writepage */
        NULL,                   /* bmap -- not really */
        NULL,                   /* bmap -- not really */
        NULL,                   /* truncate */
        NULL,                   /* truncate */
        NULL,                   /* permission */
        NULL,                   /* permission */
        NULL,                   /* smap */
        NULL,                   /* smap */
};
};
 
 
static struct file_operations romfs_dir_operations = {
static struct file_operations romfs_dir_operations = {
        NULL,                   /* lseek - default */
        NULL,                   /* lseek - default */
        NULL,                   /* read */
        NULL,                   /* read */
        NULL,                   /* write - bad */
        NULL,                   /* write - bad */
        romfs_readdir,          /* readdir */
        romfs_readdir,          /* readdir */
        NULL,                   /* select - default */
        NULL,                   /* select - default */
        NULL,                   /* ioctl */
        NULL,                   /* ioctl */
        NULL,                   /* mmap */
        NULL,                   /* mmap */
        NULL,                   /* open */
        NULL,                   /* open */
        NULL,                   /* release */
        NULL,                   /* release */
        NULL,                   /* fsync */
        NULL,                   /* fsync */
        NULL,                   /* fasync */
        NULL,                   /* fasync */
        NULL,                   /* check_media_change */
        NULL,                   /* check_media_change */
        NULL                    /* revalidate */
        NULL                    /* revalidate */
};
};
 
 
/* Merged dir/symlink op table.  readdir/lookup/readlink/follow_link
/* Merged dir/symlink op table.  readdir/lookup/readlink/follow_link
 * will protect from type mismatch.
 * will protect from type mismatch.
 */
 */
 
 
static struct inode_operations romfs_dirlink_inode_operations = {
static struct inode_operations romfs_dirlink_inode_operations = {
        &romfs_dir_operations,
        &romfs_dir_operations,
        NULL,                   /* create */
        NULL,                   /* create */
        romfs_lookup,           /* lookup */
        romfs_lookup,           /* lookup */
        NULL,                   /* link */
        NULL,                   /* link */
        NULL,                   /* unlink */
        NULL,                   /* unlink */
        NULL,                   /* symlink */
        NULL,                   /* symlink */
        NULL,                   /* mkdir */
        NULL,                   /* mkdir */
        NULL,                   /* rmdir */
        NULL,                   /* rmdir */
        NULL,                   /* mknod */
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* rename */
        romfs_readlink,         /* readlink */
        romfs_readlink,         /* readlink */
        romfs_follow_link,      /* follow_link */
        romfs_follow_link,      /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
        NULL,                   /* truncate */
        NULL,                   /* permission */
        NULL,                   /* permission */
        NULL,                   /* smap */
        NULL,                   /* smap */
};
};
 
 
static mode_t romfs_modemap[] =
static mode_t romfs_modemap[] =
{
{
        0, S_IFDIR, S_IFREG, S_IFLNK+0777,
        0, S_IFDIR, S_IFREG, S_IFLNK+0777,
        S_IFBLK, S_IFCHR, S_IFSOCK, S_IFIFO
        S_IFBLK, S_IFCHR, S_IFSOCK, S_IFIFO
};
};
 
 
static struct inode_operations *romfs_inoops[] =
static struct inode_operations *romfs_inoops[] =
{
{
        NULL,                           /* hardlink, handled elsewhere */
        NULL,                           /* hardlink, handled elsewhere */
        &romfs_dirlink_inode_operations,
        &romfs_dirlink_inode_operations,
        &romfs_file_inode_operations,
        &romfs_file_inode_operations,
        &romfs_dirlink_inode_operations,
        &romfs_dirlink_inode_operations,
        &blkdev_inode_operations,       /* standard handlers */
        &blkdev_inode_operations,       /* standard handlers */
        &chrdev_inode_operations,
        &chrdev_inode_operations,
        NULL,                           /* socket */
        NULL,                           /* socket */
        NULL,                           /* fifo */
        NULL,                           /* fifo */
};
};
 
 
static void
static void
romfs_read_inode(struct inode *i)
romfs_read_inode(struct inode *i)
{
{
        int nextfh, ino;
        int nextfh, ino;
        struct romfs_inode ri;
        struct romfs_inode ri;
 
 
        ino = i->i_ino & ROMFH_MASK;
        ino = i->i_ino & ROMFH_MASK;
 
 
        i->i_op = NULL;
        i->i_op = NULL;
        i->i_mode = 0;
        i->i_mode = 0;
 
 
        /* Loop for finding the real hard link */
        /* Loop for finding the real hard link */
        for(;;) {
        for(;;) {
                if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
                if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
                        printk("romfs: read error for inode 0x%x\n", ino);
                        printk("romfs: read error for inode 0x%x\n", ino);
                        return;
                        return;
                }
                }
                /* XXX: do romfs_checksum here too (with name) */
                /* XXX: do romfs_checksum here too (with name) */
 
 
                nextfh = ntohl(ri.next);
                nextfh = ntohl(ri.next);
                if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
                if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
                        break;
                        break;
 
 
                ino = ntohl(ri.spec) & ROMFH_MASK;
                ino = ntohl(ri.spec) & ROMFH_MASK;
        }
        }
 
 
        i->i_nlink = 1;         /* Hard to decide.. */
        i->i_nlink = 1;         /* Hard to decide.. */
        i->i_size = ntohl(ri.size);
        i->i_size = ntohl(ri.size);
        i->i_mtime = i->i_atime = i->i_ctime = 0;
        i->i_mtime = i->i_atime = i->i_ctime = 0;
        i->i_uid = i->i_gid = 0;
        i->i_uid = i->i_gid = 0;
 
 
        i->i_op = romfs_inoops[nextfh & ROMFH_TYPE];
        i->i_op = romfs_inoops[nextfh & ROMFH_TYPE];
 
 
        /* Precalculate the data offset */
        /* Precalculate the data offset */
        ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
        ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
        if (ino >= 0)
        if (ino >= 0)
                ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
                ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
        else
        else
                ino = 0;
                ino = 0;
 
 
        i->u.romfs_i.i_metasize = ino;
        i->u.romfs_i.i_metasize = ino;
        i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
        i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
 
 
        /* Compute permissions */
        /* Compute permissions */
        ino = S_IRUGO|S_IWUSR;
        ino = S_IRUGO|S_IWUSR;
        ino |= romfs_modemap[nextfh & ROMFH_TYPE];
        ino |= romfs_modemap[nextfh & ROMFH_TYPE];
        if (nextfh & ROMFH_EXEC) {
        if (nextfh & ROMFH_EXEC) {
                ino |= S_IXUGO;
                ino |= S_IXUGO;
        }
        }
        i->i_mode = ino;
        i->i_mode = ino;
 
 
        if (S_ISFIFO(ino))
        if (S_ISFIFO(ino))
                init_fifo(i);
                init_fifo(i);
        else if (S_ISDIR(ino))
        else if (S_ISDIR(ino))
                i->i_size = i->u.romfs_i.i_metasize;
                i->i_size = i->u.romfs_i.i_metasize;
        else if (S_ISBLK(ino) || S_ISCHR(ino)) {
        else if (S_ISBLK(ino) || S_ISCHR(ino)) {
                i->i_mode &= ~(S_IRWXG|S_IRWXO);
                i->i_mode &= ~(S_IRWXG|S_IRWXO);
                ino = ntohl(ri.spec);
                ino = ntohl(ri.spec);
                i->i_rdev = MKDEV(ino>>16,ino&0xffff);
                i->i_rdev = MKDEV(ino>>16,ino&0xffff);
        }
        }
}
}
 
 
static struct super_operations romfs_ops = {
static struct super_operations romfs_ops = {
        romfs_read_inode,       /* read inode */
        romfs_read_inode,       /* read inode */
        NULL,                   /* notify change */
        NULL,                   /* notify change */
        NULL,                   /* write inode */
        NULL,                   /* write inode */
        NULL,                   /* put inode */
        NULL,                   /* put inode */
        romfs_put_super,        /* put super */
        romfs_put_super,        /* put super */
        NULL,                   /* write super */
        NULL,                   /* write super */
        romfs_statfs,           /* statfs */
        romfs_statfs,           /* statfs */
        NULL                    /* remount */
        NULL                    /* remount */
};
};
 
 
static struct file_system_type romfs_fs_type = {
static struct file_system_type romfs_fs_type = {
        romfs_read_super, "romfs", 1, NULL
        romfs_read_super, "romfs", 1, NULL
};
};
 
 
int
int
init_romfs_fs(void)
init_romfs_fs(void)
{
{
        return register_filesystem(&romfs_fs_type);
        return register_filesystem(&romfs_fs_type);
}
}
 
 
#ifdef MODULE
#ifdef MODULE
 
 
/* Yes, works even as a module... :) */
/* Yes, works even as a module... :) */
 
 
int
int
init_module(void)
init_module(void)
{
{
        int status;
        int status;
 
 
        if ((status = init_romfs_fs()) == 0)
        if ((status = init_romfs_fs()) == 0)
                register_symtab(0);
                register_symtab(0);
        return status;
        return status;
}
}
 
 
void
void
cleanup_module(void)
cleanup_module(void)
{
{
        unregister_filesystem(&romfs_fs_type);
        unregister_filesystem(&romfs_fs_type);
}
}
#endif
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.