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
- Lines: 197
- Date:
Mon Apr 22 10:59:39 1996
- Orig file:
v1.3.93/linux/fs/ufs/ufs_dir.c
- Orig date:
Thu Jan 1 02:00:00 1970
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