root/fs/affs/symlink.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. affs_follow_link
  2. affs_conv_path
  3. affs_readlink

   1 /*
   2  *  linux/fs/affs/symlink.c
   3  *
   4  *  (C) 1995  Joerg Dorchain Modified for Amiga FFS filesystem
   5  *            based on:
   6  *
   7  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   8  *
   9  *  Copyright (C) 1991, 1992  Linus Torvalds
  10  *
  11  *  isofs symlink handling code.  This is only used with the Rock Ridge
  12  *  extensions to iso9660
  13  */
  14 
  15 #include <asm/segment.h>
  16 
  17 #include <linux/errno.h>
  18 #include <linux/sched.h>
  19 #include <linux/fs.h>
  20 #include <linux/stat.h>
  21 #include <linux/malloc.h>
  22 #include <linux/affs_fs.h>
  23 
  24 #include "amigaffs.h"
  25 
  26 static int affs_readlink(struct inode *, char *, int);
  27 static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
  28 
  29 /*
  30  * symlinks can't do much...
  31  */
  32 struct inode_operations affs_symlink_inode_operations = {
  33         NULL,                   /* no file-operations */
  34         NULL,                   /* create */
  35         NULL,                   /* lookup */
  36         NULL,                   /* link */
  37         NULL,                   /* unlink */
  38         NULL,                   /* symlink */
  39         NULL,                   /* mkdir */
  40         NULL,                   /* rmdir */
  41         NULL,                   /* mknod */
  42         NULL,                   /* rename */
  43         affs_readlink,          /* readlink */
  44         affs_follow_link,       /* follow_link */
  45         NULL,                   /* bmap */
  46         NULL,                   /* truncate */
  47         NULL                    /* permission */
  48 };
  49 
  50 static int affs_follow_link(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
  51         int flag, int mode, struct inode ** res_inode)
  52 {
  53         int error;
  54         char * pnt;
  55         struct buffer_head *bh;
  56         struct symlink_front *sy_data;
  57 
  58         if (!dir) {
  59                 dir = current->fs->root;
  60                 dir->i_count++;
  61         }
  62         if (!inode) {
  63                 iput(dir);
  64                 *res_inode = NULL;
  65                 return -ENOENT;
  66         }
  67         if (!S_ISLNK(inode->i_mode)) {
  68                 iput(dir);
  69                 *res_inode = inode;
  70                 return 0;
  71         }
  72         if (current->link_count > 5) {
  73                 iput(dir);
  74                 iput(inode);
  75                 *res_inode = NULL;
  76                 return -ELOOP;
  77         }
  78         if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
  79                 printk("affs: unable to read block %ld",inode->i_ino);
  80                 return 0;
  81         }
  82 
  83         pnt = sy_data->symname;
  84         iput(inode);
  85         current->link_count++;
  86         error = open_namei(pnt,flag,mode,res_inode,dir);
  87         current->link_count--;
  88         brelse(bh);
  89         return error;
  90 }
  91 
  92 static char *affs_conv_path(char *affs_path)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94 static char unix_path[1024]="/";
  95 int up,ap;
  96 char dp,slash;
  97 
  98 
  99 dp=1;
 100 slash=1;
 101 ap=0;
 102 up=1;
 103 if (affs_path[0] == 0)
 104   unix_path[up++]='.';
 105 while ((up < 1020) && (affs_path[ap]!=0))
 106  {
 107   switch (affs_path[ap]) {
 108     case ':':
 109       if (dp == 0) {
 110         slash=0;
 111         unix_path[up++]=':';
 112       }
 113       else {
 114         dp=0;
 115         slash=1;
 116         unix_path[up++]='/';
 117       }
 118       break;
 119     case '/':
 120       if (slash==0) {
 121         slash=1;
 122         unix_path[up++]='/';
 123       }
 124       else {
 125         unix_path[up++]='.';
 126         unix_path[up++]='.';
 127         unix_path[up++]='/';
 128       }
 129       break;
 130     default:
 131       slash=0;
 132       unix_path[up++]=affs_path[ap];
 133       break;
 134   }
 135   ap++;
 136  }
 137 unix_path[up]=0;
 138 return unix_path+dp;
 139 }
 140 
 141 
 142 static int affs_readlink(struct inode * inode, char * buffer, int buflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         char * pnt;
 145         int i;
 146         char c;
 147         struct buffer_head *bh;
 148         struct symlink_front *sy_data;
 149 
 150         if (!S_ISLNK(inode->i_mode)) {
 151                 iput(inode);
 152                 return -EINVAL;
 153         }
 154 
 155         if (buflen > 1023)
 156                 buflen = 1023;
 157         
 158         if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
 159                 printk("affs: unable to read block %ld\n",inode->i_ino);
 160                 return -ENOENT;
 161         }
 162         
 163         iput(inode);
 164 
 165         pnt = sy_data->symname;
 166         if (inode->i_sb->u.affs_sb.s_options.conv_links != 0)
 167           pnt = affs_conv_path(pnt);
 168 
 169         i = 0;
 170 
 171         while (i<buflen && (c = pnt[i])) {
 172                 i++;
 173                 put_fs_byte(c,buffer++);
 174         }
 175         
 176         brelse(bh);
 177 
 178         return i;
 179 }

/* [previous][next][first][last][top][bottom][index][help] */