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

Next file: linux/fs/block_dev.c
Previous file: linux/fs/affs/namei.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.98/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
@@ -1,34 +1,28 @@
 /*
  *  linux/fs/affs/symlink.c
  *
- *  (C) 1995  Joerg Dorchain Modified for Amiga FFS filesystem
- *            based on:
- *
- *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *  1995  Hans-Joachim Widmaier - modified for AFFS.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
- *  isofs symlink handling code.  This is only used with the Rock Ridge
- *  extensions to iso9660
+ *  affs symlink handling code
  */
 
-#include <asm/segment.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/malloc.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
-#include <linux/malloc.h>
 #include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+
+#include <asm/segment.h>
 
-#include "amigaffs.h"
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
 
 static int affs_readlink(struct inode *, char *, int);
 static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
-/*
- * symlinks can't do much...
- */
 struct inode_operations affs_symlink_inode_operations = {
 	NULL,			/* no file-operations */
 	NULL,			/* create */
@@ -47,21 +41,27 @@
 	NULL			/* permission */
 };
 
-static int affs_follow_link(struct inode * dir, struct inode * inode,
-	int flag, int mode, struct inode ** res_inode)
+static int
+affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
+		 struct inode **res_inode)
 {
-	int error;
-	char * pnt;
-	struct buffer_head *bh;
-	struct symlink_front *sy_data;
+	struct buffer_head	*bh;
+	struct slink_front	*lf;
+	char			*buffer;
+	int			 error;
+	int			 i, j;
+	char			 c;
+	char			 lc;
 
+	pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
+
+	*res_inode = NULL;
 	if (!dir) {
 		dir = current->fs->root;
 		dir->i_count++;
 	}
 	if (!inode) {
 		iput(dir);
-		*res_inode = NULL;
 		return -ENOENT;
 	}
 	if (!S_ISLNK(inode->i_mode)) {
@@ -70,110 +70,108 @@
 		return 0;
 	}
 	if (current->link_count > 5) {
-		iput(dir);
 		iput(inode);
-		*res_inode = NULL;
+		iput(dir);
 		return -ELOOP;
 	}
-	if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
-		printk("affs: unable to read block %ld",inode->i_ino);
-		return 0;
+	if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
+		iput(inode);
+		iput(dir);
+		return -ENOSPC;
 	}
-
-	pnt = sy_data->symname;
+	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+	i  = 0;
+	j  = 0;
+	if (!bh) {
+		printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+		kfree(buffer);
+		iput(inode);
+		iput(dir);
+		return -EIO;
+	}
+	lf = (struct slink_front *)bh->b_data;
+	lc = 0;
+	if (strchr(lf->symname,':')) {		/* Handle assign or volume name */
+		while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[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);
 	iput(inode);
 	current->link_count++;
-	error = open_namei(pnt,flag,mode,res_inode,dir);
+	error = open_namei(buffer,flag,mode,res_inode,dir);
 	current->link_count--;
-	brelse(bh);
+	kfree(buffer);
 	return error;
 }
 
-static char *affs_conv_path(char *affs_path)
+static int
+affs_readlink(struct inode *inode, char *buffer, int buflen)
 {
-static char unix_path[1024]="/";
-int up,ap;
-char dp,slash;
-
-
-dp=1;
-slash=1;
-ap=0;
-up=1;
-if (affs_path[0] == 0)
-  unix_path[up++]='.';
-while ((up < 1020) && (affs_path[ap]!=0))
- {
-  switch (affs_path[ap]) {
-    case ':':
-      if (dp == 0) {
-        slash=0;
-        unix_path[up++]=':';
-      }
-      else {
-        dp=0;
-        slash=1;
-        unix_path[up++]='/';
-      }
-      break;
-    case '/':
-      if (slash==0) {
-        slash=1;
-        unix_path[up++]='/';
-      }
-      else {
-        unix_path[up++]='.';
-        unix_path[up++]='.';
-        unix_path[up++]='/';
-      }
-      break;
-    default:
-      slash=0;
-      unix_path[up++]=affs_path[ap];
-      break;
-  }
-  ap++;
- }
-unix_path[up]=0;
-return unix_path+dp;
-}
-
+	struct buffer_head	*bh;
+	struct slink_front	*lf;
+	int			 i, j;
+	char			 c;
+	char			 lc;
 
-static int affs_readlink(struct inode * inode, char * buffer, int buflen)
-{
-        char * pnt;
-	int i;
-	char c;
-	struct buffer_head *bh;
-	struct symlink_front *sy_data;
+	pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
 
 	if (!S_ISLNK(inode->i_mode)) {
 		iput(inode);
 		return -EINVAL;
 	}
-
-	if (buflen > 1023)
-		buflen = 1023;
-	
-	if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
-		printk("affs: unable to read block %ld\n",inode->i_ino);
-		return -ENOENT;
+	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+	i  = 0;
+	j  = 0;
+	if (!bh) {
+		printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+		goto symlink_end;
 	}
+	lf = (struct slink_front *)bh->b_data;
+	lc = 0;
 	
-	iput(inode);
-
-	pnt = sy_data->symname;
-	if (inode->i_sb->u.affs_sb.s_options.conv_links != 0)
-	  pnt = affs_conv_path(pnt);
-
-	i = 0;
-
-	while (i<buflen && (c = pnt[i])) {
-		i++;
-		put_fs_byte(c,buffer++);
+	if (strchr(lf->symname,':')) {		/* Handle assign or volume name */
+		while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[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++;
 	}
-	
-	brelse(bh);
-
+symlink_end:
+	iput(inode);
+	affs_brelse(bh);
 	return i;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this