diff options
Diffstat (limited to 'fs/ncpfs/symlink.c')
-rw-r--r-- | fs/ncpfs/symlink.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c new file mode 100644 index 000000000000..e935f1b34bc2 --- /dev/null +++ b/fs/ncpfs/symlink.c | |||
@@ -0,0 +1,183 @@ | |||
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 | #include <linux/config.h> | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/ncp_fs.h> | ||
30 | #include <linux/time.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/stat.h> | ||
33 | #include "ncplib_kernel.h" | ||
34 | |||
35 | |||
36 | /* these magic numbers must appear in the symlink file -- this makes it a bit | ||
37 | more resilient against the magic attributes being set on random files. */ | ||
38 | |||
39 | #define NCP_SYMLINK_MAGIC0 cpu_to_le32(0x6c6d7973) /* "symlnk->" */ | ||
40 | #define NCP_SYMLINK_MAGIC1 cpu_to_le32(0x3e2d6b6e) | ||
41 | |||
42 | /* ----- read a symbolic link ------------------------------------------ */ | ||
43 | |||
44 | static int ncp_symlink_readpage(struct file *file, struct page *page) | ||
45 | { | ||
46 | struct inode *inode = page->mapping->host; | ||
47 | int error, length, len; | ||
48 | char *link, *rawlink; | ||
49 | char *buf = kmap(page); | ||
50 | |||
51 | error = -ENOMEM; | ||
52 | rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL); | ||
53 | if (!rawlink) | ||
54 | goto fail; | ||
55 | |||
56 | if (ncp_make_open(inode,O_RDONLY)) | ||
57 | goto failEIO; | ||
58 | |||
59 | error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle, | ||
60 | 0,NCP_MAX_SYMLINK_SIZE,rawlink,&length); | ||
61 | |||
62 | ncp_inode_close(inode); | ||
63 | /* Close file handle if no other users... */ | ||
64 | ncp_make_closed(inode); | ||
65 | if (error) | ||
66 | goto failEIO; | ||
67 | |||
68 | if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) { | ||
69 | if (length<NCP_MIN_SYMLINK_SIZE || | ||
70 | ((__le32 *)rawlink)[0]!=NCP_SYMLINK_MAGIC0 || | ||
71 | ((__le32 *)rawlink)[1]!=NCP_SYMLINK_MAGIC1) | ||
72 | goto failEIO; | ||
73 | link = rawlink + 8; | ||
74 | length -= 8; | ||
75 | } else { | ||
76 | link = rawlink; | ||
77 | } | ||
78 | |||
79 | len = NCP_MAX_SYMLINK_SIZE; | ||
80 | error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0); | ||
81 | kfree(rawlink); | ||
82 | if (error) | ||
83 | goto fail; | ||
84 | SetPageUptodate(page); | ||
85 | kunmap(page); | ||
86 | unlock_page(page); | ||
87 | return 0; | ||
88 | |||
89 | failEIO: | ||
90 | error = -EIO; | ||
91 | kfree(rawlink); | ||
92 | fail: | ||
93 | SetPageError(page); | ||
94 | kunmap(page); | ||
95 | unlock_page(page); | ||
96 | return error; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * symlinks can't do much... | ||
101 | */ | ||
102 | struct address_space_operations ncp_symlink_aops = { | ||
103 | .readpage = ncp_symlink_readpage, | ||
104 | }; | ||
105 | |||
106 | /* ----- create a new symbolic link -------------------------------------- */ | ||
107 | |||
108 | int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { | ||
109 | struct inode *inode; | ||
110 | char *rawlink; | ||
111 | int length, err, i, outlen; | ||
112 | int kludge; | ||
113 | int mode; | ||
114 | __le32 attr; | ||
115 | unsigned int hdr; | ||
116 | |||
117 | DPRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname); | ||
118 | |||
119 | if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) | ||
120 | kludge = 0; | ||
121 | else | ||
122 | #ifdef CONFIG_NCPFS_EXTRAS | ||
123 | if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS) | ||
124 | kludge = 1; | ||
125 | else | ||
126 | #endif | ||
127 | /* EPERM is returned by VFS if symlink procedure does not exist */ | ||
128 | return -EPERM; | ||
129 | |||
130 | rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL); | ||
131 | if (!rawlink) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | if (kludge) { | ||
135 | mode = 0; | ||
136 | attr = aSHARED | aHIDDEN; | ||
137 | ((__le32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0; | ||
138 | ((__le32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1; | ||
139 | hdr = 8; | ||
140 | } else { | ||
141 | mode = S_IFLNK | S_IRWXUGO; | ||
142 | attr = 0; | ||
143 | hdr = 0; | ||
144 | } | ||
145 | |||
146 | length = strlen(symname); | ||
147 | /* map to/from server charset, do not touch upper/lower case as | ||
148 | symlink can point out of ncp filesystem */ | ||
149 | outlen = NCP_MAX_SYMLINK_SIZE - hdr; | ||
150 | err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0); | ||
151 | if (err) | ||
152 | goto failfree; | ||
153 | |||
154 | outlen += hdr; | ||
155 | |||
156 | err = -EIO; | ||
157 | if (ncp_create_new(dir,dentry,mode,0,attr)) { | ||
158 | goto failfree; | ||
159 | } | ||
160 | |||
161 | inode=dentry->d_inode; | ||
162 | |||
163 | if (ncp_make_open(inode, O_WRONLY)) | ||
164 | goto failfree; | ||
165 | |||
166 | if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, | ||
167 | 0, outlen, rawlink, &i) || i!=outlen) { | ||
168 | goto fail; | ||
169 | } | ||
170 | |||
171 | ncp_inode_close(inode); | ||
172 | ncp_make_closed(inode); | ||
173 | kfree(rawlink); | ||
174 | return 0; | ||
175 | fail:; | ||
176 | ncp_inode_close(inode); | ||
177 | ncp_make_closed(inode); | ||
178 | failfree:; | ||
179 | kfree(rawlink); | ||
180 | return err; | ||
181 | } | ||
182 | |||
183 | /* ----- EOF ----- */ | ||