summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/efs/Makefile2
-rw-r--r--fs/efs/dir.c173
-rw-r--r--fs/efs/inode.c6
-rw-r--r--fs/efs/namei.c10
-rw-r--r--fs/efs/symlink.c138
-rw-r--r--include/linux/efs_fs.h191
-rw-r--r--include/linux/efs_fs_i.h27
-rw-r--r--include/linux/efs_fs_sb.h29
8 files changed, 416 insertions, 160 deletions
diff --git a/fs/efs/Makefile b/fs/efs/Makefile
index 049456899..5a8556795 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 fa07a298f..a89dd304e 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -17,35 +17,35 @@ static int efs_readdir(struct file *,void *,filldir_t);
extern int efs_lookup(struct inode *, struct dentry *);
static struct file_operations efs_dir_ops = {
- NULL,
- NULL,
- NULL,
- efs_readdir,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL,
+ NULL,
+ NULL,
+ efs_readdir,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};
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
+ &efs_dir_ops,
+ NULL,
+ efs_lookup,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ efs_bmap,
+ NULL,
+ NULL
};
@@ -61,72 +61,77 @@ struct inode_operations efs_dir_in_ops = {
return - 0 ok, <0 error
*/
static int efs_readdir(struct file *filp,
- void *dirent, filldir_t filldir)
+ 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;
+ 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_readdir: More than one extent!\n");
- 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;
+ /* 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;
+ }
+ 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;
-
-#ifdef DEBUG
- printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n",itemnum,rawdepos,iteminode,nameptr,namelen);
+ /* 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;
+
+#ifdef DEBUG_EFS
+ printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n",
+ itemnum,rawdepos,iteminode,nameptr,namelen);
#endif
- /* copy filename and data in direntry */
- filldir(dirent,nameptr,namelen,filp->f_pos,iteminode);
+ /* copy filename and data in direntry */
+ filldir(dirent,nameptr,namelen,filp->f_pos,iteminode);
- brelse(bh);
+ brelse(bh);
/* store pos of next item */
- itemnum++;
- if(itemnum==numitems) {
- itemnum = 0;
- block++;
- }
- filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum;
- UPDATE_ATIME(inode);
+ 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/inode.c b/fs/efs/inode.c
index b84231cd5..e8f38294d 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -415,16 +415,18 @@ void efs_read_inode(struct inode *in)
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;
+ 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 extends!\n");
+ printk("efs: failed reading indirect extents!\n");
} else {
#ifdef DEBUG_EFS
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index 82086accd..752aa5fe1 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -84,7 +84,7 @@ static struct buffer_head * efs_find_entry(struct inode *dir,
entry_inode = efs_swab32(de->ud_inum.l);
namelen = de->d_namelen;
name = de->d_name;
-#ifdef DEBUG_EFS
+#ifdef 0
printk("EFS: entry %d @ %#x has inode %#x, %s/%d\n",
i, db_offset, entry_inode, name, namelen);
#endif
@@ -99,13 +99,11 @@ static struct buffer_head * efs_find_entry(struct inode *dir,
return bh;
}
}
+ }
#ifdef DEBUG_EFS
- printk("EFS: efs_find_entry didn't find inode for \"%s\"!\n",
- oname);
+ printk("EFS: efs_find_entry didn't find inode for \"%s\"/%d!\n",
+ oname, onamelen);
#endif
- return NULL;
- }
- printk("EFS: Falling off the end of efs_find_entry! Bogus!\n");
return NULL;
/* not reached */
}
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 6197bb6f3..05e3c082d 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -45,45 +45,45 @@ struct inode_operations efs_symlink_in_ops = {
*/
static char *efs_getlinktarget(struct inode *in)
{
- struct buffer_head * bh;
- char *name;
- __u32 size = in->i_size;
- __u32 block;
+ 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;
- }
+ /* 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;
+ /* 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);
+ /* 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);
- }
+ /* 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;
+ /* terminate string and return it */
+ name[size]=0;
+ return name;
}
@@ -92,19 +92,16 @@ static char *efs_getlinktarget(struct inode *in)
*/
static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base)
{
- struct buffer_head * bh;
- __u32 block;
-
- block = efs_bmap(dir,0);
- bh = bread(dir->i_dev,block,EFS_BLOCK_SIZE);
- if (!bh) {
- dput(base);
- return ERR_PTR(-EIO);
- }
- UPDATE_ATIME(dir);
- base = lookup_dentry(bh->b_data, base, 1);
- brelse(bh);
- return 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 -----
@@ -112,25 +109,32 @@ static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base)
*/
static int efs_readlink(struct inode * dir, char * buffer, int buflen)
{
- int i;
- char c;
- struct buffer_head * bh;
- __u32 block;
-
- block = efs_bmap(dir,0);
- if (buflen > 1023)
- buflen = 1023;
- bh = bread(dir->i_dev,block,EFS_BLOCK_SIZE);
- if (!bh)
- return 0;
+ int i;
+ struct buffer_head * bh;
- /* copy the link target to the given buffer */
- i = 0;
- while (i<buflen && (c = bh->b_data[i])) {
- i++;
- put_user(c,buffer++);
- }
-
- brelse(bh);
- return i;
+ 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;
}
+
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
new file mode 100644
index 000000000..93fcb272a
--- /dev/null
+++ b/include/linux/efs_fs.h
@@ -0,0 +1,191 @@
+/*
+ * linux/include/linux/efs_fs.h
+ *
+ * Copyright (C) 1997
+ * Mike Shaver (shaver@neon.ingenia.ca)
+ *
+ * Based on work Copyright (C) 1995, 1996 Christian Vogelgsang.
+ *
+ * $Id$
+ */
+
+#ifndef __LINUX_EFS_FS_H
+#define __LINUX_EFS_FS_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/stat.h>
+#include <linux/fs.h>
+
+/* SuperMagic: need a unique Identifier for EFS */
+#define EFS_SUPER_MAGIC 0x280273
+#define EFS_ROOT_INODE 2
+#define EFS_BLK_SUPER 1
+
+#define EFS_BLOCK_SIZE 512
+#define EFS_BLOCK_SIZE_BITS 9
+
+/* EFS Magic IDs */
+#define EFS_MAGIC1 0x72959
+#define EFS_MAGIC2 0x7295a
+
+/* Offsets in VolumeDescriptor */
+#define EFS_VD_FS_START 0x190 /* First FS block */
+#define EFS_VD_ENTRYFIRST 0x48 /* Begin of Entry list */
+#define EFS_VD_ENTRYPOS 8 /* offset for the entry position */
+#define EFS_VD_ENTRYLEN 12 /* offset for the entry length */
+#define EFS_VD_ENTRYSIZE 16 /* length of an entry */
+
+/* Offsets in Superblock */
+#define EFS_SB_TOTAL 0 /* Number of Blocks used for filesystem */
+#define EFS_SB_FIRST 4 /* BB of Begin First Cylinder Group */
+#define EFS_SB_GROUP 8 /* BBs per Group */
+#define EFS_SB_INODE 12 /* BBs used for Inodes at begin of group */
+#define EFS_SB_TOGRP 18 /* Number of Groups in Filesystem */
+#define EFS_SB_MAGIC 28
+
+struct efs_super_block {
+ __u32 s_size;
+ __u32 s_firstcg;
+ __u32 s_cgfsize;
+ __u16 s_cgisize;
+ __u16 s_sectors;
+ __u16 s_heads;
+ __u16 s_ncg;
+ __u16 s_dirty;
+ __u32 s_time;
+ __u32 s_magic;
+ char s_fname[6];
+ char s_fpack[6];
+ __u32 s_bmsize;
+ __u32 s_tfree;
+ __u32 s_tinode;
+ __u32 s_bmblock;
+ __u32 s_replsb;
+ __u32 s_lastialloc;
+ char s_spare[20]; /* Must be zero */
+ __u32 s_checksum;
+};
+
+#ifdef DEBUG
+void efs_dump_super(struct efs_super_block *);
+#endif
+
+#define EFS_MAX_EXTENTS 12
+
+/* odev is used by "pre-extended-dev_t" IRIX EFS implementations, and
+ later ones use odev and ndev together */
+
+struct efs_devs {
+ __u16 odev;
+ __u32 ndev;
+};
+
+union efs_extent {
+ struct {
+ __u32 ex_magic:4, /* must be zero */
+ ex_bn:24;
+ __u32 ex_length:8,
+ ex_offset;
+ } ex_ex;
+ __u32 ex_bytes[2];
+};
+
+struct efs_disk_inode {
+ __u16 di_mode;
+ __u16 di_nlink;
+ __u16 di_uid;
+ __u16 di_gid;
+ __u32 di_size;
+ __u32 di_atime;
+ __u32 di_mtime;
+ __u32 di_ctime;
+ __u32 di_gen;
+ __u16 di_numextents;
+ __u8 di_version;
+ __u8 di_spare;
+ union di_addr {
+ union efs_extent di_extents[EFS_MAX_EXTENTS];
+ struct efs_devs di_dev;
+ } di_u;
+};
+
+/* Offsets in DirBlock */
+#define EFS_DB_ENTRIES 3
+#define EFS_DB_FIRST 4
+#define EFS_DIRBLK_MAGIC 0xBEEF
+#define EFS_DIRBLK_HEADERSIZE 4
+#define EFS_DIRBLK_SIZE EFS_BLOCK_SIZE
+
+struct efs_dirblk {
+ __u16 db_magic; /* 0xBEEF */
+ __u8 db_firstused;
+ __u8 db_slots;
+ __u8 db_space[EFS_DIRBLK_SIZE - EFS_DIRBLK_HEADERSIZE];
+};
+
+/* Offsets in DirItem */
+#define EFS_DI_NAMELEN 4
+#define EFS_DI_NAME 5
+
+struct efs_dent {
+ union {
+ __u32 l;
+ __u16 s[2];
+ } ud_inum;
+ __u8 d_namelen;
+ __u8 d_name[3];
+};
+
+#define EFS_EXT_PER_BLK_BITS 5
+#define EFS_EXT_PER_BLK_MASK 63
+#define EFS_EXT_SIZE_BITS 3
+
+/* define a few convenient types */
+#if 0
+typedef unsigned char BYTE; /* 8 bit */
+typedef unsigned short SHORT; /* 16 bit */
+typedef unsigned long LONG; /* 32 bit */
+#endif
+
+#ifdef __KERNEL__
+
+struct efs_dir_entry {
+ __u16 inode;
+ char name[0];
+};
+
+/* Byte swapping 32/16-bit quantities into little endian format. */
+#define efs_need_swab 0
+/* extern int efs_need_swab; */
+
+extern __inline__ __u32 efs_swab32(__u32 value)
+{
+ return (efs_need_swab ? ((value >> 24) |
+ ((value >> 8) & 0xff00) |
+ ((value << 8) & 0xff0000) |
+ (value << 24)) : value);
+}
+
+extern __inline__ __u16 efs_swab16(__u16 value)
+{
+ return (efs_need_swab ? ((value >> 8) |
+ (value << 8)) : value);
+}
+
+int init_efs_fs(void);
+
+/* Inode Method structures for Dirs, Files and Symlinks */
+extern struct inode_operations efs_dir_in_ops;
+extern struct inode_operations efs_file_in_ops;
+extern struct inode_operations efs_symlink_in_ops;
+
+/* exported Prototypes */
+extern int efs_bmap(struct inode *,int);
+extern __u32 ConvertLong(__u8 *buf,int off);
+extern __u16 ConvertShort(__u8 *buf,int off);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_EFS_FS_H */
diff --git a/include/linux/efs_fs_i.h b/include/linux/efs_fs_i.h
new file mode 100644
index 000000000..5e6441df7
--- /dev/null
+++ b/include/linux/efs_fs_i.h
@@ -0,0 +1,27 @@
+/*
+ * linux/include/linux/efs_fs_i.h
+ *
+ * Copyright (C) 1997
+ * Mike Shaver (shaver@neon.ingenia.ca)
+ *
+ * Based on work Copyright (C) 1995, 1996 Christian Vogelgsang.
+ *
+ * $Id$
+ */
+
+#ifndef __LINUX_EFS_FS_I_H
+#define __LINUX_EFS_FS_I_H
+
+#include <linux/efs_fs.h>
+
+/* private Inode part */
+struct efs_inode_info {
+ __u32 extblk;
+
+ __u16 tot;
+ __u16 cur;
+
+ union efs_extent extents[EFS_MAX_EXTENTS];
+};
+
+#endif /* __LINUX_EFS_FS_I_H */
diff --git a/include/linux/efs_fs_sb.h b/include/linux/efs_fs_sb.h
new file mode 100644
index 000000000..b3f887899
--- /dev/null
+++ b/include/linux/efs_fs_sb.h
@@ -0,0 +1,29 @@
+/*
+ * linux/include/linux/efs_fs_sb.h
+ *
+ * Copyright (C) 1997
+ * Mike Shaver (shaver@neon.ingenia.ca)
+ *
+ * Based on work Copyright (C) 1995, 1996 Christian Vogelgsang.
+ *
+ * $Id$
+ */
+
+#ifndef __LINUX_EFS_FS_SB_H
+#define __LINUX_EFS_FS_SB_H
+
+#include <linux/efs_fs.h>
+
+/* EFS Superblock Information */
+struct efs_sb_info {
+ __u32 fs_start; /* first block of filesystem */
+ __u32 total_blocks; /* total number of blocks in filesystem */
+ __u32 first_block; /* first data block in filesystem */
+ __u32 group_size; /* number of blocks a group consists of */
+ __u16 inode_blocks; /* number of blocks used for inodes in
+ * every group */
+ __u16 total_groups; /* number of groups */
+};
+
+
+#endif /* __LINUX_UFS_FS_SB_H */