diff options
-rw-r--r-- | fs/efs/Makefile | 2 | ||||
-rw-r--r-- | fs/efs/dir.c | 173 | ||||
-rw-r--r-- | fs/efs/inode.c | 6 | ||||
-rw-r--r-- | fs/efs/namei.c | 10 | ||||
-rw-r--r-- | fs/efs/symlink.c | 138 | ||||
-rw-r--r-- | include/linux/efs_fs.h | 191 | ||||
-rw-r--r-- | include/linux/efs_fs_i.h | 27 | ||||
-rw-r--r-- | include/linux/efs_fs_sb.h | 29 |
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 */ |