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/fs.h>
13 #include <linux/stat.h>
14 #include <linux/affs_fs.h>
15 #include <linux/amigaffs.h>
16 #include <linux/pagemap.h>
17 #include <linux/smp_lock.h>
18 
affs_symlink_readpage(struct file * file,struct page * page)19 static int affs_symlink_readpage(struct file *file, struct page *page)
20 {
21 	struct buffer_head *bh;
22 	struct inode *inode = page->mapping->host;
23 	char *link = kmap(page);
24 	struct slink_front *lf;
25 	int err;
26 	int			 i, j;
27 	char			 c;
28 	char			 lc;
29 	char			*pf;
30 
31 	pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
32 
33 	err = -EIO;
34 	lock_kernel();
35 	bh = affs_bread(inode->i_sb, inode->i_ino);
36 	unlock_kernel();
37 	if (!bh)
38 		goto fail;
39 	i  = 0;
40 	j  = 0;
41 	lf = (struct slink_front *)bh->b_data;
42 	lc = 0;
43 	pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/";
44 
45 	if (strchr(lf->symname,':')) {	/* Handle assign or volume name */
46 		while (i < 1023 && (c = pf[i]))
47 			link[i++] = c;
48 		while (i < 1023 && lf->symname[j] != ':')
49 			link[i++] = lf->symname[j++];
50 		if (i < 1023)
51 			link[i++] = '/';
52 		j++;
53 		lc = '/';
54 	}
55 	while (i < 1023 && (c = lf->symname[j])) {
56 		if (c == '/' && lc == '/' && i < 1020) {	/* parent dir */
57 			link[i++] = '.';
58 			link[i++] = '.';
59 		}
60 		link[i++] = c;
61 		lc = c;
62 		j++;
63 	}
64 	link[i] = '\0';
65 	lock_kernel();
66 	affs_brelse(bh);
67 	unlock_kernel();
68 	SetPageUptodate(page);
69 	kunmap(page);
70 	UnlockPage(page);
71 	return 0;
72 fail:
73 	SetPageError(page);
74 	kunmap(page);
75 	UnlockPage(page);
76 	return err;
77 }
78 
79 struct address_space_operations affs_symlink_aops = {
80 	readpage:	affs_symlink_readpage,
81 };
82 
83 struct inode_operations affs_symlink_inode_operations = {
84 	readlink:	page_readlink,
85 	follow_link:	page_follow_link,
86 	setattr:	affs_notify_change,
87 };
88