diff -urN linux-1.2.13/arch/i386/config.in linux/arch/i386/config.in
--- linux-1.2.13/arch/i386/config.in	Fri Apr 28 10:17:56 1995
+++ linux/arch/i386/config.in	Tue Oct 24 18:56:05 1995
@@ -221,6 +221,7 @@
 fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
+bool 'Amiga Fast File System support' CONFIG_AFFS_FS n
 
 comment 'character devices'
 
diff -urN linux-1.2.13/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-1.2.13/drivers/block/genhd.c	Fri May 26 07:23:33 1995
+++ linux/drivers/block/genhd.c	Tue Oct 24 18:56:05 1995
@@ -10,11 +10,26 @@
  *  in the early extended-partition checks and added DM partitions
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 
+#ifdef CONFIG_AFFS_FS
+#include <linux/affs_hardblocks.h>
+
+static __inline__ unsigned long
+checksum_block(unsigned long *m, unsigned long size)
+{
+  unsigned long sum = 0;
+
+  while( size-- )
+    sum += *m++;
+  return sum;
+}
+#endif
+
 struct gendisk *gendisk_head = NULL;
 
 static int current_minor = 0;
@@ -158,6 +173,79 @@
 				add_partition(hd, current_minor, p->start_sect, p->nr_sects);
 			}
 		}
+#ifdef CONFIG_AFFS_FS
+
+	/* Check wether the Disk contains a valid Amiga RDB. If so,
+	 * set up the partitions. */
+	
+	} else if (*(ULONG *)bh->b_data == 0x4B534452) {
+
+		struct RigidDiskBlock	*rdb;
+		struct PartitionBlock	*pb;
+		ULONG			*lp;
+		LONG			 pkey;
+		ULONG			 chksum;
+		ULONG			 start_sect;
+		ULONG			 nr_sects;
+		int			 currblock;
+
+		printk(" RDSK");
+
+		/* Swap all longs in the 2 sectors read. */
+
+		for (lp=(ULONG *)bh->b_data; lp < (ULONG *)(bh->b_data+1024); lp++ ) {
+			*lp = swap_long(*lp);
+		}
+		rdb = (struct RigidDiskBlock *)bh->b_data;
+
+		/* Sanity check: calculate checksum. */
+
+		chksum = checksum_block((ULONG *)bh->b_data,rdb->rdb_SummedLongs & 0x7F);
+#ifdef DEBUG
+		printk("     %ld Cyl %ld Heads %ld Sectors/Track\n",
+			rdb->rdb_Cylinders,rdb->rdb_Heads,rdb->rdb_Sectors);
+		printk("     Partition list starts at %ld, CheckSum=%u\n",
+			rdb->rdb_PartitionList,chksum);
+#endif
+		if( chksum ) {
+		  printk(" bad partition table");
+		} else {
+			pkey      = rdb->rdb_PartitionList;
+			currblock = 0;
+			for( i = 1; pkey > 0 && i <= 16; i++, minor++ ) {
+				if (pkey > (currblock << 1) + 1) {
+					currblock = pkey >> 1;
+					if (bh) {
+						brelse(bh);
+						bh = NULL;
+					}
+					if ((bh = bread(dev,currblock,1024)) == NULL) {
+						break;
+					}
+					for (lp=(ULONG *)bh->b_data; lp < (ULONG *)(bh->b_data+1024); lp++ ) {
+						*lp = swap_long(*lp);
+					}
+				}
+				pb   = (struct PartitionBlock *)(bh->b_data + 
+					((pkey & 1) ? 0x200 : 0));
+				pkey = pb->pb_Next;
+				if (pb->pb_ID == IDNAME_PARTITION 
+				    && checksum_block((ULONG *)pb,pb->pb_SummedLongs & 0x7F) == 0 ) {
+					
+					/* Tell Kernel about it */
+
+					if (!(nr_sects = 
+						(pb->pb_Environment[10] + 1 - pb->pb_Environment[9]) *
+						pb->pb_Environment[3] * pb->pb_Environment[5])) {
+						continue;
+					}
+					start_sect = pb->pb_Environment[9]
+						     * pb->pb_Environment[3] * pb->pb_Environment[5];
+					add_partition(hd, minor, start_sect, nr_sects);
+				}
+			}
+		}
+#endif
 	} else
 		printk(" bad partition table");
 	printk("\n");
diff -urN linux-1.2.13/fs/Makefile linux/fs/Makefile
--- linux-1.2.13/fs/Makefile	Mon Jan 23 09:38:28 1995
+++ linux/fs/Makefile	Tue Oct 24 18:56:05 1995
@@ -7,7 +7,7 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv
+SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv affs
 
 ifdef CONFIG_MINIX_FS
 FS_SUBDIRS := $(FS_SUBDIRS) minix
@@ -43,6 +43,12 @@
 FS_SUBDIRS := $(FS_SUBDIRS) nfs
 else
 MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) nfs
+endif
+
+ifdef CONFIG_AFFS_FS
+FS_SUBDIRS := $(FS_SUBDIRS) affs
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) affs
 endif
 
 ifdef CONFIG_XIA_FS
