summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMike Shaver <shaver@ingenia.com>1999-01-18 04:16:25 +0000
committerMike Shaver <shaver@ingenia.com>1999-01-18 04:16:25 +0000
commit6bafd683c6bd78f19df9a42aea24037137f913ce (patch)
tree7580dc3040c32da4048009721d60a7ac442962ca /fs
parent317b660279d583d4db3fc112e3ef2e56b20bec87 (diff)
EFS mark II. Incomplete, but much cleaner.
Diffstat (limited to 'fs')
-rw-r--r--fs/efs/Makefile2
-rw-r--r--fs/efs/dir.c239
-rw-r--r--fs/efs/file.c349
-rw-r--r--fs/efs/inode.c741
-rw-r--r--fs/efs/namei.c211
-rw-r--r--fs/efs/symlink.c178
6 files changed, 706 insertions, 1014 deletions
diff --git a/fs/efs/Makefile b/fs/efs/Makefile
index 5a8556795..a0532be3e 100644
--- a/fs/efs/Makefile
+++ b/fs/efs/Makefile
@@ -7,7 +7,7 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-#CFLAGS+=-g -DDEBUG_EFS
+CFLAGS+=-g -DDEBUG_EFS
O_TARGET := efs.o
O_OBJS := dir.o file.o inode.o namei.o \
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index a89dd304e..a31f6784a 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -1,137 +1,146 @@
-/* dir.c
-
- directory inode operations for EFS filesystem
-
- (C)95,96 Christian Vogelgsang
-*/
+/*
+ * linux/fs/efs/dir.c
+ *
+ * Copyright (C) 1998 Mike Shaver
+ *
+ * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
+ * ``Inspired by'' fs/minix/dir.c.
+ */
#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/fs.h>
#include <linux/efs_fs.h>
-#include <linux/efs_fs_i.h>
-#include <linux/stat.h>
#include <asm/uaccess.h>
-static int efs_readdir(struct file *,void *,filldir_t);
-extern int efs_lookup(struct inode *, struct dentry *);
+static int efs_readdir(struct file *, void *, filldir_t);
+int efs_lookup(struct inode *, struct dentry *);
+
+static ssize_t
+efs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
static struct file_operations efs_dir_ops = {
- NULL,
- NULL,
- NULL,
- efs_readdir,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* lseek */
+ efs_dir_read,
+ NULL, /* write */
+ efs_readdir,
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+ NULL /* fsync */
};
-struct inode_operations efs_dir_in_ops = {
- &efs_dir_ops,
- NULL,
- efs_lookup,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- efs_bmap,
- NULL,
- NULL
+struct inode_operations efs_dir_inode_operations = {
+ &efs_dir_ops,
+ NULL, /* create */
+ efs_lookup,
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ efs_bmap,
+ NULL, /* truncate */
+ NULL /* permission */
};
+static int
+efs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *in = filp->f_dentry->d_inode;
+ struct efs_inode_info *ini = &in->u.efs_i;
+ struct buffer_head *bh;
+ __u16 item;
+ __u32 block;
+ __u16 offset;
+ struct efs_dirblk *dirblk;
+ struct efs_dir_entry *entry;
+
+ if (!in || !in->i_sb || !S_ISDIR(in->i_mode) || !ini->tot)
+ return -EBADF;
+
+ if (ini->tot > 1) {
+ printk("EFS: ERROR: directory %s has %d extents\n",
+ filp->f_dentry->d_name.name, ini->tot);
+ printk("EFS: ERROR: Mike is lazy, so this is NYI.\n");
+ return 0;
+ };
+
+ if (in->i_size & (EFS_BLOCK_SIZE - 1))
+ printk("EFS: readdir: dirsize %#lx not block multiple\n", in->i_size);
+
+ /* filp->f_pos is (block << BLOCK_SIZE | item) */
+ block = filp->f_pos >> EFS_BLOCK_SIZE_BITS;
+ item = filp->f_pos & 0xFF;
+
+ start_block:
+ if (block == (in->i_size >> EFS_BLOCK_SIZE_BITS))
+ return 0; /* all done! */
+
+ bh = bread(in->i_dev, efs_bmap(in, block), EFS_BLOCK_SIZE);
+ if (!bh) {
+ printk("EFS: ERROR: readdir: bread of %#lx/%#x\n",
+ in->i_ino, efs_bmap(in, block));
+ return 0;
+ }
-/* ----- efs_readdir -----
- readdir inode operation:
- read the next directory entry of a given dir file
-
- inode - pointer to inode struct of directory
- filp - pointer to file struct of directory inode
- dirent - pointer to dirent struct that has to be filled
- filldir - function to store values in the directory
+ dirblk = (struct efs_dirblk *)bh->b_data;
- return - 0 ok, <0 error
-*/
-static int efs_readdir(struct file *filp,
- void *dirent, filldir_t filldir)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i;
- struct buffer_head *bh;
- __u8 *rawdirblk;
- __u32 iteminode;
- __u16 namelen;
- __u8 *nameptr;
- __u32 numitems;
- __u16 itemnum;
- __u32 block;
- __u16 rawdepos;
-
- /* some checks */
- if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
- /* Warnings */
- if(ini->tot!=1) {
- printk("EFS: directory %s has more than one extent.\n",
- filp->f_dentry->d_name.name);
- printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n");
- return 0;
+ /* skip empty slots */
+ do {
+ offset = EFS_SLOT2OFF(dirblk, item);
+ if (!offset) {
+ DB(("EFS: skipping empty slot %d\n", item));
+ }
+ item++;
+ if (item == dirblk->db_slots) {
+ item = 0;
+ block++;
+ if (!offset) {
+ brelse(bh);
+ goto start_block;
+ }
}
- if(inode->i_size & (EFS_BLOCK_SIZE-1))
- printk("efs_readdir: dirsize != blocksize*n\n");
-
- /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */
- block = filp->f_pos >> EFS_BLOCK_SIZE_BITS;
- itemnum = filp->f_pos & 0xff;
-
- /* We found the last entry -> ready */
- if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS))
- return 0;
-
- /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */
- bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE);
- if(!bh) return 0;
-
- /* dirblock */
- rawdirblk = (__u8 *)bh->b_data;
- /* number of entries stored in this dirblock */
- numitems = rawdirblk[EFS_DB_ENTRIES];
- /* offset in block of #off diritem */
- rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+itemnum]<<1;
-
- /* diritem first contains the inode number, the namelen and the name */
- iteminode = ConvertLong(rawdirblk,rawdepos);
- namelen = (__u16)rawdirblk[rawdepos+EFS_DI_NAMELEN];
- nameptr = rawdirblk + rawdepos + EFS_DI_NAME;
+ } while(!offset);
+ entry = EFS_DENT4OFF(dirblk, offset);
+ /*
+ DB(("EFS_SLOT2OFF(%d) -> %d, EFS_DENT4OFF(%p, %d) -> %p) || ",
+ item-1, offset, dirblk, offset, entry));
#ifdef DEBUG_EFS
- printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n",
- itemnum,rawdepos,iteminode,nameptr,namelen);
+ {
+ __u8 *rawdirblk, nameptr;
+ __u32 iteminode;
+ __u16 namelen, rawdepos;
+ rawdirblk = (__u8*)bh->b_data;
+ rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+item-1] << 1;
+ DB(("OLD_WAY: offset = %d, dent = %p ||", rawdepos,
+ (struct efs_dir_entry *)(rawdirblk + rawdepos)));
+ }
#endif
- /* copy filename and data in direntry */
- filldir(dirent,nameptr,namelen,filp->f_pos,iteminode);
+ DB(("EFS: filldir(dirent, \"%.*s\", %d, %d, %d)\n",
+ entry->d_namelen, entry->d_name, entry->d_namelen,
+ filp->f_pos, efs_swab32(entry->ud_inum.l)));
+ */
+ filldir(dirent, entry->d_name, entry->d_namelen, filp->f_pos,
+ efs_swab32(entry->ud_inum.l));
+
+ brelse(bh);
- brelse(bh);
+ filp->f_pos = (block << EFS_BLOCK_SIZE_BITS) | item;
+ UPDATE_ATIME(in);
- /* store pos of next item */
- itemnum++;
- if(itemnum==numitems) {
- itemnum = 0;
- block++;
- }
- filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum;
- UPDATE_ATIME(inode);
-
- return 0;
+ return 0;
}
-
diff --git a/fs/efs/file.c b/fs/efs/file.c
index 4c04616bb..7ffaa6a16 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -1,218 +1,165 @@
-/* file.c
-
- read files on EFS filesystems
- now replaced by generic functions of the kernel:
- leaves only mapping of file block number -> disk block number in this file
-
- (C)95,96 Christian Vogelgsang
-*/
-
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
+/*
+ * linux/fs/efs/file.c
+ *
+ * Copyright (C) 1998 Mike Shaver
+ *
+ * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
+ * ``Inspired by'' fs/minix/file.c.
+ */
+
#include <linux/efs_fs.h>
-#include <linux/efs_fs_i.h>
-#include <linux/efs_fs_sb.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-
-static struct file_operations efs_file_ops = {
- NULL,
- generic_file_read,
- NULL,
- NULL,
- NULL,
- NULL,
- generic_file_mmap,
- NULL,
- NULL,
- NULL
+
+static struct file_operations efs_file_operations = {
+ NULL, /* lseek */
+ generic_file_read,
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ generic_file_mmap, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+ NULL /* fsync */
};
-struct inode_operations efs_file_in_ops = {
- &efs_file_ops,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- generic_readpage,
- NULL,
- efs_bmap,
- NULL,
- NULL
+struct inode_operations efs_file_inode_operations = {
+ &efs_file_operations, /* default file ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ generic_readpage, /* readpage */
+ NULL, /* writepage */
+ efs_bmap, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
};
-
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-#define CHECK(num) \
- eblk = ini->extents[num].ex_bytes[0]; \
- epos = ini->extents[num].ex_bytes[1] & 0xffffff; \
- elen = ini->extents[num].ex_bytes[1] >> 24; \
- if((blk >= epos)&&(blk < (epos+elen))) \
- result = (blk - epos) + eblk + sbi->fs_start;
-
-
-/* ----- efs_getblknum -----
- find the disc block number for a given logical file block number
-
- in - inode of file
- blk - logical file block number
-
- return - 0 on error, or unmapped block number
-*/
-static __u32 efs_getblk(struct inode *in,__u32 blk)
+
+static inline __u32
+check_extent(union efs_extent *ext, int blk, int fs_start)
{
- struct efs_sb_info *sbi = &in->i_sb->u.efs_sb;
- struct efs_inode_info *ini = &in->u.efs_i;
- struct buffer_head *bh;
-
- __u32 result = 0;
- __u32 eblk,epos,elen;
- int num,extnum,readahead;
- __u32 extblk;
- __u16 extoff,pos,cur,tot;
- union efs_extent *ptr;
-
-
- /* first check the current extend */
- cur = ini->cur;
- tot = ini->tot;
- CHECK(cur)
- if(result)
- return result;
-
- /* if only one extent exists and we are here the test failed */
- if(tot==1) {
- printk("efs: bmap failed on one extent!\n");
- return 0;
- }
-
- /* check the stored extents in the inode */
- num = MIN(tot,EFS_MAX_EXTENTS);
- for(pos=0;pos<num;pos++) {
- /* don't check the current again! */
- if(pos==cur)
- continue;
-
- CHECK(pos)
- if(result) {
- ini->cur = pos;
- return result;
- }
- }
+ int eblk, epos, elen;
- /* If the inode has only direct extents,
- the above tests must have found the block's extend! */
- if(tot<=EFS_MAX_EXTENTS) {
- printk("efs: bmap failed for direct extents!\n");
- return 0;
- }
-
- /* --- search in the indirect extensions list blocks --- */
-#ifdef DEBUG
- printk("efs - indirect search for %lu\n",blk);
-#endif
-
- /* calculate block and offset for begin of extent descr and read it */
- extblk = ini->extblk;
- extoff = 0;
- bh = bread(in->i_dev,extblk,EFS_BLOCK_SIZE);
- if(!bh) {
- printk("efs: read error in indirect extents\n");
+ eblk = ext->ex_bytes[0]; /* start disk block of the extent */
+ epos = ext->ex_bytes[1] & 0xFFFFFF; /* starting logical block */
+ elen = ext->ex_bytes[1] >> 24; /* length of the extent */
+
+ if ( (blk >= epos) && (blk < epos+elen) )
+ return blk - epos + eblk + fs_start;
return 0;
- }
- ptr = (union efs_extent *)bh->b_data;
-
- pos = 0; /* number of extend store in the inode */
- extnum = 0; /* count the extents in the indirect blocks */
- readahead = 10; /* number of extents to read ahead */
- while(1) {
-
- /* skip last current extent store in the inode */
- if(pos==cur) pos++;
-
- /* read new extent in inode buffer */
- ini->extents[pos].ex_bytes[0] = efs_swab32(ptr[pos].ex_bytes[0]);
- ini->extents[pos].ex_bytes[1] = efs_swab32(ptr[pos].ex_bytes[1]);
-
- /* we must still search */
- if(!result) {
- CHECK(pos)
- if(result)
- ini->cur = pos;
- }
- /* we found it already and read ahead */
- else {
- readahead--;
- if(!readahead)
- break;
- }
+}
- /* next storage place */
- pos++;
- extnum++;
+#define CHECK(index) (check_extent(&ini->extents[index], blk, sbi->fs_start))
- /* last extent checked -> finished */
- if(extnum==tot) {
- if(!result)
- printk("efs: bmap on indirect failed!\n");
- break;
- }
+static __u32
+efs_getblk(struct inode *in, __u32 blk)
+{
+ struct efs_sb_info *sbi = &in->i_sb->u.efs_sb;
+ struct efs_inode_info *ini = &in->u.efs_i;
+ int iter;
+
+ __u32 diskblk, total = ini->tot, current = ini->cur;
+
+ if (total <= EFS_MAX_EXTENTS) {
+ diskblk = CHECK(current);
+ if (diskblk)
+ return diskblk;
+
+ if (total == 1)
+ return 0;
+
+ /*
+ * OPT: start with current and then wrap, to optimize for
+ * read-forward pattern.
+ */
+ for (iter = 0; iter < total; iter++) {
+ if (iter == current)
+ continue; /* already checked the current extent */
+ diskblk = CHECK(iter);
+ if (diskblk) {
+ ini->cur = iter;
+ DB(("EFS: inode %d: found block %d as %d in ext %d\n",
+ in->i_ino, blk, diskblk, iter));
+ return diskblk;
+ }
+ }
+
+ DB(("EFS: block %d not found in direct inode %d (size %d)\n",
+ blk, in->i_ino, in->i_size));
+ return 0;
- extoff += 8;
- /* need new block */
- if(extoff==EFS_BLOCK_SIZE) {
- extoff = 0;
- extblk++;
-
- brelse(bh);
- bh = bread(in->i_dev,extblk,EFS_BLOCK_SIZE);
- if(!bh) {
- printk("efs: read error in indirect extents\n");
+ } else {
+ int indirext = 0, total_extents_checked = 0;
+
+ /* indirect inode */
+ DB(("EFS: inode %d is indirect (total %d, indir ", in->i_ino, total));
+ total = ini->extents[0].ex_ex.ex_offset;
+ DB(("%d)\n", total));
+
+ for (indirext = 0; indirext < total; indirext++) {
+ struct buffer_head *extbh;
+ union efs_extent *ptr;
+ int indirblk, indirbn, indirlen;
+ /*
+ * OPT: copy the current direct extent into the inode info for a
+ * quick check before we start reading blocks.
+ * OPT: copy _10_ into the inode info, like the old code did.
+ */
+
+ indirbn = ini->extents[indirext].ex_ex.ex_bn;
+ indirlen = ini->extents[indirext].ex_ex.ex_length;
+ for (indirblk = indirbn;
+ indirblk < indirbn + indirlen;
+ indirblk++) {
+ extbh = bread(in->i_dev, indirblk, EFS_BLOCK_SIZE);
+ if (!extbh) {
+ printk("EFS: ERROR: inode %ld bread of extent block %d failed\n",
+ in->i_ino, indirblk);
+ return 0;
+ }
+
+ for (ptr = (union efs_extent *)extbh->b_data;
+ ptr < (union efs_extent *)(extbh->b_data+EFS_BLOCK_SIZE);
+ ptr++, ++total_extents_checked) {
+
+ diskblk = check_extent(ptr, blk, sbi->fs_start);
+ if (diskblk || total_extents_checked > ini->tot) {
+ brelse(extbh);
+ return diskblk;
+ }
+ }
+
+ brelse(extbh);
+ }
+ }
+ DB(("EFS: inode %d: didn't find block %d (indirect search, size %d)\n",
+ in->i_ino, in->i_size));
return 0;
- }
- ptr = (union efs_extent *)bh->b_data;
}
- }
- brelse(bh);
-
- return result;
-}
-
+}
-/* ----- efs_bmap -----
- bmap: map a file block number to a device block number
-
- in - inode owning the block
- block - block number
-
- return - disk block
-*/
int efs_bmap(struct inode *in, int block)
{
- /* quickly reject invalid block numbers */
- if(block<0) {
-#ifdef DEBUG
- printk("efs_bmap: block < 0\n");
-#endif
- return 0;
- }
- /* since the kernel wants to read a full page of data, i.e. 8 blocks
- we must check if the block number is not too large */
- if(block>((in->i_size-1)>>EFS_BLOCK_SIZE_BITS)) {
-#ifdef DEBUG
- printk("efs_bmap: block %d > max %d == %d\n",
- block,in->i_size>>EFS_BLOCK_SIZE_BITS,in->i_blocks);
-#endif
- return 0;
- }
+ if (block < 0)
+ return 0;
+
+ /*
+ * the kernel wants a full page (== 4K == 8 EFS blocks), so be sure that
+ * the block number isn't too large for that.
+ */
+ if (block > ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS)) {
+ DB(("EFS: wacky: block %d > max %d\n", block,
+ ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS)));
+ return 0;
+ }
- return efs_getblk(in,block);
+ return efs_getblk(in, block);
}
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 7928e45b4..735d86d99 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -1,498 +1,339 @@
-/* inode.c
- *
- * Inode and Superblock handling for the EFS filesystem
+/*
+ * linux/fs/efs/inode.c
*
- * (C) 1995,96 Christian Vogelgsang
+ * Copyright (C) 1998 Mike Shaver
+ *
+ * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
+ * ``Inspired by'' fs/minix/inode.c.
*/
-
-#include <linux/module.h>
+
+#include <linux/module.h> /* module apparatus */
#include <linux/init.h> /* __initfunc */
-#include <linux/fs.h>
#include <linux/efs_fs.h>
-#include <linux/efs_fs_i.h>
-#include <linux/efs_fs_sb.h>
#include <linux/locks.h>
-
#include <asm/uaccess.h>
-/* ----- Define the operations for the Superblock ----- */
-void efs_read_inode(struct inode *);
-void efs_put_super(struct super_block *);
-int efs_statfs(struct super_block *, struct statfs *,int );
-
-static struct super_operations efs_sops = {
- efs_read_inode,
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- efs_put_super,
- NULL, /* write_super */
- efs_statfs,
- NULL
-};
-
-
-/* ----- Conversion utilities -----
- Get 16- and 32-bit unsigned values in big-endian format from a byte buffer
-*/
-__u32 ConvertLong(__u8 *buf, int offset)
-{
- return *((__u32 *)(buf + offset));
- /* return (__u32)buf[offset+3] |
- ((__u32)buf[offset+2])<<8 |
- ((__u32)buf[offset+1])<<16 |
- ((__u32)buf[offset])<<24;
- */
+#define COPY_EXTENT(from, to) \
+{ \
+ to.ex_bytes[0] = efs_swab32(from.ex_bytes[0]); \
+ to.ex_bytes[1] = efs_swab32(from.ex_bytes[1]); \
}
-__u16 ConvertShort(__u8 *buf, int offset)
+void
+efs_put_super(struct super_block *sb)
{
- return *((__u16 *)(buf + offset));
- /*
- return (__u16)buf[offset+1] |
- ((__u16)buf[offset])<<8;
- */
+ DB(("efs_put_super ... "));
+ lock_super(sb);
+ DB(("locked ... "));
+ sb->s_dev = 0;
+ unlock_super(sb);
+ DB(("unlocked ... "));
+ MOD_DEC_USE_COUNT;
+ DB(("MOD_DEC_USE_COUNT\n"));
}
+static struct super_operations efs_sops = {
+ efs_read_inode,
+ NULL, /* write_inode */
+ NULL, /* put_inode */
+ NULL, /* delete_inode */
+ NULL, /* notify_change */
+ efs_put_super,
+ NULL, /* write_super */
+ efs_statfs,
+ NULL, /* remount */
+};
-/* ----- Install/Remove Module -----
- These procedures are used to install/remove our filesystem
- module in the linux kernel
-*/
+static const char *
+efs_checkroot(struct super_block *sb, struct inode *dir)
+{
+ struct buffer_head *bh;
-/* describe filesystem */
-struct super_block *efs_read_super(struct super_block *s, void *d, int sil);
+ if (!S_ISDIR(dir->i_mode))
+ return "root directory is not a directory";
-static struct file_system_type efs_fs_type = {
- "efs",
- FS_REQUIRES_DEV,
- efs_read_super,
- NULL
-};
+ bh = bread(dir->i_dev, efs_bmap(dir, 0), EFS_BLOCK_SIZE);
+ if (!bh)
+ return "unable to read root directory";
-__initfunc(int init_efs_fs(void)) {
- return register_filesystem(&efs_fs_type);
+ /* XXX check sanity of root directory */
+
+ brelse(bh);
+ return NULL;
}
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-/* install module */
-int init_module(void)
+struct super_block *
+efs_read_super(struct super_block *s, void *data, int silent)
{
- return init_efs_fs();
+ struct buffer_head *bh;
+ struct efs_disk_sb *efs_sb;
+ struct efs_sb_info *sbi;
+ kdev_t dev = s->s_dev;
+ const char *errmsg;
+ struct inode *root;
+ __u32 magic;
+
+ DB(("read_super\n"));
+ MOD_INC_USE_COUNT;
+
+ lock_super(s);
+ set_blocksize(dev, EFS_BLOCK_SIZE);
+
+ /*
+ * XXXshaver
+ * If this is a CDROM, then there's a volume descriptor at block
+ * EFS_BLK_VOLDESC. What's there if it's just a disk partition?
+ */
+
+ bh = bread(dev, EFS_BLK_SUPER, EFS_BLOCK_SIZE);
+ if (!bh)
+ goto out_bad_sb;
+
+ efs_sb = (struct efs_disk_sb *)bh->b_data;
+ sbi = &s->u.efs_sb;
+ sbi->total_blocks = efs_sb->s_size;
+ sbi->first_block = efs_sb->s_firstcg;
+ sbi->group_size = efs_sb->s_cgfsize;
+ sbi->inode_blocks = efs_sb->s_cgisize;
+ sbi->total_groups = efs_sb->s_ncg;
+ magic = efs_sb->s_magic;
+ brelse(bh);
+
+ if (magic == EFS_MAGIC1 || magic == EFS_MAGIC2) {
+ DB(("EFS: valid superblock magic\n"));
+ } else {
+ goto out_no_fs;
+ }
+
+ if (efs_sb->s_dirty != EFS_CLEAN) {
+ switch(efs_sb->s_dirty) {
+ case EFS_ACTIVE:
+ errmsg = "Partition was not unmounted properly, but is clean";
+ break;
+ case EFS_ACTIVEDIRT:
+ errmsg = "Partition was mounted dirty and not cleanly unmounted";
+ break;
+ case EFS_DIRTY:
+ errmsg = "Partition was not umounted properly, and is dirty";
+ break;
+ }
+ if (!silent)
+ printk("EFS: ERROR: %s\n", errmsg);
+ goto out_unlock;
+ }
+
+ s->s_blocksize = EFS_BLOCK_SIZE;
+ s->s_blocksize_bits = EFS_BLOCK_SIZE_BITS;
+ s->s_magic = EFS_SUPER_MAGIC;
+ s->s_op = &efs_sops;
+ root = iget(s, EFS_ROOT_INODE);
+
+ errmsg = efs_checkroot(s, root);
+ if (errmsg)
+ goto out_bad_root;
+
+ s->s_root = d_alloc_root(root, NULL);
+ if (!s->s_root)
+ goto out_iput;
+
+ /* we only do RO right now */
+ if (!(s->s_flags & MS_RDONLY)) {
+ if (!silent)
+ printk("EFS: forcing read-only: RW access not supported\n");
+ s->s_flags |= MS_RDONLY;
+ }
+
+ unlock_super(s);
+ return s;
+
+ /* error-handling exit paths */
+ out_bad_root:
+ if (!silent)
+ printk("EFS: ERROR: %s\n", errmsg);
+ goto out_unlock;
+
+ out_iput:
+ iput(root);
+ brelse(bh);
+ goto out_unlock;
+
+ out_no_fs:
+ printk("EFS: ERROR: bad magic\n");
+ goto out_unlock;
+
+ out_bad_sb:
+ printk("EFS: unable to read superblock\n");
+
+ out_unlock:
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
-/* remove module */
-void cleanup_module(void)
+int
+efs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- unregister_filesystem(&efs_fs_type);
+ struct statfs tmp;
+
+ DB(("statfs\n"));
+ tmp.f_type = sb->s_magic;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = sb->u.efs_sb.total_blocks;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0; /* XXX? */
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
-#endif /* MODULE */
-
-#ifdef DEBUG_EFS
-void efs_dump_super(struct efs_super_block *sb) {
- printk("efs_super_block @ 0x%p:\n", sb);
- printk("size: %0#8lX firstcg: %0#8lX\n", sb->s_size, sb->s_firstcg);
- printk("cgfsize: %0#8lX cgisize: %0#8hX\n", sb->s_cgfsize,sb->s_cgisize);
- printk("sectors: %0#8hX heads: %0#8hX\n", sb->s_sectors, sb->s_heads);
- printk("ncg: %0#8hX dirty: %0#8hX\n", sb->s_ncg, sb->s_dirty);
- printk("time: %0#8lX magic: %0#8lX\n", sb->s_time, sb->s_magic);
- printk("fname: %.6s fpack: %.6s\n", sb->s_fname, sb->s_fpack);
- printk("bmsize: %0#8lX tfree: %0#8lX\n", sb->s_bmsize, sb->s_tfree);
- printk("tinode: %0#8lX bmblock: %0#8lX\n", sb->s_tinode, sb->s_bmblock);
- printk("replsb: %0#8lX lastiall: %0#8lX\n", sb->s_replsb,
- sb->s_lastialloc);
- printk("checksum: %0#8lX\n", sb->s_checksum);
-}
-
-void efs_dump_inode(struct efs_disk_inode *di) {
- printk("efs_disk_inode @ 0x%p: ", di);
- printk("[%o %hd %hd %u %u %u %u %u #ext=%hd %u %u]\n",
- di->di_mode, di->di_nlink, di->di_uid, di->di_gid, di->di_size,
- di->di_atime, di->di_mtime, di->di_ctime, di->di_gen,
- di->di_numextents, di->di_version);
-}
-#endif
-/* ----- efs_checkVolDesc -----
- Analyse the first block of a CD and check
- if it's a valid efs volume descriptor
-
- blk - buffer with the data of first block
- silent - 0 -> verbose
-
- return : 0 - error ; >0 - start block of filesystem
-*/
-#if 0
-static __u32 efs_checkVolDesc(__u8 *blk,int silent)
+void
+efs_read_inode(struct inode *in)
{
- __u32 magic;
- __u8 *ptr;
- __u8 name[10];
- __u32 pos,len;
- int i;
-
- /* is the magic cookie here? */
- magic = ConvertLong(blk,0);
- if(magic!=0x0be5a941) {
- printk("EFS: no magic on first block\n");
- return 0;
- }
-
- /* Walk through the entries of the VD */
- /* Quite useless, but gives nice output ;-) */
- ptr = blk + EFS_VD_ENTRYFIRST;
- name[8] = 0;
- while(*ptr) {
- for(i=0;i<8;i++)
- name[i] = ptr[i];
-
- /* start and length of entry */
- pos = ConvertLong(ptr,EFS_VD_ENTRYPOS);
- len = ConvertLong(ptr,EFS_VD_ENTRYLEN);
-
- if(!silent)
- printk("EFS: VolDesc: %8s blk: %08lx len: %08lx\n",
- name,pos,len);
+ struct efs_sb_info *efs_sb = &in->i_sb->u.efs_sb;
+ struct buffer_head *bh;
+ struct efs_disk_inode *di;
+ struct efs_inode_info *ini = &in->u.efs_i;
+ int block, ino = in->i_ino, offset;
+ __u16 numext;
+ __u32 rdev;
+
+ DB(("read_inode"));
+
+ /*
+ * Calculate the disk block and offset for the inode.
+ * There are 4 inodes per block.
+ */
+ block = ino / EFS_INODES_PER_BLOCK;
+
+ /*
+ * Inodes are stored at the beginning of every cylinder group.
+ *
+ * We find the block containing the inode like so:
+ * - block is set above to the ``logical'' block number
+ * - first_block is the start of the FS
+ * - (block / inode_blocks) is the cylinder group that the inode is in.
+ * - (block % inode_blocks) is the block offset within the cg
+ *
+ */
+ block = efs_sb->first_block +
+ (efs_sb->group_size * (block / efs_sb->inode_blocks)) +
+ (block % efs_sb->inode_blocks);
- ptr+=EFS_VD_ENTRYSIZE;
- }
+ /* find the offset */
+ offset = (ino % EFS_INODES_PER_BLOCK) << 7;
- pos = ConvertLong(blk,EFS_VD_FS_START);
- printk("EFS: FS start: %08lx\n",pos);
- return pos;
-}
-#endif
+ DB(("EFS: looking for inode #%xl\n", ino));
-/* ----- efs_checkSuper -----
- Check if the given block is a valid EFS-superblock
-
- sbi - my EFS superblock info
- block - block that must be examined
-
- return - 0 ok, -1 error
-*/
-static int efs_verify_super(struct efs_super_block *sb,
- struct efs_sb_info *sbi,
- int silent)
-{
- __u32 magic;
-
- magic = sb->s_magic;
- /* check if the magic cookie is here */
- if((magic!=EFS_MAGIC1)&&(magic!=EFS_MAGIC2)) {
- printk("EFS: magic %#X doesn't match %#X or %#X!\n",
- magic, EFS_MAGIC1, EFS_MAGIC2);
- return -1;
- }
+ bh = bread(in->i_dev, block, EFS_BLOCK_SIZE);
- /* XXX should check csum */
-
- sbi->total_blocks = sb->s_size;
- sbi->first_block = sb->s_firstcg;
- sbi->group_size = sb->s_cgfsize;
- sbi->inode_blocks = sb->s_cgisize;
- sbi->total_groups = sb->s_ncg;
-
- return 0;
-}
+ if (!bh) {
+ printk("EFS: failed to bread blk #%xl for inode %#xl\n", block, ino);
+ goto error;
+ }
+ di = (struct efs_disk_inode *)(bh->b_data + offset);
-/* ----- efs_read_super -----
- read_super: if the fs gets mounted this procedure is called to
- check if the filesystem is valid and to fill the superblock struct
-
- s - superblock struct
- d - options for fs (unused)
- sil - flag to be silent
-
- return - filled s struct or NULL on error
- */
+ /* standard inode info */
+ in->i_mtime = efs_swab32(di->di_mtime);
+ in->i_ctime = efs_swab32(di->di_ctime);
+ in->i_atime = efs_swab32(di->di_atime);
+ in->i_size = efs_swab32(di->di_size);
+ in->i_nlink = efs_swab16(di->di_nlink);
+ in->i_uid = efs_swab16(di->di_uid);
+ in->i_gid = efs_swab16(di->di_gid);
+ in->i_mode = efs_swab16(di->di_mode);
-struct super_block *efs_read_super(struct super_block *s, void *d, int silent)
-{
- struct buffer_head *bh;
- struct efs_sb_info *sb_info = (struct efs_sb_info *)&s->u.efs_sb;
- struct efs_super_block *es;
- int error = 0;
- int dev = s->s_dev;
- struct inode *root_inode = NULL;
-
- MOD_INC_USE_COUNT;
-
- /* say hello to my log file! */
-#ifdef EFS_DEBUG
- if(!silent)
- printk("EFS: --- Filesystem ---\n");
-#endif
- /* set blocksize to 512 */
- set_blocksize(dev, EFS_BLOCK_SIZE);
-
- lock_super(s);
-
-#if 0
- /* Read first block of CD: the Volume Descriptor */
- bh = bread(dev, 0, EFS_BLOCK_SIZE);
- if(bh) {
- sb_info->fs_start = efs_checkVolDesc((__u8 *)bh->b_data,silent);
- if(sb_info->fs_start==0) {
- printk("EFS: failed checking Volume Descriptor\n");
- /* error++; */
- }
- brelse(bh);
- } else {
- printk("EFS: cannot read the first block\n");
- error++;
- }
-#endif 0
+ rdev = efs_swab32(*(__u32 *) &di->di_u.di_dev);
+ numext = efs_swab16(di->di_numextents);
- /* Read the Superblock */
- if(!error) {
-#ifdef DEBUG_EFS
- if (!silent)
- printk("EFS: reading superblock.\n");
-#endif
- bh = bread(dev, EFS_BLK_SUPER, EFS_BLOCK_SIZE );
- if(bh) {
- es = (struct efs_super_block *)(bh->b_data);
-#ifdef DEBUG_EFS
- if(!silent)
- efs_dump_super(es);
-#endif
- if(efs_verify_super(es, sb_info, silent)) {
- printk("EFS: failed checking Superblock\n");
- error++;
- }
- brelse(bh);
- } else {
- printk("EFS: cannot read the superblock\n");
- error++;
- }
- }
-
- if(!error) {
- s->s_blocksize = EFS_BLOCK_SIZE;
- s->s_blocksize_bits = EFS_BLOCK_SIZE_BITS;
-
- s->s_magic = EFS_SUPER_MAGIC;
- s->s_flags = MS_RDONLY;
- s->s_op = &efs_sops;
- s->s_dev = dev;
- root_inode = iget(s, EFS_ROOT_INODE);
- s->s_root = d_alloc_root(root_inode, NULL);
- if (!s->s_root) {
- error++;
- printk("EFS: couldn't allocate root inode!\n");
- }
- }
+ if (numext > EFS_MAX_EXTENTS) {
+ DB(("EFS: inode #%lx is indirect (%d)\n", ino, numext));
+
+ /*
+ * OPT: copy the first 10 extents in here?
+ */
+ } else {
+ int i;
- unlock_super(s);
-
- if(check_disk_change(s->s_dev)) {
- printk("EFS: Device changed!\n");
- error++;
+ DB(("EFS: inode %#lx is direct. Happy day!\n", in->i_ino));
+ ini->extblk = block;
+
+ /* copy extents into inode_info */
+ for (i = 0; i < numext; i++) {
+ COPY_EXTENT(di->di_u.di_extents[i], ini->extents[i]);
}
- /* We found errors -> say goodbye! */
- if(error) {
- s->s_dev = 0;
- d_delete(s->s_root); /* XXX is this enough? */
- printk("EFS: init failed with %d errors\n", error);
- brelse(bh);
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- return s;
+ }
+ ini->tot = numext;
+ ini->cur = 0;
+ brelse(bh);
+
+ switch(in->i_mode & S_IFMT) {
+ case S_IFDIR:
+ in->i_op = &efs_dir_inode_operations;
+ break;
+ case S_IFREG:
+ in->i_op = &efs_file_inode_operations;
+ break;
+ case S_IFLNK:
+ in->i_op = &efs_symlink_inode_operations;
+ break;
+ case S_IFCHR:
+ in->i_rdev = rdev;
+ in->i_op = &chrdev_inode_operations;
+ break;
+ case S_IFBLK:
+ in->i_rdev = rdev;
+ in->i_op = &blkdev_inode_operations;
+ break;
+ case S_IFIFO:
+ init_fifo(in);
+ break;
+ default:
+ printk("EFS: ERROR: unsupported inode mode %lo\n",
+ (in->i_mode & S_IFMT));
+ goto error;
+ }
+
+ return;
+
+ error:
+ in->i_mtime = in->i_atime = in->i_ctime = 0;
+ in->i_size = 0;
+ in->i_nlink = 1;
+ in->i_uid = in->i_gid = 0;
+ in->i_mode = S_IFREG;
+ in->i_op = NULL;
}
+static struct file_system_type efs_fs_type = {
+ "efs",
+ FS_REQUIRES_DEV,
+ efs_read_super,
+ NULL
+};
-/* ----- efs_put_super -----
- put_super: remove the filesystem and the module use count
-
- s - superblock
-*/
-void efs_put_super(struct super_block *s)
+__initfunc(int
+init_efs_fs(void))
{
- lock_super(s);
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
+ return register_filesystem(&efs_fs_type);
}
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
-/* ----- efs_statfs -----
- statfs: get informatio on the filesystem
-
- s - superblock of fs
- buf - statfs struct that has to be filled
-*/
-int efs_statfs(struct super_block *s, struct statfs *buf,int bufsize)
+int
+init_module(void)
{
- struct efs_sb_info *sbi = (struct efs_sb_info *)&s->u.generic_sbp;
- struct statfs tmp;
-
- tmp.f_type = EFS_SUPER_MAGIC;
- tmp.f_bsize = EFS_BLOCK_SIZE;
- tmp.f_blocks = sbi->total_blocks;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 100; /* don't know how to calculate the correct value */
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
-
- return copy_to_user(buf,&tmp,bufsize) ? -EFAULT : 0;
+ return init_efs_fs();
}
-
-/* ----- efs_read_inode -----
- read an inode specified by in->i_ino from disk, fill the inode
- structure and install the correct handler for the file type
-
- in - inode struct
-*/
-void efs_read_inode(struct inode *in)
+void
+cleanup_module(void)
{
- struct buffer_head *bh;
- struct efs_sb_info *sbi = (struct efs_sb_info *)&in->i_sb->u.generic_sbp;
- __u32 blk,off;
- int error = 0;
-
- /* Calc the discblock and the offset for inode (4 Nodes fit in one block) */
- blk = in->i_ino >> 2;
- blk = sbi->fs_start + sbi->first_block +
- (sbi->group_size * (blk / sbi->inode_blocks)) +
- (blk % sbi->inode_blocks);
- off = (in->i_ino&3)<<7;
-
- /* Read the block with the inode from disk */
-#ifdef DEBUG_EFS
- printk("EFS: looking for inode %#xl\n", in->i_ino);
-#endif
- bh = bread(in->i_dev,blk,EFS_BLOCK_SIZE);
- if(bh) {
-
- struct efs_disk_inode *di = (struct efs_disk_inode *)(bh->b_data + off);
- __u16 numext;
- struct efs_inode_info *ini = &in->u.efs_i;
- __u32 rdev;
- int i;
-
- /* fill in standard inode infos */
- in->i_mtime = efs_swab32(di->di_mtime);
- in->i_ctime = efs_swab32(di->di_ctime);
- in->i_atime = efs_swab32(di->di_atime);
- in->i_size = efs_swab32(di->di_size);
- in->i_nlink = efs_swab16(di->di_nlink);
- in->i_uid = efs_swab16(di->di_uid);
- in->i_gid = efs_swab16(di->di_gid);
- in->i_mode = efs_swab16(di->di_mode);
-
- /* Special files store their rdev value where the extends of
- a regular file are found */
- /* rdev = ConvertLong(rawnode,EFS_IN_EXTENTS);*/
- /* XXX this isn't right */
- rdev = efs_swab32(*(__u32 *)&di->di_u.di_dev);
-
- /* -----------------------------------------------------------------
- The following values are stored in my private part of the Inode.
- They are necessary for further operations with the file */
-
- /* get the number of extends the inode posseses */
- numext = efs_swab16(di->di_numextents);
-
- /* if this inode has more than EFS_MAX_EXTENDS then the extends are
- stored not directly in the inode but indirect on an extra block.
- The address of the extends-block is stored in the inode */
- if(numext>EFS_MAX_EXTENTS) {
- struct buffer_head *bh2;
- printk("EFS: inode #%lx has > EFS_MAX_EXTENTS (%d)\n",
- in->i_ino, numext);
-
- /* Store the discblock and offset of extend-list in Inode info */
- ini->extblk = sbi->fs_start + efs_swab32((__u32)(di->di_u.di_extents));
-
- /* read INI_MAX_EXT extents from the indirect block */
- printk("EFS: ");
- bh2 = bread(in->i_dev,ini->extblk,EFS_BLOCK_SIZE);
- if(bh2) {
- union efs_extent *ptr =
- (union efs_extent *)bh2->b_data;
- for(i=0;i<EFS_MAX_EXTENTS;i++) {
- ini->extents[i].ex_bytes[0] = efs_swab32(ptr[i].ex_bytes[0]);
- ini->extents[i].ex_bytes[1] = efs_swab32(ptr[i].ex_bytes[1]);
- }
- brelse(bh2);
- } else
- printk("efs: failed reading indirect extents!\n");
-
- } else {
-#ifdef DEBUG_EFS
- printk("EFS: inode %#Xl is direct (woohoo!)\n",
- in->i_ino);
-#endif
- /* The extends are found in the inode block */
- ini->extblk = blk;
-
- /* copy extends directly from rawinode */
- for(i=0;i<numext;i++) {
- ini->extents[i].ex_bytes[0] = efs_swab32(di->di_u.di_extents[i].ex_bytes[0]);
- ini->extents[i].ex_bytes[1] = efs_swab32(di->di_u.di_extents[i].ex_bytes[1]);
- }
- }
- ini->tot = numext;
- ini->cur = 0;
-
- brelse(bh);
-
-#ifdef DEBUG_EFS
- printk("%lx inode: blk %lx numext %x\n",in->i_ino,ini->extblk,numext);
- efs_dump_inode(di);
-#endif
-
- /* Install the filetype Handler */
- switch(in->i_mode & S_IFMT) {
- case S_IFDIR:
- in->i_op = &efs_dir_in_ops;
- break;
- case S_IFREG:
- in->i_op = &efs_file_in_ops;
- break;
- case S_IFLNK:
- in->i_op = &efs_symlink_in_ops;
- break;
- case S_IFCHR:
- in->i_rdev = rdev;
- in->i_op = &chrdev_inode_operations;
- break;
- case S_IFBLK:
- in->i_rdev = rdev;
- in->i_op = &blkdev_inode_operations;
- break;
- case S_IFIFO:
- init_fifo(in);
- break;
- default:
- printk("EFS: Unsupported inode Mode %o\n",(unsigned int)(in->i_mode));
- error++;
- break;
- }
-
- } else {
- printk("EFS: Inode: failed bread!\n");
- error++;
- }
-
- /* failed inode */
- if(error) {
- printk("EFS: read inode failed with %d errors\n",error);
- in->i_mtime = in->i_atime = in->i_ctime = 0;
- in->i_size = 0;
- in->i_nlink = 1;
- in->i_uid = in->i_gid = 0;
- in->i_mode = S_IFREG;
- in->i_op = NULL;
- }
+ unregister_filesystem(&efs_fs_type);
}
+
+#endif
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index 752aa5fe1..eba441e5a 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -1,141 +1,96 @@
-/* namei.c
-
- name lookup for EFS filesystem
-
- (C)95,96 Christian Vogelgsang
-*/
+/*
+ * linux/fs/efs/namei.c
+ *
+ * Copyright (C) 1998 Mike Shaver
+ *
+ * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
+ * ``Inspired by'' fs/minix/namei.c.
+ */
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
#include <linux/efs_fs.h>
-#include <linux/efs_fs_i.h>
-#include <linux/efs_fs_sb.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
+#include <linux/errno.h>
-/* ----- efs_find_entry -----
- search a raw efs dir entry for the given name
-
- dir - inode of directory
- oname - name to search for
- onamelen- length of name
-
- return - inode number of the found entry or 0 on error
-*/
-static struct buffer_head * efs_find_entry(struct inode *dir,
- const char *oname,
- int onamelen,
- struct efs_dir_entry *res_dir)
+static struct buffer_head *
+efs_find_entry(struct inode *dir, const char *oname, int onamelen,
+ struct efs_dir_entry **res_dir)
{
- struct efs_inode_info *ini = &dir->u.efs_i;
- struct buffer_head *bh = NULL;
- __u32 inode;
- __u16 i;
- __u8 *name;
- __u16 namelen;
- __u32 blknum,b;
- struct efs_dirblk *db;
-
- /* Warnings */
- if(ini->tot!=1)
- printk("efs_find: More than one extent!\n");
- if(dir->i_size & (EFS_BLOCK_SIZE-1))
- printk("efs_find: dirsize != blocklen * n\n");
+ struct buffer_head *bh;
+ struct efs_sb_info *sbi;
+ struct efs_dirblk *dirblk;
+ __u32 offset, block, maxblk;
+ __u16 i, namelen;
+ char *name;
- /* Search in every dirblock */
- inode = 0;
- blknum = dir->i_size >> EFS_BLOCK_SIZE_BITS;
-#ifdef DEBUG_EFS
- printk("EFS: directory with inode %#xd has %d blocks\n",
- dir->i_ino, blknum);
-#endif
- for(b=0;b<blknum;b++) {
- int db_offset;
-#ifdef DEBUG_EFS
- printk("EFS: trying block %d\n", b);
-#endif
- /* Read a raw dirblock */
- bh = bread(dir->i_dev,efs_bmap(dir,b),EFS_BLOCK_SIZE);
- if(!bh) {
- printk("EFS: efs_bmap returned NULL!\n");
- return 0;
- }
-
- db = (struct efs_dirblk *)bh->b_data;
- if (db->db_magic != EFS_DIRBLK_MAGIC) {
- printk("EFS: dirblk has bad magic (%#xl)!\n",
- db->db_magic);
- return NULL;
- }
-#ifdef DEBUG_EFS
- printk("EFS: db %d has %d entries, starting at offset %#x\n",
- b, db->db_slots, (__u16)db->db_firstused << 1);
-#endif
- for(i = 0 ; i < db->db_slots ; i++) {
- struct efs_dent * de;
- int entry_inode;
- db_offset = ((__u16)db->db_space[i] << 1)
- - EFS_DIRBLK_HEADERSIZE;
- de = (struct efs_dent *)(&db->db_space[db_offset]);
+ *res_dir = NULL;
+ if (!dir || !dir->i_sb)
+ return NULL;
+ sbi = &dir->i_sb->u.efs_sb;
+ bh = NULL;
+ block = offset = 0;
+ maxblk = dir->i_size >> EFS_BLOCK_SIZE_BITS;
+ DB(("EFS: dir has %d blocks\n", maxblk));
+ for (block = 0; block < maxblk; block++) {
- /* inode, namelen and name of direntry */
- entry_inode = efs_swab32(de->ud_inum.l);
- namelen = de->d_namelen;
- name = de->d_name;
-#ifdef 0
- printk("EFS: entry %d @ %#x has inode %#x, %s/%d\n",
- i, db_offset, entry_inode, name, namelen);
-#endif
- /* we found the name! */
- if((namelen==onamelen)&&
- (!memcmp(oname,name,onamelen))) {
- res_dir->inode = entry_inode;
-#ifdef DEBUG_EFS
- printk("EFS: found inode %d\n",
- entry_inode);
-#endif
- return bh;
- }
- }
+ bh = bread(dir->i_dev, efs_bmap(dir, block), EFS_BLOCK_SIZE);
+ if (!bh) {
+ DB(("EFS: find_entry: skip blk %d (ino %#lx): bread\n",
+ block, dir->i_ino));
+ continue;
}
-#ifdef DEBUG_EFS
- printk("EFS: efs_find_entry didn't find inode for \"%s\"/%d!\n",
- oname, onamelen);
-#endif
- return NULL;
- /* not reached */
-}
+ dirblk = (struct efs_dirblk *)bh->b_data;
+
+ if (efs_swab32(dirblk->db_magic) != EFS_DIRBLK_MAGIC) {
+ printk("EFS: dirblk %d (ino %#lx) has bad magic (%#x)!\n",
+ block, dir->i_ino, efs_swab32(dirblk->db_magic));
+ brelse(bh);
+ continue;
+ }
+
+ DB(("EFS: db %d has %d entries\n", block, dirblk->db_slots));
+
+ for (i = 0; i < dirblk->db_slots; i++) {
+ struct efs_dir_entry *dent;
+ __u16 off = EFS_SLOT2OFF(dirblk, i);
+ if (!off) {
+ DB(("skipping empty slot %d\n", i));
+ continue; /* skip empty slot */
+ }
+ dent = EFS_DENT4OFF(dirblk, off);
+ namelen = dent->d_namelen;
+ name = dent->d_name;
+
+ if ((namelen == onamelen) &&
+ !memcmp(oname, name, onamelen)) {
+ *res_dir = dent;
+ return bh;
+ }
+ }
-/* ----- efs_lookup -----
- lookup inode operation:
- check if a given name is in the dir directory
-
- dir - pointer to inode of directory
- name - name we must search for
- len - length of name
- result - pointer to inode struct if we found it or NULL on error
-
- return - 0 everything is ok or <0 on error
-*/
-int efs_lookup(struct inode *dir, struct dentry *dentry)
+ brelse(bh);
+ }
+ DB(("EFS: find_entry didn't find inode for \"%s\"/%d\n",
+ oname, onamelen));
+ return NULL;
+}
+
+int
+efs_lookup(struct inode *dir, struct dentry *dentry)
{
- struct inode *inode = NULL;
- struct buffer_head *bh;
- struct efs_dir_entry de;
-
- bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
- if (bh) {
- int ino = de.inode;
- brelse(bh);
- inode = iget(dir->i_sb, ino);
+ struct buffer_head *bh;
+ struct inode *in = NULL;
+ struct efs_dir_entry *dent;
+
+ bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &dent);
+ if (bh) {
+ int ino = efs_swab32(dent->ud_inum.l);
- if (!inode)
- return -EACCES;
- }
+ brelse(bh);
+ in = iget(dir->i_sb, ino);
+ if (!in)
+ return -EACCES;
+ }
- d_add(dentry, inode);
- return 0;
+ d_add(dentry, in);
+ return 0;
}
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 05e3c082d..95ab238a4 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -1,25 +1,64 @@
-/* symlink.c
+/*
+ * linux/fs/efs/symlink.c
*
- * Symbolic link handling for EFS
+ * Copyright (C) 1998 Mike Shaver
*
- * (C)1995,96 Christian Vogelgsang
- *
- * Based on the symlink.c from minix-fs by Linus
+ * Portions derived from work (C) 1995,1996 Christian Vogelgsang.
+ * ``Inspired by'' fs/ext2/symlink.c.
*/
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
#include <linux/efs_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
#include <asm/uaccess.h>
-static int efs_readlink(struct inode *, char *, int);
-static struct dentry * efs_follow_link(struct inode *, struct dentry *);
+static struct dentry *
+efs_follow_link(struct dentry *dentry, struct dentry *base)
+{
+ struct inode *in = dentry->d_inode;
+ struct buffer_head *bh;
+
+ bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE);
+ if (!bh) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ UPDATE_ATIME(in);
+ base = lookup_dentry(bh->b_data, base, 1);
+ brelse(bh);
+ return base;
+}
+
+static int
+efs_readlink(struct dentry *dentry, char * buffer, int buflen)
+{
+ int i;
+ struct buffer_head *bh;
+ struct inode *in = dentry->d_inode;
+
+ if (buflen > 1023)
+ buflen = 1023;
+
+ if (in->i_size < buflen)
+ buflen = in->i_size;
+
+ bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE);
+ if (!bh)
+ return 0;
+ i = 0;
+
+ /* XXX need strncpy_to_user */
+ while (i < buflen && bh->b_data[i])
+ i++;
+
+ if (copy_to_user(buffer, bh->b_data, i))
+ i = -EFAULT;
+
+ UPDATE_ATIME(in);
+
+ brelse(bh);
+ return i;
+}
-struct inode_operations efs_symlink_in_ops = {
+struct inode_operations efs_symlink_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
@@ -30,111 +69,12 @@ struct inode_operations efs_symlink_in_ops = {
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- efs_readlink, /* readlink */
- efs_follow_link, /* follow_link */
- NULL,
- NULL,
+ efs_readlink,
+ efs_follow_link,
+ NULL, /* readpage */
+ NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL /* smap */
};
-
-
-/* ----- efs_getlinktarget -----
- read the target of the link from the data zone of the file
-*/
-static char *efs_getlinktarget(struct inode *in)
-{
- struct buffer_head * bh;
- char *name;
- __u32 size = in->i_size;
- __u32 block;
-
- /* link data longer than 1024 not supported */
- if(size>2*EFS_BLOCK_SIZE) {
- printk("efs_getlinktarget: name too long: %lu\n",in->i_size);
- return NULL;
- }
-
- /* get some memory from the kernel to store the name */
- name = kmalloc(size+1,GFP_KERNEL);
- if(!name) return NULL;
-
- /* read first 512 bytes of target */
- block = efs_bmap(in,0);
- bh = bread(in->i_dev,block,EFS_BLOCK_SIZE);
- if(!bh) {
- kfree(name);
- return NULL;
- }
- memcpy(name,bh->b_data,(size>EFS_BLOCK_SIZE)?EFS_BLOCK_SIZE:size);
- brelse(bh);
-
- /* if the linktarget is long, read the next block */
- if(size>EFS_BLOCK_SIZE) {
- bh = bread(in->i_dev,block+1,EFS_BLOCK_SIZE);
- if(!bh) {
- kfree(name);
- return NULL;
- }
- memcpy(name+EFS_BLOCK_SIZE,bh->b_data,size-EFS_BLOCK_SIZE);
- brelse(bh);
- }
-
- /* terminate string and return it */
- name[size]=0;
- return name;
-}
-
-
-/* ----- efs_follow_link -----
- get the inode of the link target
-*/
-static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base)
-{
- char * name;
- UPDATE_ATIME(dir);
- name = efs_getlinktarget(dir);
-#ifdef DEBUG_EFS
- printk("EFS: efs_getlinktarget(%d) returned \"%s\"\n",
- dir->i_ino, name);
-#endif
- base = lookup_dentry(name, base, 1);
- kfree(name);
- return base;
-}
-
-/* ----- efs_readlink -----
- read the target of a link and return the name
-*/
-static int efs_readlink(struct inode * dir, char * buffer, int buflen)
-{
- int i;
- struct buffer_head * bh;
-
- if (buflen > 1023)
- buflen = 1023;
- bh = bread(dir->i_dev,efs_bmap(dir,0),EFS_BLOCK_SIZE);
- if (!bh)
- return 0;
- /* copy the link target to the given buffer */
- i = 0;
-#ifdef DEBUG_EFS
- printk("EFS: efs_readlink returning ");
-#endif
- while (i<buflen && bh->b_data[i] && i < dir->i_size) {
-#ifdef DEBUG_EFS
- printk("%c", bh->b_data[i]);
-#endif
- i++;
- }
-#ifdef DEBUG_EFS
- printk("\n");
-#endif
- if (copy_to_user(buffer, bh->b_data, i))
- i = -EFAULT;
-
- brelse(bh);
- return i;
-}
-