1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
/*
* linux/fs/ext2/symlink.c
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/fs/minix/symlink.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext2 symlink handling code
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
static int ext2_readlink (struct inode *, char *, int);
static int ext2_follow_link (struct inode *, struct inode *, int, int,
struct inode **);
/*
* symlinks can't do much...
*/
struct inode_operations ext2_symlink_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
ext2_readlink, /* readlink */
ext2_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
};
static int ext2_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
int error;
struct buffer_head * bh = NULL;
char * link;
*res_inode = NULL;
if (!dir) {
dir = current->fs->root;
dir->i_count++;
}
if (!inode) {
iput (dir);
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
iput (dir);
*res_inode = inode;
return 0;
}
if (current->link_count > 5) {
iput (dir);
iput (inode);
return -ELOOP;
}
if (inode->i_blocks) {
if (!(bh = ext2_bread (inode, 0, 0, &error))) {
iput (dir);
iput (inode);
return -EIO;
}
link = bh->b_data;
} else
link = (char *) inode->u.ext2_i.i_data;
UPDATE_ATIME(inode);
current->link_count++;
error = open_namei (link, flag, mode, res_inode, dir);
current->link_count--;
iput (inode);
if (bh)
brelse (bh);
return error;
}
static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh = NULL;
char * link;
int i, err;
char c;
if (!S_ISLNK(inode->i_mode)) {
iput (inode);
return -EINVAL;
}
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) {
bh = ext2_bread (inode, 0, 0, &err);
if (!bh) {
iput (inode);
return 0;
}
link = bh->b_data;
}
else
link = (char *) inode->u.ext2_i.i_data;
i = 0;
while (i < buflen && (c = link[i])) {
i++;
put_user (c, buffer++);
}
UPDATE_ATIME(inode);
iput (inode);
if (bh)
brelse (bh);
return i;
}
|