Import 2.3.26pre2
[davej-history.git] / fs / efs / symlink.c
blob69ddda45b164df3801e502f23fdfa81664b2acb0
1 /*
2 * symlink.c
4 * Copyright (c) 1999 Al Smith
6 * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
7 */
9 #include <linux/string.h>
10 #include <linux/malloc.h>
11 #include <linux/efs_fs.h>
13 static int efs_readlink(struct dentry *, char *, int);
14 static struct dentry * efs_follow_link(struct dentry *, struct dentry *, unsigned int);
16 struct inode_operations efs_symlink_inode_operations = {
17 NULL, /* no symlink file-operations */
18 NULL, /* create */
19 NULL, /* lookup */
20 NULL, /* link */
21 NULL, /* unlink */
22 NULL, /* symlink */
23 NULL, /* mkdir */
24 NULL, /* rmdir */
25 NULL, /* mknod */
26 NULL, /* rename */
27 efs_readlink, /* readlink */
28 efs_follow_link, /* follow_link */
29 NULL, /* get_block */
30 NULL, /* readpage */
31 NULL, /* writepage */
32 NULL, /* flushpage */
33 NULL, /* truncate */
34 NULL, /* permission */
35 NULL, /* smap */
36 NULL /* revalidate */
39 static char *efs_linktarget(struct inode *in, int *len) {
40 char *name;
41 struct buffer_head * bh;
42 efs_block_t size = in->i_size;
44 if (size > 2 * EFS_BLOCKSIZE) {
45 printk(KERN_ERR "EFS: linktarget(): name too long: %lu\n", in->i_size);
46 return NULL;
49 if (!(name = kmalloc(size + 1, GFP_KERNEL)))
50 return NULL;
52 /* read first 512 bytes of link target */
53 bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCKSIZE);
54 if (!bh) {
55 kfree(name);
56 printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 0));
57 return NULL;
60 memcpy(name, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size);
61 brelse(bh);
63 if (size > EFS_BLOCKSIZE) {
64 bh = bread(in->i_dev, efs_bmap(in, 1), EFS_BLOCKSIZE);
65 if (!bh) {
66 kfree(name);
67 printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 1));
68 return NULL;
70 memcpy(name + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE);
71 brelse(bh);
74 name[size] = (char) 0;
75 if (len) *len = size;
77 return name;
80 static struct dentry *efs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) {
81 char *name;
82 struct inode *inode = dentry->d_inode;
84 if (!(name = efs_linktarget(inode, NULL))) {
85 dput(base);
86 return ERR_PTR(-ELOOP);
88 base = lookup_dentry(name, base, follow);
89 kfree(name);
91 return base;
94 static int efs_readlink(struct dentry * dir, char * buf, int bufsiz) {
95 int rc;
96 char *name;
97 struct inode *inode = dir->d_inode;
99 if (!(name = efs_linktarget(inode, &bufsiz))) return 0;
100 rc = copy_to_user(buf, name, bufsiz) ? -EFAULT : bufsiz;
101 kfree(name);
103 return rc;