patch-2.3.32 linux/fs/udf/symlink.c

Next file: linux/fs/ufs/inode.c
Previous file: linux/fs/sysv/symlink.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.31/linux/fs/udf/symlink.c linux/fs/udf/symlink.c
@@ -33,155 +33,93 @@
 #include <linux/mm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
 #include "udf_i.h"
 
-static int udf_readlink(struct dentry *, char *, int);
-static struct dentry * udf_follow_link(struct dentry * dentry,
-	struct dentry * base, unsigned int follow);
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations udf_symlink_inode_operations = {
-	NULL,			/* no file-operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	udf_readlink,		/* readlink */
-	udf_follow_link,	/* follow_link */
-	NULL,			/* get_block */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL			/* revalidate */
-};
-
-int udf_pc_to_char(char *from, int fromlen, char **to)
+static void udf_pc_to_char(char *from, int fromlen, char *to)
 {
 	struct PathComponent *pc;
 	int elen = 0, len = 0;
+	char *p = to;
 
-	*to = (char *)kmalloc(fromlen, GFP_KERNEL);
-
-	if (!(*to))
-		return -1;
-
-	while (elen < fromlen)
-	{
+	while (elen < fromlen) {
 		pc = (struct PathComponent *)(from + elen);
-		if (pc->componentType == 1 && pc->lengthComponentIdent == 0)
-		{
-			(*to)[0] = '/';
-			len = 1;
-		}
-		else if (pc->componentType == 3)
-		{
-			memcpy(&(*to)[len], "../", 3);
-			len += 3;
-		}
-        else if (pc->componentType == 4)
-		{
-			memcpy(&(*to)[len], "./", 2);
-			len += 2;
-		}
-		else if (pc->componentType == 5)
-		{
-			memcpy(&(*to)[len], pc->componentIdent, pc->lengthComponentIdent);
-			len += pc->lengthComponentIdent + 1;
-			(*to)[len-1] = '/';
+		switch (pc->componentType) {
+			case 1:
+				if (pc->lengthComponentIdent == 0) {
+					p = to;
+					*p++ = '/';
+				}
+				break;
+			case 3:
+				memcpy(p, "../", 3);
+				p += 3;
+				break;
+			case 4:
+				memcpy(p, "./", 2);
+				p += 2;
+				/* that would be . - just ignore */
+				break;
+			case 5:
+				memcpy(p+len, pc->componentIdent,
+					pc->lengthComponentIdent);
+				p += pc->lengthComponentIdent;
+				*p++ = '/';
 		}
 		elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
 	}
 
-	if (len)
-	{
-		len --;
-		(*to)[len] = '\0';
+	if (p>to+1) {
+		p[-1] = '\0';
 	}
-	return len;
 }
 
-static struct dentry * udf_follow_link(struct dentry * dentry,
-	struct dentry * base, unsigned int follow)
+static int udf_symlink_filler(struct dentry * dentry, struct page *page)
 {
 	struct inode *inode = dentry->d_inode;
 	struct buffer_head *bh = NULL;
-	char *symlink, *tmpbuf;
-	int len;
-	
-	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
-	{
-		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
-
-		if (!bh)
-			return 0;
-
-		symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
-	}
-	else
-	{
-		bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
-
-		if (!bh)
-			return 0;
-
-		symlink = bh->b_data;
-	}
-
-	if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
-	{
-		base = lookup_dentry(tmpbuf, base, follow);
-		kfree(tmpbuf);
-		return base;
-	}
-	else
-		return ERR_PTR(-ENOMEM);
-}
+	char *symlink;
+	int err;
 
-static int udf_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
-	struct inode *inode = dentry->d_inode;
-	struct buffer_head *bh = NULL;
-	char *symlink, *tmpbuf;
-	int len;
+	char *p = (char*)kmap(page);
 	
-	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
-	{
-		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	err = -EIO;
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) {
+		bh = udf_tread(inode->i_sb, inode->i_ino,
+				inode->i_sb->s_blocksize);
 
 		if (!bh)
-			return 0;
+			goto out;
 
 		symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
-	}
-	else
-	{
-		bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
+	} else {
+		bh = bread(inode->i_dev, udf_block_map(inode, 0),
+				inode->i_sb->s_blocksize);
 
 		if (!bh)
-			return 0;
+			goto out;
 
 		symlink = bh->b_data;
 	}
 
-	if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
-	{
-		if (copy_to_user(buffer, tmpbuf, len > buflen ? buflen : len))
-			len = -EFAULT;
-		kfree(tmpbuf);
-	}
-	else
-		len = -ENOMEM;
-
-	UPDATE_ATIME(inode);
-	if (bh)
-		udf_release_data(bh);
-	return len;
+	udf_pc_to_char(symlink, inode->i_size, p);
+	udf_release_data(bh);
+	SetPageUptodate(page);
+	kunmap(page);
+	UnlockPage(page);
+	return 0;
+out:
+	SetPageError(page);
+	kunmap(page);
+	UnlockPage(page);
+	return -EIO;
 }
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations udf_symlink_inode_operations = {
+	readlink:	page_readlink,
+	follow_link:	page_follow_link,
+	readpage:	udf_symlink_filler,
+};

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)