patch-1.3.99 linux/fs/affs/dir.c

Next file: linux/fs/affs/file.c
Previous file: linux/fs/affs/bitmap.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.98/linux/fs/affs/dir.c linux/fs/affs/dir.c
@@ -1,6 +1,8 @@
 /*
  *  linux/fs/affs/dir.c
  *
+ *  (c) 1996  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.
@@ -8,25 +10,25 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  *
  *  affs directory handling functions
+ *
  */
 
-#include <linux/errno.h>
-
 #include <asm/segment.h>
-
+#include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/affs_fs.h>
 #include <linux/kernel.h>
 #include <linux/affs_fs.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
 
 static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count);
 
-struct file_operations affs_dir_operations = {
+static struct file_operations affs_dir_operations = {
 	NULL,			/* lseek - default */
-	NULL,			/* read */
+	affs_dir_read,		/* read */
 	NULL,			/* write - bad */
 	affs_readdir,		/* readdir */
 	NULL,			/* select - default */
@@ -34,7 +36,7 @@
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
-	NULL			/* fsync */
+	file_fsync		/* default fsync */
 };
 
 /*
@@ -42,109 +44,153 @@
  */
 struct inode_operations affs_dir_inode_operations = {
 	&affs_dir_operations,	/* default directory file-ops */
-	NULL,			/* create */
+	affs_create,		/* create */
 	affs_lookup,		/* lookup */
-	NULL,			/* link */
-	NULL,       		/* unlink */
-	NULL,       		/* symlink */
-	NULL,       		/* mkdir */
-	NULL,			/* rmdir */
+	affs_link,		/* link */
+	affs_unlink,		/* unlink */
+	affs_symlink,		/* symlink */
+	affs_mkdir,		/* mkdir */
+	affs_rmdir,		/* rmdir */
 	NULL,			/* mknod */
-	NULL,			/* rename */
+	affs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
 	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL			/* permission */
+	affs_dir_truncate,	/* truncate */
+	NULL			/* permissions */
 };
 
-/* 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_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+	return -EISDIR;
+}
 
-static int affs_readdir(struct inode * inode, struct file * filp,
-	void * dirent, filldir_t filldir)
+static int
+affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
 {
-	int i, j, chain_pos, hash_pos, reclen, ino;
+	int			 j, namelen;
+	LONG			 i;
+	ULONG			 hash_pos;
+	ULONG			 chain_pos;
+	unsigned long		 ino;
+	unsigned long			 old;
+	int stored;
 	char *name;
 	struct buffer_head *dir_bh;
 	struct buffer_head *fh_bh;
-	void *dir_data;
-	void *fh_data;
+	struct inode	   *dir;
 
-#ifdef DEBUG
-	printk ("AFFS: readdir: inode=%d f_pos=%d\n",
-		inode->i_ino, filp->f_pos);
-#endif
+	pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
 	
+
 	if (!inode || !S_ISDIR(inode->i_mode))
 		return -EBADF;
 
-	while ((unsigned long)filp->f_pos < 2) {
-		if (filp->f_pos == 0) {
-			if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
-				return 0;
-		} else {
-			i = affs_parent_ino (inode);
-			if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
-				return 0;
+	stored = 0;
+	dir_bh = NULL;
+	fh_bh  = NULL;
+	dir    = NULL;
+	old    = filp->f_pos & 0x80000000;
+	filp->f_pos &= 0x7FFFFFFF;
+
+	if (filp->f_pos == 0) {
+		filp->private_data = (void *)0;
+		if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+			return 0;
 		}
-		filp->f_pos++;
+		++filp->f_pos;
+		stored++;
 	}
-	/* 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 = affs_pread(inode, inode->i_ino, &dir_data)))
-		return 0;
-	/* 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_I2BSIZE (inode), dir_data,
-				       &hash_pos);
-	j = chain_pos;
-	for (;;) {
-		if (i <= 0) {
-#ifdef DEBUG
-			printk ("AFFS: bad f_pos in readdir\n");
-#endif
-			brelse (dir_bh);
-			return 0;
+	if (filp->f_pos == 1) {
+		if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+			filp->f_pos |= 0x80000000;
+			return stored;
 		}
-		ino = i;
-		if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
-			brelse (dir_bh);
-			return 0;
+		filp->f_pos = 2;
+		stored++;
+	}
+
+	/* Read original if this is a link */
+	ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+	if (!(dir = iget(inode->i_sb,ino)))
+		return stored;
+	
+	chain_pos = (filp->f_pos - 2) & 0xffff;
+	hash_pos  = (filp->f_pos - 2) >> 16;
+	if (chain_pos == 0xffff) {
+		printk("AFFS: more than 65535 entries in chain\n");
+		chain_pos = 0;
+		hash_pos++;
+		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+	}
+	if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
+		goto readdir_done;
+
+	while (!stored || !old) {
+		while (hash_pos < AFFS_I2HSIZE(inode) &&
+		     !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
+			hash_pos++;
+		if (hash_pos >= AFFS_I2HSIZE(inode))
+			goto readdir_done;
+		
+		i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
+		j = chain_pos;
+		/* If the directory hasn't changed since the last call to readdir(),
+		 * we can jump directly to where we left off.
+		 */
+		if (filp->private_data && filp->f_version == dir->i_version) {
+			i = (ULONG)filp->private_data;
+			j = 0;
+			pd_debug("AFFS: readdir() left off=%lu\n",i);
 		}
-		i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
-		if (j == 0) {
-			j = 1;
-			if (i <= 0) {
-				hash_pos++;
-				i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
-							       dir_data, &hash_pos);
-				if (i <= 0)
-					chain_pos = 0xffff;
-				else
-					chain_pos = 0;
-			} else
-				chain_pos++;
-			reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
-						     fh_data, &name);
-			if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
-				brelse (fh_bh);
-				brelse (dir_bh);
-				return 0;
+		filp->f_version = dir->i_version;
+		pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+		while (i) {
+			if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
+				printk("AFFS: readdir: Can't get block %d\n",i);
+				goto readdir_done;
 			}
-			filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+			ino = i;
+			i   = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
+			if (j == 0)
+				break;
+			affs_brelse(fh_bh);
+			fh_bh = NULL;
+			j--;
+		}
+		if (fh_bh) {
+			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
+			pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
+			filp->private_data = (void *)ino;
+			if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+				goto readdir_done;
+			filp->private_data = (void *)i;
+			affs_brelse(fh_bh);
+			fh_bh = NULL;
+			stored++;
 		}
-		brelse (fh_bh);
-		j--;
+		if (i == 0) {
+			hash_pos++;
+			chain_pos = 0;
+		} else
+			chain_pos++;
+		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 	}
+
+readdir_done:
+	filp->f_pos |= old;
+	affs_brelse(dir_bh);
+	affs_brelse(fh_bh);
+	iput(dir);
+	pr_debug("AFFS: readdir()=%d\n",stored);
+	return stored;
+}
+
+void
+affs_dir_truncate(struct inode *inode)
+{
+	printk("AFFS: dir_truncate()\n");
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this