diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/udf/symlink.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/udf/symlink.c')
-rw-r--r-- | fs/udf/symlink.c | 184 |
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, +}; |