diff -urN linux-1.2.13/fs/affs/Makefile linux/fs/affs/Makefile
--- linux-1.2.13/fs/affs/Makefile	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/Makefile	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,38 @@
+#
+# Makefile for the linux affs-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+#.c.s:
+#	$(CC) -DDEBUG $(CFLAGS) -S $<
+#.c.o:
+#	$(CC) -DDEBUG $(CFLAGS) -c $<
+
+.c.s:
+	$(CC) $(CFLAGS) -S $<
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+.s.o:
+	$(AS) -o $*.o $<
+
+OBJS=	namei.o inode.o file.o dir.o amigaffs.o bitmap.o # symlink.o
+
+affs.o: $(OBJS)
+	$(LD) -r -o affs.o $(OBJS)
+
+clean:
+	rm -f core *.o *.a *.s
+
+dep:
+	$(CPP) -M *.c > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -urN linux-1.2.13/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- linux-1.2.13/fs/affs/amigaffs.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/amigaffs.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,151 @@
+/*
+ *  linux/fs/affs/amigaffs.c
+ *
+ *  (c) 1995  Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ *  (C) 1993  Ray Burr - Amiga FFS filesystem.
+ *
+ */
+#include <linux/config.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+/*
+ * Functions for accessing Amiga-FFS structures.
+ *
+ */
+
+/* Get key entry number ENTRY_POS from the header block pointed to
+   by DATA.  If ENTRY_POS is invalid, -1 is returned.  This is
+   used to get entries from file and directory headers as well
+   as extension and root blocks.  In the current FFS specs, these
+   tables are defined to be the same size in all of these. */
+
+int affs_get_key_entry (int bsize, void *data, int entry_pos)
+{
+	struct dir_front *dir_front = data;
+	int key, hash_table_size;
+
+#ifdef DEBUG
+	printk("affs_get_key_entry(%d,%p,%d)\n",bsize,data,entry_pos);
+#endif
+	hash_table_size = MIDBLOCK_LONGS (bsize);
+	key = 0;
+	if (entry_pos >= 0 && entry_pos < hash_table_size)
+		key = swap_long (dir_front->hash_table[entry_pos]);
+
+	return key;
+}
+
+/* Find the next used hash entry at or after *HASH_POS in a directory's hash
+   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
+   the directory header block in memory.  If there are no more entries,
+   0 is returned.  Otherwise, the key number in the next used hash slot
+   is returned. */
+
+int affs_find_next_hash_entry (int hsize, void *dir_data, int *hash_pos)
+{
+	struct dir_front *dir_front = dir_data;
+	int i;
+
+#ifdef DEBUG
+	printk("affs_find_next_hash_entry(%d,%p,%d)\n",hsize,dir_data,hash_pos);
+#endif
+	if (*hash_pos < 0 || *hash_pos >= hsize)
+		return -1;
+	for (i = *hash_pos; i < hsize; i++)
+		if (dir_front->hash_table[i] != 0)
+			break;
+	if (i == hsize)
+		return 0;
+	*hash_pos = i;
+	return swap_long (dir_front->hash_table[i]);
+}
+
+/* Get the hash_chain (next file header key in hash chain) entry from a
+   file header block in memory pointed to by FH_DATA. */
+
+int affs_get_fh_hash_link (int bsize, void *fh_data)
+{
+	struct file_end *file_end;
+	int key;
+
+#ifdef DEBUG
+	printk("affs_get_fh_hash_link(%d,%p)\n",bsize,fh_data);
+#endif
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	key = swap_long (file_end->hash_chain);
+	return key;
+}
+
+/* Set *NAME to point to the file name in a file header block in memory
+   pointed to by FH_DATA.  The length of the name is returned. */
+
+int affs_get_file_name (int bsize, void *fh_data, char **name)
+{
+	struct file_end *file_end;
+
+#ifdef DEBUG
+	printk("affs_get_file_name(%d,%p,...)\n",bsize,fh_data);
+#endif
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	if (file_end->file_name[0] == 0
+	    || file_end->file_name[0] > 30) {
+		printk ("affs_get_file_name: OOPS! bad filename\n");
+		printk ("  file_end->file_name[0] = %d\n",
+			file_end->file_name[0]);
+		*name = "***BAD_FILE***";
+		return 14;
+        }
+	*name = (char *) &file_end->file_name[1];
+        return file_end->file_name[0];
+}
+
+/* Get the key number of the first extention block for the file
+   header pointed to by FH_DATA. */
+
+int affs_get_extension (int bsize, void *fh_data)
+{
+	struct file_end *file_end;
+	int key;
+
+#ifdef DEBUG
+	printk("affs_get_extension(%d,%p)\n",bsize,fh_data);
+#endif
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	key = swap_long (file_end->extension);
+	return key;
+}
+
+/* Checksum a block, do various consistency checks and optionally return
+   the blocks type number.  DATA points to the block.  If their pointers
+   are non-null, *PTYPE and *STYPE are set to the primary and secondary
+   block types respectively, *HASHSIZE is set to the size of the hashtable
+   (which lets us calculate the block size).
+   Returns non-zero if the block is not consistent. */
+
+ULONG affs_checksum_block (int bsize, void *data, int *ptype, int *stype)
+{
+	ULONG sum;
+	ULONG *p;
+
+#ifdef DEBUG
+	printk("affs_checksum_block(%d,%p,...)\n",bsize,data);
+#endif
+
+	bsize /= 4;
+	if (ptype)
+		*ptype = swap_long (((long *) data)[0]);
+	if (stype)
+		*stype = swap_long (((long *) data)[bsize - 1]);
+
+	sum    = 0;
+	p      = data;
+	while( bsize-- )
+		sum += swap_long(*p++);
+	return sum;
+}
diff -urN linux-1.2.13/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- linux-1.2.13/fs/affs/bitmap.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/bitmap.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,102 @@
+/*
+ *  linux/fs/affs/bitmap.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Widmaier - stolen from linux/fs/minix/bitmap.c
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/amigaffs.h>
+
+#include <asm/bitops.h>
+
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+/* Currently, the bits of a probably only partially used
+ * last longword are counted wrong. But I'm quite sure that
+ * the unused bits (in this last word) are initialized to
+ * zero, so it doesn't matter ...
+ */
+
+static ULONG
+count_free_bits(int blocksize, UBYTE *data, int *rest)
+{
+  ULONG	 free;
+  int	 i;
+
+  free = 0;
+  for( i = 4; i < blocksize && *rest > 0; i++ ) {
+    free  += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF];
+    *rest -= 8;
+  }
+  return free;
+}
+
+ULONG
+affs_count_free_blocks(struct super_block *s)
+{
+  struct buffer_head	*bh;
+  struct buffer_head	*bb;
+  ULONG			 free;
+  ULONG			*bm;
+  ULONG			 key;
+  int			 i;
+  int			 bs;
+  int			 first, last, rest;
+
+  key  = s->u.affs_sb.s_root_block;
+  bs   = s->u.affs_sb.s_block_size;
+  rest = s->u.affs_sb.s_partition_size - 2;	/* Assume 2 reserved blocks */
+  free = 0;
+  while( key && rest > 0 ) {
+    if( (bh = bread(s->s_dev,key,bs)) ) {
+      if( key == s->u.affs_sb.s_root_block ) {
+	/* This is the root block and need special treatment */
+	if( (ULONG)((UBYTE *)bh->b_data + bs - 200) == 0 ) {
+	  /* invalid bitmap */
+	  brelse(bh);
+	  return 0;
+	}
+	first = bs / 4 - 49;
+	last  = first + 25;
+      } else {
+	first = 0;
+	last  = bs / 4 - 1;
+      }
+      bm = (ULONG *)bh->b_data;
+
+      for( i = first; i < last && bm[i] && rest > 0; i++ ) {
+	bb = bread(s->s_dev,swap_long(bm[i]),bs);
+	if( bb ) {
+	  if( affs_checksum_block(bs,bb->b_data,NULL,NULL) == 0 )
+	    free += count_free_bits(bs,bb->b_data,&rest);
+	  else {
+	    brelse(bb);
+	    brelse(bh);
+	    return 0;
+	  }
+	  brelse(bb);
+	} else {
+	  brelse(bh);
+	  return 0;
+	}
+      }
+      key = swap_long(bm[i]);
+      brelse(bh);
+    } else
+      return 0;
+  }
+  return free;
+}
+
diff -urN linux-1.2.13/fs/affs/dir.c linux/fs/affs/dir.c
--- linux-1.2.13/fs/affs/dir.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/dir.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,183 @@
+/*
+ *  linux/fs/affs/dir.c
+ *
+ *  (c) 1995  Hans-Joachim Widmaier - Modifications for larger blocks
+ *		and hard links.
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ *
+ *  affs directory handling functions
+ *
+ */
+
+#include <linux/errno.h>
+
+#include <asm/segment.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+static int affs_readdir(struct inode *, struct file *, struct dirent *, int);
+
+static struct file_operations affs_dir_operations = {
+	NULL,			/* lseek - default */
+	NULL,			/* read */
+	NULL,			/* write - bad */
+	affs_readdir,		/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* no special open code */
+	NULL			/* no special release code */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations affs_dir_inode_operations = {
+	&affs_dir_operations,	/* default directory file-ops */
+	NULL,			/* create */
+	affs_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,       		/* unlink */
+	NULL,       		/* symlink */
+	NULL,       		/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* bmap */
+	NULL			/* truncate */
+};
+
+/* This is used to speed up lookup.  Without this we would need to
+make a linear search of the directory to find the file that the
+directory read just returned.  This is a single element cache. */
+
+/* struct lookup_cache cache = {0,}; */
+
+static int affs_readdir(struct inode * inode, struct file * filp,
+	struct dirent * dirent, int count)
+{
+	int i, j, chain_pos, hash_pos, reclen;
+	char *name;
+	struct buffer_head *dir_bh;
+	struct buffer_head *fh_bh;
+
+#ifdef DEBUG
+	printk ("AFFS: readdir: inode=%d f_pos=%d\n",
+		inode->i_ino, filp->f_pos);
+#endif
+	
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -EBADF;
+
+	reclen = 0;
+
+	if( filp->f_pos == 0 ) {
+		put_fs_long (inode->i_ino, &dirent->d_ino);
+		reclen = 1;
+		put_fs_byte ('.', &dirent->d_name[0]);
+		put_fs_byte (0  , &dirent->d_name[1]);
+	} else if( filp->f_pos == 1 ) {
+		i = affs_parent_ino (inode);
+		put_fs_long (i, &dirent->d_ino);
+		reclen = 2;
+		put_fs_byte ('.', &dirent->d_name[0]);
+		put_fs_byte ('.', &dirent->d_name[1]);
+		put_fs_byte (0  , &dirent->d_name[2]);
+	}
+	if (reclen) {
+		put_fs_word (reclen, &dirent->d_reclen);
+		++filp->f_pos;
+		return reclen;
+	}
+	/* No caching here.  I've got 16 megs why should I care?  :-) */
+	chain_pos = (filp->f_pos - 2) & 0xffff;
+	if (chain_pos == 0xffff)
+		return 0;
+	hash_pos = (filp->f_pos - 2) >> 16;
+#ifdef DEBUG
+	printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
+#endif
+	if (!(dir_bh = bread(inode->i_dev, inode->i_ino, AFFS_I2BSIZE(inode))))
+		return 0;
+
+#if 0
+	/* If this is actually a hardlink, we quietly exchange it with
+	 * the real entry.
+	 */
+	if (inode->u.affs_i.i_original) {
+		brelse(dir_bh);
+		if (!(dir_bh = bread(inode->i_dev,
+			  inode->u.affs_i.i_original, AFFS_I2BSIZE(inode))))
+			return 0;
+	}
+#endif
+
+	/* HASH_POS should already be on a used entry unless it is
+	   the first read of the directory.  Will this break the
+	   dirtell thing somehow? */
+	i = affs_find_next_hash_entry (AFFS_I2HSIZE (inode), dir_bh->b_data,
+				       &hash_pos);
+	j = chain_pos;
+	for (;;) {
+		if (i <= 0) {
+#ifdef DEBUG
+			if( i )
+				printk ("AFFS: bad f_pos in readdir\n");
+#endif
+			brelse (dir_bh);
+			return 0;
+		}
+		if (!(fh_bh = bread (inode->i_dev, i, AFFS_I2BSIZE(inode)))) {
+			brelse (dir_bh);
+			return 0;
+		}
+#if 0
+		/* If the current block is a hard link, we have to put in
+		 * the number of the original header block.
+		 */
+		link_end = GET_END_PTR(struct hlink_end, fh_bh->b_data,
+					AFFS_I2BSIZE (inode));
+		if (link_end->secondary_type == swap_long(ST_LINKFILE)
+			  || link_end->secondary_type == swap_long(ST_LINKDIR))
+			put_fs_long (link_end->original, &dirent->d_ino);
+		else
+#endif
+			put_fs_long (i, &dirent->d_ino);
+		i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_bh->b_data);
+		if (j == 0)
+			break;
+		brelse (fh_bh);
+		j--;
+	}
+	if (i <= 0) {
+		hash_pos++;
+		if (affs_find_next_hash_entry (AFFS_I2HSIZE (inode),
+				       dir_bh->b_data, &hash_pos) <= 0)
+			chain_pos = 0xffff;
+		else
+			chain_pos = 0;
+	}
+	else
+		chain_pos++;
+	reclen = affs_get_file_name (AFFS_I2BSIZE (inode), fh_bh->b_data, &name);
+	for (i = 0; i < reclen; i++)
+		put_fs_byte (name[i], &dirent->d_name[i]);
+	put_fs_byte (0, &dirent->d_name[reclen]);
+	brelse (fh_bh);
+	brelse (dir_bh);
+	put_fs_word (reclen, &dirent->d_reclen);
+	filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+	put_fs_long (filp->f_pos, &dirent->d_off);
+	return reclen;
+}
diff -urN linux-1.2.13/fs/affs/file.c linux/fs/affs/file.c
--- linux-1.2.13/fs/affs/file.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/file.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,179 @@
+/*
+ *  linux/fs/affs/file.c
+ *
+ *  (c) 1995  Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ *
+ *  affs regular file handling primitives
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+
+#include <linux/dirent.h>
+
+#define	NBUF	16
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/affs_fs.h>
+
+#include <linux/amigaffs.h>
+
+int affs_file_read(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the affs filesystem.
+ */
+static struct file_operations affs_file_operations = {
+	NULL,			/* lseek - default */
+	affs_file_read,		/* read */
+	NULL,			/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	NULL			/* fsync */
+};
+
+struct inode_operations affs_file_inode_operations = {
+	&affs_file_operations,	/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL /* affs_bmap */,		/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static int affs_smap(struct inode *inode, int block)
+{
+	struct buffer_head *bh;
+	int key;
+	void *fh_data;
+
+#ifdef DEBUG
+	printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block);
+#endif
+
+	if (block < 0) {
+		printk("affs_smap: block < 0");
+		return 0;
+	}
+
+	key = inode->i_ino;
+	for (;;) {
+		bh = bread (inode->i_dev, key, AFFS_I2BSIZE(inode));
+		if (!bh)
+			return 0;
+		fh_data = bh->b_data;
+		if (block < AFFS_I2HSIZE(inode))
+			break;
+		block -= AFFS_I2HSIZE(inode);
+		key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data);
+#ifdef DEBUG
+		printk ("affs_smap: reading extension block %d\n", key);
+#endif
+		brelse (bh);
+	}
+	key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data,
+				  (AFFS_I2HSIZE(inode) - 1) - block);
+	brelse (bh);
+
+#ifdef DEBUG
+	printk ("affs_smap: key=%d\n", key);
+#endif
+	return key;
+}
+
+/*
+ * affs_file_read() is also needed by the directory read-routine,
+ * so it's not static. NOTE! reading directories directly is a bad idea,
+ * but has to be supported for now for compatability reasons with older
+ * versions.
+ */
+int affs_file_read(struct inode * inode, struct file * filp,
+		   char * buf, int count)
+{
+	char *start;
+	int left, offset, size, sector;
+	struct buffer_head *bh;
+	void *data;
+
+#ifdef DEBUG
+	printk("affs_file_read(...,%d)\n",count);
+#endif
+
+	if (!inode) {
+		printk("affs_file_read: inode = NULL\n");
+		return -EINVAL;
+	}
+	if (!(S_ISREG(inode->i_mode))) {
+#ifdef DEBUG
+		printk("affs_file_read: mode = %07o\n",inode->i_mode);
+#endif
+		return -EINVAL;
+	}
+	if (filp->f_pos >= inode->i_size || count <= 0)
+		return 0;
+
+	start = buf;
+	for (;;) {
+		left = MIN (inode->i_size - filp->f_pos,
+			    count - (buf - start));
+		if (!left)
+			break;
+		sector = affs_smap (inode, filp->f_pos >> AFFS_I2BITS(inode));
+		if (!sector)
+			break;
+		offset = filp->f_pos & (AFFS_I2BSIZE(inode) - 1);
+		bh = bread (inode->i_dev, sector, AFFS_I2BSIZE(inode));
+		if (!bh)
+			break;
+		data = bh->b_data;
+		size = MIN (AFFS_I2BSIZE(inode) - offset, left);
+		filp->f_pos += size;
+		memcpy_tofs (buf, data + offset, size);
+		buf += size;
+		brelse (bh);
+	}
+	if (start == buf)
+		return -EIO;
+	return buf - start;
+
+#if 0
+	if (filp->f_pos == 0 && count > 0) {
+		put_fs_byte ('X', buf++);
+		filp->f_pos++;
+		return 1;
+	}
+	else
+		return 0;
+#endif
+}
diff -urN linux-1.2.13/fs/affs/inode.c linux/fs/affs/inode.c
--- linux-1.2.13/fs/affs/inode.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/inode.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,385 @@
+/*
+ *  linux/fs/affs/inode.c
+ *
+ *  (c) 1995  Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ * 
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+#include <linux/config.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+
+#include <linux/genhd.h>
+
+#include <linux/amigaffs.h>
+
+#ifdef LEAK_CHECK
+static int check_malloc = 0;
+static int check_bread = 0;
+#endif
+
+void affs_put_super(struct super_block *sb)
+{
+	lock_super(sb);
+
+#ifdef DEBUG
+	printk("affs_put_super(...)\n");
+#endif
+#ifdef LEAK_CHECK
+	printk("Outstanding mallocs:%d, outstanding buffers: %d\n", 
+	       check_malloc, check_bread);
+#endif
+	sb->s_dev = 0;
+	unlock_super(sb);
+	return;
+}
+
+static struct super_operations affs_sops = { 
+	affs_read_inode,
+	NULL,			/* notify_change */
+	NULL,			/* write_inode */
+	NULL,			/* put_inode */
+	affs_put_super,
+	NULL,			/* write_super */
+	affs_statfs
+};
+
+int affs_parent_ino(struct inode *dir)
+{
+	int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
+
+#ifdef DEBUG
+	printk("affs_parent_ino(...)\n");
+#endif
+	if (!S_ISDIR (dir->i_mode)) {
+		printk ("affs_parent_ino: argument is not a directory\n");
+		return root_ino;
+	}
+	if (dir->i_ino == root_ino)
+		return root_ino;
+	return dir->u.affs_i.i_parent;
+}
+
+
+/* Is this The Right Way?  Should I be locking something? */
+
+static int get_device_size (dev_t dev)
+{
+	struct gendisk *gd_p;
+	int dev_size = 0;
+
+#ifdef DEBUG
+	printk("get_device_size()\n");
+#endif
+	for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
+		if (gd_p->major != MAJOR(dev))
+			continue;
+		dev_size = gd_p->sizes[MINOR(dev)];
+		break;
+	}
+	/* Return size in 512-byte blocks. */
+	return dev_size * 2;
+}
+
+struct super_block *affs_read_super(struct super_block *s,void *data)
+{
+	struct buffer_head *bh = NULL;
+	struct buffer_head *boot_bh;
+	int dev = s->s_dev;
+	int root_block;
+	int size;
+	ULONG chksum;
+	int ptype, stype, hashsize;
+
+#ifdef DEBUG
+	printk("affs_read_super()\n");
+#endif
+	lock_super(s);
+
+	root_block = 0;
+
+	/* Get the size of the device in 512-byte blocks.
+	 * If we later see that the partition uses bigger
+	 * blocks, we will have to change it.
+	 */
+	size = get_device_size (dev);
+	if (size == 0) {
+		s->s_dev = 0;
+		unlock_super(s);
+		printk ("affs_read_super: could not "
+			"determine device size\n");
+		goto out;
+	}
+	s->u.affs_sb.s_partition_size = size;
+
+	/* This works well for a blocksize of 512 bytes. Bigger
+	 * blocks should be aligned, but we don't know the size
+	 * in advance. Maybe time for an option? Naah ...
+	 */
+	root_block = s->u.affs_sb.s_partition_size / 2;
+	s->u.affs_sb.s_root_block  = root_block;
+
+	/* Ok, our first bet is 512 bytes. If this doesn't work,
+	 * we'll have to change it back later.
+	 */
+	set_blocksize(dev,512);
+	bh = bread(dev,root_block,512);
+	if (!bh) {
+		printk ("AFFS: unable to read superblock\n");
+		goto out;
+	}
+	hashsize  = swap_long(((long *) bh->b_data)[3]);
+
+	if (hashsize != 72) {
+		switch (hashsize) {
+			case 200 :
+				s->u.affs_sb.s_block_size  = 1024;
+				s->u.affs_sb.s_block_bits  = 10;
+				break;
+			case 456 :
+				s->u.affs_sb.s_block_size  = 2048;
+				s->u.affs_sb.s_block_bits  = 11;
+				break;
+			case 968 :
+				s->u.affs_sb.s_block_size  = 4096;
+				s->u.affs_sb.s_block_bits  = 12;
+				break;
+			case 1992: case 4040: case 8136:
+				printk("AFFS: Block size %d not supported\n",
+					(hashsize + 56) * 4);
+				goto out;
+			default:
+				printk ("AFFS: invalid root block %d on "
+					"device 0x%04x (hashsize=%d)\n",
+					root_block, dev, hashsize);
+				goto out;
+		}
+		brelse(bh);
+		set_blocksize(dev,s->u.affs_sb.s_block_size);
+		root_block >>= s->u.affs_sb.s_block_bits - 9;
+		bh = bread(dev,root_block,s->u.affs_sb.s_block_size);
+		if (!bh) {
+			printk ("AFFS: unable to read superblock\n");
+			goto out;
+		}
+	} else {
+		s->u.affs_sb.s_block_size = 512;
+		s->u.affs_sb.s_block_bits = 9;
+	}
+	if ((chksum = affs_checksum_block(s->u.affs_sb.s_block_size,
+			bh->b_data, &ptype, &stype))
+			|| ptype != T_SHORT || stype != ST_ROOT) {
+		printk ("AFFS: invalid root block %d on "
+			"device 0x%04x (bs=%d, cs=%lu, pt=%d, st=%d)\n",
+			root_block, dev, s->u.affs_sb.s_block_size,
+			chksum, ptype, stype);
+		goto out;
+	}
+
+	s->u.affs_sb.s_partition_size >>= s->u.affs_sb.s_block_bits - 9;
+	s->u.affs_sb.s_hashsize         = hashsize;
+	s->u.affs_sb.s_root_block       = root_block;
+
+	/* Find out which kind of FS we have */
+	boot_bh = bread(dev,0,s->u.affs_sb.s_block_size);
+	if (boot_bh) {
+		if (*(ULONG *)boot_bh->b_data == FS_FFS)
+			s->u.affs_sb.s_intl = 0;
+		else if (*(ULONG *)boot_bh->b_data == FS_INTLFFS)
+			s->u.affs_sb.s_intl = 1;
+		else	/* Don't want to deal with that */
+			s->u.affs_sb.s_intl = -1;
+		brelse(boot_bh);
+	}
+	if (!boot_bh || s->u.affs_sb.s_intl < 0) {
+		printk("AFFS: Could not determine file system type\n");
+		goto out;
+	}
+
+#if 1
+	printk ("affs_read_super: dev=0x%04x "
+		"size=%d root=%d blocksize=%d, fs=%sl\n",
+		dev, s->u.affs_sb.s_partition_size,
+		s->u.affs_sb.s_root_block, s->u.affs_sb.s_block_size,
+		s->u.affs_sb.s_intl ? "Int" : "Norma");
+{
+	char *name;
+	int len;
+	len = affs_get_file_name (s->u.affs_sb.s_block_size, bh->b_data,
+				  &name);
+	printk ("affs_read_super: volume name \"%.*s\"\n", len, name);
+}
+#endif
+
+	s->s_magic = AFFS_SUPER_MAGIC;
+	s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
+
+	brelse(bh);
+	
+	/* set up enough so that it can read an inode */
+	s->s_dev = dev;
+	s->s_op = &affs_sops;
+	s->s_blocksize = s->u.affs_sb.s_block_size;
+	s->s_mounted   = iget (s, root_block);
+	unlock_super(s);
+
+	if (!(s->s_mounted)) {
+		s->s_dev = 0;
+		printk("AFFS: get root inode failed\n");
+		return NULL;
+	}
+	return s;
+
+ out: /* Kick out for various error conditions */
+	if (bh)
+		brelse (bh);
+	s->s_dev = 0;
+	unlock_super(s);
+	return NULL;
+}
+
+void affs_statfs (struct super_block *sb, struct statfs *buf)
+{
+	ULONG	 free;
+
+#ifdef DEBUG
+	printk ("AFFS: affs_statfs called\n");
+#endif
+	free = affs_count_free_blocks(sb);
+	put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
+	put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
+	put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
+	put_fs_long(free, &buf->f_bfree);
+	put_fs_long(free, &buf->f_bavail);
+	put_fs_long(0, &buf->f_files);
+	put_fs_long(0, &buf->f_ffree);
+	/* Don't know what value to put in buf->f_fsid */
+}
+
+void affs_read_inode(struct inode * inode)
+{
+	struct buffer_head *bh;
+	int block;
+	struct file_front *file_front;
+	struct file_end *file_end;
+
+#ifdef DEBUG
+	printk ("AFFS: entering affs_read_inode\n");
+#endif
+
+	block = inode->i_ino;
+	if (!(bh=bread (inode->i_dev, block, AFFS_I2BSIZE (inode)))) {
+		printk("AFFS: unable to read i-node block %d\n", block);
+		return;
+	}
+	file_front = (struct file_front *) bh->b_data;
+	file_end   = GET_END_PTR (struct file_end, bh->b_data,
+				AFFS_I2BSIZE (inode));
+
+	inode->u.affs_i.i_protect  = file_end->protect;
+	inode->u.affs_i.i_parent   = swap_long (file_end->parent);
+	inode->u.affs_i.i_original = 0;		/* Default no link */
+	inode->i_mode              = 0444;	/* Let everybody read it */
+	inode->i_nlink             = 1;
+	
+	/* At least the nlink-entries are false. But that doesn't
+	 * matter much, it just seems to make things harder for
+	 * the kernel.
+	 */
+	
+	/* Until I understand how to implement the Amiga links,
+	 * I fake them to be empty files.
+	 */
+
+	switch (swap_long(file_end->secondary_type)) {
+#if 0
+		case ST_LINKDIR:
+			inode->i_ino = swap_long(file_end->original);
+#endif
+		case ST_USERDIR:
+		case ST_ROOT:
+			inode->i_mode |= 0111 | S_IFDIR;
+			inode->i_size  = 0;
+			break;
+		case ST_LINKFILE:
+#if 0
+			inode->i_ino   = swap_long(file_end->original);
+			inode->i_nlink = 2;
+#endif
+		case ST_LINKDIR:
+		case ST_FILE:
+			inode->i_mode |= S_IFREG;
+			inode->i_size  = swap_long (file_end->byte_size);
+			break;
+		case ST_SOFTLINK:
+#if 0
+			inode->i_mode |= S_IFLNK;
+#else
+			inode->i_mode |= S_IFREG;
+#endif
+			inode->i_size  = 0;
+			break;
+	}
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+
+#ifdef DEBUG
+	printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
+#endif
+	inode->i_mtime = inode->i_atime = inode->i_ctime
+		= (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
+		   + swap_long (file_end->created.ds_Minute) * 60
+		   + swap_long (file_end->created.ds_Tick) / 50
+		   + ((8 * 365 + 2) * 24 * 60 * 60));
+
+	brelse(bh);
+	
+	inode->i_op = NULL;
+	if (S_ISREG(inode->i_mode))
+		inode->i_op = &affs_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &affs_dir_inode_operations;
+}
+
+#ifdef LEAK_CHECK
+#undef malloc
+#undef free_s
+#undef bread
+#undef brelse
+
+void * leak_check_malloc(unsigned int size){
+  void * tmp;
+  check_malloc++;
+  tmp = kmalloc(size, GFP_ATOMIC);
+  return tmp;
+}
+
+void leak_check_free_s(void * obj, int size){
+  check_malloc--;
+  return kfree_s(obj, size);
+}
+
+struct buffer_head * leak_check_bread(int dev, int block, int size){
+  check_bread++;
+  return bread(dev, block, size);
+}
+
+void leak_check_brelse(struct buffer_head * bh){
+  check_bread--;
+  return brelse(bh);
+}
+
+#endif
diff -urN linux-1.2.13/fs/affs/namei.c linux/fs/affs/namei.c
--- linux-1.2.13/fs/affs/namei.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/namei.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,205 @@
+/*
+ *  linux/fs/affs/namei.c
+ *
+ *  (c) 1995  Hans-Joachim Widmaier - Modified for larger blocks and
+ *				international FFS.
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+
+
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use affs_match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
+ */
+static int affs_match(int len,const char * name, char * compare, int dlen)
+{
+
+#ifdef DEBUG
+	printk("affs_match(len=%d,name=\"%.*s\",compare=\"%.*s\",clen=%d)\n",len,len,name,dlen,compare,dlen);
+#endif
+	
+	if (!compare) return 0;
+
+	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+	if (!len && dlen == 1 && compare[0] == '.')
+		return 1;
+	
+	if (dlen != len)
+		return 0;
+	return !memcmp(name,compare,len);
+}
+
+/* Simple toupper() for DOS\1 */
+
+static unsigned int affs_toupper (unsigned int ch)
+{
+	return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
+}
+
+/* International Variant for DOS\3 */
+
+static unsigned int affs_intl_toupper (unsigned int ch)
+{
+	return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
+		&& ch <= 0xFE && ch != 0xF7) ?
+		ch - ('a' - 'A') : ch;
+}
+
+static int affs_hash_name (const char *name, int len, int intl,
+			   int hashsize)
+{
+	unsigned int i, x;
+
+#ifdef DEBUG
+	printk("affs_hash_name(%.*s): ",len,name);
+#endif
+	x = len;
+	for (i = 0; i < len; i++)
+		if (intl)
+			x = (x * 13 + affs_intl_toupper (name[i] & 0xFF)) & 0x7ff;
+		else
+			x = (x * 13 + affs_toupper (name[i] & 0xFF)) & 0x7ff;
+
+	return x % hashsize;
+}
+
+static struct buffer_head *affs_find_entry(struct inode *dir,
+	const char *name, int namelen, int *ino)
+{
+	struct buffer_head *bh;
+	int key;
+
+#ifdef DEBUG
+	printk("affs_find_entry(%.*s)\n",namelen,name);
+#endif
+	*ino = 0;
+
+	bh = bread (dir->i_dev, dir->i_ino, AFFS_I2BSIZE (dir));
+	if (!bh)
+		return NULL;
+
+	if (affs_match (namelen, name, ".", 1)) {
+		*ino = dir->i_ino;
+		return bh;
+	}
+	if (affs_match (namelen, name, "..", 2)) {
+		*ino = affs_parent_ino (dir);
+		return bh;
+	}
+	key = affs_get_key_entry (AFFS_I2BSIZE (dir), bh->b_data,
+		  affs_hash_name (name, namelen, AFFS_I2FSTYPE(dir),
+		  		  AFFS_I2HSIZE(dir)));
+
+	for (;;) {
+		char *cname;
+		int cnamelen;
+
+		brelse (bh);
+		if (key <= 0)
+			return NULL;
+		bh = bread (dir->i_dev, key, AFFS_I2BSIZE (dir));
+		if (!bh)
+			return NULL;
+		cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir),
+					       bh->b_data, &cname);
+		if (affs_match (namelen, name, cname, cnamelen))
+			break;
+		key = affs_get_fh_hash_link(AFFS_I2BSIZE (dir), bh->b_data);
+	}
+		
+	*ino = key;
+
+	return bh;
+}
+
+int affs_lookup(struct inode * dir,const char * name, int len,
+	struct inode ** result)
+{
+	int ino;
+	struct buffer_head *bh;
+
+#ifdef DEBUG
+	printk("affs_lookup(%.*s)\n",len,name);
+#endif
+	*result = NULL;
+	if (!dir)
+		return -ENOENT;
+
+#ifdef DEBUG
+	printk ("lookup: %d %d\n", dir->i_ino, len);
+#endif
+
+	if (!S_ISDIR(dir->i_mode)) {
+		iput(dir);
+		return -ENOENT;
+	}
+	if (!(bh = affs_find_entry(dir, name, len, &ino))) {
+	  iput(dir);
+	  return -ENOENT;
+	}
+	brelse(bh);
+	if (!(*result = iget(dir->i_sb, ino))) {
+		iput(dir);
+		return -EACCES;
+	}
+	iput (dir);
+	return 0;
+
+#if 0
+	ino = 0;
+	while(cache.lock);
+	cache.lock = 1;
+	if (dir->i_dev == cache.dev && 
+	    dir->i_ino == cache.dir &&
+	    len == cache.dlen && 
+	    affs_match(len, name, cache.filename, cache.dlen))
+	  {
+	    ino = cache.ino;
+	    ino_back = dir->i_ino;
+	    /* These two cases are special, but since they are at the start
+	       of the directory, we can just as easily search there */
+	    if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
+	    if (cache.dlen == 2 && cache.filename[0] == '.' && 
+		cache.filename[1] == '.') ino = 0;
+	  };
+	cache.lock = 0;
+
+	if (!ino) {
+	  if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) {
+	    iput(dir);
+	    return -ENOENT;
+	  }
+	  brelse(bh);
+	};
+
+	if (!(*result = iget(dir->i_sb,ino))) {
+		iput(dir);
+		return -EACCES;
+	}
+
+	/* We need this backlink for the .. entry */
+	
+	if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; 
+	
+	iput(dir);
+	return 0;
+#endif
+}
diff -urN linux-1.2.13/fs/affs/symlink.c linux/fs/affs/symlink.c
--- linux-1.2.13/fs/affs/symlink.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/affs/symlink.c	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,69 @@
+/*
+ *  linux/fs/affs/symlink.c
+ *
+ *  1995  Hans-Joachim Widmaier - modified for AFFS.
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  affs symlink handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+
+static int affs_readlink(struct inode *, char *, int);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations affs_symlink_inode_operations = {
+	NULL,			/* no file-operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	affs_readlink,		/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static int affs_readlink(struct inode * inode, char * buffer, int buflen)
+{
+  struct buffer_head	*bh;
+  struct slink_front	*lf;
+  int			 i;
+  char			 c;
+
+  if( !S_ISLNK(inode->i_mode) ) {
+    iput(inode);
+    return -EINVAL;
+  }
+  if( buflen > 1023 )
+    buflen = 1023;
+
+  bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+  iput(inode);
+  if( !bh )
+    return 0;
+  i  = 0;
+  lf = (struct slink_front *)bh->b_data;
+  while( i<buflen && (c = lf->symname[i]) ) {
+    i++;
+    put_fs_byte(c,buffer++);
+  }
+  brelse(bh);
+  return i;
+}
diff -urN linux-1.2.13/fs/filesystems.c linux/fs/filesystems.c
--- linux-1.2.13/fs/filesystems.c	Sun Jul 24 16:39:44 1994
+++ linux/fs/filesystems.c	Tue Oct 24 18:56:06 1995
@@ -20,6 +20,7 @@
 #include <linux/iso_fs.h>
 #include <linux/sysv_fs.h>
 #include <linux/hpfs_fs.h>
+#include <linux/affs_fs.h>
 
 extern void device_setup(void);
 
@@ -76,6 +77,11 @@
 #ifdef CONFIG_ISO9660_FS
 	register_filesystem(&(struct file_system_type)
 		{isofs_read_super, "iso9660", 1, NULL});
+#endif
+
+#ifdef CONFIG_AFFS_FS
+	register_filesystem(&(struct file_system_type)
+		{affs_read_super, "affs", 1, NULL});
 #endif
 
 #ifdef CONFIG_SYSV_FS
diff -urN linux-1.2.13/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- linux-1.2.13/include/linux/affs_fs.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/affs_fs.h	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,86 @@
+#ifndef _AFFS_FS_H
+#define _AFFS_FS_H
+
+#include <linux/types.h>
+/*
+ * The affs filesystem constants/structures
+ */
+
+#define AFFS_SUPER_MAGIC 0xadff
+
+/* Get the filesystem block size given an inode. */
+#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size)
+
+/* Get the filesystem hash table size given an inode. */
+#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
+
+/* Get the block number bits given an inode */
+#define AFFS_I2BITS(inode) ((inode)->i_sb->u.affs_sb.s_block_bits)
+
+/* Get the fs type given an inode */
+#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_intl)
+
+#if 0
+static inline struct buffer_head *affs_bread(struct inode *inode,
+					     int sector, int size)
+{
+	int offset = inode->i_sb->u.affs_sb.s_partition_offset;
+	return bread (inode->i_dev,
+			(sector << AFFS_I2BSHIFT(inode)) + offset, size);
+}
+#endif
+
+/* amigaffs.c prototypes */
+
+extern int affs_get_key_entry (int bsize, void *data, int entry_pos);
+extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos);
+extern int affs_get_fh_hash_link (int bsize, void *fh_data);
+extern int affs_get_file_name (int bsize, void *fh_data, char **name);
+extern int affs_get_extension (int bsize, void *fh_data);
+extern unsigned long affs_count_free_blocks(struct super_block *s);
+extern unsigned long affs_checksum_block (int bsize, void *data, int *ptype, int *stype);
+
+/* The stuff that follows may be totally unneeded. I have not checked to see 
+ which prototypes we are still using.  */
+
+extern int affs_open(struct inode * inode, struct file * filp);
+extern void affs_release(struct inode * inode, struct file * filp);
+extern int affs_lookup(struct inode * dir,const char * name, int len,
+	struct inode ** result);
+extern unsigned long affs_count_free_inodes(struct super_block *sb);
+extern int affs_new_block(int dev);
+extern int affs_free_block(int dev, int block);
+extern int affs_bmap(struct inode *,int);
+
+extern void affs_put_super(struct super_block *);
+extern struct super_block *affs_read_super(struct super_block *,void *);
+extern void affs_read_inode(struct inode *);
+extern void affs_put_inode(struct inode *);
+extern void affs_statfs(struct super_block *, struct statfs *);
+extern int affs_parent_ino(struct inode *dir);
+extern int affs_lseek(struct inode *, struct file *, off_t, int);
+extern int affs_read(struct inode *, struct file *, char *, int);
+extern int affs_file_read(struct inode *, struct file *, char *, int);
+
+extern struct inode_operations affs_file_inode_operations;
+extern struct inode_operations affs_dir_inode_operations;
+extern struct inode_operations affs_symlink_inode_operations;
+extern struct inode_operations affs_chrdev_inode_operations;
+extern struct inode_operations affs_blkdev_inode_operations;
+
+extern struct file_operations affs_file_operations;
+extern struct file_operations affs_dir_operations;
+
+/* The following macros are used to check for memory leaks. */
+#ifdef LEAK_CHECK
+#define free_s leak_check_free_s
+#define malloc leak_check_malloc
+#define bread leak_check_bread
+#define brelse leak_check_brelse
+extern void * leak_check_malloc(unsigned int size);
+extern void leak_check_free_s(void * obj, int size);
+extern struct buffer_head * leak_check_bread(int dev, int block, int size);
+extern void leak_check_brelse(struct buffer_head * bh);
+#endif /* LEAK_CHECK */
+
+#endif
diff -urN linux-1.2.13/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- linux-1.2.13/include/linux/affs_fs_i.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/affs_fs_i.h	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,13 @@
+#ifndef _AFFS_FS_I
+#define _AFFS_FS_I
+
+/*
+ * affs fs inode data in memory
+ */
+struct affs_inode_info {
+	int i_protect;	/* unused attribute bits */
+	int i_parent;   /* parent ino */
+	int i_original;	/* if != 0, this is the key of the original */
+};
+
+#endif
diff -urN linux-1.2.13/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h
--- linux-1.2.13/include/linux/affs_fs_sb.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/affs_fs_sb.h	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,21 @@
+#ifndef _AFFS_FS_SB
+#define _AFFS_FS_SB
+
+/*
+ * super-block data in memory
+ *
+ * Block numbers are adjusted for their acual size
+ *
+ */
+
+struct affs_sb_info {
+	int s_partition_size;		/* Partition size in blocks. */
+	int s_root_block;		/* Absolute FFS root block number. */
+	int s_block_size;		/* Block size in bytes. */
+	int s_block_bits;		/* Number of bits in a block. */
+	int s_hashsize;			/* Size of hash table. */
+	int s_intl;			/* FS is DOS\3. */
+	char s_volume_name[32];		/* Amiga disk label. */
+};
+
+#endif
diff -urN linux-1.2.13/include/linux/affs_hardblocks.h linux/include/linux/affs_hardblocks.h
--- linux-1.2.13/include/linux/affs_hardblocks.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/affs_hardblocks.h	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,68 @@
+#ifndef	AFFS_HARDBLOCKS_H
+#define	AFFS_HARDBLOCKS_H
+
+/* Just the needed definitions for the RDB of an Amiga HD. */
+
+#ifndef AMIGAFFS_H
+#include <linux/amigaffs.h>
+#endif
+
+struct RigidDiskBlock {
+	ULONG	rdb_ID;
+	ULONG	rdb_SummedLongs;
+	LONG	rdb_ChkSum;
+	ULONG	rdb_HostID;
+	ULONG	rdb_BlockBytes;
+	ULONG	rdb_Flags;
+	ULONG	rdb_BadBlockList;
+	ULONG	rdb_PartitionList;
+	ULONG	rdb_FileSysHeaderList;
+	ULONG	rdb_DriveInit;
+	ULONG	rdb_Reserved1[6];
+	ULONG	rdb_Cylinders;
+	ULONG	rdb_Sectors;
+	ULONG	rdb_Heads;
+	ULONG	rdb_Interleave;
+	ULONG	rdb_Park;
+	ULONG	rdb_Reserved2[3];
+	ULONG	rdb_WritePreComp;
+	ULONG	rdb_ReducedWrite;
+	ULONG	rdb_StepRate;
+	ULONG	rdb_Reserved3[5];
+	ULONG	rdb_RDBBlocksLo;
+	ULONG	rdb_RDBBlocksHi;
+	ULONG	rdb_LoCylinder;
+	ULONG	rdb_HiCylinder;
+	ULONG	rdb_CylBlocks;
+	ULONG	rdb_AutoParkSeconds;
+	ULONG	rdb_HighRDSKBlock;
+	ULONG	rdb_Reserved4;
+	char	rdb_DiskVendor[8];
+	char	rdb_DiskProduct[16];
+	char	rdb_DiskRevision[4];
+	char	rdb_ControllerVendor[8];
+	char	rdb_ControllerProduct[16];
+	char	rdb_ControllerRevision[4];
+	ULONG	rdb_Reserved5[10];
+};
+
+#define	IDNAME_RIGIDDISK	0x5244534B	/* "RDSK" */
+
+struct PartitionBlock {
+	ULONG	pb_ID;
+	ULONG	pb_SummedLongs;
+	LONG	pb_ChkSum;
+	ULONG	pb_HostID;
+	ULONG	pb_Next;
+	ULONG	pb_Flags;
+	ULONG	pb_Reserved1[2];
+	ULONG	pb_DevFlags;
+	UBYTE	pb_DriveName[32];
+	ULONG	pb_Reserved2[15];
+	ULONG	pb_Environment[17];
+	ULONG	pb_EReserved[15];
+};
+
+#define	IDNAME_PARTITION	0x50415254	/* "PART" */
+
+#endif	/* AFFS_HARDBLOCKS_H */
diff -urN linux-1.2.13/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- linux-1.2.13/include/linux/amigaffs.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/amigaffs.h	Tue Oct 24 18:56:06 1995
@@ -0,0 +1,175 @@
+#ifndef AMIGAFFS_H
+#define AMIGAFFS_H
+
+/* Ugly macros to make the code pretty. */
+
+#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
+
+#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \
+			     - sizeof (struct dir_end)) / 4)
+
+static __inline__ unsigned long
+swap_long (unsigned long x)
+{
+  unsigned char *px;
+
+  px = (unsigned char *) &x;
+  return (  (px[3] <<  0)
+	  | (px[2] <<  8)
+	  | (px[1] << 16)
+	  | (px[0] << 24));
+}
+
+typedef unsigned long	ULONG;
+typedef unsigned short	UWORD;
+typedef unsigned char	UBYTE;
+
+typedef long		LONG;
+typedef short		WORD;
+typedef char		BYTE;
+
+struct DateStamp
+{
+  ULONG ds_Days;
+  ULONG ds_Minute;
+  ULONG ds_Tick;
+};
+
+#define T_SHORT		2
+#define T_LIST		16
+#define T_DATA		8
+
+#define ST_LINKFILE	-4
+#define ST_FILE		-3
+#define ST_USERDIR	2
+#define ST_ROOT		1
+#define ST_SOFTLINK	3		/* These are not supported */
+#define ST_LINKDIR	4
+
+#define FS_FFS		0x01534F44	/* These are already byte swapped */
+#define FS_INTLFFS	0x03534F44
+
+struct ffs_root_front
+{
+  LONG primary_type;
+  ULONG spare1[2];
+  ULONG hash_size;
+  ULONG spare2;
+  ULONG checksum;
+};
+
+struct ffs_root_end
+{
+  LONG bm_flag;
+  ULONG bm_keys[25];
+  ULONG bm_extend;
+  struct DateStamp dir_altered;
+  UBYTE disk_name[40];
+  struct DateStamp disk_altered;
+  struct DateStamp disk_made;
+  ULONG spare1[3];
+  LONG secondary_type;
+};
+
+struct dir_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+  ULONG hash_table[0];
+};
+
+struct dir_end
+{
+  ULONG spare1[2];
+  ULONG protect;
+  ULONG spare2;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE dir_name[32];
+  ULONG spare3[2];
+  ULONG link_chain;
+  ULONG spare4[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare5;
+  LONG secondary_type;
+};
+
+struct file_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG block_count;
+  ULONG unknown1;
+  ULONG first_data;
+  ULONG checksum;
+  ULONG blocks[0];
+};
+
+struct file_end
+{
+  ULONG spare1[2];
+  ULONG protect;
+  ULONG byte_size;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE file_name[32];
+  ULONG spare2;
+  ULONG original;	/* not really in file_end */
+  ULONG link_chain;
+  ULONG spare3[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG extension;
+  LONG secondary_type;
+};
+
+struct hlink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+};
+
+struct hlink_end
+{
+  ULONG spare1[2];
+  ULONG protect;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE link_name[32];
+  ULONG spare2;
+  ULONG original;
+  ULONG link_chain;
+  ULONG spare3[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare4;
+  LONG secondary_type;
+};
+
+struct slink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+  UBYTE	symname[288];	/* depends on block size */
+};
+
+/* Since the OFS isn't supported, there's actually no need for this. */
+
+struct data_front
+{
+  LONG primary_type;
+  ULONG header;
+  ULONG seq_num;
+  ULONG data_size;
+  ULONG next_data;
+  ULONG checksum;
+};
+
+#endif
diff -urN linux-1.2.13/include/linux/fs.h linux/include/linux/fs.h
--- linux-1.2.13/include/linux/fs.h	Thu Feb 23 12:32:05 1995
+++ linux/include/linux/fs.h	Tue Oct 24 18:56:06 1995
@@ -163,6 +163,7 @@
 #include <linux/nfs_fs_i.h>
 #include <linux/xia_fs_i.h>
 #include <linux/sysv_fs_i.h>
+#include <linux/affs_fs_i.h>
 
 #ifdef __KERNEL__
 
@@ -246,6 +247,7 @@
 		struct nfs_inode_info nfs_i;
 		struct xiafs_inode_info xiafs_i;
 		struct sysv_inode_info sysv_i;
+		struct affs_inode_info affs_i;
 		struct socket socket_i;
 		void * generic_ip;
 	} u;
@@ -294,6 +296,7 @@
 #include <linux/nfs_fs_sb.h>
 #include <linux/xia_fs_sb.h>
 #include <linux/sysv_fs_sb.h>
+#include <linux/affs_fs_sb.h>
 
 struct super_block {
 	dev_t s_dev;
@@ -320,6 +323,7 @@
 		struct nfs_sb_info nfs_sb;
 		struct xiafs_sb_info xiafs_sb;
 		struct sysv_sb_info sysv_sb;
+		struct affs_sb_info affs_sb;
 		void *generic_sbp;
 	} u;
 };
