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_readlink

   1 /*
   2  *  linux/fs/affs/symlink.c
   3  *
   4  *  1995  Hans-Joachim Widmaier - modified for AFFS.
   5  *
   6  *  Copyright (C) 1991, 1992  Linus Torvalds
   7  *
   8  *  affs symlink handling code
   9  */
  10 
  11 #include <linux/errno.h>
  12 #include <linux/sched.h>
  13 #include <linux/malloc.h>
  14 #include <linux/fs.h>
  15 #include <linux/stat.h>
  16 #include <linux/affs_fs.h>
  17 #include <linux/amigaffs.h>
  18 
  19 #include <asm/segment.h>
  20 
  21 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  22 
  23 static int affs_readlink(struct inode *, char *, int);
  24 static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
  25 
  26 struct inode_operations affs_symlink_inode_operations = {
  27         NULL,                   /* no file-operations */
  28         NULL,                   /* create */
  29         NULL,                   /* lookup */
  30         NULL,                   /* link */
  31         NULL,                   /* unlink */
  32         NULL,                   /* symlink */
  33         NULL,                   /* mkdir */
  34         NULL,                   /* rmdir */
  35         NULL,                   /* mknod */
  36         NULL,                   /* rename */
  37         affs_readlink,          /* readlink */
  38         affs_follow_link,       /* follow_link */
  39         NULL,                   /* bmap */
  40         NULL,                   /* truncate */
  41         NULL                    /* permission */
  42 };
  43 
  44 static int
  45 affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
  46                  struct inode **res_inode)
  47 {
  48         struct buffer_head      *bh;
  49         struct slink_front      *lf;
  50         char                    *buffer;
  51         int                      error;
  52         int                      i, j;
  53         char                     c;
  54         char                     lc;
  55 
  56         pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
  57 
  58         *res_inode = NULL;
  59         if (!dir) {
  60                 dir = current->fs->root;
  61                 dir->i_count++;
  62         }
  63         if (!inode) {
  64                 iput(dir);
  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(inode);
  74                 iput(dir);
  75                 return -ELOOP;
  76         }
  77         if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
  78                 iput(inode);
  79                 iput(dir);
  80                 return -ENOSPC;
  81         }
  82         bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
  83         i  = 0;
  84         j  = 0;
  85         if (!bh) {
  86                 printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
  87                 kfree(buffer);
  88                 iput(inode);
  89                 iput(dir);
  90                 return -EIO;
  91         }
  92         lf = (struct slink_front *)bh->b_data;
  93         lc = 0;
  94         if (strchr(lf->symname,':')) {          /* Handle assign or volume name */
  95                 while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i]))
  96                         buffer[i++] = c;
  97                 while (i < 1023 && lf->symname[j] != ':')
  98                         buffer[i++] = lf->symname[j++];
  99                 if (i < 1023)
 100                          buffer[i++] = '/';
 101                 j++;
 102                 lc = '/';
 103         }
 104         while (i < 1023 && (c = lf->symname[j])) {
 105                 if (c == '/' && lc == '/' && i < 1020) {        /* parent dir */
 106                         buffer[i++] = '.';
 107                         buffer[i++] = '.';
 108                 }
 109                 buffer[i++] = c;
 110                 lc = c;
 111                 j++;
 112         }
 113         buffer[i] = '\0';
 114         affs_brelse(bh);
 115         iput(inode);
 116         current->link_count++;
 117         error = open_namei(buffer,flag,mode,res_inode,dir);
 118         current->link_count--;
 119         kfree(buffer);
 120         return error;
 121 }
 122 
 123 static int
 124 affs_readlink(struct inode *inode, char *buffer, int buflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126         struct buffer_head      *bh;
 127         struct slink_front      *lf;
 128         int                      i, j;
 129         char                     c;
 130         char                     lc;
 131 
 132         pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
 133 
 134         if (!S_ISLNK(inode->i_mode)) {
 135                 iput(inode);
 136                 return -EINVAL;
 137         }
 138         bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
 139         i  = 0;
 140         j  = 0;
 141         if (!bh) {
 142                 printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
 143                 goto symlink_end;
 144         }
 145         lf = (struct slink_front *)bh->b_data;
 146         lc = 0;
 147         
 148         if (strchr(lf->symname,':')) {          /* Handle assign or volume name */
 149                 while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) {
 150                         put_user(c,buffer++);
 151                         i++;
 152                 }
 153                 while (i < buflen && (c = lf->symname[j]) != ':') {
 154                         put_user(c,buffer++);
 155                         i++, j++;
 156                 }
 157                 if (i < buflen) {
 158                         put_user('/',buffer++);
 159                         i++, j++;
 160                 }
 161                 lc = '/';
 162         }
 163         while (i < buflen && (c = lf->symname[j])) {
 164                 if (c == '/' && lc == '/' && (i + 3 < buflen)) {        /* parent dir */
 165                         put_user('.',buffer++);
 166                         put_user('.',buffer++);
 167                         i += 2;
 168                 }
 169                 put_user(c,buffer++);
 170                 lc = c;
 171                 i++, j++;
 172         }
 173 symlink_end:
 174         iput(inode);
 175         affs_brelse(bh);
 176         return i;
 177 }

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