diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
commit | 967c65a99059fd459b956c1588ce0ba227912c4e (patch) | |
tree | 8224d013ff5d255420713d05610c7efebd204d2a /fs/affs/symlink.c | |
parent | e20c1cc1656a66a2773bca4591a895cbc12696ff (diff) |
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'fs/affs/symlink.c')
-rw-r--r-- | fs/affs/symlink.c | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 24d1ed118..22042158a 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -19,7 +19,8 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -static int affs_readlink(struct inode *, char *, int); +static int affs_readlink(struct inode *, char *, int); +static struct dentry *affs_follow_link(struct inode *inode, struct dentry *base); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -33,9 +34,13 @@ struct inode_operations affs_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ affs_readlink, /* readlink */ + affs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL /* smap */ }; static int @@ -46,21 +51,24 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) 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)); - i = 0; - j = 0; if (!bh) { - affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino); - goto symlink_end; + 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 = inode->i_sb->u.affs_sb.s_prefix[i])) { + while (i < buflen && (c = pf[i])) { put_user(c,buffer++); i++; } @@ -84,8 +92,64 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) lc = c; i++, j++; } -symlink_end: - iput(inode); affs_brelse(bh); return i; } + +static struct dentry * +affs_follow_link(struct inode *inode, struct dentry *base) +{ + struct buffer_head *bh; + struct slink_front *lf; + char *buffer; + int i, j; + char c; + char lc; + char *pf; + + pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); + + if (!(buffer = kmalloc(1024,GFP_KERNEL))) { + dput(base); + return ERR_PTR(-ENOSPC); + } + 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); + } + 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 */ + while (i < 1023 && (c = pf[i])) + buffer[i++] = c; + while (i < 1023 && lf->symname[j] != ':') + buffer[i++] = lf->symname[j++]; + if (i < 1023) + buffer[i++] = '/'; + j++; + lc = '/'; + } + while (i < 1023 && (c = lf->symname[j])) { + if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ + buffer[i++] = '.'; + buffer[i++] = '.'; + } + buffer[i++] = c; + lc = c; + j++; + } + buffer[i] = '\0'; + affs_brelse(bh); + base = lookup_dentry(buffer,base,1); + kfree(buffer); + return base; +} + |