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
- Lines: 271
- Date:
Mon May 6 14:36:05 1996
- Orig file:
v1.3.98/linux/fs/affs/symlink.c
- Orig date:
Tue Apr 23 13:57:11 1996
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