[PATCH 05/12] cmsfs: file operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
---
 fs/cmsfs/file.c |  204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 204 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/file.c

diff --git a/fs/cmsfs/file.c b/fs/cmsfs/file.c
new file mode 100644
index 0000000..26f23f8
--- /dev/null
+++ b/fs/cmsfs/file.c
@@ -0,0 +1,204 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@xxxxxxx>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/uaccess.h>
+
+#include "cmsfs.h"
+
+/**
+ * __read_recfm_fixed - read len bytes from file position pos
+ * @inode:	inode to read from
+ * @buf:	user buffer pointer to copy data to
+ * @len:	length of the buffer
+ * @pos:	position into the inode
+ */
+static ssize_t __read_recfm_fixed(struct inode *inode, char __user *buf,
+				  size_t len, loff_t pos)
+{
+	struct cmsfs_inode_info *ci = CMSFS_I(inode);
+	struct super_block *sb = inode->i_sb;
+	struct page *page;
+	unsigned char *kaddr;
+	u32 blkoff;
+	size_t err = -EIO;
+
+	BUG_ON(ci->recfm != RECFM_FIXED);
+	BUG_ON(sb->s_blocksize > PAGE_SIZE);
+
+	page = read_mapping_page(inode->i_mapping, pos >> PAGE_SHIFT, NULL);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
+
+	kaddr = kmap(page);
+	if (PageError(page))
+		goto out;
+
+	blkoff = pos & ~PAGE_MASK;
+
+	/* won't read more than a page */
+	len = min(len, PAGE_SIZE - blkoff);
+
+	err = copy_to_user(buf, kaddr + blkoff, len);
+	if (!err)
+		err = len;
+
+out:
+	kunmap(page);
+	page_cache_release(page);
+	return err;
+}
+
+/**
+ * cmsfs_file_read - read from a file
+ * @file:	file to read from
+ * @buf:	user buffer pointer for data
+ * @len:	length of the buffer
+ * @ppos:	pointer to the file offset to read at
+ */
+static ssize_t cmsfs_file_read(struct file *file, char __user *buf, size_t len,
+			       loff_t *ppos)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	ssize_t ret;
+
+	if ((*ppos < inode->i_size) && (*ppos + len > inode->i_size))
+		len = inode->i_size - *ppos;
+	else if (*ppos >= inode->i_size)
+		return 0;
+
+	switch (CMSFS_I(inode)->recfm) {
+		case RECFM_FIXED:
+			ret = __read_recfm_fixed(inode, buf, len, *ppos);
+			break;
+		case RECFM_VAR:
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	if (ret > 0)
+		*ppos = *ppos + ret;
+
+	return ret;
+}
+
+/**
+ * cmsfs_readdir - readdir
+ * @file:	file to readdir
+ * @dirent:	?
+ * @filldir:	readdir filler function ptr
+ */
+static int cmsfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct cmsfs_inode_info *cinode = CMSFS_I(inode);
+	struct CMSFSFST *fst;
+	struct page *page;
+	char outname[18];
+	int i;
+	int err = 0;
+
+	if (inode->i_ino != CMSFS_DIRECTOR_INO)
+		return -ENOTDIR;
+
+	/* FIXME: this should go away, I think */
+	if (file->f_pos != 0)
+		return 0;
+
+	page = NULL;
+	fst = NULL;
+	file->f_pos = 0;
+
+	for (i = 0; i < cinode->items; i++, fst++) {
+		if ((i * cinode->lrecl) % CMSFS_SB(sb)->blksz == 0) {
+			if (i) {
+				kunmap(page);
+				page_cache_release(page);
+			}
+
+			page = read_mapping_page(inode->i_mapping,
+						 (i * cinode->lrecl) /
+						  CMSFS_SB(sb)->blksz,
+						 NULL);
+			if (IS_ERR(page)) {
+				err = PTR_ERR(page);
+				goto out;
+			}
+
+			fst = kmap(page);
+			if (PageError(page)) {
+				err = -EIO;
+				goto out_release;
+			}
+		}
+
+		/*
+		 * skipping .DIRECTOR and .ALLOCMAP, but using the dirent
+		 * space for the '.' and '..' entries
+		 */
+		if (i < 2) {
+			err = filldir(dirent, i ? ".." : ".",
+				      i ? 2 : 1, file->f_pos,
+				      CMSFS_DIRECTOR_INO,
+				      DT_DIR);
+			if (err)
+				break;
+			continue;
+		}
+
+		munge_name(fst->FSTFNAME, outname);
+
+		/* No subdirs so all files are regular */
+		err = filldir(dirent, outname, strlen(outname), file->f_pos,
+			      i + CMSFS_FIRST_INO, DT_REG);
+		if (err)
+			break;
+
+		/* set the file possition */
+		file->f_pos += cinode->lrecl;
+	}
+
+	kunmap(page);
+out_release:
+	page_cache_release(page);
+out:
+	return err;
+}
+
+/**
+ * cmsfs_file_open - open routine
+ * @inode:	inode to read
+ * @file:	file ptr to be associated with the inode
+ *
+ * NOTE: The only reason this exists is because it's a good place to prevent
+ * RECFM_VAR files being open, and later read. Once that's supported, this
+ * function should go away.
+ */
+static int cmsfs_file_open(struct inode *inode, struct file *file)
+{
+	if (CMSFS_I(inode)->recfm != RECFM_FIXED) {
+		printk("cmsfs: cannot open files with recfm != fixed\n");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+struct file_operations cmsfs_file_ops = {
+	.readdir	= cmsfs_readdir,
+	.open		= cmsfs_file_open,
+	.read		= cmsfs_file_read,
+};
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux