patch-2.1.112 linux/fs/ufs/dir.c
Next file: linux/fs/ufs/file.c
Previous file: linux/fs/ufs/cylinder.c
Back to the patch index
Back to the overall index
- Lines: 229
- Date:
Sun Jul 26 01:20:22 1998
- Orig file:
v2.1.111/linux/fs/ufs/dir.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/dir.c linux/fs/ufs/dir.c
@@ -0,0 +1,228 @@
+/*
+ * 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
+ *
+ * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
+ */
+
+#include <linux/fs.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_DIR_DEBUG
+
+#ifdef UFS_DIR_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ int error = 0;
+ unsigned long offset, lblk, blk;
+ int i, stored;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ struct super_block * sb;
+ int de_reclen;
+ unsigned flags, swab;
+
+
+ /* Isn't that already done in the upper layer???
+ * the VFS layer really needs some explicit documentation!
+ */
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ flags = sb->u.ufs_sb.s_flags;
+
+ UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
+
+ 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;
+ /* 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 ufs_dir_entry *)(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. */
+ de_reclen = SWAB16(de->d_reclen);
+ if (de_reclen < 1)
+ break;
+ i += de_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 ufs_dir_entry *) (bh->b_data + offset);
+ /* XXX - put in a real ufs_check_dir_entry() */
+ if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
+ /* SWAB16() was unneeded -- compare to 0 */
+ filp->f_pos = (filp->f_pos &
+ (sb->s_blocksize - 1)) +
+ sb->s_blocksize;
+ brelse(bh);
+ return stored;
+ }
+#if 0 /* XXX */
+ if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+ /* XXX - beware about de having to be swabped somehow */
+ 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 += SWAB16(de->d_reclen);
+ if (de->d_ino) {
+ /* SWAB16() was unneeded -- compare to 0 */
+ /* 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 = inode->i_version;
+
+ UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
+ UFSD(("namlen %u\n", ufs_namlen(de)))
+ error = filldir(dirent, de->d_name, ufs_namlen(de),
+ filp->f_pos, SWAB32(de->d_ino));
+ if (error)
+ break;
+ if (version != inode->i_version)
+ goto revalidate;
+ stored ++;
+ }
+ filp->f_pos += SWAB16(de->d_reclen);
+ }
+ offset = 0;
+ brelse (bh);
+ }
+ UPDATE_ATIME(inode);
+ return 0;
+}
+
+int ufs_check_dir_entry (const char * function, struct inode * dir,
+ struct ufs_dir_entry * de, struct buffer_head * bh,
+ unsigned long offset)
+{
+ struct super_block * sb;
+ const char * error_msg;
+ unsigned flags, swab;
+
+ sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+ error_msg = NULL;
+
+ if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
+ error_msg = "reclen is smaller than minimal";
+ else if (SWAB16(de->d_reclen) % 4 != 0)
+ error_msg = "reclen % 4 != 0";
+ else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de)))
+ error_msg = "reclen is too small for namlen";
+ else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
+ dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+ else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
+ error_msg = "inode out of bounds";
+
+ if (error_msg != NULL)
+ ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
+ "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
+ dir->i_ino, dir->i_size, error_msg, offset,
+ (unsigned long) SWAB32(de->d_ino),
+ SWAB16(de->d_reclen), ufs_namlen(de));
+
+ return (error_msg == NULL ? 1 : 0);
+}
+
+static struct file_operations ufs_dir_operations = {
+ NULL, /* lseek */
+ NULL, /* 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 */
+ ufs_create, /* create */
+ ufs_lookup, /* lookup */
+ ufs_link, /* link */
+ ufs_unlink, /* unlink */
+ ufs_symlink, /* symlink */
+ ufs_mkdir, /* mkdir */
+ ufs_rmdir, /* rmdir */
+ ufs_mknod, /* mknod */
+ ufs_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ ufs_bmap, /* bmap */
+ ufs_truncate, /* truncate */
+ ufs_permission, /* permission */
+ NULL, /* smap */
+};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov