File: /usr/src/linux/fs/udf/symlink.c

1     /*
2      * symlink.c
3      *
4      * PURPOSE
5      *	Symlink handling routines for the OSTA-UDF(tm) filesystem.
6      *
7      * CONTACTS
8      *	E-mail regarding any portion of the Linux UDF file system should be
9      *	directed to the development team mailing list (run by majordomo):
10      *		linux_udf@hpesjro.fc.hp.com
11      *
12      * COPYRIGHT
13      *	This file is distributed under the terms of the GNU General Public
14      *	License (GPL). Copies of the GPL can be obtained from:
15      *		ftp://prep.ai.mit.edu/pub/gnu/GPL
16      *	Each contributing author retains all rights to their own work.
17      *
18      *  (C) 1998-2000 Ben Fennema
19      *  (C) 1999 Stelias Computing Inc 
20      *
21      * HISTORY
22      *
23      *  04/16/99 blf  Created.
24      *
25      */
26     
27     #include "udfdecl.h"
28     #include <asm/uaccess.h>
29     #include <linux/errno.h>
30     #include <linux/fs.h>
31     #include <linux/udf_fs.h>
32     #include <linux/sched.h>
33     #include <linux/mm.h>
34     #include <linux/stat.h>
35     #include <linux/slab.h>
36     #include <linux/pagemap.h>
37     #include <linux/smp_lock.h>
38     #include "udf_i.h"
39     
40     static void udf_pc_to_char(char *from, int fromlen, char *to)
41     {
42     	struct PathComponent *pc;
43     	int elen = 0;
44     	char *p = to;
45     
46     	while (elen < fromlen)
47     	{
48     		pc = (struct PathComponent *)(from + elen);
49     		switch (pc->componentType)
50     		{
51     			case 1:
52     				if (pc->lengthComponentIdent == 0)
53     				{
54     					p = to;
55     					*p++ = '/';
56     				}
57     				break;
58     			case 3:
59     				memcpy(p, "../", 3);
60     				p += 3;
61     				break;
62     			case 4:
63     				memcpy(p, "./", 2);
64     				p += 2;
65     				/* that would be . - just ignore */
66     				break;
67     			case 5:
68     				memcpy(p, pc->componentIdent, pc->lengthComponentIdent);
69     				p += pc->lengthComponentIdent;
70     				*p++ = '/';
71     		}
72     		elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
73     	}
74     	if (p > to+1)
75     		p[-1] = '\0';
76     	else
77     		p[0] = '\0';
78     }
79     
80     static int udf_symlink_filler(struct file *file, struct page *page)
81     {
82     	struct inode *inode = page->mapping->host;
83     	struct buffer_head *bh = NULL;
84     	char *symlink;
85     	int err = -EIO;
86     	char *p = kmap(page);
87     	
88     	lock_kernel();
89     	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
90     	{
91     		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
92     
93     		if (!bh)
94     			goto out;
95     
96     		symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
97     	}
98     	else
99     	{
100     		bh = bread(inode->i_dev, udf_block_map(inode, 0),
101     				inode->i_sb->s_blocksize);
102     
103     		if (!bh)
104     			goto out;
105     
106     		symlink = bh->b_data;
107     	}
108     
109     	udf_pc_to_char(symlink, inode->i_size, p);
110     	udf_release_data(bh);
111     
112     	unlock_kernel();
113     	SetPageUptodate(page);
114     	kunmap(page);
115     	UnlockPage(page);
116     	return 0;
117     out:
118     	unlock_kernel();
119     	SetPageError(page);
120     	kunmap(page);
121     	UnlockPage(page);
122     	return err;
123     }
124     
125     /*
126      * symlinks can't do much...
127      */
128     struct address_space_operations udf_symlink_aops = {
129     	readpage:		udf_symlink_filler,
130     };
131