summaryrefslogtreecommitdiffstats
path: root/fs/udf/symlink.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
commit33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch)
tree2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/udf/symlink.c
parent216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff)
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/udf/symlink.c')
-rw-r--r--fs/udf/symlink.c184
1 files changed, 60 insertions, 124 deletions
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 0e52198f5..63ebb5713 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -33,157 +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, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- 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,
+};