• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  linux/fs/ncpfs/symlink.c
3  *
4  *  Code for allowing symbolic links on NCPFS (i.e. NetWare)
5  *  Symbolic links are not supported on native NetWare, so we use an
6  *  infrequently-used flag (Sh) and store a two-word magic header in
7  *  the file to make sure we don't accidentally use a non-link file
8  *  as a link.
9  *
10  *  When using the NFS namespace, we set the mode to indicate a symlink and
11  *  don't bother with the magic numbers.
12  *
13  *  from linux/fs/ext2/symlink.c
14  *
15  *  Copyright (C) 1998-99, Frank A. Vorstenbosch
16  *
17  *  ncpfs symlink handling code
18  *  NLS support (c) 1999 Petr Vandrovec
19  *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
20  *
21  */
22 
23 
24 #include <asm/uaccess.h>
25 
26 #include <linux/errno.h>
27 #include <linux/fs.h>
28 #include <linux/time.h>
29 #include <linux/slab.h>
30 #include <linux/mm.h>
31 #include <linux/stat.h>
32 #include "ncp_fs.h"
33 
34 /* these magic numbers must appear in the symlink file -- this makes it a bit
35    more resilient against the magic attributes being set on random files. */
36 
37 #define NCP_SYMLINK_MAGIC0	cpu_to_le32(0x6c6d7973)     /* "symlnk->" */
38 #define NCP_SYMLINK_MAGIC1	cpu_to_le32(0x3e2d6b6e)
39 
40 /* ----- read a symbolic link ------------------------------------------ */
41 
ncp_symlink_readpage(struct file * file,struct page * page)42 static int ncp_symlink_readpage(struct file *file, struct page *page)
43 {
44 	struct inode *inode = page->mapping->host;
45 	int error, length, len;
46 	char *link, *rawlink;
47 	char *buf = kmap(page);
48 
49 	error = -ENOMEM;
50 	rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
51 	if (!rawlink)
52 		goto fail;
53 
54 	if (ncp_make_open(inode,O_RDONLY))
55 		goto failEIO;
56 
57 	error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
58                          0,NCP_MAX_SYMLINK_SIZE,rawlink,&length);
59 
60 	ncp_inode_close(inode);
61 	/* Close file handle if no other users... */
62 	ncp_make_closed(inode);
63 	if (error)
64 		goto failEIO;
65 
66 	if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) {
67 		if (length<NCP_MIN_SYMLINK_SIZE ||
68 		    ((__le32 *)rawlink)[0]!=NCP_SYMLINK_MAGIC0 ||
69 		    ((__le32 *)rawlink)[1]!=NCP_SYMLINK_MAGIC1)
70 		    	goto failEIO;
71 		link = rawlink + 8;
72 		length -= 8;
73 	} else {
74 		link = rawlink;
75 	}
76 
77 	len = NCP_MAX_SYMLINK_SIZE;
78 	error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0);
79 	kfree(rawlink);
80 	if (error)
81 		goto fail;
82 	SetPageUptodate(page);
83 	kunmap(page);
84 	unlock_page(page);
85 	return 0;
86 
87 failEIO:
88 	error = -EIO;
89 	kfree(rawlink);
90 fail:
91 	SetPageError(page);
92 	kunmap(page);
93 	unlock_page(page);
94 	return error;
95 }
96 
97 /*
98  * symlinks can't do much...
99  */
100 const struct address_space_operations ncp_symlink_aops = {
101 	.readpage	= ncp_symlink_readpage,
102 };
103 
104 /* ----- create a new symbolic link -------------------------------------- */
105 
ncp_symlink(struct inode * dir,struct dentry * dentry,const char * symname)106 int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
107 	struct inode *inode;
108 	char *rawlink;
109 	int length, err, i, outlen;
110 	int kludge;
111 	umode_t mode;
112 	__le32 attr;
113 	unsigned int hdr;
114 
115 	ncp_dbg(1, "dir=%p, dentry=%p, symname=%s\n", dir, dentry, symname);
116 
117 	if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
118 		kludge = 0;
119 	else
120 #ifdef CONFIG_NCPFS_EXTRAS
121 	if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)
122 		kludge = 1;
123 	else
124 #endif
125 	/* EPERM is returned by VFS if symlink procedure does not exist */
126 		return -EPERM;
127 
128 	rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
129 	if (!rawlink)
130 		return -ENOMEM;
131 
132 	if (kludge) {
133 		mode = 0;
134 		attr = aSHARED | aHIDDEN;
135 		((__le32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0;
136 		((__le32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1;
137 		hdr = 8;
138 	} else {
139 		mode = S_IFLNK | S_IRWXUGO;
140 		attr = 0;
141 		hdr = 0;
142 	}
143 
144 	length = strlen(symname);
145 	/* map to/from server charset, do not touch upper/lower case as
146 	   symlink can point out of ncp filesystem */
147 	outlen = NCP_MAX_SYMLINK_SIZE - hdr;
148 	err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0);
149 	if (err)
150 		goto failfree;
151 
152 	outlen += hdr;
153 
154 	err = -EIO;
155 	if (ncp_create_new(dir,dentry,mode,0,attr)) {
156 		goto failfree;
157 	}
158 
159 	inode=d_inode(dentry);
160 
161 	if (ncp_make_open(inode, O_WRONLY))
162 		goto failfree;
163 
164 	if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
165 			     0, outlen, rawlink, &i) || i!=outlen) {
166 		goto fail;
167 	}
168 
169 	ncp_inode_close(inode);
170 	ncp_make_closed(inode);
171 	kfree(rawlink);
172 	return 0;
173 fail:;
174 	ncp_inode_close(inode);
175 	ncp_make_closed(inode);
176 failfree:;
177 	kfree(rawlink);
178 	return err;
179 }
180 
181 /* ----- EOF ----- */
182