summaryrefslogtreecommitdiffstats
path: root/fs/affs/symlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/affs/symlink.c')
-rw-r--r--fs/affs/symlink.c143
1 files changed, 31 insertions, 112 deletions
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 18c03730f..6aad1c222 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -9,103 +9,19 @@
*/
#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/affs_fs.h>
#include <linux/amigaffs.h>
-#include <asm/uaccess.h>
+#include <linux/pagemap.h>
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-static int affs_readlink(struct dentry *, char *, int);
-static struct dentry *affs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int);
-
-struct inode_operations affs_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 */
- affs_readlink, /* readlink */
- affs_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static int
-affs_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int affs_symlink_readpage(struct dentry *dentry, struct page *page)
{
+ struct buffer_head *bh;
struct inode *inode = dentry->d_inode;
- struct buffer_head *bh;
- struct slink_front *lf;
- int i, j;
- char c;
- char lc;
- char *pf;
-
- pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
-
- bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- if (!bh) {
- affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n",
- inode->i_ino);
- return -EIO;
- }
- lf = (struct slink_front *)bh->b_data;
- lc = 0;
- i = 0;
- j = 0;
- pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/";
-
- if (strchr(lf->symname,':')) { /* Handle assign or volume name */
- while (i < buflen && (c = pf[i])) {
- put_user(c,buffer++);
- i++;
- }
- while (i < buflen && (c = lf->symname[j]) != ':') {
- put_user(c,buffer++);
- i++, j++;
- }
- if (i < buflen) {
- put_user('/',buffer++);
- i++, j++;
- }
- lc = '/';
- }
- while (i < buflen && (c = lf->symname[j])) {
- if (c == '/' && lc == '/' && (i + 3 < buflen)) { /* parent dir */
- put_user('.',buffer++);
- put_user('.',buffer++);
- i += 2;
- }
- put_user(c,buffer++);
- lc = c;
- i++, j++;
- }
- affs_brelse(bh);
- return i;
-}
-
-static struct dentry *
-affs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct buffer_head *bh;
- struct slink_front *lf;
- char *buffer;
+ char *link = (char*)kmap(page);
+ struct slink_front *lf;
+ int err;
int i, j;
char c;
char lc;
@@ -113,47 +29,50 @@ affs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow
pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
- if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
- dput(base);
- return ERR_PTR(-ENOSPC);
- }
+ err = -EIO;
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- if (!bh) {
- affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n",
- inode->i_ino);
- kfree(buffer);
- dput(base);
- return ERR_PTR(-EIO);
- }
+ if (!bh)
+ goto fail;
i = 0;
j = 0;
lf = (struct slink_front *)bh->b_data;
lc = 0;
pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/";
- if (strchr(lf->symname,':')) { /* Handle assign or volume name */
+ if (strchr(lf->symname,':')) { /* Handle assign or volume name */
while (i < 1023 && (c = pf[i]))
- buffer[i++] = c;
+ link[i++] = c;
while (i < 1023 && lf->symname[j] != ':')
- buffer[i++] = lf->symname[j++];
+ link[i++] = lf->symname[j++];
if (i < 1023)
- buffer[i++] = '/';
+ link[i++] = '/';
j++;
lc = '/';
}
while (i < 1023 && (c = lf->symname[j])) {
if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
- buffer[i++] = '.';
- buffer[i++] = '.';
+ link[i++] = '.';
+ link[i++] = '.';
}
- buffer[i++] = c;
+ link[i++] = c;
lc = c;
j++;
}
- buffer[i] = '\0';
+ link[i] = '\0';
affs_brelse(bh);
- base = lookup_dentry(buffer,base,follow);
- kfree(buffer);
- return base;
+ SetPageUptodate(page);
+ kunmap(page);
+ UnlockPage(page);
+ return 0;
+fail:
+ SetPageError(page);
+ kunmap(page);
+ UnlockPage(page);
+ return err;
}
+struct inode_operations affs_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ readpage: affs_symlink_readpage,
+};