patch-2.1.71 linux/fs/affs/symlink.c

Next file: linux/fs/coda/sysctl.c
Previous file: linux/fs/affs/super.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.70/linux/fs/affs/symlink.c linux/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 @@
 	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 @@
 	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 @@
 		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;
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov