patch-1.3.94 linux/fs/ufs/ufs_dir.c

Next file: linux/fs/ufs/ufs_file.c
Previous file: linux/fs/ufs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
@@ -0,0 +1,196 @@
+/*
+ *  linux/fs/ufs/ufs_dir.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+
+/* XXX */
+extern int ufs_lookup();
+extern int ufs_bmap();
+
+static int ufs_dir_read (struct inode * inode, struct file * filp,
+	                 char * buf, int count)
+{
+	/* XXX - probably allow this for root, EISDIR for normal users */
+	return -EISDIR;
+}
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir (struct inode * inode, struct file * filp, void * dirent,
+	     filldir_t filldir)
+{
+	int error = 0;
+	unsigned long offset, lblk, blk;
+	int i, stored;
+	struct buffer_head * bh;
+	struct direct * de;
+	struct super_block * sb;
+
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -EBADF;
+	sb = inode->i_sb;
+
+	if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
+	               inode->i_ino, filp->f_pos);
+	        ufs_print_inode(inode);
+	}
+
+	stored = 0;
+	bh = NULL;
+	offset = filp->f_pos & (sb->s_blocksize - 1);
+
+	while (!error && !stored && filp->f_pos < inode->i_size) {
+		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
+	        blk = ufs_bmap(inode, lblk);
+	        /* XXX - ufs_bmap() call needs error checking */
+	        blk = ufs_bmap(inode, lblk);
+		bh = bread (sb->s_dev, blk, sb->s_blocksize);
+		if (!bh) {
+	                /* XXX - error - skip to the next block */
+	                printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n",
+	                       inode->i_ino, (unsigned long int)filp->f_pos);
+			filp->f_pos += sb->s_blocksize - offset;
+			continue;
+		}
+
+revalidate:
+		/* If the dir block has changed since the last call to
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (filp->f_version != inode->i_version) {
+			for (i = 0; i < sb->s_blocksize && i < offset; ) {
+				de = (struct direct *) 
+					(bh->b_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				if (de->d_reclen < 1)
+					break;
+				i += de->d_reclen;
+			}
+			offset = i;
+			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+				| offset;
+			filp->f_version = inode->i_version;
+		}
+		
+		while (!error && filp->f_pos < inode->i_size 
+		       && offset < sb->s_blocksize) {
+			de = (struct direct *) (bh->b_data + offset);
+	                /* XXX - put in a real ufs_check_dir_entry() */
+	                if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
+	                        filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize;
+	                        brelse(bh);
+	                        return stored;
+	                }
+#if 0
+			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+						   bh, offset)) {
+				/* On error, skip the f_pos to the
+	                           next block. */
+				filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
+					      + sb->s_blocksize;
+				brelse (bh);
+				return stored;
+			}
+#endif /* XXX */
+			offset += de->d_reclen;
+			if (de->d_ino) {
+				/* We might block in the next section
+				 * if the data destination is
+				 * currently swapped out.  So, use a
+				 * version stamp to detect whether or
+				 * not the directory has been modified
+				 * during the copy operation. */
+				unsigned long version;
+				dcache_add(inode, de->d_name, de->d_namlen,
+	                                   de->d_ino);
+				version = inode->i_version;
+	                        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                                printk("ufs_readdir: filldir(%s,%lu)\n",
+	                                       de->d_name, de->d_ino);
+	                        }
+				error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino);
+				if (error)
+					break;
+				if (version != inode->i_version)
+					goto revalidate;
+				stored ++;
+			}
+			filp->f_pos += de->d_reclen;
+		}
+		offset = 0;
+		brelse (bh);
+	}
+#if 0 /* XXX */
+	if (!IS_RDONLY(inode)) {
+		inode->i_atime = CURRENT_TIME;
+		inode->i_dirt = 1;
+	}
+#endif /* XXX */
+	return 0;
+}
+
+
+static struct file_operations ufs_dir_operations = {
+	NULL,			/* lseek */
+	&ufs_dir_read,		/* read */
+	NULL,			/* write */
+	&ufs_readdir,		/* readdir */
+	NULL,			/* select */
+	NULL,			/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
+	&file_fsync,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+struct inode_operations ufs_dir_inode_operations = {
+	&ufs_dir_operations,	/* default directory file operations */
+	NULL,			/* create */
+	&ufs_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */

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